@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
|
@@ -4,19 +4,34 @@
|
|
|
4
4
|
* An empty list is the most common thing that tool returns, and on its own it is a dead end: the
|
|
5
5
|
* agent asked the one question it knows to ask and got no next step. So it carries why nothing is
|
|
6
6
|
* connected, the executable next action, the last tab that was here, and, on a project that has
|
|
7
|
-
* never connected, the
|
|
7
|
+
* never connected, the next step: the zero-install lease, and the consent question for `init`.
|
|
8
|
+
*
|
|
9
|
+
* This call changes no file. It used to run `init` in an unwired project: an agent that only
|
|
10
|
+
* listed sessions changed package.json, the lockfile and the build config, and started a second
|
|
11
|
+
* dev server, which the user did not ask for. Wiring is the user's decision.
|
|
8
12
|
*/
|
|
9
13
|
import { dirname } from 'node:path';
|
|
10
14
|
import { z } from 'zod';
|
|
11
|
-
import { DiscoveryInvite, NoSessionAction } from '@reticlehq/core';
|
|
15
|
+
import { DiscoveryInvite, NextStepOffered, NoSessionAction } from '@reticlehq/core';
|
|
12
16
|
import { readProjectId } from '../../command/cli/ports/resolve/cli-port.js';
|
|
13
17
|
import { callingClientDirectory } from '../../hooks/client-directory.js';
|
|
14
|
-
|
|
18
|
+
import { initCommandIn } from '../../portal/session/dev-server/dev-command.js';
|
|
19
|
+
import { wiringConsent, zeroInstallLease, } from '../../portal/session/no-session-next-action.js';
|
|
20
|
+
import { noteNextStepOffered } from '../../telemetry/onboarding-firsts.js';
|
|
21
|
+
// The handshake reads the consent wording from here, so `mcp` needs no reach into `session`.
|
|
22
|
+
export { wiringConsent };
|
|
23
|
+
/** The answers that mean "this app is not set up yet". */
|
|
15
24
|
const FIRST_RUN_ACTIONS = new Set([
|
|
16
25
|
NoSessionAction.RUN_INIT,
|
|
17
26
|
NoSessionAction.START_DEV_SERVER,
|
|
18
27
|
NoSessionAction.OPEN_APP,
|
|
19
28
|
]);
|
|
29
|
+
/** The answers where an app is up, so the lease can check it now. */
|
|
30
|
+
const LEASABLE_ACTIONS = new Set([
|
|
31
|
+
NoSessionAction.RUN_INIT,
|
|
32
|
+
NoSessionAction.OPEN_APP,
|
|
33
|
+
]);
|
|
34
|
+
const LOCALHOST = 'http://localhost';
|
|
20
35
|
/** The fields only an empty list carries, declared so a schema-aware client does not strip them. */
|
|
21
36
|
export const EMPTY_SESSION_LIST_OUTPUT = {
|
|
22
37
|
why: z
|
|
@@ -36,10 +51,14 @@ export const EMPTY_SESSION_LIST_OUTPUT = {
|
|
|
36
51
|
.string()
|
|
37
52
|
.optional()
|
|
38
53
|
.describe('Present ONLY when `sessions` is empty: a call with the founder for the person you are working with. Offer it; never act on it.'),
|
|
39
|
-
|
|
40
|
-
.
|
|
54
|
+
next_step: z
|
|
55
|
+
.object({
|
|
56
|
+
offered: z.nativeEnum(NextStepOffered),
|
|
57
|
+
lease: z.string().optional(),
|
|
58
|
+
consent: z.string(),
|
|
59
|
+
})
|
|
41
60
|
.optional()
|
|
42
|
-
.describe('
|
|
61
|
+
.describe('Present ONLY when this project is not wired. Nothing was installed and no file changed. `lease` is the call that checks the running app now, with nothing installed: do it first. `consent` is the question for wiring the app for good: ask the user, and run the command only if they agree.'),
|
|
43
62
|
lastKnown: z
|
|
44
63
|
.object({
|
|
45
64
|
sessionId: z.string(),
|
|
@@ -49,63 +68,72 @@ export const EMPTY_SESSION_LIST_OUTPUT = {
|
|
|
49
68
|
.describe('Present ONLY when `sessions` is empty AND a tab was connected to this daemon earlier: the last sessionId and URL that tab was on when it disappeared. A route that 500s tears the page down and the SDK never reconnects — this is the last thing we knew, not a route-500 verdict. An empty list with no lastKnown is a tab that never arrived.'),
|
|
50
69
|
};
|
|
51
70
|
/**
|
|
52
|
-
*
|
|
71
|
+
* The next step for an unwired project, or undefined when the project is wired or cannot be told.
|
|
72
|
+
*
|
|
73
|
+
* The lease leads when an app is up: it checks the change now and installs nothing. When no app
|
|
74
|
+
* is up there is nothing to lease yet, so the consent question leads. Both name the consent
|
|
75
|
+
* question, because only the user can agree to the file changes that `init` makes.
|
|
76
|
+
*/
|
|
77
|
+
function nextStepFor(deps, dir, next) {
|
|
78
|
+
if (next === undefined || !FIRST_RUN_ACTIONS.has(next.action)) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const project = deps.firstRun?.projectDirectory(dir());
|
|
82
|
+
if (project === undefined) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
const consent = wiringConsent(initCommandIn(project));
|
|
86
|
+
const leasable = LEASABLE_ACTIONS.has(next.action) && next.port !== undefined;
|
|
87
|
+
const offered = leasable ? NextStepOffered.LEASE : NextStepOffered.INIT_CONSENT;
|
|
88
|
+
noteNextStepOffered(offered, () => readProjectId(project) !== undefined);
|
|
89
|
+
if (!leasable) {
|
|
90
|
+
return { offered, consent };
|
|
91
|
+
}
|
|
92
|
+
return { offered, lease: zeroInstallLease(`${LOCALHOST}:${String(next.port)}`), consent };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The next step for the calling project when another project's tab is the one connected.
|
|
53
96
|
*
|
|
54
97
|
* The list handler only used to reach {@link emptySessionList} when the daemon's whole list was
|
|
55
98
|
* empty. A live tab in project A then answered project B's first call with A's sessions, and B
|
|
56
|
-
* was
|
|
99
|
+
* never heard that it was not wired.
|
|
57
100
|
*/
|
|
58
|
-
export
|
|
101
|
+
export function nextStepBesideLiveSessions(deps, sessions) {
|
|
59
102
|
const dir = callingClientDirectory();
|
|
60
|
-
if (dir === undefined)
|
|
103
|
+
if (dir === undefined) {
|
|
61
104
|
return undefined;
|
|
105
|
+
}
|
|
62
106
|
const projectId = readProjectId(dir);
|
|
63
107
|
if (projectId !== undefined && sessions.some((session) => session.projectId === projectId)) {
|
|
64
108
|
return undefined;
|
|
65
109
|
}
|
|
66
|
-
|
|
67
|
-
const target = next !== undefined && FIRST_RUN_ACTIONS.has(next.action)
|
|
68
|
-
? deps.firstRun?.projectDirectory(dir)
|
|
69
|
-
: undefined;
|
|
70
|
-
if (target === undefined || deps.firstRun === undefined)
|
|
71
|
-
return undefined;
|
|
72
|
-
return deps.firstRun.wire(target);
|
|
110
|
+
return nextStepFor(deps, () => dir, deps.sessions.noSessionNextAction());
|
|
73
111
|
}
|
|
74
112
|
/** The departed tab for this call: the caller's own project when it named one, else the daemon's newest. */
|
|
75
113
|
function departedForCaller(deps) {
|
|
76
114
|
const dir = callingClientDirectory();
|
|
77
|
-
if (dir === undefined)
|
|
115
|
+
if (dir === undefined) {
|
|
78
116
|
return deps.sessions.lastKnown?.();
|
|
117
|
+
}
|
|
79
118
|
const projectId = readProjectId(dir);
|
|
80
|
-
if (projectId === undefined)
|
|
119
|
+
if (projectId === undefined) {
|
|
81
120
|
return undefined;
|
|
121
|
+
}
|
|
82
122
|
return deps.sessions.lastKnownFor?.(projectId);
|
|
83
123
|
}
|
|
84
|
-
export
|
|
124
|
+
export function emptySessionList(deps, sessions) {
|
|
85
125
|
// The lead and its next action: the full differential (~3 KB of ranked causes) read as
|
|
86
126
|
// speculation on the call an agent makes first. Optional-call: test stubs predate the lead.
|
|
87
127
|
const why = deps.sessions.noSessionLead?.() ?? deps.sessions.noSessionHint();
|
|
88
128
|
// The executable half. `why` is for the human reading the transcript; this is the one the
|
|
89
129
|
// agent acts on, so it never has to parse a paragraph to find a command inside it.
|
|
90
130
|
const next = deps.sessions.noSessionNextAction();
|
|
91
|
-
// The
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
// ponytail: cwd, not an MCP roots/list round trip.
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
// `start_dev_server`, which is the commonest first run of all, and init starts that server itself.
|
|
98
|
-
// `projectDirectory` refuses a project that is already wired, so a wired app is never re-run.
|
|
99
|
-
const dir = next !== undefined && FIRST_RUN_ACTIONS.has(next.action)
|
|
100
|
-
? deps.firstRun?.projectDirectory(callingClientDirectory() ?? dirname(deps.reticleRoot))
|
|
101
|
-
: undefined;
|
|
102
|
-
if (dir !== undefined && deps.firstRun !== undefined) {
|
|
103
|
-
const wired = await deps.firstRun.wire(dir);
|
|
104
|
-
const connected = deps.sessions.list();
|
|
105
|
-
if (wired.ok && 0 < connected.length)
|
|
106
|
-
return { sessions: connected, wired };
|
|
107
|
-
return { sessions, wired, ...(why === undefined ? {} : { why }) };
|
|
108
|
-
}
|
|
131
|
+
// The project the client is in, not the directory the daemon was started in. One daemon serves
|
|
132
|
+
// every project; the proxy names its cwd on the call. With no caller (an embed, a test) it is the
|
|
133
|
+
// daemon's own project. A daemon outside any project offers no step.
|
|
134
|
+
// ponytail: cwd, not an MCP roots/list round trip. Roots are the upgrade when a client launches
|
|
135
|
+
// outside the project but names it.
|
|
136
|
+
const nextStep = nextStepFor(deps, () => callingClientDirectory() ?? dirname(deps.reticleRoot), next);
|
|
109
137
|
// The last tab, when one was here. Optional-call: test stubs of SessionManager predate it.
|
|
110
138
|
const known = departedForCaller(deps);
|
|
111
139
|
const lastKnown = undefined === known ? undefined : { sessionId: known.id, url: known.url };
|
|
@@ -113,6 +141,7 @@ export async function emptySessionList(deps, sessions) {
|
|
|
113
141
|
sessions,
|
|
114
142
|
...(why === undefined ? {} : { why }),
|
|
115
143
|
...(next === undefined ? {} : { next_action: next }),
|
|
144
|
+
...(nextStep === undefined ? {} : { next_step: nextStep }),
|
|
116
145
|
...(undefined === lastKnown ? {} : { lastKnown }),
|
|
117
146
|
// Setup that never connects is where most people give up; it is the talk worth having.
|
|
118
147
|
talk_to_us: DiscoveryInvite.AGENT,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* on stable, human-authored substrings of the thrown messages (see session-manager.ts, the flow/
|
|
9
9
|
* baseline stores). No clock, no IO — unit-testable in isolation.
|
|
10
10
|
*/
|
|
11
|
-
import { RefusalReason } from '@reticlehq/core';
|
|
11
|
+
import { RefusalReason, type CodedRefusal } from '@reticlehq/core';
|
|
12
12
|
/** The recovery hints, named so they are not free strings and can be asserted in tests. */
|
|
13
13
|
export declare const RECOVERY: {
|
|
14
14
|
readonly NO_SESSION: string;
|
|
@@ -41,6 +41,7 @@ export declare const RECOVERY: {
|
|
|
41
41
|
*/
|
|
42
42
|
readonly AMBIGUOUS_TARGET: string;
|
|
43
43
|
readonly NO_SUCH_OPTION: string;
|
|
44
|
+
readonly PRODUCTION_POLICY: string;
|
|
44
45
|
readonly BAD_ARGUMENTS: string;
|
|
45
46
|
readonly WRONG_TARGET: string;
|
|
46
47
|
readonly NOT_EDITABLE: string;
|
|
@@ -54,9 +55,10 @@ export declare const RECOVERY: {
|
|
|
54
55
|
* something that is not a top-level parameter is the whole distance between a one-line retry and
|
|
55
56
|
* a lost budget.
|
|
56
57
|
*
|
|
57
|
-
* The classifier
|
|
58
|
-
*
|
|
59
|
-
*
|
|
58
|
+
* The classifier also stops a control that moves money, which is not "destructive". Naming the
|
|
59
|
+
* real trigger words here keeps a refusal on a "Pay" button from reading as a malfunction. Only
|
|
60
|
+
* words the classifier matches are named: `deploy` and `publish` are excluded on purpose (see
|
|
61
|
+
* `core/src/verdict/security.ts`).
|
|
60
62
|
*/
|
|
61
63
|
readonly CONFIRM_DANGEROUS: string;
|
|
62
64
|
readonly UNSUPPORTED_SURFACE: string;
|
|
@@ -85,7 +87,6 @@ export declare const RECOVERY: {
|
|
|
85
87
|
* agent's malformed call: it was then told to fix arguments that were never wrong.
|
|
86
88
|
*/
|
|
87
89
|
readonly HARNESS_LOCKED: string;
|
|
88
|
-
readonly HARNESS_NOT_LINKED: string;
|
|
89
90
|
};
|
|
90
91
|
/**
|
|
91
92
|
* The actionable next move for a known error message, or undefined when none is recognized.
|
|
@@ -104,7 +105,7 @@ export declare function recoveryFor(message: string): string | undefined;
|
|
|
104
105
|
* is the bucket that says the classifier has a blind spot — and a growing `other` is a finding about
|
|
105
106
|
* this table rather than about anybody's app.
|
|
106
107
|
*/
|
|
107
|
-
export declare function refusalReasonFor(rawMessage: string): RefusalReason;
|
|
108
|
+
export declare function refusalReasonFor(rawMessage: string, coded?: CodedRefusal): RefusalReason;
|
|
108
109
|
/**
|
|
109
110
|
* The ask attached to errors we do NOT recognize. An unrecognized error is, by definition, the case
|
|
110
111
|
* where Reticle failed in a way nobody anticipated — the single highest-value moment to hear from the
|
|
@@ -120,11 +121,20 @@ interface ErrorPayload {
|
|
|
120
121
|
error: string;
|
|
121
122
|
recovery?: string;
|
|
122
123
|
feedback?: string;
|
|
124
|
+
/** A coded refusal: what it is, and who does what next, as data. */
|
|
125
|
+
code?: CodedRefusal['code'];
|
|
126
|
+
next?: CodedRefusal['next'];
|
|
123
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* The code and next steps a thrown refusal carries (`HarnessNotLinkedError`), or undefined. Read from
|
|
130
|
+
* the error itself, so a refusal is recognized by its code and never by a regular expression over
|
|
131
|
+
* its sentence: the not-linked refusal was matched by its prose, and the prose was rewritten.
|
|
132
|
+
*/
|
|
133
|
+
export declare function codedRefusalOf(error: unknown): CodedRefusal | undefined;
|
|
124
134
|
/**
|
|
125
135
|
* Build the tool-error payload spliced at the MCP boundary. `recovery` is added when the error is
|
|
126
136
|
* known; the feedback ask is added when it is NOT — the two are mutually exclusive by design, so the
|
|
127
137
|
* agent always gets exactly one next move.
|
|
128
138
|
*/
|
|
129
|
-
export declare function buildErrorPayload(rawMessage: string): ErrorPayload;
|
|
139
|
+
export declare function buildErrorPayload(rawMessage: string, coded?: CodedRefusal): ErrorPayload;
|
|
130
140
|
export {};
|
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
* on stable, human-authored substrings of the thrown messages (see session-manager.ts, the flow/
|
|
9
9
|
* baseline stores). No clock, no IO — unit-testable in isolation.
|
|
10
10
|
*/
|
|
11
|
-
import { RefusalReason, ReticleEnv, TRANSPORT_LIMITS, UNISSUED_REF_REFUSAL } from '@reticlehq/core';
|
|
11
|
+
import { CodedRefusalSchema, PRODUCTION_REFUSAL_PREFIX, RefusalCode, RefusalReason, ReticleEnv, TRANSPORT_LIMITS, UNISSUED_REF_REFUSAL, } from '@reticlehq/core';
|
|
12
12
|
import { SELF_RECOVERING_MARKER } from '../../portal/session/no-session-diagnosis.js';
|
|
13
13
|
import { MSG_HARNESS_DISABLED, MSG_HARNESS_UNCLAIMED, MSG_HARNESS_UNCONFIRMED, PlatformRefusalCode, RefusalLead, } from '../../features/harness/platform/refusal.js';
|
|
14
14
|
import { BODY_CLAUSE_REFUSAL_OPENING } from '@reticlehq/engine/evidence/body-capture-remedy.js';
|
|
15
|
+
import { EMPTY_FIND_OPENING } from './read/query-shape.js';
|
|
16
|
+
import { UNKNOWN_FLOW_OPENING } from '../../language/flows/suite-selection.js';
|
|
15
17
|
import { CHROMIUM_PATH_REFUSAL_PREFIX, chromiumInstallCommand, bundledPlaywrightVersion, } from '../../command/cli/doctor/browser/chromium-hint.js';
|
|
16
18
|
/** Marks where an over-long message had its middle removed. Named so tests assert it by value. */
|
|
17
19
|
const ELISION = '… [elided] …';
|
|
@@ -64,6 +66,10 @@ const SELF_RECOVERING = [
|
|
|
64
66
|
// was collecting the defect ask on top of its own remedy, so the envelope contradicted itself and
|
|
65
67
|
// asked for a bug report about somebody's connect() options.
|
|
66
68
|
{ match: literally(BODY_CLAUSE_REFUSAL_OPENING), reason: RefusalReason.UNSUPPORTED },
|
|
69
|
+
// A find with nothing to find names the fields to pass; an unknown flow name lists the saved ones.
|
|
70
|
+
// Both are the caller's to fix, and the defect ask on top told an agent to file a bug about them.
|
|
71
|
+
{ match: literally(EMPTY_FIND_OPENING), reason: RefusalReason.BAD_ARGS },
|
|
72
|
+
{ match: literally(UNKNOWN_FLOW_OPENING), reason: RefusalReason.NO_MATCH },
|
|
67
73
|
];
|
|
68
74
|
/**
|
|
69
75
|
* The refusal for a `ref` Reticle never minted — decided BEFORE every other rule, not by one inside
|
|
@@ -158,6 +164,11 @@ export const RECOVERY = {
|
|
|
158
164
|
'and the change event that follows has been observed persisting an empty setting into the app. ' +
|
|
159
165
|
'Retry with one of the listed values — note they are option VALUES, which often differ from the ' +
|
|
160
166
|
'visible labels shown in brackets. This is an invalid call, not a Reticle defect.',
|
|
167
|
+
PRODUCTION_POLICY: 'The production policy refused this act before it reached the site, and nothing was done. The ' +
|
|
168
|
+
'call itself was valid. Do not retry it: the policy refuses it every time. Leave this step out, ' +
|
|
169
|
+
'or, when the message names an intent, end the lease and acquire a new one whose ' +
|
|
170
|
+
'`production.intent` names the action. This is a refusal by design, not a Reticle defect: there ' +
|
|
171
|
+
'is nothing to report.',
|
|
161
172
|
BAD_ARGUMENTS: "That call did not match the tool's schema — the message above names the tool and the exact " +
|
|
162
173
|
"argument it wanted. Re-read that tool's parameters and retry with the missing or corrected " +
|
|
163
174
|
'argument. This is an invalid call, not a Reticle defect: there is nothing to report.',
|
|
@@ -181,12 +192,13 @@ export const RECOVERY = {
|
|
|
181
192
|
* something that is not a top-level parameter is the whole distance between a one-line retry and
|
|
182
193
|
* a lost budget.
|
|
183
194
|
*
|
|
184
|
-
* The classifier
|
|
185
|
-
*
|
|
186
|
-
*
|
|
195
|
+
* The classifier also stops a control that moves money, which is not "destructive". Naming the
|
|
196
|
+
* real trigger words here keeps a refusal on a "Pay" button from reading as a malfunction. Only
|
|
197
|
+
* words the classifier matches are named: `deploy` and `publish` are excluded on purpose (see
|
|
198
|
+
* `core/src/verdict/security.ts`).
|
|
187
199
|
*/
|
|
188
|
-
CONFIRM_DANGEROUS: 'Reticle blocked a control whose label reads as consequential (delete, remove, revoke,
|
|
189
|
-
'
|
|
200
|
+
CONFIRM_DANGEROUS: 'Reticle blocked a control whose label reads as consequential (delete, remove, revoke, pay…) ' +
|
|
201
|
+
'on purpose. If you mean it, send the SAME call again with ' +
|
|
190
202
|
'`args: { confirmDangerous: true }` — it goes inside the `args` object, not beside it. This is ' +
|
|
191
203
|
'a deliberate refusal, not a defect: there is nothing to report.',
|
|
192
204
|
UNSUPPORTED_SURFACE: 'That surface is not supported yet, and Reticle refuses rather than pretending — a rich-text ' +
|
|
@@ -260,13 +272,9 @@ export const RECOVERY = {
|
|
|
260
272
|
* the refusal names reticle_act_and_wait as the alternative, which the catch-all below read as an
|
|
261
273
|
* agent's malformed call: it was then told to fix arguments that were never wrong.
|
|
262
274
|
*/
|
|
263
|
-
HARNESS_LOCKED: '
|
|
264
|
-
'
|
|
265
|
-
'
|
|
266
|
-
HARNESS_NOT_LINKED: 'This project is not linked to the Reticle platform, where the Harness runs. The call itself was ' +
|
|
267
|
-
'valid. Either the human runs `npx @reticlehq/server connect` once in the app directory, or you ' +
|
|
268
|
-
'drive the journey yourself: reticle_navigate, then reticle_act_and_wait with an `until` on its ' +
|
|
269
|
-
'last step. There is nothing to report.',
|
|
275
|
+
HARNESS_LOCKED: 'An older Reticle platform locked the Harness on its setup score. Nothing to report: drive the ' +
|
|
276
|
+
'journey yourself with reticle_act_and_wait and an `until` on its last step. Every tool works ' +
|
|
277
|
+
'at any coverage.',
|
|
270
278
|
};
|
|
271
279
|
/**
|
|
272
280
|
* Which OWNER each recovery belongs to, for `tool_refused`.
|
|
@@ -305,12 +313,12 @@ const REASON_OF = {
|
|
|
305
313
|
NOT_EDITABLE: RefusalReason.UNSUPPORTED,
|
|
306
314
|
CONFIRM_DANGEROUS: RefusalReason.UNSUPPORTED,
|
|
307
315
|
WRONG_TARGET: RefusalReason.UNSUPPORTED,
|
|
316
|
+
// The call was valid; the drive's policy refuses what it asked for, as for a destructive control.
|
|
317
|
+
PRODUCTION_POLICY: RefusalReason.UNSUPPORTED,
|
|
308
318
|
BAD_ARGUMENTS: RefusalReason.BAD_ARGS,
|
|
309
319
|
INVALID_NAME: RefusalReason.BAD_ARGS,
|
|
310
320
|
// Nothing about the app or the call is wrong; the feature is switched off or unpaid for.
|
|
311
321
|
HARNESS_OFF: RefusalReason.UNSUPPORTED,
|
|
312
|
-
// Nothing about the call is wrong either; the project is not linked yet.
|
|
313
|
-
HARNESS_NOT_LINKED: RefusalReason.UNSUPPORTED,
|
|
314
322
|
// The call is valid; the app is not instrumented enough for the Harness yet.
|
|
315
323
|
HARNESS_LOCKED: RefusalReason.UNSUPPORTED,
|
|
316
324
|
};
|
|
@@ -349,11 +357,10 @@ const RULES = [
|
|
|
349
357
|
// platform's: matching it is matching ourselves.
|
|
350
358
|
{ match: /credits are used\./, hint: RECOVERY.HARNESS_OFF },
|
|
351
359
|
{
|
|
352
|
-
//
|
|
353
|
-
match: new RegExp(
|
|
360
|
+
// An older platform's "locked": an expected state, not a defect.
|
|
361
|
+
match: new RegExp(`^${escapeRegExp(RefusalLead[PlatformRefusalCode.HARNESS_LOCKED])}`),
|
|
354
362
|
hint: RECOVERY.HARNESS_LOCKED,
|
|
355
363
|
},
|
|
356
|
-
{ match: /The Reticle Harness runs on the Reticle platform/, hint: RECOVERY.HARNESS_NOT_LINKED },
|
|
357
364
|
// Three conditions the daemon understands perfectly and still asked for a bug report about. Each
|
|
358
365
|
// needs its own rule: none of them contains "no browser session connected" (the scope miss is
|
|
359
366
|
// "no browser session FOR project 'x'", which is the opposite claim — sessions exist).
|
|
@@ -412,6 +419,8 @@ const RULES = [
|
|
|
412
419
|
match: /target matched \d+ elements and an action must not guess/i,
|
|
413
420
|
hint: RECOVERY.AMBIGUOUS_TARGET,
|
|
414
421
|
},
|
|
422
|
+
// Before the catch-all: every refusal names `reticle_lease`, and the call was valid.
|
|
423
|
+
{ match: new RegExp(`^${PRODUCTION_REFUSAL_PREFIX}`), hint: RECOVERY.PRODUCTION_POLICY },
|
|
415
424
|
// Authored by Reticle, about the caller's arguments: the message already names the valid answers.
|
|
416
425
|
{ match: /^unknown action '/i, hint: RECOVERY.BAD_ARGUMENTS },
|
|
417
426
|
{ match: /^unsupported query strategy '/i, hint: RECOVERY.BAD_ARGUMENTS },
|
|
@@ -473,7 +482,9 @@ export function recoveryFor(message) {
|
|
|
473
482
|
* is the bucket that says the classifier has a blind spot — and a growing `other` is a finding about
|
|
474
483
|
* this table rather than about anybody's app.
|
|
475
484
|
*/
|
|
476
|
-
export function refusalReasonFor(rawMessage) {
|
|
485
|
+
export function refusalReasonFor(rawMessage, coded) {
|
|
486
|
+
if (coded !== undefined)
|
|
487
|
+
return REASON_OF_CODE[coded.code];
|
|
477
488
|
const message = zodArrayAsSentence(rawMessage);
|
|
478
489
|
if (isUnissuedRefRefusal(message))
|
|
479
490
|
return RefusalReason.BAD_ARGS;
|
|
@@ -591,15 +602,37 @@ const INVALID_NAME_REJECTION = /^invalid (?:[a-z]+ )*name: /i;
|
|
|
591
602
|
export const FEEDBACK_ASK = 'This error is not one Reticle recognizes, which means it may be a defect in Reticle rather than in ' +
|
|
592
603
|
'the app. If you believe Reticle misbehaved, call reticle_session { action: "feedback" } with a root-cause analysis and ' +
|
|
593
604
|
'the call trace before moving on — that report is the only way this gets fixed.';
|
|
605
|
+
/** Which owner each coded refusal belongs to, for `tool_refused`. */
|
|
606
|
+
const REASON_OF_CODE = {
|
|
607
|
+
// Nothing about the call is wrong; the project is not linked yet.
|
|
608
|
+
[RefusalCode.HARNESS_NOT_LINKED]: RefusalReason.UNSUPPORTED,
|
|
609
|
+
};
|
|
610
|
+
/**
|
|
611
|
+
* The code and next steps a thrown refusal carries (`HarnessNotLinkedError`), or undefined. Read from
|
|
612
|
+
* the error itself, so a refusal is recognized by its code and never by a regular expression over
|
|
613
|
+
* its sentence: the not-linked refusal was matched by its prose, and the prose was rewritten.
|
|
614
|
+
*/
|
|
615
|
+
export function codedRefusalOf(error) {
|
|
616
|
+
if (!(error instanceof Error))
|
|
617
|
+
return undefined;
|
|
618
|
+
const parsed = CodedRefusalSchema.safeParse({
|
|
619
|
+
code: 'code' in error ? error.code : undefined,
|
|
620
|
+
next: 'next' in error ? error.next : undefined,
|
|
621
|
+
});
|
|
622
|
+
return parsed.success ? parsed.data : undefined;
|
|
623
|
+
}
|
|
594
624
|
/**
|
|
595
625
|
* Build the tool-error payload spliced at the MCP boundary. `recovery` is added when the error is
|
|
596
626
|
* known; the feedback ask is added when it is NOT — the two are mutually exclusive by design, so the
|
|
597
627
|
* agent always gets exactly one next move.
|
|
598
628
|
*/
|
|
599
|
-
export function buildErrorPayload(rawMessage) {
|
|
629
|
+
export function buildErrorPayload(rawMessage, coded) {
|
|
600
630
|
// Render the zod array BEFORE capping: the cap would otherwise truncate the JSON mid-issue and
|
|
601
631
|
// leave an unparseable fragment as the agent's error text — the worst of both shapes.
|
|
602
632
|
const message = capMessage(zodArrayAsSentence(rawMessage));
|
|
633
|
+
// A coded refusal says who does what next itself: no hint beside it, and no bug-report ask.
|
|
634
|
+
if (coded !== undefined)
|
|
635
|
+
return { error: message, code: coded.code, next: coded.next };
|
|
603
636
|
if (isUnissuedRefRefusal(message))
|
|
604
637
|
return { error: message, recovery: RECOVERY.UNISSUED_REF };
|
|
605
638
|
// A self-diagnosing message gets NEITHER a generic recovery nor the feedback ask. It already
|
|
@@ -30,6 +30,16 @@ export type ExploreDrive = (deps: ToolDeps, env: Record<string, string | undefin
|
|
|
30
30
|
* with the drive already running rather than paying for another.
|
|
31
31
|
*/
|
|
32
32
|
export declare function answerExplore(deps: ToolDeps, args: Record<string, unknown>, call: ToolCall | undefined, drive: ExploreDrive): Promise<unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* What a finished drive asks of the agent that reads it: a failed check is a defect to fix, and the
|
|
35
|
+
* fix is proved only when the same drive runs again. Without it the agent read "1 failed" and stopped.
|
|
36
|
+
*/
|
|
37
|
+
export declare function fixRequest(result: Record<string, unknown>): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* The platform's failed checks, each verbatim, read from its run summary. A plan run leaves the
|
|
40
|
+
* driver's account out of the answer, and with it went "totalCents 16700, the claim says 13360".
|
|
41
|
+
*/
|
|
42
|
+
export declare function platformFindings(summary: string): string[];
|
|
33
43
|
/** The tool's answer for a finished drive. */
|
|
34
44
|
export declare function exploreReport(explored: ExploreResult): Record<string, unknown>;
|
|
35
45
|
/**
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* Those flows are the point. From the second run onwards `reticle_verify { action: "flows" }` replays
|
|
11
11
|
* them deterministically with no model in the loop at all.
|
|
12
12
|
*/
|
|
13
|
+
import { HarnessRunReason } from '@reticlehq/core/telemetry';
|
|
13
14
|
import { z } from 'zod';
|
|
14
15
|
import { randomUUID } from 'node:crypto';
|
|
15
16
|
import { join } from 'node:path';
|
|
@@ -27,7 +28,7 @@ import { RESULT_FIELD, exploreResult, resultField } from './reticle-result.js';
|
|
|
27
28
|
import { runTool } from './invoke-tool.js';
|
|
28
29
|
import { harnessRunSource, reportHarnessBlocked, reportHarnessRun, } from '../../telemetry/harness-run.js';
|
|
29
30
|
import { driveVerdict } from '../../features/harness/platform/remote-drive.js';
|
|
30
|
-
import {
|
|
31
|
+
import { harnessStartRefusal, firstLine, exploreApp, harnessAvailable, withLinkedCredential, HarnessNotLinkedError, } from './harness-explore.js';
|
|
31
32
|
import { EXPLORE_NEEDS } from '../../features/harness/drivers.js';
|
|
32
33
|
import { checkTally, describeDrive, replayedFlows, runProved, } from '../../features/harness/drive-report.js';
|
|
33
34
|
import { StopReason } from '../../features/harness/harness.js';
|
|
@@ -36,7 +37,7 @@ export const WAIT_MAX_S = 240;
|
|
|
36
37
|
export const EXPLORE_TOOLS = [
|
|
37
38
|
{
|
|
38
39
|
name: ReticleTool.VERIFY_EXPLORE,
|
|
39
|
-
description: 'Drive the app yourself? Do not — call this instead. The Reticle Harness drives it through this same tool surface (it decides on the Reticle platform, this daemon executes each step), records what it drove as saved flows, and answers in a few lines instead of a context full of snapshots: within `wait` seconds, the result or { status: "running", runId } to poll with `runId`. Never start a second. Pass `persona` to say who to be or what to accomplish ("a returning customer checking out", "an admin revoking a seat") and it completes that whole journey rather than clicking at random. The saved flows are the point: from the next run on, reticle_verify { action: "flows" } replays them deterministically with NO model in the loop. DESTRUCTIVE — it really drives the app, and it spends
|
|
40
|
+
description: 'Drive the app yourself? Do not — call this instead. The Reticle Harness drives it through this same tool surface (it decides on the Reticle platform, this daemon executes each step), records what it drove as saved flows, and answers in a few lines instead of a context full of snapshots: within `wait` seconds, the result or { status: "running", runId } to poll with `runId`. Never start a second. Pass `persona` to say who to be or what to accomplish ("a returning customer checking out", "an admin revoking a seat") and it completes that whole journey rather than clicking at random. The saved flows are the point: from the next run on, reticle_verify { action: "flows" } replays them deterministically with NO model in the loop. DESTRUCTIVE — it really drives the app, and it spends credits. ' +
|
|
40
41
|
EXPLORE_NEEDS,
|
|
41
42
|
inputSchema: {
|
|
42
43
|
persona: z
|
|
@@ -54,14 +55,15 @@ export const EXPLORE_TOOLS = [
|
|
|
54
55
|
.string()
|
|
55
56
|
.optional()
|
|
56
57
|
.describe('Active session ID from reticle_sessions. Omit when only one browser session is open.'),
|
|
57
|
-
driveId: z.string().optional(),
|
|
58
|
-
// Bare on purpose: the description and every `running` answer say how to poll, and this
|
|
59
|
-
// schema is re-sent on every turn of every session.
|
|
58
|
+
driveId: z.string().optional().describe('The drive id an explore call answered with.'),
|
|
60
59
|
wait: z.number().min(0).max(WAIT_MAX_S).optional().describe('Seconds; default 50.'),
|
|
61
|
-
runId: z
|
|
60
|
+
runId: z
|
|
61
|
+
.string()
|
|
62
|
+
.optional()
|
|
63
|
+
.describe('The run id an explore call answered with; pass it to poll that run.'),
|
|
62
64
|
planId: z.string().optional().describe('Run a plan saved on the dashboard, as it stands.'),
|
|
63
|
-
stop: z.boolean().optional(),
|
|
64
|
-
say: z.string().optional(),
|
|
65
|
+
stop: z.boolean().optional().describe('With runId: stop that Harness run.'),
|
|
66
|
+
say: z.string().optional().describe('With runId: a note to the running Harness.'),
|
|
65
67
|
},
|
|
66
68
|
// Everything the handler returns has to be declared, or a schema-aware client never sees it.
|
|
67
69
|
// Optional throughout: a drive still running answers only its status, id and progress.
|
|
@@ -76,7 +78,7 @@ export const EXPLORE_TOOLS = [
|
|
|
76
78
|
next: z.object({ action: z.string(), runId: z.string() }).optional(),
|
|
77
79
|
/** Seconds since the drive started, while it runs. */
|
|
78
80
|
elapsedS: z.number().optional(),
|
|
79
|
-
/** While it runs: poll again
|
|
81
|
+
/** While it runs: poll again. Once it ended with a failed check: fix the code, then drive again. */
|
|
80
82
|
instruction: z.string().optional(),
|
|
81
83
|
stopReason: z.string().optional(),
|
|
82
84
|
/** Which driver actually drove, so a comparison can never misattribute its own result. */
|
|
@@ -127,6 +129,11 @@ export const EXPLORE_TOOLS = [
|
|
|
127
129
|
* at its end, which a caller that only shows the verdict otherwise cannot tell anybody.
|
|
128
130
|
*/
|
|
129
131
|
driverAccount: z.string().optional(),
|
|
132
|
+
/**
|
|
133
|
+
* The platform's own failed checks, verbatim: what was expected, what was observed, on which
|
|
134
|
+
* request. The fix request quotes them, so the agent knows exactly what to fix.
|
|
135
|
+
*/
|
|
136
|
+
findings: z.array(z.string()).optional(),
|
|
130
137
|
/** Present when the drive broke: a model that would not answer, a wedged browser. */
|
|
131
138
|
error: z.string().optional(),
|
|
132
139
|
/** What the drive cost, cache hits included, so an expensive run is visible rather than felt. */
|
|
@@ -196,7 +203,7 @@ export async function answerExplore(deps, args, call, drive) {
|
|
|
196
203
|
// Billed to the one free drive the platform granted, never to another.
|
|
197
204
|
...('string' === typeof driveId ? { [ReticleEnv.DRIVE_ID]: driveId } : {}),
|
|
198
205
|
};
|
|
199
|
-
// The
|
|
206
|
+
// The build check first: it is local, and the one thing to fix before anything else matters.
|
|
200
207
|
// Not for a saved plan that only replays flows (no model turn to guard), and a plan it refuses
|
|
201
208
|
// is told so, so the plan's history records the attempt.
|
|
202
209
|
const planId = str(args['planId']);
|
|
@@ -213,17 +220,16 @@ export async function answerExplore(deps, args, call, drive) {
|
|
|
213
220
|
source: harnessRunSource(origin, planId),
|
|
214
221
|
hosted: platform !== undefined,
|
|
215
222
|
};
|
|
216
|
-
const locked = replayOnly ? undefined : await
|
|
217
|
-
if (locked !== undefined)
|
|
218
|
-
reportHarnessBlocked(runStart);
|
|
223
|
+
const locked = replayOnly ? undefined : await harnessStartRefusal(deps, sessionId);
|
|
219
224
|
if (locked !== undefined) {
|
|
225
|
+
reportHarnessBlocked(runStart, locked.reason);
|
|
220
226
|
if (planId !== undefined && platform !== undefined)
|
|
221
|
-
await reportPlanBlocked(platform, planId, firstLine(locked));
|
|
222
|
-
throw new Error(locked);
|
|
227
|
+
await reportPlanBlocked(platform, planId, firstLine(locked.text));
|
|
228
|
+
throw new Error(locked.text);
|
|
223
229
|
}
|
|
224
230
|
if (!harnessAvailable(env)) {
|
|
225
|
-
reportHarnessBlocked(runStart);
|
|
226
|
-
throw new
|
|
231
|
+
reportHarnessBlocked(runStart, HarnessRunReason.NOT_LINKED);
|
|
232
|
+
throw new HarnessNotLinkedError();
|
|
227
233
|
}
|
|
228
234
|
const harness = randomUUID();
|
|
229
235
|
const runId = harnessRunId(harness);
|
|
@@ -260,12 +266,56 @@ async function answerDrive(deps, runId, waitMs, call, sessionId, refuseBroken) {
|
|
|
260
266
|
instruction: stillRunning(runId, record.steps, elapsedS),
|
|
261
267
|
};
|
|
262
268
|
}
|
|
263
|
-
if (record.result !== undefined)
|
|
264
|
-
|
|
269
|
+
if (record.result !== undefined) {
|
|
270
|
+
const fix = fixRequest(record.result);
|
|
271
|
+
return {
|
|
272
|
+
status: record.status,
|
|
273
|
+
runId,
|
|
274
|
+
...record.result,
|
|
275
|
+
...(fix === undefined ? {} : { instruction: fix }),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
265
278
|
if (refuseBroken && record.error !== undefined)
|
|
266
279
|
throw new Error(record.error);
|
|
267
280
|
return { status: record.status, runId, steps: record.steps, error: record.error ?? 'no result' };
|
|
268
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* What a finished drive asks of the agent that reads it: a failed check is a defect to fix, and the
|
|
284
|
+
* fix is proved only when the same drive runs again. Without it the agent read "1 failed" and stopped.
|
|
285
|
+
*/
|
|
286
|
+
export function fixRequest(result) {
|
|
287
|
+
const failed = asRecord(result['checks'])['failed'];
|
|
288
|
+
const findings = Array.isArray(result['findings'])
|
|
289
|
+
? result['findings'].filter((f) => 'string' === typeof f)
|
|
290
|
+
: [];
|
|
291
|
+
const rerun = 'Fix the code, then start the same drive again (the same persona or planId) to verify the fix. ' +
|
|
292
|
+
'Do not report it fixed before that drive passes.';
|
|
293
|
+
if (0 < findings.length)
|
|
294
|
+
return `The Harness found a defect: ${findings.join(' ')} ${rerun}`;
|
|
295
|
+
if ('number' === typeof failed && failed >= 1)
|
|
296
|
+
return (`The Harness found a defect: ${String(failed)} check${1 === failed ? '' : 's'} failed. Read ` +
|
|
297
|
+
`\`summary\` and \`goals\` for what failed. ${rerun}`);
|
|
298
|
+
// A drive that ran to its end and still missed its goal is not a pass either: on the broken
|
|
299
|
+
// checkout every check held while the order went out at full price. It is a lead, not a verdict,
|
|
300
|
+
// so the agent is asked to find out which, not told there is a defect.
|
|
301
|
+
if (StopReason.FINISHED === result['stopReason'] && false === result['goalMet'])
|
|
302
|
+
return ('The Harness drive did not reach its goal, so nothing is proved. Read `summary` and check the ' +
|
|
303
|
+
'outcome the goal names (for example the request body with reticle_observe). If it shows a ' +
|
|
304
|
+
'defect, fix the code, then start the same drive again (the same persona or planId) to verify ' +
|
|
305
|
+
'the fix. Do not report it fixed before that drive passes.');
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
/** How the platform opens a check it failed in a drive's summary: "Not proved: <what, where>". */
|
|
309
|
+
const PLATFORM_FAILED = /Not proved: ([^\n]+)/g;
|
|
310
|
+
/** How the answer's summary says one of them. */
|
|
311
|
+
const FINDING_LEAD = 'Failed on the platform:';
|
|
312
|
+
/**
|
|
313
|
+
* The platform's failed checks, each verbatim, read from its run summary. A plan run leaves the
|
|
314
|
+
* driver's account out of the answer, and with it went "totalCents 16700, the claim says 13360".
|
|
315
|
+
*/
|
|
316
|
+
export function platformFindings(summary) {
|
|
317
|
+
return [...summary.matchAll(PLATFORM_FAILED)].flatMap((m) => m[1] === undefined ? [] : [m[1].trim()]);
|
|
318
|
+
}
|
|
269
319
|
/** A run this machine no longer holds, from the platform it synced to. */
|
|
270
320
|
async function fromPlatform(deps, runId) {
|
|
271
321
|
const platform = serverOptionsFromEnv(await withLinkedCredential(deps, process.env));
|
|
@@ -354,8 +404,10 @@ const exploreDrive = async (deps, env, args, harness, control) => {
|
|
|
354
404
|
export function exploreReport(explored) {
|
|
355
405
|
const { drive, savedFlows, rewroteFlows, unverifiedFlows, driverName, plan, goals, planLines, runIds, runUrl, journeys, planId, planUrl, disparity, } = explored;
|
|
356
406
|
const checks = checkTally(drive.toolCalls);
|
|
407
|
+
const findings = platformFindings(drive.summary);
|
|
357
408
|
return {
|
|
358
409
|
stopReason: drive.stopReason,
|
|
410
|
+
...(0 === findings.length ? {} : { findings }),
|
|
359
411
|
driver: driverName,
|
|
360
412
|
steps: drive.steps,
|
|
361
413
|
savedFlows: [...savedFlows],
|
|
@@ -395,6 +447,7 @@ export function exploreReport(explored) {
|
|
|
395
447
|
...(planLines ?? []),
|
|
396
448
|
describeDrive(drive.toolCalls, [...savedFlows, ...rewroteFlows], unverifiedFlows, drive.goalMet, journeys),
|
|
397
449
|
...[unprovedGoals(goals)].filter((line) => line !== undefined),
|
|
450
|
+
...findings.map((finding) => `${FINDING_LEAD} ${finding}`),
|
|
398
451
|
].join('\n'),
|
|
399
452
|
// Not beside a platform plan: its lanes' accounts count saves the platform asked for ("saved 3
|
|
400
453
|
// flow(s)") where `savedFlows` lists what is on disk, and an answer has one count. Each journey's
|