@telora/daemon 0.22.289 → 0.22.293
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 +2 -2
- package/build-info.json +2 -2
- package/dist/backends/agent-backend.d.ts +2 -0
- package/dist/backends/agent-backend.d.ts.map +1 -1
- package/dist/backends/availability.d.ts +14 -0
- package/dist/backends/availability.d.ts.map +1 -1
- package/dist/backends/availability.js +37 -0
- package/dist/backends/availability.js.map +1 -1
- package/dist/backends/claude/claude-backend.d.ts.map +1 -1
- package/dist/backends/claude/claude-backend.js +2 -0
- package/dist/backends/claude/claude-backend.js.map +1 -1
- package/dist/backends/codex/codex-backend.d.ts.map +1 -1
- package/dist/backends/codex/codex-backend.js +2 -0
- package/dist/backends/codex/codex-backend.js.map +1 -1
- package/dist/backends/index.d.ts +1 -1
- package/dist/backends/index.d.ts.map +1 -1
- package/dist/backends/index.js +2 -17
- package/dist/backends/index.js.map +1 -1
- package/dist/cli/connect/config-write.d.ts.map +1 -1
- package/dist/cli/connect/config-write.js +2 -1
- package/dist/cli/connect/config-write.js.map +1 -1
- package/dist/cli/status-commands.d.ts +7 -0
- package/dist/cli/status-commands.d.ts.map +1 -1
- package/dist/cli/status-commands.js +17 -0
- package/dist/cli/status-commands.js.map +1 -1
- package/dist/completion/completion-event/event.d.ts +1 -0
- package/dist/completion/completion-event/event.d.ts.map +1 -1
- package/dist/completion/completion-event/event.js +1 -0
- package/dist/completion/completion-event/event.js.map +1 -1
- package/dist/completion/review-exit/review-census-record.d.ts +4 -2
- package/dist/completion/review-exit/review-census-record.d.ts.map +1 -1
- package/dist/completion/review-exit/review-census-record.js +11 -3
- package/dist/completion/review-exit/review-census-record.js.map +1 -1
- package/dist/completion/review-exit/review-exit-deps.js +1 -1
- package/dist/completion/review-exit/review-exit-phase.d.ts +9 -0
- package/dist/completion/review-exit/review-exit-phase.d.ts.map +1 -1
- package/dist/completion/review-exit/review-exit-phase.js +1 -1
- package/dist/completion/review-exit/review-exit-phase.js.map +1 -1
- package/dist/completion/review-exit-holds/commit-verdict-release.d.ts.map +1 -1
- package/dist/completion/review-exit-holds/commit-verdict-release.js +2 -1
- package/dist/completion/review-exit-holds/commit-verdict-release.js.map +1 -1
- package/dist/completion/review-exit-holds/review-exit-verdict-gate.d.ts +1 -0
- package/dist/completion/review-exit-holds/review-exit-verdict-gate.d.ts.map +1 -1
- package/dist/completion/review-exit-holds/review-exit-verdict-gate.js +1 -0
- package/dist/completion/review-exit-holds/review-exit-verdict-gate.js.map +1 -1
- package/dist/completion/team-exit/team-completion.d.ts.map +1 -1
- package/dist/completion/team-exit/team-completion.js +3 -1
- package/dist/completion/team-exit/team-completion.js.map +1 -1
- package/dist/completion/team-liveness/liveness-firing.js +3 -3
- package/dist/completion/team-liveness/team-liveness-phase.d.ts +6 -1
- package/dist/completion/team-liveness/team-liveness-phase.d.ts.map +1 -1
- package/dist/completion/team-liveness/team-liveness-phase.js.map +1 -1
- package/dist/completion/team-outcome/apply-close.d.ts.map +1 -1
- package/dist/completion/team-outcome/apply-close.js +4 -1
- package/dist/completion/team-outcome/apply-close.js.map +1 -1
- package/dist/completion/team-outcome/apply-turn.d.ts.map +1 -1
- package/dist/completion/team-outcome/apply-turn.js +3 -1
- package/dist/completion/team-outcome/apply-turn.js.map +1 -1
- package/dist/completion/team-outcome/apply.d.ts.map +1 -1
- package/dist/completion/team-outcome/apply.js +3 -1
- package/dist/completion/team-outcome/apply.js.map +1 -1
- package/dist/completion/team-outcome/decide-shared.d.ts.map +1 -1
- package/dist/completion/team-outcome/decide-shared.js +3 -2
- package/dist/completion/team-outcome/decide-shared.js.map +1 -1
- package/dist/completion/team-outcome/exit-pipeline-state.d.ts.map +1 -1
- package/dist/completion/team-outcome/exit-pipeline-state.js +2 -1
- package/dist/completion/team-outcome/exit-pipeline-state.js.map +1 -1
- package/dist/completion/team-outcome/team-outcome.d.ts.map +1 -1
- package/dist/completion/team-outcome/team-outcome.js +3 -1
- package/dist/completion/team-outcome/team-outcome.js.map +1 -1
- package/dist/composition/execution-migrations-context.d.ts.map +1 -1
- package/dist/composition/execution-migrations-context.js +2 -0
- package/dist/composition/execution-migrations-context.js.map +1 -1
- package/dist/composition/execution-process-context.js +1 -1
- package/dist/composition/execution-spawn-context.d.ts.map +1 -1
- package/dist/composition/execution-spawn-context.js +3 -1
- package/dist/composition/execution-spawn-context.js.map +1 -1
- package/dist/composition/execution-spawn-process-context.d.ts.map +1 -1
- package/dist/composition/execution-spawn-process-context.js +3 -2
- package/dist/composition/execution-spawn-process-context.js.map +1 -1
- package/dist/composition/focus-activity-live-sources.d.ts +4 -0
- package/dist/composition/focus-activity-live-sources.d.ts.map +1 -0
- package/dist/composition/focus-activity-live-sources.js +68 -0
- package/dist/composition/focus-activity-live-sources.js.map +1 -0
- package/dist/composition/runtime-delivery-advance-context.d.ts +6 -1
- package/dist/composition/runtime-delivery-advance-context.d.ts.map +1 -1
- package/dist/composition/runtime-delivery-advance-context.js +14 -3
- package/dist/composition/runtime-delivery-advance-context.js.map +1 -1
- package/dist/composition/runtime-heartbeat-context.d.ts.map +1 -1
- package/dist/composition/runtime-heartbeat-context.js +3 -1
- package/dist/composition/runtime-heartbeat-context.js.map +1 -1
- package/dist/composition/team-lifecycle-context.d.ts.map +1 -1
- package/dist/composition/team-lifecycle-context.js +3 -1
- package/dist/composition/team-lifecycle-context.js.map +1 -1
- package/dist/composition/team-liveness-phase-sources.d.ts.map +1 -1
- package/dist/composition/team-liveness-phase-sources.js +1 -0
- package/dist/composition/team-liveness-phase-sources.js.map +1 -1
- package/dist/composition/verification-context.d.ts.map +1 -1
- package/dist/composition/verification-context.js +4 -1
- package/dist/composition/verification-context.js.map +1 -1
- package/dist/composition/verify-probe-context.d.ts +7 -0
- package/dist/composition/verify-probe-context.d.ts.map +1 -1
- package/dist/composition/verify-probe-context.js +55 -3
- package/dist/composition/verify-probe-context.js.map +1 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +4 -3
- package/dist/config/config.js.map +1 -1
- package/dist/config/session-cap.d.ts +89 -0
- package/dist/config/session-cap.d.ts.map +1 -0
- package/dist/config/session-cap.js +176 -0
- package/dist/config/session-cap.js.map +1 -0
- package/dist/daemon-state/awaiting-slot.d.ts +8 -2
- package/dist/daemon-state/awaiting-slot.d.ts.map +1 -1
- package/dist/daemon-state/awaiting-slot.js +21 -8
- package/dist/daemon-state/awaiting-slot.js.map +1 -1
- package/dist/daemon-state/engine-readiness.d.ts +73 -0
- package/dist/daemon-state/engine-readiness.d.ts.map +1 -0
- package/dist/daemon-state/engine-readiness.js +191 -0
- package/dist/daemon-state/engine-readiness.js.map +1 -0
- package/dist/daemon-state/focus-progress-clock.d.ts +34 -0
- package/dist/daemon-state/focus-progress-clock.d.ts.map +1 -0
- package/dist/daemon-state/focus-progress-clock.js +167 -0
- package/dist/daemon-state/focus-progress-clock.js.map +1 -0
- package/dist/daemon-state/focus-team-state.d.ts +32 -9
- package/dist/daemon-state/focus-team-state.d.ts.map +1 -1
- package/dist/daemon-state/focus-team-state.js +50 -9
- package/dist/daemon-state/focus-team-state.js.map +1 -1
- package/dist/daemon-state/provider-window.d.ts.map +1 -1
- package/dist/daemon-state/provider-window.js +5 -1
- package/dist/daemon-state/provider-window.js.map +1 -1
- package/dist/daemon-state/review-park-record.d.ts +36 -0
- package/dist/daemon-state/review-park-record.d.ts.map +1 -0
- package/dist/daemon-state/review-park-record.js +27 -0
- package/dist/daemon-state/review-park-record.js.map +1 -0
- package/dist/daemon-state/worker-pidfile.d.ts.map +1 -1
- package/dist/daemon-state/worker-pidfile.js +3 -1
- package/dist/daemon-state/worker-pidfile.js.map +1 -1
- package/dist/delivery/commit-verdict-hold.d.ts.map +1 -1
- package/dist/delivery/commit-verdict-hold.js +3 -1
- package/dist/delivery/commit-verdict-hold.js.map +1 -1
- package/dist/directive/directive-queue.js +1 -1
- package/dist/focus/focus-activity-held.d.ts +37 -0
- package/dist/focus/focus-activity-held.d.ts.map +1 -0
- package/dist/focus/focus-activity-held.js +89 -0
- package/dist/focus/focus-activity-held.js.map +1 -0
- package/dist/focus/focus-activity-poll-facts.d.ts +39 -0
- package/dist/focus/focus-activity-poll-facts.d.ts.map +1 -0
- package/dist/focus/focus-activity-poll-facts.js +110 -0
- package/dist/focus/focus-activity-poll-facts.js.map +1 -0
- package/dist/focus/focus-activity-producers.d.ts +43 -0
- package/dist/focus/focus-activity-producers.d.ts.map +1 -0
- package/dist/focus/focus-activity-producers.js +130 -0
- package/dist/focus/focus-activity-producers.js.map +1 -0
- package/dist/focus/focus-activity-record.d.ts +58 -0
- package/dist/focus/focus-activity-record.d.ts.map +1 -0
- package/dist/focus/focus-activity-record.js +141 -0
- package/dist/focus/focus-activity-record.js.map +1 -0
- package/dist/focus/focus-activity-sources.d.ts +99 -0
- package/dist/focus/focus-activity-sources.d.ts.map +1 -0
- package/dist/focus/focus-activity-sources.js +45 -0
- package/dist/focus/focus-activity-sources.js.map +1 -0
- package/dist/focus/focus-executor.js +1 -1
- package/dist/focus/focus-executor.js.map +1 -1
- package/dist/focus/focus-poller-auto-advance.d.ts.map +1 -1
- package/dist/focus/focus-poller-auto-advance.js +2 -0
- package/dist/focus/focus-poller-auto-advance.js.map +1 -1
- package/dist/focus/heartbeat-metadata.d.ts.map +1 -1
- package/dist/focus/heartbeat-metadata.js +6 -0
- package/dist/focus/heartbeat-metadata.js.map +1 -1
- package/dist/focus/heartbeat.d.ts +3 -0
- package/dist/focus/heartbeat.d.ts.map +1 -1
- package/dist/focus/heartbeat.js +31 -31
- package/dist/focus/heartbeat.js.map +1 -1
- package/dist/focus/pending-review-approved-head.d.ts.map +1 -1
- package/dist/focus/pending-review-approved-head.js +4 -2
- package/dist/focus/pending-review-approved-head.js.map +1 -1
- package/dist/focus/unchanged-reviewed-head.d.ts.map +1 -1
- package/dist/focus/unchanged-reviewed-head.js +4 -2
- package/dist/focus/unchanged-reviewed-head.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/queries/deliveries/deliveries.d.ts +4 -0
- package/dist/queries/deliveries/deliveries.d.ts.map +1 -1
- package/dist/queries/deliveries/deliveries.js +6 -0
- package/dist/queries/deliveries/deliveries.js.map +1 -1
- package/dist/queries/deliveries/issues.d.ts +3 -0
- package/dist/queries/deliveries/issues.d.ts.map +1 -1
- package/dist/queries/deliveries/issues.js +10 -2
- package/dist/queries/deliveries/issues.js.map +1 -1
- package/dist/queries/delivery-gate-state/delivery-gate-holds.d.ts +27 -1
- package/dist/queries/delivery-gate-state/delivery-gate-holds.d.ts.map +1 -1
- package/dist/queries/delivery-gate-state/delivery-gate-state.d.ts +3 -1
- package/dist/queries/delivery-gate-state/delivery-gate-state.d.ts.map +1 -1
- package/dist/queries/delivery-gate-state/delivery-gate-state.js.map +1 -1
- package/dist/queries/focuses/focus-discovery.d.ts.map +1 -1
- package/dist/queries/focuses/focus-discovery.js +2 -0
- package/dist/queries/focuses/focus-discovery.js.map +1 -1
- package/dist/queries/focuses/focuses.d.ts.map +1 -1
- package/dist/queries/focuses/focuses.js +2 -0
- package/dist/queries/focuses/focuses.js.map +1 -1
- package/dist/queries/sessions/daemon-connection.d.ts.map +1 -1
- package/dist/queries/sessions/daemon-connection.js +1 -0
- package/dist/queries/sessions/daemon-connection.js.map +1 -1
- package/dist/queries/workflow-transitions/workflows.d.ts.map +1 -1
- package/dist/queries/workflow-transitions/workflows.js +1 -0
- package/dist/queries/workflow-transitions/workflows.js.map +1 -1
- package/dist/shell/config-hot-reload.d.ts +11 -0
- package/dist/shell/config-hot-reload.d.ts.map +1 -1
- package/dist/shell/config-hot-reload.js +12 -0
- package/dist/shell/config-hot-reload.js.map +1 -1
- package/dist/shell/unified-engine-lifecycle.d.ts +8 -1
- package/dist/shell/unified-engine-lifecycle.d.ts.map +1 -1
- package/dist/shell/unified-engine-lifecycle.js +44 -24
- package/dist/shell/unified-engine-lifecycle.js.map +1 -1
- package/dist/shell/unified-init.d.ts +5 -1
- package/dist/shell/unified-init.d.ts.map +1 -1
- package/dist/shell/unified-init.js +2 -2
- package/dist/shell/unified-init.js.map +1 -1
- package/dist/shell/unified-shell-config.d.ts +2 -1
- package/dist/shell/unified-shell-config.d.ts.map +1 -1
- package/dist/shell/unified-shell-config.js +9 -3
- package/dist/shell/unified-shell-config.js.map +1 -1
- package/dist/shell/unified-shell-status.d.ts +11 -1
- package/dist/shell/unified-shell-status.d.ts.map +1 -1
- package/dist/shell/unified-shell-status.js +15 -1
- package/dist/shell/unified-shell-status.js.map +1 -1
- package/dist/shell/unified-shell.d.ts.map +1 -1
- package/dist/shell/unified-shell.js +25 -5
- package/dist/shell/unified-shell.js.map +1 -1
- package/dist/spawn/codex-auth.d.ts +32 -0
- package/dist/spawn/codex-auth.d.ts.map +1 -0
- package/dist/spawn/codex-auth.js +55 -0
- package/dist/spawn/codex-auth.js.map +1 -0
- package/dist/spawn/helpers.d.ts.map +1 -1
- package/dist/spawn/helpers.js +19 -3
- package/dist/spawn/helpers.js.map +1 -1
- package/dist/spawn/model-reached.d.ts +36 -0
- package/dist/spawn/model-reached.d.ts.map +1 -0
- package/dist/spawn/model-reached.js +43 -0
- package/dist/spawn/model-reached.js.map +1 -0
- package/dist/spawn/next-spawn-cooldown.d.ts +21 -2
- package/dist/spawn/next-spawn-cooldown.d.ts.map +1 -1
- package/dist/spawn/next-spawn-cooldown.js +65 -7
- package/dist/spawn/next-spawn-cooldown.js.map +1 -1
- package/dist/spawn/process-spawn.d.ts.map +1 -1
- package/dist/spawn/process-spawn.js +8 -5
- package/dist/spawn/process-spawn.js.map +1 -1
- package/dist/spawn/review-hold-park.d.ts +12 -1
- package/dist/spawn/review-hold-park.d.ts.map +1 -1
- package/dist/spawn/review-hold-park.js +25 -9
- package/dist/spawn/review-hold-park.js.map +1 -1
- package/dist/spawn/spawn-decision.d.ts.map +1 -1
- package/dist/spawn/spawn-decision.js +4 -0
- package/dist/spawn/spawn-decision.js.map +1 -1
- package/dist/spawn/team-working-delivery.d.ts +76 -0
- package/dist/spawn/team-working-delivery.d.ts.map +1 -0
- package/dist/spawn/team-working-delivery.js +76 -0
- package/dist/spawn/team-working-delivery.js.map +1 -0
- package/dist/spawn/worktree-session.d.ts +15 -0
- package/dist/spawn/worktree-session.d.ts.map +1 -1
- package/dist/spawn/worktree-session.js +25 -2
- package/dist/spawn/worktree-session.js.map +1 -1
- package/dist/supervision/spawn-cooldown-window.d.ts +15 -0
- package/dist/supervision/spawn-cooldown-window.d.ts.map +1 -0
- package/dist/supervision/spawn-cooldown-window.js +46 -0
- package/dist/supervision/spawn-cooldown-window.js.map +1 -0
- package/dist/supervision/spawn-cooldown.d.ts +3 -2
- package/dist/supervision/spawn-cooldown.d.ts.map +1 -1
- package/dist/supervision/spawn-cooldown.js +6 -1
- package/dist/supervision/spawn-cooldown.js.map +1 -1
- package/dist/supervision/stop-registry.d.ts +1 -0
- package/dist/supervision/stop-registry.d.ts.map +1 -1
- package/dist/supervision/stop-rows-spawn.d.ts +8 -0
- package/dist/supervision/stop-rows-spawn.d.ts.map +1 -1
- package/dist/supervision/stop-rows-spawn.js +28 -1
- package/dist/supervision/stop-rows-spawn.js.map +1 -1
- package/dist/testing/fake-npm-registry.d.ts +31 -0
- package/dist/testing/fake-npm-registry.d.ts.map +1 -0
- package/dist/testing/fake-npm-registry.js +127 -0
- package/dist/testing/fake-npm-registry.js.map +1 -0
- package/dist/testing/fixtures/approved-head-inert-deps.d.ts.map +1 -1
- package/dist/testing/fixtures/approved-head-inert-deps.js +4 -2
- package/dist/testing/fixtures/approved-head-inert-deps.js.map +1 -1
- package/dist/testing/fixtures/codex-stream-session.d.ts +4 -0
- package/dist/testing/fixtures/codex-stream-session.d.ts.map +1 -1
- package/dist/testing/fixtures/codex-stream-session.js +21 -5
- package/dist/testing/fixtures/codex-stream-session.js.map +1 -1
- package/dist/testing/fixtures/completion-event-deps.js +1 -1
- package/dist/testing/fixtures/index.js +1 -1
- package/dist/testing/fixtures/process-close-context.d.ts.map +1 -1
- package/dist/testing/fixtures/process-close-context.js +2 -0
- package/dist/testing/fixtures/process-close-context.js.map +1 -1
- package/dist/testing/fixtures/recording-api-client.js +1 -1
- package/dist/testing/fixtures/review-exit-deps.js +1 -1
- package/dist/testing/fixtures/session-wire.d.ts.map +1 -1
- package/dist/testing/fixtures/session-wire.js +2 -1
- package/dist/testing/fixtures/session-wire.js.map +1 -1
- package/dist/testing/fixtures/verification-deps.d.ts.map +1 -1
- package/dist/testing/fixtures/verification-deps.js +4 -0
- package/dist/testing/fixtures/verification-deps.js.map +1 -1
- package/dist/types/config.d.ts +30 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/focus-team-state.d.ts +28 -2
- package/dist/types/focus-team-state.d.ts.map +1 -1
- package/dist/types/focus-team-state.js.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/verify/deterministic-gate/verification-checkout.d.ts +8 -4
- package/dist/verify/deterministic-gate/verification-checkout.d.ts.map +1 -1
- package/dist/verify/deterministic-gate/verification-checkout.js +50 -13
- package/dist/verify/deterministic-gate/verification-checkout.js.map +1 -1
- package/dist/verify/deterministic-gate/verification-deterministic.d.ts.map +1 -1
- package/dist/verify/deterministic-gate/verification-deterministic.js +3 -1
- package/dist/verify/deterministic-gate/verification-deterministic.js.map +1 -1
- package/dist/verify/engine/verification-deps.d.ts +7 -0
- package/dist/verify/engine/verification-deps.d.ts.map +1 -1
- package/dist/verify/engine/verification-deps.js +1 -1
- package/dist/verify/engine/verification-engine.d.ts.map +1 -1
- package/dist/verify/engine/verification-engine.js +107 -8
- package/dist/verify/engine/verification-engine.js.map +1 -1
- package/dist/verify/gate-config/verification-config.js +1 -1
- package/dist/verify/gate-verdicts/commit-verdict-record.js +1 -1
- package/dist/verify/gate-verdicts/gate-run-registry.d.ts +74 -3
- package/dist/verify/gate-verdicts/gate-run-registry.d.ts.map +1 -1
- package/dist/verify/gate-verdicts/gate-run-registry.js +41 -20
- package/dist/verify/gate-verdicts/gate-run-registry.js.map +1 -1
- package/dist/verify/install-probe/in-repo-publish.d.ts +154 -0
- package/dist/verify/install-probe/in-repo-publish.d.ts.map +1 -0
- package/dist/verify/install-probe/in-repo-publish.js +183 -0
- package/dist/verify/install-probe/in-repo-publish.js.map +1 -0
- package/dist/verify/install-probe/install-probe-tick.d.ts +23 -2
- package/dist/verify/install-probe/install-probe-tick.d.ts.map +1 -1
- package/dist/verify/install-probe/install-probe-tick.js +84 -12
- package/dist/verify/install-probe/install-probe-tick.js.map +1 -1
- package/dist/verify/install-probe/install-probe.d.ts +16 -0
- package/dist/verify/install-probe/install-probe.d.ts.map +1 -1
- package/dist/verify/install-probe/install-probe.js +35 -19
- package/dist/verify/install-probe/install-probe.js.map +1 -1
- package/dist/verify/install-probe/npm-unresolved.d.ts +37 -0
- package/dist/verify/install-probe/npm-unresolved.d.ts.map +1 -0
- package/dist/verify/install-probe/npm-unresolved.js +63 -0
- package/dist/verify/install-probe/npm-unresolved.js.map +1 -0
- package/dist/verify/run-selection/default-on-guards.d.ts.map +1 -1
- package/dist/verify/run-selection/default-on-guards.js +1 -19
- package/dist/verify/run-selection/default-on-guards.js.map +1 -1
- package/dist/worktree/verify-interlock.d.ts +23 -2
- package/dist/worktree/verify-interlock.d.ts.map +1 -1
- package/dist/worktree/verify-interlock.js +79 -2
- package/dist/worktree/verify-interlock.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
// PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
|
|
2
2
|
// Pinned by: packages/daemon/src/focus/awaiting-slot.test.ts,
|
|
3
|
+
// packages/daemon/src/focus/focus-activity-producers.test.ts,
|
|
3
4
|
// packages/daemon/src/focus/heartbeat-team-liveness-phases.test.ts
|
|
4
5
|
// PINNED-BY-END
|
|
6
|
+
/** focusId -> epoch ms the pass FIRST left it waiting in the current unbroken run of passes. */
|
|
5
7
|
const awaitingSlotByPass = {
|
|
6
|
-
ready: new
|
|
7
|
-
pending: new
|
|
8
|
+
ready: new Map(),
|
|
9
|
+
pending: new Map(),
|
|
8
10
|
};
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Replace one pass's awaiting-slot set with the focuses it left waiting this run
|
|
13
|
+
* (empty clears it). A focus still waiting keeps the time it was first recorded,
|
|
14
|
+
* so the published `since` names when the wait began, not the latest pass.
|
|
15
|
+
*/
|
|
16
|
+
export function setAwaitingSlotFocuses(pass, focusIds, now = Date.now()) {
|
|
17
|
+
const prior = awaitingSlotByPass[pass];
|
|
18
|
+
awaitingSlotByPass[pass] = new Map([...focusIds].map((id) => [id, prior.get(id) ?? now]));
|
|
12
19
|
}
|
|
13
20
|
/** Every focus some pass left waiting for a slot (the union of both passes, deduplicated). */
|
|
14
21
|
export function getAwaitingSlotFocusIds() {
|
|
15
|
-
return [...new Set([...awaitingSlotByPass.ready, ...awaitingSlotByPass.pending])];
|
|
22
|
+
return [...new Set([...awaitingSlotByPass.ready.keys(), ...awaitingSlotByPass.pending.keys()])];
|
|
16
23
|
}
|
|
17
24
|
/** Whether some pass left this focus waiting for a slot on its latest run. */
|
|
18
25
|
export function isAwaitingSlot(focusId) {
|
|
19
26
|
return awaitingSlotByPass.ready.has(focusId) || awaitingSlotByPass.pending.has(focusId);
|
|
20
27
|
}
|
|
28
|
+
/** When the focus's current wait for a slot began (the earlier of the two passes), or null when it is not waiting. */
|
|
29
|
+
export function awaitingSlotSince(focusId) {
|
|
30
|
+
const times = [awaitingSlotByPass.ready.get(focusId), awaitingSlotByPass.pending.get(focusId)]
|
|
31
|
+
.filter((t) => t !== undefined);
|
|
32
|
+
return times.length > 0 ? Math.min(...times) : null;
|
|
33
|
+
}
|
|
21
34
|
/** Test-only: clear both passes' sets so state never leaks across tests. */
|
|
22
35
|
export function __resetAwaitingSlotForTesting() {
|
|
23
|
-
awaitingSlotByPass.ready = new
|
|
24
|
-
awaitingSlotByPass.pending = new
|
|
36
|
+
awaitingSlotByPass.ready = new Map();
|
|
37
|
+
awaitingSlotByPass.pending = new Map();
|
|
25
38
|
}
|
|
26
39
|
//# sourceMappingURL=awaiting-slot.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"awaiting-slot.js","sourceRoot":"","sources":["../../src/daemon-state/awaiting-slot.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,8DAA8D;AAC9D,qEAAqE;AACrE,gBAAgB;AA8BhB,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"awaiting-slot.js","sourceRoot":"","sources":["../../src/daemon-state/awaiting-slot.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,8DAA8D;AAC9D,gEAAgE;AAChE,qEAAqE;AACrE,gBAAgB;AA8BhB,gGAAgG;AAChG,MAAM,kBAAkB,GAAmD;IACzE,KAAK,EAAE,IAAI,GAAG,EAAE;IAChB,OAAO,EAAE,IAAI,GAAG,EAAE;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAe,EAAE,QAA0B,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IAC1G,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACvC,kBAAkB,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,uBAAuB;IACrC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAClG,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC1F,CAAC;AAED,sHAAsH;AACtH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,KAAK,GAAG,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;SAC3F,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,6BAA6B;IAC3C,kBAAkB,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;IACrC,kBAAkB,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How long a not-ready engine holds its spawns before it is re-probed (and, if
|
|
3
|
+
* no re-probe runs, before one spawn is let through to try it). Five minutes:
|
|
4
|
+
* a host that was fixed (installed, logged in) resumes within one wait, and a
|
|
5
|
+
* host that was not costs one probe -- not one failed lead -- per wait.
|
|
6
|
+
*/
|
|
7
|
+
export declare const ENGINE_REPROBE_MS: number;
|
|
8
|
+
/** The persisted record's file name, under the global state dir. */
|
|
9
|
+
export declare const ENGINE_READINESS_FILE = "engine-readiness.json";
|
|
10
|
+
/** What a not-ready engine lacks: its CLI binary, or its login. */
|
|
11
|
+
export type EngineMissing = 'binary' | 'login';
|
|
12
|
+
/** What last set an engine's readiness. */
|
|
13
|
+
export type EngineReadinessSource = 'probe' | 'spawn_enoent' | 'auth_failure';
|
|
14
|
+
/** One engine's readiness on this host. */
|
|
15
|
+
export interface EngineReadiness {
|
|
16
|
+
engineId: string;
|
|
17
|
+
ready: boolean;
|
|
18
|
+
/** What is missing when not ready; null when ready. */
|
|
19
|
+
missing: EngineMissing | null;
|
|
20
|
+
/** Names the missing binary or login (and how to fix it); null when ready. */
|
|
21
|
+
detail: string | null;
|
|
22
|
+
source: EngineReadinessSource;
|
|
23
|
+
/** When the engine entered its current readiness, epoch ms. */
|
|
24
|
+
sinceMs: number;
|
|
25
|
+
/** When a not-ready engine is next re-probed, epoch ms; null when ready. */
|
|
26
|
+
nextProbeAtMs: number | null;
|
|
27
|
+
/** Whether the gap holds spawns on the engine (see WHICH GAPS HOLD); false when ready. */
|
|
28
|
+
holdsSpawns: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** The persisted file's shape. */
|
|
31
|
+
export interface PersistedEngineReadiness {
|
|
32
|
+
host: string;
|
|
33
|
+
updatedAt: string;
|
|
34
|
+
engines: EngineReadiness[];
|
|
35
|
+
}
|
|
36
|
+
/** A probe result, as backends' probeAvailability returns it. */
|
|
37
|
+
export interface EngineProbeResult {
|
|
38
|
+
available: boolean;
|
|
39
|
+
detail?: string;
|
|
40
|
+
missing?: EngineMissing;
|
|
41
|
+
}
|
|
42
|
+
/** Record what a probe found for an engine. A not-ready engine is re-probed after ENGINE_REPROBE_MS. */
|
|
43
|
+
export declare function recordEngineProbe(engineId: string, probe: EngineProbeResult, nowMs?: number): EngineReadiness;
|
|
44
|
+
/**
|
|
45
|
+
* Mark an engine not ready from a failed start or a failed authentication. Its
|
|
46
|
+
* spawns are held until a re-probe finds it ready or ENGINE_REPROBE_MS elapses.
|
|
47
|
+
*/
|
|
48
|
+
export declare function markEngineNotReady(engineId: string, why: {
|
|
49
|
+
missing: EngineMissing;
|
|
50
|
+
detail: string;
|
|
51
|
+
source: Exclude<EngineReadinessSource, 'probe'>;
|
|
52
|
+
}, nowMs?: number): EngineReadiness;
|
|
53
|
+
/**
|
|
54
|
+
* The instant a not-ready engine's hold on its spawns ends, or null when it
|
|
55
|
+
* holds none: the engine is ready, unknown (never probed -- a spawn is its
|
|
56
|
+
* probe), reported without a hold, or its wait has elapsed.
|
|
57
|
+
*/
|
|
58
|
+
export declare function engineNotReadyUntilMs(engineId: string, nowMs?: number): number | null;
|
|
59
|
+
/** True when any engine's readiness holds spawns now (the spawn gates resolve a route only then). */
|
|
60
|
+
export declare function anyEngineSpawnHold(nowMs?: number): boolean;
|
|
61
|
+
/** The engines whose re-probe is due: recorded not ready, with the wait elapsed. */
|
|
62
|
+
export declare function enginesDueForReprobe(nowMs?: number): string[];
|
|
63
|
+
/** Every engine's current readiness, in engine-id order. */
|
|
64
|
+
export declare function engineReadinessSnapshot(): EngineReadiness[];
|
|
65
|
+
/** Read the record the running daemon persisted, or null when there is none (or it is unreadable). */
|
|
66
|
+
export declare function readPersistedEngineReadiness(): PersistedEngineReadiness | null;
|
|
67
|
+
/** One engine's readiness line, as the startup log and `telora-daemon status` print it. */
|
|
68
|
+
export declare function formatEngineReadinessLine(record: Pick<EngineReadiness, 'engineId' | 'ready' | 'missing' | 'detail' | 'holdsSpawns'>): string;
|
|
69
|
+
/** Every engine's readiness line. */
|
|
70
|
+
export declare function formatEngineReadinessLines(engines: ReadonlyArray<Pick<EngineReadiness, 'engineId' | 'ready' | 'missing' | 'detail' | 'holdsSpawns'>>): string[];
|
|
71
|
+
/** Test-only: forget every record, as a daemon re-exec starts with none. */
|
|
72
|
+
export declare function __resetEngineReadinessForTests(): void;
|
|
73
|
+
//# sourceMappingURL=engine-readiness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-readiness.d.ts","sourceRoot":"","sources":["../../src/daemon-state/engine-readiness.ts"],"names":[],"mappings":"AAmDA;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,QAAa,CAAC;AAE5C,oEAAoE;AACpE,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/C,2CAA2C;AAC3C,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,cAAc,GAAG,cAAc,CAAC;AAE9E,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,uDAAuD;IACvD,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,8EAA8E;IAC9E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0FAA0F;IAC1F,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,kCAAkC;AAClC,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAsCD,wGAAwG;AACxG,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,GAAE,MAAmB,GAAG,eAAe,CAmBzH;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE;IAAE,OAAO,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAA;CAAE,EAChG,KAAK,GAAE,MAAmB,GACzB,eAAe,CAejB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAmB,GAAG,MAAM,GAAG,IAAI,CAIjG;AAED,qGAAqG;AACrG,wBAAgB,kBAAkB,CAAC,KAAK,GAAE,MAAmB,GAAG,OAAO,CAGtE;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,KAAK,GAAE,MAAmB,GAAG,MAAM,EAAE,CAIzE;AAED,4DAA4D;AAC5D,wBAAgB,uBAAuB,IAAI,eAAe,EAAE,CAE3D;AAED,sGAAsG;AACtG,wBAAgB,4BAA4B,IAAI,wBAAwB,GAAG,IAAI,CAU9E;AAED,2FAA2F;AAC3F,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAC,GAAG,MAAM,CAK5I;AAED,qCAAqC;AACrC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAC,CAAC,GAAG,MAAM,EAAE,CAE/J;AAED,4EAA4E;AAC5E,wBAAgB,8BAA8B,IAAI,IAAI,CAErD"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
|
|
2
|
+
// Pinned by: packages/daemon/src/daemon-state/engine-readiness.test.ts,
|
|
3
|
+
// packages/daemon/src/integration/engine-readiness-runtime.test.ts,
|
|
4
|
+
// packages/daemon/src/integration/model-reached-review-exit-effects.test.ts,
|
|
5
|
+
// packages/daemon/src/shell/unified-shell-status.test.ts, packages/daemon/src/spawn/codex-auth.test.ts,
|
|
6
|
+
// packages/daemon/src/spawn/engine-not-ready-gate.test.ts, packages/daemon/src/spawn/model-reached.test.ts
|
|
7
|
+
// PINNED-BY-END
|
|
8
|
+
/**
|
|
9
|
+
* Per-host engine readiness: can this host START each engine the daemon may
|
|
10
|
+
* spawn (claude, codex), and can that engine AUTHENTICATE?
|
|
11
|
+
*
|
|
12
|
+
* Readiness is HOST STATE. An engine whose binary is missing, or which is not
|
|
13
|
+
* logged in, is not a team failure, not a review and not an escalation (the
|
|
14
|
+
* standing ruling: config gaps are state, never escalations). Without this
|
|
15
|
+
* record a missing binary drew a failed lead on every poll, and nothing a human
|
|
16
|
+
* looks at said the host could not run the engine.
|
|
17
|
+
*
|
|
18
|
+
* So:
|
|
19
|
+
* - A probe (backends/availability.ts, the backends' own probeAvailability)
|
|
20
|
+
* seeds the record at startup and re-reads a not-ready engine.
|
|
21
|
+
* - A failed start (ENOENT, spawn/process-spawn.ts) or a failed authentication
|
|
22
|
+
* (a Codex 401, spawn/codex-auth.ts) marks the engine not ready.
|
|
23
|
+
* - While an engine is not ready AND the gap holds spawns, no lead is spawned
|
|
24
|
+
* on it (the `engine_not_ready` stop row, read by the spawn gates) until a
|
|
25
|
+
* re-probe finds it ready or ENGINE_REPROBE_MS elapses. A re-probe that finds
|
|
26
|
+
* it ready clears the record -- installing or logging in needs no restart.
|
|
27
|
+
*
|
|
28
|
+
* WHICH GAPS HOLD. A missing binary always does: nothing can start it. A missing
|
|
29
|
+
* login does only once a spawn has OBSERVED the authentication fail. The host
|
|
30
|
+
* probe reads the host's own login (~/.codex/auth.json, ~/.claude.json, the
|
|
31
|
+
* daemon's env) and cannot see a key the per-spawn environment supplies
|
|
32
|
+
* (spawn/spawn-environment.ts fetchBackendEnvExtras), so a probe that finds only
|
|
33
|
+
* the login missing is REPORTED -- status and the startup log say so -- but
|
|
34
|
+
* holds nothing (spawn/process-spawn.ts gateLocalModelBackendSpawn makes the
|
|
35
|
+
* same call for the same reason).
|
|
36
|
+
*
|
|
37
|
+
* The record is persisted under the global state dir so the separate
|
|
38
|
+
* `telora-daemon status` process can read what the running daemon knows.
|
|
39
|
+
*
|
|
40
|
+
* History: docs/daemon/history-team-lifecycle.md (daemon-state/engine-readiness.ts).
|
|
41
|
+
*/
|
|
42
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
43
|
+
import { hostname } from 'node:os';
|
|
44
|
+
import { join } from 'node:path';
|
|
45
|
+
import { resolveGlobalStateDir } from './daemon-process.js';
|
|
46
|
+
import { createLogger } from '../log/daemon-log.js';
|
|
47
|
+
const log = createLogger({ module: 'engine-readiness' });
|
|
48
|
+
/**
|
|
49
|
+
* How long a not-ready engine holds its spawns before it is re-probed (and, if
|
|
50
|
+
* no re-probe runs, before one spawn is let through to try it). Five minutes:
|
|
51
|
+
* a host that was fixed (installed, logged in) resumes within one wait, and a
|
|
52
|
+
* host that was not costs one probe -- not one failed lead -- per wait.
|
|
53
|
+
*/
|
|
54
|
+
export const ENGINE_REPROBE_MS = 5 * 60_000;
|
|
55
|
+
/** The persisted record's file name, under the global state dir. */
|
|
56
|
+
export const ENGINE_READINESS_FILE = 'engine-readiness.json';
|
|
57
|
+
const records = new Map();
|
|
58
|
+
function statePath() {
|
|
59
|
+
return join(resolveGlobalStateDir(), ENGINE_READINESS_FILE);
|
|
60
|
+
}
|
|
61
|
+
/** Write the record for `telora-daemon status`. Best-effort: a failed write never breaks a spawn. */
|
|
62
|
+
function persist(nowMs) {
|
|
63
|
+
try {
|
|
64
|
+
const dir = resolveGlobalStateDir();
|
|
65
|
+
if (!existsSync(dir))
|
|
66
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
67
|
+
const body = {
|
|
68
|
+
host: hostname(),
|
|
69
|
+
updatedAt: new Date(nowMs).toISOString(),
|
|
70
|
+
engines: [...records.values()],
|
|
71
|
+
};
|
|
72
|
+
const path = statePath();
|
|
73
|
+
const tmp = `${path}.tmp`;
|
|
74
|
+
writeFileSync(tmp, `${JSON.stringify(body, null, 2)}\n`, { mode: 0o600 });
|
|
75
|
+
renameSync(tmp, path);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
log.warn(`[engine] could not persist engine readiness: ${err.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function set(next, nowMs) {
|
|
82
|
+
const prev = records.get(next.engineId);
|
|
83
|
+
records.set(next.engineId, next);
|
|
84
|
+
// A change of readiness is logged as it happens; the first reading is printed
|
|
85
|
+
// by the startup report (shell/unified-shell-status.ts reportEngineReadiness).
|
|
86
|
+
if (prev && (prev.ready !== next.ready || prev.missing !== next.missing)) {
|
|
87
|
+
log.info(formatEngineReadinessLine(next));
|
|
88
|
+
}
|
|
89
|
+
persist(nowMs);
|
|
90
|
+
}
|
|
91
|
+
/** Record what a probe found for an engine. A not-ready engine is re-probed after ENGINE_REPROBE_MS. */
|
|
92
|
+
export function recordEngineProbe(engineId, probe, nowMs = Date.now()) {
|
|
93
|
+
const prev = records.get(engineId);
|
|
94
|
+
const ready = probe.available;
|
|
95
|
+
const missing = ready ? null : (probe.missing ?? 'binary');
|
|
96
|
+
const unchanged = prev !== undefined && prev.ready === ready && prev.missing === missing;
|
|
97
|
+
// A login the probe cannot find holds spawns only when a spawn already saw it fail.
|
|
98
|
+
const holdsSpawns = !ready && (missing === 'binary' || (unchanged && prev.holdsSpawns));
|
|
99
|
+
const next = {
|
|
100
|
+
engineId,
|
|
101
|
+
ready,
|
|
102
|
+
missing,
|
|
103
|
+
detail: ready ? null : (unchanged && prev.detail ? prev.detail : (probe.detail ?? `${engineId} is not ready on ${hostname()}`)),
|
|
104
|
+
source: unchanged ? prev.source : 'probe',
|
|
105
|
+
sinceMs: unchanged ? prev.sinceMs : nowMs,
|
|
106
|
+
nextProbeAtMs: ready ? null : nowMs + ENGINE_REPROBE_MS,
|
|
107
|
+
holdsSpawns,
|
|
108
|
+
};
|
|
109
|
+
set(next, nowMs);
|
|
110
|
+
return next;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Mark an engine not ready from a failed start or a failed authentication. Its
|
|
114
|
+
* spawns are held until a re-probe finds it ready or ENGINE_REPROBE_MS elapses.
|
|
115
|
+
*/
|
|
116
|
+
export function markEngineNotReady(engineId, why, nowMs = Date.now()) {
|
|
117
|
+
const prev = records.get(engineId);
|
|
118
|
+
const unchanged = prev !== undefined && !prev.ready && prev.missing === why.missing;
|
|
119
|
+
const next = {
|
|
120
|
+
engineId,
|
|
121
|
+
ready: false,
|
|
122
|
+
missing: why.missing,
|
|
123
|
+
detail: why.detail,
|
|
124
|
+
source: why.source,
|
|
125
|
+
sinceMs: unchanged ? prev.sinceMs : nowMs,
|
|
126
|
+
nextProbeAtMs: nowMs + ENGINE_REPROBE_MS,
|
|
127
|
+
holdsSpawns: true,
|
|
128
|
+
};
|
|
129
|
+
set(next, nowMs);
|
|
130
|
+
return next;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The instant a not-ready engine's hold on its spawns ends, or null when it
|
|
134
|
+
* holds none: the engine is ready, unknown (never probed -- a spawn is its
|
|
135
|
+
* probe), reported without a hold, or its wait has elapsed.
|
|
136
|
+
*/
|
|
137
|
+
export function engineNotReadyUntilMs(engineId, nowMs = Date.now()) {
|
|
138
|
+
const record = records.get(engineId);
|
|
139
|
+
if (!record || record.ready || !record.holdsSpawns || record.nextProbeAtMs === null)
|
|
140
|
+
return null;
|
|
141
|
+
return record.nextProbeAtMs > nowMs ? record.nextProbeAtMs : null;
|
|
142
|
+
}
|
|
143
|
+
/** True when any engine's readiness holds spawns now (the spawn gates resolve a route only then). */
|
|
144
|
+
export function anyEngineSpawnHold(nowMs = Date.now()) {
|
|
145
|
+
for (const record of records.values())
|
|
146
|
+
if (engineNotReadyUntilMs(record.engineId, nowMs) !== null)
|
|
147
|
+
return true;
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
/** The engines whose re-probe is due: recorded not ready, with the wait elapsed. */
|
|
151
|
+
export function enginesDueForReprobe(nowMs = Date.now()) {
|
|
152
|
+
return [...records.values()]
|
|
153
|
+
.filter((r) => !r.ready && r.nextProbeAtMs !== null && r.nextProbeAtMs <= nowMs)
|
|
154
|
+
.map((r) => r.engineId);
|
|
155
|
+
}
|
|
156
|
+
/** Every engine's current readiness, in engine-id order. */
|
|
157
|
+
export function engineReadinessSnapshot() {
|
|
158
|
+
return [...records.values()].sort((a, b) => a.engineId.localeCompare(b.engineId));
|
|
159
|
+
}
|
|
160
|
+
/** Read the record the running daemon persisted, or null when there is none (or it is unreadable). */
|
|
161
|
+
export function readPersistedEngineReadiness() {
|
|
162
|
+
try {
|
|
163
|
+
const path = statePath();
|
|
164
|
+
if (!existsSync(path))
|
|
165
|
+
return null;
|
|
166
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
167
|
+
if (typeof parsed !== 'object' || parsed === null || !Array.isArray(parsed.engines))
|
|
168
|
+
return null;
|
|
169
|
+
return parsed;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** One engine's readiness line, as the startup log and `telora-daemon status` print it. */
|
|
176
|
+
export function formatEngineReadinessLine(record) {
|
|
177
|
+
if (record.ready)
|
|
178
|
+
return `[engine] ${record.engineId}: ready (starts and authenticates on ${hostname()})`;
|
|
179
|
+
const what = record.missing === 'login' ? 'not logged in' : 'binary not found';
|
|
180
|
+
const hold = record.holdsSpawns ? 'no lead is spawned on it until it re-probes ready' : 'reported only; a per-spawn key may still authenticate it';
|
|
181
|
+
return `[engine] ${record.engineId}: NOT READY on ${hostname()} -- ${what}: ${record.detail ?? 'no detail recorded'} (${hold})`;
|
|
182
|
+
}
|
|
183
|
+
/** Every engine's readiness line. */
|
|
184
|
+
export function formatEngineReadinessLines(engines) {
|
|
185
|
+
return [...engines].sort((a, b) => a.engineId.localeCompare(b.engineId)).map(formatEngineReadinessLine);
|
|
186
|
+
}
|
|
187
|
+
/** Test-only: forget every record, as a daemon re-exec starts with none. */
|
|
188
|
+
export function __resetEngineReadinessForTests() {
|
|
189
|
+
records.clear();
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=engine-readiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-readiness.js","sourceRoot":"","sources":["../../src/daemon-state/engine-readiness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Whether a delivery moving from `from` to `to` is forward progress toward done. The ONE definition. */
|
|
2
|
+
export declare function isForwardDeliveryAdvance(from: string | null | undefined, to: string | null | undefined): boolean;
|
|
3
|
+
/** Record a read of a focus's deliveries; stamps the clock when one advanced forward since the last status known for it. */
|
|
4
|
+
export declare function observeDeliveryProgress(focusId: string, rows: readonly {
|
|
5
|
+
id: string;
|
|
6
|
+
executionStatus?: string | null;
|
|
7
|
+
}[], now: number): void;
|
|
8
|
+
/** Record a read of one delivery's issues; stamps the clock when an issue seen open before is now Done. */
|
|
9
|
+
export declare function observeIssueProgress(focusId: string, deliveryId: string, issues: readonly {
|
|
10
|
+
id: string;
|
|
11
|
+
status: string;
|
|
12
|
+
}[], now: number): void;
|
|
13
|
+
/**
|
|
14
|
+
* A delivery status write LANDED at `now` (the physical writer calls this once
|
|
15
|
+
* its write resolved). Stamps the clock of the focus whose latest read listed
|
|
16
|
+
* the delivery when the move is forward from the last status known for it, and
|
|
17
|
+
* records the written status so the next read does not count the same move
|
|
18
|
+
* again at its later time.
|
|
19
|
+
*/
|
|
20
|
+
export declare function recordDeliveryStatusWrite(deliveryId: string, status: string, now: number): void;
|
|
21
|
+
/**
|
|
22
|
+
* An issue status write LANDED at `now` (the issue status writer calls this once
|
|
23
|
+
* its write resolved). Stamps the clock of the focus whose latest read of a
|
|
24
|
+
* delivery's issues listed the issue when the write completed it, and records
|
|
25
|
+
* the written status so the next read does not count it again.
|
|
26
|
+
*/
|
|
27
|
+
export declare function recordIssueStatusWrite(issueId: string, status: string, now: number): void;
|
|
28
|
+
/** When the focus's work last moved forward (epoch ms), or null when this process has seen no movement. */
|
|
29
|
+
export declare function readFocusLastProgressAt(focusId: string): number | null;
|
|
30
|
+
/** Forget a focus that is no longer active (the poll stopped listing it). */
|
|
31
|
+
export declare function forgetFocusProgress(focusId: string): void;
|
|
32
|
+
/** Test-only: forget every focus. */
|
|
33
|
+
export declare function __resetFocusProgressClockForTests(): void;
|
|
34
|
+
//# sourceMappingURL=focus-progress-clock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-progress-clock.d.ts","sourceRoot":"","sources":["../../src/daemon-state/focus-progress-clock.ts"],"names":[],"mappings":"AAuEA,yGAAyG;AACzG,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAIhH;AAiCD,4HAA4H;AAC5H,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,EAChE,GAAG,EAAE,MAAM,GACV,IAAI,CAUN;AAED,2GAA2G;AAC3G,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,EACjD,GAAG,EAAE,MAAM,GACV,IAAI,CASN;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAQ/F;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CASzF;AAED,2GAA2G;AAC3G,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEtE;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,qCAAqC;AACrC,wBAAgB,iCAAiC,IAAI,IAAI,CAExD"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
|
|
2
|
+
// Pinned by: packages/daemon/src/focus/focus-activity-progress-clock.test.ts,
|
|
3
|
+
// packages/daemon/src/focus/heartbeat-focus-activity.test.ts
|
|
4
|
+
// PINNED-BY-END
|
|
5
|
+
/**
|
|
6
|
+
* The per-focus PROGRESS CLOCK: when a focus's work last moved forward, by the
|
|
7
|
+
* two facts the focus activity record names -- a delivery's execution status
|
|
8
|
+
* advancing FORWARD ({@link isForwardDeliveryAdvance}: queued -> coding ->
|
|
9
|
+
* verify -> done, and verify_failed -> coding) or an issue moving to Done. The
|
|
10
|
+
* record publishes it as every entry's `lastProgressAt`
|
|
11
|
+
* (focus/focus-activity-sources.ts commonFields).
|
|
12
|
+
*
|
|
13
|
+
* Why its own clock: the live team's progress measure
|
|
14
|
+
* (completion/team-progress/team-stillness.ts) is forgotten when the team ends,
|
|
15
|
+
* so the between-sessions entries (idle, cooldown, review_parked, a pending
|
|
16
|
+
* spawn) -- exactly the ones a reader checks for churn -- would publish no
|
|
17
|
+
* progress time at all. This clock is keyed by focus, not by team: a teardown,
|
|
18
|
+
* a respawn or a session ending changes nothing here, so repeated teardowns
|
|
19
|
+
* without progress leave the time standing while the spawn-teardown streak
|
|
20
|
+
* grows beside it.
|
|
21
|
+
*
|
|
22
|
+
* TWO FEEDS, one primary:
|
|
23
|
+
*
|
|
24
|
+
* 1. The daemon's own WRITES, stamped when they land. The physical delivery
|
|
25
|
+
* status writer (queries/deliveries/deliveries.ts updateDeliveryStatus)
|
|
26
|
+
* calls {@link recordDeliveryStatusWrite} once its write resolves, and the
|
|
27
|
+
* issue status writer (queries/deliveries/issues.ts updateIssueStatus)
|
|
28
|
+
* calls {@link recordIssueStatusWrite}: the stamp is the write's own time,
|
|
29
|
+
* not the next poll's.
|
|
30
|
+
* 2. The poll's READS, as RECOVERY (focus/focus-activity-poll-facts.ts), at
|
|
31
|
+
* no extra query: each read of a focus's deliveries and of a delivery's
|
|
32
|
+
* issues is compared with the last status this clock knows for the same
|
|
33
|
+
* rows -- which a landed write has already updated, so the write is not
|
|
34
|
+
* counted twice at the later read time. What the reads catch is movement
|
|
35
|
+
* written ELSEWHERE (an agent closing an issue over MCP, an operator).
|
|
36
|
+
*
|
|
37
|
+
* A write names a delivery or issue, not a focus: it is attributed to the focus
|
|
38
|
+
* whose latest read listed that row. A write to a row no read has listed yet
|
|
39
|
+
* stamps nothing (the first read of it is its baseline). The FIRST read of a
|
|
40
|
+
* focus's deliveries or of a delivery's issues is a baseline, not movement -- a
|
|
41
|
+
* restart or a newly active focus publishes null until something actually
|
|
42
|
+
* moves, never the daemon's boot time dressed up as progress. Only forward
|
|
43
|
+
* edges count: a back-path (verify -> verify_failed, a re-queue) or an issue
|
|
44
|
+
* re-opened is not progress.
|
|
45
|
+
*
|
|
46
|
+
* In memory, per daemon process. Nothing is written to the database.
|
|
47
|
+
*
|
|
48
|
+
* @module daemon-state/focus-progress-clock
|
|
49
|
+
*/
|
|
50
|
+
import { DELIVERY_STATUS } from '@telora/daemon-core';
|
|
51
|
+
/**
|
|
52
|
+
* A delivery's position on the main path toward done; a status absent here
|
|
53
|
+
* (draft, planning, paused, cancelled) is off the path, so no move into or out
|
|
54
|
+
* of it is progress. verify_failed sits with queued: its work is owed again, so
|
|
55
|
+
* a re-queue (verify_failed -> queued) is not progress and a restart
|
|
56
|
+
* (verify_failed -> coding) is. Every adjacent forward step here is a declared
|
|
57
|
+
* EXECUTION_STATUS_TRANSITIONS edge (pinned by the progress-clock test); a read
|
|
58
|
+
* may observe a multi-step jump (queued -> verify between two polls), which is
|
|
59
|
+
* forward too.
|
|
60
|
+
*/
|
|
61
|
+
const MAIN_PATH_RANK = new Map([
|
|
62
|
+
[DELIVERY_STATUS.QUEUED, 0],
|
|
63
|
+
[DELIVERY_STATUS.VERIFY_FAILED, 0],
|
|
64
|
+
[DELIVERY_STATUS.CODING, 1],
|
|
65
|
+
[DELIVERY_STATUS.VERIFY, 2],
|
|
66
|
+
[DELIVERY_STATUS.DONE, 3],
|
|
67
|
+
]);
|
|
68
|
+
/** Whether a delivery moving from `from` to `to` is forward progress toward done. The ONE definition. */
|
|
69
|
+
export function isForwardDeliveryAdvance(from, to) {
|
|
70
|
+
const a = MAIN_PATH_RANK.get(from ?? '');
|
|
71
|
+
const b = MAIN_PATH_RANK.get(to ?? '');
|
|
72
|
+
return a !== undefined && b !== undefined && b > a;
|
|
73
|
+
}
|
|
74
|
+
/** An issue reaching one of these has moved to Done. */
|
|
75
|
+
const DONE_ISSUE_STATUSES = new Set(['Done', 'Verified']);
|
|
76
|
+
/** Whether an issue moving from `before` to `after` completed it. */
|
|
77
|
+
function isIssueCompletion(before, after) {
|
|
78
|
+
return before !== undefined && !DONE_ISSUE_STATUSES.has(before) && DONE_ISSUE_STATUSES.has(after);
|
|
79
|
+
}
|
|
80
|
+
const clocks = new Map();
|
|
81
|
+
function clockOf(focusId) {
|
|
82
|
+
let clock = clocks.get(focusId);
|
|
83
|
+
if (!clock) {
|
|
84
|
+
clock = { deliveryStatuses: null, issueStatuses: new Map(), lastProgressAt: null };
|
|
85
|
+
clocks.set(focusId, clock);
|
|
86
|
+
}
|
|
87
|
+
return clock;
|
|
88
|
+
}
|
|
89
|
+
function stamp(clock, now) {
|
|
90
|
+
clock.lastProgressAt = clock.lastProgressAt === null ? now : Math.max(clock.lastProgressAt, now);
|
|
91
|
+
}
|
|
92
|
+
/** Record a read of a focus's deliveries; stamps the clock when one advanced forward since the last status known for it. */
|
|
93
|
+
export function observeDeliveryProgress(focusId, rows, now) {
|
|
94
|
+
const clock = clockOf(focusId);
|
|
95
|
+
const prior = clock.deliveryStatuses;
|
|
96
|
+
const next = new Map(rows.map((d) => [d.id, d.executionStatus ?? null]));
|
|
97
|
+
if (prior) {
|
|
98
|
+
const advanced = [...next].some(([id, status]) => prior.has(id) && isForwardDeliveryAdvance(prior.get(id), status));
|
|
99
|
+
if (advanced)
|
|
100
|
+
stamp(clock, now);
|
|
101
|
+
}
|
|
102
|
+
clock.deliveryStatuses = next;
|
|
103
|
+
for (const deliveryId of clock.issueStatuses.keys())
|
|
104
|
+
if (!next.has(deliveryId))
|
|
105
|
+
clock.issueStatuses.delete(deliveryId);
|
|
106
|
+
}
|
|
107
|
+
/** Record a read of one delivery's issues; stamps the clock when an issue seen open before is now Done. */
|
|
108
|
+
export function observeIssueProgress(focusId, deliveryId, issues, now) {
|
|
109
|
+
const clock = clockOf(focusId);
|
|
110
|
+
const prior = clock.issueStatuses.get(deliveryId);
|
|
111
|
+
const next = new Map(issues.map((i) => [i.id, i.status]));
|
|
112
|
+
if (prior) {
|
|
113
|
+
const completed = [...next].some(([id, status]) => isIssueCompletion(prior.get(id), status));
|
|
114
|
+
if (completed)
|
|
115
|
+
stamp(clock, now);
|
|
116
|
+
}
|
|
117
|
+
clock.issueStatuses.set(deliveryId, next);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* A delivery status write LANDED at `now` (the physical writer calls this once
|
|
121
|
+
* its write resolved). Stamps the clock of the focus whose latest read listed
|
|
122
|
+
* the delivery when the move is forward from the last status known for it, and
|
|
123
|
+
* records the written status so the next read does not count the same move
|
|
124
|
+
* again at its later time.
|
|
125
|
+
*/
|
|
126
|
+
export function recordDeliveryStatusWrite(deliveryId, status, now) {
|
|
127
|
+
for (const clock of clocks.values()) {
|
|
128
|
+
const statuses = clock.deliveryStatuses;
|
|
129
|
+
if (!statuses?.has(deliveryId))
|
|
130
|
+
continue;
|
|
131
|
+
if (isForwardDeliveryAdvance(statuses.get(deliveryId), status))
|
|
132
|
+
stamp(clock, now);
|
|
133
|
+
statuses.set(deliveryId, status);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* An issue status write LANDED at `now` (the issue status writer calls this once
|
|
139
|
+
* its write resolved). Stamps the clock of the focus whose latest read of a
|
|
140
|
+
* delivery's issues listed the issue when the write completed it, and records
|
|
141
|
+
* the written status so the next read does not count it again.
|
|
142
|
+
*/
|
|
143
|
+
export function recordIssueStatusWrite(issueId, status, now) {
|
|
144
|
+
for (const clock of clocks.values()) {
|
|
145
|
+
for (const issues of clock.issueStatuses.values()) {
|
|
146
|
+
if (!issues.has(issueId))
|
|
147
|
+
continue;
|
|
148
|
+
if (isIssueCompletion(issues.get(issueId), status))
|
|
149
|
+
stamp(clock, now);
|
|
150
|
+
issues.set(issueId, status);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** When the focus's work last moved forward (epoch ms), or null when this process has seen no movement. */
|
|
156
|
+
export function readFocusLastProgressAt(focusId) {
|
|
157
|
+
return clocks.get(focusId)?.lastProgressAt ?? null;
|
|
158
|
+
}
|
|
159
|
+
/** Forget a focus that is no longer active (the poll stopped listing it). */
|
|
160
|
+
export function forgetFocusProgress(focusId) {
|
|
161
|
+
clocks.delete(focusId);
|
|
162
|
+
}
|
|
163
|
+
/** Test-only: forget every focus. */
|
|
164
|
+
export function __resetFocusProgressClockForTests() {
|
|
165
|
+
clocks.clear();
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=focus-progress-clock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-progress-clock.js","sourceRoot":"","sources":["../../src/daemon-state/focus-progress-clock.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* Owner of the `lifecycle` and `activity` sub-records of FocusTeamState (see
|
|
12
12
|
* types/focus-team-state.ts, TEAM_STATE_OWNERS): every write of phase,
|
|
13
13
|
* shutdownReason, shutdownAttribution, shuttingDownAt, lastActivityAt,
|
|
14
|
-
* toolActivityCount and
|
|
14
|
+
* toolActivityCount, errorResultAt, modelReachedAt and the working delivery goes through a writer
|
|
15
|
+
* exported here.
|
|
15
16
|
*
|
|
16
17
|
* The ONE intentional side-table is `slotTokens`. It is deliberately NOT folded
|
|
17
18
|
* onto the record because its lifecycle must OUTLIVE activeTeams membership: a
|
|
@@ -39,6 +40,26 @@ import type { ShutdownAttribution, TeamShutdownReason } from '../types/shutdown-
|
|
|
39
40
|
* @param now Epoch ms of the event (default Date.now()).
|
|
40
41
|
*/
|
|
41
42
|
export declare function recordTeamActivity(focusId: string, now?: number): void;
|
|
43
|
+
/**
|
|
44
|
+
* Record the delivery `team` is working, observed at `observedAt`. Bound to the
|
|
45
|
+
* team OBJECT, not its focus: an observation that resolves after its team left
|
|
46
|
+
* activeTeams (and a replacement took the focus) is dropped, never stamped on the
|
|
47
|
+
* replacement. An observation older than the one already recorded is dropped too
|
|
48
|
+
* (resolutions complete out of order).
|
|
49
|
+
*/
|
|
50
|
+
export declare function recordTeamWorkingDelivery(team: FocusTeamState, deliveryId: string, observedAt: number): void;
|
|
51
|
+
/**
|
|
52
|
+
* Seed the delivery a team is spawned to work (spawn/team-working-delivery.ts
|
|
53
|
+
* workingDeliveryAtSpawn), before its first act. Dated at epoch 0, so any
|
|
54
|
+
* observation of the team's own acts supersedes it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function seedTeamWorkingDelivery(team: FocusTeamState, deliveryId: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Record that `team` was spawned with no delivery to work on a focus whose
|
|
59
|
+
* deliveries are all terminal (spawn/team-working-delivery.ts). A delivery its
|
|
60
|
+
* own acts later name supersedes it (the producer reads the delivery first).
|
|
61
|
+
*/
|
|
62
|
+
export declare function seedTeamResolvingWithoutDelivery(team: FocusTeamState): void;
|
|
42
63
|
/**
|
|
43
64
|
* Epoch ms of the team's last recorded agent event, or null when nothing has
|
|
44
65
|
* been recorded yet (e.g. a team still initializing before its first event, or
|
|
@@ -88,6 +109,8 @@ export declare function setTeamShutdownReason(team: FocusTeamState, reason: Team
|
|
|
88
109
|
export declare function setShutdownAttribution(team: FocusTeamState, attribution: ShutdownAttribution): void;
|
|
89
110
|
/** Count one tool invocation by the pass (inspection evidence for the review-exit gate). */
|
|
90
111
|
export declare function countToolActivity(team: FocusTeamState): void;
|
|
112
|
+
/** Record that the session's model was reached, at the FIRST output it produced (later outputs keep that instant). */
|
|
113
|
+
export declare function markModelReached(team: FocusTeamState, atMs: number): void;
|
|
91
114
|
/** Record that the session emitted a terminal-error result at `atMs`. */
|
|
92
115
|
export declare function stampErrorResult(team: FocusTeamState, atMs: number): void;
|
|
93
116
|
/**
|
|
@@ -153,18 +176,18 @@ export declare function hasActiveTeam(focusId: string): boolean;
|
|
|
153
176
|
*/
|
|
154
177
|
export declare function getActiveTeamCount(): number;
|
|
155
178
|
/**
|
|
156
|
-
* Build the per-focus
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
179
|
+
* Build the per-focus activity-clock map: focusId -> epoch ms of the team's last
|
|
180
|
+
* recorded agent event, for every active team that has recorded at least one
|
|
181
|
+
* event -- the SAME in-memory clock the daemon acts on to decide a team is still
|
|
182
|
+
* running (getTeamLastActivityAt / recordTeamActivity). The heartbeat feeds it to
|
|
183
|
+
* the clock-divergence health check; it is no longer published as
|
|
184
|
+
* metadata.teamClocks (the focus activity record carries the clock as
|
|
185
|
+
* lastAgentEventAt on its team entries).
|
|
162
186
|
*
|
|
163
187
|
* Pull-model, exactly like buildTeamLivenessPhaseMap: recomputed from live activeTeams
|
|
164
188
|
* each heartbeat, so a torn-down focus drops out of the map on its own. A team
|
|
165
189
|
* still initializing before its first event (lastActivityAt undefined) is
|
|
166
|
-
* omitted -- an absent clock
|
|
167
|
-
* never as a frozen-since-epoch team.
|
|
190
|
+
* omitted -- an absent clock is "no event yet", never a frozen-since-epoch team.
|
|
168
191
|
*/
|
|
169
192
|
export declare function buildTeamClockMap(): Record<string, number>;
|
|
170
193
|
/**
|