tumwater 0.1.2 → 0.2.0
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/README.md +74 -108
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +24 -0
- package/dist/src/agent/agent-backend.js +2 -2
- package/dist/src/agent/backend-traits.js +60 -0
- package/dist/src/agent/claude/claude-account.js +61 -8
- package/dist/src/agent/claude/claude-args.js +12 -15
- package/dist/src/agent/claude/claude-backend.js +51 -41
- package/dist/src/agent/claude/claude-env.js +7 -3
- package/dist/src/agent/claude/claude-stream.js +7 -16
- package/dist/src/agent/image-input.js +107 -0
- package/dist/src/agent/notes-shim.js +41 -0
- package/dist/src/agent/opencode/opencode-args.js +61 -0
- package/dist/src/agent/opencode/opencode-backend.js +255 -0
- package/dist/src/agent/opencode/opencode-catalog.js +184 -0
- package/dist/src/agent/opencode/opencode-config.js +188 -0
- package/dist/src/agent/opencode/opencode-env.js +36 -0
- package/dist/src/agent/opencode/opencode-session-id.js +37 -0
- package/dist/src/agent/opencode/opencode-stream.js +278 -0
- package/dist/src/agent/role-notes-write.js +16 -32
- package/dist/src/agent/run-agent.js +95 -18
- package/dist/src/agent/session-ledger.js +57 -1
- package/dist/src/backlog/backlog-archive.js +296 -0
- package/dist/src/backlog/backlog-cli.js +573 -0
- package/dist/src/backlog/backlog-commit.js +31 -0
- package/dist/src/backlog/backlog-eligibility.js +357 -33
- package/dist/src/backlog/backlog-md.js +98 -18
- package/dist/src/backlog/backlog-render.js +62 -11
- package/dist/src/backlog/backlog-structure.js +261 -58
- package/dist/src/backlog/backlog-write.js +197 -319
- package/dist/src/backlog/backlog.js +113 -16
- package/dist/src/backlog/question-answer.js +339 -0
- package/dist/src/baseline/main-baseline.js +75 -88
- package/dist/src/baseline/main-red.js +38 -30
- package/dist/src/brief/brief-edit.js +43 -0
- package/dist/src/{brief.js → brief/brief.js} +66 -10
- package/dist/src/budget/budget.js +32 -15
- package/dist/src/budget/fallback-breaker.js +8 -7
- package/dist/src/build/build-check-detect.js +8 -7
- package/dist/src/build/build-check-events.js +68 -22
- package/dist/src/build/build-check-report.js +22 -23
- package/dist/src/build/build-check-scoped.js +51 -62
- package/dist/src/build/build-check.js +15 -14
- package/dist/src/build/build-info.js +2 -1
- package/dist/src/build/build-stage.js +23 -22
- package/dist/src/build/dep-install.js +22 -21
- package/dist/src/build/host-sleep.js +1 -1
- package/dist/src/change/change-data.js +25 -14
- package/dist/src/change/change-render.js +11 -10
- package/dist/src/cli/brief-command.js +58 -0
- package/dist/src/cli/cli-args.js +25 -5
- package/dist/src/cli/cli-command-args.js +46 -14
- package/dist/src/cli/cli-editor.js +64 -0
- package/dist/src/cli/cli-flag-specs.js +54 -16
- package/dist/src/cli/cli-marker-commands.js +13 -10
- package/dist/src/cli/cli-output.js +9 -0
- package/dist/src/cli/cli-query-commands.js +458 -49
- package/dist/src/cli/cli-repo-gate.js +1 -1
- package/dist/src/cli/cli-run.js +208 -59
- package/dist/src/cli/completion.js +207 -0
- package/dist/src/cli/config-commands.js +14 -11
- package/dist/src/cli/help.js +305 -110
- package/dist/src/cli/log-commands.js +127 -21
- package/dist/src/cli/notify-command.js +33 -18
- package/dist/src/cli/question-commands.js +29 -224
- package/dist/src/cli.js +121 -40
- package/dist/src/collections.js +66 -16
- package/dist/src/concurrency/check-permit.js +16 -17
- package/dist/src/concurrency/lock.js +6 -5
- package/dist/src/concurrency/provider-lease.js +69 -0
- package/dist/src/concurrency/semaphore.js +258 -36
- package/dist/src/config/config-aliases.js +106 -0
- package/dist/src/config/config-editable-keys.js +3 -3
- package/dist/src/config/config-fallbacks.js +379 -0
- package/dist/src/config/config-field-checks.js +19 -10
- package/dist/src/config/config-keys.js +160 -0
- package/dist/src/config/config-live.js +64 -12
- package/dist/src/config/config-schema.js +34 -22
- package/dist/src/config/config-validation.js +132 -48
- package/dist/src/config/config-views.js +119 -337
- package/dist/src/config/config-write.js +138 -177
- package/dist/src/config/config.js +60 -49
- package/dist/src/config/model-selector.js +28 -2
- package/dist/src/doctor/doctor-backlog.js +546 -49
- package/dist/src/doctor/doctor-checks.js +534 -56
- package/dist/src/doctor/doctor-holds.js +193 -53
- package/dist/src/doctor/doctor-install.js +30 -0
- package/dist/src/doctor/doctor-launch-services.js +2 -2
- package/dist/src/doctor/doctor-model-checks.js +549 -157
- package/dist/src/doctor/doctor-notify.js +27 -0
- package/dist/src/doctor/doctor-orphans.js +10 -9
- package/dist/src/doctor/doctor-render.js +36 -9
- package/dist/src/doctor/doctor.js +80 -22
- package/dist/src/doctor/image-probe.js +244 -0
- package/dist/src/doctor/probe.js +64 -0
- package/dist/src/events/event-format.js +226 -102
- package/dist/src/events/event-labels.js +116 -0
- package/dist/src/events/event-legacy.js +140 -0
- package/dist/src/events/event-read.js +58 -22
- package/dist/src/events/event-window.js +27 -7
- package/dist/src/events/events.js +18 -14
- package/dist/src/events/notify.js +137 -38
- package/dist/src/failure/failure-cluster.js +12 -9
- package/dist/src/failure/failure-data.js +96 -48
- package/dist/src/failure/failure-render.js +69 -58
- package/dist/src/failure/failure-state-change.js +33 -26
- package/dist/src/failure/time-spend.js +79 -59
- package/dist/src/files/file-queue.js +16 -4
- package/dist/src/files/files.js +18 -6
- package/dist/src/files/json-object.js +18 -3
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +5 -4
- package/dist/src/gates/budget-gates.js +250 -34
- package/dist/src/gates/disk-gate.js +18 -18
- package/dist/src/gates/gate-polls.js +117 -69
- package/dist/src/gates/maintenance-quota.js +29 -29
- package/dist/src/gates/pause-gates.js +11 -11
- package/dist/src/gates/readiness.js +2 -1
- package/dist/src/gates/role-cap-gates.js +16 -21
- package/dist/src/gates/startup-gate.js +75 -31
- package/dist/src/gates/streak-gate.js +18 -16
- package/dist/src/git/commit-message.js +12 -5
- package/dist/src/git/git-diff.js +16 -16
- package/dist/src/git/git-run.js +8 -8
- package/dist/src/git/git.js +86 -55
- package/dist/src/git/slots-state.js +14 -5
- package/dist/src/git/worktree-pool.js +25 -18
- package/dist/src/git/worktree-use.js +15 -14
- package/dist/src/git/worktree.js +18 -18
- package/dist/src/gui/gui-args.js +10 -14
- package/dist/src/gui/gui-backlog-commands.js +273 -0
- package/dist/src/gui/gui-command.js +1 -1
- package/dist/src/gui/gui-config-commands.js +440 -0
- package/dist/src/gui/gui-endpoint-commands.js +16 -669
- package/dist/src/gui/gui-endpoint-common.js +49 -0
- package/dist/src/gui/gui-endpoints.js +116 -56
- package/dist/src/gui/gui-operator-commands.js +145 -0
- package/dist/src/gui/gui-prompt-commands.js +234 -0
- package/dist/src/gui/gui-server.js +28 -8
- package/dist/src/gui/gui-team-commands.js +164 -0
- package/dist/src/gui/http-body.js +17 -1
- package/dist/src/history/history-data.js +194 -98
- package/dist/src/history/history-render.js +76 -0
- package/dist/src/history/history.js +37 -58
- package/dist/src/inbox/inbox-attachments.js +75 -14
- package/dist/src/inbox/inbox-cancel.js +7 -5
- package/dist/src/inbox/inbox-edit.js +1 -1
- package/dist/src/inbox/inbox-submit.js +44 -4
- package/dist/src/inbox/inbox-top.js +83 -0
- package/dist/src/inbox/inbox.js +8 -2
- package/dist/src/inbox/pending-prompt.js +1 -1
- package/dist/src/inbox/prompt-commands.js +170 -80
- package/dist/src/init/init-templates.js +16 -14
- package/dist/src/init/init.js +12 -11
- package/dist/src/loop/leftover.js +28 -27
- package/dist/src/loop/loop-fallback.js +2 -2
- package/dist/src/loop/loop-pi.js +106 -52
- package/dist/src/loop/loop-recovery.js +15 -15
- package/dist/src/loop/loop-state.js +139 -13
- package/dist/src/loop/loop-tick.js +194 -86
- package/dist/src/loop/loop.js +72 -36
- package/dist/src/loop/model-fallback.js +3 -2
- package/dist/src/loop/revision.js +16 -7
- package/dist/src/merge/backlog-conflicts.js +155 -0
- package/dist/src/{landing/landing-batch.js → merge/merge-batch.js} +90 -89
- package/dist/src/{landing/landing-check-failures.js → merge/merge-check-failures.js} +87 -41
- package/dist/src/{landing/landing-core.js → merge/merge-core.js} +119 -95
- package/dist/src/{landing/landing-diff.js → merge/merge-diff.js} +1 -1
- package/dist/src/merge/merge-drain.js +212 -0
- package/dist/src/{landing/landing-git.js → merge/merge-git.js} +94 -21
- package/dist/src/merge/merge-pipeline.js +99 -0
- package/dist/src/{landing/landing-questions.js → merge/merge-questions.js} +9 -6
- package/dist/src/merge/merge-queue-render.js +75 -0
- package/dist/src/{landing/landing-queue.js → merge/merge-queue.js} +95 -36
- package/dist/src/merge/merge-slot.js +340 -0
- package/dist/src/{landing/landing-stack.js → merge/merge-stack.js} +66 -62
- package/dist/src/{landing/landing-merge.js → merge/merge-to-main.js} +72 -62
- package/dist/src/merge/merge-verify.js +212 -0
- package/dist/src/notes-cli.js +97 -0
- package/dist/src/operator/operator-commands.js +154 -47
- package/dist/src/operator/operator-intent.js +87 -49
- package/dist/src/operator/operator-requests.js +52 -52
- package/dist/src/operator/retire.js +62 -27
- package/dist/src/operator/revert.js +71 -0
- package/dist/src/orchestrator/orchestrator-launch.js +74 -14
- package/dist/src/orchestrator/orchestrator-scheduling.js +129 -44
- package/dist/src/orchestrator/orchestrator.js +158 -100
- package/dist/src/orchestrator/retention.js +29 -12
- package/dist/src/orchestrator/startup-migration-steps.js +51 -0
- package/dist/src/orchestrator/startup-migrations.js +40 -0
- package/dist/src/paths.js +128 -37
- package/dist/src/pi/pi-args.js +26 -3
- package/dist/src/pi/pi-backend.js +15 -23
- package/dist/src/pi/pi-bin.js +18 -12
- package/dist/src/pi/pi-event-line.js +17 -1
- package/dist/src/pi/pi-failure.js +87 -0
- package/dist/src/pi/pi-models.js +126 -38
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +86 -0
- package/dist/src/pi/pi-stream.js +131 -107
- package/dist/src/pi/pi-watchdogs.js +47 -43
- package/dist/src/pi-extension/bounded-output.js +20 -5
- package/dist/src/pi-extension/context-budget.js +3 -1
- package/dist/src/pi-extension/context-shake.js +54 -21
- package/dist/src/pi-extension/context-window.js +37 -0
- package/dist/src/pi-extension/full-output.js +2 -2
- package/dist/src/pi-extension/strip-thinking.js +80 -0
- package/dist/src/pi-extension/trim-system-prompt.js +38 -0
- package/dist/src/process/launch-services.js +11 -10
- package/dist/src/process/process-table.js +1 -1
- package/dist/src/process/process.js +7 -7
- package/dist/src/process/run-marker.js +29 -6
- package/dist/src/process/supervisor.js +47 -25
- package/dist/src/prompt/dialect.js +30 -10
- package/dist/src/prompt/gate-prompts.js +170 -67
- package/dist/src/prompt/principles.js +1 -0
- package/dist/src/prompt/prompt-followup.js +35 -20
- package/dist/src/prompt/prompt.js +249 -91
- package/dist/src/redeploy/redeploy-policy.js +10 -10
- package/dist/src/redeploy/redeploy.js +6 -4
- package/dist/src/redeploy/redeployer.js +63 -55
- package/dist/src/redeploy/self-reload.js +1 -1
- package/dist/src/report/report-data.js +264 -255
- package/dist/src/report/report-fold.js +353 -0
- package/dist/src/report/report-render.js +270 -33
- package/dist/src/request-timeouts.js +1 -1
- package/dist/src/review/known-flakes.js +34 -14
- package/dist/src/review/protected-edits.js +33 -0
- package/dist/src/review/review-followup.js +16 -4
- package/dist/src/review/review-precheck.js +14 -13
- package/dist/src/review/review-verdict.js +14 -0
- package/dist/src/review/review.js +81 -39
- package/dist/src/review/secret-leaks.js +127 -0
- package/dist/src/review/suite-rerun.js +4 -3
- package/dist/src/roles/legacy-role-ids.js +21 -0
- package/dist/src/roles/legacy-role-migration.js +62 -0
- package/dist/src/roles/loop-ids.js +19 -2
- package/dist/src/roles/role-catalog.js +125 -135
- package/dist/src/roles/role-guidance.js +64 -31
- package/dist/src/roles/role-labels.js +10 -0
- package/dist/src/roles/role-render.js +194 -18
- package/dist/src/roles/role-view.js +216 -17
- package/dist/src/roles/roles.js +18 -15
- package/dist/src/scheduling/backoff.js +29 -19
- package/dist/src/scheduling/claims.js +25 -9
- package/dist/src/scheduling/once-round.js +11 -11
- package/dist/src/scheduling/quiet-hours.js +25 -32
- package/dist/src/scheduling/scheduling.js +43 -24
- package/dist/src/scheduling/{work-landed-cache.js → work-merged-cache.js} +14 -14
- package/dist/src/status/status-budget.js +115 -0
- package/dist/src/status/status-data.js +77 -184
- package/dist/src/status/status-inbox.js +47 -0
- package/dist/src/status/status-install.js +27 -0
- package/dist/src/status/status-polls.js +68 -33
- package/dist/src/status/status-roles.js +105 -0
- package/dist/src/{fleet → team}/error-storm.js +10 -10
- package/dist/src/{fleet → team}/failure-spread.js +8 -8
- package/dist/src/{fleet → team}/orchestrator-info.js +86 -18
- package/dist/src/{fleet → team}/reclaim.js +5 -4
- package/dist/src/{fleet/fleet-hold.js → team/team-hold.js} +55 -21
- package/dist/src/{fleet/fleet-polls.js → team/team-polls.js} +116 -65
- package/dist/src/{fleet/fleet-state.js → team/team-state.js} +62 -37
- package/dist/src/text/datetime.js +42 -2
- package/dist/src/text/format.js +10 -1
- package/dist/src/text/markdown.js +1 -1
- package/dist/src/text/phrases.js +35 -34
- package/dist/src/text/suggest.js +3 -2
- package/dist/src/text/text.js +2 -2
- package/dist/src/tick/qa-coverage.js +2 -1
- package/dist/src/tick/stage-check.js +147 -26
- package/dist/src/tick/telemetry-digest.js +10 -9
- package/dist/src/tick/tick-apply.js +101 -72
- package/dist/src/tick/tick-detail-data.js +32 -18
- package/dist/src/tick/tick-detail.js +62 -21
- package/dist/src/tick/tick-finalize.js +29 -22
- package/dist/src/tick/tick-outcome.js +2 -1
- package/dist/src/tick/tick-prompt.js +94 -26
- package/dist/src/tick/tick-resume.js +29 -13
- package/dist/src/tick/tick-stage.js +91 -47
- package/dist/src/tick/tick-timing.js +60 -59
- package/dist/src/tick/tick-usage.js +53 -23
- package/dist/src/tick/tick-verdict.js +76 -10
- package/dist/src/ui/badges.js +118 -67
- package/dist/src/ui/gui/gui-client-boot.js +209 -30
- package/dist/src/ui/gui/gui-client-composer.js +102 -23
- package/dist/src/ui/gui/gui-client-drawer.js +330 -75
- package/dist/src/ui/gui/gui-client-history.js +96 -38
- package/dist/src/ui/gui/gui-client-labels.js +24 -0
- package/dist/src/ui/gui/gui-client-loops.js +94 -52
- package/dist/src/ui/gui/gui-client-markdown.js +1 -0
- package/dist/src/ui/gui/gui-client-model.js +63 -43
- package/dist/src/ui/gui/gui-client-operator.js +129 -39
- package/dist/src/ui/gui/gui-client-pending.js +36 -32
- package/dist/src/ui/gui/gui-client-report.js +339 -46
- package/dist/src/ui/gui/gui-client-settings.js +148 -14
- package/dist/src/ui/gui/gui-client-sound.js +2 -1
- package/dist/src/ui/gui/{gui-client-fleet.js → gui-client-team.js} +196 -72
- package/dist/src/ui/gui/gui-client.js +26 -20
- package/dist/src/ui/gui/gui-page.js +19 -19
- package/dist/src/ui/gui/gui-styles.js +12 -4
- package/dist/src/ui/progress-data.js +5 -3
- package/dist/src/ui/status-model.js +184 -122
- package/dist/src/ui/status-payload.js +119 -32
- package/dist/src/ui/status-render.js +122 -52
- package/dist/src/ui/team-alerts.js +341 -0
- package/dist/src/ui/tick-progress-model.js +14 -14
- package/dist/src/ui/tone.js +11 -8
- package/dist/src/ui/transcript-tail.js +1 -0
- package/dist/src/ui/transcript.js +23 -16
- package/dist/src/ui/tui/tui-app.js +1 -0
- package/dist/src/ui/tui/tui-backlog.js +85 -11
- package/dist/src/ui/tui/tui-editor-answer.js +97 -0
- package/dist/src/ui/tui/tui-editor-attach.js +107 -0
- package/dist/src/ui/tui/tui-editor-brief.js +107 -0
- package/dist/src/ui/tui/tui-editor-budget.js +155 -0
- package/dist/src/ui/tui/tui-editor-ctx.js +1 -0
- package/dist/src/ui/tui/tui-editor-entry.js +230 -0
- package/dist/src/ui/tui/tui-editor-interval.js +122 -0
- package/dist/src/ui/tui/tui-editor-notes.js +114 -0
- package/dist/src/ui/tui/tui-editor-pause.js +266 -0
- package/dist/src/ui/tui/tui-editor-prompt.js +95 -0
- package/dist/src/ui/tui/tui-editor-queued.js +98 -0
- package/dist/src/ui/tui/tui-editor-quiet.js +106 -0
- package/dist/src/ui/tui/tui-editor-retire.js +83 -0
- package/dist/src/ui/tui/tui-editor-search.js +73 -0
- package/dist/src/ui/tui/tui-editor-session.js +97 -0
- package/dist/src/ui/tui/tui-editors.js +152 -0
- package/dist/src/ui/tui/tui-frame.js +67 -55
- package/dist/src/ui/tui/tui-history.js +12 -7
- package/dist/src/ui/tui/tui-input.js +49 -44
- package/dist/src/ui/tui/tui-keymap.js +1 -0
- package/dist/src/ui/tui/tui-keys.js +91 -1704
- package/dist/src/ui/tui/tui-pane-activity.js +99 -0
- package/dist/src/ui/tui/tui-pane-backlog.js +224 -0
- package/dist/src/ui/tui/tui-pane-brief.js +30 -0
- package/dist/src/ui/tui/tui-pane-ctx.js +11 -0
- package/dist/src/ui/tui/tui-pane-health.js +124 -0
- package/dist/src/ui/tui/tui-pane-history.js +316 -0
- package/dist/src/ui/tui/tui-pane-pending.js +74 -0
- package/dist/src/ui/tui/tui-pane-queued.js +143 -0
- package/dist/src/ui/tui/tui-pane-report.js +122 -0
- package/dist/src/ui/tui/tui-pane-session.js +101 -0
- package/dist/src/ui/tui/tui-pane-transcript.js +150 -0
- package/dist/src/ui/tui/tui-pane.js +66 -28
- package/dist/src/ui/tui/tui-panes.js +294 -0
- package/dist/src/ui/tui/tui.js +45 -25
- package/dist/src/verdict/fix-claim.js +141 -38
- package/dist/src/verdict/no-change.js +19 -0
- package/dist/src/verdict/refusal.js +92 -8
- package/dist/src/verdict/reply-contract.js +17 -5
- package/dist/src/version.js +3 -2
- package/package.json +4 -2
- package/dist/src/agent/mcp/role-notes-server.js +0 -160
- package/dist/src/landing/backlog-conflicts.js +0 -116
- package/dist/src/landing/landing-drain.js +0 -204
- package/dist/src/landing/landing-pipeline.js +0 -96
- package/dist/src/landing/landing-queue-render.js +0 -31
- package/dist/src/landing/landing-slot.js +0 -246
- package/dist/src/landing/landing-vetting.js +0 -196
- package/dist/src/pi-extension/role-notes.js +0 -40
- package/dist/src/ui/fleet-alerts.js +0 -174
|
@@ -1,34 +1,24 @@
|
|
|
1
|
+
// vocabulary: plain
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { loadConfigSafe } from "../config/config.js";
|
|
4
|
-
import {
|
|
5
|
+
import { seamsInUse } from "../config/config-fallbacks.js";
|
|
5
6
|
import { findOnPath } from "../files/files.js";
|
|
6
7
|
import { GIT_MISSING_MESSAGE } from "../git/git-run.js";
|
|
7
8
|
import { branchesPhrase, branchExists, currentBranch, hasCommits, isGitRepo } from "../git/git.js";
|
|
8
9
|
import { DETACHED_HEAD_MESSAGE, NOT_A_REPO_MESSAGE, NOT_INITIALIZED_MESSAGE, NO_COMMITS_MESSAGE, } from "./readiness.js";
|
|
9
10
|
import { agentMissingMessage, findAgentBinary, resolveAgentBin } from "../pi/pi-bin.js";
|
|
10
11
|
import { seedClaudeAccount } from "../agent/claude/claude-account.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* before its swap, and the supervisor (src/process/supervisor.ts) asks it to name why a generation
|
|
17
|
-
* died. On 2026-09-22 only the first existed: a redeploy swapped onto a build whose child found
|
|
18
|
-
* tumwater.json missing, exited "not initialized", and the supervisor exited with it — 4 h 44 m
|
|
19
|
-
* of a dead fleet and no event (BUGS.md 2026-09-23). The operator-facing wording lives in
|
|
20
|
-
* readiness.ts, shared with doctor's per-check report.
|
|
21
|
-
*
|
|
22
|
-
* The one startup check deliberately outside the gate is cmdRun's "an orchestrator is already
|
|
23
|
-
* running": to a redeploy asking on behalf of its successor, the live orchestrator is itself —
|
|
24
|
-
* gone by the time the successor boots. The gate is the ASKER's build's rule, so a redeploy checks
|
|
25
|
-
* what the running build knows of startup; a precondition the new build adds is invisible to it
|
|
26
|
-
* until that build runs. */
|
|
12
|
+
import { refreshOpencodeCatalog } from "../agent/opencode/opencode-catalog.js";
|
|
13
|
+
import { agentBackend } from "../agent/agent-backend.js";
|
|
14
|
+
// Register the built-in pi and claude adapters into the registry this module reads (see
|
|
15
|
+
// unregisteredBackendInUse) — importing run-agent.ts is the one place they register.
|
|
16
|
+
import "../agent/run-agent.js";
|
|
27
17
|
/** The repo-level preconditions every repo-bound command shares (requireReadyRepo in
|
|
28
18
|
* cli/cli-repo-gate.ts): git
|
|
29
19
|
* on PATH, a repository, tumwater.json present, at least one commit. The first unmet one's
|
|
30
20
|
* message, or null when the repo is ready. A missing tumwater.json is "not initialized" here,
|
|
31
|
-
* never "use defaults": starting a
|
|
21
|
+
* never "use defaults": starting a team is the moment an operator's config must exist. */
|
|
32
22
|
export async function repoNotReady(root) {
|
|
33
23
|
// Fail fast on a missing binary: without this, the probe below reads as "not a git
|
|
34
24
|
// repository" — pointing at the wrong fix for a machine with no git installed.
|
|
@@ -49,13 +39,24 @@ export async function repoNotReady(root) {
|
|
|
49
39
|
export async function runStartupCheck(root,
|
|
50
40
|
/** The `--branch` flag of the invocation (null when absent) — the supervisor forwards it to
|
|
51
41
|
* every generation, so every asker must pass the same one. */
|
|
52
|
-
branchArg
|
|
42
|
+
branchArg,
|
|
43
|
+
/** The opencode-catalog seed's injectable parts — tests only; production callers omit it and
|
|
44
|
+
* the seed uses the real models.dev fetch (see OpenCodeSeedOptions). */
|
|
45
|
+
opencodeSeed = {}) {
|
|
53
46
|
const notReady = await repoNotReady(root);
|
|
54
47
|
if (notReady !== null)
|
|
55
48
|
return { problem: notReady };
|
|
56
49
|
const { config, error } = loadConfigSafe(root);
|
|
57
50
|
if (config === undefined)
|
|
58
51
|
return { problem: error };
|
|
52
|
+
// A backend an enabled seam routes to that this build has no registered adapter for cannot
|
|
53
|
+
// run its jobs: refuse to start rather than letting the run fall through to pi with a model
|
|
54
|
+
// id pi cannot serve (plans/opencode-backend.md part 2/7). Read the registry through
|
|
55
|
+
// run-agent.ts, whose module scope registers the built-in pi and claude adapters.
|
|
56
|
+
const unregistered = unregisteredBackendInUse(config);
|
|
57
|
+
if (unregistered !== undefined) {
|
|
58
|
+
return { problem: `backend ${unregistered} is configured but this build has no adapter for it` };
|
|
59
|
+
}
|
|
59
60
|
// Fail fast instead of starting loops whose every tick dies with "spawn <bin> ENOENT". Every
|
|
60
61
|
// enabled seam's agent — the top-level `agent` plus each enabled loop's resolved view and the
|
|
61
62
|
// reviewer — resolves through the same resolveAgentBin the spawn uses (and doctor's pi check);
|
|
@@ -71,7 +72,7 @@ branchArg) {
|
|
|
71
72
|
}
|
|
72
73
|
// Seed the claude account state before the first run (plans/agent-backends.md part 6a):
|
|
73
74
|
// `claude auth status` decides subscription vs API key, and an existing file is left alone.
|
|
74
|
-
// Gated on a claude seam so a pi-only
|
|
75
|
+
// Gated on a claude seam so a pi-only team spawns nothing, and attempted once per root per
|
|
75
76
|
// process: runStartupCheck is also the redeploy/supervisor poll's ask (runStartupProblem),
|
|
76
77
|
// and a logged-out claude would otherwise spawn a bounded probe on every poll. If the seed
|
|
77
78
|
// fails, the first claude run's observation fills the file in.
|
|
@@ -79,6 +80,22 @@ branchArg) {
|
|
|
79
80
|
claudeSeedAttempted.add(root);
|
|
80
81
|
seedClaudeAccount(root, config);
|
|
81
82
|
}
|
|
83
|
+
// Seed the opencode models catalog (part 6b/7) before the first run: the poll surfaces price
|
|
84
|
+
// opencode seams from the cached `.tumwater/state/opencode-models.json`, and an absent cache
|
|
85
|
+
// reads every opencode seam NOT free (the safe direction for the budget gate). Mirroring the
|
|
86
|
+
// claude seed above, it runs once per root per process when a model job routes to opencode;
|
|
87
|
+
// a failed fetch keeps the last good cache (or an empty one) and never blocks startup.
|
|
88
|
+
if (!opencodeSeedAttempted.has(root) && agentsInUse(config).includes("opencode")) {
|
|
89
|
+
opencodeSeedAttempted.add(root);
|
|
90
|
+
await refreshOpencodeCatalog(root, {
|
|
91
|
+
providers: opencodeProviders(config),
|
|
92
|
+
// Probe the configured opencode binary (not a different one on PATH) for the version, so
|
|
93
|
+
// the freshness check compares against the binary the team actually runs.
|
|
94
|
+
cliBin: resolveAgentBin(config, "opencode").bin,
|
|
95
|
+
fetch: opencodeSeed.fetch,
|
|
96
|
+
now: opencodeSeed.now,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
82
99
|
const branch = await resolveMainBranch(root, config, branchArg);
|
|
83
100
|
if ("problem" in branch)
|
|
84
101
|
return branch;
|
|
@@ -88,17 +105,44 @@ branchArg) {
|
|
|
88
105
|
* so the supervisor's and redeploy's repeated startup checks do not respawn `claude auth
|
|
89
106
|
* status` on every poll when the probe fails. */
|
|
90
107
|
const claudeSeedAttempted = new Set();
|
|
91
|
-
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
|
|
108
|
+
/** Roots this process has already attempted an opencode-catalog seed for (see runStartupCheck),
|
|
109
|
+
* so the supervisor's and redeploy's repeated startup checks do not respawn the models.dev
|
|
110
|
+
* fetch on every poll when it fails. */
|
|
111
|
+
const opencodeSeedAttempted = new Set();
|
|
112
|
+
/** The models.dev providers the config routes through OpenCode beyond its own gateway, which
|
|
113
|
+
* the catalog parse (part 6a/7) keeps only when named here (finding 10's `opencode-go` and so
|
|
114
|
+
* on). A bare gateway seam (`opencode/<id>`) adds nothing — `opencode` is always kept. Each
|
|
115
|
+
* provider is the model id's segment before the first `/` — `opencode/anthropic/…` routes to
|
|
116
|
+
* models.dev's `anthropic` provider, so its catalog key is `anthropic/<id>` — read from the
|
|
117
|
+
* same seam enumeration the startup gate already sweeps for binaries. */
|
|
118
|
+
export function opencodeProviders(config) {
|
|
119
|
+
const providers = new Set();
|
|
120
|
+
for (const seam of seamsInUse(config)) {
|
|
121
|
+
if (seam.agent !== "opencode")
|
|
122
|
+
continue;
|
|
123
|
+
const m = seam.model;
|
|
124
|
+
if (m?.includes("/"))
|
|
125
|
+
providers.add(m.slice(0, m.indexOf("/")));
|
|
126
|
+
}
|
|
127
|
+
return [...providers];
|
|
128
|
+
}
|
|
129
|
+
/** Every agent backend an enabled seam resolves to — the distinct agents of the one
|
|
130
|
+
* seamsInUse list (startup-gate's consumer of it), so a claude or pi clause that exists only
|
|
131
|
+
* as a fallback, the resolver, or the director is checked exactly like a primary seam.
|
|
132
|
+
* One list the startup gate and doctor's binary check share, so a route the harness would
|
|
133
|
+
* spawn is checked on both surfaces. */
|
|
95
134
|
export function agentsInUse(config) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
135
|
+
return [...new Set(seamsInUse(config).map((s) => s.agent ?? "pi"))];
|
|
136
|
+
}
|
|
137
|
+
/** The first backend an enabled seam routes to that this build has no registered adapter for,
|
|
138
|
+
* or undefined when every seam's backend is registered. The built-in pi and claude adapters
|
|
139
|
+
* are registered by importing src/agent/run-agent.ts (see the import above); a seam backend
|
|
140
|
+
* that is not in the registry is one this build cannot run. Doctor's binary check asks the
|
|
141
|
+
* same question, so the startup gate and doctor cannot disagree about which backend a build
|
|
142
|
+
* can serve. After the opencode adapter lands (part 5/7) this stays the general rule for any
|
|
143
|
+
* future id. */
|
|
144
|
+
export function unregisteredBackendInUse(config) {
|
|
145
|
+
return agentsInUse(config).find((agent) => agentBackend(agent) === undefined);
|
|
102
146
|
}
|
|
103
147
|
/** runStartupCheck reduced to its verdict: the message a generation would fail on right now, or
|
|
104
148
|
* null when one would boot — what the redeploy and the supervisor ask. */
|
|
@@ -106,7 +150,7 @@ export async function runStartupProblem(root, branchArg) {
|
|
|
106
150
|
const check = await runStartupCheck(root, branchArg);
|
|
107
151
|
return "problem" in check ? check.problem : null;
|
|
108
152
|
}
|
|
109
|
-
/** The branch the
|
|
153
|
+
/** The branch the team targets: `--branch <name>` wins, then `baseBranch` in config, then
|
|
110
154
|
* whatever the primary checkout has checked out — the branch-agnostic default. An explicit
|
|
111
155
|
* value must exist: failing at startup with the branches that do exist beats failing at the
|
|
112
156
|
* first `git worktree add`. */
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/** The error-streak circuit breaker (PLANS.md 2026-09-30): a role whose ticks keep failing
|
|
2
|
-
* consecutively is warned at ERROR_STREAK_WARN (src/tick/tick-apply.ts) and named by the
|
|
3
|
-
* storm alarms (src/
|
|
2
|
+
* consecutively is warned at ERROR_STREAK_WARN (src/tick/tick-apply.ts) and named by the team-wide
|
|
3
|
+
* storm alarms (src/team/error-storm.ts, src/team/failure-spread.ts), but both only talk — the
|
|
4
4
|
* role keeps ticking on the error ladder's 600 s max backoff forever, burning a model slot and
|
|
5
5
|
* spend on a loop that cannot succeed. Past ERROR_STREAK_BREAKER consecutive failed ticks this gate
|
|
6
6
|
* pauses the role through the same per-role pause marker the operator's `tumwater pause --role
|
|
7
|
-
* <id>` writes (src/
|
|
7
|
+
* <id>` writes (src/team/team-state.ts's pauseRole — the marker, lock, and idempotence come
|
|
8
8
|
* free), so the scheduler's existing pausedRolesSet skip blocks new ticks with zero scheduler
|
|
9
9
|
* changes. The director is NOT exempt: a failing director cannot process prompts anyway, and one
|
|
10
10
|
* uniform rule needs no carve-out. `tumwater resume --role <id>` (or the dashboard's per-row
|
|
11
11
|
* toggle) lifts it, as today.
|
|
12
12
|
*
|
|
13
13
|
* Shape, like every gate in the family (src/gates/gate-polls.ts): the pure trip bookkeeping lives
|
|
14
|
-
* here so it is unit-testable without a
|
|
14
|
+
* here so it is unit-testable without a team, and the module owns the only event emission — the
|
|
15
15
|
* orchestrator's poll owns only the wiring.
|
|
16
16
|
*
|
|
17
17
|
* Ack bookkeeping. The marker itself is the ack carrier: every poll, each role present in the
|
|
@@ -26,12 +26,13 @@
|
|
|
26
26
|
* the ack: the next episode trips on its own fresh ERROR_STREAK_BREAKER failures.
|
|
27
27
|
*
|
|
28
28
|
* Accepted behavior, stated here and not fixed in this change: the dashboards' "failing tick after
|
|
29
|
-
* tick" alert (src/ui/
|
|
29
|
+
* tick" alert (src/ui/team-alerts.ts) reads consecutiveErrors regardless of pause, so it keeps
|
|
30
30
|
* listing a breaker-paused role until the streak clears; the loop cell's paused badge explains why
|
|
31
31
|
* it is not ticking, and the role_streak_paused event tells the operator why. */
|
|
32
32
|
import { ERROR_STREAK_BREAKER } from "../tick/tick-apply.js";
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
33
|
+
import { loopPaused } from "../roles/loop-ids.js";
|
|
34
|
+
import { pauseRole } from "../team/team-state.js";
|
|
35
|
+
import { logEventBestEffort, TUMWATER_SOURCE } from "../events/events.js";
|
|
35
36
|
/** A fresh gate state: nothing acked, so a live streak at or past the breaker trips on the
|
|
36
37
|
* first poll (the durable-cause case a restart after an operator resume relies on). */
|
|
37
38
|
export function newStreakGateState() {
|
|
@@ -40,21 +41,22 @@ export function newStreakGateState() {
|
|
|
40
41
|
/** Step the gate by one orchestrator poll. For each runner whose consecutive error streak
|
|
41
42
|
* has reached ERROR_STREAK_BREAKER plus what its ack already excused, and whose role is not
|
|
42
43
|
* in `pausedRoles`: write the per-role pause marker and log one `role_streak_paused` event
|
|
43
|
-
* carrying the role, the streak, and the last error. Returns the
|
|
44
|
-
*
|
|
45
|
-
*
|
|
44
|
+
* carrying the role, the streak, and the last error. Returns the pause keys this poll wrote
|
|
45
|
+
* (`pauseKey` maps a loop id to its marker key; instance 1 of a multi-instance role pauses as
|
|
46
|
+
* `<role>-1`), so the wiring can fold them into the poll's paused-roles view and the scheduler
|
|
47
|
+
* blocks them on this very poll, not the next one.
|
|
46
48
|
*
|
|
47
49
|
* Roles already paused are acked instead of tripped (the ack carrier is the marker itself,
|
|
48
50
|
* per the module doc), a healthy streak clears its ack, and a streak below its bar leaves
|
|
49
51
|
* the state untouched — so repeated polls while a breaker-paused role stays paused log
|
|
50
52
|
* nothing more, and pauseRole's own idempotence backstops any race. */
|
|
51
|
-
export function pollStreakGate(root, state, runners, pausedRoles) {
|
|
53
|
+
export function pollStreakGate(root, state, runners, pausedRoles, pauseKey = (r) => r) {
|
|
52
54
|
const tripped = [];
|
|
53
55
|
for (const { role, state: s } of runners) {
|
|
54
56
|
const streak = s.consecutiveErrors ?? 0;
|
|
55
57
|
// Ack while paused: the marker is the ack carrier. The streak is frozen while a role is
|
|
56
58
|
// paused (no ticks run), so recording it here is exactly the level the resume excuses.
|
|
57
|
-
if (pausedRoles
|
|
59
|
+
if (loopPaused(pausedRoles, role)) {
|
|
58
60
|
state.acked.set(role, streak);
|
|
59
61
|
continue;
|
|
60
62
|
}
|
|
@@ -71,15 +73,15 @@ export function pollStreakGate(root, state, runners, pausedRoles) {
|
|
|
71
73
|
// ERROR_STREAK_BREAKER more failures from this level, whether or not any poll sees the
|
|
72
74
|
// role paused in between (an operator resume racing the next poll must not re-trip).
|
|
73
75
|
state.acked.set(role, streak);
|
|
74
|
-
if (pauseRole(root, role)) {
|
|
76
|
+
if (pauseRole(root, pauseKey(role))) {
|
|
75
77
|
logEventBestEffort(root, {
|
|
76
|
-
|
|
78
|
+
source: TUMWATER_SOURCE,
|
|
77
79
|
type: "role_streak_paused",
|
|
78
|
-
role,
|
|
80
|
+
role: pauseKey(role),
|
|
79
81
|
streak,
|
|
80
82
|
...(s.lastError ? { lastError: s.lastError } : {}),
|
|
81
83
|
});
|
|
82
|
-
tripped.push(role);
|
|
84
|
+
tripped.push(pauseKey(role));
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
return tripped;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// vocabulary: plain
|
|
1
2
|
import { truncate } from "../text/text.js";
|
|
2
3
|
import { compactTokens } from "../text/format.js";
|
|
3
4
|
import { labeledLine } from "../verdict/reply-contract.js";
|
|
@@ -12,6 +13,12 @@ import { labeledLine } from "../verdict/reply-contract.js";
|
|
|
12
13
|
* bloat every commit subject. Truncated with an ellipsis — like the body fields below — rather
|
|
13
14
|
* than silently cut mid-word, which would read as if the subject were complete. */
|
|
14
15
|
const COMMIT_SUMMARY_MAX = 100;
|
|
16
|
+
/** The untruncated SUMMARY length when it exceeds COMMIT_SUMMARY_MAX (extractSummary would cut
|
|
17
|
+
* it); null when it fits or the reply has no SUMMARY line. */
|
|
18
|
+
export function summaryOverCap(finalText) {
|
|
19
|
+
const summary = labeledLine(finalText, "SUMMARY");
|
|
20
|
+
return summary !== null && summary.length > COMMIT_SUMMARY_MAX ? summary.length : null;
|
|
21
|
+
}
|
|
15
22
|
/** Pull the SUMMARY: line out of a pi final reply; null when absent. Capped at
|
|
16
23
|
* COMMIT_SUMMARY_MAX chars with an ellipsis (consistent with extractCommitBody's field cap). */
|
|
17
24
|
export function extractSummary(finalText) {
|
|
@@ -21,11 +28,11 @@ export function extractSummary(finalText) {
|
|
|
21
28
|
/** The subject for a changed tick whose reply — and whose follow-up request — carried no
|
|
22
29
|
* SUMMARY line: named from what actually changed, so the log still says what the commit touched
|
|
23
30
|
* instead of only which loop made it. Up to three repo-relative paths (worktree order), then a
|
|
24
|
-
* count; capped like a real summary. Falls back to the bare "<role>
|
|
31
|
+
* count; capped like a real summary. Falls back to the bare "<role> run N" only when nothing is
|
|
25
32
|
* known. */
|
|
26
33
|
export function fallbackSummary(files, role, tick) {
|
|
27
34
|
if (files.length === 0)
|
|
28
|
-
return `${role}
|
|
35
|
+
return `${role} run ${tick}`;
|
|
29
36
|
const shown = files.slice(0, 3).join(", ");
|
|
30
37
|
const rest = files.length > 3 ? ` and ${files.length - 3} more` : "";
|
|
31
38
|
return truncate(`Update ${shown}${rest}`, COMMIT_SUMMARY_MAX);
|
|
@@ -75,11 +82,11 @@ export function formatCommitBody(body) {
|
|
|
75
82
|
/** The harness-stamped trailer line of every tick commit — truth from the run's counters, not
|
|
76
83
|
* model claims. `turns` sums this tick's pre-commit pi runs (main + transient retry); `peakCtx`
|
|
77
84
|
* is their largest single-request context. A changed tick flagged high-friction (plans/
|
|
78
|
-
* refusal-and-thrash.md) appends a sibling Friction line after the
|
|
85
|
+
* refusal-and-thrash.md) appends a sibling Friction line after the Run line — minutes rounded,
|
|
79
86
|
* e.g. `Friction: high (41 turns / 62m)`; only changed ticks carry it, so the refusal path
|
|
80
|
-
* never passes the argument and the
|
|
87
|
+
* never passes the argument and the Run line's asserted format stays stable. */
|
|
81
88
|
export function commitTrailer(role, tick, turns, peakCtx, highFrictionMinutes, revisionRound) {
|
|
82
|
-
const base = `
|
|
89
|
+
const base = `Run: ${role} #${tick} · turns ${turns} · ctx ${compactTokens(peakCtx)}`;
|
|
83
90
|
const friction = highFrictionMinutes === undefined
|
|
84
91
|
? ""
|
|
85
92
|
: `\nFriction: high (${turns} turns / ${Math.round(highFrictionMinutes)}m)`;
|
package/dist/src/git/git-diff.js
CHANGED
|
@@ -28,7 +28,7 @@ const C_QUOTE_ESCAPES = {
|
|
|
28
28
|
* Non-ASCII arrives one octal escape per UTF-8 byte, so the escapes are first collected into
|
|
29
29
|
* a latin1 byte string and only then reassembled as UTF-8 (decoding each escape to a character
|
|
30
30
|
* on its own yields mojibake — `héllo.md` would come back as `héllo.md`). Used by
|
|
31
|
-
* conflictedFiles in
|
|
31
|
+
* conflictedFiles in merge-git.ts; changedFiles reads git's NUL-terminated `-z` format, which
|
|
32
32
|
* emits paths verbatim (no quoting), so it has no encoded path to decode. */
|
|
33
33
|
export function unquotePorcelainPath(p) {
|
|
34
34
|
if (!p.startsWith('"'))
|
|
@@ -66,9 +66,9 @@ export function unquotePorcelainPath(p) {
|
|
|
66
66
|
}
|
|
67
67
|
return Buffer.from(bytes, "latin1").toString("utf8");
|
|
68
68
|
}
|
|
69
|
-
/** Repo-relative paths of every change in the worktree — modified, untracked, and deleted,
|
|
70
|
-
*
|
|
71
|
-
*
|
|
69
|
+
/** Repo-relative paths of every change in the worktree — modified, untracked, and deleted, parsed
|
|
70
|
+
* from `git status --porcelain -z` (paths only). The refusal path uses this to classify what a
|
|
71
|
+
* refusing run left behind: markdown notes may be kept, everything else is discarded.
|
|
72
72
|
*
|
|
73
73
|
* The `-z` format is what git recommends for machine parsing: records are NUL-terminated and
|
|
74
74
|
* paths are emitted verbatim, never C-quoted, so a path with whitespace, a quote, a control
|
|
@@ -100,7 +100,7 @@ export async function changedFiles(wt) {
|
|
|
100
100
|
return files;
|
|
101
101
|
}
|
|
102
102
|
/** Repo-relative paths changed between the branch's fork point from main and its HEAD —
|
|
103
|
-
* everything a merge of this branch would
|
|
103
|
+
* everything a merge of this branch would bring in (the three-dot range diffs against the
|
|
104
104
|
* merge-base, so commits main gained during the tick are not included). */
|
|
105
105
|
export async function aheadOfMainFiles(wt, mainBranch) {
|
|
106
106
|
const out = await gitTry(wt, "diff", "--name-only", `${mainBranch}...HEAD`);
|
|
@@ -138,15 +138,15 @@ function splitDiffByFile(diff) {
|
|
|
138
138
|
sections.push(cur.join("\n"));
|
|
139
139
|
return sections;
|
|
140
140
|
}
|
|
141
|
-
/** The combined ahead-of-main diff — everything a merge of this branch would
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
141
|
+
/** The combined ahead-of-main diff — everything a merge of this branch would bring in. Capped: over
|
|
142
|
+
* `maxBytes`, the result is a truncation note plus `--stat` and the largest files' full diffs (an
|
|
143
|
+
* oversized diff is itself reviewable information, and the reviewer can read any file in the
|
|
144
|
+
* worktree directly). The per-file sections are split out of the one full diff already fetched —
|
|
145
|
+
* spawning a diff per file would re-diff the entire range once per file for text we already hold in
|
|
146
|
+
* memory (measured ~0.5 s of redundant git work on a 530 KB / 39-file tick). Section byte length
|
|
147
|
+
* ranks files at least as well as numstat's added+deleted: it is exactly what the reviewer will
|
|
148
|
+
* see, and a binary file's short "Binary files differ" stub naturally ranks below any real text
|
|
149
|
+
* change. */
|
|
150
150
|
export async function aheadOfMainDiff(wt, mainBranch, maxBytes = 200_000) {
|
|
151
151
|
const range = `${mainBranch}...HEAD`;
|
|
152
152
|
const full = (await gitTry(wt, "diff", range)) ?? "";
|
|
@@ -157,8 +157,8 @@ export async function aheadOfMainDiff(wt, mainBranch, maxBytes = 200_000) {
|
|
|
157
157
|
let out = `[diff truncated: the full ahead-of-main diff is ${full.length} bytes; ` +
|
|
158
158
|
`showing --stat plus the largest files]\n\n` + ((await gitTry(wt, "diff", "--stat", range)) ?? "") + "\n";
|
|
159
159
|
for (const d of ranked) {
|
|
160
|
-
// Account for the surrounding newlines in the budget check so the output never exceeds
|
|
161
|
-
//
|
|
160
|
+
// Account for the surrounding newlines in the budget check so the output never exceeds maxBytes
|
|
161
|
+
// even when a section ends exactly on the boundary.
|
|
162
162
|
if (out.length + d.length + 2 > maxBytes)
|
|
163
163
|
break;
|
|
164
164
|
out += `\n${d}\n`;
|
package/dist/src/git/git-run.js
CHANGED
|
@@ -8,12 +8,12 @@ import { realGitFromXcrun } from "./xcrun-git.js";
|
|
|
8
8
|
import { EXEC_MAX_BUFFER, childEnv, releaseChildHandles, signalTree } from "../process/process.js";
|
|
9
9
|
import { KILL_GRACE_MS, armGroupDeadline } from "../process/process-group.js";
|
|
10
10
|
import { errorMessage } from "../text/text.js";
|
|
11
|
-
/** The wall-clock bound on one git subprocess. Generous enough for a large rebase or diff on
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
11
|
+
/** The wall-clock bound on one git subprocess. Generous enough for a large rebase or diff on a slow
|
|
12
|
+
* disk, but finite: a git wedged on a stuck filesystem or a dead helper otherwise stalls its
|
|
13
|
+
* awaited merge/scheduling path with no bound at all. `runGit`'s optional timeoutMs overrides it —
|
|
14
|
+
* tests drive the deadline down to exercise the timeout; production callers need no override. The
|
|
15
|
+
* SIGTERM → SIGKILL escalation then runs for KILL_GRACE_MS, so one call is bounded at timeoutMs +
|
|
16
|
+
* KILL_GRACE_MS whatever the child does. */
|
|
17
17
|
export const GIT_TIMEOUT_MS = 600_000;
|
|
18
18
|
/** Identity used for harness-authored commits so ticks work without global git config. */
|
|
19
19
|
export const COMMIT_IDENT = [
|
|
@@ -50,7 +50,7 @@ let resolvedGit;
|
|
|
50
50
|
/** Wall-clock bound on the one-time macOS `xcrun --find git` probe. Unlike a git command, the
|
|
51
51
|
* probe is a synchronous spawnSync, so a wedged xcrun (an Xcode license prompt, a corrupt
|
|
52
52
|
* developer directory) blocks the whole event loop — no timer or watchdog can run until it
|
|
53
|
-
* returns. A short bound keeps that from freezing the
|
|
53
|
+
* returns. A short bound keeps that from freezing the team: on timeout the probe reads as
|
|
54
54
|
* "no answer" and the harness spawns `git` by name, exactly as a machine without the stub
|
|
55
55
|
* does. */
|
|
56
56
|
const GIT_RESOLVE_TIMEOUT_MS = 10_000;
|
|
@@ -200,7 +200,7 @@ export function execGitBounded(args, opts) {
|
|
|
200
200
|
return Object.assign(promise, { child });
|
|
201
201
|
}
|
|
202
202
|
/** Like git(), with extra environment variables (e.g. GIT_EDITOR for rebase --continue, which the
|
|
203
|
-
*
|
|
203
|
+
* merge flow in merge-to-main.ts needs so `rebase --continue` can never block on a commit-message
|
|
204
204
|
* prompt; and the harness ident for rewritten committer identity). The subprocess is bounded by
|
|
205
205
|
* GIT_TIMEOUT_MS plus the KILL_GRACE_MS escalation (an optional `timeoutMs`/`killGraceMs` override
|
|
206
206
|
* both for tests), so a hung or signal-ignoring git fails loudly as a GitError instead of stalling
|