@reticlehq/server 3.7.0 → 3.8.1
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/SKILL.md +59 -68
- package/bin/reticle.js +9 -2
- package/dist/command/cli/adhoc-suite.js +1 -1
- package/dist/command/cli/adhoc-verdict.d.ts +12 -0
- package/dist/command/cli/adhoc-verdict.js +62 -4
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +5 -1
- package/dist/command/cli/auth/cloud-session.d.ts +11 -19
- package/dist/command/cli/auth/cloud-session.js +23 -0
- package/dist/command/cli/auth/device-flow.d.ts +3 -37
- package/dist/command/cli/cli-doctor.js +66 -21
- package/dist/command/cli/cli-flow-commands.js +53 -11
- package/dist/command/cli/cli-kill.d.ts +8 -0
- package/dist/command/cli/cli-kill.js +43 -3
- package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
- package/dist/command/cli/cli-parse-feedback.js +13 -1
- package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
- package/dist/command/cli/cli-parse-grammar.js +1 -6
- package/dist/command/cli/cli-parse-serve.d.ts +24 -0
- package/dist/command/cli/cli-parse-serve.js +124 -0
- package/dist/command/cli/cli-parse.d.ts +12 -11
- package/dist/command/cli/cli-parse.js +100 -123
- package/dist/command/cli/cli-usage.d.ts +0 -11
- package/dist/command/cli/cli-usage.js +43 -16
- package/dist/command/cli/cli-verify.d.ts +1 -1
- package/dist/command/cli/cli-verify.js +29 -14
- package/dist/command/cli/cloud-cli.js +27 -9
- package/dist/command/cli/cloud-kit.js +3 -3
- package/dist/command/cli/cloud-link.d.ts +1 -20
- package/dist/command/cli/cloud-link.js +2 -0
- package/dist/command/cli/cloud-login.d.ts +6 -2
- package/dist/command/cli/cloud-login.js +13 -41
- package/dist/command/cli/config/checkout.d.ts +10 -0
- package/dist/command/cli/config/checkout.js +78 -0
- package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
- package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
- package/dist/command/cli/doctor/doctor-rows.js +4 -0
- package/dist/command/cli/drive/drive-attach.d.ts +5 -0
- package/dist/command/cli/drive/drive-attach.js +21 -1
- package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
- package/dist/command/cli/hook/codex-transcript.js +224 -0
- package/dist/command/cli/hook/episode-structure.d.ts +24 -0
- package/dist/command/cli/hook/episode-structure.js +138 -0
- package/dist/command/cli/hook/hook-command.d.ts +9 -0
- package/dist/command/cli/hook/hook-command.js +211 -0
- package/dist/command/cli/hook/hook-fast.d.ts +31 -0
- package/dist/command/cli/hook/hook-fast.js +136 -0
- package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
- package/dist/command/cli/hook/prompt-hook.js +199 -0
- package/dist/command/cli/hook/tool-hook.d.ts +21 -0
- package/dist/command/cli/hook/tool-hook.js +259 -0
- package/dist/command/cli/launch/cli-launch.d.ts +2 -0
- package/dist/command/cli/launch/cli-launch.js +22 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
- package/dist/command/cli/mcp-command.d.ts +9 -0
- package/dist/command/cli/mcp-command.js +127 -41
- package/dist/command/cli/open-navigate.d.ts +43 -0
- package/dist/command/cli/open-navigate.js +85 -0
- package/dist/command/cli/ports/port-holder.d.ts +16 -4
- package/dist/command/cli/ports/port-holder.js +58 -12
- package/dist/command/cli/ports/resolve/cli-port.js +18 -2
- package/dist/command/cli/project-name.d.ts +1 -7
- package/dist/command/cli/project-name.js +1 -0
- package/dist/command/cli/report-command.d.ts +8 -2
- package/dist/command/cli/report-command.js +95 -18
- package/dist/command/cli/status-fields.d.ts +9 -2
- package/dist/command/cli/status-fields.js +148 -4
- package/dist/command/cli/try-command.d.ts +3 -4
- package/dist/command/cli/try-command.js +6 -11
- package/dist/command/cli/verify-results.d.ts +4 -1
- package/dist/command/cli/verify-results.js +3 -1
- package/dist/command/cli.d.ts +1 -7
- package/dist/command/cli.js +79 -160
- package/dist/command/daemon/daemon-resilience.d.ts +6 -1
- package/dist/command/daemon/daemon-resilience.js +31 -18
- package/dist/command/daemon/daemon.d.ts +11 -0
- package/dist/command/daemon/daemon.js +70 -2
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
- package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
- package/dist/command/daemon/wake-decision.js +4 -2
- package/dist/command/daemon/win32-escape.d.ts +32 -0
- package/dist/command/daemon/win32-escape.js +119 -0
- package/dist/command/setup/agent-configs.d.ts +9 -0
- package/dist/command/setup/agent-configs.js +9 -0
- package/dist/command/setup/auto-approve.d.ts +10 -3
- package/dist/command/setup/auto-approve.js +51 -3
- package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
- package/dist/command/setup/bringup/dev-server-wait.js +5 -1
- package/dist/command/setup/bringup/ensure-daemon.js +4 -7
- package/dist/command/setup/init/init-host.js +6 -0
- package/dist/command/setup/init/init-port.js +5 -4
- package/dist/command/setup/init/init-runtime.js +7 -1
- package/dist/command/setup/node-effects.d.ts +8 -0
- package/dist/command/setup/node-effects.js +36 -4
- package/dist/command/setup/probe/dev-port.d.ts +26 -0
- package/dist/command/setup/probe/dev-port.js +117 -0
- package/dist/command/setup/probe/page-probe.d.ts +1 -1
- package/dist/command/setup/probe/page-probe.js +11 -3
- package/dist/command/setup/remaining-steps.d.ts +0 -7
- package/dist/command/setup/remaining-steps.js +3 -2
- package/dist/command/setup/run-setup.d.ts +11 -0
- package/dist/command/setup/run-setup.js +33 -5
- package/dist/command/setup/setup-command.d.ts +2 -0
- package/dist/command/setup/setup-command.js +22 -4
- package/dist/command/update/updater.d.ts +1 -6
- package/dist/command/update/updater.js +4 -5
- package/dist/command/update/version-seen.d.ts +24 -0
- package/dist/command/update/version-seen.js +65 -0
- package/dist/command/version/peer-announce.d.ts +9 -1
- package/dist/command/version/peer-announce.js +25 -2
- package/dist/command/version/sdk-fix.d.ts +5 -6
- package/dist/command/version/sdk-fix.js +17 -32
- package/dist/command/version/version-skew.d.ts +16 -1
- package/dist/command/version/version-skew.js +84 -10
- package/dist/features/crawl/crawl-tools.js +2 -2
- package/dist/features/crawl/crawl.js +2 -0
- package/dist/features/exhaust/ledger.d.ts +15 -96
- package/dist/features/exhaust/ledger.js +3 -3
- package/dist/features/harness/drive-runs.d.ts +28 -4
- package/dist/features/harness/drive-runs.js +99 -7
- package/dist/features/harness/drivers.d.ts +1 -1
- package/dist/features/harness/drivers.js +1 -1
- package/dist/features/harness/harness.d.ts +5 -0
- package/dist/features/harness/harness.js +24 -12
- package/dist/features/harness/platform/platform-drives.d.ts +7 -1
- package/dist/features/harness/platform/platform-drives.js +12 -7
- package/dist/features/harness/platform/refusal.d.ts +1 -1
- package/dist/features/harness/platform/refusal.js +4 -4
- package/dist/features/harness/platform/remote-drive.js +70 -28
- package/dist/features/harness/platform/server-driver.js +22 -1
- package/dist/features/harness/platform-config.d.ts +1 -10
- package/dist/features/harness/platform-config.js +0 -20
- package/dist/features/license/license.d.ts +2 -14
- package/dist/features/visual/step-shots.d.ts +33 -1
- package/dist/features/visual/step-shots.js +155 -1
- package/dist/features/visual/visual-tools.js +12 -4
- package/dist/hooks/coding-agents.d.ts +6 -0
- package/dist/hooks/coding-agents.js +24 -3
- package/dist/hooks/episode-stamp.d.ts +32 -0
- package/dist/hooks/episode-stamp.js +61 -0
- package/dist/hooks/hook-commands.js +19 -9
- package/dist/index.d.ts +5 -1
- package/dist/index.js +66 -24
- package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
- package/dist/judgement/app-graph/journal-steps.js +92 -0
- package/dist/judgement/capsule/capsule-store.d.ts +2 -39
- package/dist/judgement/domain/domain-model.js +1 -10
- package/dist/judgement/domain/domain-tools.js +4 -2
- package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
- package/dist/judgement/runs/artifact/run-store.js +153 -28
- package/dist/judgement/runs/default-run-id.d.ts +3 -1
- package/dist/judgement/runs/default-run-id.js +15 -3
- package/dist/judgement/runs/drive-run.d.ts +3 -3
- package/dist/judgement/runs/drive-run.js +11 -7
- package/dist/judgement/runs/run-ledger.d.ts +21 -0
- package/dist/judgement/runs/run-ledger.js +143 -0
- package/dist/judgement/runs/runner-port.d.ts +1 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +4 -3
- package/dist/judgement/runs/verification-sync.js +27 -5
- package/dist/language/flows/affected-tools.js +2 -1
- package/dist/language/flows/annotate-notes/annotate.js +8 -3
- package/dist/language/flows/annotate-tools.js +1 -1
- package/dist/language/flows/change/affected.d.ts +8 -0
- package/dist/language/flows/change/affected.js +20 -7
- package/dist/language/flows/decision.js +19 -4
- package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
- package/dist/language/flows/fields/flow-secret-field.js +67 -5
- package/dist/language/flows/flow-anchor.d.ts +5 -0
- package/dist/language/flows/flow-anchor.js +4 -0
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +9 -0
- package/dist/language/flows/flow-expect-grammar.js +15 -10
- package/dist/language/flows/flow-intent.js +6 -1
- package/dist/language/flows/flow-journey.d.ts +8 -0
- package/dist/language/flows/flow-journey.js +13 -0
- package/dist/language/flows/flow-lease.d.ts +27 -0
- package/dist/language/flows/flow-lease.js +59 -0
- package/dist/language/flows/flow-replay-run.d.ts +1 -87
- package/dist/language/flows/flow-replay-run.js +111 -310
- package/dist/language/flows/flow-replay.js +21 -19
- package/dist/language/flows/flow-replayable.d.ts +38 -0
- package/dist/language/flows/flow-replayable.js +179 -0
- package/dist/language/flows/flow-start-path.d.ts +108 -0
- package/dist/language/flows/flow-start-path.js +313 -0
- package/dist/language/flows/flow-step-runners.d.ts +23 -2
- package/dist/language/flows/flow-step-runners.js +191 -32
- package/dist/language/flows/flow-store-for-session.d.ts +8 -1
- package/dist/language/flows/flow-store-for-session.js +6 -0
- package/dist/language/flows/flow-tools.d.ts +2 -23
- package/dist/language/flows/flow-tools.js +63 -113
- package/dist/language/flows/flows.d.ts +4 -6
- package/dist/language/flows/flows.js +90 -15
- package/dist/language/flows/heal-run.d.ts +10 -4
- package/dist/language/flows/heal-run.js +26 -9
- package/dist/language/flows/recording/flake.d.ts +3 -27
- package/dist/language/flows/recording/flake.js +1 -1
- package/dist/language/flows/recording/recording-backtrack.js +1 -4
- package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
- package/dist/language/flows/recording/tape/recordings.js +9 -3
- package/dist/language/flows/replay.d.ts +25 -5
- package/dist/language/flows/replay.js +83 -16
- package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
- package/dist/language/flows/suite/coverage.d.ts +9 -0
- package/dist/language/flows/suite/coverage.js +12 -1
- package/dist/language/flows/suite-selection.d.ts +25 -0
- package/dist/language/flows/suite-selection.js +41 -9
- package/dist/machine/git-tracks.d.ts +6 -0
- package/dist/machine/git-tracks.js +36 -0
- package/dist/memory/cloud/background-sync.d.ts +25 -0
- package/dist/memory/cloud/background-sync.js +79 -0
- package/dist/memory/cloud/cloud-config.d.ts +12 -1
- package/dist/memory/cloud/cloud-config.js +39 -13
- package/dist/memory/cloud/cloud-sync.d.ts +3 -24
- package/dist/memory/cloud/cloud-sync.js +5 -2
- package/dist/memory/cloud/harness-config.d.ts +0 -7
- package/dist/memory/cloud/memory-scope.d.ts +19 -0
- package/dist/memory/cloud/memory-scope.js +48 -0
- package/dist/memory/cloud/sync-answer.d.ts +43 -0
- package/dist/memory/cloud/sync-answer.js +42 -0
- package/dist/memory/cloud/sync-cycle.d.ts +40 -10
- package/dist/memory/cloud/sync-cycle.js +97 -144
- package/dist/memory/cloud/sync-daemon.d.ts +50 -3
- package/dist/memory/cloud/sync-daemon.js +473 -83
- package/dist/memory/cloud/sync-describe.d.ts +28 -0
- package/dist/memory/cloud/sync-describe.js +92 -0
- package/dist/memory/cloud/sync-disk.d.ts +9 -1
- package/dist/memory/cloud/sync-disk.js +137 -33
- package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
- package/dist/memory/cloud/sync-flow-versions.js +42 -0
- package/dist/memory/impact/impact-store.js +32 -15
- package/dist/memory/intent/intent-shard.d.ts +41 -266
- package/dist/memory/intent/intent-tools.js +20 -61
- package/dist/memory/intent/record-request.d.ts +27 -0
- package/dist/memory/intent/record-request.js +88 -0
- package/dist/memory/intent/settled-words.js +9 -1
- package/dist/memory/journal/drive-flow.d.ts +3 -0
- package/dist/memory/journal/drive-flow.js +11 -41
- package/dist/memory/journal/envelope-store.js +1 -1
- package/dist/memory/journal/envelope.d.ts +6 -154
- package/dist/memory/journal/episode-log.d.ts +107 -0
- package/dist/memory/journal/episode-log.js +302 -0
- package/dist/memory/journal/journal-recorder.d.ts +7 -0
- package/dist/memory/journal/journal-recorder.js +22 -9
- package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
- package/dist/memory/journal/on-disk/ambient-file.js +1 -1
- package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
- package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
- package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
- package/dist/memory/journal/self-observation.js +3 -1
- package/dist/memory/journal/session-end.js +23 -9
- package/dist/memory/journal/session-journal.js +39 -20
- package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
- package/dist/memory/project/artifact-root-resolver.js +68 -23
- package/dist/memory/project/artifact-root.d.ts +17 -3
- package/dist/memory/project/artifact-root.js +47 -9
- package/dist/memory/project/fs/fs-port.d.ts +5 -0
- package/dist/memory/project/fs/fs-port.js +13 -0
- package/dist/memory/project/learned-routes.d.ts +3 -4
- package/dist/memory/project/learned-routes.js +3 -11
- package/dist/memory/project/link-directory.js +5 -2
- package/dist/memory/project/root-claims.d.ts +3 -1
- package/dist/memory/project/root-claims.js +41 -7
- package/dist/memory/project/session-root.d.ts +1 -1
- package/dist/memory/project/session-root.js +1 -15
- package/dist/memory/project/sync-status.js +5 -6
- package/dist/memory/recall/memory-tools.js +2 -2
- package/dist/memory/recall/platform-memory.d.ts +3 -1
- package/dist/memory/recall/platform-memory.js +9 -1
- package/dist/memory/recall/project-memory.js +15 -19
- package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
- package/dist/portal/bridge/auth-failure-reason.js +19 -0
- package/dist/portal/bridge/bridge.d.ts +19 -4
- package/dist/portal/bridge/bridge.js +150 -177
- package/dist/portal/bridge/harness-request.d.ts +15 -0
- package/dist/portal/bridge/harness-request.js +19 -0
- package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
- package/dist/portal/bridge/origin/origin-follow.js +110 -0
- package/dist/portal/bridge/pairing-token.d.ts +6 -0
- package/dist/portal/bridge/pairing-token.js +47 -16
- package/dist/portal/bridge/protocol-skew.d.ts +27 -2
- package/dist/portal/bridge/protocol-skew.js +66 -2
- package/dist/portal/bridge/session-nonces.d.ts +46 -0
- package/dist/portal/bridge/session-nonces.js +72 -0
- package/dist/portal/input/viewport-tools.d.ts +31 -0
- package/dist/portal/input/viewport-tools.js +106 -15
- package/dist/portal/pool/bounded-close.d.ts +23 -0
- package/dist/portal/pool/bounded-close.js +38 -0
- package/dist/portal/pool/browser-pool.d.ts +44 -39
- package/dist/portal/pool/browser-pool.js +247 -95
- package/dist/portal/pool/context-permissions.d.ts +9 -1
- package/dist/portal/pool/context-permissions.js +26 -0
- package/dist/portal/pool/lease-emulation.d.ts +37 -0
- package/dist/portal/pool/lease-emulation.js +29 -0
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +74 -7
- package/dist/portal/pool/pool-contract.d.ts +23 -1
- package/dist/portal/pool/pool-lease.d.ts +128 -0
- package/dist/portal/pool/pool-lease.js +49 -0
- package/dist/portal/pool/zero-install.d.ts +8 -1
- package/dist/portal/pool/zero-install.js +24 -2
- package/dist/portal/production/production-activation.d.ts +136 -0
- package/dist/portal/production/production-activation.js +173 -0
- package/dist/portal/production/production-drive.d.ts +52 -0
- package/dist/portal/production/production-drive.js +301 -0
- package/dist/portal/production/production-hello.d.ts +23 -0
- package/dist/portal/production/production-hello.js +23 -0
- package/dist/portal/realm/web-realm.js +42 -15
- package/dist/portal/session/control-envelope.d.ts +1 -1
- package/dist/portal/session/dev-server/served-document.d.ts +0 -5
- package/dist/portal/session/dev-server/served-document.js +6 -8
- package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
- package/dist/portal/session/first-run-wiring.d.ts +3 -36
- package/dist/portal/session/first-run-wiring.js +10 -103
- package/dist/portal/session/live-control-tools.js +61 -19
- package/dist/portal/session/no-session-next-action.d.ts +11 -0
- package/dist/portal/session/no-session-next-action.js +40 -15
- package/dist/portal/session/no-session-watch.d.ts +7 -0
- package/dist/portal/session/no-session-watch.js +67 -23
- package/dist/portal/session/output-budget.d.ts +10 -0
- package/dist/portal/session/output-budget.js +16 -0
- package/dist/portal/session/presence/session-lease.d.ts +2 -0
- package/dist/portal/session/presence/session-lease.js +8 -0
- package/dist/portal/session/recorded-gaps.d.ts +15 -11
- package/dist/portal/session/recorded-gaps.js +39 -18
- package/dist/portal/session/serving-directory.d.ts +24 -2
- package/dist/portal/session/serving-directory.js +93 -5
- package/dist/portal/session/session-info.d.ts +26 -0
- package/dist/portal/session/session-info.js +20 -0
- package/dist/portal/session/session-manager.d.ts +35 -3
- package/dist/portal/session/session-manager.js +69 -14
- package/dist/portal/session/session-successor.js +1 -9
- package/dist/portal/session/session-tools.js +22 -4
- package/dist/portal/session/session.d.ts +10 -10
- package/dist/portal/session/session.js +37 -29
- package/dist/portal/session/zero-install-first-call.d.ts +7 -2
- package/dist/portal/session/zero-install-first-call.js +43 -20
- package/dist/start-wiring.d.ts +2 -2
- package/dist/start-wiring.js +17 -3
- package/dist/status-payload.d.ts +11 -1
- package/dist/status-payload.js +7 -1
- package/dist/surface/agent-presence-grace.d.ts +11 -0
- package/dist/surface/agent-presence-grace.js +34 -0
- package/dist/surface/http-server.d.ts +12 -1
- package/dist/surface/http-server.js +64 -15
- package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
- package/dist/surface/mcp/faults/mcp-outage.js +19 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
- package/dist/surface/mcp/mcp-proxy.js +194 -267
- package/dist/surface/mcp/mcp.d.ts +20 -3
- package/dist/surface/mcp/mcp.js +88 -25
- package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
- package/dist/surface/mcp/proxy/drive-calls.js +114 -5
- package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
- package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
- package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
- package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
- package/dist/surface/mcp/server-instructions.js +35 -16
- package/dist/surface/mcp/shared-params.d.ts +8 -0
- package/dist/surface/mcp/shared-params.js +15 -1
- package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
- package/dist/surface/mcp/sse-frame-parser.js +18 -0
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +13 -0
- package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
- package/dist/surface/mcp/tool-catalog-cache.js +14 -4
- package/dist/surface/tools/account-tool.d.ts +4 -3
- package/dist/surface/tools/account-tool.js +20 -31
- package/dist/surface/tools/act/act-danger.d.ts +2 -0
- package/dist/surface/tools/act/act-danger.js +41 -14
- package/dist/surface/tools/act/act-observation.d.ts +11 -0
- package/dist/surface/tools/act/act-observation.js +33 -0
- package/dist/surface/tools/act/act-preflight.js +10 -3
- package/dist/surface/tools/act/act-sequence-retry.js +2 -1
- package/dist/surface/tools/act/act-target.js +19 -5
- package/dist/surface/tools/act/durable.js +1 -1
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
- package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
- package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
- package/dist/surface/tools/act/unsettled-find.js +71 -0
- package/dist/surface/tools/act-sequence-tool.js +53 -24
- package/dist/surface/tools/act-tools.d.ts +2 -3
- package/dist/surface/tools/act-tools.js +49 -47
- package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
- package/dist/surface/tools/agent/for-the-agent.js +41 -3
- package/dist/surface/tools/assert/assert-grade.js +8 -3
- package/dist/surface/tools/assert/assert-verdict.js +4 -2
- package/dist/surface/tools/browser-tools.js +7 -4
- package/dist/surface/tools/chat-drives.js +50 -25
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.d.ts +8 -0
- package/dist/surface/tools/dynamic-tools.js +89 -34
- package/dist/surface/tools/empty-session-list.d.ts +18 -25
- package/dist/surface/tools/empty-session-list.js +67 -38
- package/dist/surface/tools/error-recovery.d.ts +17 -7
- package/dist/surface/tools/error-recovery.js +53 -20
- package/dist/surface/tools/explore-tools.d.ts +10 -0
- package/dist/surface/tools/explore-tools.js +72 -19
- package/dist/surface/tools/feedback-tools.js +23 -2
- package/dist/surface/tools/gap-novelty.d.ts +6 -0
- package/dist/surface/tools/gap-novelty.js +9 -0
- package/dist/surface/tools/gaps/capability-absences.js +4 -3
- package/dist/surface/tools/harness-explore.d.ts +1 -1
- package/dist/surface/tools/harness-explore.js +6 -4
- package/dist/surface/tools/harness-gate.d.ts +43 -21
- package/dist/surface/tools/harness-gate.js +55 -81
- package/dist/surface/tools/harness-script.d.ts +2 -0
- package/dist/surface/tools/harness-script.js +11 -6
- package/dist/surface/tools/harness-toolset.js +3 -4
- package/dist/surface/tools/invoke-tool.d.ts +0 -8
- package/dist/surface/tools/invoke-tool.js +164 -178
- package/dist/surface/tools/lease-hint.d.ts +9 -0
- package/dist/surface/tools/lease-hint.js +22 -3
- package/dist/surface/tools/lease-permissions.d.ts +1 -1
- package/dist/surface/tools/lease-readiness.d.ts +55 -0
- package/dist/surface/tools/lease-readiness.js +150 -2
- package/dist/surface/tools/lease-tools.d.ts +3 -75
- package/dist/surface/tools/lease-tools.js +124 -188
- package/dist/surface/tools/map-tools.d.ts +20 -0
- package/dist/surface/tools/map-tools.js +145 -0
- package/dist/surface/tools/merge-tools.js +11 -7
- package/dist/surface/tools/next-step.js +6 -3
- package/dist/surface/tools/observe-tools.js +46 -35
- package/dist/surface/tools/platform-moment.d.ts +3 -12
- package/dist/surface/tools/platform-moment.js +12 -24
- package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
- package/dist/surface/tools/read/complete-snapshot.js +13 -2
- package/dist/surface/tools/read/query-paginate.js +6 -0
- package/dist/surface/tools/read/query-shape.d.ts +9 -0
- package/dist/surface/tools/read/query-shape.js +15 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
- package/dist/surface/tools/read-tools.js +5 -5
- package/dist/surface/tools/real-input-attempt.d.ts +11 -0
- package/dist/surface/tools/real-input-attempt.js +206 -38
- package/dist/surface/tools/reconcile-tools.js +21 -8
- package/dist/surface/tools/reticle-result.d.ts +3 -0
- package/dist/surface/tools/reticle-result.js +8 -1
- package/dist/surface/tools/run-report.d.ts +22 -0
- package/dist/surface/tools/run-report.js +141 -0
- package/dist/surface/tools/session-ports.d.ts +57 -0
- package/dist/surface/tools/session-ports.js +102 -0
- package/dist/surface/tools/tool-kit.d.ts +58 -4
- package/dist/surface/tools/tool-kit.js +140 -6
- package/dist/surface/tools/tool-surface.d.ts +2 -0
- package/dist/surface/tools/tool-surface.js +45 -0
- package/dist/surface/tools/tools.js +49 -87
- package/dist/telemetry/automation-hint.d.ts +5 -0
- package/dist/telemetry/automation-hint.js +7 -0
- package/dist/telemetry/cli-telemetry.d.ts +22 -0
- package/dist/telemetry/cli-telemetry.js +80 -11
- package/dist/telemetry/daemon-telemetry.d.ts +3 -1
- package/dist/telemetry/daemon-telemetry.js +9 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +8 -3
- package/dist/telemetry/feedback.d.ts +1 -1
- package/dist/telemetry/feedback.js +51 -4
- package/dist/telemetry/harness-run.d.ts +3 -3
- package/dist/telemetry/harness-run.js +18 -7
- package/dist/telemetry/hud-events.d.ts +1 -1
- package/dist/telemetry/hud-metrics.d.ts +6 -3
- package/dist/telemetry/hud-metrics.js +20 -8
- package/dist/telemetry/install-source.js +1 -1
- package/dist/telemetry/mcp-connection.d.ts +1 -1
- package/dist/telemetry/mcp-connection.js +21 -2
- package/dist/telemetry/onboarding-firsts.d.ts +6 -1
- package/dist/telemetry/onboarding-firsts.js +41 -1
- package/dist/telemetry/proxy-telemetry.d.ts +42 -0
- package/dist/telemetry/proxy-telemetry.js +70 -1
- package/dist/telemetry/session-metrics.d.ts +1 -3
- package/dist/telemetry/session-metrics.js +16 -12
- package/dist/telemetry/telemetry.d.ts +9 -1
- package/dist/telemetry/telemetry.js +16 -1
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +7 -1
- package/dist/wire-journal.js +12 -2
- package/docs/README.md +4 -2
- package/docs/actions.mdx +7 -6
- package/docs/adapters.md +2 -1
- package/docs/agent-cheatsheet.md +19 -5
- package/docs/architecture.md +13 -10
- package/docs/autodrive.md +6 -5
- package/docs/benchmarks.md +2 -2
- package/docs/capabilities.mdx +1 -1
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +6 -6
- package/docs/cli/doctor.mdx +3 -1
- package/docs/cli/feedback.mdx +11 -7
- package/docs/cli/gate.mdx +1 -1
- package/docs/cli/help.mdx +1 -1
- package/docs/cli/init.mdx +20 -16
- package/docs/cli/mcp.mdx +5 -2
- package/docs/cli/open.mdx +5 -2
- package/docs/cli/report.mdx +1 -1
- package/docs/cli/restart.mdx +1 -1
- package/docs/cli/rollback.mdx +4 -4
- package/docs/cli/serve.mdx +7 -5
- package/docs/cli/setup.mdx +1 -1
- package/docs/cli/status.mdx +6 -2
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/telemetry.mdx +5 -1
- package/docs/cli/try.mdx +8 -8
- package/docs/cli/update.mdx +8 -5
- package/docs/cli/verify.mdx +12 -5
- package/docs/cli/version.mdx +1 -1
- package/docs/cli.mdx +10 -6
- package/docs/debugging.md +1 -1
- package/docs/deploy-checks.md +8 -6
- package/docs/desktop.mdx +14 -18
- package/docs/enterprise.md +6 -6
- package/docs/environment.mdx +5 -3
- package/docs/faq.mdx +9 -6
- package/docs/first-drive.md +19 -9
- package/docs/flows.md +3 -4
- package/docs/for-agents.md +1 -1
- package/docs/frameworks.mdx +34 -11
- package/docs/getting-started.md +46 -29
- package/docs/http-transport.md +2 -2
- package/docs/human-control.md +8 -8
- package/docs/index.mdx +2 -2
- package/docs/install-agentic.mdx +18 -19
- package/docs/install-manual.mdx +8 -4
- package/docs/integration-patterns.md +5 -5
- package/docs/multi-agent-testing.md +7 -5
- package/docs/packages/browser.mdx +34 -2
- package/docs/packages/core.mdx +2 -1
- package/docs/packages/electron.mdx +15 -3
- package/docs/packages/eslint-plugin.mdx +1 -1
- package/docs/packages/next.mdx +17 -5
- package/docs/packages/react.mdx +8 -1
- package/docs/packages/server.mdx +3 -3
- package/docs/packages/tauri.mdx +3 -3
- package/docs/packages/vite-plugin.mdx +1 -1
- package/docs/packages.mdx +19 -6
- package/docs/platform-integration.md +12 -4
- package/docs/predicates.mdx +18 -7
- package/docs/production-mode.md +108 -0
- package/docs/prompt-capture.md +99 -0
- package/docs/quickstart.mdx +14 -12
- package/docs/recipes.mdx +9 -8
- package/docs/required-checks.md +3 -2
- package/docs/skill-file.mdx +4 -3
- package/docs/skill-setup.md +2 -2
- package/docs/skill.md +62 -70
- package/docs/state-files.md +1 -0
- package/docs/state-management.mdx +11 -9
- package/docs/system-map.md +14 -13
- package/docs/telemetry.md +32 -24
- package/docs/testing.md +9 -5
- package/docs/tools/act-and-wait.mdx +17 -13
- package/docs/tools/act-sequence.mdx +40 -66
- package/docs/tools/act.mdx +7 -5
- package/docs/tools/assert.mdx +1 -1
- package/docs/tools/look.mdx +1 -1
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/network.mdx +13 -11
- package/docs/tools/overview.mdx +3 -3
- package/docs/tools/query.mdx +3 -3
- package/docs/tools/session-and-feedback.mdx +9 -6
- package/docs/tools/sessions.mdx +7 -0
- package/docs/tools/snapshot.mdx +9 -7
- package/docs/tools/tools-and-run.mdx +11 -10
- package/docs/tools/verify.mdx +1 -1
- package/docs/troubleshooting.mdx +21 -9
- package/docs/usage.md +58 -43
- package/docs/use-cases.mdx +2 -2
- package/docs/vs-chrome-devtools-mcp.mdx +5 -5
- package/docs/vs-playwright-mcp.mdx +5 -4
- package/docs/what-is-recorded.md +12 -7
- package/docs/what-is-reticle.mdx +2 -2
- package/docs/why-reticle.mdx +1 -1
- package/package.json +9 -12
- package/dist/command/dev/stale-issue-guard.d.ts +0 -34
- package/dist/command/dev/stale-issue-guard.js +0 -69
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
import { FlowErrorCode, ReticleDir, SYNC_BATCH_LIMITS, flowJsonReplacer } from '@reticlehq/core';
|
|
34
34
|
import { hashPayload } from './sync-hash.js';
|
|
35
35
|
import { syncScreenshots } from './sync-screenshots.js';
|
|
36
|
+
import { describeTransportError, problemsOf } from './sync-describe.js';
|
|
37
|
+
import { conflictOf, flowBases, versionsIn } from './sync-flow-versions.js';
|
|
38
|
+
import { asJson, flowName, isRecord, numberAt, numbersIn, partResult, } from './sync-answer.js';
|
|
39
|
+
export { FLOW_CONFLICT_CODE } from './sync-flow-versions.js';
|
|
36
40
|
/** The server's own doors. Kept beside the code that calls them, like the other cloud paths. */
|
|
37
41
|
const SYNC_PATH = '/v1/sync';
|
|
38
42
|
const SYNC_STATUS_PATH = '/v1/sync/status';
|
|
@@ -57,49 +61,19 @@ export const DERIVED_RECORDS = [
|
|
|
57
61
|
// The notes a human pinned in the HUD, pending and resolved: the review trail a team reads.
|
|
58
62
|
{ kind: 'notes', file: ReticleDir.NOTES_FILE },
|
|
59
63
|
];
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/** A list of numbers, or undefined when the server did not send a list at all. */
|
|
70
|
-
const numbersIn = (v) => Array.isArray(v) ? v.filter((n) => 'number' === typeof n) : undefined;
|
|
71
|
-
/** A numeric field of an artifact, or undefined when it has none. */
|
|
72
|
-
const numberAt = (v, field) => {
|
|
73
|
-
const n = isRecord(v) ? v[field] : undefined;
|
|
74
|
-
return 'number' === typeof n ? n : undefined;
|
|
75
|
-
};
|
|
76
|
-
/** The name a person knows a flow by, falling back to its position. */
|
|
77
|
-
const flowName = (flow, index) => {
|
|
78
|
-
const name = isRecord(flow) ? flow['name'] : undefined;
|
|
79
|
-
return 'string' === typeof name && name.length > 0 ? name : `flow #${String(index)}`;
|
|
80
|
-
};
|
|
64
|
+
/** A refusal older than this is offered again, whatever else is unchanged. */
|
|
65
|
+
export const REFUSAL_RETRY_AFTER_MS = 7 * 24 * 60 * 60 * 1000;
|
|
66
|
+
/** Does an earlier refusal still hold? An entry from before the stamp existed is asked once more. */
|
|
67
|
+
function refusalHolds(prior, now) {
|
|
68
|
+
return (prior.acceptsHash === now.acceptsHash &&
|
|
69
|
+
prior.version === now.version &&
|
|
70
|
+
'number' === typeof prior.at &&
|
|
71
|
+
now.at - prior.at < REFUSAL_RETRY_AFTER_MS);
|
|
72
|
+
}
|
|
81
73
|
const FLOW_VERSION_FIX = 'update the platform or remove `compare` from the flow';
|
|
82
74
|
const RUN_VERSION_FIX = 'update the platform';
|
|
83
|
-
/** The server's per-part answer: accepted count and rejection list, each read defensively. */
|
|
84
75
|
/** A 200 that never confirmed the runs it was sent. Kept queued, and said, rather than dropped. */
|
|
85
76
|
export const MSG_RUNS_UNCONFIRMED = 'sync 200 without a runs result: the server did not confirm the runs it was sent, so they stay queued';
|
|
86
|
-
function partResult(body, part) {
|
|
87
|
-
const raw = isRecord(body[part]) ? body[part] : {};
|
|
88
|
-
const accepted = 'number' === typeof raw['accepted'] ? raw['accepted'] : 0;
|
|
89
|
-
const rejected = (Array.isArray(raw['rejected']) ? raw['rejected'] : [])
|
|
90
|
-
.filter(isRecord)
|
|
91
|
-
.map((r) => ({
|
|
92
|
-
index: 'number' === typeof r['index'] ? r['index'] : -1,
|
|
93
|
-
reason: 'string' === typeof r['reason'] ? r['reason'] : 'no reason given',
|
|
94
|
-
code: r['code'],
|
|
95
|
-
version: r['version'],
|
|
96
|
-
}));
|
|
97
|
-
return { accepted, rejected };
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Split runs into requests bounded by count and by serialized size. A run bigger than the byte
|
|
101
|
-
* bound on its own still goes, alone: it cannot be split, and holding it back would hide it.
|
|
102
|
-
*/
|
|
103
77
|
/** The delivery record, kept only for the runs still on disk — the same bound as `sentRunIds`. */
|
|
104
78
|
function heldHashes(runs, recorded) {
|
|
105
79
|
const out = {};
|
|
@@ -110,6 +84,10 @@ function heldHashes(runs, recorded) {
|
|
|
110
84
|
}
|
|
111
85
|
return out;
|
|
112
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Split runs into requests bounded by count and by serialized size. A run bigger than the byte
|
|
89
|
+
* bound on its own still goes, alone: it cannot be split, and holding it back would hide it.
|
|
90
|
+
*/
|
|
113
91
|
function batchRuns(runs) {
|
|
114
92
|
const batches = [];
|
|
115
93
|
let current = [];
|
|
@@ -129,10 +107,6 @@ function batchRuns(runs) {
|
|
|
129
107
|
batches.push(current);
|
|
130
108
|
return batches;
|
|
131
109
|
}
|
|
132
|
-
/**
|
|
133
|
-
* Run one cycle. Never throws: the local record is already safe on disk, and a sync that can take
|
|
134
|
-
* down the thing it is backing up is worse than no sync.
|
|
135
|
-
*/
|
|
136
110
|
/** The command that moves a folder's earlier runs to the link it has now. */
|
|
137
111
|
export const MOVE_HISTORY_COMMAND = 'reticle sync --move-history';
|
|
138
112
|
/**
|
|
@@ -154,6 +128,10 @@ function stateForLink(deps) {
|
|
|
154
128
|
}
|
|
155
129
|
return { link, ...(true === deps.moveHistory ? {} : { linkedAt: deps.now() }) };
|
|
156
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Run one cycle. Never throws: the local record is already safe on disk, and a sync that can take
|
|
133
|
+
* down the thing it is backing up is worse than no sync.
|
|
134
|
+
*/
|
|
157
135
|
export async function runSyncCycle(given) {
|
|
158
136
|
const deps = { ...given, state: stateForLink(given) };
|
|
159
137
|
const empty = {
|
|
@@ -231,6 +209,11 @@ export async function runSyncCycle(given) {
|
|
|
231
209
|
// 2. SEND — only what the server does not already have, and only what it can read.
|
|
232
210
|
const allRuns = deps.source.runs();
|
|
233
211
|
const acceptsHash = hashPayload(held.accepts ?? null);
|
|
212
|
+
const stamp = {
|
|
213
|
+
acceptsHash,
|
|
214
|
+
...(deps.clientVersion === undefined ? {} : { version: deps.clientVersion }),
|
|
215
|
+
at: deps.now(),
|
|
216
|
+
};
|
|
234
217
|
const priorRefusals = isRecord(deps.state.refusedRuns) ? deps.state.refusedRuns : {};
|
|
235
218
|
const refusedRuns = {};
|
|
236
219
|
const notRetried = [];
|
|
@@ -253,7 +236,7 @@ export async function runSyncCycle(given) {
|
|
|
253
236
|
const prior = priorRefusals[run.runId];
|
|
254
237
|
const unchanged = prior !== undefined &&
|
|
255
238
|
'string' === typeof prior.reason &&
|
|
256
|
-
prior
|
|
239
|
+
refusalHolds(prior, stamp) &&
|
|
257
240
|
prior.payloadHash === hashPayload(run.payload);
|
|
258
241
|
if (!unchanged)
|
|
259
242
|
return true;
|
|
@@ -332,7 +315,19 @@ export async function runSyncCycle(given) {
|
|
|
332
315
|
return false;
|
|
333
316
|
});
|
|
334
317
|
const capsulesAll = deps.source.capsules();
|
|
335
|
-
const
|
|
318
|
+
const named = flows.map((flow, index) => ({ flow, name: flowName(flow, index) }));
|
|
319
|
+
const priorFlowHashes = {};
|
|
320
|
+
if (isRecord(deps.state.sentFlowHashes)) {
|
|
321
|
+
for (const [name, hash] of Object.entries(deps.state.sentFlowHashes))
|
|
322
|
+
if ('string' === typeof hash)
|
|
323
|
+
priorFlowHashes[name] = hash;
|
|
324
|
+
}
|
|
325
|
+
else if (deps.state.sentFlowsHash === hashPayload(flows))
|
|
326
|
+
for (const { flow, name } of named)
|
|
327
|
+
priorFlowHashes[name] = hashPayload(flow);
|
|
328
|
+
// Only the flows that changed since the platform last took them; the platform upserts by name.
|
|
329
|
+
const pendingFlows = named.filter(({ flow, name }) => priorFlowHashes[name] !== hashPayload(flow));
|
|
330
|
+
const flowsHash = hashPayload(pendingFlows.map(({ flow }) => flow));
|
|
336
331
|
const capsulesHash = hashPayload(capsulesAll);
|
|
337
332
|
const priorSets = isRecord(deps.state.refusedSets) ? deps.state.refusedSets : {};
|
|
338
333
|
const setsNotRetried = [];
|
|
@@ -343,7 +338,7 @@ export async function runSyncCycle(given) {
|
|
|
343
338
|
return false;
|
|
344
339
|
const prior = priorSets[part];
|
|
345
340
|
if (prior !== undefined && prior.hash === hash) {
|
|
346
|
-
if (prior
|
|
341
|
+
if (!refusalHolds(prior, stamp))
|
|
347
342
|
return true;
|
|
348
343
|
refusedSets[part] = prior;
|
|
349
344
|
setsNotRetried.push({ part, count: prior.count, reason: prior.reason });
|
|
@@ -351,10 +346,26 @@ export async function runSyncCycle(given) {
|
|
|
351
346
|
}
|
|
352
347
|
return hash !== sentHash;
|
|
353
348
|
};
|
|
354
|
-
const flowsChanged = due('flow', flowsHash,
|
|
349
|
+
const flowsChanged = due('flow', flowsHash, pendingFlows.length, undefined);
|
|
355
350
|
const capsulesChanged = due('capsule', capsulesHash, capsulesAll.length, deps.state.sentCapsulesHash);
|
|
356
|
-
|
|
357
|
-
|
|
351
|
+
// Each flow names the version it was based on; a stale base is answered with a conflict.
|
|
352
|
+
const priorVersions = versionsIn(deps.state.flowVersions);
|
|
353
|
+
const taken = {};
|
|
354
|
+
if (flowsChanged) {
|
|
355
|
+
bundle['flows'] = pendingFlows.map(({ flow }) => flow);
|
|
356
|
+
bundle['flowBases'] = flowBases(pendingFlows, priorVersions, priorFlowHashes);
|
|
357
|
+
}
|
|
358
|
+
const conflictCopies = [];
|
|
359
|
+
// What the platform holds from here once this cycle is answered: kept for the flows still here.
|
|
360
|
+
const flowHashes = {};
|
|
361
|
+
for (const { name } of named) {
|
|
362
|
+
const hash = priorFlowHashes[name];
|
|
363
|
+
if (hash !== undefined)
|
|
364
|
+
flowHashes[name] = hash;
|
|
365
|
+
const v = priorVersions[name];
|
|
366
|
+
if (v !== undefined)
|
|
367
|
+
taken[name] = v;
|
|
368
|
+
}
|
|
358
369
|
const capsules = capsulesChanged ? capsulesAll : [];
|
|
359
370
|
if (capsules.length > 0)
|
|
360
371
|
bundle['capsules'] = capsules;
|
|
@@ -406,7 +417,7 @@ export async function runSyncCycle(given) {
|
|
|
406
417
|
recorded[run.runId] = hashPayload(run.payload);
|
|
407
418
|
}
|
|
408
419
|
else
|
|
409
|
-
refusedRuns[run.runId] = { reason, payloadHash: hashPayload(run.payload),
|
|
420
|
+
refusedRuns[run.runId] = { reason, payloadHash: hashPayload(run.payload), ...stamp };
|
|
410
421
|
});
|
|
411
422
|
runsRejected.push(...runs.rejected.map((r) => ({ index: r.index + offset, reason: r.reason })));
|
|
412
423
|
offset += batch.length;
|
|
@@ -418,8 +429,33 @@ export async function runSyncCycle(given) {
|
|
|
418
429
|
const capsulesPart = partResult(answer, 'capsules');
|
|
419
430
|
flowsSent = flowsPart.accepted;
|
|
420
431
|
capsulesSent = capsulesPart.accepted;
|
|
432
|
+
const refusedFlows = new Set(flowsPart.rejected.map((r) => r.index));
|
|
433
|
+
const answered = isRecord(answer['flows']) ? answer['flows']['versions'] : undefined;
|
|
434
|
+
if (flowsChanged)
|
|
435
|
+
pendingFlows.forEach(({ flow, name }, index) => {
|
|
436
|
+
if (refusedFlows.has(index))
|
|
437
|
+
return;
|
|
438
|
+
flowHashes[name] = hashPayload(flow);
|
|
439
|
+
const v = isRecord(answered) ? answered[name] : undefined;
|
|
440
|
+
if ('string' === typeof v)
|
|
441
|
+
taken[name] = v;
|
|
442
|
+
});
|
|
443
|
+
// Another machine saved over the version this edit was based on: keep both, take theirs.
|
|
444
|
+
flowsPart.rejected = flowsPart.rejected.filter((r) => {
|
|
445
|
+
const name = pendingFlows[r.index]?.name;
|
|
446
|
+
const theirs = conflictOf(r);
|
|
447
|
+
if (name === undefined || theirs === undefined)
|
|
448
|
+
return true;
|
|
449
|
+
const copy = deps.sink.resolveFlowConflict?.(name, theirs.flow);
|
|
450
|
+
if (copy === undefined)
|
|
451
|
+
return true;
|
|
452
|
+
conflictCopies.push(copy);
|
|
453
|
+
flowHashes[name] = hashPayload(theirs.flow);
|
|
454
|
+
taken[name] = theirs.version;
|
|
455
|
+
return false;
|
|
456
|
+
});
|
|
421
457
|
for (const r of flowsPart.rejected) {
|
|
422
|
-
const name =
|
|
458
|
+
const name = pendingFlows[r.index]?.name ?? flowName(undefined, r.index);
|
|
423
459
|
refused.push({
|
|
424
460
|
part: 'flow',
|
|
425
461
|
reason: FlowErrorCode.WRONG_VERSION === r.code && 'number' === typeof r.version
|
|
@@ -433,14 +469,14 @@ export async function runSyncCycle(given) {
|
|
|
433
469
|
if (flowsPart.rejected.length > 0)
|
|
434
470
|
refusedSets.flow = {
|
|
435
471
|
hash: flowsHash,
|
|
436
|
-
|
|
472
|
+
...stamp,
|
|
437
473
|
count: flowsPart.rejected.length,
|
|
438
474
|
reason: firstOf('flow'),
|
|
439
475
|
};
|
|
440
476
|
if (capsulesPart.rejected.length > 0)
|
|
441
477
|
refusedSets.capsule = {
|
|
442
478
|
hash: capsulesHash,
|
|
443
|
-
|
|
479
|
+
...stamp,
|
|
444
480
|
count: capsulesPart.rejected.length,
|
|
445
481
|
reason: firstOf('capsule'),
|
|
446
482
|
};
|
|
@@ -474,12 +510,17 @@ export async function runSyncCycle(given) {
|
|
|
474
510
|
}
|
|
475
511
|
if (deps.projectId !== undefined)
|
|
476
512
|
nextState.sentFlowNames = kept;
|
|
513
|
+
// Every cycle, so a flow gone from here is forgotten too: saved again, it goes again.
|
|
514
|
+
nextState.sentFlowHashes = flowHashes;
|
|
515
|
+
nextState.flowVersions = taken;
|
|
516
|
+
// Open until the person deletes the copy (or merges it back): counted on every cycle till then.
|
|
517
|
+
const flowConflicts = [...(deps.state.flowConflicts ?? []), ...conflictCopies].filter((copy, i, all) => all.indexOf(copy) === i && (onDisk.has(copy) || conflictCopies.includes(copy)));
|
|
518
|
+
nextState.flowConflicts = flowConflicts;
|
|
519
|
+
delete nextState.sentFlowsHash;
|
|
477
520
|
if (requests > 0 && pushError === undefined) {
|
|
478
521
|
nextState.lastPushAt = deps.now();
|
|
479
522
|
// The platform answered for these sets, refusals included (reported above, and not re-offered
|
|
480
523
|
// until the set changes — the same rule as a refused run).
|
|
481
|
-
if (flowsChanged)
|
|
482
|
-
nextState.sentFlowsHash = flowsHash;
|
|
483
524
|
if (flowsChanged && deps.projectId !== undefined)
|
|
484
525
|
nextState.sentFlowNames = [...new Set([...kept, ...flows.map(flowName)])];
|
|
485
526
|
if (capsules.length > 0)
|
|
@@ -578,6 +619,7 @@ export async function runSyncCycle(given) {
|
|
|
578
619
|
...(0 === screenshotsSent ? {} : { screenshotsSent }),
|
|
579
620
|
runsRejected,
|
|
580
621
|
flowsSent,
|
|
622
|
+
...(0 === flowConflicts.length ? {} : { flowConflicts }),
|
|
581
623
|
capsulesSent,
|
|
582
624
|
derivedSent,
|
|
583
625
|
refused,
|
|
@@ -613,92 +655,3 @@ export async function runSyncCycle(given) {
|
|
|
613
655
|
return { ...empty, error: message };
|
|
614
656
|
}
|
|
615
657
|
}
|
|
616
|
-
/**
|
|
617
|
-
* Say WHICH host failed and WHY.
|
|
618
|
-
*
|
|
619
|
-
* Node's fetch rejects with the bare string "fetch failed" and hides the real reason — a refused
|
|
620
|
-
* connection, a bad hostname, an expired certificate — one level down in `cause`. A machine that
|
|
621
|
-
* has quietly stopped syncing shows that string in `reticle whoami`, and on its own it is
|
|
622
|
-
* indistinguishable from every other network problem, so the person reading it learns nothing and
|
|
623
|
-
* checks nothing. Naming the origin and the underlying code turns it into one thing to look at.
|
|
624
|
-
*/
|
|
625
|
-
function describeTransportError(error, url) {
|
|
626
|
-
if (!(error instanceof Error))
|
|
627
|
-
return String(error);
|
|
628
|
-
const cause = error.cause;
|
|
629
|
-
if (!(cause instanceof Error))
|
|
630
|
-
return `${error.message} (${url})`;
|
|
631
|
-
const code = cause.code;
|
|
632
|
-
// The code and the message are each sometimes empty — an aggregate DNS failure carries a code and
|
|
633
|
-
// no text, a TLS failure the reverse. Joined only when both are there, so the line never trails
|
|
634
|
-
// off into a dangling separator.
|
|
635
|
-
const parts = ['string' === typeof code && code.length > 0 ? code : '', cause.message].filter((part) => part.length > 0);
|
|
636
|
-
const detail = parts.join(': ');
|
|
637
|
-
return 0 === detail.length
|
|
638
|
-
? `${error.message} (${url})`
|
|
639
|
-
: `${error.message} — ${detail} (${url})`;
|
|
640
|
-
}
|
|
641
|
-
/** One line a human can read, for the CLI and the daemon log. */
|
|
642
|
-
export function describeSync(report) {
|
|
643
|
-
if (report.error !== undefined)
|
|
644
|
-
return `sync failed — ${report.error}`;
|
|
645
|
-
const sent = [];
|
|
646
|
-
if (report.runsSent > 0)
|
|
647
|
-
sent.push(`${String(report.runsSent)} run(s)`);
|
|
648
|
-
if (report.flowsSent > 0)
|
|
649
|
-
sent.push(`${String(report.flowsSent)} flow(s)`);
|
|
650
|
-
if (report.capsulesSent > 0)
|
|
651
|
-
sent.push(`${String(report.capsulesSent)} capsule(s)`);
|
|
652
|
-
if ((report.screenshotsSent ?? 0) > 0)
|
|
653
|
-
sent.push(`${String(report.screenshotsSent)} screenshot(s)`);
|
|
654
|
-
if (report.derivedSent.length > 0)
|
|
655
|
-
sent.push(report.derivedSent.join(', '));
|
|
656
|
-
/*
|
|
657
|
-
* "Nothing to send" is a statement about the QUEUE, and it is false the moment the queue was full
|
|
658
|
-
* and the server threw it away. Built from what was accepted, the sentence used to read "nothing
|
|
659
|
-
* to send, 3 rejected" — something was very much sent, and the reader is told both that it was
|
|
660
|
-
* not and nothing about why.
|
|
661
|
-
*/
|
|
662
|
-
const rejectedCount = report.runsRejected.length + report.refused.length;
|
|
663
|
-
const push = sent.length > 0
|
|
664
|
-
? `sent ${sent.join(' + ')}`
|
|
665
|
-
: rejectedCount > 0
|
|
666
|
-
? 'nothing accepted'
|
|
667
|
-
: true === report.localIsEmpty
|
|
668
|
-
? // Not the same statement as "nothing to send", which describes a repo that is simply up
|
|
669
|
-
// to date. This one has never recorded anything, which for a LINKED repo usually means
|
|
670
|
-
// the app announces no projectId and its runs are landing under a different root.
|
|
671
|
-
'nothing recorded here yet — if this app has been driven, it is reporting somewhere else'
|
|
672
|
-
: 'nothing to send';
|
|
673
|
-
const pull = 0 === report.pulled
|
|
674
|
-
? ''
|
|
675
|
-
: `, pulled ${String(report.pulled)} decision(s)${report.morePending ? ' (more waiting)' : ''}`;
|
|
676
|
-
return `${push}${pull}${problemsOf(report)
|
|
677
|
-
.map((problem) => `, ${problem}`)
|
|
678
|
-
.join('')}`;
|
|
679
|
-
}
|
|
680
|
-
/**
|
|
681
|
-
* What went wrong, one phrase per kind of problem.
|
|
682
|
-
*
|
|
683
|
-
* One reason, not a count. A rejection count tells somebody they have a problem and nothing about
|
|
684
|
-
* which problem — and these arrive from a BACKGROUND daemon, so the summary line is often the only
|
|
685
|
-
* place anybody ever sees it. Rejections in one cycle almost always share a cause (a version skew
|
|
686
|
-
* refuses every payload the same way), so the first reason plus the count is the whole story
|
|
687
|
-
* without printing a line per item; `reticle sync` still lists them all.
|
|
688
|
-
*/
|
|
689
|
-
function problemsOf(report) {
|
|
690
|
-
const problems = [];
|
|
691
|
-
const count = report.runsRejected.length + report.refused.length;
|
|
692
|
-
if (count > 0) {
|
|
693
|
-
const first = report.runsRejected[0]?.reason ?? report.refused[0]?.reason ?? 'no reason given';
|
|
694
|
-
problems.push(`${String(count)} rejected — ${first}`);
|
|
695
|
-
}
|
|
696
|
-
const firstRefusal = report.notRetried[0];
|
|
697
|
-
if (firstRefusal !== undefined)
|
|
698
|
-
problems.push(`refused, not retried: ${String(report.notRetried.length)} run(s) (${firstRefusal.reason})`);
|
|
699
|
-
for (const set of report.setsNotRetried)
|
|
700
|
-
problems.push(`refused, not retried: ${String(set.count)} ${set.part}(s) (${set.reason})`);
|
|
701
|
-
if (report.held.length > 0)
|
|
702
|
-
problems.push(`not sent: ${report.held.join('; ')}`);
|
|
703
|
-
return problems;
|
|
704
|
-
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type SyncReport } from './sync-cycle.js';
|
|
2
2
|
import { type ProjectCloud } from './cloud-config.js';
|
|
3
|
+
import { type FSWatcher } from 'node:fs';
|
|
4
|
+
import { BackgroundSyncState, type BackgroundSyncGate } from './background-sync.js';
|
|
3
5
|
import { type UnsyncedRoot } from './unsynced-roots.js';
|
|
4
6
|
import type { FileSystemPort } from '../project/fs/fs-port.js';
|
|
5
7
|
interface SyncDaemonDeps {
|
|
@@ -20,12 +22,15 @@ interface SyncDaemonDeps {
|
|
|
20
22
|
/** Resolve the link for a root that is not this daemon's own. Required to use `otherRoots`. */
|
|
21
23
|
cloudFor?: (root: string) => Promise<ProjectCloud>;
|
|
22
24
|
now?: () => number;
|
|
25
|
+
/** This CLI's version, stamped on each refusal so a new one asks the platform again. */
|
|
26
|
+
clientVersion?: string;
|
|
23
27
|
intervalMs?: number;
|
|
24
28
|
/**
|
|
25
|
-
* Call `onChange`
|
|
26
|
-
*
|
|
29
|
+
* Call `onChange` with the path (relative to the root) of anything that changes under it; returns
|
|
30
|
+
* how to stop, or undefined when the root cannot be watched YET (it does not exist), in which case
|
|
31
|
+
* the daemon tries again after each cycle. A re-link is one of these changes.
|
|
27
32
|
*/
|
|
28
|
-
|
|
33
|
+
watch?: (onChange: (path: string) => void) => (() => void) | undefined;
|
|
29
34
|
/** Injected for the test; the real one is `fetch`. */
|
|
30
35
|
request?: (url: string, init: {
|
|
31
36
|
method: string;
|
|
@@ -34,7 +39,22 @@ interface SyncDaemonDeps {
|
|
|
34
39
|
}) => Promise<{
|
|
35
40
|
status: number;
|
|
36
41
|
text: string;
|
|
42
|
+
etag?: string;
|
|
37
43
|
}>;
|
|
44
|
+
/**
|
|
45
|
+
* May this root's work be sent now (opt-outs, link, sign-in)? Asked for every root on every tick.
|
|
46
|
+
* Absent: every resolved link may send, which is how `startSyncDaemon` behaved before.
|
|
47
|
+
*/
|
|
48
|
+
gate?: (root: string, cloud: ProjectCloud) => BackgroundSyncGate;
|
|
49
|
+
}
|
|
50
|
+
/** Where the background sync of the daemon's own project stands, for `doctor` and the tests. */
|
|
51
|
+
export interface BackgroundSyncReport {
|
|
52
|
+
state: BackgroundSyncState;
|
|
53
|
+
why: string;
|
|
54
|
+
/** Network failures in a row; the backoff grows with it. */
|
|
55
|
+
failures: number;
|
|
56
|
+
lastError?: string;
|
|
57
|
+
lastPushAt?: number;
|
|
38
58
|
}
|
|
39
59
|
export interface SyncDaemon {
|
|
40
60
|
/** Run one cycle now, whatever the timer is doing. Returns undefined when not linked. */
|
|
@@ -69,12 +89,22 @@ export interface SyncDaemon {
|
|
|
69
89
|
* or not. An unlinked one is the case nothing will ever send, and it used to be skipped silently.
|
|
70
90
|
*/
|
|
71
91
|
unsyncedRoots: () => readonly UnsyncedRoot[];
|
|
92
|
+
/** Where the background sync of this daemon's own root stands. */
|
|
93
|
+
background: () => BackgroundSyncReport;
|
|
72
94
|
}
|
|
73
95
|
/**
|
|
74
96
|
* Start the loop. Safe to call for an UNLINKED project: it resolves the link on every tick and does
|
|
75
97
|
* nothing until one appears, which is what lets `reticle link` take effect without a restart.
|
|
76
98
|
*/
|
|
77
99
|
export declare function startSyncDaemon(deps: SyncDaemonDeps): SyncDaemon;
|
|
100
|
+
/**
|
|
101
|
+
* Flush, but return after `budgetMs` at the latest, and never throw.
|
|
102
|
+
*
|
|
103
|
+
* For a process on its way out. The cycle has per-call timeouts, but a stalled network still adds
|
|
104
|
+
* them up, and an exit must not wait on that. A cycle cut short loses nothing: the artifacts stay
|
|
105
|
+
* on disk, and the next daemon or `reticle sync` sends them.
|
|
106
|
+
*/
|
|
107
|
+
export declare function flushWithin(daemon: Pick<SyncDaemon, 'flush'>, budgetMs: number): Promise<void>;
|
|
78
108
|
/**
|
|
79
109
|
* Start cloud sync for a daemon and hand back the two hooks the daemon wires to it.
|
|
80
110
|
*
|
|
@@ -93,5 +123,22 @@ export declare function attachCloudSync(deps: {
|
|
|
93
123
|
homeDir: string;
|
|
94
124
|
env: NodeJS.ProcessEnv;
|
|
95
125
|
otherRoots: () => readonly string[];
|
|
126
|
+
clientVersion: string;
|
|
127
|
+
/**
|
|
128
|
+
* The signed-in session's token for a platform address, or undefined. See `signedInTo`. Given by
|
|
129
|
+
* the background daemon only: `start()`'s one cycle on close also serves CI, keyed by the env.
|
|
130
|
+
*/
|
|
131
|
+
signedIn?: (url: string) => string | undefined;
|
|
132
|
+
/** Injected for the tests. */
|
|
133
|
+
request?: SyncDaemonDeps['request'];
|
|
134
|
+
intervalMs?: number;
|
|
96
135
|
}): SyncDaemon;
|
|
136
|
+
/**
|
|
137
|
+
* Watch a whole `.reticle` root, reporting each change by its path under the root.
|
|
138
|
+
*
|
|
139
|
+
* Returns undefined only when the root does not exist yet, so the caller tries again later. Where a
|
|
140
|
+
* recursive watch is unsupported (an old Node on Linux, a network filesystem) or fails later (too
|
|
141
|
+
* many files), it says so ONCE and returns a no-op: the backstop timer is the whole sync from then on.
|
|
142
|
+
*/
|
|
143
|
+
export declare function watchReticleRoot(reticleRoot: string, onChange: (path: string) => void, watchFn?: (root: string, listener: (event: string, name: string | null) => void) => FSWatcher): (() => void) | undefined;
|
|
97
144
|
export {};
|