@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,5 +1,5 @@
|
|
|
1
|
-
import { ActionType,
|
|
2
|
-
import {
|
|
1
|
+
import { ActionType, QueryBy, REPLAY_PROGRAM_VERSION, asFlowName, defaultIsSensitiveKey, } from '@reticlehq/core';
|
|
2
|
+
import { journeySentence } from '@reticlehq/core';
|
|
3
3
|
/**
|
|
4
4
|
* What a session drove, saved as a replayable flow — without anybody asking for it.
|
|
5
5
|
*
|
|
@@ -23,45 +23,12 @@ const segment = (value, max) => value
|
|
|
23
23
|
.slice(0, max)
|
|
24
24
|
.replace(/-$/, '');
|
|
25
25
|
/**
|
|
26
|
-
* What
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* happened in its own words, a request is the next best, a store read is one step removed, and the
|
|
30
|
-
* DOM-shaped claims are the weakest. Naming a flow after the strongest thing it proves is the same
|
|
31
|
-
* judgement the honesty grade makes, reused where a human reads it.
|
|
32
|
-
*
|
|
33
|
-
* Returns '' when a step claims nothing nameable.
|
|
26
|
+
* What a journey proved, in one sentence, when no step declared why it was driven. An auto-saved
|
|
27
|
+
* drive was named by its request path and a hash ("drive-get-v1-runs-issues-c69f82") and its file
|
|
28
|
+
* said nothing about what it was for.
|
|
34
29
|
*/
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
const expect = step.expect;
|
|
38
|
-
if (expect === undefined)
|
|
39
|
-
continue;
|
|
40
|
-
// A predicate names its kind, so the slug reads the tree rather than probing a struct. The
|
|
41
|
-
// signal wins over the request for the same reason it always did: it is the app saying what it
|
|
42
|
-
// did, which is the strongest thing a name can carry.
|
|
43
|
-
const signal = clauseOfKind(expect, PredicateKind.SIGNAL);
|
|
44
|
-
if (signal?.name !== undefined)
|
|
45
|
-
return segment(signal.name, 32);
|
|
46
|
-
const netClause = clauseOfKind(expect, PredicateKind.NET);
|
|
47
|
-
if (netClause !== undefined) {
|
|
48
|
-
const method = segment(netClause.method ?? '', 6);
|
|
49
|
-
const where = segment(netClause.urlContains ?? '', 24);
|
|
50
|
-
const joined = [method, where].filter((part) => '' !== part).join('-');
|
|
51
|
-
if ('' !== joined)
|
|
52
|
-
return joined;
|
|
53
|
-
}
|
|
54
|
-
const state = clauseOfKind(expect, PredicateKind.STATE);
|
|
55
|
-
if (state !== undefined)
|
|
56
|
-
return segment(state.path, 32);
|
|
57
|
-
const route = clauseOfKind(expect, PredicateKind.ROUTE);
|
|
58
|
-
if (route?.pathname !== undefined)
|
|
59
|
-
return segment(route.pathname, 24);
|
|
60
|
-
const text = clauseOfKind(expect, PredicateKind.TEXT);
|
|
61
|
-
if (text?.contains !== undefined)
|
|
62
|
-
return segment(text.contains, 24);
|
|
63
|
-
}
|
|
64
|
-
return '';
|
|
30
|
+
function provedSentence(steps) {
|
|
31
|
+
return journeySentence(steps.flatMap((step) => (step.expect === undefined ? [] : [step.expect])));
|
|
65
32
|
}
|
|
66
33
|
/** Every auto-saved flow's name starts here, which is what lets a merge tell them from hand-named ones. */
|
|
67
34
|
export const DRIVE_FLOW_PREFIX = 'drive-';
|
|
@@ -81,7 +48,7 @@ export function driveFlowName(route, steps = []) {
|
|
|
81
48
|
const intent = steps.find((step) => step.intent !== undefined)?.intent;
|
|
82
49
|
const leg = segment(route ?? '', 24);
|
|
83
50
|
const why = intent === undefined ? '' : segment(intent, 48);
|
|
84
|
-
const lead = '' !== why ? why :
|
|
51
|
+
const lead = '' !== why ? why : segment(provedSentence(steps) ?? '', 48);
|
|
85
52
|
// Minted here: every character has just been forced through `segment`, so this IS the validated
|
|
86
53
|
// boundary the brand is meant to be created at.
|
|
87
54
|
const parts = [lead, ...('' !== why || 0 === leg.length ? [] : [leg])].filter((p) => '' !== p);
|
|
@@ -186,7 +153,10 @@ export function driveFlowsFrom(tape) {
|
|
|
186
153
|
continue;
|
|
187
154
|
}
|
|
188
155
|
const startPath = segment.route ?? tape.startPath;
|
|
156
|
+
const declared = segment.steps.some((step) => step.intent !== undefined);
|
|
157
|
+
const built = declared ? undefined : provedSentence(segment.steps);
|
|
189
158
|
programs.push({
|
|
159
|
+
...(built === undefined ? {} : { intent: built, intentDerived: true }),
|
|
190
160
|
name: driveFlowName(startPath, segment.steps),
|
|
191
161
|
version: REPLAY_PROGRAM_VERSION,
|
|
192
162
|
// The route is recorder-internal and has no business on disk — `startPath` is where the
|
|
@@ -7,7 +7,7 @@ import { RouteEnvelopeSchema } from './envelope.js';
|
|
|
7
7
|
const ENVELOPE_FILE_VERSION = 1;
|
|
8
8
|
const EnvelopeFileSchema = z.object({
|
|
9
9
|
version: z.literal(ENVELOPE_FILE_VERSION),
|
|
10
|
-
routes: z.record(RouteEnvelopeSchema),
|
|
10
|
+
routes: z.record(z.string(), RouteEnvelopeSchema),
|
|
11
11
|
});
|
|
12
12
|
/**
|
|
13
13
|
* Persists the learned per-route envelopes at `.reticle/envelopes.json`. Local, single-project statistics
|
|
@@ -41,175 +41,27 @@ export declare const RouteEnvelopeSchema: z.ZodObject<{
|
|
|
41
41
|
mean: z.ZodNumber;
|
|
42
42
|
m2: z.ZodNumber;
|
|
43
43
|
max: z.ZodNumber;
|
|
44
|
-
},
|
|
45
|
-
count: number;
|
|
46
|
-
mean: number;
|
|
47
|
-
m2: number;
|
|
48
|
-
max: number;
|
|
49
|
-
}, {
|
|
50
|
-
count: number;
|
|
51
|
-
mean: number;
|
|
52
|
-
m2: number;
|
|
53
|
-
max: number;
|
|
54
|
-
}>;
|
|
44
|
+
}, z.core.$strip>;
|
|
55
45
|
net: z.ZodObject<{
|
|
56
46
|
count: z.ZodNumber;
|
|
57
47
|
mean: z.ZodNumber;
|
|
58
48
|
m2: z.ZodNumber;
|
|
59
49
|
max: z.ZodNumber;
|
|
60
|
-
},
|
|
61
|
-
count: number;
|
|
62
|
-
mean: number;
|
|
63
|
-
m2: number;
|
|
64
|
-
max: number;
|
|
65
|
-
}, {
|
|
66
|
-
count: number;
|
|
67
|
-
mean: number;
|
|
68
|
-
m2: number;
|
|
69
|
-
max: number;
|
|
70
|
-
}>;
|
|
50
|
+
}, z.core.$strip>;
|
|
71
51
|
netErrors: z.ZodObject<{
|
|
72
52
|
count: z.ZodNumber;
|
|
73
53
|
mean: z.ZodNumber;
|
|
74
54
|
m2: z.ZodNumber;
|
|
75
55
|
max: z.ZodNumber;
|
|
76
|
-
},
|
|
77
|
-
count: number;
|
|
78
|
-
mean: number;
|
|
79
|
-
m2: number;
|
|
80
|
-
max: number;
|
|
81
|
-
}, {
|
|
82
|
-
count: number;
|
|
83
|
-
mean: number;
|
|
84
|
-
m2: number;
|
|
85
|
-
max: number;
|
|
86
|
-
}>;
|
|
56
|
+
}, z.core.$strip>;
|
|
87
57
|
consoleErrors: z.ZodObject<{
|
|
88
58
|
count: z.ZodNumber;
|
|
89
59
|
mean: z.ZodNumber;
|
|
90
60
|
m2: z.ZodNumber;
|
|
91
61
|
max: z.ZodNumber;
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
m2: number;
|
|
96
|
-
max: number;
|
|
97
|
-
}, {
|
|
98
|
-
count: number;
|
|
99
|
-
mean: number;
|
|
100
|
-
m2: number;
|
|
101
|
-
max: number;
|
|
102
|
-
}>;
|
|
103
|
-
}, "strip", z.ZodTypeAny, {
|
|
104
|
-
net: {
|
|
105
|
-
count: number;
|
|
106
|
-
mean: number;
|
|
107
|
-
m2: number;
|
|
108
|
-
max: number;
|
|
109
|
-
};
|
|
110
|
-
durationMs: {
|
|
111
|
-
count: number;
|
|
112
|
-
mean: number;
|
|
113
|
-
m2: number;
|
|
114
|
-
max: number;
|
|
115
|
-
};
|
|
116
|
-
consoleErrors: {
|
|
117
|
-
count: number;
|
|
118
|
-
mean: number;
|
|
119
|
-
m2: number;
|
|
120
|
-
max: number;
|
|
121
|
-
};
|
|
122
|
-
netErrors: {
|
|
123
|
-
count: number;
|
|
124
|
-
mean: number;
|
|
125
|
-
m2: number;
|
|
126
|
-
max: number;
|
|
127
|
-
};
|
|
128
|
-
}, {
|
|
129
|
-
net: {
|
|
130
|
-
count: number;
|
|
131
|
-
mean: number;
|
|
132
|
-
m2: number;
|
|
133
|
-
max: number;
|
|
134
|
-
};
|
|
135
|
-
durationMs: {
|
|
136
|
-
count: number;
|
|
137
|
-
mean: number;
|
|
138
|
-
m2: number;
|
|
139
|
-
max: number;
|
|
140
|
-
};
|
|
141
|
-
consoleErrors: {
|
|
142
|
-
count: number;
|
|
143
|
-
mean: number;
|
|
144
|
-
m2: number;
|
|
145
|
-
max: number;
|
|
146
|
-
};
|
|
147
|
-
netErrors: {
|
|
148
|
-
count: number;
|
|
149
|
-
mean: number;
|
|
150
|
-
m2: number;
|
|
151
|
-
max: number;
|
|
152
|
-
};
|
|
153
|
-
}>;
|
|
154
|
-
}, "strip", z.ZodTypeAny, {
|
|
155
|
-
route: string;
|
|
156
|
-
samples: number;
|
|
157
|
-
stats: {
|
|
158
|
-
net: {
|
|
159
|
-
count: number;
|
|
160
|
-
mean: number;
|
|
161
|
-
m2: number;
|
|
162
|
-
max: number;
|
|
163
|
-
};
|
|
164
|
-
durationMs: {
|
|
165
|
-
count: number;
|
|
166
|
-
mean: number;
|
|
167
|
-
m2: number;
|
|
168
|
-
max: number;
|
|
169
|
-
};
|
|
170
|
-
consoleErrors: {
|
|
171
|
-
count: number;
|
|
172
|
-
mean: number;
|
|
173
|
-
m2: number;
|
|
174
|
-
max: number;
|
|
175
|
-
};
|
|
176
|
-
netErrors: {
|
|
177
|
-
count: number;
|
|
178
|
-
mean: number;
|
|
179
|
-
m2: number;
|
|
180
|
-
max: number;
|
|
181
|
-
};
|
|
182
|
-
};
|
|
183
|
-
}, {
|
|
184
|
-
route: string;
|
|
185
|
-
samples: number;
|
|
186
|
-
stats: {
|
|
187
|
-
net: {
|
|
188
|
-
count: number;
|
|
189
|
-
mean: number;
|
|
190
|
-
m2: number;
|
|
191
|
-
max: number;
|
|
192
|
-
};
|
|
193
|
-
durationMs: {
|
|
194
|
-
count: number;
|
|
195
|
-
mean: number;
|
|
196
|
-
m2: number;
|
|
197
|
-
max: number;
|
|
198
|
-
};
|
|
199
|
-
consoleErrors: {
|
|
200
|
-
count: number;
|
|
201
|
-
mean: number;
|
|
202
|
-
m2: number;
|
|
203
|
-
max: number;
|
|
204
|
-
};
|
|
205
|
-
netErrors: {
|
|
206
|
-
count: number;
|
|
207
|
-
mean: number;
|
|
208
|
-
m2: number;
|
|
209
|
-
max: number;
|
|
210
|
-
};
|
|
211
|
-
};
|
|
212
|
-
}>;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
}, z.core.$strip>;
|
|
213
65
|
export declare function emptyEnvelope(route: string): RouteEnvelope;
|
|
214
66
|
/** Fold one observed segment into the envelope as a new sample. */
|
|
215
67
|
export declare function addSegmentToEnvelope(envelope: RouteEnvelope, segment: SegmentRollup): RouteEnvelope;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type DrivenBy, type ReticleEvent } from '@reticlehq/core';
|
|
2
|
+
/** Per-record schema version, the same convention as the journal's. */
|
|
3
|
+
export declare const EPISODE_FILE_VERSION = 1;
|
|
4
|
+
export declare const EpisodeRecordKind: {
|
|
5
|
+
readonly START: "start";
|
|
6
|
+
readonly CALL: "call";
|
|
7
|
+
};
|
|
8
|
+
export type EpisodeRecordKind = (typeof EpisodeRecordKind)[keyof typeof EpisodeRecordKind];
|
|
9
|
+
/** One field past this many characters keeps its head and is named in the record's `truncated`. */
|
|
10
|
+
export declare const MAX_EPISODE_FIELD_CHARS = 200000;
|
|
11
|
+
/** The id for calls that came over no MCP connection (the CLI, the programmatic invoker). */
|
|
12
|
+
export declare const UNATTACHED_EPISODE = "unattached";
|
|
13
|
+
/** The repository as the episode found it. `failed` says why git could not answer. */
|
|
14
|
+
export type GitAtStart = {
|
|
15
|
+
head: string;
|
|
16
|
+
changed: {
|
|
17
|
+
file: string;
|
|
18
|
+
added: number | null;
|
|
19
|
+
removed: number | null;
|
|
20
|
+
}[];
|
|
21
|
+
moreChanged?: number;
|
|
22
|
+
} | {
|
|
23
|
+
failed: string;
|
|
24
|
+
};
|
|
25
|
+
export interface EpisodeCallInput {
|
|
26
|
+
tool: string;
|
|
27
|
+
args: Record<string, unknown>;
|
|
28
|
+
/** Wall-clock ms, from the caller's injected clock. */
|
|
29
|
+
startedAt: number;
|
|
30
|
+
endedAt: number;
|
|
31
|
+
result?: unknown;
|
|
32
|
+
error?: string;
|
|
33
|
+
sessionId?: string;
|
|
34
|
+
agent?: string;
|
|
35
|
+
drivenBy?: DrivenBy;
|
|
36
|
+
/** The events the page emitted between the call's start and its end, already attributed. */
|
|
37
|
+
effect?: readonly ReticleEvent[];
|
|
38
|
+
/** The coding agent's own session id, as its MCP server announced it. */
|
|
39
|
+
agentSession?: string;
|
|
40
|
+
}
|
|
41
|
+
interface EpisodeLogDeps {
|
|
42
|
+
/** The project's `.reticle` root. */
|
|
43
|
+
root: string;
|
|
44
|
+
episodeId: string;
|
|
45
|
+
now: () => number;
|
|
46
|
+
/** Injected for the tests; the real one asks git in the project directory. */
|
|
47
|
+
git?: (projectDir: string) => Promise<GitAtStart>;
|
|
48
|
+
/** False when the journal is switched off: nothing is written. */
|
|
49
|
+
enabled?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface EpisodeLog {
|
|
52
|
+
record: (call: EpisodeCallInput) => void;
|
|
53
|
+
/** Wait for every queued line to reach the disk. */
|
|
54
|
+
flush: () => Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
export declare function episodePath(root: string, episodeId: string): string;
|
|
57
|
+
/** HEAD and the uncommitted change against it, per file. Never throws. */
|
|
58
|
+
export declare function gitAtStart(projectDir: string): Promise<GitAtStart>;
|
|
59
|
+
export declare function createEpisodeLog(deps: EpisodeLogDeps): EpisodeLog;
|
|
60
|
+
export declare function setEpisodeLogEnabled(enabled: boolean): void;
|
|
61
|
+
/** Wait until every queued line of every open episode is on the disk. */
|
|
62
|
+
export declare function flushEpisodeLogs(): Promise<void>;
|
|
63
|
+
/** Append one call to its episode. The entry point the tool dispatcher uses. */
|
|
64
|
+
export declare function recordEpisodeCall(root: string, attachId: string | undefined, now: () => number, call: EpisodeCallInput): void;
|
|
65
|
+
/**
|
|
66
|
+
* May an episode leave this machine? Only when the project opted in (`"sync": { "episodes": true }`
|
|
67
|
+
* in `cloud.json`) AND the platform says the workspace consented to share its data. Unknown consent
|
|
68
|
+
* is no consent. No sync path calls this yet: there is no platform endpoint to receive an episode.
|
|
69
|
+
*/
|
|
70
|
+
export declare function episodesMaySync(cloud: {
|
|
71
|
+
config: unknown;
|
|
72
|
+
policy: {
|
|
73
|
+
episodes?: boolean;
|
|
74
|
+
};
|
|
75
|
+
}, workspaceConsent: boolean | undefined): boolean;
|
|
76
|
+
/** The record kinds the agent hooks write beside the daemon's (`reticle hook tool`). */
|
|
77
|
+
export declare const AgentRecordKind: {
|
|
78
|
+
readonly TOOL: "agent_tool";
|
|
79
|
+
readonly MODEL: "agent_model";
|
|
80
|
+
readonly STOP: "agent_stop";
|
|
81
|
+
};
|
|
82
|
+
/** An agent hook's file: `agent-<session>.jsonl`, beside the daemon's episodes. */
|
|
83
|
+
export declare const AGENT_FILE_PREFIX = "agent-";
|
|
84
|
+
/**
|
|
85
|
+
* The agent's model and the claim that closed the run's turn, from the agent hooks' records in
|
|
86
|
+
* this project's episodes. The turn is the run's: its claim is the first `agent_stop` at or after
|
|
87
|
+
* the run's last Reticle call (from its episode, else its `createdAt`); a later stop belongs to a
|
|
88
|
+
* later turn. The model is the newest `agent_model` record, or the `model` a tool or stop record
|
|
89
|
+
* carried, at or before that point.
|
|
90
|
+
*
|
|
91
|
+
* Whose records: the run's own agent session (`agentSession`, announced by its MCP server) when it
|
|
92
|
+
* names one. Otherwise the same agent's, by name, and only when they all come from one session:
|
|
93
|
+
* two sessions of one agent in a project and no session on the run is unknown, never a guess.
|
|
94
|
+
*/
|
|
95
|
+
export declare function agentContextFor(root: string, run: {
|
|
96
|
+
episodeId?: unknown;
|
|
97
|
+
createdAt?: unknown;
|
|
98
|
+
agent?: unknown;
|
|
99
|
+
agentSession?: unknown;
|
|
100
|
+
}): {
|
|
101
|
+
model?: string;
|
|
102
|
+
claim?: {
|
|
103
|
+
text: string;
|
|
104
|
+
at: number;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
export {};
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The episode log: every tool call an agent made, in full, and what each one did to the app.
|
|
3
|
+
*
|
|
4
|
+
* `.reticle/episodes/<episodeId>.jsonl`, one file per agent connection and project. The first line
|
|
5
|
+
* says where the work started (the git HEAD, the uncommitted change, the user's request); every
|
|
6
|
+
* line after it is one call: the tool, its arguments, its whole result or error, when it started
|
|
7
|
+
* and ended, the tab it drove, the agent that made it, and the events the page emitted while it ran.
|
|
8
|
+
*
|
|
9
|
+
* The journal (`sessions/<id>/`) keeps the page's events and the actions that drove it, but not the
|
|
10
|
+
* reads, not the results, and not the calls made before a tab connected. Together they are the
|
|
11
|
+
* trajectory: what the agent was asked, what it did, what it was told, and what the app did.
|
|
12
|
+
*
|
|
13
|
+
* LOCAL ONLY. No file in `episodes/` is sent. The sync reads two values from the agent hooks' files
|
|
14
|
+
* (`agentContextFor`): the agent's model, and its closing message, which a run carries only when the
|
|
15
|
+
* project shares requests. An upload of the files would go through `episodesMaySync`, which needs
|
|
16
|
+
* both an explicit project opt-in and a workspace that consented to share its data. It obeys the journal switch (`RETICLE_JOURNAL`, `"journal": false`).
|
|
17
|
+
*/
|
|
18
|
+
import { execFile } from 'node:child_process';
|
|
19
|
+
import { appendFile, mkdir } from 'node:fs/promises';
|
|
20
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
21
|
+
import { dirname, join } from 'node:path';
|
|
22
|
+
import { promisify } from 'node:util';
|
|
23
|
+
import { ReticleDir } from '@reticlehq/core';
|
|
24
|
+
import { PromptContextSchema } from '@reticlehq/core/artifacts';
|
|
25
|
+
import { withoutTypedInput } from './journal-recorder.js';
|
|
26
|
+
import { noteEpisode } from '../../hooks/episode-stamp.js';
|
|
27
|
+
const run = promisify(execFile);
|
|
28
|
+
/** Per-record schema version, the same convention as the journal's. */
|
|
29
|
+
export const EPISODE_FILE_VERSION = 1;
|
|
30
|
+
export const EpisodeRecordKind = { START: 'start', CALL: 'call' };
|
|
31
|
+
/** One field past this many characters keeps its head and is named in the record's `truncated`. */
|
|
32
|
+
export const MAX_EPISODE_FIELD_CHARS = 200_000;
|
|
33
|
+
/** A page can emit thousands of events in one call; past this many the record keeps the first ones. */
|
|
34
|
+
const MAX_EFFECT_EVENTS = 500;
|
|
35
|
+
/** A checkout with a huge uncommitted change keeps the first files and says how many more. */
|
|
36
|
+
const MAX_CHANGED_FILES = 500;
|
|
37
|
+
const GIT_TIMEOUT_MS = 5_000;
|
|
38
|
+
/** The id for calls that came over no MCP connection (the CLI, the programmatic invoker). */
|
|
39
|
+
export const UNATTACHED_EPISODE = 'unattached';
|
|
40
|
+
export function episodePath(root, episodeId) {
|
|
41
|
+
return join(root, ReticleDir.EPISODES_SUBDIR, `${episodeId}.jsonl`);
|
|
42
|
+
}
|
|
43
|
+
/** The value as kept: whole, or its first characters when its JSON is too long. */
|
|
44
|
+
function capped(value) {
|
|
45
|
+
const text = JSON.stringify(value ?? null);
|
|
46
|
+
return text.length > MAX_EPISODE_FIELD_CHARS
|
|
47
|
+
? { value: { head: text.slice(0, MAX_EPISODE_FIELD_CHARS) }, cut: true }
|
|
48
|
+
: { value, cut: false };
|
|
49
|
+
}
|
|
50
|
+
function effectOf(events) {
|
|
51
|
+
const counts = {};
|
|
52
|
+
for (const e of events) {
|
|
53
|
+
counts[e.type] = (counts[e.type] ?? 0) + 1;
|
|
54
|
+
}
|
|
55
|
+
const seqs = events.map((e) => e.seq).filter((s) => s !== undefined);
|
|
56
|
+
return {
|
|
57
|
+
counts,
|
|
58
|
+
...(0 === seqs.length ? {} : { seqRange: { from: Math.min(...seqs), to: Math.max(...seqs) } }),
|
|
59
|
+
events: events.slice(0, MAX_EFFECT_EVENTS),
|
|
60
|
+
...(events.length > MAX_EFFECT_EVENTS ? { moreEvents: events.length - MAX_EFFECT_EVENTS } : {}),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** HEAD and the uncommitted change against it, per file. Never throws. */
|
|
64
|
+
export async function gitAtStart(projectDir) {
|
|
65
|
+
try {
|
|
66
|
+
const opts = { cwd: projectDir, timeout: GIT_TIMEOUT_MS };
|
|
67
|
+
const head = (await run('git', ['rev-parse', 'HEAD'], opts)).stdout.trim();
|
|
68
|
+
const numstat = (await run('git', ['diff', '--numstat', 'HEAD'], opts)).stdout;
|
|
69
|
+
const all = numstat
|
|
70
|
+
.split('\n')
|
|
71
|
+
.filter((line) => line.trim().length > 0)
|
|
72
|
+
.map((line) => {
|
|
73
|
+
const [added = '', removed = '', ...file] = line.split('\t');
|
|
74
|
+
const count = (n) => (/^\d+$/.test(n) ? Number(n) : null);
|
|
75
|
+
return { file: file.join('\t'), added: count(added), removed: count(removed) };
|
|
76
|
+
});
|
|
77
|
+
return {
|
|
78
|
+
head,
|
|
79
|
+
changed: all.slice(0, MAX_CHANGED_FILES),
|
|
80
|
+
...(all.length > MAX_CHANGED_FILES ? { moreChanged: all.length - MAX_CHANGED_FILES } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return {
|
|
85
|
+
failed: error instanceof Error ? (error.message.split('\n')[0] ?? '') : String(error),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function requestIn(root) {
|
|
90
|
+
try {
|
|
91
|
+
const parsed = PromptContextSchema.safeParse(JSON.parse(readFileSync(join(root, ReticleDir.REQUEST_FILE), 'utf8')));
|
|
92
|
+
return parsed.success ? parsed.data : undefined;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export function createEpisodeLog(deps) {
|
|
99
|
+
const path = episodePath(deps.root, deps.episodeId);
|
|
100
|
+
const git = deps.git ?? gitAtStart;
|
|
101
|
+
let chain = Promise.resolve();
|
|
102
|
+
let n = 0;
|
|
103
|
+
const append = (line) => {
|
|
104
|
+
// A log that cannot be written never fails the call it describes.
|
|
105
|
+
chain = chain
|
|
106
|
+
.then(async () => appendFile(path, `${JSON.stringify(await line())}\n`))
|
|
107
|
+
.catch(() => undefined);
|
|
108
|
+
};
|
|
109
|
+
return {
|
|
110
|
+
record: (call) => {
|
|
111
|
+
if (false === deps.enabled) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
noteEpisode(deps.root, deps.episodeId, {
|
|
115
|
+
...(call.sessionId === undefined ? {} : { sessionId: call.sessionId }),
|
|
116
|
+
...(call.agentSession === undefined ? {} : { agentSession: call.agentSession }),
|
|
117
|
+
});
|
|
118
|
+
n += 1;
|
|
119
|
+
if (1 === n) {
|
|
120
|
+
// The start is taken at the first call: that is when the agent began working through us.
|
|
121
|
+
const at = deps.now();
|
|
122
|
+
const request = requestIn(deps.root);
|
|
123
|
+
append(async () => {
|
|
124
|
+
await mkdir(dirname(path), { recursive: true });
|
|
125
|
+
return {
|
|
126
|
+
v: EPISODE_FILE_VERSION,
|
|
127
|
+
kind: EpisodeRecordKind.START,
|
|
128
|
+
episodeId: deps.episodeId,
|
|
129
|
+
at,
|
|
130
|
+
...(call.agent === undefined ? {} : { agent: call.agent }),
|
|
131
|
+
...(call.agentSession === undefined ? {} : { agentSession: call.agentSession }),
|
|
132
|
+
git: await git(dirname(deps.root)).then((found) => {
|
|
133
|
+
if ('head' in found) {
|
|
134
|
+
noteEpisode(deps.root, deps.episodeId, { head: found.head });
|
|
135
|
+
}
|
|
136
|
+
return found;
|
|
137
|
+
}),
|
|
138
|
+
...(request === undefined ? {} : { request }),
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
const args = capped(withoutTypedInput(call.args));
|
|
143
|
+
const outcome = call.error === undefined ? capped(call.result) : undefined;
|
|
144
|
+
const truncated = [
|
|
145
|
+
...(args.cut ? ['args'] : []),
|
|
146
|
+
...(true === outcome?.cut ? ['result'] : []),
|
|
147
|
+
];
|
|
148
|
+
const record = {
|
|
149
|
+
v: EPISODE_FILE_VERSION,
|
|
150
|
+
kind: EpisodeRecordKind.CALL,
|
|
151
|
+
n,
|
|
152
|
+
tool: call.tool,
|
|
153
|
+
args: args.value,
|
|
154
|
+
...(outcome === undefined ? { error: call.error } : { result: outcome.value }),
|
|
155
|
+
startedAt: call.startedAt,
|
|
156
|
+
endedAt: call.endedAt,
|
|
157
|
+
...(call.sessionId === undefined ? {} : { sessionId: call.sessionId }),
|
|
158
|
+
...(call.agent === undefined ? {} : { agent: call.agent }),
|
|
159
|
+
...(call.drivenBy === undefined ? {} : { drivenBy: call.drivenBy }),
|
|
160
|
+
...(call.effect === undefined || 0 === call.effect.length
|
|
161
|
+
? {}
|
|
162
|
+
: { effect: effectOf(call.effect) }),
|
|
163
|
+
...(0 === truncated.length ? {} : { truncated }),
|
|
164
|
+
};
|
|
165
|
+
append(() => Promise.resolve(record));
|
|
166
|
+
},
|
|
167
|
+
flush: () => chain,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/** One log per project root and connection, for the daemon's lifetime. */
|
|
171
|
+
const open = new Map();
|
|
172
|
+
/**
|
|
173
|
+
* Set at start from the journal switch, by `attachJournal`, which both daemon paths call. Off until
|
|
174
|
+
* then, so a process that never started a daemon (a test, a library caller) writes nothing.
|
|
175
|
+
*/
|
|
176
|
+
let enabledInDaemon = false;
|
|
177
|
+
export function setEpisodeLogEnabled(enabled) {
|
|
178
|
+
enabledInDaemon = enabled;
|
|
179
|
+
}
|
|
180
|
+
/** Wait until every queued line of every open episode is on the disk. */
|
|
181
|
+
export async function flushEpisodeLogs() {
|
|
182
|
+
await Promise.all([...open.values()].map((log) => log.flush()));
|
|
183
|
+
}
|
|
184
|
+
/** Append one call to its episode. The entry point the tool dispatcher uses. */
|
|
185
|
+
export function recordEpisodeCall(root, attachId, now, call) {
|
|
186
|
+
if (!enabledInDaemon) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const episodeId = attachId ?? UNATTACHED_EPISODE;
|
|
190
|
+
const key = `${root}\n${episodeId}`;
|
|
191
|
+
let log = open.get(key);
|
|
192
|
+
if (log === undefined) {
|
|
193
|
+
log = createEpisodeLog({
|
|
194
|
+
root,
|
|
195
|
+
episodeId,
|
|
196
|
+
now,
|
|
197
|
+
enabled: enabledInDaemon,
|
|
198
|
+
});
|
|
199
|
+
open.set(key, log);
|
|
200
|
+
}
|
|
201
|
+
log.record(call);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* May an episode leave this machine? Only when the project opted in (`"sync": { "episodes": true }`
|
|
205
|
+
* in `cloud.json`) AND the platform says the workspace consented to share its data. Unknown consent
|
|
206
|
+
* is no consent. No sync path calls this yet: there is no platform endpoint to receive an episode.
|
|
207
|
+
*/
|
|
208
|
+
export function episodesMaySync(cloud, workspaceConsent) {
|
|
209
|
+
return null !== cloud.config && true === cloud.policy.episodes && true === workspaceConsent;
|
|
210
|
+
}
|
|
211
|
+
/** The record kinds the agent hooks write beside the daemon's (`reticle hook tool`). */
|
|
212
|
+
export const AgentRecordKind = {
|
|
213
|
+
TOOL: 'agent_tool',
|
|
214
|
+
MODEL: 'agent_model',
|
|
215
|
+
STOP: 'agent_stop',
|
|
216
|
+
};
|
|
217
|
+
/** An agent hook's file: `agent-<session>.jsonl`, beside the daemon's episodes. */
|
|
218
|
+
export const AGENT_FILE_PREFIX = 'agent-';
|
|
219
|
+
const isJson = (value) => 'object' === typeof value && null !== value && !Array.isArray(value);
|
|
220
|
+
function readLines(path) {
|
|
221
|
+
try {
|
|
222
|
+
return readFileSync(path, 'utf8')
|
|
223
|
+
.split('\n')
|
|
224
|
+
.flatMap((line) => {
|
|
225
|
+
try {
|
|
226
|
+
const parsed = JSON.parse(line);
|
|
227
|
+
return isJson(parsed) ? [parsed] : [];
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/** The same agent: a hook names it `cursor`, an MCP handshake `cursor-vscode`. */
|
|
239
|
+
const sameAgent = (hook, run) => {
|
|
240
|
+
if ('string' !== typeof hook || 0 === hook.length) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
const a = hook.toLowerCase();
|
|
244
|
+
const b = run.toLowerCase();
|
|
245
|
+
return a.includes(b) || b.includes(a);
|
|
246
|
+
};
|
|
247
|
+
/** The hook file of one agent session: the id as the hook wrote it into the file name. */
|
|
248
|
+
const agentFileOf = (session) => `${AGENT_FILE_PREFIX}${session.replace(/[^\w-]/g, '_')}.jsonl`;
|
|
249
|
+
/**
|
|
250
|
+
* The agent's model and the claim that closed the run's turn, from the agent hooks' records in
|
|
251
|
+
* this project's episodes. The turn is the run's: its claim is the first `agent_stop` at or after
|
|
252
|
+
* the run's last Reticle call (from its episode, else its `createdAt`); a later stop belongs to a
|
|
253
|
+
* later turn. The model is the newest `agent_model` record, or the `model` a tool or stop record
|
|
254
|
+
* carried, at or before that point.
|
|
255
|
+
*
|
|
256
|
+
* Whose records: the run's own agent session (`agentSession`, announced by its MCP server) when it
|
|
257
|
+
* names one. Otherwise the same agent's, by name, and only when they all come from one session:
|
|
258
|
+
* two sessions of one agent in a project and no session on the run is unknown, never a guess.
|
|
259
|
+
*/
|
|
260
|
+
export function agentContextFor(root, run) {
|
|
261
|
+
const agentId = isJson(run.agent) ? run.agent['id'] : undefined;
|
|
262
|
+
if ('string' !== typeof agentId) {
|
|
263
|
+
return {};
|
|
264
|
+
}
|
|
265
|
+
const dir = join(root, ReticleDir.EPISODES_SUBDIR);
|
|
266
|
+
let files;
|
|
267
|
+
try {
|
|
268
|
+
files = readdirSync(dir);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
return {};
|
|
272
|
+
}
|
|
273
|
+
const calls = 'string' === typeof run.episodeId ? readLines(join(dir, `${run.episodeId}.jsonl`)) : [];
|
|
274
|
+
const ends = calls.map((c) => c['endedAt']).filter((t) => 'number' === typeof t);
|
|
275
|
+
const createdAt = 'number' === typeof run.createdAt ? run.createdAt : 0;
|
|
276
|
+
const lastCall = 0 < ends.length ? Math.max(...ends) : createdAt;
|
|
277
|
+
const own = 'string' === typeof run.agentSession ? agentFileOf(run.agentSession) : undefined;
|
|
278
|
+
const bySession = files
|
|
279
|
+
.filter((file) => (own === undefined ? file.startsWith(AGENT_FILE_PREFIX) : own === file))
|
|
280
|
+
.map((file) => readLines(join(dir, file)).filter((r) => own !== undefined || sameAgent(r['agent'], agentId)))
|
|
281
|
+
.filter((lines) => 0 < lines.length);
|
|
282
|
+
if (1 < bySession.length) {
|
|
283
|
+
return {};
|
|
284
|
+
}
|
|
285
|
+
const records = bySession
|
|
286
|
+
.flat()
|
|
287
|
+
.map((r) => ({ r, at: 'number' === typeof r['at'] ? r['at'] : Number(r['endedAt'] ?? 0) }))
|
|
288
|
+
.sort((a, b) => a.at - b.at);
|
|
289
|
+
const stop = records.find(({ r, at }) => AgentRecordKind.STOP === r['kind'] && at >= lastCall);
|
|
290
|
+
const until = stop?.at ?? lastCall;
|
|
291
|
+
const model = records
|
|
292
|
+
.filter(({ r, at }) => at <= until && 'string' === typeof r['model'])
|
|
293
|
+
.map(({ r }) => r['model'])
|
|
294
|
+
.at(-1);
|
|
295
|
+
const message = isJson(stop?.r['message']) ? stop?.r['message']['head'] : undefined;
|
|
296
|
+
return {
|
|
297
|
+
...(model === undefined ? {} : { model }),
|
|
298
|
+
...(stop === undefined || 'string' !== typeof message
|
|
299
|
+
? {}
|
|
300
|
+
: { claim: { text: message, at: stop.at } }),
|
|
301
|
+
};
|
|
302
|
+
}
|