elanous 0.2.14 → 0.2.16
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/chunks/{1307-6e7e0377c1db0bdc.js → 1307-b46d45b705e8c9ae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +1 -0
- package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9103-7a3ae7f60af3b99f.js → 9103-60fbef33e66f0a46.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-79c3ed84baaedd03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-7b2b4f378354869a.js → page-3cb52e5ea8fc2fa5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-a424ef80885d1743.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-c1e20d7d338713f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/{page-1512d91c7491ed62.js → page-482c5dbde699947c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-1e962b31d1f11081.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-a627db94ec6904a0.js → page-8c2d9526164f5d09.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-ffff6d819fbc6e0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-e6b84ab07d3567d5.js → page-a0e2a6d1bfb52fc5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c53598cfce6156f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/{page-fed69f9759d248d0.js → page-13a63953f53c6a23.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-15374909d8f1aebd.js → page-5d3c8429d04f3831.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-012a742f81218b01.js → page-3193bdc0bbab047a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-76270efaee638f17.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-99effd9d893a43dc.js → page-6107ca8ddd5e3bdd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{layout-938de57ae0315e46.js → layout-dce686e582c23937.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-d3d53b146416e422.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/{page-160089123a40dd91.js → page-1a61c7ca1ceb3ae7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/market/{page-629e1ede482ec6eb.js → page-51f811fa119308b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-dacff46049e1557e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-27e99b4e54a849d4.js → page-4167348049166852.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-de52e8fdf9095f7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-36a7d994f4ca0299.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-32cde713be47cddb.js → page-ca3952cd78a83ca2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-e7e10cd3386222e5.js → page-5b042736aa113756.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-acb749f1e432bcf3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-cd78862707999911.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-54b9ef8afe6278fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-e64caff084f7ce21.js → page-1ebfe049c640e171.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-db07eaffba0df7e3.js → page-57924393e3e4e539.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9e0ce6c8129fa641.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-31fa1ce4c4aff9ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-86f91034bd5cabe5.js → page-0f5cd57ca928f42b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-abe8e3b74bea1ffc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-4364ef9f4e7c7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/{page-ce4d8a1215ce53a3.js → page-d28573d6792b4275.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/{page-58043db78ba519ae.js → page-59f03fda76c03d22.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/{page-357750dfb91bf960.js → page-d751de5f8062ff5e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/term/{page-274703bc41b71333.js → page-fe1759f94003b32b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-d64c984e855c8c68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-86914b0dee8ab7f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/{page-3b7e821dc492bdfd.js → page-9afdee66b820c76e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d4aef67abf264874.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/{page-f8da5dc6f3752276.js → page-1ea64acadd704ace.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-2f810b18d89ecba6.js → page-3544f154c87b43ee.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-30c2073bfc21c004.js +1 -0
- package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +1 -0
- package/apps/pwa/out/_next/static/css/{04dabcbcc4bfa6db.css → 085673d826b98b62.css} +1 -1
- package/apps/pwa/out/_next/static/rv9cierV0jSOvDBm1g0XB/_buildManifest.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +15 -15
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +15 -15
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +15 -15
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +15 -15
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +15 -15
- package/apps/pwa/out/ceo/index.html +1 -0
- package/apps/pwa/out/ceo/index.txt +33 -0
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +15 -15
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +15 -15
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +15 -15
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +15 -15
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +15 -15
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +15 -15
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +15 -15
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +15 -15
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +15 -15
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +15 -15
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +15 -15
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +15 -15
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +15 -15
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +15 -15
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +15 -15
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +15 -15
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +15 -15
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +15 -15
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +15 -15
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +15 -15
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +16 -16
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +15 -15
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +15 -15
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +15 -15
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +15 -15
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +15 -15
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +15 -15
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +15 -15
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +15 -15
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +15 -15
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +15 -15
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +15 -15
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +15 -15
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +15 -15
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +15 -15
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +15 -15
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +15 -15
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +15 -15
- package/graphs/doc-gen/doc-gen.yaml +24 -0
- package/graphs/doc-gen/recipes.yaml +3 -0
- package/graphs/heal/heal-loop.yaml +1 -1
- package/graphs/implement-loop.yaml +1 -1
- package/graphs/orchestrator/orchestrator.yaml +7 -0
- package/graphs/orchestrator/recipes.yaml +3 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -2
- package/graphs/steward/recipes.yaml +2 -1
- package/package.json +1 -1
- package/scripts/brand/check.ts +7 -5
- package/scripts/ci-public-export-import-gate.ts +154 -0
- package/scripts/ci-test-interference-gate.ts +5 -1
- package/scripts/ci-typecheck-changed.ts +82 -31
- package/scripts/docs/doc-rot.ts +164 -0
- package/scripts/docs/generate-graph-anatomy.ts +437 -0
- package/scripts/docs-cli-check.ts +4 -4
- package/scripts/expose-rubric-suggest.ts +18 -12
- package/scripts/goals/goal-census.ts +343 -0
- package/scripts/lecture-note/node.ts +31 -11
- package/scripts/lessons/handbook-page.ts +30 -3
- package/scripts/marketing/generate-ax-brief.ts +140 -0
- package/scripts/marketing/generate-feature-map.ts +118 -0
- package/scripts/measure/author-section-contribution.ts +84 -0
- package/scripts/release-loop/checklist-gate-node.ts +53 -14
- package/scripts/release-loop/cut-branch.ts +43 -13
- package/scripts/release-loop/gate-node.ts +82 -14
- package/scripts/release-loop/vault-note-node.ts +257 -8
- package/scripts/release-story/draft.ts +57 -9
- package/scripts/rhythm/daily.ts +263 -76
- package/scripts/rhythm/monthly.ts +97 -0
- package/scripts/rhythm/weekly.ts +30 -9
- package/scripts/smart-merge/resync-shadow.ts +147 -0
- package/src/acp/client.ts +17 -2
- package/src/agent-env/profile.ts +161 -0
- package/src/agent-mission/driver.ts +51 -1
- package/src/agent-mission/supervisor-metrics-cli.ts +40 -0
- package/src/agent-mission/supervisor-metrics.ts +218 -0
- package/src/agent-substrate/pr-reviewer.ts +2 -0
- package/src/ask-user-question/pending-questions.ts +5 -0
- package/src/auth/github-app-token.ts +112 -13
- package/src/autopilot/build/llm-conflict-merge.ts +32 -6
- package/src/autopilot/track-agent-shadow.ts +2 -1
- package/src/briefing/brief-items.ts +276 -0
- package/src/budget/usage-outcomes.ts +204 -0
- package/src/claims/claims-render.ts +14 -5
- package/src/cli/agent-env-cli.ts +21 -0
- package/src/cli/brief-cli.ts +73 -0
- package/src/cli/decisions-cli.ts +9 -0
- package/src/cli/doctor-cli.ts +23 -1
- package/src/cli/doctor-node-modules.ts +147 -0
- package/src/cli/intake-cli.ts +46 -17
- package/src/cli/know-cli.ts +20 -0
- package/src/cli/logs-cli.ts +43 -1
- package/src/cli/pod-cli.ts +2 -0
- package/src/cli/pr-cli.ts +80 -12
- package/src/cli/release-cli.ts +66 -29
- package/src/cli/seat-requests-cli.ts +52 -0
- package/src/cli/self-update.ts +200 -1
- package/src/cli/usage-cli.ts +26 -0
- package/src/context-bus/context-now-public.ts +16 -6
- package/src/context-bus/context-now.ts +3 -1
- package/src/context-bus/coord-events.ts +6 -4
- package/src/decisions/decision-cards.ts +33 -7
- package/src/decisions/proact-meter.ts +286 -0
- package/src/decisions/proact1-lite.ts +86 -0
- package/src/decisions/web-push-decision-cards.ts +1 -1
- package/src/discord-self-message.ts +9 -0
- package/src/domains/alert-audit.ts +271 -0
- package/src/domains/core-tools.ts +4 -3
- package/src/domains/ops-facts-tool.ts +31 -1
- package/src/flow-loop/split.ts +24 -0
- package/src/harness/harness-cli-command.ts +147 -17
- package/src/harness/harness-incidents.ts +2 -0
- package/src/harness/harness-pod-dispatch.ts +67 -8
- package/src/harness/harness-queue.ts +380 -50
- package/src/harness/harness-seams.ts +13 -3
- package/src/harness/helper-repair.ts +218 -0
- package/src/harness/helper-scan.ts +27 -4
- package/src/harness/launch-stamp.ts +236 -0
- package/src/harness/ledger-write-guard-child.fixture.ts +12 -0
- package/src/harness/ledger-write-guard.ts +35 -0
- package/src/harness/nested-elanous-policy.ts +114 -0
- package/src/harness/pod-memory-policy.ts +15 -0
- package/src/harness/repository-name.ts +55 -0
- package/src/hq/fence-audit.ts +90 -0
- package/src/hq/hq.ts +70 -6
- package/src/hq/lease.ts +9 -7
- package/src/hq/move-plan.ts +126 -0
- package/src/hq/promote.ts +31 -0
- package/src/hq/transfer.ts +185 -0
- package/src/index.ts +189 -13
- package/src/intake-plane/check.ts +63 -0
- package/src/intake-plane/digest.ts +65 -21
- package/src/intake-plane/front-classifier.ts +6 -0
- package/src/intake-plane/items.ts +3 -2
- package/src/intake-plane/lens.ts +177 -0
- package/src/intake-plane/route.ts +145 -1
- package/src/knowledge/know-find.ts +105 -0
- package/src/llm.ts +75 -19
- package/src/loops/budget.ts +36 -5
- package/src/loops/checker.ts +2 -2
- package/src/loops/orchestrator/author-depth.ts +65 -9
- package/src/loops/orchestrator/author-input-check.ts +8 -3
- package/src/loops/orchestrator/author-ledger.ts +3 -1
- package/src/loops/orchestrator/finish-rate.ts +14 -3
- package/src/loops/orchestrator/seat-share.ts +56 -0
- package/src/loops/orchestrator/tick.ts +107 -29
- package/src/loops/orchestrator/traffic.ts +117 -11
- package/src/loops/registry.ts +142 -61
- package/src/maturity/bot-slash-catalog.ts +11 -2
- package/src/maturity/feature-maturity.ts +4 -3
- package/src/maturity/tui-slash-availability.ts +40 -0
- package/src/mss/logging/log-store.ts +35 -4
- package/src/nexus/api/http-server.ts +28 -14
- package/src/nexus/api/loop-edges.ts +173 -0
- package/src/nexus/api/schedules-read.ts +13 -0
- package/src/nexus/api/seat-requests.ts +79 -56
- package/src/oauth/overload-failover-launch.ts +75 -0
- package/src/oauth/overload-failover.ts +137 -0
- package/src/prompt-enhance/enhance.ts +6 -1
- package/src/release-loop/auto-start.ts +6 -3
- package/src/release-loop/checklist.ts +19 -5
- package/src/release-loop/feature-store.ts +59 -31
- package/src/release-loop/merged-pr-checklist.ts +125 -0
- package/src/release-loop/placement.ts +98 -29
- package/src/seat-dispatch/seat-ask.ts +33 -6
- package/src/seat-dispatch/seat-request-eligibility.ts +19 -0
- package/src/seat-dispatch/seat-request-ledger.ts +133 -0
- package/src/seat-loop/seat-loop.ts +215 -12
- package/src/self-dev/ask-launch-flow.ts +22 -1
- package/src/self-dev/authored-goal-trace.ts +64 -0
- package/src/self-dev/dev-cli.ts +19 -1
- package/src/self-dev/dev-pipeline.ts +14 -9
- package/src/self-dev/draft-sweep.ts +90 -10
- package/src/self-dev/draft-triage-rules.ts +25 -8
- package/src/self-dev/entrance-registry.ts +10 -6
- package/src/self-dev/old-door.ts +73 -0
- package/src/self-dev/orchestrate.ts +15 -1
- package/src/self-dev/review-provider-fallback.ts +6 -1
- package/src/self-dev/run-supervisor.ts +49 -2
- package/src/self-implement/app-api-budget.ts +166 -0
- package/src/self-implement/budget-gate.ts +7 -5
- package/src/self-implement/follow-up-goals.ts +289 -0
- package/src/self-implement/frozen-merges.ts +3 -2
- package/src/self-implement/goal-author.ts +50 -6
- package/src/self-implement/goal-clarification-escalation.ts +5 -0
- package/src/self-implement/heal-intake.ts +120 -2
- package/src/self-implement/heal-triage.ts +44 -0
- package/src/self-implement/host-regate.ts +9 -2
- package/src/self-implement/l8-merge-queue.ts +132 -0
- package/src/self-implement/orchestrator.ts +325 -47
- package/src/self-implement/pipeline-shape.ts +1 -1
- package/src/self-implement/revert-guard.ts +42 -7
- package/src/self-implement/run-ledger.ts +6 -0
- package/src/self-implement/run-status-mapping.ts +2 -0
- package/src/self-implement/seams.ts +45 -16
- package/src/self-implement/self-implement-cli.ts +1 -0
- package/src/self-implement/speed-claims.ts +338 -0
- package/src/session-runtime/index.ts +2 -0
- package/src/session-runtime/retry-api.ts +87 -0
- package/src/session-runtime/retry-policy.ts +107 -6
- package/src/steward/triage.ts +74 -3
- package/src/steward/working-backwards.ts +20 -2
- package/src/task-cards/card-cli.ts +25 -0
- package/src/task-cards/card-store.ts +5 -3
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +63 -48
- package/src/task-orchestrator/surfaces/pod-command-job.ts +84 -9
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +48 -0
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +4 -3
- package/src/task-orchestrator/surfaces/pod-ledger-prod-sink.ts +75 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +70 -9
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +37 -1
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +166 -46
- package/src/task-orchestrator/surfaces/self-implement.ts +7 -1
- package/src/telegram-commands.ts +5 -0
- package/src/telegram.ts +72 -4
- package/src/user-config.ts +64 -7
- package/src/version/packed-revision.json +1 -1
- package/src/workflow-runtime/nodes/bash.ts +9 -1
- package/apps/pwa/out/_next/static/chunks/4562-071d8bac44a01069.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-2df489622a52a33a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-74383f890f075511.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-c496bb16da85385f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-1abfe3aec3be6bdc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-fb260b9283dbf646.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-61ec1d2e92bdd50a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-fd7e200d4d83fbd7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-d47266766766d227.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2ce5471926761fdd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-e995d30f6800b6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-39f89c53038a51d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-5a753bb4ec0cc511.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-04250f0e2c0d03df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-341480ed8e3c1ea8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-8ac8d71c2adf9c8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e1e47d8d940aba3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-94dc383d3d54db1a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b3759cc14da80908.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-194dce4a83143fce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-35bdeae2e2c17147.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-16bef3da05a900c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-134c1bc762aee62c.js +0 -1
- package/apps/pwa/out/_next/static/css/2e33713c444d5b39.css +0 -1
- package/apps/pwa/out/_next/static/x6mjI6vqOkVVu0jFuDkz1/_buildManifest.js +0 -1
- /package/apps/pwa/out/_next/static/{x6mjI6vqOkVVu0jFuDkz1 → rv9cierV0jSOvDBm1g0XB}/_ssgManifest.js +0 -0
|
@@ -66,9 +66,11 @@ import { appendRunLedgerEntry, loadRunLedger, parseRunShardIdentity, queryRunCha
|
|
|
66
66
|
import { emitSessionEvent, type SessionEventInput } from '../context-bus/session-events.js';
|
|
67
67
|
import { decideLineageSupersede, lineageSupersedeCloseComment, type LineageSupersedeOpenDraft } from './lineage-supersede.js';
|
|
68
68
|
import { basename, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
69
|
+
import { homedir } from 'node:os';
|
|
69
70
|
import { enqueueControlMemo, readSoftStopRequestStatus, type SoftStopRequestRead } from '../harness/control-inbox.js';
|
|
70
71
|
import { debug } from '../debug/log.js';
|
|
71
72
|
import { recordFailureEvent } from './heal-intake.js';
|
|
73
|
+
import { classifyReworkCapExhaustion, type ReworkCapHealDecision } from './heal-triage.js';
|
|
72
74
|
import { releasePathHold, releasePathHoldComment, RELEASE_PATH_LABEL } from '../self-dev/release-path-guard.js';
|
|
73
75
|
import { emitDecision } from '../live/detail-switch.js';
|
|
74
76
|
import { reworkDecision } from './decision-events.js';
|
|
@@ -94,12 +96,33 @@ import type { DocumentReferenceStatus } from './self-implement-runtime.js';
|
|
|
94
96
|
import { DEV_PIPELINE_SINK_SURFACE } from './self-cli-sink-surface.js';
|
|
95
97
|
import { registerLoopAgentSafe, type LoopAgentInput } from '../domains/loop-agent-registry.js';
|
|
96
98
|
import { originObservationFields } from '../agent/origin-observation.js';
|
|
99
|
+
import { resolveLaunchStamp, type LaunchStamp } from '../harness/launch-stamp.js';
|
|
97
100
|
import { getHarnessSpace, normalizeSpaceId, resolveRunIdentity } from '../harness/harness-space.js';
|
|
98
101
|
import { getElanousConfigDir } from '../elanous-config-dir.js';
|
|
99
102
|
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
100
103
|
import { addNextMdReleaseNote, harnessReleaseNote, parseReleaseNoteSection, releaseNotesDir, renderReleaseNoteSection, writeReleaseNote, type ReleaseNoteFragment, type ReleaseNoteSection } from '../release-loop/release-note.js';
|
|
101
104
|
import { landingFreezeMessage } from '../release-loop/landing-freeze.js';
|
|
102
105
|
import { admitLandingMerge, owningRepoRoot } from './frozen-merges.js';
|
|
106
|
+
import { recordFollowUpOnMerge, type FollowUpMergeInput, type FollowUpSeams } from './follow-up-goals.js';
|
|
107
|
+
|
|
108
|
+
/** Merge result and exit stay untouched: a draft failure is one debug line. */
|
|
109
|
+
async function draftFollowUpAfterMerge(input: FollowUpMergeInput, followUp: FollowUpSeams | undefined): Promise<void> {
|
|
110
|
+
try {
|
|
111
|
+
await recordFollowUpOnMerge(input, {
|
|
112
|
+
...(followUp ? {
|
|
113
|
+
...(followUp.mode ? { mode: followUp.mode } : {}),
|
|
114
|
+
...(followUp.readDrafts ? { readDrafts: followUp.readDrafts } : {}),
|
|
115
|
+
...(followUp.appendDraft ? { appendDraft: followUp.appendDraft } : {}),
|
|
116
|
+
...(followUp.enqueue ? { enqueue: followUp.enqueue } : {}),
|
|
117
|
+
...(followUp.cellOwner ? { cellOwner: followUp.cellOwner } : {}),
|
|
118
|
+
...(followUp.stateRoot ? { stateRoot: followUp.stateRoot } : {}),
|
|
119
|
+
} : {}),
|
|
120
|
+
log: (category, event, data) => { debug.log(category, event, data); },
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
debug.log('self-implement.follow-up', 'draft-failed', { prNumber: input.prNumber, error: error instanceof Error ? error.message : String(error) });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
103
126
|
import { plannedSelfImplBranch } from '../harness/worktree-branch-prefix.js';
|
|
104
127
|
export { slugifyFeature } from '../harness/worktree-branch-prefix.js';
|
|
105
128
|
import { AUTO_REVIEW_LABEL, resolveAutoReviewLabels } from './context-capsule.js';
|
|
@@ -183,7 +206,7 @@ import type { RunOutcome, ReworkBudgetVerdict } from './run-outcome.js';
|
|
|
183
206
|
import type { EscalateTier } from './rework-policy.js';
|
|
184
207
|
import type { ClassifyShadowCallLLM } from './classify-shadow.js';
|
|
185
208
|
import { hasModuleLoadFailure, type GateTestFailure } from './gate-baseline.js';
|
|
186
|
-
import { commitWorktree, defaultBranchRef } from './seams.js';
|
|
209
|
+
import { commitWorktree, defaultBranchRef, preservationHasChanges } from './seams.js';
|
|
187
210
|
import { detectUncommittedWork } from './uncommitted-work.js';
|
|
188
211
|
import { spawnSync } from 'node:child_process';
|
|
189
212
|
import { blockedDraftDisposition } from './blocked-draft-policy.js';
|
|
@@ -1037,10 +1060,13 @@ export interface SelfImplementSeams {
|
|
|
1037
1060
|
/** Read-only cited-path observer. Omission uses the deterministic target-worktree filesystem observation. */
|
|
1038
1061
|
observeCitedPathFacts?: (mustFix: readonly string[], cwd: string, round: number) => MustFixCitedPathFact[] | Promise<MustFixCitedPathFact[]>;
|
|
1039
1062
|
/** PR을 열기 전에 보존할 산출물이 있는지 판별한다. `base` 대비 branch 고유 변경과 미커밋 변경을 함께 본다.
|
|
1040
|
-
* 생략 시
|
|
1063
|
+
* Pod에서 생략 시 실제 git 상태로 판정한다. */
|
|
1041
1064
|
preservationHasChanges?: (ctx: { cwd: string; base?: string }) => boolean | Promise<boolean>;
|
|
1042
1065
|
/** Test seam for blocked environment branch persistence; return whether the branch was pushed. */
|
|
1043
|
-
|
|
1066
|
+
/** Test seam — the worktree commit to pin before main sync (default `git rev-parse HEAD`). */
|
|
1067
|
+
headCommit?: (cwd: string) => string | undefined;
|
|
1068
|
+
/** `commit` pins the pushed state; without it the worktree HEAD is pushed. */
|
|
1069
|
+
preserveBlockedBranch?: (ctx: { cwd: string; branch: string; title: string; commit?: string }) => boolean | Promise<boolean>;
|
|
1044
1070
|
/** Hard-cap salvage evidence: a clean worktree and commits ahead of origin/main. */
|
|
1045
1071
|
readReworkSalvageEvidence?: (cwd: string) => Promise<ReworkSalvageEvidence>;
|
|
1046
1072
|
/** Starts exactly one detached `elanous dev --file <goal> --base <branch>` follow-up. */
|
|
@@ -1052,7 +1078,7 @@ export interface SelfImplementSeams {
|
|
|
1052
1078
|
/** PR 생성 뒤 런의 라운드 대화를 게시한다. 실패는 PR 개설을 되돌리지 않는다. */
|
|
1053
1079
|
postPrComment?: (opts: { number: number; body: string; cwd: string }) => Promise<void>;
|
|
1054
1080
|
addPrLabel?: (opts: { number: number; label: string; cwd: string }) => Promise<void>;
|
|
1055
|
-
readPrFiles?: (opts: { number: number; cwd: string }) => Promise<string[]>;
|
|
1081
|
+
readPrFiles?: (opts: { number: number; cwd: string; base?: string }) => Promise<string[]>;
|
|
1056
1082
|
/** PR의 base/head SHA와 관측된 PR base를 한 응답에서 고정한다. 미주입·실패·빈 SHA면 검사 대상을 증명할 수 없어 fail-closed로 PR을 열어 둔다. */
|
|
1057
1083
|
readPrCommitShas?: (opts: { number: number; cwd: string }) => Promise<{ baseCommit: string; headCommit: string; baseRefName?: string }>;
|
|
1058
1084
|
/** 고정한 base/head SHA 쌍의 unified diff. 가변 PR 조회를 다시 사용하면 ABA head 변경에 안전하지 않으므로 두 SHA는 필수 입력이다. */
|
|
@@ -1086,6 +1112,12 @@ export interface SelfImplementSeams {
|
|
|
1086
1112
|
readRunLedger?: (runId: string) => RunLedgerEntry[] | null | Promise<RunLedgerEntry[] | null>;
|
|
1087
1113
|
closeDraft: (input: { number: number; comment: string }) => void | Promise<void>;
|
|
1088
1114
|
};
|
|
1115
|
+
/**
|
|
1116
|
+
* FOLLOWUP-LOOP① — after a successful merge, leftover findings become one follow-up draft.
|
|
1117
|
+
* Tests inject every store. Omission writes nothing (no operational ledger, no queue).
|
|
1118
|
+
* Production `defaultSeams` fills the state-root ledger and, only in `live`, the harness queue.
|
|
1119
|
+
*/
|
|
1120
|
+
followUp?: FollowUpSeams;
|
|
1089
1121
|
/** ⑥ HITL 게이트 — PR open 전 승인. ★fail-closed: 생략/false 면 PR 안 열림(자동 승인 없음). review 동봉
|
|
1090
1122
|
* (2026-07-21) — HITL 이 리뷰 verdict 를 보고 판단, auto 모드는 verdict 로 자동 결정. */
|
|
1091
1123
|
approvePr?: (summary: { branch: string; gateLog?: string; implSummary: string; review?: SelfImplementReview }) => Promise<boolean>;
|
|
@@ -1995,6 +2027,8 @@ export interface SelfImplementOptions {
|
|
|
1995
2027
|
graphOverlays?: readonly GraphOverlaySpec[];
|
|
1996
2028
|
/** Validated, run-local graph variant injected at launch; rejected plans never start the pipeline. */
|
|
1997
2029
|
graphVariantPlan?: import('./graph-variant.js').GraphVariantPlan;
|
|
2030
|
+
/** Door this run was launched through. Absent means the ledger stamp reads `unknown`. */
|
|
2031
|
+
launch?: LaunchStamp;
|
|
1998
2032
|
/** ★ K run-identity — 이 self-implement 호출의 per-run join anchor. 미지정 시 상속(env)→canonical mint.
|
|
1999
2033
|
* 리워크 라운드 전부가 이 값을 공유한다(`elanous self run <runId>` 가 호출 전체를 조인). */
|
|
2000
2034
|
runId?: string;
|
|
@@ -2163,6 +2197,8 @@ export interface SelfImplementResult {
|
|
|
2163
2197
|
runId: string;
|
|
2164
2198
|
ok: boolean;
|
|
2165
2199
|
stage: SelfImplementStage;
|
|
2200
|
+
/** Verbatim must-fix findings retained on a review-blocked terminal result. */
|
|
2201
|
+
mustFix?: readonly string[];
|
|
2166
2202
|
/** Pipeline node that produced this terminal result. */
|
|
2167
2203
|
node: PipelineNodeId;
|
|
2168
2204
|
/** Structured terminal disposition for every normal run exit. */
|
|
@@ -2212,6 +2248,8 @@ export interface SelfImplementResult {
|
|
|
2212
2248
|
quotaExhaustionAssessment?: QuotaExhaustionAssessment;
|
|
2213
2249
|
/** Automatic merge was authorized before this run reached its terminal result. */
|
|
2214
2250
|
mergeApprovalReceived?: true;
|
|
2251
|
+
/** Completed implementation survived a failed main sync on the pushed branch. */
|
|
2252
|
+
harvestable?: true;
|
|
2215
2253
|
merged?: boolean;
|
|
2216
2254
|
/** Observed PR base for a confirmed merge; never inferred from the requested launch base. */
|
|
2217
2255
|
mergedBase?: string;
|
|
@@ -2619,7 +2657,9 @@ function prBody(feature: string, implSummary: string, gateLog?: string, review?:
|
|
|
2619
2657
|
...((gateLog ?? '').split('\n').filter((line) => line.startsWith('⚠️ 동작 검증 0:'))),
|
|
2620
2658
|
...exposeGateLines(gateLog),
|
|
2621
2659
|
...(gateLog ? ['```', gateLog.trim().slice(0, 3000), '```'] : []),
|
|
2622
|
-
...(revertGuard?.reverted.length ? [`- 되돌림 방지: ${revertGuard.reverted.length}파일 제외`] : []),
|
|
2660
|
+
...(revertGuard?.reverted.length && revertGuard.reverted.length > (revertGuard.staleDeleted?.length ?? 0) ? [`- 되돌림 방지: ${revertGuard.reverted.length - (revertGuard.staleDeleted?.length ?? 0)}파일 제외`] : []),
|
|
2661
|
+
...(revertGuard?.staleDeleted?.length ? [`- 되돌림 방지: 삭제 ${revertGuard.staleDeleted.length}파일 제외`] : []),
|
|
2662
|
+
...(revertGuard?.outsideDeleted?.length ? [`- 삭제 경고: 대상 밖 ${revertGuard.outsideDeleted.length}파일 유지 (${revertGuard.outsideDeleted.join(', ')})`] : []),
|
|
2623
2663
|
...(revertGuard?.protected.length ? [`- 되돌림 경고: 대상 경로 ${revertGuard.protected.length}파일 유지 (${revertGuard.protected.join(', ')})`] : []),
|
|
2624
2664
|
...(revertGuard?.warning ? [`- 되돌림 검사 실패(커밋 계속): ${revertGuard.warning}`] : [])] : []),
|
|
2625
2665
|
...relaxation,
|
|
@@ -2968,6 +3008,7 @@ export function assembleBlockedDraftPrBody(
|
|
|
2968
3008
|
JSON.stringify(classificationRecord),
|
|
2969
3009
|
...(state.reasonTruncated ? ['- reason truncated: true'] : []),
|
|
2970
3010
|
...(state.terminalStatus ? [`- child terminal status: reached=${state.terminalStatus.reached}; changed=${state.terminalStatus.changed}; toolCalls=${state.terminalStatus.toolCalls}; timedOut=${state.terminalStatus.timedOut}`] : []),
|
|
3011
|
+
...(state.review?.mustFix.length ? ['## 마지막 리뷰 must-fix', ...state.review.mustFix.map((item) => `- ${item}`)] : []),
|
|
2971
3012
|
].join('\n');
|
|
2972
3013
|
return preparePrBody(raw, persist, 'self-implement-blocked-draft-pr', essentialSuffix);
|
|
2973
3014
|
}
|
|
@@ -3381,7 +3422,26 @@ function mergeDecisionEvidenceCoverage(evidenceCoverage: {
|
|
|
3381
3422
|
: { evidenceCoverageMeasured: false };
|
|
3382
3423
|
}
|
|
3383
3424
|
|
|
3425
|
+
function installedBuildForOrigin(env: NodeJS.ProcessEnv): { installedVersion: string; installedCommit: string } {
|
|
3426
|
+
const root = env.ELANOUS_TEST_HOME?.trim()
|
|
3427
|
+
? join(env.ELANOUS_TEST_HOME.trim(), '.local/share/elanous')
|
|
3428
|
+
: join(homedir(), '.local/share/elanous');
|
|
3429
|
+
try {
|
|
3430
|
+
const parsed: unknown = JSON.parse(readFileSync(join(root, 'install.json'), 'utf8'));
|
|
3431
|
+
if (typeof parsed !== 'object' || parsed === null) return { installedVersion: 'unknown', installedCommit: 'unknown' };
|
|
3432
|
+
const version = (parsed as { version?: unknown }).version;
|
|
3433
|
+
const commit = (parsed as { commit?: unknown }).commit;
|
|
3434
|
+
return {
|
|
3435
|
+
installedVersion: typeof version === 'string' && version.trim() ? version.trim() : 'unknown',
|
|
3436
|
+
installedCommit: typeof commit === 'string' && commit.trim() ? commit.trim() : 'unknown',
|
|
3437
|
+
};
|
|
3438
|
+
} catch {
|
|
3439
|
+
return { installedVersion: 'unknown', installedCommit: 'unknown' };
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3384
3443
|
function runOriginData(env: NodeJS.ProcessEnv = process.env): RunOriginData {
|
|
3444
|
+
const installed = installedBuildForOrigin(env);
|
|
3385
3445
|
return {
|
|
3386
3446
|
hostId: resolveHostId(env),
|
|
3387
3447
|
hostname: hostname(),
|
|
@@ -3390,6 +3450,8 @@ function runOriginData(env: NodeJS.ProcessEnv = process.env): RunOriginData {
|
|
|
3390
3450
|
substrate: env.ELANOUS_SUBSTRATE || 'host',
|
|
3391
3451
|
instance: resolveInstanceName(),
|
|
3392
3452
|
elanousVersion: (JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8')) as { version: string }).version,
|
|
3453
|
+
installedVersion: installed.installedVersion,
|
|
3454
|
+
installedCommit: installed.installedCommit,
|
|
3393
3455
|
...(env.ELANOUS_POD_NAME ? { podName: env.ELANOUS_POD_NAME } : {}),
|
|
3394
3456
|
...(env.ELANOUS_NODE_NAME ? { nodeName: env.ELANOUS_NODE_NAME } : {}),
|
|
3395
3457
|
...(env.ELANOUS_POD_NAMESPACE ? { podNamespace: env.ELANOUS_POD_NAMESPACE } : {}),
|
|
@@ -3413,7 +3475,9 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
3413
3475
|
const shardIdentity = parseRunShardIdentity(opts.feature);
|
|
3414
3476
|
const observeOuter = makeRunObserver(runId, opts.goalId, debug.log.bind(debug), opts.seams.writeRunLedger, shardIdentity);
|
|
3415
3477
|
try {
|
|
3416
|
-
|
|
3478
|
+
// 10-05 PODPROVIDER: record which child provider this run uses — «default» when the launch named none.
|
|
3479
|
+
const launch = opts.launch ?? resolveLaunchStamp();
|
|
3480
|
+
const origin = { ...runOriginData(), childProvider: opts.childLlm?.provider ?? 'default', ...(opts.childLlm?.model ? { childModel: opts.childLlm.model } : {}), launch };
|
|
3417
3481
|
(opts.seams.writeRunLedger ?? appendRunLedgerEntry)({
|
|
3418
3482
|
timestamp: new Date().toISOString(), runId, event: 'run-origin', data: origin,
|
|
3419
3483
|
...(opts.goalId ? { goalId: opts.goalId } : {}), ...shardIdentity,
|
|
@@ -3491,6 +3555,30 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
3491
3555
|
let loopRegistered = false;
|
|
3492
3556
|
let mergeApprovalReceived = false;
|
|
3493
3557
|
let autoMergeAuthorizedBeforeSync = false;
|
|
3558
|
+
let finishedImplementationAtMainSync = false;
|
|
3559
|
+
// The finished implementation's commit, pinned before main sync starts. A timed-out mergeMain is not
|
|
3560
|
+
// cancellable and may keep moving HEAD in the same worktree, so the harvest pushes this SHA, never HEAD.
|
|
3561
|
+
let preSyncCommit: string | undefined;
|
|
3562
|
+
const preserveMergeHarvest = async (reason: string, inputChars?: number): Promise<boolean> => {
|
|
3563
|
+
if (!finishedImplementationAtMainSync || !worktreePath || !branch) return false;
|
|
3564
|
+
if (!preSyncCommit) {
|
|
3565
|
+
observeOuter('merge-harvest-push-failed', { branch, reason, error: 'pre-sync commit was not pinned' }, { level: 'warn' });
|
|
3566
|
+
return false;
|
|
3567
|
+
}
|
|
3568
|
+
try {
|
|
3569
|
+
const pushed = opts.seams.preserveBlockedBranch
|
|
3570
|
+
? await opts.seams.preserveBlockedBranch({ cwd: worktreePath, branch, title: prTitle(opts.feature), commit: preSyncCommit })
|
|
3571
|
+
: runGitCommand(worktreePath, ['push', '-u', 'origin', `${preSyncCommit}:refs/heads/${branch}`]).status === 0;
|
|
3572
|
+
if (!pushed) throw new Error('branch push failed');
|
|
3573
|
+
// The worktree is left untouched: a late merge may still be writing it. The harvest source is the pinned commit.
|
|
3574
|
+
try { observeOuter('merge-abandoned-harvestable', { branch, reason, inputChars: inputChars ?? null, commit: preSyncCommit, worktree: 'left-as-is' }); }
|
|
3575
|
+
catch { /* observation cannot undo a confirmed push */ }
|
|
3576
|
+
return true;
|
|
3577
|
+
} catch (error) {
|
|
3578
|
+
observeOuter('merge-harvest-push-failed', { branch, reason, error: safeErrorDescription(error) }, { level: 'warn' });
|
|
3579
|
+
return false;
|
|
3580
|
+
}
|
|
3581
|
+
};
|
|
3494
3582
|
let lastParsedSupervisorVerdict: ReworkBudgetVerdict | undefined;
|
|
3495
3583
|
let lastParsedSupervisorReason: string | undefined;
|
|
3496
3584
|
let providerErrorCount = 0;
|
|
@@ -3577,6 +3665,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
3577
3665
|
},
|
|
3578
3666
|
} satisfies LogSink);
|
|
3579
3667
|
let traversalFinalized = false;
|
|
3668
|
+
reworkCapProceed = false;
|
|
3580
3669
|
const progressDelivery = { delivered: 0, unwired: 0, callbackFailed: 0 };
|
|
3581
3670
|
let capturedPrNumber: number | undefined;
|
|
3582
3671
|
let openPrInvoked = false;
|
|
@@ -3970,6 +4059,8 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
3970
4059
|
() => credentialFailureCount > 0,
|
|
3971
4060
|
hasCurrentProviderError,
|
|
3972
4061
|
hasCurrentCredentialFailure,
|
|
4062
|
+
(commit: string | undefined) => { finishedImplementationAtMainSync = true; preSyncCommit = commit; },
|
|
4063
|
+
preserveMergeHarvest,
|
|
3973
4064
|
);
|
|
3974
4065
|
terminalNode = result.node;
|
|
3975
4066
|
await mergeChildProviderErrors();
|
|
@@ -4042,9 +4133,11 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
4042
4133
|
} catch (e) {
|
|
4043
4134
|
if (e instanceof StepTimeoutError) {
|
|
4044
4135
|
observeOuter('step-timeout', { step: e.step, ms: e.ms, branch, feature: opts.feature.slice(0, 80) }, { level: 'warn' });
|
|
4136
|
+
const harvestable = e.step === 'merge' && await preserveMergeHarvest('step-timeout');
|
|
4045
4137
|
const result: SelfImplementResult = {
|
|
4046
4138
|
runId,
|
|
4047
4139
|
ok: false,
|
|
4140
|
+
...(harvestable ? { harvestable: true } : {}),
|
|
4048
4141
|
stage: 'timed-out',
|
|
4049
4142
|
node: 'implement',
|
|
4050
4143
|
...resolveRunOutcome({ termination: 'abandoned' }),
|
|
@@ -4052,7 +4145,9 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
4052
4145
|
...(worktreePath ? { worktreePath } : {}),
|
|
4053
4146
|
...(lastParsedSupervisorReason ? { supervisorReason: lastParsedSupervisorReason } : {}),
|
|
4054
4147
|
...(mergeApprovalReceived || (e.step === 'merge' && autoMergeAuthorizedBeforeSync) ? { mergeApprovalReceived: true } : {}),
|
|
4055
|
-
detail:
|
|
4148
|
+
detail: harvestable
|
|
4149
|
+
? `자율 단계 '${e.step}' wall-clock ${e.ms}ms 초과 — 구현 완료 · 수확 대기 (${branch}, worktree: ${worktreePath})`
|
|
4150
|
+
: worktreePath
|
|
4056
4151
|
? `자율 단계 '${e.step}' wall-clock ${e.ms}ms 초과 — hang 방지 종결(worktree 회수 경로: ${worktreePath})`
|
|
4057
4152
|
: `자율 단계 '${e.step}' wall-clock ${e.ms}ms 초과 — hang 방지 종결(worktree 생성 전)`,
|
|
4058
4153
|
};
|
|
@@ -4134,10 +4229,31 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
4134
4229
|
const terminalStage = terminalResult?.stage ?? 'crashed';
|
|
4135
4230
|
try {
|
|
4136
4231
|
const mappedStatus = mapStageToRunStatus(terminalStage)?.runStatus;
|
|
4137
|
-
|
|
4232
|
+
const reworkCapStop = terminalResult?.stage === 'pr-opened' && (
|
|
4233
|
+
terminalResult.outcome === 'budget-exhausted'
|
|
4234
|
+
|| (terminalResult.outcome === 'completed' && reworkCapProceed)
|
|
4235
|
+
);
|
|
4236
|
+
if (!terminalResult || mappedStatus === 'failed' || (mappedStatus === undefined && terminalResult.ok === false) || signalIncompleteState(roundClassifications).latestSignalIncomplete || reworkCapStop) {
|
|
4237
|
+
const reworkCap = reworkCapStop ? classifyReworkCapExhaustion({
|
|
4238
|
+
introduced: terminalResult?.gate?.reflectGateFacts?.introduced
|
|
4239
|
+
? [`introduced=${terminalResult.gate.reflectGateFacts.introduced}`]
|
|
4240
|
+
: [],
|
|
4241
|
+
mustFix: terminalResult?.review?.mustFix ?? terminalResult?.mustFix,
|
|
4242
|
+
summary: terminalResult?.review?.summary,
|
|
4243
|
+
}) : undefined;
|
|
4244
|
+
if (reworkCap) {
|
|
4245
|
+
observeOuter('rework-cap-heal', {
|
|
4246
|
+
stage: terminalStage,
|
|
4247
|
+
defectClass: reworkCap.defectClass,
|
|
4248
|
+
nextAction: reworkCap.nextAction,
|
|
4249
|
+
evidence: reworkCap.evidence,
|
|
4250
|
+
});
|
|
4251
|
+
}
|
|
4138
4252
|
recordFailureEvent({
|
|
4139
|
-
source: 'harness-run', kind: terminalStage, ref: runId,
|
|
4140
|
-
summary:
|
|
4253
|
+
source: 'harness-run', kind: reworkCapStop ? 'rework-cap-exhausted' : terminalStage, ref: runId,
|
|
4254
|
+
summary: reworkCap
|
|
4255
|
+
? reworkCapFailureSummary(opts.feature, reworkCap)
|
|
4256
|
+
: opts.feature.split(/\r?\n/, 1)[0]?.trim() || `Harness run ${runId} failed`,
|
|
4141
4257
|
at: new Date().toISOString(),
|
|
4142
4258
|
});
|
|
4143
4259
|
}
|
|
@@ -4499,6 +4615,14 @@ function observeRunRollup(
|
|
|
4499
4615
|
}, effectiveOutcome.runStatus === 'failed' ? { level: 'warn' } : undefined);
|
|
4500
4616
|
}
|
|
4501
4617
|
|
|
4618
|
+
let reworkCapProceed = false;
|
|
4619
|
+
|
|
4620
|
+
function reworkCapFailureSummary(feature: string, decision: ReworkCapHealDecision): string {
|
|
4621
|
+
const title = feature.split(/\\r?\\n/, 1)[0]?.trim() || 'rework cap exhausted';
|
|
4622
|
+
const evidence = decision.evidence.length ? decision.evidence.join(' | ') : 'no gate introduced list and no review finding';
|
|
4623
|
+
return `${title} [${decision.defectClass} → ${decision.nextAction}] ${evidence}`;
|
|
4624
|
+
}
|
|
4625
|
+
|
|
4502
4626
|
async function runSelfImplementInner(
|
|
4503
4627
|
opts: SelfImplementOptions,
|
|
4504
4628
|
identity?: { runId: string; source: ReturnType<typeof resolveRunIdentity>['source'] },
|
|
@@ -4545,6 +4669,8 @@ async function runSelfImplementInner(
|
|
|
4545
4669
|
hasObservedCredentialFailure: () => boolean = hasCredentialFailure,
|
|
4546
4670
|
hasCurrentProviderError: () => boolean = hasProviderError,
|
|
4547
4671
|
hasCurrentCredentialFailure: () => boolean = hasCredentialFailure,
|
|
4672
|
+
onMainSyncStarted: (commit: string | undefined) => void = () => {},
|
|
4673
|
+
preserveMergeHarvest: (reason: string, inputChars?: number) => Promise<boolean> = async () => false,
|
|
4548
4674
|
): Promise<Omit<SelfImplementResult, 'runId'>> {
|
|
4549
4675
|
const s = opts.seams;
|
|
4550
4676
|
const pipelineStartedAtMs = Date.now();
|
|
@@ -4983,6 +5109,8 @@ async function runSelfImplementInner(
|
|
|
4983
5109
|
} | undefined;
|
|
4984
5110
|
let gate!: SelfImplementGateResult;
|
|
4985
5111
|
let review: SelfImplementReview | undefined;
|
|
5112
|
+
/** Review-budget leftovers and the body that carried them, so a later merge drafts from the same text. */
|
|
5113
|
+
let preparedReviewBudgetPrBody: string | undefined;
|
|
4986
5114
|
const reviewMustFixCountHistory: number[] = [];
|
|
4987
5115
|
const reviewMustFixTrend = (): string => {
|
|
4988
5116
|
if (reviewMustFixCountHistory.length < 2) return '아직 못 잰다';
|
|
@@ -5318,6 +5446,23 @@ async function runSelfImplementInner(
|
|
|
5318
5446
|
observe('pr.comment.seam-missing', { number: pr.number, buffered: prCommentBuffer.length }, { level: 'warn' });
|
|
5319
5447
|
return;
|
|
5320
5448
|
}
|
|
5449
|
+
const marker = '<!-- elanous:run-status -->';
|
|
5450
|
+
if (s.findPrComment && s.editPrComment) {
|
|
5451
|
+
try {
|
|
5452
|
+
const existing = await s.findPrComment({ number: pr.number, marker, cwd: wt.path });
|
|
5453
|
+
const history = prCommentBuffer.join('\n\n');
|
|
5454
|
+
const body = existing
|
|
5455
|
+
? existing.body.includes('</details>')
|
|
5456
|
+
? existing.body.replace(/<\/details>(?![\s\S]*<\/details>)/, `\n\n${history}\n</details>`)
|
|
5457
|
+
: `${existing.body}\n\n<details>\n<summary>Round history</summary>\n\n${history}\n</details>`
|
|
5458
|
+
: `${marker}\n<details>\n<summary>Round history</summary>\n\n${history}\n</details>`;
|
|
5459
|
+
if (existing) await s.editPrComment({ id: existing.id, body, cwd: wt.path });
|
|
5460
|
+
else await s.postPrComment({ number: pr.number, body, cwd: wt.path });
|
|
5461
|
+
} catch (error) {
|
|
5462
|
+
// Unknown lookup/edit outcome is not proof of absence: never create a second status comment.
|
|
5463
|
+
observe('pr.comment.status-failed', { number: pr.number, error: error instanceof Error ? error.message : String(error) }, { level: 'warn' });
|
|
5464
|
+
}
|
|
5465
|
+
}
|
|
5321
5466
|
for (const body of prCommentBuffer) {
|
|
5322
5467
|
try {
|
|
5323
5468
|
await s.postPrComment({ number: pr.number, body, cwd: wt.path });
|
|
@@ -5338,9 +5483,11 @@ async function runSelfImplementInner(
|
|
|
5338
5483
|
let finishedChildCommitted = false;
|
|
5339
5484
|
const revertGuard: RevertGuardResult = { reverted: [], protected: [] };
|
|
5340
5485
|
const inspectStaleReverts = (targets: readonly string[]): void => {
|
|
5341
|
-
const inspected = dropStaleReverts(wt.path, targets, runId, getUserConfig().harness?.revertGuard?.depth);
|
|
5486
|
+
const inspected = dropStaleReverts(wt.path, targets, runId, getUserConfig().harness?.revertGuard?.depth, wt.resolvedBase);
|
|
5342
5487
|
for (const file of inspected.reverted) if (!revertGuard.reverted.includes(file)) revertGuard.reverted.push(file);
|
|
5343
5488
|
for (const file of inspected.protected) if (!revertGuard.protected.includes(file)) revertGuard.protected.push(file);
|
|
5489
|
+
for (const file of inspected.staleDeleted ?? []) if (!revertGuard.staleDeleted?.includes(file)) (revertGuard.staleDeleted ??= []).push(file);
|
|
5490
|
+
for (const file of inspected.outsideDeleted ?? []) if (!revertGuard.outsideDeleted?.includes(file)) (revertGuard.outsideDeleted ??= []).push(file);
|
|
5344
5491
|
if (inspected.warning) revertGuard.warning = inspected.warning;
|
|
5345
5492
|
};
|
|
5346
5493
|
const classifyUnfinishedRun = (stage: SelfImplementStage, verdict?: ReworkBudgetVerdict, decomposition?: TerminalDecomposition): AbandonedClassificationResult => {
|
|
@@ -5363,6 +5510,14 @@ async function runSelfImplementInner(
|
|
|
5363
5510
|
mustFixReported: (review?.mustFix.length ?? 0) > 0,
|
|
5364
5511
|
});
|
|
5365
5512
|
};
|
|
5513
|
+
const podReviewBlockedDraft = process.env.ELANOUS_SUBSTRATE === 'pod';
|
|
5514
|
+
let blockedDraftNoChanges = false;
|
|
5515
|
+
let blockedDraftPrFailure: string | undefined;
|
|
5516
|
+
const reviewBlockedResult = (pr: { url: string; number: number } | undefined) => ({
|
|
5517
|
+
stage: blockedDraftNoChanges && podReviewBlockedDraft ? 'no-changes' as const : podReviewBlockedDraft && !pr ? 'aborted' as const : 'review-blocked' as const,
|
|
5518
|
+
mustFix: [...(review?.mustFix ?? [])],
|
|
5519
|
+
...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}),
|
|
5520
|
+
});
|
|
5366
5521
|
const preserveBlockedArtifacts = async ({ stage, reason, verdict, gate: preservedGate, typecheck, decomposition, childSummary, reasonTruncated, failureKind, terminalStatus, salvageStatusExpected }: { stage: 'review-blocked' | 'gate-failed' | 'aborted'; reason: string; verdict?: ReworkBudgetVerdict; gate?: SelfImplementGateResult; typecheck?: { passed: boolean; log?: string }; decomposition?: TerminalDecomposition; childSummary?: string; reasonTruncated?: boolean; failureKind?: ReturnType<typeof classifyReviewProviderFailure> | null; terminalStatus?: ImplementTerminalStatus; salvageStatusExpected: boolean }): Promise<{ url: string; number: number } | undefined> => {
|
|
5367
5522
|
let childSummaryArtifact: ChildSummaryArtifactRef | undefined;
|
|
5368
5523
|
if (childSummary !== undefined) {
|
|
@@ -5455,6 +5610,7 @@ async function runSelfImplementInner(
|
|
|
5455
5610
|
...(childSummaryArtifact ? { childSummaryArtifactPath: childSummaryArtifact.path } : {}),
|
|
5456
5611
|
};
|
|
5457
5612
|
if (s.preservationHasChanges && !await s.preservationHasChanges({ cwd: wt.path, base: preservationBase })) {
|
|
5613
|
+
if (stage === 'review-blocked' && podReviewBlockedDraft) blockedDraftNoChanges = true;
|
|
5458
5614
|
observe('rework-blocked-draft-pr', { ...observation, skipped: 'no-changes' });
|
|
5459
5615
|
progress(stage, '보존할 변경이 없어 draft PR을 열지 않음');
|
|
5460
5616
|
return undefined;
|
|
@@ -5488,8 +5644,9 @@ async function runSelfImplementInner(
|
|
|
5488
5644
|
s.persistPrBodyArtifact,
|
|
5489
5645
|
);
|
|
5490
5646
|
// no-changes wins; worktree-only remains local even for environment stops.
|
|
5491
|
-
const environmentStop = blockedDraftDisposition(classificationRecord.classification) === 'preserve-branch'
|
|
5492
|
-
|
|
5647
|
+
const environmentStop = blockedDraftDisposition(classificationRecord.classification) === 'preserve-branch'
|
|
5648
|
+
&& !(stage === 'review-blocked' && podReviewBlockedDraft);
|
|
5649
|
+
const worktreeOnly = opts.completion === 'worktree-only' && !(stage === 'review-blocked' && podReviewBlockedDraft);
|
|
5493
5650
|
if (worktreeOnly || environmentStop) {
|
|
5494
5651
|
let artifactPath: string | undefined;
|
|
5495
5652
|
let artifactError: string | undefined;
|
|
@@ -5559,7 +5716,54 @@ async function runSelfImplementInner(
|
|
|
5559
5716
|
}
|
|
5560
5717
|
return undefined;
|
|
5561
5718
|
}
|
|
5719
|
+
if (stage === 'review-blocked' && podReviewBlockedDraft && !s.preservationHasChanges
|
|
5720
|
+
&& !preservationHasChanges(wt.path, preservationBase)) {
|
|
5721
|
+
blockedDraftNoChanges = true;
|
|
5722
|
+
observe('rework-blocked-draft-pr', { ...observation, skipped: 'no-changes' });
|
|
5723
|
+
progress(stage, '보존할 변경이 없어 draft PR을 열지 않음');
|
|
5724
|
+
return undefined;
|
|
5725
|
+
}
|
|
5726
|
+
// Pod review-blocked: a failed commit or PR still pushes the branch, and the result detail says what survived.
|
|
5727
|
+
const preserveReviewBlockedBranch = async (cause: string, commitFirst: boolean, suffix = ''): Promise<undefined> => {
|
|
5728
|
+
let pushed = false;
|
|
5729
|
+
try {
|
|
5730
|
+
if (s.preserveBlockedBranch) {
|
|
5731
|
+
pushed = await s.preserveBlockedBranch({ cwd: wt.path, branch: wt.branch, title: prTitle(opts.feature) });
|
|
5732
|
+
} else {
|
|
5733
|
+
if (commitFirst) {
|
|
5734
|
+
const commit = commitWorktree(wt.path, prTitle(opts.feature));
|
|
5735
|
+
if (!commit.ok && !/nothing to commit/.test(commit.out)) throw new Error(`로컬 브랜치 커밋 실패: ${commit.out}`);
|
|
5736
|
+
}
|
|
5737
|
+
const push = runGitCommand(wt.path, ['push', '-u', 'origin', `HEAD:refs/heads/${wt.branch}`]);
|
|
5738
|
+
if (push.status !== 0) throw new Error(push.stderr || push.stdout || 'git push failed');
|
|
5739
|
+
pushed = true;
|
|
5740
|
+
}
|
|
5741
|
+
if (!pushed) throw new Error('브랜치 push가 성공하지 않았음');
|
|
5742
|
+
} catch (pushError) {
|
|
5743
|
+
const pushReason = safeErrorDescription(pushError);
|
|
5744
|
+
blockedDraftPrFailure = `${cause}; 원격 브랜치 보존 실패: ${pushReason}; worktree: ${wt.path}`;
|
|
5745
|
+
observe('rework-blocked-draft-pr', { ...observation, error: cause, pushed: false, pushError: pushReason, branch: wt.branch }, { level: 'warn' });
|
|
5746
|
+
progress('aborted', blockedDraftPrFailure);
|
|
5747
|
+
return undefined;
|
|
5748
|
+
}
|
|
5749
|
+
blockedDraftPrFailure = `${cause}; 원격 브랜치 보존: ${wt.branch}${suffix}`;
|
|
5750
|
+
observe('rework-blocked-draft-pr', { ...observation, error: cause, pushed: true, branch: wt.branch }, { level: 'warn' });
|
|
5751
|
+
progress('aborted', blockedDraftPrFailure);
|
|
5752
|
+
return undefined;
|
|
5753
|
+
};
|
|
5562
5754
|
progress('pr-opening', '중단 산출물을 draft PR로 보존…');
|
|
5755
|
+
if (stage === 'review-blocked' && podReviewBlockedDraft) {
|
|
5756
|
+
let commitError: string | undefined;
|
|
5757
|
+
try {
|
|
5758
|
+
const commit = commitWorktree(wt.path, prTitle(opts.feature));
|
|
5759
|
+
if (!commit.ok && !/nothing to commit/.test(commit.out)) commitError = commit.out.trim() || 'git commit failed';
|
|
5760
|
+
} catch (error) {
|
|
5761
|
+
commitError = safeErrorDescription(error);
|
|
5762
|
+
}
|
|
5763
|
+
if (commitError !== undefined) {
|
|
5764
|
+
return preserveReviewBlockedBranch(`review-blocked 작업 커밋 실패: ${commitError}`, false, `; 미커밋 작업은 worktree 에 남음: ${wt.path}`);
|
|
5765
|
+
}
|
|
5766
|
+
}
|
|
5563
5767
|
let pr: { url: string; number: number };
|
|
5564
5768
|
try {
|
|
5565
5769
|
pr = await withStepTimeout(s.openPr({
|
|
@@ -5568,6 +5772,7 @@ async function runSelfImplementInner(
|
|
|
5568
5772
|
head: wt.branch,
|
|
5569
5773
|
...(opts.base ? { base: opts.base } : {}),
|
|
5570
5774
|
draft: true,
|
|
5775
|
+
...(stage === 'review-blocked' ? { labels: ['review-blocked'] } : {}),
|
|
5571
5776
|
cwd: wt.path,
|
|
5572
5777
|
}), T.pr, 'pr');
|
|
5573
5778
|
} catch (error) {
|
|
@@ -5589,6 +5794,10 @@ async function runSelfImplementInner(
|
|
|
5589
5794
|
...(artifactPath ? { prBodyArtifactPath: artifactPath } : {}),
|
|
5590
5795
|
...(artifactError ? { prBodyArtifactError: artifactError } : {}),
|
|
5591
5796
|
}, { level: 'warn' });
|
|
5797
|
+
if (stage === 'review-blocked' && podReviewBlockedDraft) {
|
|
5798
|
+
return preserveReviewBlockedBranch(`draft PR 생성 실패: ${prError}`, true,
|
|
5799
|
+
`; ${artifactPath ? `판정 본문: ${artifactPath}` : `판정 본문 보존 실패: ${artifactError ?? 'unknown error'}`}`);
|
|
5800
|
+
}
|
|
5592
5801
|
progress('aborted', artifactPath
|
|
5593
5802
|
? `중단 산출물의 draft PR 생성 실패(worktree·branch 보존 · 판정 본문 보존: ${artifactPath})`
|
|
5594
5803
|
: `중단 산출물의 draft PR 생성 실패(worktree·branch 보존 · 판정 본문 보존 실패: ${artifactError ?? 'unknown error'})`);
|
|
@@ -5601,6 +5810,9 @@ async function runSelfImplementInner(
|
|
|
5601
5810
|
...(assembled.truncated ? { prBodyTruncated: true, prBodyOriginalChars: assembled.originalChars } : {}),
|
|
5602
5811
|
});
|
|
5603
5812
|
await flushPrComments(pr);
|
|
5813
|
+
if (stage === 'review-blocked') {
|
|
5814
|
+
try { debug.log('self-implement.terminal', 'review-blocked-pr', { runId, prNumber: pr.number, round: Math.max(0, round - 1) }); } catch { /* observation is fail-soft */ }
|
|
5815
|
+
}
|
|
5604
5816
|
progress('pr-opened', `중단 산출물 draft PR 개설 (#${pr.number}·사람 판단 대기)`);
|
|
5605
5817
|
return pr;
|
|
5606
5818
|
};
|
|
@@ -5684,6 +5896,7 @@ async function runSelfImplementInner(
|
|
|
5684
5896
|
'self-implement-review-budget-pr',
|
|
5685
5897
|
followUpMustFix,
|
|
5686
5898
|
);
|
|
5899
|
+
preparedReviewBudgetPrBody = preparedPrBody.body;
|
|
5687
5900
|
const pr = await withStepTimeout(s.openPr({
|
|
5688
5901
|
title: prTitle(opts.feature),
|
|
5689
5902
|
body: preparedPrBody.body,
|
|
@@ -6097,6 +6310,7 @@ async function runSelfImplementInner(
|
|
|
6097
6310
|
if (budgetDecision.stop) {
|
|
6098
6311
|
if (budgetDecision.exit === 'proceed') {
|
|
6099
6312
|
finalizeSupervisorDeliveries('supervisor-rework-proceed');
|
|
6313
|
+
if (round > effectiveMax) reworkCapProceed = true;
|
|
6100
6314
|
break;
|
|
6101
6315
|
}
|
|
6102
6316
|
finalizeSupervisorDeliveries('supervisor-rework-blocked');
|
|
@@ -6113,7 +6327,7 @@ async function runSelfImplementInner(
|
|
|
6113
6327
|
if (reflectRejectedAudit.length && review) review.shouldFix = [...review.shouldFix, ...reflectRejectedAudit];
|
|
6114
6328
|
const pr = await preserveBlockedArtifacts({ stage: 'review-blocked', verdict: parsedDecision.verdict, reason: parsedDecision.reason, gate, decomposition: terminalDecomposition, salvageStatusExpected: false });
|
|
6115
6329
|
const quotaExhaustionAssessment = quotaExhaustionAssessmentForRun();
|
|
6116
|
-
return { ok: false,
|
|
6330
|
+
return { ok: false, node: 'rework', ...terminal, ...supervisorOutcome, sessionId, worktreePath: wt.path, branch: wt.branch, gate, review, quotaExhaustionAssessment, ...(lastSupervisorReason ? { supervisorReason: lastSupervisorReason } : {}), ...reviewBlockedResult(pr), detail: `${blockedDraftPrFailure ? `${blockedDraftPrFailure}; ` : ''}rework judged unconvergeable after ${round} rework round(s): ${parsedDecision.reason}` };
|
|
6117
6331
|
}
|
|
6118
6332
|
const baselineStop = noRetryBaseline();
|
|
6119
6333
|
const reason = baselineStop.terminationReason ?? parsedDecision.reason;
|
|
@@ -6141,7 +6355,7 @@ async function runSelfImplementInner(
|
|
|
6141
6355
|
if (isReviewRework(reworkKind)) {
|
|
6142
6356
|
if (reflectRejectedAudit.length && review) review.shouldFix = [...review.shouldFix, ...reflectRejectedAudit];
|
|
6143
6357
|
const pr = await preserveBlockedArtifacts({ stage: 'review-blocked', verdict: lastReworkVerdict, reason, gate, salvageStatusExpected: false });
|
|
6144
|
-
return { ok: false,
|
|
6358
|
+
return { ok: false, node: 'rework', ...terminal, sessionId, worktreePath: wt.path, branch: wt.branch, gate, review, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(lastSupervisorVerdict === 'CONTRACT-CONFLICT' ? { supervisorVerdict: lastSupervisorVerdict } : {}), ...reviewBlockedResult(pr), detail: blockedDraftPrFailure ?? reason };
|
|
6145
6359
|
}
|
|
6146
6360
|
const baselineStop = noRetryBaseline();
|
|
6147
6361
|
const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', verdict: lastReworkVerdict, reason: baselineStop.terminationReason ?? reason, gate, salvageStatusExpected: false });
|
|
@@ -6157,32 +6371,47 @@ async function runSelfImplementInner(
|
|
|
6157
6371
|
if (isReviewRework(reworkKind)) {
|
|
6158
6372
|
if (reflectRejectedAudit.length && review) review.shouldFix = [...review.shouldFix, ...reflectRejectedAudit];
|
|
6159
6373
|
const reason = `review must-fix unresolved after ${round - 1} rework round(s)`;
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6374
|
+
// Pod keeps review-blocked work as a labelled draft (or aborts with the preserved branch) instead of
|
|
6375
|
+
// accepting the review budget into a non-draft PR — restored after #24341 (0.2.16 gate shard 5).
|
|
6376
|
+
if (!podReviewBlockedDraft) {
|
|
6377
|
+
const acceptance = await acceptReviewBudget(
|
|
6378
|
+
review?.mustFix ?? [],
|
|
6379
|
+
reworkParts.some((part) => part.source === 'supervisor'),
|
|
6380
|
+
);
|
|
6381
|
+
if (acceptance.decision.action === 'accept') {
|
|
6382
|
+
if (acceptance.pr) {
|
|
6383
|
+
await draftFollowUpAfterMerge({
|
|
6384
|
+
prNumber: acceptance.pr.number,
|
|
6385
|
+
followUpMustFix: acceptance.decision.unresolvedMustFix,
|
|
6386
|
+
shouldFix: review?.shouldFix,
|
|
6387
|
+
prBody: preparedReviewBudgetPrBody,
|
|
6388
|
+
feature: opts.feature,
|
|
6389
|
+
...(opts.goalId ? { cellId: opts.goalId } : {}),
|
|
6390
|
+
...(opts.goalFile ? { goalFile: opts.goalFile } : {}),
|
|
6391
|
+
}, s.followUp);
|
|
6392
|
+
}
|
|
6393
|
+
return {
|
|
6394
|
+
ok: true,
|
|
6395
|
+
stage: 'pr-opened',
|
|
6396
|
+
node: 'open-pr',
|
|
6397
|
+
...terminal,
|
|
6398
|
+
sessionId,
|
|
6399
|
+
worktreePath: wt.path,
|
|
6400
|
+
branch: wt.branch,
|
|
6401
|
+
gate,
|
|
6402
|
+
review,
|
|
6403
|
+
mergeReason: 'review-budget-follow-up-required',
|
|
6404
|
+
followUpMustFix: acceptance.decision.unresolvedMustFix,
|
|
6405
|
+
followUpMustFixCount: acceptance.decision.unresolvedMustFix.length,
|
|
6406
|
+
...(acceptance.pr ? { prUrl: acceptance.pr.url, prNumber: acceptance.pr.number } : {}),
|
|
6407
|
+
detail: `${reason}; accepted with ${acceptance.decision.unresolvedMustFix.length} follow-up must-fix item(s)`,
|
|
6408
|
+
};
|
|
6409
|
+
}
|
|
6181
6410
|
}
|
|
6182
6411
|
const pr = await preserveBlockedArtifacts({ stage: 'review-blocked', reason, gate, salvageStatusExpected: true });
|
|
6183
|
-
const salvage = await salvageHardCap(canSalvage, pr);
|
|
6412
|
+
const salvage = blockedDraftNoChanges || blockedDraftPrFailure ? 'parked' : await salvageHardCap(canSalvage, pr);
|
|
6184
6413
|
const disposition = { ...terminal, ...(salvage ? { salvage } : {}) };
|
|
6185
|
-
return { ok: false,
|
|
6414
|
+
return { ok: false, node: 'rework', ...disposition, sessionId, worktreePath: wt.path, branch: wt.branch, gate, review, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(lastSupervisorVerdict === 'CONTRACT-CONFLICT' ? { supervisorVerdict: lastSupervisorVerdict } : {}), ...reviewBlockedResult(pr), detail: blockedDraftPrFailure ?? reason };
|
|
6186
6415
|
}
|
|
6187
6416
|
const baselineStop = noRetryBaseline();
|
|
6188
6417
|
const reason = baselineStop.terminationReason ?? `gate failed after ${round - 1} rework round(s)`;
|
|
@@ -7073,9 +7302,13 @@ async function runSelfImplementInner(
|
|
|
7073
7302
|
`Child completion: ${impl.summary.trim() || '(summary unavailable)'}`,
|
|
7074
7303
|
]);
|
|
7075
7304
|
if (review) {
|
|
7076
|
-
|
|
7077
|
-
`
|
|
7078
|
-
|
|
7305
|
+
if (review.reviewed) {
|
|
7306
|
+
bufferPrComment(round, 'reviewer', `Round ${round}: review completed (${review.verdict}).`, [
|
|
7307
|
+
`Review summary: ${review.summary.trim() || '(summary unavailable)'}`,
|
|
7308
|
+
]);
|
|
7309
|
+
} else {
|
|
7310
|
+
bufferPrComment(round, 'reviewer', `Round ${round}: 리뷰 못 함(사유: ${review.failureReason?.trim() || '사유 미상'}) — 통과 판정 아님`, []);
|
|
7311
|
+
}
|
|
7079
7312
|
}
|
|
7080
7313
|
finalizeSupervisorDeliveries('no-next-rework-round');
|
|
7081
7314
|
break;
|
|
@@ -7193,7 +7426,23 @@ async function runSelfImplementInner(
|
|
|
7193
7426
|
return { ok: false, stage: 'merge-conflict', node: 'main-sync', ...resolveRunOutcome({ termination: 'abandoned' }), ...decisionSignalResult, sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), detail: 'pre-PR main sync default-branch-unresolved' };
|
|
7194
7427
|
}
|
|
7195
7428
|
progress('gating', `최신 ${mergeTarget} 정합 (병렬 드리프트·LLM 충돌해결)…`);
|
|
7196
|
-
|
|
7429
|
+
onMainSyncStarted((s.headCommit ?? ((cwd: string) => {
|
|
7430
|
+
const head = runGitCommand(cwd, ['rev-parse', '--verify', 'HEAD'], { encoding: 'utf8' });
|
|
7431
|
+
return head.status === 0 ? String(head.stdout).trim() || undefined : undefined;
|
|
7432
|
+
}))(wt.path));
|
|
7433
|
+
let sync: Awaited<ReturnType<NonNullable<SelfImplementSeams['mergeMain']>>>;
|
|
7434
|
+
try {
|
|
7435
|
+
sync = await withStepTimeout(s.mergeMain(wt.path, mergeTarget), T.merge, 'merge');
|
|
7436
|
+
} catch (error) {
|
|
7437
|
+
if (error instanceof StepTimeoutError) throw error;
|
|
7438
|
+
const harvestable = await preserveMergeHarvest('merge-interrupted');
|
|
7439
|
+
if (!harvestable) throw error;
|
|
7440
|
+
canAuto = false;
|
|
7441
|
+
mergeReason = 'main-sync-interrupted';
|
|
7442
|
+
recordMergeDecision();
|
|
7443
|
+
progress('merge-conflict', `⚠️ ${mergeTarget} 정합 중단 — 사람 수확 (${wt.branch})`);
|
|
7444
|
+
return { ok: false, stage: 'merge-conflict', node: 'main-sync', ...resolveRunOutcome({ termination: 'abandoned' }), ...decisionSignalResult, sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), harvestable: true, detail: `pre-PR main sync interrupted: ${safeErrorDescription(error)}` };
|
|
7445
|
+
}
|
|
7197
7446
|
// ⛔⭐ `OBS-T96` 🅐 — 「무엇을 봤는지」를 남긴다. 수만 남기면 정합 실패가 «재현 불가»가 된다.
|
|
7198
7447
|
observe('pre-pr-sync', mainSyncObservation(sync, mergeTarget, opts.base, wt.branch));
|
|
7199
7448
|
if (sync.status === 'conflict-unresolved' || sync.status === 'error') {
|
|
@@ -7201,7 +7450,9 @@ async function runSelfImplementInner(
|
|
|
7201
7450
|
canAuto = false;
|
|
7202
7451
|
mergeReason = `main-sync-${sync.status}`;
|
|
7203
7452
|
recordMergeDecision();
|
|
7204
|
-
|
|
7453
|
+
const harvestable = (sync.reason === 'conflict-input-too-large' || sync.reason === 'conflict-resolver-interrupted')
|
|
7454
|
+
&& await preserveMergeHarvest(sync.reason, sync.inputChars);
|
|
7455
|
+
return { ok: false, stage: 'merge-conflict', node: 'main-sync', ...resolveRunOutcome({ termination: 'abandoned' }), ...decisionSignalResult, sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), ...(harvestable ? { harvestable: true } : {}), detail: harvestable ? sync.reason === 'conflict-input-too-large' ? `충돌 큼 — 사람 수확 (${wt.branch}, 입력 ${sync.inputChars}자)` : `충돌 해결 중단 — 사람 수확 (${wt.branch})` : `pre-PR main sync ${sync.status}` };
|
|
7205
7456
|
}
|
|
7206
7457
|
if (sync.status === 'llm-resolved' || sync.status === 'merged') {
|
|
7207
7458
|
preservationBase = opts.base ?? mergeTarget;
|
|
@@ -7385,11 +7636,15 @@ async function runSelfImplementInner(
|
|
|
7385
7636
|
let releasePathInspectionError: string | undefined;
|
|
7386
7637
|
if (s.readPrFiles) {
|
|
7387
7638
|
try {
|
|
7388
|
-
|
|
7639
|
+
// Rate-limit recovery may wait up to 15 minutes for X-RateLimit-Reset; the PR step cap must not cut that wait.
|
|
7640
|
+
const files = await s.readPrFiles({ number: pr.number, cwd: wt.path, ...(opts.base ? { base: opts.base } : {}) });
|
|
7389
7641
|
if (!Array.isArray(files) || !files.every((path) => typeof path === 'string')) throw new Error('invalid PR file list');
|
|
7390
7642
|
releaseHoldPath = releasePathHold(files);
|
|
7391
7643
|
} catch (error) {
|
|
7392
|
-
|
|
7644
|
+
const rateLimited = error instanceof Error && (error as { rateLimited?: boolean }).rateLimited === true;
|
|
7645
|
+
releasePathInspectionError = rateLimited
|
|
7646
|
+
? `rate-limit: ${safeErrorDescription(error)}`
|
|
7647
|
+
: safeErrorDescription(error);
|
|
7393
7648
|
}
|
|
7394
7649
|
} else if (canAuto || labels?.includes(AUTO_REVIEW_LABEL)) {
|
|
7395
7650
|
releasePathInspectionError = 'readPrFiles seam unavailable';
|
|
@@ -7428,7 +7683,9 @@ async function runSelfImplementInner(
|
|
|
7428
7683
|
if (releasePathInspectionError && (canAuto || labels?.includes(AUTO_REVIEW_LABEL))) {
|
|
7429
7684
|
observe('release-path-inspection-failed', { number: pr.number, error: releasePathInspectionError }, { level: 'error' });
|
|
7430
7685
|
canAuto = false;
|
|
7431
|
-
mergeSkipReason = mergeReason = '
|
|
7686
|
+
mergeSkipReason = mergeReason = releasePathInspectionError.startsWith('rate-limit:')
|
|
7687
|
+
? 'release-path-inspection-failed: rate-limit'
|
|
7688
|
+
: 'release-path-inspection-failed';
|
|
7432
7689
|
recordMergeDecision();
|
|
7433
7690
|
progress('pr-opened', `OP 승인 대기 (#${pr.number}): PR 경로 조회 실패`);
|
|
7434
7691
|
return { ok: true, stage: 'pr-opened', node: 'open-pr', ...resolveRunOutcome({ termination: 'completed' }), ...decisionSignalResult, ...preservedCompletionResult, ...(completionStatus ? { completionStatus } : {}), sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), mergeReason, prUrl: pr.url, prNumber: pr.number };
|
|
@@ -7522,6 +7779,16 @@ async function runSelfImplementInner(
|
|
|
7522
7779
|
const m = await withStepTimeout(merging, T.pr, 'pr');
|
|
7523
7780
|
observe('merged', { number: pr.number, merged: m.merged, detail: m.detail ?? null });
|
|
7524
7781
|
if (m.merged) {
|
|
7782
|
+
const mergedBase = m.baseRefName?.trim() || observedPrBase;
|
|
7783
|
+
if (mergedBase && displayBranchName(mergedBase) === 'main') {
|
|
7784
|
+
try {
|
|
7785
|
+
const { syncMergedPrChecklist } = await import('../release-loop/merged-pr-checklist.js');
|
|
7786
|
+
const goalFile = opts.goalFile ?? (opts.goalId ? s.goalDocumentPathByGoalId?.(opts.goalId) : undefined);
|
|
7787
|
+
syncMergedPrChecklist(pr.number, wt.path, goalFile);
|
|
7788
|
+
} catch (error) {
|
|
7789
|
+
observe('merged-pr-checklist-sync-failed', { number: pr.number, error: safeErrorDescription(error) }, { level: 'warn' });
|
|
7790
|
+
}
|
|
7791
|
+
}
|
|
7525
7792
|
try {
|
|
7526
7793
|
await s.supersedeDraftsOnMerge?.(pr.number, wt.path);
|
|
7527
7794
|
} catch (error) {
|
|
@@ -7540,7 +7807,6 @@ async function runSelfImplementInner(
|
|
|
7540
7807
|
observe('release-note-write-failed', { number: pr.number, prUrl: pr.url, directory, fragment, error: safeErrorDescription(error) }, { level: 'error' });
|
|
7541
7808
|
throw new MergedReleaseNoteWriteError(pr.url, directory, fragment, error);
|
|
7542
7809
|
}
|
|
7543
|
-
const mergedBase = m.baseRefName?.trim() || observedPrBase;
|
|
7544
7810
|
const defaultBranch = resolveDefaultBranchTarget(s.defaultBranchRef ?? defaultBranchRef, wt.path).target ?? undefined;
|
|
7545
7811
|
progress('merged', formatAutoMergeSuccessMessage({ prNumber: pr.number, mergedBase, defaultBranch }));
|
|
7546
7812
|
await runPostMergeCleanup(s.postMergeCleanup, wt.path, wt.branch, opts.goalFile, mergedBase && defaultBranch && displayBranchName(mergedBase) === displayBranchName(defaultBranch) ? defaultBranch : undefined, observe);
|
|
@@ -7553,6 +7819,18 @@ async function runSelfImplementInner(
|
|
|
7553
7819
|
prNumber: pr.number,
|
|
7554
7820
|
openedAt: openedAtFromLedger(mergedLedger, new Date().toISOString()),
|
|
7555
7821
|
}, observe);
|
|
7822
|
+
// FOLLOWUP-LOOP① — leftover findings become one follow-up draft. Failure is a log line only;
|
|
7823
|
+
// this return (stage, merged, exit via ok) stays the merge result.
|
|
7824
|
+
await draftFollowUpAfterMerge({
|
|
7825
|
+
prNumber: pr.number,
|
|
7826
|
+
// 정상 병합은 리뷰를 통과한 뒤라 미해결 must-fix 가 없다 — 남은 것은 should-fix ⊕ PR 본문 «남은 조각».
|
|
7827
|
+
// 미해결 must-fix 는 리뷰 예산 수락 경로가 직접 넘긴다(위 acceptance 분기).
|
|
7828
|
+
shouldFix: review?.shouldFix,
|
|
7829
|
+
prBody: [preparedReviewBudgetPrBody, preparedPrBody.body].filter(Boolean).join('\n'),
|
|
7830
|
+
feature: opts.feature,
|
|
7831
|
+
...(opts.goalId ? { cellId: opts.goalId } : {}),
|
|
7832
|
+
...(opts.goalFile ? { goalFile: opts.goalFile } : {}),
|
|
7833
|
+
}, s.followUp);
|
|
7556
7834
|
return { ok: true, stage: 'merged', node: 'merge', ...resolveRunOutcome({ termination: 'completed' }), ...decisionSignalResult, ...preservedCompletionResult, ...(completionStatus ? { completionStatus } : {}), sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), merged: true, ...(mergedBase ? { mergedBase } : {}), prUrl: pr.url, prNumber: pr.number };
|
|
7557
7835
|
}
|
|
7558
7836
|
progress('pr-opened', `병합 실패 — PR 개설됨(#${pr.number}·수동 병합). ${m.detail ?? ''}`);
|