@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
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { type JournalAction, type JournalWriteLoss, type ReticleEvent } from '@reticlehq/core';
|
|
2
|
+
/**
|
|
3
|
+
* The arguments as the journal keeps them: every typed value replaced, at any depth (a sequence's
|
|
4
|
+
* steps too). A fill's arguments kept a typed password in clear in `actions.jsonl`; the page cannot
|
|
5
|
+
* tell the daemon which field was secret before the call is written, and nothing reads a typed value
|
|
6
|
+
* back from the journal — the run fold reads the ref, the target and the action — so none is kept.
|
|
7
|
+
*/
|
|
8
|
+
export declare function withoutTypedInput(args: unknown): unknown;
|
|
2
9
|
/** Where a recorder persists. `SessionJournal` satisfies this structurally. */
|
|
3
10
|
export interface JournalSink {
|
|
4
11
|
appendEvents(events: readonly ReticleEvent[]): Promise<void>;
|
|
@@ -3,6 +3,7 @@ import { isSelfObservation } from './self-observation.js';
|
|
|
3
3
|
import { currentDrivenBy } from '../../hooks/driven-by.js';
|
|
4
4
|
import { callerClientName } from '../../hooks/coding-agents.js';
|
|
5
5
|
import { log } from '../../log.js';
|
|
6
|
+
import { runLedger } from '../../judgement/runs/run-ledger.js';
|
|
6
7
|
/**
|
|
7
8
|
* Logged the FIRST time a journal write is lost, and never again for that recorder.
|
|
8
9
|
*
|
|
@@ -23,11 +24,13 @@ const TYPED_KEYS = ['value', 'text'];
|
|
|
23
24
|
* tell the daemon which field was secret before the call is written, and nothing reads a typed value
|
|
24
25
|
* back from the journal — the run fold reads the ref, the target and the action — so none is kept.
|
|
25
26
|
*/
|
|
26
|
-
function withoutTypedInput(args) {
|
|
27
|
-
if (Array.isArray(args))
|
|
27
|
+
export function withoutTypedInput(args) {
|
|
28
|
+
if (Array.isArray(args)) {
|
|
28
29
|
return args.map(withoutTypedInput);
|
|
29
|
-
|
|
30
|
+
}
|
|
31
|
+
if ('object' !== typeof args || null === args) {
|
|
30
32
|
return args;
|
|
33
|
+
}
|
|
31
34
|
const record = args;
|
|
32
35
|
const typing = TYPING_ACTIONS.has(String(record['action']));
|
|
33
36
|
const out = {};
|
|
@@ -37,9 +40,11 @@ function withoutTypedInput(args) {
|
|
|
37
40
|
}
|
|
38
41
|
if (typing && 'object' === typeof record['args'] && null !== record['args']) {
|
|
39
42
|
const inner = { ...record['args'] };
|
|
40
|
-
for (const key of TYPED_KEYS)
|
|
41
|
-
if ('string' === typeof inner[key])
|
|
43
|
+
for (const key of TYPED_KEYS) {
|
|
44
|
+
if ('string' === typeof inner[key]) {
|
|
42
45
|
inner[key] = REDACTED_VALUE;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
43
48
|
out['args'] = inner;
|
|
44
49
|
}
|
|
45
50
|
return out;
|
|
@@ -90,8 +95,9 @@ export class JournalRecorder {
|
|
|
90
95
|
// session keeps seeing this event. What is declined is the DURABLE copy: see isSelfObservation.
|
|
91
96
|
if (!isSelfObservation(out)) {
|
|
92
97
|
this.#pending.push(out);
|
|
93
|
-
if (this.#pending.length >= this.#flushAt)
|
|
98
|
+
if (this.#pending.length >= this.#flushAt) {
|
|
94
99
|
this.#enqueueFlush();
|
|
100
|
+
}
|
|
95
101
|
}
|
|
96
102
|
return out;
|
|
97
103
|
}
|
|
@@ -109,8 +115,9 @@ export class JournalRecorder {
|
|
|
109
115
|
/** Close the active window: persist its buffered events, then the action record. No-op if none active. */
|
|
110
116
|
finishAction(effect, settled, settledInMs) {
|
|
111
117
|
const active = this.#active;
|
|
112
|
-
if (active === undefined)
|
|
118
|
+
if (active === undefined) {
|
|
113
119
|
return;
|
|
120
|
+
}
|
|
114
121
|
this.#active = undefined;
|
|
115
122
|
const action = {
|
|
116
123
|
v: JOURNAL_FILE_VERSION,
|
|
@@ -128,6 +135,8 @@ export class JournalRecorder {
|
|
|
128
135
|
...(active.drivenBy === undefined ? {} : { drivenBy: active.drivenBy }),
|
|
129
136
|
...(active.agent === undefined ? {} : { agent: active.agent }),
|
|
130
137
|
};
|
|
138
|
+
// The agent's own verdicts make its run's report; the ledger ignores the Harness's.
|
|
139
|
+
runLedger.verdict(action);
|
|
131
140
|
this.#enqueueFlush();
|
|
132
141
|
this.#chain = this.#chain
|
|
133
142
|
.then(() => this.#sink.appendAction(action))
|
|
@@ -173,6 +182,8 @@ export class JournalRecorder {
|
|
|
173
182
|
return agent === undefined ? {} : { agent };
|
|
174
183
|
})(),
|
|
175
184
|
};
|
|
185
|
+
// The agent's own verdicts make its run's report; the ledger ignores the Harness's.
|
|
186
|
+
runLedger.verdict(action);
|
|
176
187
|
this.#enqueueFlush();
|
|
177
188
|
this.#chain = this.#chain
|
|
178
189
|
.then(() => this.#sink.appendAction(action))
|
|
@@ -184,8 +195,9 @@ export class JournalRecorder {
|
|
|
184
195
|
await this.#chain;
|
|
185
196
|
}
|
|
186
197
|
#enqueueFlush() {
|
|
187
|
-
if (0 === this.#pending.length)
|
|
198
|
+
if (0 === this.#pending.length) {
|
|
188
199
|
return;
|
|
200
|
+
}
|
|
189
201
|
const batch = this.#pending;
|
|
190
202
|
this.#pending = [];
|
|
191
203
|
this.#chain = this.#chain
|
|
@@ -194,8 +206,9 @@ export class JournalRecorder {
|
|
|
194
206
|
}
|
|
195
207
|
/** Swallow a lost write, but say so once. See JOURNAL_WRITE_LOST. */
|
|
196
208
|
#reportLoss(error) {
|
|
197
|
-
if (this.#lossReported)
|
|
209
|
+
if (this.#lossReported) {
|
|
198
210
|
return;
|
|
211
|
+
}
|
|
199
212
|
this.#lossReported = true;
|
|
200
213
|
log(JOURNAL_WRITE_LOST, { error: error instanceof Error ? error.message : String(error) });
|
|
201
214
|
}
|
|
@@ -12,10 +12,4 @@ import { z } from 'zod';
|
|
|
12
12
|
export declare const AmbientFileSchema: z.ZodObject<{
|
|
13
13
|
version: z.ZodLiteral<1>;
|
|
14
14
|
regions: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
15
|
-
},
|
|
16
|
-
version: 1;
|
|
17
|
-
regions: Record<string, number>;
|
|
18
|
-
}, {
|
|
19
|
-
version: 1;
|
|
20
|
-
regions: Record<string, number>;
|
|
21
|
-
}>;
|
|
15
|
+
}, z.core.$strip>;
|
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
import type { FileSystemPort } from '../../project/fs/fs-port.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* The `.reticle/` entries that are LOCAL state, and must never be committed by accident.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Read from the tier table rather than restated here: which half a name belongs to is one decision,
|
|
6
|
+
* and a second copy of it is the list that silently disagrees. This file asks the table exactly one
|
|
7
|
+
* of its two questions — `sharing` — and has no opinion at all about what retention may delete.
|
|
8
|
+
*
|
|
9
|
+
* The reason this matters beyond tidiness: a session journal carries URLs, request and response
|
|
10
|
+
* bodies, and DOM text from the app under test. `.reticle/` is created by the daemon rather than by
|
|
11
|
+
* the user, so it arrives untracked and unexplained, and one `git add -A` puts an app's traffic into
|
|
12
|
+
* a shared repository. Reticle created the directory; the ignore for it is Reticle's to write.
|
|
13
|
+
*/
|
|
14
|
+
/** The ignore file inside `.reticle/`. */
|
|
15
|
+
export declare const WORKSPACE_GITIGNORE = ".gitignore";
|
|
16
|
+
/**
|
|
17
|
+
* The ignore file `.reticle/` should hold, given the one it holds now (`undefined`: none). Returns
|
|
18
|
+
* `undefined` when nothing needs to change. A new file gets every local entry. An existing file
|
|
19
|
+
* keeps every line it has, and gets only the prompt files it lacks, appended at the end.
|
|
20
|
+
*/
|
|
21
|
+
export declare function workspaceGitignore(existing: string | undefined): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Write `.reticle/.gitignore`, or add the prompt files to the one that is there.
|
|
24
|
+
*
|
|
25
|
+
* Never overwrites. Once the file exists it belongs to whoever edited it last, and silently
|
|
6
26
|
* reverting somebody's change to a file we placed in their repository is worse than not having
|
|
7
|
-
* written it.
|
|
27
|
+
* written it. The one exception is additive: the prompt files are appended when missing, because
|
|
28
|
+
* a file written before prompt capture existed would otherwise let them be committed. Best-effort throughout: this runs on the daemon's start path, and a workspace that
|
|
8
29
|
* cannot be written must not stop a daemon coming up. Nothing about verification depends on it.
|
|
9
30
|
*/
|
|
10
31
|
export declare function ensureWorkspaceGitignore(fs: FileSystemPort, root: string): Promise<void>;
|
|
@@ -13,6 +13,8 @@ import { LOCAL_DIRS, LOCAL_FILES } from './workspace-tiers.js';
|
|
|
13
13
|
* the user, so it arrives untracked and unexplained, and one `git add -A` puts an app's traffic into
|
|
14
14
|
* a shared repository. Reticle created the directory; the ignore for it is Reticle's to write.
|
|
15
15
|
*/
|
|
16
|
+
/** The ignore file inside `.reticle/`. */
|
|
17
|
+
export const WORKSPACE_GITIGNORE = '.gitignore';
|
|
16
18
|
const TRANSIENT = [
|
|
17
19
|
...LOCAL_DIRS.map((dir) => `${dir}/`),
|
|
18
20
|
...LOCAL_FILES,
|
|
@@ -30,23 +32,52 @@ const HEADER = [
|
|
|
30
32
|
`# ${ReticleDir.CAPSULES_SUBDIR}/. Those are meant to be committed — a saved flow only earns its keep`,
|
|
31
33
|
'# when a teammate or CI can replay it.',
|
|
32
34
|
'#',
|
|
33
|
-
'# Edit freely
|
|
35
|
+
'# Edit freely. Reticle only adds the prompt files below when they are missing: they hold every',
|
|
36
|
+
'# prompt you typed, and a `git add -A` must never publish them.',
|
|
34
37
|
];
|
|
35
38
|
/**
|
|
36
|
-
*
|
|
39
|
+
* The entries Reticle adds to an ignore file that already exists. They are the user's prompts, and
|
|
40
|
+
* a `.gitignore` written before prompt capture existed has none of them.
|
|
41
|
+
*/
|
|
42
|
+
const PROMPT_FILES = [
|
|
43
|
+
ReticleDir.REQUEST_FILE,
|
|
44
|
+
ReticleDir.REQUESTS_LOG_FILE,
|
|
45
|
+
ReticleDir.REQUESTS_LOG_ROTATED_FILE,
|
|
46
|
+
];
|
|
47
|
+
const MERGED_NOTE = '# Added by Reticle: the prompts you typed, kept on this machine.';
|
|
48
|
+
/**
|
|
49
|
+
* The ignore file `.reticle/` should hold, given the one it holds now (`undefined`: none). Returns
|
|
50
|
+
* `undefined` when nothing needs to change. A new file gets every local entry. An existing file
|
|
51
|
+
* keeps every line it has, and gets only the prompt files it lacks, appended at the end.
|
|
52
|
+
*/
|
|
53
|
+
export function workspaceGitignore(existing) {
|
|
54
|
+
if (existing === undefined)
|
|
55
|
+
return `${[...HEADER, '', ...TRANSIENT].join('\n')}\n`;
|
|
56
|
+
const lines = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
|
|
57
|
+
const missing = PROMPT_FILES.filter((name) => !lines.has(name) && !lines.has(`/${name}`));
|
|
58
|
+
if (0 === missing.length)
|
|
59
|
+
return undefined;
|
|
60
|
+
const base = existing.endsWith('\n') || '' === existing ? existing : `${existing}\n`;
|
|
61
|
+
return `${base}${[MERGED_NOTE, ...missing].join('\n')}\n`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Write `.reticle/.gitignore`, or add the prompt files to the one that is there.
|
|
37
65
|
*
|
|
38
|
-
* Never overwrites
|
|
66
|
+
* Never overwrites. Once the file exists it belongs to whoever edited it last, and silently
|
|
39
67
|
* reverting somebody's change to a file we placed in their repository is worse than not having
|
|
40
|
-
* written it.
|
|
68
|
+
* written it. The one exception is additive: the prompt files are appended when missing, because
|
|
69
|
+
* a file written before prompt capture existed would otherwise let them be committed. Best-effort throughout: this runs on the daemon's start path, and a workspace that
|
|
41
70
|
* cannot be written must not stop a daemon coming up. Nothing about verification depends on it.
|
|
42
71
|
*/
|
|
43
72
|
export async function ensureWorkspaceGitignore(fs, root) {
|
|
44
|
-
const path = join(root,
|
|
73
|
+
const path = join(root, WORKSPACE_GITIGNORE);
|
|
45
74
|
try {
|
|
46
|
-
|
|
75
|
+
const existing = (await fs.exists(path)) ? await fs.readFile(path) : undefined;
|
|
76
|
+
const next = workspaceGitignore(existing);
|
|
77
|
+
if (next === undefined)
|
|
47
78
|
return;
|
|
48
79
|
await fs.mkdir(root);
|
|
49
|
-
await fs.writeFile(path,
|
|
80
|
+
await fs.writeFile(path, next);
|
|
50
81
|
}
|
|
51
82
|
catch {
|
|
52
83
|
/* a workspace we cannot write is not a reason to fail a session */
|
|
@@ -41,7 +41,11 @@ const sharedFile = { durability: Durability.MEMORY, sharing: Sharing.COMMIT, isD
|
|
|
41
41
|
*/
|
|
42
42
|
export const WORKSPACE_TIERS = {
|
|
43
43
|
[ReticleDir.SESSIONS_SUBDIR]: localDir,
|
|
44
|
+
// Every tool call and its whole result: app data, so local, and evidence, so swept by age.
|
|
45
|
+
[ReticleDir.EPISODES_SUBDIR]: localDir,
|
|
44
46
|
[ReticleDir.RUNS_SUBDIR]: localDir,
|
|
47
|
+
// A dev server's output, written here only when the state home cannot be written.
|
|
48
|
+
[ReticleDir.LOGS_SUBDIR]: localDir,
|
|
45
49
|
[ReticleDir.VISUAL_SUBDIR]: localDir,
|
|
46
50
|
// Write-only: a local copy of what was already sent. The outbox is the record.
|
|
47
51
|
[ReticleDir.FEEDBACK_SUBDIR]: localDir,
|
|
@@ -56,6 +60,9 @@ export const WORKSPACE_TIERS = {
|
|
|
56
60
|
[ReticleDir.TIERS_FILE]: localFile,
|
|
57
61
|
// The user's request in their own words: it leaves only with `shareRequests`, never by git push.
|
|
58
62
|
[ReticleDir.REQUEST_FILE]: localFile,
|
|
63
|
+
// Every prompt the agent hook captured: the same words, so the same rule.
|
|
64
|
+
[ReticleDir.REQUESTS_LOG_FILE]: localFile,
|
|
65
|
+
[ReticleDir.REQUESTS_LOG_ROTATED_FILE]: localFile,
|
|
59
66
|
// How to target this app, learned from corrected failures: a teammate's agent needs it too.
|
|
60
67
|
[ReticleDir.APP_NOTES_FILE]: sharedFile,
|
|
61
68
|
[ReticleDir.PLATFORM_MOMENTS_FILE]: localFile,
|
|
@@ -46,6 +46,7 @@ const NET_TYPES = new Set([
|
|
|
46
46
|
EventType.NET_REQUEST,
|
|
47
47
|
EventType.NET_PENDING,
|
|
48
48
|
EventType.NET_DETAIL,
|
|
49
|
+
EventType.NET_RESPONSE_BODY,
|
|
49
50
|
EventType.NET_STREAM,
|
|
50
51
|
]);
|
|
51
52
|
/** A base for parsing relative URLs. Never dereferenced — only the path is read. */
|
|
@@ -60,8 +61,9 @@ function pathOf(url) {
|
|
|
60
61
|
}
|
|
61
62
|
/** True when this event is the page fetching Reticle's own code rather than doing anything. */
|
|
62
63
|
export function isSelfObservation(event) {
|
|
63
|
-
if (!NET_TYPES.has(event.type))
|
|
64
|
+
if (!NET_TYPES.has(event.type)) {
|
|
64
65
|
return false;
|
|
66
|
+
}
|
|
65
67
|
const path = pathOf(urlForMatch(event.data));
|
|
66
68
|
return path.includes(SCOPE_PATH) || path.includes(SCOPE_FLATTENED);
|
|
67
69
|
}
|
|
@@ -22,6 +22,8 @@ import { RunStore } from '../../judgement/runs/artifact/run-store.js';
|
|
|
22
22
|
* starts already knowing which regions churn.
|
|
23
23
|
*/
|
|
24
24
|
export function makeSessionEnd(deps) {
|
|
25
|
+
// The `flow_recorded` outcomes this daemon already reported. See saveDrivenFlow.
|
|
26
|
+
const flowStepsSent = new Set();
|
|
25
27
|
return async (session) => {
|
|
26
28
|
/*
|
|
27
29
|
* Retention is maintenance of a directory, not a part of journalling, so it runs either way.
|
|
@@ -94,7 +96,7 @@ export function makeSessionEnd(deps) {
|
|
|
94
96
|
// Saved only when the tape declared a consequence — see drive-flow.ts for why the alternative is
|
|
95
97
|
// a false-green factory running once per session.
|
|
96
98
|
try {
|
|
97
|
-
await saveDrivenFlow(deps, session);
|
|
99
|
+
await saveDrivenFlow(deps, session, flowStepsSent);
|
|
98
100
|
}
|
|
99
101
|
catch (error) {
|
|
100
102
|
// A flow is a by-product of the session; failing to write one never fails the teardown. It is
|
|
@@ -171,8 +173,9 @@ export function makeSessionEnd(deps) {
|
|
|
171
173
|
export async function recordDriveRun(deps, session) {
|
|
172
174
|
// Called through the object, not lifted into a local: a lifted method loses its `this`, and the
|
|
173
175
|
// real Session's reader closes over the journal it was constructed with.
|
|
174
|
-
if (session.readJournalActions === undefined)
|
|
176
|
+
if (session.readJournalActions === undefined) {
|
|
175
177
|
return;
|
|
178
|
+
}
|
|
176
179
|
const actions = await session.readJournalActions();
|
|
177
180
|
const root = session.artifactRoot ?? deps.reticleRoot;
|
|
178
181
|
const inputs = driveRunsFrom(actions, {
|
|
@@ -188,8 +191,9 @@ export async function recordDriveRun(deps, session) {
|
|
|
188
191
|
...(session.projectId === undefined ? {} : { projectId: session.projectId }),
|
|
189
192
|
projectName: basename(dirname(root)),
|
|
190
193
|
});
|
|
191
|
-
if (0 === inputs.length)
|
|
194
|
+
if (0 === inputs.length) {
|
|
192
195
|
return;
|
|
196
|
+
}
|
|
193
197
|
// The protocol reaching the artifact a person actually reads. Only when the session could say
|
|
194
198
|
// where it was: a subject with no locator is not a weaker subject, it is a guess, and the
|
|
195
199
|
// schema makes the field optional so that absence can be told from invention.
|
|
@@ -213,15 +217,16 @@ export async function recordDriveRun(deps, session) {
|
|
|
213
217
|
// restamping on every rewrite showed the tab's close as the drive's time.
|
|
214
218
|
const held = await store.read(asRunId(input.runId));
|
|
215
219
|
const firstAt = held.ok ? held.run.createdAt : undefined;
|
|
216
|
-
await store.write(buildVerificationRun({ ...input, ...(subject === undefined ? {} : { subject }) }, firstAt === undefined ? clock : () => firstAt));
|
|
220
|
+
await store.write(buildVerificationRun({ ...input, ...(subject === undefined ? {} : { subject }) }, firstAt === undefined ? clock : () => firstAt), { sessionId: session.id });
|
|
217
221
|
}
|
|
218
222
|
}
|
|
219
223
|
/** Persist what this session drove as a replayable flow, when it declared anything provable. */
|
|
220
|
-
async function saveDrivenFlow(deps, session) {
|
|
224
|
+
async function saveDrivenFlow(deps, session, stepsSent) {
|
|
221
225
|
const takeTape = deps.takeAmbientTape;
|
|
222
226
|
const flows = deps.flowsAt?.(session.artifactRoot ?? deps.reticleRoot) ?? deps.flows;
|
|
223
|
-
if (takeTape === undefined || flows === undefined)
|
|
227
|
+
if (takeTape === undefined || flows === undefined) {
|
|
224
228
|
return;
|
|
229
|
+
}
|
|
225
230
|
// One flow per journey the session contained, not one flow per session — see drive-flow.ts.
|
|
226
231
|
const { programs, outcome } = driveFlowsFrom(takeTape(session.id));
|
|
227
232
|
const author = deps.author?.();
|
|
@@ -235,7 +240,7 @@ async function saveDrivenFlow(deps, session) {
|
|
|
235
240
|
// which is a real outcome and not our bug. Counting it as a failure would blame the product for a
|
|
236
241
|
// choice the agent made, and counting it as success would claim a regression test that cannot go
|
|
237
242
|
// red. `unprovenSteps` is what separates "drove and proved nothing" from "drove nothing at all".
|
|
238
|
-
|
|
243
|
+
const step = {
|
|
239
244
|
phase: OnboardingPhase.FIRST_RUN,
|
|
240
245
|
step: 'flow_recorded',
|
|
241
246
|
status: 0 === programs.length ? OnboardingStepStatus.SKIPPED : OnboardingStepStatus.COMPLETED,
|
|
@@ -246,7 +251,15 @@ async function saveDrivenFlow(deps, session) {
|
|
|
246
251
|
...(0 < programs.length || outcome.mockedSteps === undefined
|
|
247
252
|
? {}
|
|
248
253
|
: { reason: DriveFlowSkipReason.DRIVEN_UNDER_NETWORK_MOCKS }),
|
|
249
|
-
}
|
|
254
|
+
};
|
|
255
|
+
// Once per daemon for each status and reason. A browser session ends at every page reload, and
|
|
256
|
+
// a page that reloads in a loop sent this step without end. A repeat tells the funnel nothing.
|
|
257
|
+
const key = `${step.status}/${step.reason ?? ''}`;
|
|
258
|
+
if (stepsSent.has(key)) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
stepsSent.add(key);
|
|
262
|
+
await deps.reportStep?.(step);
|
|
250
263
|
}
|
|
251
264
|
/**
|
|
252
265
|
* Remove this session's journal when it served no tool call.
|
|
@@ -258,8 +271,9 @@ async function saveDrivenFlow(deps, session) {
|
|
|
258
271
|
async function dropUndrivenJournal(fs, root, sessionId) {
|
|
259
272
|
try {
|
|
260
273
|
const actions = await fs.readFile(journalActionsPath(root, sessionId)).catch(() => '');
|
|
261
|
-
if (actions.trim().length > 0)
|
|
274
|
+
if (actions.trim().length > 0) {
|
|
262
275
|
return;
|
|
276
|
+
}
|
|
263
277
|
await fs.rm(sessionDirPath(root, sessionId));
|
|
264
278
|
}
|
|
265
279
|
catch {
|
|
@@ -49,8 +49,9 @@ const CACHE_COMPACT_AT = 1024;
|
|
|
49
49
|
* bound is used in and silently disable it, which is the one failure mode a bound must not have.
|
|
50
50
|
*/
|
|
51
51
|
function boundedOption(value, fallback, name) {
|
|
52
|
-
if (value === undefined)
|
|
52
|
+
if (value === undefined) {
|
|
53
53
|
return fallback;
|
|
54
|
+
}
|
|
54
55
|
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
55
56
|
throw new Error(`refusing a journal ${name} that is not a positive whole number: ${String(value)}`);
|
|
56
57
|
}
|
|
@@ -184,11 +185,13 @@ export class SessionJournal {
|
|
|
184
185
|
* already on disk is deleted, and the loss is at the end where it can be declared.
|
|
185
186
|
*/
|
|
186
187
|
async appendEvents(events) {
|
|
187
|
-
if (0 === events.length)
|
|
188
|
+
if (0 === events.length) {
|
|
188
189
|
return;
|
|
190
|
+
}
|
|
189
191
|
// Durable, not a field: see #writeLoss. A closed ledger is closed for a one-event batch too.
|
|
190
|
-
if ((await this.#closureReport()) !== undefined)
|
|
192
|
+
if ((await this.#closureReport()) !== undefined) {
|
|
191
193
|
return;
|
|
194
|
+
}
|
|
192
195
|
await this.#ensureDir();
|
|
193
196
|
const path = journalEventsPath(this.#root, this.#sessionId);
|
|
194
197
|
const written = await this.#eventBytesOnDisk(path);
|
|
@@ -221,8 +224,9 @@ export class SessionJournal {
|
|
|
221
224
|
*/
|
|
222
225
|
async #eventBytesOnDisk(path) {
|
|
223
226
|
const known = this.#eventBytes;
|
|
224
|
-
if (known !== undefined)
|
|
227
|
+
if (known !== undefined) {
|
|
225
228
|
return known;
|
|
229
|
+
}
|
|
226
230
|
let size;
|
|
227
231
|
try {
|
|
228
232
|
size = (await this.#fs.stat(path)).size;
|
|
@@ -235,8 +239,9 @@ export class SessionJournal {
|
|
|
235
239
|
// by exactly the conditions most likely to accompany a failing disk. Thrown before anything is
|
|
236
240
|
// appended; `JournalRecorder` swallows sink errors, so a live session is never taken down by
|
|
237
241
|
// one.
|
|
238
|
-
if (!this.#fs.isNotFound(error))
|
|
242
|
+
if (!this.#fs.isNotFound(error)) {
|
|
239
243
|
throw error;
|
|
244
|
+
}
|
|
240
245
|
size = 0;
|
|
241
246
|
}
|
|
242
247
|
this.#eventBytes = size;
|
|
@@ -252,16 +257,18 @@ export class SessionJournal {
|
|
|
252
257
|
* necessarily the ceiling that closed the file.
|
|
253
258
|
*/
|
|
254
259
|
async #closureReport() {
|
|
255
|
-
if (this.#lossLoaded)
|
|
260
|
+
if (this.#lossLoaded) {
|
|
256
261
|
return this.#writeLoss;
|
|
262
|
+
}
|
|
257
263
|
let text;
|
|
258
264
|
try {
|
|
259
265
|
text = await this.#fs.readFile(journalClosedPath(this.#root, this.#sessionId));
|
|
260
266
|
}
|
|
261
267
|
catch (error) {
|
|
262
268
|
// Same rule as the size read above, and for the same reason: only ENOENT is "never closed".
|
|
263
|
-
if (!this.#fs.isNotFound(error))
|
|
269
|
+
if (!this.#fs.isNotFound(error)) {
|
|
264
270
|
throw error;
|
|
271
|
+
}
|
|
265
272
|
this.#lossLoaded = true;
|
|
266
273
|
return undefined;
|
|
267
274
|
}
|
|
@@ -371,8 +378,9 @@ export class SessionJournal {
|
|
|
371
378
|
await this.#fs.appendFile(path, text);
|
|
372
379
|
}
|
|
373
380
|
catch (error) {
|
|
374
|
-
if (!this.#fs.isNotFound(error))
|
|
381
|
+
if (!this.#fs.isNotFound(error)) {
|
|
375
382
|
throw error;
|
|
383
|
+
}
|
|
376
384
|
this.#dirEnsured = false;
|
|
377
385
|
await this.#ensureDir();
|
|
378
386
|
await this.#fs.appendFile(path, text);
|
|
@@ -390,8 +398,9 @@ export class SessionJournal {
|
|
|
390
398
|
chunk = await readFrom(path, this.#eventBytesConsumed, this.#maxReadBytes);
|
|
391
399
|
}
|
|
392
400
|
catch (error) {
|
|
393
|
-
if (this.#fs.isNotFound(error))
|
|
401
|
+
if (this.#fs.isNotFound(error)) {
|
|
394
402
|
return this.#liveEvents();
|
|
403
|
+
}
|
|
395
404
|
throw error;
|
|
396
405
|
}
|
|
397
406
|
// Shrink guard: if the file is smaller than what we consumed, the offset is meaningless — reset
|
|
@@ -408,8 +417,9 @@ export class SessionJournal {
|
|
|
408
417
|
const from = chunk.from ?? this.#eventBytesConsumed;
|
|
409
418
|
const skipped = Math.max(0, from - this.#eventBytesConsumed);
|
|
410
419
|
this.#ingestTail(chunk.text);
|
|
411
|
-
if (skipped > 0)
|
|
420
|
+
if (skipped > 0) {
|
|
412
421
|
this.#noteCut(skipped);
|
|
422
|
+
}
|
|
413
423
|
// Resume at the end of the last COMPLETE line, counted forward over the bytes that actually
|
|
414
424
|
// ARRIVED. Not from `chunk.size`: that is the file's end as `fstat` reported it, and a read
|
|
415
425
|
// truncated or cut short returns less — a cursor there would skip every unread byte, silently
|
|
@@ -424,8 +434,9 @@ export class SessionJournal {
|
|
|
424
434
|
text = await this.#fs.readFile(path);
|
|
425
435
|
}
|
|
426
436
|
catch (error) {
|
|
427
|
-
if (this.#fs.isNotFound(error))
|
|
437
|
+
if (this.#fs.isNotFound(error)) {
|
|
428
438
|
return this.#liveEvents();
|
|
439
|
+
}
|
|
429
440
|
throw error;
|
|
430
441
|
}
|
|
431
442
|
// Fallback (whole-file) path: #eventCharsConsumed is a UTF-16 offset into the whole text. Shrink
|
|
@@ -467,11 +478,13 @@ export class SessionJournal {
|
|
|
467
478
|
*/
|
|
468
479
|
#ingestTail(tail) {
|
|
469
480
|
const end = tail.lastIndexOf('\n') + 1;
|
|
470
|
-
if (0 === end)
|
|
471
|
-
return;
|
|
481
|
+
if (0 === end) {
|
|
482
|
+
return;
|
|
483
|
+
} // no complete line yet
|
|
472
484
|
for (const line of tail.slice(0, end).split('\n')) {
|
|
473
|
-
if (0 === line.length)
|
|
485
|
+
if (0 === line.length) {
|
|
474
486
|
continue;
|
|
487
|
+
}
|
|
475
488
|
let parsed;
|
|
476
489
|
try {
|
|
477
490
|
parsed = JSON.parse(line);
|
|
@@ -515,8 +528,9 @@ export class SessionJournal {
|
|
|
515
528
|
this.#droppedBytes += cost;
|
|
516
529
|
this.#droppedEvents += 1;
|
|
517
530
|
// Exact, unlike a byte cut: this record was parsed, so the millisecond it was lost at is known.
|
|
518
|
-
if (victim !== undefined)
|
|
531
|
+
if (victim !== undefined) {
|
|
519
532
|
this.#lostThroughT = Math.max(this.#lostThroughT, victim.t);
|
|
533
|
+
}
|
|
520
534
|
// Release the payload now. Waiting for slot compaction keeps evicted snapshots strongly
|
|
521
535
|
// reachable, so a short returned list alone would not bound retained evidence in memory.
|
|
522
536
|
this.#eventCache[this.#cacheHead] = undefined;
|
|
@@ -545,8 +559,9 @@ export class SessionJournal {
|
|
|
545
559
|
* is what carries this to a verdict.
|
|
546
560
|
*/
|
|
547
561
|
readLoss() {
|
|
548
|
-
if (0 === this.#droppedBytes && 0 === this.#droppedEvents)
|
|
562
|
+
if (0 === this.#droppedBytes && 0 === this.#droppedEvents) {
|
|
549
563
|
return undefined;
|
|
564
|
+
}
|
|
550
565
|
const bounded = Number.isFinite(this.#lostThroughT);
|
|
551
566
|
return {
|
|
552
567
|
droppedBytes: this.#droppedBytes,
|
|
@@ -568,8 +583,9 @@ export class SessionJournal {
|
|
|
568
583
|
return this.#readLines(journalActionsPath(this.#root, this.#sessionId), JournalActionSchema);
|
|
569
584
|
}
|
|
570
585
|
async #ensureDir() {
|
|
571
|
-
if (this.#dirEnsured)
|
|
586
|
+
if (this.#dirEnsured) {
|
|
572
587
|
return;
|
|
588
|
+
}
|
|
573
589
|
await this.#fs.mkdir(sessionDirPath(this.#root, this.#sessionId));
|
|
574
590
|
this.#dirEnsured = true;
|
|
575
591
|
}
|
|
@@ -579,14 +595,16 @@ export class SessionJournal {
|
|
|
579
595
|
text = await this.#fs.readFile(path);
|
|
580
596
|
}
|
|
581
597
|
catch (error) {
|
|
582
|
-
if (this.#fs.isNotFound(error))
|
|
598
|
+
if (this.#fs.isNotFound(error)) {
|
|
583
599
|
return [];
|
|
600
|
+
}
|
|
584
601
|
throw error;
|
|
585
602
|
}
|
|
586
603
|
const out = [];
|
|
587
604
|
for (const line of text.split('\n')) {
|
|
588
|
-
if (0 === line.length)
|
|
605
|
+
if (0 === line.length) {
|
|
589
606
|
continue;
|
|
607
|
+
}
|
|
590
608
|
let parsed;
|
|
591
609
|
try {
|
|
592
610
|
parsed = JSON.parse(line);
|
|
@@ -596,8 +614,9 @@ export class SessionJournal {
|
|
|
596
614
|
}
|
|
597
615
|
const result = schema.safeParse(parsed);
|
|
598
616
|
// Validated at this boundary; ZodTypeAny widens `.data` to any, so re-narrow to the schema output.
|
|
599
|
-
if (result.success)
|
|
617
|
+
if (result.success) {
|
|
600
618
|
out.push(result.data);
|
|
619
|
+
}
|
|
601
620
|
}
|
|
602
621
|
return out;
|
|
603
622
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { type ProjectCandidate } from '@reticlehq/core/artifacts';
|
|
2
|
-
import { type ProjectId } from '@reticlehq/core';
|
|
2
|
+
import { type Checkout, type ProjectId } from '@reticlehq/core';
|
|
3
3
|
import { type ArtifactRoot } from './artifact-root.js';
|
|
4
|
+
/**
|
|
5
|
+
* May the daemon write into this `.reticle` root? This is the one answer for every writer.
|
|
6
|
+
*
|
|
7
|
+
* The resolver asks it ONCE for the daemon's own root: a directory does not become a project
|
|
8
|
+
* between two tabs connecting, and this is the IO half `unmatchedRoot` deliberately does not do.
|
|
9
|
+
* A writer that holds a root for the daemon's life (the impact ledger) asks it on each write, so
|
|
10
|
+
* that it starts to write into the project when `init` wires it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mayWriteIntoRoot(reticleRoot: string): boolean;
|
|
4
13
|
/**
|
|
5
14
|
* Every project this machine knows the directory of: discovered `.reticle.json` files first, then
|
|
6
15
|
* the user-level registry, then the dev servers the build plugin announced. Read on each call, since
|
|
@@ -34,5 +43,9 @@ export interface ArtifactRootResolverDeps {
|
|
|
34
43
|
* would silently keep sending every worktree's artifacts to the primary checkout.
|
|
35
44
|
*/
|
|
36
45
|
servingDirectory: (origin: string) => string | undefined;
|
|
46
|
+
/** The git checkout a directory is in. Defaults to reading `.git` on disk. */
|
|
47
|
+
checkout?: (dir: string) => Checkout | undefined;
|
|
48
|
+
/** Whether a repository has linked worktrees. Defaults to one directory read. */
|
|
49
|
+
hasWorktrees?: (commonDir: string) => boolean;
|
|
37
50
|
}
|
|
38
51
|
export declare function artifactRootResolver(daemonRoot: string, deps: ArtifactRootResolverDeps): (projectId: ProjectId | undefined, origin?: string) => ArtifactRoot;
|