tumwater 0.4.2 → 0.4.3
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 +6 -6
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-backend.js +6 -6
- package/dist/src/agent/{run-agent.js → agent-run.js} +25 -12
- package/dist/src/agent/{run-settle.js → agent-settle.js} +48 -24
- package/dist/src/agent/{run-spawn.js → agent-spawn.js} +21 -12
- package/dist/src/agent/{run-stream.js → agent-stream.js} +4 -4
- package/dist/src/agent/backend-traits.js +2 -2
- package/dist/src/agent/claude/claude-account.js +1 -8
- package/dist/src/agent/claude/claude-backend.js +3 -3
- package/dist/src/agent/claude/claude-env.js +27 -31
- package/dist/src/agent/claude/claude-stream.js +111 -54
- package/dist/src/agent/codex/codex-account.js +9 -0
- package/dist/src/agent/codex/codex-backend.js +2 -2
- package/dist/src/agent/codex/codex-env.js +28 -15
- package/dist/src/agent/codex/codex-hook-trust.js +39 -20
- package/dist/src/agent/codex/codex-rollout.js +93 -56
- package/dist/src/agent/codex/codex-stream.js +1 -1
- package/dist/src/agent/env-scrub.js +18 -0
- package/dist/src/agent/image-input.js +68 -11
- package/dist/src/agent/notes-shim.js +2 -2
- package/dist/src/agent/opencode/opencode-backend.js +2 -2
- package/dist/src/agent/opencode/opencode-catalog.js +50 -27
- package/dist/src/agent/opencode/opencode-config.js +32 -14
- package/dist/src/agent/opencode/opencode-env.js +12 -13
- package/dist/src/agent/opencode/opencode-stream.js +47 -25
- package/dist/src/agent/session-ledger.js +1 -1
- package/dist/src/agent/subscription-account.js +3 -3
- package/dist/src/backlog/backlog-cli-view.js +81 -41
- package/dist/src/backlog/backlog-cli.js +57 -26
- package/dist/src/backlog/backlog-eligibility.js +58 -102
- package/dist/src/backlog/backlog-md.js +5 -5
- package/dist/src/backlog/backlog-parts.js +65 -27
- package/dist/src/backlog/backlog-release.js +12 -12
- package/dist/src/backlog/backlog-structure.js +114 -61
- package/dist/src/backlog/backlog.js +1 -1
- package/dist/src/baseline/main-baseline.js +148 -84
- package/dist/src/budget/budget-fallback-view.js +100 -243
- package/dist/src/budget/budget-wiring.js +29 -65
- package/dist/src/budget/fallback-breaker.js +2 -2
- package/dist/src/build/build-check-detect.js +43 -14
- package/dist/src/build/build-check-events.js +2 -2
- package/dist/src/build/build-check-scoped.js +40 -16
- package/dist/src/build/build-check.js +13 -5
- package/dist/src/cli/cli-command-args.js +89 -52
- package/dist/src/cli/cli-flag-specs.js +42 -22
- package/dist/src/cli/cli-init.js +34 -12
- package/dist/src/cli/cli-query-commands.js +1 -1
- package/dist/src/cli/cli-repo-gate.js +2 -2
- package/dist/src/cli/cli-start.js +91 -58
- package/dist/src/cli/completion.js +82 -46
- package/dist/src/cli/config-commands.js +82 -71
- package/dist/src/cli/help.js +4 -6
- package/dist/src/cli/log-commands.js +43 -23
- package/dist/src/cli/notify-command.js +2 -2
- package/dist/src/cli/question-commands.js +86 -60
- package/dist/src/cli.js +181 -135
- package/dist/src/collections.js +31 -16
- package/dist/src/concurrency/check-slots.js +70 -0
- package/dist/src/concurrency/lock.js +22 -0
- package/dist/src/concurrency/run-permit.js +49 -0
- package/dist/src/concurrency/semaphore.js +46 -250
- package/dist/src/config/config-editable-keys.js +4 -7
- package/dist/src/config/config-fallbacks.js +81 -101
- package/dist/src/config/config-field-checks.js +66 -37
- package/dist/src/config/config-keys.js +5 -20
- package/dist/src/config/config-live.js +4 -28
- package/dist/src/config/{model-selector.js → config-model-selector.js} +4 -4
- package/dist/src/config/config-request.js +153 -102
- package/dist/src/config/config-schema.js +9 -11
- package/dist/src/config/config-selector-checks.js +1 -1
- package/dist/src/config/config-validation-agents.js +2 -2
- package/dist/src/config/config-validation-roles.js +4 -52
- package/dist/src/config/config-validation.js +4 -38
- package/dist/src/config/config-views.js +9 -34
- package/dist/src/config/config-write.js +6 -23
- package/dist/src/config/config.js +4 -5
- package/dist/src/doctor/doctor-backlog-bugs.js +7 -6
- package/dist/src/doctor/doctor-backlog-plans.js +24 -24
- package/dist/src/doctor/doctor-backlog.js +7 -5
- package/dist/src/doctor/doctor-check-names.js +3 -6
- package/dist/src/doctor/doctor-checks.js +5 -5
- package/dist/src/doctor/doctor-claude-checks.js +44 -28
- package/dist/src/doctor/doctor-codex-checks.js +6 -6
- package/dist/src/doctor/doctor-contention-checks.js +44 -112
- package/dist/src/doctor/doctor-fallback-checks.js +2 -2
- package/dist/src/doctor/doctor-holds.js +6 -45
- package/dist/src/doctor/doctor-install.js +1 -1
- package/dist/src/doctor/doctor-launch-services.js +1 -1
- package/dist/src/doctor/doctor-model-checks.js +178 -94
- package/dist/src/doctor/doctor-notify.js +2 -2
- package/dist/src/doctor/doctor-opencode-checks.js +5 -4
- package/dist/src/doctor/doctor-orphans.js +120 -20
- package/dist/src/doctor/{outcome.js → doctor-outcome.js} +7 -0
- package/dist/src/doctor/doctor-pi-checks.js +2 -2
- package/dist/src/doctor/doctor-principles.js +3 -3
- package/dist/src/doctor/doctor-project-checks.js +3 -3
- package/dist/src/doctor/doctor-role-notes.js +1 -1
- package/dist/src/doctor/doctor.js +8 -11
- package/dist/src/events/event-format.js +30 -54
- package/dist/src/events/event-labels.js +1 -5
- package/dist/src/events/event-legacy.js +1 -3
- package/dist/src/events/{notify.js → event-notify.js} +2 -2
- package/dist/src/events/event-read.js +1 -1
- package/dist/src/failure/failure-cluster.js +6 -6
- package/dist/src/failure/failure-data.js +8 -4
- package/dist/src/failure/failure-render.js +44 -34
- package/dist/src/failure/failure-state-change.js +4 -34
- package/dist/src/failure/{time-spend.js → failure-time-spend.js} +117 -84
- package/dist/src/files/files.js +30 -0
- package/dist/src/files/json-object.js +8 -8
- package/dist/src/files/stat-cache.js +12 -8
- package/dist/src/gates/budget-gates.js +85 -84
- package/dist/src/gates/gate-polls.js +27 -68
- package/dist/src/gates/pause-gates.js +16 -2
- package/dist/src/gates/readiness.js +1 -1
- package/dist/src/gates/role-cap-gates.js +44 -35
- package/dist/src/gates/{startup-gate.js → startup-gates.js} +7 -7
- package/dist/src/gates/{streak-gate.js → streak-gates.js} +75 -52
- package/dist/src/git/git.js +75 -45
- package/dist/src/git/worktree-pool.js +3 -6
- package/dist/src/gui/gui-admin-endpoints.js +3 -3
- package/dist/src/gui/gui-backlog-commands.js +4 -4
- package/dist/src/gui/gui-backlog-endpoints.js +61 -41
- package/dist/src/gui/gui-command.js +43 -24
- package/dist/src/gui/gui-history-endpoints.js +100 -52
- package/dist/src/gui/gui-operator-commands.js +22 -23
- package/dist/src/gui/gui-prompt-commands.js +23 -23
- package/dist/src/gui/gui-report-endpoints.js +1 -1
- package/dist/src/history/history-data.js +71 -44
- package/dist/src/history/history-queued.js +49 -27
- package/dist/src/history/history.js +51 -33
- package/dist/src/inbox/prompt-commands.js +59 -42
- package/dist/src/init/init.js +88 -40
- package/dist/src/merge/merge-backlog-conflicts.js +1 -1
- package/dist/src/merge/merge-core.js +1 -1
- package/dist/src/merge/merge-drain.js +8 -11
- package/dist/src/merge/merge-pipeline.js +6 -7
- package/dist/src/merge/merge-post-review-drain.js +10 -13
- package/dist/src/merge/merge-requeue.js +1 -1
- package/dist/src/merge/merge-slot.js +0 -8
- package/dist/src/merge/merge-verify.js +8 -18
- package/dist/src/notes-cli.js +52 -42
- package/dist/src/operator/operator-commands.js +76 -44
- package/dist/src/operator/operator-intent.js +3 -3
- package/dist/src/orchestrator/orchestrator-launch.js +31 -63
- package/dist/src/orchestrator/orchestrator-poll.js +27 -32
- package/dist/src/orchestrator/orchestrator.js +8 -21
- package/dist/src/orchestrator/scheduling-admit.js +101 -68
- package/dist/src/orchestrator/scheduling-scope.js +1 -1
- package/dist/src/orchestrator/scheduling-skip.js +1 -1
- package/dist/src/orchestrator/startup-migrations.js +1 -1
- package/dist/src/paths.js +8 -7
- package/dist/src/pi/pi-args.js +5 -2
- package/dist/src/pi/pi-backend.js +2 -2
- package/dist/src/pi/pi-bin.js +3 -3
- package/dist/src/pi/pi-event-line.js +1 -1
- package/dist/src/pi/pi-models.js +43 -29
- package/dist/src/pi/pi-settings.js +43 -20
- package/dist/src/pi/pi-stream.js +32 -6
- package/dist/src/pi/pi-watchdogs.js +12 -5
- package/dist/src/pi/pi.js +2 -2
- package/dist/src/pi-extension/context-shake.js +32 -20
- package/dist/src/pi-extension/kill-guard.js +69 -0
- package/dist/src/process/process-group.js +49 -5
- package/dist/src/process/process.js +8 -8
- package/dist/src/process/run-marker.js +31 -13
- package/dist/src/process/supervisor.js +40 -28
- package/dist/src/prompt/dialect.js +1 -1
- package/dist/src/prompt/gate-notes.js +2 -2
- package/dist/src/prompt/notes-backlog.js +66 -37
- package/dist/src/prompt/principles.js +6 -4
- package/dist/src/prompt/prompt-followup.js +12 -4
- package/dist/src/prompt/prompt.js +88 -38
- package/dist/src/report/report-data.js +53 -37
- package/dist/src/report/report-fold.js +16 -9
- package/dist/src/report/report-render.js +21 -194
- package/dist/src/report/report-since-data.js +4 -3
- package/dist/src/report/report-since-render.js +173 -0
- package/dist/src/report/report-usage-fold.js +8 -8
- package/dist/src/report/report.js +46 -22
- package/dist/src/review/post-merge-review-render.js +9 -3
- package/dist/src/review/post-merge-review.js +1 -1
- package/dist/src/review/review-precheck.js +11 -1
- package/dist/src/review/review.js +40 -153
- package/dist/src/review/secret-leaks.js +26 -16
- package/dist/src/roles/role-catalog.js +11 -3
- package/dist/src/roles/role-guidance.js +16 -12
- package/dist/src/roles/role-render.js +1 -14
- package/dist/src/roles/role-view.js +9 -21
- package/dist/src/run/acceptance-greps.js +88 -45
- package/dist/src/run/run-apply.js +12 -6
- package/dist/src/run/run-detail-data.js +121 -68
- package/dist/src/run/run-detail-render.js +92 -35
- package/dist/src/run/run-detail.js +72 -41
- package/dist/src/run/run-prompt.js +63 -50
- package/dist/src/run/run-resume.js +76 -29
- package/dist/src/run/run-stage.js +135 -84
- package/dist/src/run/run-timing.js +8 -2
- package/dist/src/run/run-usage.js +31 -1
- package/dist/src/run/run-verdict.js +119 -50
- package/dist/src/run/stage-check.js +49 -32
- package/dist/src/run/stage-checks-shared.js +28 -0
- package/dist/src/run/stage-name-checks.js +111 -92
- package/dist/src/run/stage-path-checks.js +69 -42
- package/dist/src/run/stage-prose-checks.js +55 -40
- package/dist/src/runner/runner-outcome.js +6 -1
- package/dist/src/runner/runner-pi.js +3 -10
- package/dist/src/runner/runner-recovery.js +1 -1
- package/dist/src/runner/{revision.js → runner-revision.js} +1 -1
- package/dist/src/runner/runner-run.js +97 -35
- package/dist/src/runner/runner-state-load.js +12 -9
- package/dist/src/runner/runner.js +41 -25
- package/dist/src/scheduling/claims.js +0 -4
- package/dist/src/scheduling/scheduling.js +53 -66
- package/dist/src/status/status-data.js +2 -2
- package/dist/src/status/status-role-notes.js +2 -2
- package/dist/src/status/status-roles.js +9 -17
- package/dist/src/team/{error-storm.js → team-error-storm.js} +1 -1
- package/dist/src/team/{failure-spread.js → team-failure-spread.js} +5 -5
- package/dist/src/team/team-hold.js +98 -65
- package/dist/src/team/{orchestrator-info.js → team-orchestrator-info.js} +2 -15
- package/dist/src/team/team-polls.js +28 -126
- package/dist/src/team/{reclaim.js → team-reclaim.js} +61 -31
- package/dist/src/team/team-state.js +4 -13
- package/dist/src/text/markdown.js +1 -1
- package/dist/src/text/phrases.js +20 -15
- package/dist/src/text/text.js +3 -3
- package/dist/src/ui/alert-feeds.js +49 -73
- package/dist/src/ui/badges.js +3 -13
- package/dist/src/ui/gui/gui-client-boot.js +2 -2
- package/dist/src/ui/gui/gui-client-composer.js +1 -1
- package/dist/src/ui/gui/gui-client-drawer-config.js +7 -17
- package/dist/src/ui/gui/gui-client-drawer.js +1 -1
- package/dist/src/ui/gui/gui-client-history.js +28 -14
- package/dist/src/ui/gui/gui-client-model.js +0 -12
- package/dist/src/ui/gui/gui-client-pending.js +7 -6
- package/dist/src/ui/gui/gui-client-report-chart.js +5 -5
- package/dist/src/ui/gui/gui-client-report.js +1 -1
- package/dist/src/ui/gui/gui-client-roles.js +0 -1
- package/dist/src/ui/gui/gui-client-settings.js +43 -84
- package/dist/src/ui/gui/gui-client-team.js +4 -4
- package/dist/src/ui/gui/gui-client.js +7 -1
- package/dist/src/ui/progress-data.js +53 -40
- package/dist/src/ui/run-progress-model.js +9 -2
- package/dist/src/ui/status-model.js +2 -24
- package/dist/src/ui/status-payload.js +3 -7
- package/dist/src/ui/status-render.js +5 -9
- package/dist/src/ui/team-alert-backlog.js +6 -6
- package/dist/src/ui/team-alert-status.js +9 -170
- package/dist/src/ui/team-alert-tail.js +19 -215
- package/dist/src/ui/team-alerts.js +7 -8
- package/dist/src/ui/transcript-run.js +27 -16
- package/dist/src/ui/tui/tui-editor-answer.js +12 -10
- package/dist/src/ui/tui/tui-editor-attach.js +4 -3
- package/dist/src/ui/tui/tui-editor-backends.js +4 -3
- package/dist/src/ui/tui/tui-editor-brief.js +6 -9
- package/dist/src/ui/tui/tui-editor-budget.js +4 -3
- package/dist/src/ui/tui/tui-editor-config.js +80 -68
- package/dist/src/ui/tui/tui-editor-entry.js +12 -20
- package/dist/src/ui/tui/tui-editor-pause.js +51 -57
- package/dist/src/ui/tui/tui-editor-prompt.js +9 -13
- package/dist/src/ui/tui/tui-editor-queued.js +11 -14
- package/dist/src/ui/tui/tui-editor-quiet.js +4 -3
- package/dist/src/ui/tui/tui-editor-release.js +4 -3
- package/dist/src/ui/tui/tui-editor-retire.js +7 -7
- package/dist/src/ui/tui/tui-editor-role-enabled.js +4 -3
- package/dist/src/ui/tui/tui-editor-role-file.js +4 -4
- package/dist/src/ui/tui/tui-editor-role-key.js +4 -3
- package/dist/src/ui/tui/tui-editor-role-model.js +97 -15
- package/dist/src/ui/tui/tui-editor-search.js +4 -3
- package/dist/src/ui/tui/tui-editor-session.js +17 -4
- package/dist/src/ui/tui/tui-editors.js +1 -7
- package/dist/src/ui/tui/tui-frame.js +182 -134
- package/dist/src/ui/tui/tui-guard.js +20 -0
- package/dist/src/ui/tui/tui-input.js +159 -92
- package/dist/src/ui/tui/tui-keymap.js +51 -29
- package/dist/src/ui/tui/tui-keys.js +1 -1
- package/dist/src/ui/tui/tui-pane-activity.js +3 -3
- package/dist/src/ui/tui/tui-pane-backlog.js +74 -36
- package/dist/src/ui/tui/tui-pane-ctx.js +1 -1
- package/dist/src/ui/tui/tui-pane-health.js +252 -228
- package/dist/src/ui/tui/tui-pane-history.js +61 -70
- package/dist/src/ui/tui/tui-pane-pending.js +284 -247
- package/dist/src/ui/tui/tui-pane-queued.js +25 -27
- package/dist/src/ui/tui/tui-pane-report.js +2 -1
- package/dist/src/ui/tui/tui-pane-session.js +11 -7
- package/dist/src/ui/tui/tui-pane-transcript.js +19 -31
- package/dist/src/ui/tui/tui-pane.js +14 -11
- package/dist/src/ui/tui/tui-panes.js +29 -32
- package/dist/src/ui/tui/tui.js +3 -4
- package/dist/src/verdict/fix-claim.js +76 -54
- package/dist/src/verdict/refusal.js +1 -1
- package/package.json +5 -5
- package/dist/src/concurrency/provider-lease.js +0 -105
- package/dist/src/runner/model-fallback.js +0 -76
- package/dist/src/runner/runner-fallback.js +0 -66
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +0 -24
- package/dist/src/ui/tui/tui-editor-provider-caps.js +0 -27
- /package/dist/src/backlog/{question-answer.js → backlog-question-answer.js} +0 -0
- /package/dist/src/doctor/{probe.js → doctor-probe.js} +0 -0
- /package/dist/src/gates/{disk-gate.js → disk-gates.js} +0 -0
- /package/dist/src/operator/{retire.js → operator-retire.js} +0 -0
- /package/dist/src/operator/{revert.js → operator-revert.js} +0 -0
- /package/dist/src/runner/{leftover.js → runner-leftover.js} +0 -0
|
@@ -103,6 +103,11 @@ export function followUntilParentGone(file, offset, onLines, seams) {
|
|
|
103
103
|
});
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
|
+
/** The `-n` ceiling for the event-log dump (`tumwater logs -n <count>`): a terminal tail has
|
|
107
|
+
* no use for more than this many scanned events, and bounding it keeps an accidental
|
|
108
|
+
* `-n 999999999` from traversing the whole event file. Sister counts are bounded the same way
|
|
109
|
+
* (history's HISTORY_MAX_RUNS, report's REPORT_MAX_DAYS); the GUI clamps its logs counts too. */
|
|
110
|
+
const LOGS_MAX_EVENTS = 100_000;
|
|
106
111
|
/** `tumwater logs [-f] [-n <count>] [--since <duration>] [--until <duration>]
|
|
107
112
|
* [--role <id>[,<id>...]] [--transcript <id>] [--prompt]
|
|
108
113
|
* [--grep <text>]`: follow or dump the harness event log, with `--since` a bounded
|
|
@@ -126,7 +131,7 @@ export async function cmdLogs(root, args, seams = {}) {
|
|
|
126
131
|
return;
|
|
127
132
|
}
|
|
128
133
|
const nRaw = flagValue(feed.rest, "-n");
|
|
129
|
-
const limit = nRaw !== null ? parseCountFlag("-n", nRaw) : 50;
|
|
134
|
+
const limit = nRaw !== null ? parseCountFlag("-n", nRaw, LOGS_MAX_EVENTS) : 50;
|
|
130
135
|
// The event feed (no --transcript) never needs the config at all: parseRoleScope reads it only
|
|
131
136
|
// when the flag is present.
|
|
132
137
|
const role = parseRoleScope(root, feed.rest, "--transcript", LOGS_TRANSCRIPT_VALUE_ERROR);
|
|
@@ -278,39 +283,54 @@ function sayLogsWindowNoMatch(feed, windowPhrase) {
|
|
|
278
283
|
else
|
|
279
284
|
say(feed.roles !== null ? `${feed.roleEmpty} ${windowPhrase}` : `no events ${windowPhrase}`);
|
|
280
285
|
}
|
|
281
|
-
/** The `-n` tail view and its follow:
|
|
282
|
-
*
|
|
283
|
-
* `followUntilParentGone` seeded from `tail.coveredEnd`. It owns the follow-loop locals. */
|
|
286
|
+
/** The `-n` tail view and its `-f` follow: read the filtered tail, print the `--count`
|
|
287
|
+
* tally or the per-event rows, and seed the follow; each job lives in a named helper. */
|
|
284
288
|
async function sayLogsTail(root, feed, limit, seams) {
|
|
285
|
-
|
|
286
|
-
// appears, so `-n 200 --grep merge_failed` may print 3 rows from 200 scanned. The read is
|
|
287
|
-
// the tail-with-end shape (not the per-poll cached readEvents) so the follow below can seed
|
|
288
|
-
// from the byte end this very read covered instead of a later stat of the file.
|
|
289
|
-
const tail = readEventsTailWithEnd(root, limit);
|
|
290
|
-
const shown = feed.grepLower !== null || feed.type !== null || feed.roles !== null || feed.notable ? tail.events.filter(feed.filter) : tail.events;
|
|
291
|
-
// `--count` over the -n view answers with the tally of exactly the filtered rows the plain
|
|
292
|
-
// view would print, and carries over the plain view's empty-match prose below (a `--type`
|
|
293
|
-
// or `--grep` that matches nothing names its value; an empty unfiltered -n view prints
|
|
294
|
-
// nothing, as the plain view does). In JSON mode the empty output is the answer.
|
|
289
|
+
const { shown, coveredEnd } = readTailShown(root, feed, limit);
|
|
295
290
|
if (feed.count) {
|
|
291
|
+
// `--count` over the -n view answers with the tally of exactly the filtered rows the plain
|
|
292
|
+
// view would print, and carries over the plain view's empty-match prose (a `--type` or
|
|
293
|
+
// `--grep` that matches nothing names its value; an empty unfiltered -n view prints
|
|
294
|
+
// nothing, as the plain view does). In JSON mode the empty output is the answer.
|
|
296
295
|
if (shown.length !== 0)
|
|
297
296
|
sayTally(shown, feed.json);
|
|
298
|
-
else
|
|
299
|
-
|
|
297
|
+
else
|
|
298
|
+
sayTailEmptyNote(shown, feed);
|
|
300
299
|
return;
|
|
301
300
|
}
|
|
302
301
|
for (const e of shown)
|
|
303
302
|
sayEventLine(e, feed.json);
|
|
304
303
|
if (!feed.follow) {
|
|
305
|
-
|
|
306
|
-
// for either filter, naming the flag's value(s) whose match came up empty so the operator
|
|
307
|
-
// knows what to loosen.
|
|
308
|
-
if (shown.length === 0 && !feed.json && (feed.filtersGrepOrType || feed.roles !== null || feed.notable))
|
|
309
|
-
sayLogsTailNoMatch(feed);
|
|
304
|
+
sayTailEmptyNote(shown, feed);
|
|
310
305
|
return;
|
|
311
306
|
}
|
|
307
|
+
await followLogsTail(root, feed, coveredEnd, seams);
|
|
308
|
+
}
|
|
309
|
+
/** How `-n` scans versus prints: `limit` bounds the scan, not the print — the matched
|
|
310
|
+
* subset of the last `limit` events is what appears, so `-n 200 --grep merge_failed` may
|
|
311
|
+
* print 3 rows from 200 scanned. The read is the tail-with-end shape (not the per-poll
|
|
312
|
+
* cached readEvents) so the follow can seed from the byte end this very read covered
|
|
313
|
+
* instead of a later stat of the file. It also owns the share of output to print: the
|
|
314
|
+
* `shown` rows in read order. */
|
|
315
|
+
function readTailShown(root, feed, limit) {
|
|
316
|
+
const tail = readEventsTailWithEnd(root, limit);
|
|
317
|
+
const shown = feed.grepLower !== null || feed.type !== null || feed.roles !== null || feed.notable ? tail.events.filter(feed.filter) : tail.events;
|
|
318
|
+
return { shown, coveredEnd: tail.coveredEnd };
|
|
319
|
+
}
|
|
320
|
+
/** The empty-match guard shared by the `--count` branch and the no-follow plain branch: the
|
|
321
|
+
* empty-match line is prose (in JSON mode the empty output is the answer) and fires for
|
|
322
|
+
* either filter, naming the flag's value(s) whose match came up empty so the operator knows
|
|
323
|
+
* what to loosen. */
|
|
324
|
+
function sayTailEmptyNote(shown, feed) {
|
|
325
|
+
if (shown.length === 0 && !feed.json && (feed.filtersGrepOrType || feed.roles !== null || feed.notable))
|
|
326
|
+
sayLogsTailNoMatch(feed);
|
|
327
|
+
}
|
|
328
|
+
/** The `-f` follow: resolve the event-log path and stream every newly landed event through
|
|
329
|
+
* the same `feed.filter` as the seeded window, seeded from `coveredEnd` (the byte end the
|
|
330
|
+
* initial read covered) and holding the filter across rotation. */
|
|
331
|
+
async function followLogsTail(root, feed, coveredEnd, seams) {
|
|
312
332
|
const file = eventsLogPath(root);
|
|
313
|
-
// Seed the follow from the byte end the initial read covered (
|
|
333
|
+
// Seed the follow from the byte end the initial read covered (coveredEnd), mirroring
|
|
314
334
|
// cmdLogsTranscript's tail.end seed: an event appended between the read and the follow's
|
|
315
335
|
// start lies past the printed window but at or above this offset, so the follow's first
|
|
316
336
|
// poll delivers it — seeding from a fresh statOrNull(file).size instead would start past
|
|
@@ -318,7 +338,7 @@ async function sayLogsTail(root, feed, limit, seams) {
|
|
|
318
338
|
// log scans to coveredEnd 0, and followFile tolerates a missing file (its poll re-stats
|
|
319
339
|
// every interval), so a read-only command never leaves a harness state file behind — the
|
|
320
340
|
// module contract above promises writes to stdout only.
|
|
321
|
-
await followUntilParentGone(file,
|
|
341
|
+
await followUntilParentGone(file, coveredEnd, (lines) => {
|
|
322
342
|
for (const line of lines.filter(Boolean)) {
|
|
323
343
|
const e = parseEventLine(line);
|
|
324
344
|
// The filter holds across rotation: every event the follow callback sees goes through
|
|
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { fail, say } from "./cli-output.js";
|
|
3
3
|
import { loadConfig } from "../config/config.js";
|
|
4
4
|
import { TUMWATER_SOURCE } from "../events/events.js";
|
|
5
|
-
import { notifyCommandEnv, notifyExitGloss } from "../events/notify.js";
|
|
5
|
+
import { notifyCommandEnv, notifyExitGloss } from "../events/event-notify.js";
|
|
6
6
|
/** The one representative allowlisted event `tumwater notify --test` fires: a failed merge
|
|
7
7
|
* with source `tumwater`. Fixed and opinionated — the goal is to prove the hook runs, not to
|
|
8
8
|
* replay a specific page, so there are no per-type or per-message flags. */
|
|
@@ -16,7 +16,7 @@ const NOTIFY_TEST_MESSAGE = "tumwater notify --test";
|
|
|
16
16
|
* Generous enough not to misclassify a hook that is merely slow. */
|
|
17
17
|
export const NOTIFY_TEST_TIMEOUT_MS = 10_000;
|
|
18
18
|
/** Run one notify hook to completion, returning its exit code. Unlike the notifier's detached
|
|
19
|
-
* fire-and-forget spawn (src/events/notify.ts), this waits with inherited stdio by
|
|
19
|
+
* fire-and-forget spawn (src/events/event-notify.ts), this waits with inherited stdio by
|
|
20
20
|
* default (the dashboard passes "ignore"), so the
|
|
21
21
|
* operator sees the hook's own output and its exit. A shell that cannot start resolves 127 —
|
|
22
22
|
* the conventional "command not found" code. A hook that does not finish within `timeoutMs`
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** The CLI layer of `tumwater questions` — the `tumwater questions` command body: list the open
|
|
2
2
|
* questions in QUESTIONS.md numbered, or `answer <n> <decision>` one, which moves its entry from
|
|
3
3
|
* `## Open` to `## Answered` with a dated operator answer. The markdown surgery itself — the
|
|
4
|
-
* fence-aware `### ` block cut and the `## Answered` skeleton — lives in
|
|
5
|
-
* question-answer.ts (the shared QUESTIONS.md core the TUI and dashboard also
|
|
4
|
+
* fence-aware `### ` block cut and the `## Answered` skeleton — lives in
|
|
5
|
+
* src/backlog/backlog-question-answer.ts (the shared QUESTIONS.md core the TUI and dashboard also
|
|
6
|
+
* call); this module
|
|
6
7
|
* is the command's argument scan, say/fail/editor jacket and commit-and-wake tail over that core,
|
|
7
8
|
* routed to by src/cli.ts.
|
|
8
9
|
*/
|
|
@@ -17,8 +18,14 @@ import { typoSuffix } from "../text/suggest.js";
|
|
|
17
18
|
import { commitOperatorBacklogEdit } from "../backlog/backlog-commit.js";
|
|
18
19
|
import { stampedSubject } from "../git/commit-message.js";
|
|
19
20
|
import { wakeQuestionAsker } from "../operator/operator-intent.js";
|
|
20
|
-
import { answeredQuestionAt, answeredQuestionCount, answeredQuestionList, answeredQuestionPayload, openQuestionAt, openQuestionList, questionListPayload, renderShownQuestion, UNCLOSED_FENCE_MESSAGE, tryAnswerQuestion } from "../backlog/question-answer.js";
|
|
21
|
+
import { answeredQuestionAt, answeredQuestionCount, answeredQuestionList, answeredQuestionPayload, openQuestionAt, openQuestionList, questionListPayload, renderShownQuestion, UNCLOSED_FENCE_MESSAGE, tryAnswerQuestion } from "../backlog/backlog-question-answer.js";
|
|
21
22
|
import { bodyStructureProblem, normalizeEntryBody } from "../backlog/backlog-write.js";
|
|
23
|
+
/** `questions --answered -n`'s ceiling: bounds how many answered questions one list shows,
|
|
24
|
+
* so a typo'd huge count fails fast with the shared `must be between 1 and <max>` wording
|
|
25
|
+
* (the logs/history/report pattern) instead of silently meaning "everything". The list data
|
|
26
|
+
* is small (QUESTIONS.md), so the cap never meaningfully binds — it exists for the uniform
|
|
27
|
+
* count-flag contract and the clear over-range rebuke, not for memory. */
|
|
28
|
+
const QUESTIONS_MAX_LISTED = 100_000;
|
|
22
29
|
/** The `tumwater questions answer` entry point: `tryAnswerQuestion` without a title check, its
|
|
23
30
|
* refusals mapped to `fail` (exit 1) with the CLI's wording. Returns the answered question's
|
|
24
31
|
* title plus the collapsed decision that landed in the file. */
|
|
@@ -84,6 +91,72 @@ function sayQuestionList(root, json, pattern) {
|
|
|
84
91
|
}
|
|
85
92
|
/** `questions answer`'s `--file <path>` flag: the decision comes from the file, lines kept. */
|
|
86
93
|
const FILE_SPEC = { names: ["--file"], value: true, valueName: "<path>" };
|
|
94
|
+
/** The `--show`/`--answered`/`-n`/`--grep` arms — the flags only valid before the question's
|
|
95
|
+
* number positional. Each performs its read and writes its `scan.<field>` exactly as the
|
|
96
|
+
* inline scan did; returns `i` (the index of the last token consumed, after any `args[++i]`);
|
|
97
|
+
* every other token returns `undefined`. */
|
|
98
|
+
function readPreNumberFlag(scan, args, i) {
|
|
99
|
+
if (scan.numbered)
|
|
100
|
+
return undefined;
|
|
101
|
+
const arg = args[i];
|
|
102
|
+
if (arg === "--show") {
|
|
103
|
+
rejectRepeatFlag(scan.show !== undefined, "--show");
|
|
104
|
+
scan.show = parsePositionFlag("--show", args[++i], "--show 2");
|
|
105
|
+
return i;
|
|
106
|
+
}
|
|
107
|
+
if (arg === "--answered") {
|
|
108
|
+
rejectRepeatFlag(scan.answeredFlag, "--answered");
|
|
109
|
+
scan.answeredFlag = true;
|
|
110
|
+
return i;
|
|
111
|
+
}
|
|
112
|
+
if (arg === "-n") {
|
|
113
|
+
rejectRepeatFlag(scan.limit !== undefined, "-n");
|
|
114
|
+
scan.limit = parseCountFlag("-n", args[++i], QUESTIONS_MAX_LISTED);
|
|
115
|
+
return i;
|
|
116
|
+
}
|
|
117
|
+
if (arg === "--grep") {
|
|
118
|
+
rejectRepeatFlag(scan.grep !== undefined, "--grep");
|
|
119
|
+
const text = args[++i];
|
|
120
|
+
if (text === undefined || text === "")
|
|
121
|
+
fail("--grep needs text (usage: tumwater questions [--answered] --grep <text>)");
|
|
122
|
+
scan.grep = text;
|
|
123
|
+
return i;
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
/** The `--file` arm (valid anywhere), the `!numbered && --json` arm, and the unknown
|
|
128
|
+
* `--`-flag gate — in that order. Returns `i` when `--file`/`--json` consumed the token; the
|
|
129
|
+
* unknown-flag arm never returns (it `fail`s). */
|
|
130
|
+
function readAnywhereFlag(scan, args, i) {
|
|
131
|
+
const arg = args[i];
|
|
132
|
+
if (arg === "--file") {
|
|
133
|
+
rejectRepeatFlag(scan.file !== undefined, "--file");
|
|
134
|
+
scan.file = promptFileValue(args[++i]);
|
|
135
|
+
return i;
|
|
136
|
+
}
|
|
137
|
+
if (!scan.numbered && arg === "--json") {
|
|
138
|
+
rejectRepeatFlag(scan.jsonFlag, "--json");
|
|
139
|
+
scan.jsonFlag = true;
|
|
140
|
+
return i;
|
|
141
|
+
}
|
|
142
|
+
if (arg.startsWith("--") && arg !== "--json") {
|
|
143
|
+
rejectEqualsForm(arg, [JSON_FLAG, FILE_SPEC, { names: ["--show"], value: true, valueName: "<n>" }, { names: ["--grep"], value: true, valueName: "<text>" }]);
|
|
144
|
+
// The complete flag set (this gate only sees `--`-flags, but `-n` is a real flag the
|
|
145
|
+
// list should not omit) plus the same did-you-mean hint the sibling commands'
|
|
146
|
+
// unknown-argument gate (cli-flag-specs's failUnknownArgument) attaches, so a mistyped
|
|
147
|
+
// `--ansered` names `--answered` instead of only printing the valid list — the missing
|
|
148
|
+
// treatment the questions gate was the one unknown-argument caller without.
|
|
149
|
+
const spellings = ["--json", "--file", "--answered", "--show", "--grep", "-n"];
|
|
150
|
+
fail(`unknown argument: ${arg} (valid flags for tumwater questions: ${spellings.join(", ")})${typoSuffix(arg, spellings)}`);
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
/** The trailing `-n needs --answered` guard: `-n` limits the answered list, so without
|
|
155
|
+
* `--answered` it means nothing. */
|
|
156
|
+
function assertQuestionsFlags(scan) {
|
|
157
|
+
if (scan.limit !== undefined && !scan.answeredFlag)
|
|
158
|
+
fail("-n needs --answered (it limits the answered questions listed)");
|
|
159
|
+
}
|
|
87
160
|
/** No requireReadyRepo gate, like backlog: the reader degrades to an empty list on a
|
|
88
161
|
* missing QUESTIONS.md, so the command inspects any directory instead of refusing (a team
|
|
89
162
|
* workspace still refuses).
|
|
@@ -102,72 +175,25 @@ const FILE_SPEC = { names: ["--file"], value: true, valueName: "<path>" };
|
|
|
102
175
|
* into JSON mode. Unknown `--`-prefixed tokens stay refused even there, so a misspelled
|
|
103
176
|
* flag is still an error rather than silent decision text. */
|
|
104
177
|
function parseQuestionsInvocation(args) {
|
|
105
|
-
const
|
|
106
|
-
let jsonFlag = false;
|
|
107
|
-
let numbered = false;
|
|
108
|
-
let file;
|
|
109
|
-
let answeredFlag = false;
|
|
110
|
-
let limit;
|
|
111
|
-
let grep;
|
|
112
|
-
let show;
|
|
178
|
+
const scan = { words: [], jsonFlag: false, numbered: false, file: undefined, answeredFlag: false, limit: undefined, grep: undefined, show: undefined };
|
|
113
179
|
for (let i = 0; i < args.length; i++) {
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
show = parsePositionFlag("--show", args[++i], "--show 2");
|
|
180
|
+
const consumed = readPreNumberFlag(scan, args, i) ?? readAnywhereFlag(scan, args, i);
|
|
181
|
+
if (consumed !== undefined) {
|
|
182
|
+
i = consumed;
|
|
118
183
|
continue;
|
|
119
184
|
}
|
|
120
|
-
if (!numbered
|
|
121
|
-
rejectRepeatFlag(answeredFlag, "--answered");
|
|
122
|
-
answeredFlag = true;
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
if (!numbered && arg === "-n") {
|
|
126
|
-
rejectRepeatFlag(limit !== undefined, "-n");
|
|
127
|
-
limit = parseCountFlag("-n", args[++i]);
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
if (!numbered && arg === "--grep") {
|
|
131
|
-
rejectRepeatFlag(grep !== undefined, "--grep");
|
|
132
|
-
const text = args[++i];
|
|
133
|
-
if (text === undefined || text === "")
|
|
134
|
-
fail("--grep needs text (usage: tumwater questions [--answered] --grep <text>)");
|
|
135
|
-
grep = text;
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (arg === "--file") {
|
|
139
|
-
rejectRepeatFlag(file !== undefined, "--file");
|
|
140
|
-
file = promptFileValue(args[++i]);
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
if (!numbered && arg === "--json") {
|
|
144
|
-
rejectRepeatFlag(jsonFlag, "--json");
|
|
145
|
-
jsonFlag = true;
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
if (arg.startsWith("--") && arg !== "--json") {
|
|
149
|
-
rejectEqualsForm(arg, [JSON_FLAG, FILE_SPEC, { names: ["--show"], value: true, valueName: "<n>" }, { names: ["--grep"], value: true, valueName: "<text>" }]);
|
|
150
|
-
// The complete flag set (this gate only sees `--`-flags, but `-n` is a real flag the
|
|
151
|
-
// list should not omit) plus the same did-you-mean hint the sibling commands'
|
|
152
|
-
// unknown-argument gate (cli-flag-specs's failUnknownArgument) attaches, so a mistyped
|
|
153
|
-
// `--ansered` names `--answered` instead of only printing the valid list — the missing
|
|
154
|
-
// treatment the questions gate was the one unknown-argument caller without.
|
|
155
|
-
const spellings = ["--json", "--file", "--answered", "--show", "--grep", "-n"];
|
|
156
|
-
fail(`unknown argument: ${arg} (valid flags for tumwater questions: ${spellings.join(", ")})${typoSuffix(arg, spellings)}`);
|
|
157
|
-
}
|
|
158
|
-
if (!numbered) {
|
|
185
|
+
if (!scan.numbered) {
|
|
159
186
|
// The position is a plain-decimal positive integer (parsePositiveInt's rule, the same
|
|
160
187
|
// one --cancel's position honors): bare Number() admitted hex ("0x2"), exponent
|
|
161
188
|
// ("1e2"), and whitespace-padded spellings as a valid question number, answering a
|
|
162
189
|
// question the operator never named.
|
|
163
|
-
if (parsePositiveInt(
|
|
164
|
-
numbered = true;
|
|
190
|
+
if (parsePositiveInt(args[i]) !== null)
|
|
191
|
+
scan.numbered = true;
|
|
165
192
|
}
|
|
166
|
-
words.push(
|
|
193
|
+
scan.words.push(args[i]);
|
|
167
194
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return { words, jsonFlag, file, answeredFlag, limit, grep, show };
|
|
195
|
+
assertQuestionsFlags(scan);
|
|
196
|
+
return { words: scan.words, jsonFlag: scan.jsonFlag, file: scan.file, answeredFlag: scan.answeredFlag, limit: scan.limit, grep: scan.grep, show: scan.show };
|
|
171
197
|
}
|
|
172
198
|
/** The `--show` output branch: one open (or, with `--answered`, answered) question in full. */
|
|
173
199
|
function sayShownQuestion(root, inv) {
|