@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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a sync cycle says about itself: one line for the CLI and the daemon log, and the failure a
|
|
3
|
+
* person reads in `reticle whoami`. Kept beside the cycle, apart from it, because the cycle is the
|
|
4
|
+
* protocol and this is only how it is reported.
|
|
5
|
+
*/
|
|
6
|
+
import type { SyncReport } from './sync-cycle.js';
|
|
7
|
+
/**
|
|
8
|
+
* Say WHICH host failed and WHY.
|
|
9
|
+
*
|
|
10
|
+
* Node's fetch rejects with the bare string "fetch failed" and hides the real reason — a refused
|
|
11
|
+
* connection, a bad hostname, an expired certificate — one level down in `cause`. A machine that
|
|
12
|
+
* has quietly stopped syncing shows that string in `reticle whoami`, and on its own it is
|
|
13
|
+
* indistinguishable from every other network problem, so the person reading it learns nothing and
|
|
14
|
+
* checks nothing. Naming the origin and the underlying code turns it into one thing to look at.
|
|
15
|
+
*/
|
|
16
|
+
export declare function describeTransportError(error: unknown, url: string): string;
|
|
17
|
+
/** One line a human can read, for the CLI and the daemon log. */
|
|
18
|
+
export declare function describeSync(report: SyncReport): string;
|
|
19
|
+
/**
|
|
20
|
+
* What went wrong, one phrase per kind of problem.
|
|
21
|
+
*
|
|
22
|
+
* One reason, not a count. A rejection count tells somebody they have a problem and nothing about
|
|
23
|
+
* which problem — and these arrive from a BACKGROUND daemon, so the summary line is often the only
|
|
24
|
+
* place anybody ever sees it. Rejections in one cycle almost always share a cause (a version skew
|
|
25
|
+
* refuses every payload the same way), so the first reason plus the count is the whole story
|
|
26
|
+
* without printing a line per item; `reticle sync` still lists them all.
|
|
27
|
+
*/
|
|
28
|
+
export declare function problemsOf(report: SyncReport): string[];
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Say WHICH host failed and WHY.
|
|
3
|
+
*
|
|
4
|
+
* Node's fetch rejects with the bare string "fetch failed" and hides the real reason — a refused
|
|
5
|
+
* connection, a bad hostname, an expired certificate — one level down in `cause`. A machine that
|
|
6
|
+
* has quietly stopped syncing shows that string in `reticle whoami`, and on its own it is
|
|
7
|
+
* indistinguishable from every other network problem, so the person reading it learns nothing and
|
|
8
|
+
* checks nothing. Naming the origin and the underlying code turns it into one thing to look at.
|
|
9
|
+
*/
|
|
10
|
+
export function describeTransportError(error, url) {
|
|
11
|
+
if (!(error instanceof Error))
|
|
12
|
+
return String(error);
|
|
13
|
+
const cause = error.cause;
|
|
14
|
+
if (!(cause instanceof Error))
|
|
15
|
+
return `${error.message} (${url})`;
|
|
16
|
+
const code = cause.code;
|
|
17
|
+
// The code and the message are each sometimes empty — an aggregate DNS failure carries a code and
|
|
18
|
+
// no text, a TLS failure the reverse. Joined only when both are there, so the line never trails
|
|
19
|
+
// off into a dangling separator.
|
|
20
|
+
const parts = ['string' === typeof code && code.length > 0 ? code : '', cause.message].filter((part) => part.length > 0);
|
|
21
|
+
const detail = parts.join(': ');
|
|
22
|
+
return 0 === detail.length
|
|
23
|
+
? `${error.message} (${url})`
|
|
24
|
+
: `${error.message} — ${detail} (${url})`;
|
|
25
|
+
}
|
|
26
|
+
/** One line a human can read, for the CLI and the daemon log. */
|
|
27
|
+
export function describeSync(report) {
|
|
28
|
+
if (report.error !== undefined)
|
|
29
|
+
return `sync failed — ${report.error}`;
|
|
30
|
+
const sent = [];
|
|
31
|
+
if (report.runsSent > 0)
|
|
32
|
+
sent.push(`${String(report.runsSent)} run(s)`);
|
|
33
|
+
if (report.flowsSent > 0)
|
|
34
|
+
sent.push(`${String(report.flowsSent)} flow(s)`);
|
|
35
|
+
if (report.capsulesSent > 0)
|
|
36
|
+
sent.push(`${String(report.capsulesSent)} capsule(s)`);
|
|
37
|
+
if ((report.screenshotsSent ?? 0) > 0)
|
|
38
|
+
sent.push(`${String(report.screenshotsSent)} screenshot(s)`);
|
|
39
|
+
if (report.derivedSent.length > 0)
|
|
40
|
+
sent.push(report.derivedSent.join(', '));
|
|
41
|
+
/*
|
|
42
|
+
* "Nothing to send" is a statement about the QUEUE, and it is false the moment the queue was full
|
|
43
|
+
* and the server threw it away. Built from what was accepted, the sentence used to read "nothing
|
|
44
|
+
* to send, 3 rejected" — something was very much sent, and the reader is told both that it was
|
|
45
|
+
* not and nothing about why.
|
|
46
|
+
*/
|
|
47
|
+
const rejectedCount = report.runsRejected.length + report.refused.length;
|
|
48
|
+
const push = sent.length > 0
|
|
49
|
+
? `sent ${sent.join(' + ')}`
|
|
50
|
+
: rejectedCount > 0
|
|
51
|
+
? 'nothing accepted'
|
|
52
|
+
: true === report.localIsEmpty
|
|
53
|
+
? // Not the same statement as "nothing to send", which describes a repo that is simply up
|
|
54
|
+
// to date. This one has never recorded anything, which for a LINKED repo usually means
|
|
55
|
+
// the app announces no projectId and its runs are landing under a different root.
|
|
56
|
+
'nothing recorded here yet — if this app has been driven, it is reporting somewhere else'
|
|
57
|
+
: 'nothing to send';
|
|
58
|
+
const pull = 0 === report.pulled
|
|
59
|
+
? ''
|
|
60
|
+
: `, pulled ${String(report.pulled)} decision(s)${report.morePending ? ' (more waiting)' : ''}`;
|
|
61
|
+
return `${push}${pull}${problemsOf(report)
|
|
62
|
+
.map((problem) => `, ${problem}`)
|
|
63
|
+
.join('')}`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* What went wrong, one phrase per kind of problem.
|
|
67
|
+
*
|
|
68
|
+
* One reason, not a count. A rejection count tells somebody they have a problem and nothing about
|
|
69
|
+
* which problem — and these arrive from a BACKGROUND daemon, so the summary line is often the only
|
|
70
|
+
* place anybody ever sees it. Rejections in one cycle almost always share a cause (a version skew
|
|
71
|
+
* refuses every payload the same way), so the first reason plus the count is the whole story
|
|
72
|
+
* without printing a line per item; `reticle sync` still lists them all.
|
|
73
|
+
*/
|
|
74
|
+
export function problemsOf(report) {
|
|
75
|
+
const problems = [];
|
|
76
|
+
const count = report.runsRejected.length + report.refused.length;
|
|
77
|
+
if (count > 0) {
|
|
78
|
+
const first = report.runsRejected[0]?.reason ?? report.refused[0]?.reason ?? 'no reason given';
|
|
79
|
+
problems.push(`${String(count)} rejected — ${first}`);
|
|
80
|
+
}
|
|
81
|
+
const firstRefusal = report.notRetried[0];
|
|
82
|
+
if (firstRefusal !== undefined)
|
|
83
|
+
problems.push(`refused, not retried: ${String(report.notRetried.length)} run(s) (${firstRefusal.reason})`);
|
|
84
|
+
for (const set of report.setsNotRetried)
|
|
85
|
+
problems.push(`refused, not retried: ${String(set.count)} ${set.part}(s) (${set.reason})`);
|
|
86
|
+
if (report.held.length > 0)
|
|
87
|
+
problems.push(`not sent: ${report.held.join('; ')}`);
|
|
88
|
+
const copies = report.flowConflicts ?? [];
|
|
89
|
+
if (copies.length > 0)
|
|
90
|
+
problems.push(`${String(copies.length)} flow conflict(s): another machine saved first, so this edit is kept as ${copies.join(', ')}; merge or delete it`);
|
|
91
|
+
return problems;
|
|
92
|
+
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { type CloudSyncState, type PulledIssues, type SyncSink, type SyncSource } from './sync-cycle.js';
|
|
2
2
|
/** What the cycle reads, backed by a real `.reticle` directory. */
|
|
3
|
-
export declare function diskSource(reticleRoot: string): SyncSource;
|
|
3
|
+
export declare function diskSource(reticleRoot: string, env?: NodeJS.ProcessEnv): SyncSource;
|
|
4
|
+
/**
|
|
5
|
+
* The screenshot reader a sync policy allows: none with `screenshots` off, and none for a frame with
|
|
6
|
+
* `video` off. A frame held back this way is offered again each cycle, so turning video on sends it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function policyScreenshots(read: SyncSource['screenshot'], policy: {
|
|
9
|
+
screenshots: boolean;
|
|
10
|
+
video: boolean;
|
|
11
|
+
}): Pick<SyncSource, 'screenshot'>;
|
|
4
12
|
/** What the cycle writes back into `.reticle/`. */
|
|
5
13
|
export declare function diskSink(reticleRoot: string): SyncSink;
|
|
6
14
|
/** This machine's side of the conversation, or a blank one on first run. */
|
|
@@ -11,10 +11,12 @@
|
|
|
11
11
|
* error — the file will be rewritten on the next tool call anyway.
|
|
12
12
|
*/
|
|
13
13
|
import { shareableRun } from '@reticlehq/core/artifacts';
|
|
14
|
+
import { agentContextFor } from '../journal/episode-log.js';
|
|
15
|
+
import { agentCaptureOff, agentCaptureOffIn, sharesRequests, } from '../intent/record-request.js';
|
|
14
16
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, } from 'node:fs';
|
|
15
17
|
import { basename, dirname, join } from 'node:path';
|
|
16
18
|
import { stepShotDir } from '../project/dir/reticle-dir.js';
|
|
17
|
-
import { IntentDir, ReticleDir } from '@reticlehq/core';
|
|
19
|
+
import { IntentDir, ReticleDir, STEP_SCREENSHOT } from '@reticlehq/core';
|
|
18
20
|
import { DERIVED_RECORDS, } from './sync-cycle.js';
|
|
19
21
|
import { subjectFor } from '../intent/intent-subject.js';
|
|
20
22
|
const JSON_SUFFIX = '.json';
|
|
@@ -47,8 +49,9 @@ function writeJson(path, value) {
|
|
|
47
49
|
/** Every `*.json` directly inside a directory, parsed. Absent directory reads as empty. */
|
|
48
50
|
function readJsonDir(dir) {
|
|
49
51
|
try {
|
|
50
|
-
if (!existsSync(dir))
|
|
52
|
+
if (!existsSync(dir)) {
|
|
51
53
|
return [];
|
|
54
|
+
}
|
|
52
55
|
return readdirSync(dir)
|
|
53
56
|
.filter((f) => f.endsWith(JSON_SUFFIX))
|
|
54
57
|
.map((f) => readJson(join(dir, f)))
|
|
@@ -62,25 +65,52 @@ function readJsonDir(dir) {
|
|
|
62
65
|
* Flows: one directory deeper under the app's own project id, and also flat in `.reticle/flows/`,
|
|
63
66
|
* which the flow store still saves and loads (a flow saved with no project id, or from before flows
|
|
64
67
|
* were kept per project). Reading only the subfolders skipped every flat flow while the cycle
|
|
65
|
-
* reported ok.
|
|
68
|
+
* reported ok. At any depth: a namespaced name (`onboarding/signup`) is a folder of its own, and
|
|
69
|
+
* reading one level down left every such flow on the machine.
|
|
66
70
|
*/
|
|
67
|
-
function
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
function readFlowFiles(root) {
|
|
72
|
+
const walk = (dir) => {
|
|
73
|
+
try {
|
|
74
|
+
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
|
75
|
+
const path = join(dir, entry.name);
|
|
76
|
+
if (entry.isDirectory()) {
|
|
77
|
+
return walk(path);
|
|
78
|
+
}
|
|
79
|
+
if (!entry.name.endsWith(JSON_SUFFIX)) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
const flow = readJson(path);
|
|
83
|
+
return flow === undefined ? [] : [{ path, flow }];
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
71
87
|
return [];
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
return walk(join(root, ReticleDir.FLOWS_SUBDIR));
|
|
91
|
+
}
|
|
92
|
+
const readFlows = (root) => readFlowFiles(root).map(({ flow }) => flow);
|
|
93
|
+
/**
|
|
94
|
+
* Keep this machine's edit of `name` as `<name>-conflict-<n>` in a file beside it, and write the
|
|
95
|
+
* platform's version in its place. Answers the copy's name, or undefined when the flow is not here.
|
|
96
|
+
*/
|
|
97
|
+
function keepConflictCopy(root, name, theirs) {
|
|
98
|
+
const held = readFlowFiles(root).find(({ flow }) => 'object' === typeof flow && null !== flow && flow.name === name);
|
|
99
|
+
if (held === undefined || 'object' !== typeof theirs || null === theirs) {
|
|
100
|
+
return undefined;
|
|
80
101
|
}
|
|
81
|
-
|
|
82
|
-
|
|
102
|
+
const stem = held.path.slice(0, -JSON_SUFFIX.length);
|
|
103
|
+
let n = 1;
|
|
104
|
+
while (existsSync(`${stem}-conflict-${String(n)}${JSON_SUFFIX}`)) {
|
|
105
|
+
n += 1;
|
|
83
106
|
}
|
|
107
|
+
const copy = `${name}-conflict-${String(n)}`;
|
|
108
|
+
writeJson(`${stem}-conflict-${String(n)}${JSON_SUFFIX}`, {
|
|
109
|
+
...held.flow,
|
|
110
|
+
name: copy,
|
|
111
|
+
});
|
|
112
|
+
writeJson(held.path, theirs);
|
|
113
|
+
return copy;
|
|
84
114
|
}
|
|
85
115
|
const DERIVED_FILE = Object.fromEntries(DERIVED_RECORDS.map((record) => [record.kind, record.file]));
|
|
86
116
|
/** The directory the sharded intent store writes into, beside the legacy flat file. */
|
|
@@ -112,8 +142,9 @@ function readIntent(reticleRoot) {
|
|
|
112
142
|
};
|
|
113
143
|
let shards = 0;
|
|
114
144
|
for (const entry of safeReaddir(join(reticleRoot, INTENT_SUBDIR))) {
|
|
115
|
-
if (INTENT_INDEX === entry)
|
|
145
|
+
if (INTENT_INDEX === entry) {
|
|
116
146
|
continue;
|
|
147
|
+
}
|
|
117
148
|
// `<subject>/intent.json` is the layout; a bare `<subject>.json` is an interim shard the store
|
|
118
149
|
// has not migrated yet, and is still this project's memory until it has.
|
|
119
150
|
const path = entry.endsWith(JSON_SUFFIX)
|
|
@@ -121,14 +152,17 @@ function readIntent(reticleRoot) {
|
|
|
121
152
|
: join(reticleRoot, INTENT_SUBDIR, entry, IntentDir.SHARD_FILE);
|
|
122
153
|
const shard = readJson(path);
|
|
123
154
|
// A hand-edited or half-written shard costs one subject, never the whole sync.
|
|
124
|
-
if (shard?.intents === undefined)
|
|
155
|
+
if (shard?.intents === undefined) {
|
|
125
156
|
continue;
|
|
157
|
+
}
|
|
126
158
|
shards++;
|
|
127
|
-
for (const [id, record] of Object.entries(shard.intents))
|
|
159
|
+
for (const [id, record] of Object.entries(shard.intents)) {
|
|
128
160
|
merged[id] = record;
|
|
161
|
+
}
|
|
129
162
|
}
|
|
130
|
-
if (legacy === undefined && 0 === shards)
|
|
163
|
+
if (legacy === undefined && 0 === shards) {
|
|
131
164
|
return undefined;
|
|
165
|
+
}
|
|
132
166
|
/*
|
|
133
167
|
* Stamp the SUBJECT before sending, on anything that does not already carry one.
|
|
134
168
|
*
|
|
@@ -153,8 +187,9 @@ function readIntent(reticleRoot) {
|
|
|
153
187
|
...('string' === typeof run && 0 < run.length ? { provedBy: run } : {}),
|
|
154
188
|
};
|
|
155
189
|
const held = record;
|
|
156
|
-
if ('string' === typeof held.subject && held.subject.length > 0)
|
|
190
|
+
if ('string' === typeof held.subject && held.subject.length > 0) {
|
|
157
191
|
return [id, record];
|
|
192
|
+
}
|
|
158
193
|
const subject = subjectFor({
|
|
159
194
|
surface: held.surface,
|
|
160
195
|
binding: held.binding,
|
|
@@ -172,18 +207,68 @@ function safeReaddir(dir) {
|
|
|
172
207
|
return [];
|
|
173
208
|
}
|
|
174
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* A run with the agent's model and the claim that closed its turn, from the agent hooks' records
|
|
212
|
+
* (see `agentContextFor`). Filled only where the run says nothing. The claim goes into the prompt
|
|
213
|
+
* context, so it leaves the machine under the same share decision as the request: a context the
|
|
214
|
+
* run did not have takes the project's setting.
|
|
215
|
+
*/
|
|
216
|
+
function withAgentContext(payload, reticleRoot) {
|
|
217
|
+
if ('object' !== typeof payload || null === payload) {
|
|
218
|
+
return payload;
|
|
219
|
+
}
|
|
220
|
+
const run = payload;
|
|
221
|
+
const found = agentContextFor(reticleRoot, run);
|
|
222
|
+
let out = { ...run };
|
|
223
|
+
if (found.model !== undefined && run.agent !== undefined && run.agent.model === undefined) {
|
|
224
|
+
out = { ...out, agent: { ...run.agent, model: found.model } };
|
|
225
|
+
}
|
|
226
|
+
if (found.claim !== undefined && run.context?.closingClaim === undefined) {
|
|
227
|
+
const shared = 'boolean' === typeof run.context?.shared
|
|
228
|
+
? run.context.shared
|
|
229
|
+
: sharesRequests(dirname(reticleRoot), reticleRoot);
|
|
230
|
+
out = {
|
|
231
|
+
...out,
|
|
232
|
+
context: {
|
|
233
|
+
statements: [],
|
|
234
|
+
...run.context,
|
|
235
|
+
closingClaim: found.claim.text,
|
|
236
|
+
closingClaimAt: found.claim.at,
|
|
237
|
+
shared,
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return out;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* A run with nothing the agent hooks kept: no prompt context. Agent capture is off, so the files
|
|
245
|
+
* that the hooks wrote before the switch went off do not leave the machine either.
|
|
246
|
+
*/
|
|
247
|
+
function withoutAgentCapture(payload) {
|
|
248
|
+
if ('object' !== typeof payload || null === payload) {
|
|
249
|
+
return payload;
|
|
250
|
+
}
|
|
251
|
+
const { context: _context, ...rest } = payload;
|
|
252
|
+
return rest;
|
|
253
|
+
}
|
|
175
254
|
/** What the cycle reads, backed by a real `.reticle` directory. */
|
|
176
|
-
export function diskSource(reticleRoot) {
|
|
255
|
+
export function diskSource(reticleRoot, env = process.env) {
|
|
177
256
|
return {
|
|
178
|
-
runs: () =>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
257
|
+
runs: () => {
|
|
258
|
+
const captureOff = agentCaptureOff(env) || agentCaptureOffIn(dirname(reticleRoot));
|
|
259
|
+
return (readJsonDir(join(reticleRoot, ReticleDir.RUNS_SUBDIR))
|
|
260
|
+
.map((payload) => {
|
|
261
|
+
const id = payload?.runId;
|
|
262
|
+
// The prompt context leaves the machine only when the project opted in.
|
|
263
|
+
const sent = captureOff
|
|
264
|
+
? withoutAgentCapture(payload)
|
|
265
|
+
: shareableRun(withAgentContext(payload, reticleRoot));
|
|
266
|
+
return 'string' === typeof id ? { runId: id, payload: sent } : undefined;
|
|
267
|
+
})
|
|
268
|
+
// A run artifact with no id cannot be diffed against the server's list, so sending it
|
|
269
|
+
// would mean re-sending it every cycle forever. Dropped rather than uploaded repeatedly.
|
|
270
|
+
.filter((r) => r !== undefined));
|
|
271
|
+
},
|
|
187
272
|
flows: () => readFlows(reticleRoot),
|
|
188
273
|
// Flat directory of `<id>.json`, which is exactly what readJsonDir walks — unlike flows, which
|
|
189
274
|
// sit one level deeper under the app's project id.
|
|
@@ -194,8 +279,9 @@ export function diskSource(reticleRoot) {
|
|
|
194
279
|
// own directory before it is read.
|
|
195
280
|
screenshot: (runId, file) => {
|
|
196
281
|
try {
|
|
197
|
-
if (basename(file) !== file)
|
|
282
|
+
if (basename(file) !== file) {
|
|
198
283
|
return undefined;
|
|
284
|
+
}
|
|
199
285
|
return new Uint8Array(readFileSync(join(stepShotDir(reticleRoot, runId), file)));
|
|
200
286
|
}
|
|
201
287
|
catch {
|
|
@@ -204,6 +290,23 @@ export function diskSource(reticleRoot) {
|
|
|
204
290
|
},
|
|
205
291
|
};
|
|
206
292
|
}
|
|
293
|
+
/** A frame's file name ends in its tool: `<seq>-frame.jpg`. */
|
|
294
|
+
const FRAME_FILE_SUFFIX = `-${STEP_SCREENSHOT.FRAME_TOOL}.jpg`;
|
|
295
|
+
/**
|
|
296
|
+
* The screenshot reader a sync policy allows: none with `screenshots` off, and none for a frame with
|
|
297
|
+
* `video` off. A frame held back this way is offered again each cycle, so turning video on sends it.
|
|
298
|
+
*/
|
|
299
|
+
export function policyScreenshots(read, policy) {
|
|
300
|
+
if (!policy.screenshots || read === undefined) {
|
|
301
|
+
return {};
|
|
302
|
+
}
|
|
303
|
+
if (policy.video) {
|
|
304
|
+
return { screenshot: read };
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
screenshot: (runId, file) => (file.endsWith(FRAME_FILE_SUFFIX) ? undefined : read(runId, file)),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
207
310
|
/** What the cycle writes back into `.reticle/`. */
|
|
208
311
|
export function diskSink(reticleRoot) {
|
|
209
312
|
return {
|
|
@@ -218,6 +321,7 @@ export function diskSink(reticleRoot) {
|
|
|
218
321
|
writeState: (state) => {
|
|
219
322
|
writeJson(join(reticleRoot, ReticleDir.CLOUD_STATE_FILE), state);
|
|
220
323
|
},
|
|
324
|
+
resolveFlowConflict: (name, theirs) => keepConflictCopy(reticleRoot, name, theirs),
|
|
221
325
|
};
|
|
222
326
|
}
|
|
223
327
|
/** This machine's side of the conversation, or a blank one on first run. */
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare-and-set for flows. Each pushed flow names the platform version it was based on; a push based
|
|
3
|
+
* on a version another machine has since replaced comes back as a conflict carrying the platform's
|
|
4
|
+
* version. This machine then keeps its own edit as a named copy beside the flow and takes the
|
|
5
|
+
* platform's, so nothing is lost and nothing diverges silently. Kept apart from the cycle, which is the
|
|
6
|
+
* protocol; this is the one rule about flow versions.
|
|
7
|
+
*/
|
|
8
|
+
/** The platform's code for a flow pushed on a version it no longer holds (its HTTP 409). */
|
|
9
|
+
export declare const FLOW_CONFLICT_CODE = "conflict";
|
|
10
|
+
/** Versions by name, as kept in the state: only strings count. */
|
|
11
|
+
export declare function versionsIn(value: unknown): Record<string, string>;
|
|
12
|
+
/**
|
|
13
|
+
* What each pending flow was based on: the version last taken here; null for a flow this machine never
|
|
14
|
+
* sent; nothing for one an older client sent without a version (stored unconditionally, as it was).
|
|
15
|
+
*/
|
|
16
|
+
export declare function flowBases(pending: ReadonlyArray<{
|
|
17
|
+
name: string;
|
|
18
|
+
}>, versions: Record<string, string>, sentHashes: Record<string, string>): Record<string, string | null>;
|
|
19
|
+
/** A refusal that is a conflict this machine can settle, with the platform's version. */
|
|
20
|
+
export declare function conflictOf(r: {
|
|
21
|
+
code: unknown;
|
|
22
|
+
current: unknown;
|
|
23
|
+
}): {
|
|
24
|
+
version: string;
|
|
25
|
+
flow: unknown;
|
|
26
|
+
} | undefined;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare-and-set for flows. Each pushed flow names the platform version it was based on; a push based
|
|
3
|
+
* on a version another machine has since replaced comes back as a conflict carrying the platform's
|
|
4
|
+
* version. This machine then keeps its own edit as a named copy beside the flow and takes the
|
|
5
|
+
* platform's, so nothing is lost and nothing diverges silently. Kept apart from the cycle, which is the
|
|
6
|
+
* protocol; this is the one rule about flow versions.
|
|
7
|
+
*/
|
|
8
|
+
/** The platform's code for a flow pushed on a version it no longer holds (its HTTP 409). */
|
|
9
|
+
export const FLOW_CONFLICT_CODE = 'conflict';
|
|
10
|
+
const isRecord = (v) => 'object' === typeof v && null !== v;
|
|
11
|
+
/** Versions by name, as kept in the state: only strings count. */
|
|
12
|
+
export function versionsIn(value) {
|
|
13
|
+
const out = {};
|
|
14
|
+
if (isRecord(value))
|
|
15
|
+
for (const [name, v] of Object.entries(value))
|
|
16
|
+
if ('string' === typeof v)
|
|
17
|
+
out[name] = v;
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* What each pending flow was based on: the version last taken here; null for a flow this machine never
|
|
22
|
+
* sent; nothing for one an older client sent without a version (stored unconditionally, as it was).
|
|
23
|
+
*/
|
|
24
|
+
export function flowBases(pending, versions, sentHashes) {
|
|
25
|
+
const out = {};
|
|
26
|
+
for (const { name } of pending) {
|
|
27
|
+
const v = versions[name];
|
|
28
|
+
if (v !== undefined)
|
|
29
|
+
out[name] = v;
|
|
30
|
+
else if (sentHashes[name] === undefined)
|
|
31
|
+
out[name] = null;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/** A refusal that is a conflict this machine can settle, with the platform's version. */
|
|
36
|
+
export function conflictOf(r) {
|
|
37
|
+
const current = isRecord(r.current) ? r.current : undefined;
|
|
38
|
+
const version = current?.['version'];
|
|
39
|
+
return FLOW_CONFLICT_CODE === r.code && 'string' === typeof version
|
|
40
|
+
? { version, flow: current?.['flow'] }
|
|
41
|
+
: undefined;
|
|
42
|
+
}
|
|
@@ -2,6 +2,7 @@ import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import { SyncStatus, dashboardRunUrl, describeSync, keyRefusalAtLastSync, overallStatus, readSyncSummary, } from '../project/sync-status.js';
|
|
3
3
|
import { describeUnsynced, unsentFlowCount, unsentRunCount, } from '../cloud/unsynced-roots.js';
|
|
4
4
|
import { readDashboardUrl } from '../project/sync-status.js';
|
|
5
|
+
import { mayWriteIntoRoot } from '../project/artifact-root-resolver.js';
|
|
5
6
|
import { dirname, join } from 'node:path';
|
|
6
7
|
import { homedir } from 'node:os';
|
|
7
8
|
import { readAccountState } from '../cloud/account-state.js';
|
|
@@ -107,10 +108,12 @@ function streakEndingAtLatest(sortedDates) {
|
|
|
107
108
|
let later;
|
|
108
109
|
for (let i = sortedDates.length - 1; i >= 0; i -= 1) {
|
|
109
110
|
const date = sortedDates[i];
|
|
110
|
-
if (date === undefined)
|
|
111
|
+
if (date === undefined) {
|
|
111
112
|
break;
|
|
112
|
-
|
|
113
|
+
}
|
|
114
|
+
if (later !== undefined && !isNextDay(date, later)) {
|
|
113
115
|
break;
|
|
116
|
+
}
|
|
114
117
|
streak += 1;
|
|
115
118
|
later = date;
|
|
116
119
|
}
|
|
@@ -131,8 +134,9 @@ export function applyDelta(scope, delta, now, meta = {}) {
|
|
|
131
134
|
byDate.set(today, todayCounts);
|
|
132
135
|
const dates = [...byDate.keys()].sort();
|
|
133
136
|
const days = dates.map((date) => ({ date, counts: byDate.get(date) ?? emptyImpactCounts() }));
|
|
134
|
-
while (days.length > IMPACT_DAILY_BUCKETS)
|
|
137
|
+
while (days.length > IMPACT_DAILY_BUCKETS) {
|
|
135
138
|
days.shift();
|
|
139
|
+
}
|
|
136
140
|
const records = { ...scope.records };
|
|
137
141
|
records.bestVerdictDay = Math.max(records.bestVerdictDay, todayCounts.verdicts);
|
|
138
142
|
records.bestDefectDay = Math.max(records.bestDefectDay, todayCounts.failed);
|
|
@@ -165,8 +169,9 @@ export function applyDelta(scope, delta, now, meta = {}) {
|
|
|
165
169
|
/** The larger of two counters, key by key. */
|
|
166
170
|
function maxEach(a, b) {
|
|
167
171
|
const out = { ...a };
|
|
168
|
-
for (const key of Object.keys(b))
|
|
172
|
+
for (const key of Object.keys(b)) {
|
|
169
173
|
out[key] = Math.max(a[key] ?? 0, b[key] ?? 0);
|
|
174
|
+
}
|
|
170
175
|
return out;
|
|
171
176
|
}
|
|
172
177
|
/**
|
|
@@ -254,8 +259,9 @@ export class ImpactStore {
|
|
|
254
259
|
}
|
|
255
260
|
#syncStatus(dashboardUrl) {
|
|
256
261
|
const now = this.#now();
|
|
257
|
-
if (this.#sync !== undefined && now - this.#sync.at < SYNC_STATUS_EVERY_MS)
|
|
262
|
+
if (this.#sync !== undefined && now - this.#sync.at < SYNC_STATUS_EVERY_MS) {
|
|
258
263
|
return this.#sync.value;
|
|
264
|
+
}
|
|
259
265
|
// Not linked: one line when runs or flows sit here that nothing will send, and nothing otherwise.
|
|
260
266
|
// `pending` counts both, so the HUD's existing "N not sent" includes a flow saved with no run.
|
|
261
267
|
if (dashboardUrl === undefined) {
|
|
@@ -312,18 +318,21 @@ export class ImpactStore {
|
|
|
312
318
|
project: this.#project,
|
|
313
319
|
global: atLeastProject(this.#global, this.#project),
|
|
314
320
|
};
|
|
315
|
-
if (this.#projectName !== undefined)
|
|
321
|
+
if (this.#projectName !== undefined) {
|
|
316
322
|
snap.projectName = this.#projectName;
|
|
323
|
+
}
|
|
317
324
|
// Re-read, like the account: `reticle link` runs in another terminal while this store lives as
|
|
318
325
|
// long as the daemon, so a construction-time read said "Not linked" until a restart.
|
|
319
326
|
this.#dashboardUrl = readDashboardUrl(this.#root);
|
|
320
|
-
if (this.#dashboardUrl !== undefined)
|
|
327
|
+
if (this.#dashboardUrl !== undefined) {
|
|
321
328
|
snap.dashboardUrl = this.#dashboardUrl;
|
|
329
|
+
}
|
|
322
330
|
snap.account = this.#account();
|
|
323
331
|
// Absent stays absent: the HUD reads that as "we have not heard" and renders no control.
|
|
324
332
|
const cfg = this.#config.read();
|
|
325
|
-
if (cfg !== undefined)
|
|
333
|
+
if (cfg !== undefined) {
|
|
326
334
|
snap.harnessConfig = configForHud(cfg, this.#now());
|
|
335
|
+
}
|
|
327
336
|
// Chosen here, where the account and the entitlement are both known. Absent when nothing applies,
|
|
328
337
|
// so the HUD falls back to the slides bundled with the SDK.
|
|
329
338
|
const notices = selectNotices(this.#notices.read(), {
|
|
@@ -332,16 +341,19 @@ export class ImpactStore {
|
|
|
332
341
|
sdkVersion: this.#sdkVersion,
|
|
333
342
|
now: this.#now(),
|
|
334
343
|
});
|
|
335
|
-
if (0 < notices.length)
|
|
344
|
+
if (0 < notices.length) {
|
|
336
345
|
snap.notices = notices;
|
|
346
|
+
}
|
|
337
347
|
const coverage = this.#coverage?.();
|
|
338
|
-
if (coverage !== undefined)
|
|
348
|
+
if (coverage !== undefined) {
|
|
339
349
|
snap.coverage = coverage;
|
|
350
|
+
}
|
|
340
351
|
// Only for a linked project: an unlinked one has nothing on the platform, and the HUD already
|
|
341
352
|
// offers the way to link it.
|
|
342
353
|
const sync = this.#syncStatus(this.#dashboardUrl);
|
|
343
|
-
if (sync !== undefined)
|
|
354
|
+
if (sync !== undefined) {
|
|
344
355
|
snap.sync = sync;
|
|
356
|
+
}
|
|
345
357
|
return snap;
|
|
346
358
|
}
|
|
347
359
|
/** Write now (process exit, tests). */
|
|
@@ -350,8 +362,11 @@ export class ImpactStore {
|
|
|
350
362
|
clearTimeout(this.#timer);
|
|
351
363
|
this.#timer = undefined;
|
|
352
364
|
}
|
|
353
|
-
// One writer: the in-memory copy IS the truth.
|
|
354
|
-
|
|
365
|
+
// One writer: the in-memory copy IS the truth. A project with no Reticle wiring gets no
|
|
366
|
+
// `.reticle/`: its scope stays in memory, and the first flush after `init` writes all of it.
|
|
367
|
+
if (mayWriteIntoRoot(this.#root)) {
|
|
368
|
+
writeScope(this.#paths.project, this.#project);
|
|
369
|
+
}
|
|
355
370
|
this.#flushGlobal();
|
|
356
371
|
}
|
|
357
372
|
/**
|
|
@@ -367,16 +382,18 @@ export class ImpactStore {
|
|
|
367
382
|
* plus a stale timeout) if the counters are ever load-bearing for anything but the HUD.
|
|
368
383
|
*/
|
|
369
384
|
#flushGlobal() {
|
|
370
|
-
if (0 === this.#pendingGlobal.length)
|
|
385
|
+
if (0 === this.#pendingGlobal.length) {
|
|
371
386
|
return;
|
|
387
|
+
}
|
|
372
388
|
const merged = this.#pendingGlobal.reduce((scope, p) => applyDelta(scope, p.delta, p.now, p.meta), readScope(this.#paths.global, this.#now()));
|
|
373
389
|
writeScope(this.#paths.global, merged);
|
|
374
390
|
this.#global = merged;
|
|
375
391
|
this.#pendingGlobal = [];
|
|
376
392
|
}
|
|
377
393
|
#scheduleFlush() {
|
|
378
|
-
if (this.#timer !== undefined)
|
|
394
|
+
if (this.#timer !== undefined) {
|
|
379
395
|
return;
|
|
396
|
+
}
|
|
380
397
|
this.#timer = setTimeout(() => {
|
|
381
398
|
this.#timer = undefined;
|
|
382
399
|
this.flush();
|