elanous 0.2.10 → 0.2.12
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/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
- package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3869-3cd46526879f454c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
- package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
- package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8605-0259994816604c49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-cb169620945d1952.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-5c05b0da4bc1392c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a67e11ba962337b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-1efd0cb9e0ed9d13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-793fa536b3a6ef37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-9547b5cec7cf76bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-e297866051595d81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
- package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -0
- package/apps/pwa/out/inside/index.txt +31 -0
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -0
- package/apps/pwa/out/outputs/index.txt +30 -0
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -24
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -24
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/context/nightly-condense.yaml +21 -0
- package/graphs/context/recipes.yaml +12 -0
- package/graphs/demo/inside-seed.yaml +20 -0
- package/graphs/demo/recipes.yaml +12 -0
- package/graphs/drafts/draft-cleanup.yaml +19 -0
- package/graphs/drafts/recipes.yaml +23 -0
- package/graphs/intake/intake-daily.yaml +2 -1
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/ops/secret-exposure.yaml +24 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -1
- package/graphs/video/explainer-line.yaml +2 -2
- package/package.json +2 -1
- package/plugins/card-followup/examples/sample-card.png +0 -0
- package/plugins/elanous-hwp/README.md +25 -0
- package/plugins/elanous-hwp/cli.ts +22 -0
- package/plugins/elanous-hwp/converter.ts +237 -0
- package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
- package/plugins/elanous-hwp/plugin.json +16 -0
- package/plugins/elanous-hwp/plugin.ts +40 -0
- package/scripts/ci-public-export-leak-gate.ts +75 -14
- package/scripts/ci-public-leak-gate.ts +44 -9
- package/scripts/context-hooks/claude-stop.sh +4 -0
- package/scripts/context-hooks/emit.ts +24 -0
- package/scripts/context-hooks/post-tool-use.sh +4 -0
- package/scripts/coord-channel-watch.sh +12 -0
- package/scripts/coord-requests-bridge.ts +143 -0
- package/scripts/field-feed/lib.ts +4 -0
- package/scripts/fleet/node-setup.sh +20 -3
- package/scripts/homebrew-formula-bump.ts +69 -0
- package/scripts/lib/telegram-inject-args.ts +31 -0
- package/scripts/marketing/measure-site-numbers.ts +169 -0
- package/scripts/measure-gate-shards.ts +309 -0
- package/scripts/measure-pod-memory-by-goal.ts +130 -0
- package/scripts/mission-request-judge.ts +31 -1
- package/scripts/morning-report.ts +2 -2
- package/scripts/opportunity-scan.ts +1 -1
- package/scripts/release-loop/auto-approve-node.ts +21 -4
- package/scripts/release-loop/checklist-gate-node.ts +2 -1
- package/scripts/release-loop/cut-branch.ts +84 -0
- package/scripts/release-loop/gate-node.ts +22 -15
- package/scripts/release-loop/mac-smoke-node.ts +229 -0
- package/scripts/release-loop/node-verdict.ts +3 -3
- package/scripts/release-loop/ops-upgrade-node.ts +47 -6
- package/scripts/release-loop/publish-node.ts +4 -1
- package/scripts/release-loop/tui-node-checks.ts +42 -0
- package/scripts/release-loop/tui-sim-node.ts +32 -8
- package/scripts/release-loop/unattended-release.ts +5 -3
- package/scripts/release-loop/version-node.ts +74 -13
- package/scripts/signal-digest-cycle.ts +2 -7
- package/scripts/signal-digest-photo.ts +11 -0
- package/scripts/tech1-public-measure.ts +94 -0
- package/scripts/telegram-inject.ts +14 -6
- package/scripts/test-diet/node.ts +1 -1
- package/scripts/test-diet/remeasure-list.ts +112 -0
- package/scripts/tui-regress.ts +2 -2
- package/scripts/ux/demo-rehearsal.ts +247 -0
- package/scripts/ux/demo-seed.ts +108 -0
- package/scripts/ux/lib/rehearsal-verdict.ts +80 -0
- package/skills/diagram-master/SKILL.md +366 -0
- package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
- package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
- package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
- package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
- package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
- package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
- package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
- package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
- package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
- package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
- package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
- package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
- package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
- package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
- package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
- package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
- package/skills/diagram-master/references/examples/README.md +69 -0
- package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
- package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
- package/skills/diagram-master/references/pyproject.toml +16 -0
- package/skills/diagram-master/references/quality-checklist.md +33 -0
- package/skills/diagram-master/references/routing-guide.md +164 -0
- package/skills/diagram-master/references/uv.lock +1356 -0
- package/skills/google-workspace/SKILL.md +33 -0
- package/skills/google-workspace/scripts/gws-safe.sh +177 -0
- package/skills/grill-me/SKILL.md +1 -1
- package/skills/lecture-note-digitizer/SKILL.md +926 -0
- package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
- package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
- package/skills/lecture-note-digitizer/references/html-template.md +167 -0
- package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
- package/skills/omni-crawl/SKILL.md +21 -11
- package/skills/omni-crawl/scripts/main.ts +6 -6
- package/skills/omni-crawl/src/router.ts +3 -3
- package/skills/omni-digest/SKILL.md +17 -9
- package/skills/omni-digest/digest.md +2 -2
- package/skills/omni-digest/src/fetch.ts +30 -3
- package/skills/pitch-deck/SKILL.md +2 -2
- package/skills/pitch-deck/template.html +2 -2
- package/skills/youtube-master/SKILL.md +163 -0
- package/skills/youtube-master/package-lock.json +558 -0
- package/skills/youtube-master/package.json +13 -0
- package/skills/youtube-master/references/study-note-template.md +124 -0
- package/skills/youtube-master/scripts/main.ts +435 -0
- package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
- package/skills/youtube-master/src/audio.ts +63 -0
- package/skills/youtube-master/src/domain-staging.ts +50 -0
- package/skills/youtube-master/src/env.ts +36 -0
- package/skills/youtube-master/src/obsidian.ts +155 -0
- package/skills/youtube-master/src/router.ts +110 -0
- package/skills/youtube-master/src/stt.ts +199 -0
- package/skills/youtube-master/src/study-note.ts +175 -0
- package/skills/youtube-master/src/summarize.ts +358 -0
- package/skills/youtube-master/src/transcript.ts +76 -0
- package/skills/youtube-master/src/types.ts +91 -0
- package/skills/youtube-master/src/util.ts +93 -0
- package/skills/youtube-master/src/youtube.ts +70 -0
- package/skills/youtube-master/tsconfig.json +13 -0
- package/src/acp/server.ts +5 -2
- package/src/agent-mission/driver.ts +215 -23
- package/src/agent-mission/pty-decision.ts +71 -0
- package/src/agent-mission/review-loop.ts +30 -0
- package/src/autopilot/build/llm-conflict-merge.ts +16 -3
- package/src/autopilot/pty-control-loop.ts +4 -1
- package/src/autopilot/tool-registry.ts +2 -0
- package/src/boot/daemon-prompt-turn.ts +5 -0
- package/src/boot/daemon-runtime.ts +9 -3
- package/src/boot/daemon-tools/web-search.ts +3 -0
- package/src/card-followup/core.ts +109 -0
- package/src/chat/index.ts +2 -0
- package/src/cli/drive-input-jail.ts +101 -0
- package/src/cli/hooks-cli.ts +17 -3
- package/src/cli/make-cli.ts +43 -0
- package/src/cli/persona-cli.ts +98 -9
- package/src/cli/plugin-cli.ts +31 -22
- package/src/cli/pod-cli.ts +36 -9
- package/src/cli/pod-memory-advice.ts +35 -0
- package/src/cli/pr-cli.ts +51 -15
- package/src/cli/pty-drive-cli.ts +41 -7
- package/src/cli/pty-drive-verdict.ts +40 -0
- package/src/cli/release-cli.ts +63 -10
- package/src/cli/setup-cli.ts +43 -1
- package/src/cli/skills-cli.ts +17 -1
- package/src/context-bus/claude-hooks-install.ts +10 -0
- package/src/context-bus/context-now-surfaces.ts +65 -0
- package/src/context-bus/context-now.ts +104 -0
- package/src/context-bus/coord-events.ts +2 -2
- package/src/context-bus/external-events.ts +52 -0
- package/src/context-bus/long-term-memory.ts +108 -0
- package/src/context-bus/nightly-condense.ts +153 -0
- package/src/context-bus/session-events.ts +35 -0
- package/src/dashboard/dashboard-status-lines.ts +2 -0
- package/src/dashboard/index.ts +17 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +31 -1
- package/src/decisions/decision-cards.ts +10 -3
- package/src/decisions/decision-ledger.ts +13 -5
- package/src/discord/sprint21-runtime.ts +5 -1
- package/src/discord-self-message.ts +32 -0
- package/src/discord-slash-wire.ts +5 -1
- package/src/discord.ts +17 -1
- package/src/domains/core-tools.ts +3 -2
- package/src/domains/outbound-alert.ts +105 -32
- package/src/domains/outbound-log-probe.ts +8 -0
- package/src/domains/telegram-kind-route.ts +51 -13
- package/src/exec-requests/default-outputs.ts +25 -0
- package/src/exec-requests/planner.ts +10 -2
- package/src/exec-requests/runner.ts +20 -6
- package/src/exec-requests/store.ts +3 -0
- package/src/execution-loop/launch-gate.ts +109 -0
- package/src/field/field-reel.ts +5 -1
- package/src/field-note/index.ts +201 -0
- package/src/field-note/telegram.ts +142 -0
- package/src/field-note/transcribe.ts +248 -0
- package/src/graph-kinds/registry.ts +3 -3
- package/src/graph-runner/graph-cli.ts +61 -1
- package/src/graph-runner/graph-grow-llm.ts +47 -0
- package/src/graph-runner/graph-grow.ts +50 -0
- package/src/graph-runner/runner.ts +329 -33
- package/src/grok/agent-search.ts +8 -2
- package/src/guardian/secret-exposure-scan.ts +101 -0
- package/src/harness/harness-cli-command.ts +375 -13
- package/src/harness/harness-pod-dispatch.ts +43 -23
- package/src/harness/harness-seams.ts +38 -4
- package/src/harness/harness-stop.ts +23 -4
- package/src/harness/launch-registry.ts +91 -0
- package/src/harness/process-garbage.ts +5 -3
- package/src/hooks/consult-intake.ts +153 -0
- package/src/hooks/dispatch.ts +82 -0
- package/src/hooks/expose.ts +254 -0
- package/src/hooks/github-shadow.ts +108 -0
- package/src/hooks/providers.ts +71 -5
- package/src/hooks/queue.ts +1 -1
- package/src/hooks/receiver.ts +94 -16
- package/src/index.ts +76 -14
- package/src/intake-plane/categorize.ts +18 -46
- package/src/intake-plane/discord-seat-work.ts +38 -2
- package/src/intake-plane/front-route-classifier.ts +33 -39
- package/src/intake-plane/persona-answer.ts +30 -0
- package/src/intake-plane/runtime-callables.ts +8 -1
- package/src/intake-plane/telegram-seat-work.ts +36 -2
- package/src/intake-plane/wish-card.ts +33 -0
- package/src/intake-plane/wish-folder.ts +67 -0
- package/src/intent-gate/gate.ts +30 -10
- package/src/live/detail-switch.ts +5 -0
- package/src/llm/difficulty.ts +57 -0
- package/src/llm/judge-layer.ts +101 -0
- package/src/llm/mission-router.ts +33 -19
- package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
- package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
- package/src/loops/contract/examples/steward.loop.yaml +50 -0
- package/src/loops/contract/loop-agent.schema.json +138 -0
- package/src/loops/contract/validate.ts +64 -0
- package/src/loops/registry.ts +20 -6
- package/src/market/signed-index.ts +4 -0
- package/src/maturity/bot-command-maturity.ts +45 -0
- package/src/maturity/feature-maturity.ts +27 -4
- package/src/model-tier/index.ts +2 -2
- package/src/model-tier/tier-resolver.ts +20 -20
- package/src/model-tier/types.ts +6 -6
- package/src/mss/logging/log-store.ts +15 -0
- package/src/nexus/api/config-model-tier.ts +5 -4
- package/src/nexus/api/fabric-plans.ts +53 -0
- package/src/nexus/api/harness-api.ts +5 -1
- package/src/nexus/api/health.ts +2 -0
- package/src/nexus/api/http-server.ts +67 -8
- package/src/nexus/api/inside-events.ts +226 -0
- package/src/nexus/api/meta-api.ts +21 -8
- package/src/nexus/api/missions.ts +6 -1
- package/src/nexus/api/ops-seats.ts +33 -0
- package/src/nexus/api/outbound-report.ts +40 -7
- package/src/nexus/api/outputs-route.ts +44 -0
- package/src/nexus/api/personas.ts +95 -53
- package/src/nexus/api/seat-requests.ts +44 -2
- package/src/nexus/api/sessions-store.ts +17 -38
- package/src/nexus/api/sub-seat-charters.ts +34 -0
- package/src/nexus/api/tabs-mutations.ts +3 -1
- package/src/nexus/api/task-cards-api.ts +19 -0
- package/src/nexus/api/trace.ts +18 -6
- package/src/nexus/api/workflow-history.ts +88 -0
- package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
- package/src/nexus/api/workflows.ts +132 -6
- package/src/nexus/index.ts +2 -0
- package/src/nexus/kinds/webterm.ts +2 -1
- package/src/nexus/outbound/delivery-ledger.ts +17 -8
- package/src/nexus/outbound/router.ts +8 -3
- package/src/nexus/webterm/pty.ts +6 -2
- package/src/onboarding/cli-auth-status.ts +80 -0
- package/src/onboarding/voice-ai.ts +3 -3
- package/src/org/seat-budget.ts +48 -0
- package/src/org/stall-escalation.ts +63 -0
- package/src/outputs/ledger.ts +120 -0
- package/src/persona/persona-todo.ts +79 -0
- package/src/persona/presets.ts +123 -2
- package/src/persona/team-set.ts +155 -0
- package/src/plugins/install/plugin-install.ts +14 -0
- package/src/plugins/maker/market-bundle.ts +110 -0
- package/src/plugins/maker/plugin-maker.ts +254 -11
- package/src/plugins/maker/wizard-generate.ts +103 -0
- package/src/pod-lease/admission.ts +150 -0
- package/src/pod-lease/dependency-state.ts +85 -0
- package/src/pod-lease/host-lease.ts +127 -0
- package/src/project/project-suggestion.ts +16 -0
- package/src/project/session-context.ts +24 -0
- package/src/release-loop/checklist.ts +17 -5
- package/src/release-loop/feature-store.ts +29 -13
- package/src/release-loop/landed-but-yellow.ts +48 -0
- package/src/release-loop/next-md-merge.ts +58 -0
- package/src/release-loop/release-note.ts +59 -4
- package/src/seat-dispatch/seat-ask.ts +130 -0
- package/src/seat-dispatch/seat-questions.ts +100 -0
- package/src/seat-loop/seat-loop.ts +709 -29
- package/src/seat-loop/seat-report.ts +37 -2
- package/src/self-dev/dev-cli.ts +4 -1
- package/src/self-dev/dev-pipeline.ts +37 -1
- package/src/self-dev/draft-sweep.ts +79 -40
- package/src/self-dev/draft-triage-rules.ts +62 -7
- package/src/self-dev/fabric-plan-core.ts +297 -0
- package/src/self-dev/orchestrate.ts +36 -4
- package/src/self-dev/release-path-guard.ts +62 -0
- package/src/self-dev/shard-aggregate.ts +230 -0
- package/src/self-dev/shard-placement.ts +60 -0
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-pod-run.ts +77 -0
- package/src/self-dev/shard-run.ts +105 -0
- package/src/self-implement/budget-gate.ts +29 -12
- package/src/self-implement/gate-baseline.ts +1 -1
- package/src/self-implement/gate-candidate-ranking.ts +60 -0
- package/src/self-implement/gate-cli.ts +40 -1
- package/src/self-implement/gate-scope.ts +44 -13
- package/src/self-implement/graph-variant.ts +171 -0
- package/src/self-implement/harness-policy-gates.ts +1 -1
- package/src/self-implement/headless-elanous-driver.ts +27 -3
- package/src/self-implement/host-regate.ts +22 -1
- package/src/self-implement/importer-test-index.ts +2 -1
- package/src/self-implement/l8-merge-queue.ts +130 -0
- package/src/self-implement/orchestrator.ts +257 -9
- package/src/self-implement/route-consumer-test-index.ts +122 -0
- package/src/self-implement/seams.ts +72 -11
- package/src/self-implement/test-seams.ts +2 -0
- package/src/self-implement/uncommitted-work.ts +59 -0
- package/src/session/index.ts +36 -13
- package/src/skills/gift-install.ts +215 -0
- package/src/skills/tools/web-search.ts +4 -1
- package/src/steward/launch.ts +42 -26
- package/src/steward/steward-cards.ts +17 -9
- package/src/steward/triage.ts +46 -14
- package/src/task-cards/card-cli.ts +25 -1
- package/src/task-orchestrator/mission.ts +5 -0
- package/src/task-orchestrator/store.ts +12 -3
- package/src/task-orchestrator/surfaces/pod-command-job.ts +43 -17
- package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
- package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +222 -40
- package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
- package/src/task-orchestrator/types.ts +2 -0
- package/src/telegram-card-followup.ts +16 -96
- package/src/telegram-commands.ts +31 -1
- package/src/telegram-project-command.ts +145 -0
- package/src/telegram-report.ts +21 -17
- package/src/telegram.ts +61 -8
- package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
- package/src/user-config.ts +110 -24
- package/src/version/packed-revision.json +1 -1
- package/src/web-search/grok.ts +7 -1
- package/src/web-search/index.ts +28 -1
- package/src/web-search/provider.ts +4 -0
- package/src/web-search/x-intent.ts +5 -0
- package/src/workflow-runtime/executor.ts +277 -47
- package/src/workflow-runtime/index.ts +1 -0
- package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
- package/src/workflow-runtime/plugin-kind-node.ts +1 -1
- package/src/workflow-runtime/schema.ts +79 -4
- package/src/workflow-runtime/types.ts +35 -4
- package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
- package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
- package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
- /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → -6XrAoD3eU7NyMHAE4xPS}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { GateCallerReason } from './gate-scope.js';
|
|
2
|
+
|
|
3
|
+
export interface GateCallerCandidate {
|
|
4
|
+
readonly file: string;
|
|
5
|
+
readonly reasons: readonly GateCallerReason[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Path segments between `file` and the nearest changed path's directory (0 = same directory). */
|
|
9
|
+
function directoryDistance(file: string, changedPaths: readonly string[]): number {
|
|
10
|
+
const dir = file.split('/').slice(0, -1);
|
|
11
|
+
let best = Infinity;
|
|
12
|
+
for (const changed of changedPaths) {
|
|
13
|
+
const other = changed.split('/').slice(0, -1);
|
|
14
|
+
let shared = 0;
|
|
15
|
+
while (shared < dir.length && shared < other.length && dir[shared] === other[shared]) shared += 1;
|
|
16
|
+
best = Math.min(best, dir.length - shared + other.length - shared);
|
|
17
|
+
}
|
|
18
|
+
return best;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Rank gate caller tests by closeness to the change, nearest first (GATE-CALLERS2 — the cap keeps the head).
|
|
23
|
+
* A `route` candidate names a route on a changed diff line, so it ranks with touched tests (distance 0);
|
|
24
|
+
* otherwise the distance is the shortest reverse-import path from a changed file (direct importer = 1,
|
|
25
|
+
* unreachable = after every reachable candidate). Equal distances prefer the test nearest a changed file
|
|
26
|
+
* in the directory tree, then numeric-aware path order. Inputs are not modified.
|
|
27
|
+
* `importersByFile` maps each imported file to its immediate importers (tests or sources).
|
|
28
|
+
*/
|
|
29
|
+
export function rankGateCallerCandidates<T extends GateCallerCandidate>(
|
|
30
|
+
changedPaths: readonly string[],
|
|
31
|
+
candidates: readonly T[],
|
|
32
|
+
importersByFile: ReadonlyMap<string, readonly string[]>,
|
|
33
|
+
): T[] {
|
|
34
|
+
const distances = new Map<string, number>();
|
|
35
|
+
const queue: string[] = [];
|
|
36
|
+
for (const path of changedPaths) {
|
|
37
|
+
if (distances.has(path)) continue;
|
|
38
|
+
distances.set(path, 0);
|
|
39
|
+
queue.push(path);
|
|
40
|
+
}
|
|
41
|
+
for (let index = 0; index < queue.length; index += 1) {
|
|
42
|
+
const source = queue[index]!;
|
|
43
|
+
const nextDistance = distances.get(source)! + 1;
|
|
44
|
+
for (const importer of importersByFile.get(source) ?? []) {
|
|
45
|
+
if (distances.has(importer)) continue;
|
|
46
|
+
distances.set(importer, nextDistance);
|
|
47
|
+
queue.push(importer);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const keys = new Map(candidates.map((candidate) => [candidate, {
|
|
51
|
+
distance: candidate.reasons.includes('route') ? 0 : distances.get(candidate.file) ?? Infinity,
|
|
52
|
+
directory: directoryDistance(candidate.file, changedPaths),
|
|
53
|
+
}]));
|
|
54
|
+
return [...candidates].sort((left, right) => {
|
|
55
|
+
const a = keys.get(left)!;
|
|
56
|
+
const b = keys.get(right)!;
|
|
57
|
+
return (a.distance - b.distance || 0) || (a.directory - b.directory || 0)
|
|
58
|
+
|| left.file.localeCompare(right.file, undefined, { numeric: true });
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -15,16 +15,19 @@ import { resolveGateScope } from './gate-scope.js';
|
|
|
15
15
|
import { debug } from '../debug/log.js';
|
|
16
16
|
import { buildDocumentGuardianIndex, formatDocumentGuardians } from './document-guardian-index.js';
|
|
17
17
|
import { buildImporterTestIndex, isTestPath, type ImporterTestIndex } from './importer-test-index.js';
|
|
18
|
+
import { buildRouteConsumerTestIndex } from './route-consumer-test-index.js';
|
|
18
19
|
import { gitChangedFiles, observeGateBaselineLocation } from './seams.js';
|
|
19
20
|
import {
|
|
20
21
|
collectBaseLandingCommits,
|
|
21
22
|
overlapWithCurrentChanges,
|
|
22
23
|
} from '../cli/pr-granularity.js';
|
|
23
24
|
import { listWorktrees } from '../git-fs/worktree.js';
|
|
25
|
+
import { runShardedGateTests } from '../self-dev/shard-run.js';
|
|
24
26
|
|
|
25
27
|
interface SelfGateCliOptions {
|
|
26
28
|
base?: string;
|
|
27
29
|
pr?: string;
|
|
30
|
+
shards?: number;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
interface ProcessResult {
|
|
@@ -74,6 +77,7 @@ interface SelfGateCliDeps {
|
|
|
74
77
|
readFile?: (path: string) => string | undefined;
|
|
75
78
|
runTests?: (cwd: string, files: readonly string[]) => ProcessResult;
|
|
76
79
|
runBaseline?: (cwd: string, files: readonly string[], baseRef: string) => BaselineProcessResult;
|
|
80
|
+
runShards?: typeof runShardedGateTests;
|
|
77
81
|
runIsolationGate?: (out: GateOutput) => number;
|
|
78
82
|
runMockModuleRestoreGate?: (out: GateOutput) => number;
|
|
79
83
|
/** 모델 이름 하드코딩 래칫(🅕 #20521) — `pr land` 만 물고 하니스 무인 병합은 안 물면 위반이 main 에 들어가 남의 착지를 막는다(🅣 2026-09-25). */
|
|
@@ -571,11 +575,16 @@ function logGateCliBaseline(cwd: string, payload: GateCliBaselinePayload): void
|
|
|
571
575
|
|
|
572
576
|
export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, deps: SelfGateCliDeps = {}): SelfGateCliResult {
|
|
573
577
|
if (options.base && options.pr) throw new Error('use either --base <ref> or --pr <number>, not both');
|
|
578
|
+
if (options.shards !== undefined && (!Number.isSafeInteger(options.shards) || options.shards < 1)) throw new Error('invalid --shards count');
|
|
574
579
|
const selection = (deps.changedFiles ?? ((dir, input) => defaultChangedFiles(dir, input, deps.runCommand)))(cwd, options);
|
|
575
580
|
const exists = deps.exists ?? ((path) => existsSync(`${cwd}/${path}`));
|
|
576
581
|
const importerIndex = buildGateImporterTestIndex(selection.files, cwd, deps.runCommand);
|
|
577
582
|
const lookupFailed = importerIndex && 'lookupFailed' in importerIndex ? importerIndex.lookupFailed : undefined;
|
|
578
|
-
const
|
|
583
|
+
const availableIndex = importerIndex && !('lookupFailed' in importerIndex) ? importerIndex : undefined;
|
|
584
|
+
const routeIndex = availableIndex?.testPaths
|
|
585
|
+
? buildRouteConsumerTestIndex(cwd, availableIndex.testPaths, selection.files, selection.baseRef) : null;
|
|
586
|
+
const scope = resolveGateScope(selection.files, exists, availableIndex,
|
|
587
|
+
{ routeConsumerTestIndex: routeIndex ?? undefined });
|
|
579
588
|
const testFiles = [...(scope.testArgs ?? [])];
|
|
580
589
|
const unrunImporterTotal = lookupFailed ? null : (scope.importerTestsNotRun?.total ?? 0);
|
|
581
590
|
const importerLookupFailed = Boolean(lookupFailed);
|
|
@@ -601,6 +610,9 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
601
610
|
// 🚨 러너 우주 «밖» — 형제들과 같은 정책으로 «말만» 한다(`OBS-T418`).
|
|
602
611
|
formatUnrunnableChangeKinds(selection.files),
|
|
603
612
|
formatUnrunImporterTests(scope.importerTestsNotRun, lookupFailed),
|
|
613
|
+
`caller tests: ${lookupFailed ? `lookup failed (${lookupFailed})` : scope.callerTests.map(({ file, reasons }) => `${file} (${reasons.join('+')})`).join(', ') || (routeIndex?.lookupFailures.length ? 'route lookup incomplete' : '(none)')}`,
|
|
614
|
+
...(routeIndex?.lookupFailures.length ? [`⚠️ caller route base lookup failed — unmeasured: ${routeIndex.lookupFailures.map(({ source, reason }) => `${source} (${reason})`).join(', ')}`] : []),
|
|
615
|
+
...(scope.callerTestsOverflow.length ? [`⚠️ caller test cap exceeded — not run: ${scope.callerTestsOverflow.map(({ file, reasons }) => `${file} (${reasons.join('+')})`).join(', ')}`] : []),
|
|
604
616
|
changedTestCountNote(cwd, selection.files, selection.baseRef, deps.runCommand, deps.readFile),
|
|
605
617
|
];
|
|
606
618
|
if (options.pr) {
|
|
@@ -629,6 +641,33 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
629
641
|
return { exitCode: androidPassed && iosPassed && pwaPassed && policyPassed ? 0 : 1, lines, changedFiles: selection.files, testFiles: [], unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests };
|
|
630
642
|
}
|
|
631
643
|
|
|
644
|
+
if (options.shards !== undefined) {
|
|
645
|
+
const sharded = (deps.runShards ?? runShardedGateTests)(cwd, testFiles, selection.baseRef, options.shards);
|
|
646
|
+
lines.push(`shards: ${sharded.shards.length} (${sharded.shards.map((shard) => `${shard.id}=${shard.files.join(',')}`).join('; ')})`);
|
|
647
|
+
for (const attempt of sharded.attempts) lines.push(`shard attempt: ${attempt.shardId} #${attempt.attempt}`);
|
|
648
|
+
const { aggregate } = sharded;
|
|
649
|
+
if (aggregate.status === 'unmeasured') lines.push(`shards: unmeasured (${aggregate.retryShardIds.join(', ') || sharded.reason || 'no complete JUnit'})`);
|
|
650
|
+
else if (aggregate.report) {
|
|
651
|
+
const report = aggregate.report;
|
|
652
|
+
logGateCliBaseline(cwd, {
|
|
653
|
+
introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown,
|
|
654
|
+
preconditionUnmet: report.preconditionUnmet, timedOut: report.timedOut,
|
|
655
|
+
timeoutPassedAtBase: report.timeoutPassedAtBase, failures: report.failures.slice(0, 20),
|
|
656
|
+
baselineFiles: report.files, baselineStatus: report.baselineStatus, unrunImporterTotal, lookupFailed: importerLookupFailed,
|
|
657
|
+
});
|
|
658
|
+
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, formatGateBaselineNote(report, unrunImporterTotal ?? 0)));
|
|
659
|
+
} else {
|
|
660
|
+
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
|
|
661
|
+
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
662
|
+
}
|
|
663
|
+
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
664
|
+
return {
|
|
665
|
+
exitCode: aggregate.status !== 'passed' || !policyPassed || !androidPassed || !iosPassed || !pwaPassed ? 1 : 0,
|
|
666
|
+
lines, changedFiles: selection.files, testFiles, unverified: scope.unverified,
|
|
667
|
+
documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests,
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
632
671
|
const test = (deps.runTests ?? ((dir, files) => (deps.runCommand ?? defaultRunCommand)('bun', ['test', ...files], dir)))(cwd, testFiles);
|
|
633
672
|
const worktreeLog = formatProcessOutput(test);
|
|
634
673
|
if (test.status === 0 && !test.error) {
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
// → 유도 결과는 **반드시 존재하는 파일**이어야 한다.
|
|
30
30
|
|
|
31
31
|
import { importerTestsNotInRunSet, type ImporterTestIndex } from './importer-test-index.js';
|
|
32
|
+
import type { RouteConsumerTestIndex } from './route-consumer-test-index.js';
|
|
33
|
+
import { rankGateCallerCandidates } from './gate-candidate-ranking.js';
|
|
34
|
+
|
|
35
|
+
export const GATE_CALLER_TEST_LIMIT = 30;
|
|
36
|
+
export type GateCallerReason = 'import' | 'route';
|
|
32
37
|
|
|
33
38
|
/** 테스트 파일 판정(기존 `seams.ts` 정규식과 동일 — 어휘 분기 금지). */
|
|
34
39
|
const TEST_RE = /\.(test|spec)\.[cm]?[tj]sx?$/;
|
|
@@ -245,11 +250,7 @@ interface GateScopeDecision {
|
|
|
245
250
|
readonly unverified: readonly string[];
|
|
246
251
|
/** elanous 자체가 남긴 런타임 산출물. 미검증 사용자 변경에서 제외하되 경로를 보존한다. */
|
|
247
252
|
readonly elanousRuntimeArtifacts: readonly string[];
|
|
248
|
-
/** ⭐
|
|
249
|
-
* ⚠️ 직전 판본은 이 자리에 `unrunRelatedTests`(=실행집합에 없는 연관 테스트)를 뒀는데,
|
|
250
|
-
* 실행집합이 연관 테스트를 **전부 포함**하도록 바뀌었으므로 그 값은 **정의상 항상 빈 배열**이었다.
|
|
251
|
-
* 빈 배열을 보고 *"안 돈 게 없다"* 고 읽게 되지만 그건 사실 확인이 아니라 계산의 결과였다
|
|
252
|
-
* (관측이 사실 아닌 값을 나르는 형태). ⇒ **실제로 일어난 일**을 센다: 합집합이 구제한 파일들. */
|
|
253
|
+
/** ⭐ 편집되지 않았는데 함께 끌어와 돌린 연관 테스트(`changed-tests` 분기) — 합집합이 실제로 구제한 파일들. */
|
|
253
254
|
readonly pulledInRelatedTests: readonly string[];
|
|
254
255
|
/** 실행 집합에 없는, 변경 소스를 상대 import 하는 테스트. 색인이 주입되지 않으면 null. */
|
|
255
256
|
readonly importerTestsNotRun: {
|
|
@@ -258,6 +259,10 @@ interface GateScopeDecision {
|
|
|
258
259
|
readonly truncated: boolean;
|
|
259
260
|
readonly unresolvedRelativeSpecifiers: number;
|
|
260
261
|
} | null;
|
|
262
|
+
/** Selected reverse-dependent tests and why they were pulled into the gate. */
|
|
263
|
+
readonly callerTests: readonly { readonly file: string; readonly reasons: readonly GateCallerReason[] }[];
|
|
264
|
+
/** Caller tests exceeding the cap, retained in full for warning and diagnosis. */
|
|
265
|
+
readonly callerTestsOverflow: readonly { readonly file: string; readonly reasons: readonly GateCallerReason[] }[];
|
|
261
266
|
}
|
|
262
267
|
|
|
263
268
|
/**
|
|
@@ -274,7 +279,7 @@ export function resolveGateScope(
|
|
|
274
279
|
changed: readonly string[],
|
|
275
280
|
exists: (path: string) => boolean,
|
|
276
281
|
importerTestIndex?: ImporterTestIndex,
|
|
277
|
-
opts?: { mode?: GateScopeMode; isDeleted?: (path: string) => boolean },
|
|
282
|
+
opts?: { mode?: GateScopeMode; isDeleted?: (path: string) => boolean; routeConsumerTestIndex?: RouteConsumerTestIndex },
|
|
278
283
|
): GateScopeDecision {
|
|
279
284
|
// ⚠️ **실존 검증(리뷰 must-fix 4R)** — `gitChangedFiles` 는 `git diff --name-only HEAD` 라
|
|
280
285
|
// **삭제·rename 前 경로도 포함**한다. 그걸 그대로 `testArgs` 로 넘기면 필터가 아무것도 매치하지
|
|
@@ -328,18 +333,43 @@ export function resolveGateScope(
|
|
|
328
333
|
const observationFor = (runSet: readonly string[]) => importerTestIndex
|
|
329
334
|
? importerTestsNotInRunSet(importerTestIndex, userChanged, runSet)
|
|
330
335
|
: null;
|
|
331
|
-
const
|
|
336
|
+
const conventional = deriveRelatedTests(userChanged, exists);
|
|
337
|
+
const alreadySelected = new Set([...testFiles, ...conventional]);
|
|
338
|
+
const callers = new Map<string, Set<GateCallerReason>>();
|
|
339
|
+
for (const source of userChanged) {
|
|
340
|
+
for (const [reason, tests] of [
|
|
341
|
+
['import', importerTestIndex?.testsBySource.get(source) ?? []],
|
|
342
|
+
['route', opts?.routeConsumerTestIndex?.testsBySource.get(source) ?? []],
|
|
343
|
+
] as const) {
|
|
344
|
+
for (const test of tests) {
|
|
345
|
+
if (!exists(test) || alreadySelected.has(test)) continue;
|
|
346
|
+
const reasons = callers.get(test) ?? new Set<GateCallerReason>();
|
|
347
|
+
reasons.add(reason);
|
|
348
|
+
callers.set(test, reasons);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// GATE-CALLERS2 — the cap keeps the candidates closest to the change, not the alphabetically first.
|
|
353
|
+
const candidates = rankGateCallerCandidates(userChanged, [...callers].map(([file, reasons]) => ({ file, reasons: [...reasons] })),
|
|
354
|
+
importerTestIndex?.testsBySource ?? new Map());
|
|
355
|
+
const callerTests = candidates.slice(0, GATE_CALLER_TEST_LIMIT);
|
|
356
|
+
const callerTestsOverflow = candidates.slice(GATE_CALLER_TEST_LIMIT);
|
|
357
|
+
const runWithCallers = (tests: readonly string[]) => [...new Set([...tests, ...callerTests.map(({ file }) => file)])];
|
|
358
|
+
const base = { sourceFiles, documentPaths, ignoredOutsideSrc, missingTestFiles, elanousRuntimeArtifacts, callerTests, callerTestsOverflow,
|
|
332
359
|
unverified: [] as readonly string[], derived: [] as readonly string[], pulledInRelatedTests: [] as readonly string[] };
|
|
333
360
|
const withDocumentNonContribution = (runSet: readonly string[]) => ({
|
|
334
361
|
documentsWithoutDerivedTests: documentsWithoutDerivedTestsFor(runSet),
|
|
335
362
|
});
|
|
336
363
|
|
|
337
364
|
if (testFiles.length > 0) {
|
|
338
|
-
|
|
339
|
-
|
|
365
|
+
// Edited tests ⊕ every related test of the changed sources ⊕ capped callers (restored 10-04: #23467 narrowed this
|
|
366
|
+
// to edited tests only, so a co-located sibling of a changed source stopped running — 0.2.12 gate introduced).
|
|
367
|
+
const allRelatedTests = conventional;
|
|
368
|
+
const runSet = runWithCallers([...testFiles, ...allRelatedTests]);
|
|
340
369
|
// 편집된 테스트만 돌렸다면 빠졌을 것들 — 이 목록이 비어있지 않다는 것은 합집합이 실제로 구제했다는 뜻이다.
|
|
341
370
|
const pulledInRelatedTests = allRelatedTests.filter((f) => !testFiles.includes(f));
|
|
342
|
-
return { ...base, ...withDocumentNonContribution(runSet), testArgs: runSet, unverified: unverifiedFor(runSet), pulledInRelatedTests,
|
|
371
|
+
return { ...base, ...withDocumentNonContribution(runSet), testArgs: runSet, unverified: unverifiedFor(runSet), pulledInRelatedTests,
|
|
372
|
+
importerTestsNotRun: observationFor(runSet), skipTestStep: false, reason: 'changed-tests' };
|
|
343
373
|
}
|
|
344
374
|
if (userChanged.length === 0) {
|
|
345
375
|
// postsync 빈 범위는 기존 no-changes(깨끗함)와 다른 값이다. 일반 호출자는 계속 no-changes를 읽는다.
|
|
@@ -348,9 +378,10 @@ export function resolveGateScope(
|
|
|
348
378
|
if (nonDoc.length === 0) {
|
|
349
379
|
return { ...base, ...withDocumentNonContribution([]), importerTestsNotRun: observationFor([]), skipTestStep: true, reason: 'docs-only' };
|
|
350
380
|
}
|
|
351
|
-
const derived =
|
|
352
|
-
|
|
353
|
-
|
|
381
|
+
const derived = conventional;
|
|
382
|
+
const runSet = runWithCallers(derived);
|
|
383
|
+
if (runSet.length > 0) {
|
|
384
|
+
return { ...base, ...withDocumentNonContribution(runSet), derived, testArgs: runSet, unverified: unverifiedFor(runSet), importerTestsNotRun: observationFor(runSet), skipTestStep: false, reason: 'derived' };
|
|
354
385
|
}
|
|
355
386
|
// 실행 집합이 비었으므로 비문서 전부가 미검증이다.
|
|
356
387
|
return { ...base, ...withDocumentNonContribution([]), unverified: unverifiedFor([]), importerTestsNotRun: observationFor([]), skipTestStep: true, reason: 'no-related-tests' };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { applyGraphOverlays, type GraphOverlaySpec, type OverlayPatchOp, type OverlayRejection } from './graph-overlay-yaml.js';
|
|
3
|
+
import { edgeMapOf, graphVersionHash, type GraphEdgeSpec, type GraphNodeSpec, type GraphTemplateSpec } from './graph-yaml.js';
|
|
4
|
+
import { inspectPipelineGraph } from './pipeline-shape.js';
|
|
5
|
+
import { hasNodeKind } from '../graph-kinds/registry.js';
|
|
6
|
+
|
|
7
|
+
/** A proposed change to one existing outcome of a conditional route. Unconditional and fallback edges are protected. */
|
|
8
|
+
export interface GraphVariantRoute {
|
|
9
|
+
readonly from: string;
|
|
10
|
+
readonly outcome: string;
|
|
11
|
+
readonly to: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface GraphVariantGrowth {
|
|
15
|
+
readonly node: GraphNodeSpec;
|
|
16
|
+
readonly from: string;
|
|
17
|
+
readonly outcome: string;
|
|
18
|
+
readonly returnTo?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface GraphVariantPlan {
|
|
22
|
+
readonly maxVisits?: Readonly<Record<string, number>>;
|
|
23
|
+
readonly routes?: readonly GraphVariantRoute[];
|
|
24
|
+
readonly growth?: GraphVariantGrowth;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type GraphVariantRejection =
|
|
28
|
+
| { readonly kind: 'invalid-goal' }
|
|
29
|
+
| { readonly kind: 'unknown-node'; readonly node: string }
|
|
30
|
+
| { readonly kind: 'invalid-budget'; readonly node: string; readonly value: number }
|
|
31
|
+
| { readonly kind: 'protected-edge'; readonly from: string; readonly outcome: string }
|
|
32
|
+
| { readonly kind: 'unknown-outcome'; readonly from: string; readonly outcome: string }
|
|
33
|
+
| { readonly kind: 'duplicate-route'; readonly from: string; readonly outcome: string }
|
|
34
|
+
| { readonly kind: 'ambiguous-outcome'; readonly from: string; readonly outcome: string }
|
|
35
|
+
| { readonly kind: 'unreachable-terminal'; readonly node: string }
|
|
36
|
+
| { readonly kind: 'invalid-graph'; readonly defects: ReturnType<typeof inspectPipelineGraph> }
|
|
37
|
+
| { readonly kind: 'overlay-rejected'; readonly rejections: readonly OverlayRejection[] }
|
|
38
|
+
| { readonly kind: 'invalid-growth'; readonly reason: string };
|
|
39
|
+
|
|
40
|
+
export type GraphVariantResult =
|
|
41
|
+
| { readonly ok: true; readonly overlay: GraphOverlaySpec; readonly template: GraphTemplateSpec; readonly patches: readonly OverlayPatchOp[] }
|
|
42
|
+
| { readonly ok: false; readonly rejections: readonly GraphVariantRejection[] };
|
|
43
|
+
|
|
44
|
+
/** Pure, deterministic variant authoring. Never mutates the supplied template and never writes an overlay. */
|
|
45
|
+
export function createGraphVariant(input: {
|
|
46
|
+
readonly template: GraphTemplateSpec;
|
|
47
|
+
readonly goal: string;
|
|
48
|
+
readonly plan: GraphVariantPlan;
|
|
49
|
+
}): GraphVariantResult {
|
|
50
|
+
const { template, goal, plan } = input;
|
|
51
|
+
const known = new Set(template.nodes.map((node) => node.nodeId));
|
|
52
|
+
const rejections: GraphVariantRejection[] = [];
|
|
53
|
+
if (!/^g_[a-z0-9_-]+$/i.test(goal)) rejections.push({ kind: 'invalid-goal' });
|
|
54
|
+
if (plan.growth) {
|
|
55
|
+
const { node, from, outcome, returnTo } = plan.growth;
|
|
56
|
+
if (!node || typeof node !== 'object') return { ok: false, rejections: [{ kind: 'invalid-growth', reason: 'growth requires one new contracted node' }] };
|
|
57
|
+
const edgeIndex = template.edges.findIndex((edge) => edge.from === from);
|
|
58
|
+
const edge = template.edges[edgeIndex];
|
|
59
|
+
if (!known.has(from) || known.has(node.nodeId) || template.terminalNodes.includes(from) ||
|
|
60
|
+
typeof node.nodeId !== 'string' || !node.nodeId || typeof node.recipe !== 'string' || !node.recipe ||
|
|
61
|
+
typeof node.kind !== 'string' || !hasNodeKind('harness', node.kind) || !Number.isSafeInteger(node.maxVisits) || node.maxVisits < 1 ||
|
|
62
|
+
typeof node.contract?.tools !== 'string' || !node.contract.tools.trim() || !Array.isArray(node.contract.inputs) ||
|
|
63
|
+
!Array.isArray(node.contract.outputs) || typeof outcome !== 'string' || !outcome || !edge || edge.to !== undefined || edge.on !== 'outcome' ||
|
|
64
|
+
!edge.map || Object.hasOwn(edge.map, outcome) ||
|
|
65
|
+
template.edges.filter((candidate) => candidate.from === from).length !== 1 ||
|
|
66
|
+
typeof returnTo !== 'string' || !known.has(returnTo) || plan.routes?.length || Object.keys(plan.maxVisits ?? {}).length) {
|
|
67
|
+
rejections.push({ kind: 'invalid-growth', reason: 'growth requires one new contracted node, one missing conditional outcome and an existing return destination' });
|
|
68
|
+
}
|
|
69
|
+
if (rejections.length) return { ok: false, rejections };
|
|
70
|
+
const addedEdge: GraphEdgeSpec = { from: node.nodeId, to: returnTo as string };
|
|
71
|
+
const patches: OverlayPatchOp[] = [
|
|
72
|
+
{ op: 'add', path: '/nodes/-', value: node },
|
|
73
|
+
{ op: 'add', path: `/edges/${edgeIndex}/map/${outcome.replace(/~/g, '~0').replace(/\//g, '~1')}`, value: node.nodeId },
|
|
74
|
+
{ op: 'add', path: '/edges/-', value: addedEdge },
|
|
75
|
+
];
|
|
76
|
+
const normalized = JSON.stringify({ graph: graphVersionHash(template), goal, patches });
|
|
77
|
+
const overlay: GraphOverlaySpec = { overlayId: `variant-${createHash('sha256').update(normalized).digest('hex').slice(0, 16)}`,
|
|
78
|
+
target: template.graphId, stage: 'runtime', appliesWhen: `goal_key == ${goal}`, patch: patches };
|
|
79
|
+
// Existing YAML runner nodes predate contracts; only the newly proposed node must supply one.
|
|
80
|
+
const validationTemplate: GraphTemplateSpec = { ...template, nodes: template.nodes.map((existing) => ({
|
|
81
|
+
...existing, contract: existing.contract?.tools ? existing.contract : { inputs: [], tools: 'existing', outputs: [] },
|
|
82
|
+
})) };
|
|
83
|
+
const applied = applyGraphOverlays(validationTemplate, [overlay]);
|
|
84
|
+
if (!applied.ok) return { ok: false, rejections: [{ kind: 'overlay-rejected', rejections: applied.rejections }] };
|
|
85
|
+
const projected: GraphTemplateSpec = { ...applied.template, nodes: [...template.nodes, node] };
|
|
86
|
+
const edges = edgeMapOf(projected);
|
|
87
|
+
const reached = new Set<string>();
|
|
88
|
+
const pending = [projected.entryNode];
|
|
89
|
+
while (pending.length) {
|
|
90
|
+
const at = pending.pop()!;
|
|
91
|
+
if (reached.has(at)) continue;
|
|
92
|
+
reached.add(at);
|
|
93
|
+
pending.push(...(edges[at] ?? []));
|
|
94
|
+
}
|
|
95
|
+
const unreachable = projected.terminalNodes.filter((terminal) => !reached.has(terminal) || (edges[terminal]?.length ?? 0) !== 0);
|
|
96
|
+
if (unreachable.length) return { ok: false, rejections: unreachable.map((terminal) => ({ kind: 'unreachable-terminal', node: terminal })) };
|
|
97
|
+
return { ok: true, overlay, template: projected, patches };
|
|
98
|
+
}
|
|
99
|
+
const patches: OverlayPatchOp[] = [];
|
|
100
|
+
|
|
101
|
+
for (const [node, value] of Object.entries(plan.maxVisits ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) {
|
|
102
|
+
if (!known.has(node)) { rejections.push({ kind: 'unknown-node', node }); continue; }
|
|
103
|
+
if (!Number.isSafeInteger(value) || value < 1) { rejections.push({ kind: 'invalid-budget', node, value }); continue; }
|
|
104
|
+
const index = template.nodes.findIndex((candidate) => candidate.nodeId === node);
|
|
105
|
+
if (template.nodes[index]!.maxVisits !== value) patches.push({ op: 'replace', path: `/nodes/${index}/maxVisits`, value });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const seen = new Set<string>();
|
|
109
|
+
for (const route of [...(plan.routes ?? [])].sort((a, b) => {
|
|
110
|
+
const left = JSON.stringify([a.from, a.outcome, a.to]);
|
|
111
|
+
const right = JSON.stringify([b.from, b.outcome, b.to]);
|
|
112
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
113
|
+
})) {
|
|
114
|
+
if (!known.has(route.from)) { rejections.push({ kind: 'unknown-node', node: route.from }); continue; }
|
|
115
|
+
if (!known.has(route.to)) { rejections.push({ kind: 'unknown-node', node: route.to }); continue; }
|
|
116
|
+
const key = JSON.stringify([route.from, route.outcome]);
|
|
117
|
+
if (seen.has(key)) { rejections.push({ kind: 'duplicate-route', from: route.from, outcome: route.outcome }); continue; }
|
|
118
|
+
seen.add(key);
|
|
119
|
+
const matches = template.edges.filter((edge) => edge.from === route.from && edge.map && Object.hasOwn(edge.map, route.outcome));
|
|
120
|
+
// One patch addresses one edge, so an outcome declared on two conditional edges would validate a graph we do not return.
|
|
121
|
+
if (matches.length > 1) { rejections.push({ kind: 'ambiguous-outcome', from: route.from, outcome: route.outcome }); continue; }
|
|
122
|
+
const conditional = matches[0];
|
|
123
|
+
if (!conditional) {
|
|
124
|
+
const protectedEdge = template.edges.some((edge) => edge.from === route.from && (edge.to !== undefined || edge.fallback?.length));
|
|
125
|
+
rejections.push(protectedEdge
|
|
126
|
+
? { kind: 'protected-edge', from: route.from, outcome: route.outcome }
|
|
127
|
+
: { kind: 'unknown-outcome', from: route.from, outcome: route.outcome });
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const index = template.edges.indexOf(conditional);
|
|
131
|
+
if (conditional.map![route.outcome] !== route.to) {
|
|
132
|
+
// JSON Pointer escaping keeps even unusual, already-declared outcome labels addressable.
|
|
133
|
+
const label = route.outcome.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
134
|
+
patches.push({ op: 'replace', path: `/edges/${index}/map/${label}`, value: route.to });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (rejections.length > 0) return { ok: false, rejections };
|
|
138
|
+
|
|
139
|
+
const projected: GraphTemplateSpec = {
|
|
140
|
+
...template,
|
|
141
|
+
nodes: template.nodes.map((node) => ({ ...node, maxVisits: plan.maxVisits?.[node.nodeId] ?? node.maxVisits })),
|
|
142
|
+
edges: template.edges.map((edge) => edge.map === undefined ? edge : {
|
|
143
|
+
...edge,
|
|
144
|
+
map: Object.fromEntries(Object.entries(edge.map).map(([outcome, to]) => [outcome,
|
|
145
|
+
plan.routes?.find((route) => route.from === edge.from && route.outcome === outcome)?.to ?? to])),
|
|
146
|
+
}),
|
|
147
|
+
};
|
|
148
|
+
const edges = edgeMapOf(projected);
|
|
149
|
+
const defects = inspectPipelineGraph(edges, projected.entryNode);
|
|
150
|
+
const reached = new Set<string>();
|
|
151
|
+
const pending = [projected.entryNode];
|
|
152
|
+
while (pending.length) {
|
|
153
|
+
const node = pending.pop()!;
|
|
154
|
+
if (reached.has(node)) continue;
|
|
155
|
+
reached.add(node);
|
|
156
|
+
for (const to of edges[node] ?? []) pending.push(to);
|
|
157
|
+
}
|
|
158
|
+
const unreachable = projected.terminalNodes.filter((node) => !reached.has(node) || (edges[node]?.length ?? 0) !== 0);
|
|
159
|
+
if (unreachable.length > 0) return { ok: false, rejections: unreachable.map((node) => ({ kind: 'unreachable-terminal', node })) };
|
|
160
|
+
if (defects.length > 0) return { ok: false, rejections: [{ kind: 'invalid-graph', defects }] };
|
|
161
|
+
const normalized = JSON.stringify({ graph: graphVersionHash(template), goal, patches });
|
|
162
|
+
const overlayId = `variant-${createHash('sha256').update(normalized).digest('hex').slice(0, 16)}`;
|
|
163
|
+
const overlay: GraphOverlaySpec = { overlayId, target: template.graphId, stage: 'launch', appliesWhen: `goal_key == ${goal}`, patch: patches };
|
|
164
|
+
// Existing runner YAML nodes may predate contracts; the plan only changes routes and visits.
|
|
165
|
+
const validationTemplate: GraphTemplateSpec = { ...template, nodes: template.nodes.map((node) => ({
|
|
166
|
+
...node, contract: node.contract?.tools ? node.contract : { inputs: [], tools: 'existing', outputs: [] },
|
|
167
|
+
})) };
|
|
168
|
+
const applied = applyGraphOverlays(validationTemplate, [overlay]);
|
|
169
|
+
if (!applied.ok) return { ok: false, rejections: [{ kind: 'overlay-rejected', rejections: applied.rejections }] };
|
|
170
|
+
return { ok: true, overlay, template: projected, patches };
|
|
171
|
+
}
|
|
@@ -28,7 +28,7 @@ export function runHarnessPolicyGates(input: {
|
|
|
28
28
|
['mock-module-restore-gate', input.gates?.['mock-module-restore-gate'] ?? runMockModuleRestoreGate],
|
|
29
29
|
['model-hardcode-gate', input.gates?.['model-hardcode-gate'] ?? runModelHardcodeGate],
|
|
30
30
|
['daemon-port-gate', input.gates?.['daemon-port-gate'] ?? ((out) => runDaemonPortGate({ log: out.log, error: out.error, cwd: out.cwd, args: [] }))],
|
|
31
|
-
// LEAK1 — the
|
|
31
|
+
// LEAK1 — the same pre-export check as pr land; an unmeasured result is a nonzero failure, not a pass.
|
|
32
32
|
['public-export-leak', input.gates?.['public-export-leak'] ?? runPublicExportLeakGate],
|
|
33
33
|
];
|
|
34
34
|
const failures: Array<{ gate: GateName; lines: string[] }> = [];
|
|
@@ -58,11 +58,13 @@ import { childRunContextEnv, childProviderKeyEnv, childLlmSelectionEnv, type Chi
|
|
|
58
58
|
import { childToolProfile } from '../agent/tool-profile.js';
|
|
59
59
|
import { escalationAllowedForProvider } from './rework-policy.js';
|
|
60
60
|
import { getUserConfig, resolveActiveProvider, resolveRoleLlm } from '../user-config.js';
|
|
61
|
+
import { goalDifficultySignals, classifyGoalDifficulty, resolveImplementDifficulty } from '../llm/difficulty.js';
|
|
61
62
|
import { childNestEnv } from '../agent/nest-depth.js';
|
|
62
63
|
import { childPtyIdentityEnv } from '../agent/pty-identity.js';
|
|
63
64
|
import { elanousTuiSpawnOptions } from './elanous-tui-spawn.js';
|
|
64
65
|
import { describeGrokCredentialFreshness, readGrokTokenFreshness, type GrokCredentialFreshnessSnapshot } from '../acp/grok-auth.js';
|
|
65
66
|
import { debug } from '../debug/log.js';
|
|
67
|
+
import { observeExternalEvent } from '../context-bus/external-events.js';
|
|
66
68
|
import { sendOutbound } from '../domains/outbound-alert.js';
|
|
67
69
|
import { formatPtyLinkMessage, readReportOrigin } from './report-origin.js';
|
|
68
70
|
import { DETACHED_PROGRESS_FRAME_PREFIX, decodeDetachedProgressFrame } from '../harness/dispatch-detached.js';
|
|
@@ -920,6 +922,8 @@ export interface HeadlessGoalLoopPtyOptions {
|
|
|
920
922
|
cwd: string;
|
|
921
923
|
/** 이미 featurePrompt() 적용된 프롬프트(범위제한·클린빌드 앵커 포함). */
|
|
922
924
|
featurePrompt: string;
|
|
925
|
+
/** Original goal document before the execution prompt is decorated. */
|
|
926
|
+
goalDocument?: string;
|
|
923
927
|
configDir?: string;
|
|
924
928
|
/** ★ K run-identity — 이 실행이 속한 per-run join anchor. 미지정 시 상속(env) → 없으면 canonical mint
|
|
925
929
|
* (`perCallRunId`). 호출자(runSelfImplement)가 지정하면 **리워크 라운드가 하나의 runId 를 공유**해
|
|
@@ -1164,14 +1168,30 @@ export interface HeadlessGoalLoopPtyResult {
|
|
|
1164
1168
|
ptyId: string;
|
|
1165
1169
|
}
|
|
1166
1170
|
|
|
1171
|
+
export function pickImplementRoleForGoal(document: string): ReturnType<typeof resolveRoleLlm> | undefined {
|
|
1172
|
+
try {
|
|
1173
|
+
const config = getUserConfig();
|
|
1174
|
+
const role = resolveRoleLlm('implement', { config });
|
|
1175
|
+
if (config.harness?.difficultyPlacement !== true || role.source !== 'default') return role;
|
|
1176
|
+
const signals = goalDifficultySignals(document);
|
|
1177
|
+
const level = classifyGoalDifficulty(signals);
|
|
1178
|
+
const picked = resolveImplementDifficulty(role, level);
|
|
1179
|
+
try {
|
|
1180
|
+
debug.log('llm.difficulty', 'pick', { level, tier: picked.tier ?? null, signals });
|
|
1181
|
+
debug.log('harness.role-llm', 'difficulty-placement', { difficulty: level, tier: picked.tier, source: role.source });
|
|
1182
|
+
} catch { /* observation is fail-soft */ }
|
|
1183
|
+
return picked;
|
|
1184
|
+
} catch { return undefined; }
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1167
1187
|
export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions): Promise<HeadlessGoalLoopPtyResult> {
|
|
1168
1188
|
const childLlm = opts.childLlm;
|
|
1169
1189
|
if (childLlm && (typeof childLlm.provider !== 'string' || typeof childLlm.model !== 'string' || !childLlm.provider.trim() || !childLlm.model.trim())) {
|
|
1170
1190
|
throw new Error('childLlm.provider and childLlm.model must both be non-empty');
|
|
1171
1191
|
}
|
|
1172
|
-
// ⭐ B14 —
|
|
1192
|
+
// ⭐ B14 — 명시 자식 LLM · 런 단위 모델이 없을 때 골 난이도에 따라 역할 `implement` 기본 등급을 고른다.
|
|
1173
1193
|
const implementRole = !childLlm && !process.env.ELANOUS_LLM_MODEL?.trim()
|
|
1174
|
-
? (
|
|
1194
|
+
? pickImplementRoleForGoal(opts.goalDocument ?? opts.featurePrompt)
|
|
1175
1195
|
: undefined;
|
|
1176
1196
|
// ⭐ B9 — 승급 판정에 쓸 «유효 provider»: 명시 자식 → 역할 → 런 env → config(auto 는 실제 결정으로).
|
|
1177
1197
|
const effectiveChildProvider = childLlm?.provider ?? implementRole?.provider ?? process.env.ELANOUS_LLM_PROVIDER?.trim()
|
|
@@ -1202,6 +1222,7 @@ export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions):
|
|
|
1202
1222
|
const controlInboxDir = resolveControlInboxDir(space.id);
|
|
1203
1223
|
const { key: screenKey } = resolveHarnessScreenKey(space.id, opts.cwd);
|
|
1204
1224
|
const executionId = mintPtyId('self');
|
|
1225
|
+
const contextSource = `elanous://harness/${encodeURIComponent(runId)}/${encodeURIComponent(executionId)}`;
|
|
1205
1226
|
const boundaryRequestsEnv = harnessBoundaryRequestsEnv(executionId);
|
|
1206
1227
|
const boundaryResponsesEnv = harnessBoundaryResponsesEnv(executionId);
|
|
1207
1228
|
const boundaryRequestsPath = boundaryRequestsEnv.ELANOUS_HARNESS_BOUNDARY_REQUESTS ?? '';
|
|
@@ -1213,6 +1234,8 @@ export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions):
|
|
|
1213
1234
|
const emitDone = (data: Record<string, unknown>): void => {
|
|
1214
1235
|
if (doneEmitted) return;
|
|
1215
1236
|
doneEmitted = true;
|
|
1237
|
+
if (spawned) observeExternalEvent({ origin: 'harness-child', kind: 'finished',
|
|
1238
|
+
summary: `Harness child finished: ${String(data.exitReason ?? 'unknown').slice(0, 60)}`, source: contextSource });
|
|
1216
1239
|
debug.log('self-implement', 'headless.done', {
|
|
1217
1240
|
ptyId: executionId,
|
|
1218
1241
|
runId,
|
|
@@ -1326,7 +1349,7 @@ export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions):
|
|
|
1326
1349
|
...(space ? harnessSpaceEnv(space.kind, space.id, runId) : {}), // 자식 goal-loop 자기인지(#4948 프리앰블) + ★K runId 명시 전파(captured-env 경계)
|
|
1327
1350
|
...harnessBoundaryEnv(opts.cwd), // ★ #4 명시 쓰기 경계 — worktree(cwd) 전파 → 자식 부팅 시 결정론 경계 활성(정본 오염 봉쇄)
|
|
1328
1351
|
...(opts.documentReferences?.length ? { ELANOUS_DOCUMENT_REFERENCES: JSON.stringify(opts.documentReferences) } : {}),
|
|
1329
|
-
// ⭐
|
|
1352
|
+
// ⭐ B14/E2 — 명시 자식 LLM·런 단위 모델이 없으면 골 난이도를 적용한 구현 역할 모델을 릴레이한다.
|
|
1330
1353
|
...childLlmSelectionEnv(childLlm ?? (implementRole ? { provider: implementRole.provider, model: implementRole.model, source: 'config' } : undefined)),
|
|
1331
1354
|
// 결정 2026-09-23 — 명시 childLlm 은 «같은 provider» 사다리 안에서만 한 칸 승급한다(없으면 승급 안 함).
|
|
1332
1355
|
// 미지정 경로는 기존 티어(codex sol 등)를 그대로 쓴다.
|
|
@@ -1351,6 +1374,7 @@ export async function runHeadlessGoalLoopPty(opts: HeadlessGoalLoopPtyOptions):
|
|
|
1351
1374
|
},
|
|
1352
1375
|
});
|
|
1353
1376
|
spawned = true;
|
|
1377
|
+
observeExternalEvent({ origin: 'harness-child', kind: 'started', summary: 'Harness child started', source: contextSource });
|
|
1354
1378
|
phase = 'initialization';
|
|
1355
1379
|
const ptyId = h.id;
|
|
1356
1380
|
// ⭐⭐ M5 — 그 판정을 «런 슈퍼바이저 레코드»로 올린다. 종전엔 경계 판정이 자기 로그에만 남아
|
|
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync,
|
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
5
|
import { debug } from '../debug/log.js';
|
|
6
|
+
import { releaseGitDiffPaths, releasePathHold, releasePathHoldShouldPost, releasePathHoldComment, releasePathHoldCommentsArgs, RELEASE_PATH_LABEL } from '../self-dev/release-path-guard.js';
|
|
6
7
|
import { detectTestInterference, parseFailureCount, runBunTest } from '../../scripts/detect-test-interference.js';
|
|
7
8
|
import { runTestInterferenceGate } from '../../scripts/ci-test-interference-gate.js';
|
|
8
9
|
|
|
@@ -158,6 +159,26 @@ export async function runHostRegate(input: HostRegateInput, deps: HostRegateDeps
|
|
|
158
159
|
base = run('git', ['merge-base', baseCommit, input.headCommit], worktree);
|
|
159
160
|
files = run('git', ['diff', '--name-only', base, input.headCommit], worktree).split('\n').filter(Boolean);
|
|
160
161
|
if (!files.length) throw new Error('changed files unavailable');
|
|
162
|
+
if (!input.verifyOnly) {
|
|
163
|
+
// --name-only lists only the destination of a rename. Inspect both sides without
|
|
164
|
+
// changing the gate's existing changed-file list or its test selection.
|
|
165
|
+
const guardPaths = releaseGitDiffPaths(run('git', ['diff', '--find-renames', '--name-status', '-z', base, input.headCommit], worktree));
|
|
166
|
+
const heldPath = releasePathHold(guardPaths);
|
|
167
|
+
if (heldPath) {
|
|
168
|
+
debug.log('self-dev.merge', 'release-path-hold', { number: input.prNumber, path: heldPath, label: RELEASE_PATH_LABEL, surface: 'host-regate' });
|
|
169
|
+
try {
|
|
170
|
+
const existing: unknown = JSON.parse(run('gh', ['label', 'list', '--search', RELEASE_PATH_LABEL, '--json', 'name'], input.repoRoot));
|
|
171
|
+
if (!Array.isArray(existing)) throw new Error('invalid label list');
|
|
172
|
+
if (!existing.some((item: unknown) => !!item && typeof item === 'object' && 'name' in item && item.name === RELEASE_PATH_LABEL)) {
|
|
173
|
+
run('gh', ['label', 'create', RELEASE_PATH_LABEL, '--color', 'D93F0B', '--description', 'Release path requires OP approval'], input.repoRoot);
|
|
174
|
+
}
|
|
175
|
+
run('gh', ['pr', 'edit', String(input.prNumber), '--add-label', RELEASE_PATH_LABEL], input.repoRoot);
|
|
176
|
+
} catch (error) { debug.log('self-dev.merge', 'release-path-annotation-failed', { number: input.prNumber, action: 'label', error: String(error) }); }
|
|
177
|
+
try { if (releasePathHoldShouldPost(() => JSON.parse(run('gh', releasePathHoldCommentsArgs(input.prNumber), input.repoRoot)))) run('gh', ['pr', 'comment', String(input.prNumber), '--body', releasePathHoldComment(heldPath)], input.repoRoot); }
|
|
178
|
+
catch (error) { debug.log('self-dev.merge', 'release-path-annotation-failed', { number: input.prNumber, action: 'comment', error: String(error) }); }
|
|
179
|
+
return result('failed', 'release-path-hold', `OP approval required: ${heldPath}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
161
182
|
// Materialize the proposed merge of this exact PR head into the observed base.
|
|
162
183
|
// A clean head checkout cannot expose integration breaks introduced by the base.
|
|
163
184
|
try { run('git', ['merge', '--no-ff', '--no-commit', input.headCommit], worktree); }
|
|
@@ -234,7 +255,7 @@ export async function runHostRegate(input: HostRegateInput, deps: HostRegateDeps
|
|
|
234
255
|
catch (e) { log('unmeasured', { pr: input.prNumber, files, os: process.platform, failedStep: 'cleanup', detail: String(e) }); }
|
|
235
256
|
try { release?.(); }
|
|
236
257
|
catch (e) { log('unmeasured', { pr: input.prNumber, files, os: process.platform, failedStep: 'lock', detail: String(e) }); }
|
|
237
|
-
if (failures.length) {
|
|
258
|
+
if (failures.length && failures[0]?.step !== 'release-path-hold') {
|
|
238
259
|
const { step, detail } = failures[0]!;
|
|
239
260
|
const body = `호스트 재게이트 실패(${process.platform}): ${step} — ${detail.replace(/\s+/g, ' ').slice(0, 180)}`;
|
|
240
261
|
try { run('gh', ['pr', 'comment', String(input.prNumber), '--body', body], input.repoRoot); }
|
|
@@ -6,6 +6,7 @@ const IMPORTER_TEST_DISPLAY_LIMIT = 20;
|
|
|
6
6
|
|
|
7
7
|
export interface ImporterTestIndex {
|
|
8
8
|
readonly testsBySource: ReadonlyMap<string, readonly string[]>;
|
|
9
|
+
readonly testPaths?: readonly string[];
|
|
9
10
|
readonly unresolvedRelativeSpecifiers: number;
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -105,7 +106,7 @@ export function buildImporterTestIndex(cwd: string, testPaths: readonly string[]
|
|
|
105
106
|
testsBySource.set(source, importers);
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
|
-
return { testsBySource, unresolvedRelativeSpecifiers };
|
|
109
|
+
return { testsBySource, testPaths, unresolvedRelativeSpecifiers };
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
export function importerTestsNotInRunSet(
|