@reticlehq/server 3.5.0 → 3.7.0
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/README.md +1 -1
- package/SKILL.md +123 -116
- package/dist/chromium-launch-options.d.ts +3 -1
- package/dist/chromium-launch-options.js +2 -1
- package/dist/command/cli/adhoc-suite.d.ts +14 -0
- package/dist/command/cli/adhoc-suite.js +42 -7
- package/dist/command/cli/adhoc-verdict.d.ts +19 -2
- package/dist/command/cli/adhoc-verdict.js +76 -9
- package/dist/command/cli/answers/gate-exit.d.ts +23 -0
- package/dist/command/cli/answers/gate-exit.js +45 -0
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +3 -1
- package/dist/command/cli/answers/open-note.d.ts +2 -0
- package/dist/command/cli/answers/open-note.js +22 -0
- package/dist/command/cli/auth/device-flow.d.ts +13 -2
- package/dist/command/cli/auth/device-flow.js +17 -0
- package/dist/command/cli/cli-doctor.js +14 -0
- package/dist/command/cli/cli-flow-commands.d.ts +0 -11
- package/dist/command/cli/cli-flow-commands.js +31 -112
- package/dist/command/cli/cli-kill.js +3 -2
- package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
- package/dist/command/cli/cli-parse-grammar.js +75 -0
- package/dist/command/cli/cli-parse-verify.d.ts +2 -0
- package/dist/command/cli/cli-parse-verify.js +18 -0
- package/dist/command/cli/cli-parse.d.ts +19 -28
- package/dist/command/cli/cli-parse.js +82 -182
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +61 -9
- package/dist/command/cli/cli-usage.d.ts +33 -0
- package/dist/command/cli/cli-usage.js +287 -0
- package/dist/command/cli/cli-verify.d.ts +35 -5
- package/dist/command/cli/cli-verify.js +114 -35
- package/dist/command/cli/cloud-cli.d.ts +13 -0
- package/dist/command/cli/cloud-cli.js +192 -341
- package/dist/command/cli/cloud-kit.d.ts +12 -0
- package/dist/command/cli/cloud-kit.js +41 -2
- package/dist/command/cli/cloud-link.d.ts +57 -0
- package/dist/command/cli/cloud-link.js +308 -0
- package/dist/command/cli/cloud-login.d.ts +22 -0
- package/dist/command/cli/cloud-login.js +96 -8
- package/dist/command/cli/context-command.d.ts +1 -0
- package/dist/command/cli/context-command.js +33 -0
- package/dist/command/cli/daemon-start-options.d.ts +3 -0
- package/dist/command/cli/daemon-start-options.js +24 -3
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +46 -0
- package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
- package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
- package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
- package/dist/command/cli/doctor/doctor-project-line.js +5 -4
- package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
- package/dist/command/cli/doctor/doctor-rows.js +6 -0
- package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
- package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
- package/dist/command/cli/drive/drive-attach.d.ts +27 -2
- package/dist/command/cli/drive/drive-attach.js +71 -4
- package/dist/command/cli/drive/drive-command.d.ts +2 -1
- package/dist/command/cli/drive/drive-command.js +13 -7
- package/dist/command/cli/known-regression.d.ts +13 -0
- package/dist/command/cli/known-regression.js +34 -0
- package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
- package/dist/command/cli/launch/sdk-version-match.js +25 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +15 -3
- package/dist/command/cli/mcp-command.d.ts +6 -0
- package/dist/command/cli/mcp-command.js +13 -5
- package/dist/command/cli/ports/port-holder.d.ts +10 -0
- package/dist/command/cli/ports/port-holder.js +25 -1
- package/dist/command/cli/project-name.d.ts +29 -1
- package/dist/command/cli/project-name.js +107 -2
- package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
- package/dist/command/cli/setup-mcp-cli.js +35 -12
- package/dist/command/cli/status/status-lines.d.ts +1 -0
- package/dist/command/cli/status/status-lines.js +47 -2
- package/dist/command/cli/status/workspace-links.d.ts +10 -0
- package/dist/command/cli/status/workspace-links.js +29 -0
- package/dist/command/cli/try-command.d.ts +96 -0
- package/dist/command/cli/try-command.js +362 -0
- package/dist/command/cli/tutorial.d.ts +0 -100
- package/dist/command/cli/tutorial.js +0 -181
- package/dist/command/cli/verify-results.d.ts +19 -0
- package/dist/command/cli/verify-results.js +29 -0
- package/dist/command/cli-onboarding.d.ts +0 -11
- package/dist/command/cli-onboarding.js +0 -15
- package/dist/command/cli.d.ts +20 -0
- package/dist/command/cli.js +130 -104
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
- package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
- package/dist/command/daemon/daemon-resilience.js +4 -4
- package/dist/command/daemon/daemon-resolve.d.ts +23 -1
- package/dist/command/daemon/daemon-resolve.js +79 -9
- package/dist/command/setup/agent-writer.d.ts +1 -1
- package/dist/command/setup/agent-writer.js +3 -2
- package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
- package/dist/command/setup/bringup/bridge-port.js +13 -3
- package/dist/command/setup/bringup/connect-lease.d.ts +1 -0
- package/dist/command/setup/bringup/connect-lease.js +1 -0
- package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
- package/dist/command/setup/bringup/dev-server-wait.d.ts +8 -0
- package/dist/command/setup/bringup/dev-server-wait.js +19 -0
- package/dist/command/setup/bringup/ensure-daemon.js +9 -2
- package/dist/command/setup/init/agent-restart.d.ts +23 -0
- package/dist/command/setup/init/agent-restart.js +28 -0
- package/dist/command/setup/init/init-port.d.ts +14 -1
- package/dist/command/setup/init/init-port.js +32 -2
- package/dist/command/setup/init/init-runtime.d.ts +22 -2
- package/dist/command/setup/init/init-runtime.js +114 -38
- package/dist/command/setup/node-effects.d.ts +2 -0
- package/dist/command/setup/node-effects.js +38 -9
- package/dist/command/setup/probe/existing-app.d.ts +12 -0
- package/dist/command/setup/probe/existing-app.js +14 -0
- package/dist/command/setup/remaining-steps.js +2 -1
- package/dist/command/setup/run-setup.d.ts +34 -9
- package/dist/command/setup/run-setup.js +65 -51
- package/dist/command/setup/setup-command.d.ts +25 -1
- package/dist/command/setup/setup-command.js +59 -4
- package/dist/command/setup/setup-mcp.js +25 -2
- package/dist/command/setup/tauri-signing.d.ts +19 -0
- package/dist/command/setup/tauri-signing.js +79 -0
- package/dist/command/setup/terminal/listeners.d.ts +10 -1
- package/dist/command/setup/terminal/listeners.js +37 -6
- package/dist/command/update/update-nudge.d.ts +9 -0
- package/dist/command/update/update-nudge.js +1 -1
- package/dist/command/update/updater.js +11 -15
- package/dist/command/version/version-nudge.js +3 -0
- package/dist/command/version/version-skew.d.ts +20 -1
- package/dist/command/version/version-skew.js +49 -4
- package/dist/features/crawl/crawl-tools.js +4 -0
- package/dist/features/crawl/crawl.d.ts +6 -0
- package/dist/features/crawl/crawl.js +23 -2
- package/dist/features/exhaust/ledger.d.ts +21 -14
- package/dist/features/exhaust/ledger.js +35 -9
- package/dist/features/harness/app-findings.d.ts +2 -0
- package/dist/features/harness/app-findings.js +52 -0
- package/dist/features/harness/drive-report.d.ts +61 -1
- package/dist/features/harness/drive-report.js +394 -26
- package/dist/features/harness/drive-runs.d.ts +120 -0
- package/dist/features/harness/drive-runs.js +289 -0
- package/dist/features/harness/drivers.d.ts +10 -14
- package/dist/features/harness/drivers.js +10 -14
- package/dist/features/harness/explore/console-pages.d.ts +15 -0
- package/dist/features/harness/explore/console-pages.js +146 -0
- package/dist/features/harness/explore/disparity.d.ts +19 -0
- package/dist/features/harness/explore/disparity.js +71 -0
- package/dist/features/harness/explore/fake-app.d.ts +16 -0
- package/dist/features/harness/explore/fake-app.js +49 -0
- package/dist/features/harness/explore/goal-search.d.ts +26 -0
- package/dist/features/harness/explore/goal-search.js +144 -0
- package/dist/features/harness/explore/page-tree.d.ts +49 -0
- package/dist/features/harness/explore/page-tree.js +148 -0
- package/dist/features/harness/explore/site-map.d.ts +34 -0
- package/dist/features/harness/explore/site-map.js +150 -0
- package/dist/features/harness/fill-values.d.ts +3 -73
- package/dist/features/harness/fill-values.js +3 -169
- package/dist/features/harness/goals.d.ts +82 -0
- package/dist/features/harness/goals.js +330 -0
- package/dist/features/harness/harness.d.ts +51 -1
- package/dist/features/harness/harness.js +207 -6
- package/dist/features/harness/platform/drive-target.d.ts +30 -0
- package/dist/features/harness/platform/drive-target.js +81 -0
- package/dist/features/harness/platform/local-apps.d.ts +127 -0
- package/dist/features/harness/platform/local-apps.js +280 -0
- package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
- package/dist/features/harness/platform/persona-credentials.js +69 -0
- package/dist/features/harness/platform/platform-drives.d.ts +61 -0
- package/dist/features/harness/platform/platform-drives.js +114 -0
- package/dist/features/harness/platform/refusal.d.ts +52 -0
- package/dist/features/harness/platform/refusal.js +71 -0
- package/dist/features/harness/platform/remote-drive.d.ts +186 -0
- package/dist/features/harness/platform/remote-drive.js +378 -0
- package/dist/features/harness/platform/script.d.ts +94 -0
- package/dist/features/harness/platform/script.js +260 -0
- package/dist/features/harness/platform/server-driver.d.ts +54 -0
- package/dist/features/harness/platform/server-driver.js +182 -0
- package/dist/features/harness/platform-config.d.ts +41 -1
- package/dist/features/harness/platform-config.js +106 -9
- package/dist/features/harness/route-guess.d.ts +13 -0
- package/dist/features/harness/route-guess.js +49 -0
- package/dist/features/harness/script/app-controls.d.ts +5 -0
- package/dist/features/harness/script/app-controls.js +40 -0
- package/dist/features/harness/script/lane-ids.d.ts +14 -0
- package/dist/features/harness/script/lane-ids.js +16 -0
- package/dist/features/harness/script/script-run.d.ts +70 -0
- package/dist/features/harness/script/script-run.js +606 -0
- package/dist/features/license/license.d.ts +2 -2
- package/dist/features/visual/step-shots.d.ts +31 -0
- package/dist/features/visual/step-shots.js +231 -0
- package/dist/features/visual/visual-tools.d.ts +10 -1
- package/dist/features/visual/visual-tools.js +62 -17
- package/dist/hooks/client-directory.d.ts +18 -0
- package/dist/hooks/client-directory.js +57 -0
- package/dist/hooks/coding-agents.d.ts +34 -0
- package/dist/hooks/coding-agents.js +117 -0
- package/dist/hooks/driven-by.d.ts +23 -0
- package/dist/hooks/driven-by.js +56 -0
- package/dist/hooks/hook-bus.d.ts +4 -0
- package/dist/hooks/hook-bus.js +18 -0
- package/dist/hooks/hook-commands.js +15 -4
- package/dist/hooks/tool-log.d.ts +9 -0
- package/dist/hooks/tool-log.js +29 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +80 -243
- package/dist/judgement/capsule/capsule-store.d.ts +2 -2
- package/dist/judgement/capsule/causal-summary.d.ts +15 -1
- package/dist/judgement/capsule/causal-summary.js +33 -0
- package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
- package/dist/judgement/runs/artifact/build-verification-run.js +25 -3
- package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
- package/dist/judgement/runs/artifact/gap-summary.js +12 -3
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +37 -11
- package/dist/judgement/runs/artifact/run-store.d.ts +14 -2
- package/dist/judgement/runs/artifact/run-store.js +195 -3
- package/dist/judgement/runs/context-tools.js +59 -1
- package/dist/judgement/runs/default-run-id.d.ts +3 -0
- package/dist/judgement/runs/default-run-id.js +16 -0
- package/dist/judgement/runs/drive-run.d.ts +71 -1
- package/dist/judgement/runs/drive-run.js +317 -5
- package/dist/judgement/runs/repair-prompt.js +1 -1
- package/dist/judgement/runs/resume.d.ts +44 -0
- package/dist/judgement/runs/resume.js +137 -0
- package/dist/judgement/runs/reticle-runner.js +13 -3
- package/dist/judgement/runs/runner-port.d.ts +5 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +5 -2
- package/dist/judgement/runs/verification-sync.js +40 -18
- package/dist/language/flows/change/gate.d.ts +10 -0
- package/dist/language/flows/change/gate.js +22 -0
- package/dist/language/flows/decision.js +36 -1
- package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
- package/dist/language/flows/fields/flow-secret-field.js +25 -2
- package/dist/language/flows/flow-anchor.d.ts +61 -10
- package/dist/language/flows/flow-anchor.js +98 -6
- package/dist/language/flows/flow-cross-step.d.ts +15 -0
- package/dist/language/flows/flow-cross-step.js +21 -0
- package/dist/language/flows/flow-intent.d.ts +1 -0
- package/dist/language/flows/flow-journey.d.ts +6 -0
- package/dist/language/flows/flow-journey.js +20 -0
- package/dist/language/flows/flow-learning.d.ts +4 -0
- package/dist/language/flows/flow-learning.js +45 -14
- package/dist/language/flows/flow-mutate-tools.js +5 -3
- package/dist/language/flows/flow-replay-run.d.ts +23 -9
- package/dist/language/flows/flow-replay-run.js +115 -110
- package/dist/language/flows/flow-replay-types.d.ts +1 -1
- package/dist/language/flows/flow-replay.d.ts +40 -1
- package/dist/language/flows/flow-replay.js +110 -22
- package/dist/language/flows/flow-result.d.ts +22 -1
- package/dist/language/flows/flow-result.js +47 -2
- package/dist/language/flows/flow-scope.js +5 -1
- package/dist/language/flows/flow-step-runners.d.ts +22 -2
- package/dist/language/flows/flow-step-runners.js +247 -47
- package/dist/language/flows/flow-store-for-session.d.ts +2 -2
- package/dist/language/flows/flow-store-for-session.js +7 -3
- package/dist/language/flows/flow-tools.d.ts +10 -0
- package/dist/language/flows/flow-tools.js +112 -89
- package/dist/language/flows/flows.d.ts +16 -1
- package/dist/language/flows/flows.js +74 -12
- package/dist/language/flows/heal-run.js +6 -4
- package/dist/language/flows/narrow-write.d.ts +7 -0
- package/dist/language/flows/narrow-write.js +36 -1
- package/dist/language/flows/recording/flake.d.ts +2 -2
- package/dist/language/flows/recording/recording-backtrack.js +14 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +58 -4
- package/dist/language/flows/recording/tape/recordings.js +95 -13
- package/dist/language/flows/replay-from-hud.d.ts +20 -0
- package/dist/language/flows/replay-from-hud.js +51 -0
- package/dist/language/flows/replay.d.ts +9 -5
- package/dist/language/flows/replay.js +56 -15
- package/dist/language/flows/single-replay.d.ts +7 -0
- package/dist/language/flows/single-replay.js +26 -0
- package/dist/language/flows/suite/suite-flakes.js +2 -0
- package/dist/language/flows/suite-selection.d.ts +2 -15
- package/dist/language/flows/suite-selection.js +4 -3
- package/dist/language/flows/verify-change-tools.d.ts +1 -0
- package/dist/language/flows/verify-change-tools.js +202 -191
- package/dist/launch-chromium.d.ts +27 -5
- package/dist/launch-chromium.js +38 -8
- package/dist/memory/cloud/cloud-config.d.ts +22 -1
- package/dist/memory/cloud/cloud-config.js +34 -5
- package/dist/memory/cloud/cloud-sync.d.ts +17 -14
- package/dist/memory/cloud/cloud-sync.js +15 -4
- package/dist/memory/cloud/harness-config.d.ts +75 -1
- package/dist/memory/cloud/harness-config.js +115 -24
- package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
- package/dist/memory/cloud/hud-notices-source.js +128 -0
- package/dist/memory/cloud/memory-scope.d.ts +161 -0
- package/dist/memory/cloud/memory-scope.js +227 -0
- package/dist/memory/cloud/sync-cycle.d.ts +44 -7
- package/dist/memory/cloud/sync-cycle.js +129 -15
- package/dist/memory/cloud/sync-daemon.d.ts +11 -0
- package/dist/memory/cloud/sync-daemon.js +121 -9
- package/dist/memory/cloud/sync-disk.d.ts +1 -1
- package/dist/memory/cloud/sync-disk.js +31 -10
- package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
- package/dist/memory/cloud/sync-screenshots.js +105 -0
- package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
- package/dist/memory/cloud/unsynced-roots.js +166 -0
- package/dist/memory/impact/account-watch.d.ts +34 -0
- package/dist/memory/impact/account-watch.js +59 -0
- package/dist/memory/impact/impact-recorder.d.ts +8 -0
- package/dist/memory/impact/impact-recorder.js +12 -2
- package/dist/memory/impact/impact-store.d.ts +17 -4
- package/dist/memory/impact/impact-store.js +169 -63
- package/dist/memory/intent/inline-intent.d.ts +1 -0
- package/dist/memory/intent/intent-shard-store.js +16 -4
- package/dist/memory/intent/intent-shard.d.ts +14 -2
- package/dist/memory/intent/intent-store.d.ts +1 -0
- package/dist/memory/intent/intent-tools.js +122 -4
- package/dist/memory/intent/open-intents.d.ts +6 -0
- package/dist/memory/intent/open-intents.js +10 -1
- package/dist/memory/intent/settled-words.d.ts +24 -0
- package/dist/memory/intent/settled-words.js +130 -0
- package/dist/memory/journal/drive-flow.d.ts +16 -0
- package/dist/memory/journal/drive-flow.js +34 -2
- package/dist/memory/journal/drive-run-flush.d.ts +2 -0
- package/dist/memory/journal/drive-run-flush.js +20 -5
- package/dist/memory/journal/envelope.d.ts +8 -8
- package/dist/memory/journal/journal-recorder.js +52 -3
- package/dist/memory/journal/on-disk/retention.d.ts +8 -0
- package/dist/memory/journal/on-disk/retention.js +32 -2
- package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
- package/dist/memory/journal/on-disk/workspace-tiers.js +9 -4
- package/dist/memory/journal/session-end.d.ts +15 -1
- package/dist/memory/journal/session-end.js +42 -9
- package/dist/memory/project/artifact-root-resolver.d.ts +26 -1
- package/dist/memory/project/artifact-root-resolver.js +125 -16
- package/dist/memory/project/artifact-root.d.ts +46 -8
- package/dist/memory/project/artifact-root.js +89 -10
- package/dist/memory/project/dir/reticle-dir.d.ts +18 -2
- package/dist/memory/project/dir/reticle-dir.js +26 -3
- package/dist/memory/project/link-directory.d.ts +15 -0
- package/dist/memory/project/link-directory.js +44 -0
- package/dist/memory/project/project-tools.js +22 -3
- package/dist/memory/project/root-claims.d.ts +6 -0
- package/dist/memory/project/root-claims.js +39 -0
- package/dist/memory/project/session-root.d.ts +26 -1
- package/dist/memory/project/session-root.js +49 -5
- package/dist/memory/project/sync-status.d.ts +85 -0
- package/dist/memory/project/sync-status.js +224 -0
- package/dist/memory/recall/memory-tools.js +47 -2
- package/dist/memory/recall/platform-memory.d.ts +34 -0
- package/dist/memory/recall/platform-memory.js +139 -0
- package/dist/memory/recall/project-memory.d.ts +19 -0
- package/dist/memory/recall/project-memory.js +80 -13
- package/dist/portal/bridge/bridge.d.ts +9 -3
- package/dist/portal/bridge/bridge.js +82 -22
- package/dist/portal/bridge/harness-request.d.ts +23 -0
- package/dist/portal/bridge/harness-request.js +27 -0
- package/dist/portal/bridge/pairing-token.d.ts +9 -0
- package/dist/portal/bridge/pairing-token.js +17 -0
- package/dist/portal/bridge/wrong-path.d.ts +17 -0
- package/dist/portal/bridge/wrong-path.js +35 -0
- package/dist/portal/input/network-mock-tools.js +11 -2
- package/dist/portal/input/real-input.d.ts +83 -10
- package/dist/portal/input/real-input.js +218 -30
- package/dist/portal/input/viewport-tools.js +3 -3
- package/dist/portal/pool/browser-pool.d.ts +70 -9
- package/dist/portal/pool/browser-pool.js +190 -37
- package/dist/portal/pool/context-permissions.d.ts +33 -0
- package/dist/portal/pool/context-permissions.js +33 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
- package/dist/portal/pool/lease-marker-stamp.js +49 -0
- package/dist/portal/pool/playwright-launcher.d.ts +35 -0
- package/dist/portal/pool/playwright-launcher.js +64 -3
- package/dist/portal/pool/pool-contract.d.ts +28 -5
- package/dist/portal/session/agent-link.d.ts +8 -0
- package/dist/portal/session/agent-link.js +17 -0
- package/dist/portal/session/command-payload.d.ts +8 -0
- package/dist/portal/session/command-payload.js +24 -0
- package/dist/portal/session/daemon-answers.d.ts +3 -3
- package/dist/portal/session/daemon-answers.js +4 -2
- package/dist/portal/session/dev-server/dev-command.d.ts +21 -0
- package/dist/portal/session/dev-server/dev-command.js +87 -12
- package/dist/portal/session/facts/departure-note.d.ts +22 -0
- package/dist/portal/session/facts/departure-note.js +47 -0
- package/dist/portal/session/facts/observed-state.d.ts +16 -18
- package/dist/portal/session/facts/observed-state.js +46 -3
- package/dist/portal/session/facts/session-replaced.d.ts +5 -0
- package/dist/portal/session/facts/session-replaced.js +5 -0
- package/dist/portal/session/first-run-wiring.d.ts +42 -0
- package/dist/portal/session/first-run-wiring.js +132 -0
- package/dist/portal/session/human/live-control.d.ts +9 -2
- package/dist/portal/session/human/live-control.js +12 -3
- package/dist/portal/session/human/notes-ledger.d.ts +20 -0
- package/dist/portal/session/human/notes-ledger.js +55 -0
- package/dist/portal/session/human/review-store.d.ts +12 -0
- package/dist/portal/session/human/review-store.js +18 -10
- package/dist/portal/session/live-control-tools.d.ts +0 -13
- package/dist/portal/session/live-control-tools.js +107 -13
- package/dist/portal/session/narration-args.d.ts +5 -0
- package/dist/portal/session/narration-args.js +17 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +8 -1
- package/dist/portal/session/no-session-diagnosis.js +46 -9
- package/dist/portal/session/no-session-next-action.d.ts +31 -0
- package/dist/portal/session/no-session-next-action.js +159 -60
- package/dist/portal/session/no-session-watch.d.ts +14 -1
- package/dist/portal/session/no-session-watch.js +227 -17
- package/dist/portal/session/presence/session-lease.js +1 -1
- package/dist/portal/session/presence/session-mirror.js +3 -0
- package/dist/portal/session/recorded-gaps.d.ts +97 -0
- package/dist/portal/session/recorded-gaps.js +251 -0
- package/dist/portal/session/serving-directory.d.ts +27 -0
- package/dist/portal/session/serving-directory.js +45 -0
- package/dist/portal/session/session-health.d.ts +18 -0
- package/dist/portal/session/session-health.js +9 -1
- package/dist/portal/session/session-info.d.ts +8 -1
- package/dist/portal/session/session-info.js +8 -1
- package/dist/portal/session/session-manager.d.ts +39 -0
- package/dist/portal/session/session-manager.js +98 -11
- package/dist/portal/session/session-reaper.js +4 -1
- package/dist/portal/session/session-successor.d.ts +13 -0
- package/dist/portal/session/session-successor.js +1 -1
- package/dist/portal/session/session-tools.js +26 -3
- package/dist/portal/session/session.d.ts +22 -30
- package/dist/portal/session/session.js +81 -79
- package/dist/portal/session/timing/command-timeout.js +25 -1
- package/dist/portal/session/timing/wall-clock.d.ts +1 -1
- package/dist/portal/session/timing/wall-clock.js +1 -1
- package/dist/portal/session/zero-install-first-call.d.ts +31 -0
- package/dist/portal/session/zero-install-first-call.js +88 -0
- package/dist/start-options.d.ts +12 -0
- package/dist/start-wiring.d.ts +63 -0
- package/dist/start-wiring.js +169 -0
- package/dist/status-payload.d.ts +23 -1
- package/dist/status-payload.js +36 -1
- package/dist/surface/http-server.js +18 -2
- package/dist/surface/mcp/attach-memory.d.ts +1 -0
- package/dist/surface/mcp/attach-memory.js +12 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +9 -0
- package/dist/surface/mcp/mcp-proxy.js +65 -13
- package/dist/surface/mcp/mcp.d.ts +34 -6
- package/dist/surface/mcp/mcp.js +61 -17
- package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
- package/dist/surface/mcp/proxy/drive-calls.js +27 -0
- package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
- package/dist/surface/mcp/server-instructions.d.ts +4 -2
- package/dist/surface/mcp/server-instructions.js +32 -14
- package/dist/surface/mcp/shared-params.js +2 -2
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +1 -0
- package/dist/surface/tools/account-tool.d.ts +22 -0
- package/dist/surface/tools/account-tool.js +157 -0
- package/dist/surface/tools/act/act-danger.d.ts +11 -0
- package/dist/surface/tools/act/act-danger.js +38 -1
- package/dist/surface/tools/act/act-observation.d.ts +33 -0
- package/dist/surface/tools/act/act-observation.js +57 -0
- package/dist/surface/tools/act/act-preflight.js +25 -2
- package/dist/surface/tools/act/act-target.js +8 -3
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +8 -0
- package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
- package/dist/surface/tools/act/resolve-target.d.ts +1 -1
- package/dist/surface/tools/act/resolve-target.js +18 -3
- package/dist/surface/tools/act/screen-request.d.ts +34 -0
- package/dist/surface/tools/act/screen-request.js +113 -0
- package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
- package/dist/surface/tools/act/sequence-grade.js +13 -2
- package/dist/surface/tools/act/settle-in-flight.js +25 -3
- package/dist/surface/tools/act-sequence-tool.js +138 -29
- package/dist/surface/tools/act-tools.d.ts +0 -9
- package/dist/surface/tools/act-tools.js +71 -41
- package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
- package/dist/surface/tools/agent/app-notes-learning.js +80 -0
- package/dist/surface/tools/agent/app-notes.d.ts +4 -0
- package/dist/surface/tools/agent/app-notes.js +48 -0
- package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
- package/dist/surface/tools/agent/build-staleness.js +62 -0
- package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
- package/dist/surface/tools/agent/compact-envelope.js +374 -0
- package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
- package/dist/surface/tools/agent/for-the-agent.js +44 -0
- package/dist/surface/tools/agent/notices.d.ts +50 -0
- package/dist/surface/tools/agent/notices.js +152 -0
- package/dist/surface/tools/agent/reteach.d.ts +11 -0
- package/dist/surface/tools/agent/reteach.js +50 -0
- package/dist/surface/tools/args/alias-args.d.ts +5 -0
- package/dist/surface/tools/args/alias-args.js +10 -0
- package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
- package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
- package/dist/surface/tools/assert/assert-source.d.ts +15 -0
- package/dist/surface/tools/assert/assert-source.js +40 -0
- package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +42 -17
- package/dist/surface/tools/browser-tools.js +51 -2
- package/dist/surface/tools/chat-drives.d.ts +101 -0
- package/dist/surface/tools/chat-drives.js +409 -0
- package/dist/surface/tools/coverage-tools.d.ts +2 -10
- package/dist/surface/tools/coverage-tools.js +2 -53
- package/dist/surface/tools/dynamic-tools.js +29 -1
- package/dist/surface/tools/empty-session-list.d.ts +51 -0
- package/dist/surface/tools/empty-session-list.js +120 -0
- package/dist/surface/tools/error-recovery.d.ts +14 -0
- package/dist/surface/tools/error-recovery.js +105 -8
- package/dist/surface/tools/explore-tools.d.ts +31 -1
- package/dist/surface/tools/explore-tools.js +438 -66
- package/dist/surface/tools/feedback-tools.d.ts +2 -3
- package/dist/surface/tools/feedback-tools.js +18 -3
- package/dist/surface/tools/gap-novelty.d.ts +3 -1
- package/dist/surface/tools/gap-novelty.js +8 -1
- package/dist/surface/tools/harness-explore.d.ts +118 -57
- package/dist/surface/tools/harness-explore.js +344 -292
- package/dist/surface/tools/harness-gate.d.ts +88 -0
- package/dist/surface/tools/harness-gate.js +235 -0
- package/dist/surface/tools/harness-hunt.d.ts +43 -0
- package/dist/surface/tools/harness-hunt.js +215 -0
- package/dist/surface/tools/harness-plan.d.ts +17 -0
- package/dist/surface/tools/harness-plan.js +38 -0
- package/dist/surface/tools/harness-script.d.ts +30 -0
- package/dist/surface/tools/harness-script.js +560 -0
- package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
- package/dist/surface/tools/harness-tab-guard.js +27 -0
- package/dist/surface/tools/harness-toolset.d.ts +22 -1
- package/dist/surface/tools/harness-toolset.js +101 -7
- package/dist/surface/tools/human-notes.d.ts +16 -0
- package/dist/surface/tools/human-notes.js +27 -0
- package/dist/surface/tools/invoke-tool.d.ts +5 -2
- package/dist/surface/tools/invoke-tool.js +263 -85
- package/dist/surface/tools/lease-hint.js +26 -5
- package/dist/surface/tools/lease-permissions.d.ts +33 -0
- package/dist/surface/tools/lease-permissions.js +73 -0
- package/dist/surface/tools/lease-readiness.d.ts +38 -0
- package/dist/surface/tools/lease-readiness.js +57 -0
- package/dist/surface/tools/lease-seed.d.ts +49 -0
- package/dist/surface/tools/lease-seed.js +167 -0
- package/dist/surface/tools/lease-tools.d.ts +13 -24
- package/dist/surface/tools/lease-tools.js +146 -197
- package/dist/surface/tools/live-call-text.js +4 -4
- package/dist/surface/tools/merge-tools.js +42 -2
- package/dist/surface/tools/merged-name-redirect.js +4 -0
- package/dist/surface/tools/next-step.d.ts +29 -0
- package/dist/surface/tools/next-step.js +214 -0
- package/dist/surface/tools/observe-tools.js +45 -9
- package/dist/surface/tools/platform-moment.d.ts +72 -0
- package/dist/surface/tools/platform-moment.js +296 -0
- package/dist/surface/tools/query-hint-schema.d.ts +7 -0
- package/dist/surface/tools/query-hint-schema.js +10 -0
- package/dist/surface/tools/read-tools.js +71 -14
- package/dist/surface/tools/real-input-attempt.js +96 -13
- package/dist/surface/tools/reticle-result.d.ts +120 -0
- package/dist/surface/tools/reticle-result.js +364 -0
- package/dist/surface/tools/tool-kit.d.ts +83 -3
- package/dist/surface/tools/tool-kit.js +77 -7
- package/dist/surface/tools/tools.js +43 -59
- package/dist/telemetry/account-envelope.d.ts +7 -0
- package/dist/telemetry/account-envelope.js +61 -0
- package/dist/telemetry/agent-client.d.ts +15 -0
- package/dist/telemetry/agent-client.js +57 -0
- package/dist/telemetry/app-instrumented.js +9 -2
- package/dist/telemetry/argument-shape.d.ts +7 -0
- package/dist/telemetry/argument-shape.js +86 -1
- package/dist/telemetry/automation-hint.d.ts +2 -3
- package/dist/telemetry/automation-hint.js +33 -8
- package/dist/telemetry/cli-telemetry.js +7 -2
- package/dist/telemetry/daemon-telemetry.js +3 -0
- package/dist/telemetry/error-fingerprint.d.ts +10 -1
- package/dist/telemetry/error-fingerprint.js +61 -5
- package/dist/telemetry/feedback-cli.d.ts +0 -13
- package/dist/telemetry/feedback-cli.js +0 -77
- package/dist/telemetry/feedback.d.ts +13 -0
- package/dist/telemetry/feedback.js +183 -17
- package/dist/telemetry/harness-run.d.ts +18 -0
- package/dist/telemetry/harness-run.js +80 -0
- package/dist/telemetry/hud-events.d.ts +16 -0
- package/dist/telemetry/hud-events.js +27 -0
- package/dist/telemetry/hud-metrics.d.ts +29 -6
- package/dist/telemetry/hud-metrics.js +116 -25
- package/dist/telemetry/init-telemetry.js +2 -2
- package/dist/telemetry/install-source.d.ts +13 -25
- package/dist/telemetry/install-source.js +44 -3
- package/dist/telemetry/mcp-connection.d.ts +0 -14
- package/dist/telemetry/mcp-connection.js +5 -1
- package/dist/telemetry/onboarding-firsts.d.ts +32 -0
- package/dist/telemetry/onboarding-firsts.js +81 -6
- package/dist/telemetry/platform-linked.d.ts +5 -0
- package/dist/telemetry/platform-linked.js +32 -0
- package/dist/telemetry/project-profile.js +5 -3
- package/dist/telemetry/proxy-telemetry.js +4 -1
- package/dist/telemetry/session-metrics.d.ts +15 -4
- package/dist/telemetry/session-metrics.js +88 -52
- package/dist/telemetry/telemetry.d.ts +38 -2
- package/dist/telemetry/telemetry.js +144 -34
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +13 -4
- package/dist/wire-journal.d.ts +2 -2
- package/dist/wire-journal.js +20 -6
- package/docs/README.md +3 -3
- package/docs/actions.mdx +6 -3
- package/docs/adapters.md +1 -1
- package/docs/agent-cheatsheet.md +25 -28
- package/docs/architecture.md +5 -5
- package/docs/autodrive.md +33 -28
- package/docs/benchmarks.md +5 -5
- package/docs/best-practices.mdx +27 -9
- package/docs/capabilities.mdx +14 -16
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +54 -75
- package/docs/cli/doctor.mdx +14 -3
- package/docs/cli/drive.mdx +20 -14
- package/docs/cli/feedback.mdx +3 -3
- package/docs/cli/gate.mdx +7 -2
- package/docs/cli/help.mdx +50 -55
- package/docs/cli/init.mdx +43 -28
- package/docs/cli/license.mdx +12 -8
- package/docs/cli/mcp.mdx +4 -4
- package/docs/cli/open.mdx +3 -3
- package/docs/cli/report.mdx +4 -2
- package/docs/cli/restart.mdx +2 -2
- package/docs/cli/rollback.mdx +14 -8
- package/docs/cli/serve.mdx +4 -4
- package/docs/cli/setup.mdx +23 -0
- package/docs/cli/status.mdx +18 -5
- package/docs/cli/stop.mdx +67 -8
- package/docs/cli/try.mdx +62 -0
- package/docs/cli/update.mdx +4 -3
- package/docs/cli/verify.mdx +17 -6
- package/docs/cli/version.mdx +5 -4
- package/docs/cli.mdx +111 -42
- package/docs/debugging.md +3 -3
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +9 -3
- package/docs/enterprise.md +11 -10
- package/docs/environment.mdx +7 -8
- package/docs/faq.mdx +3 -3
- package/docs/first-drive.md +5 -4
- package/docs/flows.md +35 -27
- package/docs/for-agents.md +4 -5
- package/docs/frameworks.mdx +32 -21
- package/docs/getting-started.md +65 -61
- package/docs/human-control.md +16 -16
- package/docs/index.mdx +15 -42
- package/docs/install-agentic.mdx +22 -37
- package/docs/install-manual.mdx +23 -13
- package/docs/instrumentation.mdx +5 -3
- package/docs/integration-patterns.md +7 -7
- package/docs/license-activation.mdx +1 -1
- package/docs/multi-agent-testing.md +24 -6
- package/docs/packages/babel-plugin.mdx +4 -2
- package/docs/packages/browser.mdx +16 -10
- package/docs/packages/core.mdx +12 -5
- package/docs/packages/electron.mdx +3 -2
- package/docs/packages/engine.mdx +1 -1
- package/docs/packages/eslint-plugin.mdx +18 -12
- package/docs/packages/next.mdx +8 -7
- package/docs/packages/open-verification.mdx +1 -1
- package/docs/packages/server.mdx +5 -5
- package/docs/packages/tauri.mdx +9 -9
- package/docs/packages/test.mdx +4 -10
- package/docs/packages/vite-plugin.mdx +32 -4
- package/docs/packages.mdx +11 -15
- package/docs/platform-integration.md +6 -5
- package/docs/predicates.mdx +40 -24
- package/docs/quickstart.mdx +69 -30
- package/docs/required-checks.md +8 -7
- package/docs/reticle-manual.md +15 -5
- package/docs/skill-file.mdx +17 -79
- package/docs/skill-setup.md +9 -9
- package/docs/skill.md +200 -0
- package/docs/system-map.md +7 -7
- package/docs/telemetry.md +23 -25
- package/docs/testing.md +4 -4
- package/docs/token-efficiency.md +12 -12
- package/docs/tools/act-and-wait.mdx +9 -2
- package/docs/tools/act-sequence.mdx +6 -7
- package/docs/tools/act.mdx +2 -2
- package/docs/tools/assert.mdx +18 -17
- package/docs/tools/console.mdx +9 -9
- package/docs/tools/inspect.mdx +16 -7
- package/docs/tools/look.mdx +24 -0
- package/docs/tools/navigate.mdx +5 -3
- package/docs/tools/network.mdx +2 -2
- package/docs/tools/observe.mdx +6 -6
- package/docs/tools/overview.mdx +34 -33
- package/docs/tools/query.mdx +5 -5
- package/docs/tools/session-and-feedback.mdx +22 -13
- package/docs/tools/sessions.mdx +8 -8
- package/docs/tools/snapshot.mdx +6 -5
- package/docs/tools/state.mdx +9 -9
- package/docs/tools/tools-and-run.mdx +26 -24
- package/docs/tools/verify.mdx +28 -0
- package/docs/tools/wait-for.mdx +8 -4
- package/docs/troubleshooting.mdx +21 -6
- package/docs/usage.md +55 -46
- package/docs/use-cases.mdx +3 -3
- package/docs/vs-chrome-devtools-mcp.mdx +9 -6
- package/docs/vs-playwright-mcp.mdx +3 -1
- package/docs/what-is-recorded.md +17 -5
- package/docs/what-is-reticle.mdx +5 -3
- package/docs/why-reticle.mdx +1 -1
- package/package.json +9 -12
- package/dist/command/cli/demo/demo-page.d.ts +0 -78
- package/dist/command/cli/demo/demo-page.js +0 -241
- package/dist/command/cli/demo/demo-run.d.ts +0 -38
- package/dist/command/cli/demo/demo-run.js +0 -138
- package/dist/features/harness/driver.d.ts +0 -50
- package/dist/features/harness/driver.js +0 -236
- package/dist/features/harness/jev-driver.d.ts +0 -188
- package/dist/features/harness/jev-driver.js +0 -678
- package/dist/features/harness/openai-driver.d.ts +0 -58
- package/dist/features/harness/openai-driver.js +0 -206
- package/dist/judgement/hunt/hunt-report.d.ts +0 -49
- package/dist/judgement/hunt/hunt-report.js +0 -84
- package/dist/language/flows/buddy-status.d.ts +0 -25
- package/dist/language/flows/buddy-status.js +0 -32
- package/dist/language/flows/change/watch-batcher.d.ts +0 -18
- package/dist/language/flows/change/watch-batcher.js +0 -19
- package/dist/memory/cloud/harness-offer.d.ts +0 -44
- package/dist/memory/cloud/harness-offer.js +0 -145
- package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
- package/dist/memory/project/dir/fill-value-store.js +0 -88
- package/dist/surface/tools/feature-capture.d.ts +0 -151
- package/dist/surface/tools/feature-capture.js +0 -235
- package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
- package/dist/surface/tools/tool-hit-rate.js +0 -90
- package/dist/telemetry/harness-drive.d.ts +0 -4
- package/dist/telemetry/harness-drive.js +0 -35
- package/dist/telemetry/identify.d.ts +0 -22
- package/dist/telemetry/identify.js +0 -73
- package/docs/cli/capsules.mdx +0 -70
- package/docs/cli/hunt.mdx +0 -73
- package/docs/cli/identify.mdx +0 -76
- package/docs/cli/kill.mdx +0 -91
- package/docs/cli/watch.mdx +0 -62
- package/docs/local-registry.md +0 -143
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where this project's work stands with the Reticle platform, run by run.
|
|
3
|
+
*
|
|
4
|
+
* Read from the sync cycle's own record (`.reticle/cloud-state.json`): the content hash of every run
|
|
5
|
+
* the platform ACCEPTED, and the reason for every run it REFUSED. A run whose current content matches
|
|
6
|
+
* an accepted hash is on the platform; one whose current content was refused is refused, with the
|
|
7
|
+
* platform's own sentence; anything else is waiting for the next cycle. On a machine that is not
|
|
8
|
+
* linked, everything is local only.
|
|
9
|
+
*
|
|
10
|
+
* Nothing here talks to the network. It answers "did my work go up?" from what the machine already
|
|
11
|
+
* knows, so it can ride on every verdict without costing a request.
|
|
12
|
+
*/
|
|
13
|
+
import { diskSource, readCloudState } from '../cloud/sync-disk.js';
|
|
14
|
+
import { hashPayload } from '../cloud/sync-hash.js';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { ReticleDir } from '@reticlehq/core';
|
|
18
|
+
import { resolveProjectCloud } from '../cloud/cloud-config.js';
|
|
19
|
+
import { unmatchedRoots, unsyncedRoots } from '../cloud/unsynced-roots.js';
|
|
20
|
+
import { knownProjectCandidates } from './artifact-root-resolver.js';
|
|
21
|
+
export const SyncStatus = {
|
|
22
|
+
ON_PLATFORM: 'on-platform',
|
|
23
|
+
PENDING: 'pending',
|
|
24
|
+
REFUSED: 'refused',
|
|
25
|
+
LOCAL_ONLY: 'local-only',
|
|
26
|
+
};
|
|
27
|
+
/** How many refusals a summary names before it only counts them. */
|
|
28
|
+
const MAX_NAMED_REFUSALS = 3;
|
|
29
|
+
export function summarizeSync(input) {
|
|
30
|
+
const { linked, runs, state } = input;
|
|
31
|
+
let onPlatform = 0;
|
|
32
|
+
let pending = 0;
|
|
33
|
+
const refused = [];
|
|
34
|
+
let latest;
|
|
35
|
+
if (linked) {
|
|
36
|
+
for (const run of runs) {
|
|
37
|
+
const hash = hashPayload(run.payload);
|
|
38
|
+
const refusal = state.refusedRuns?.[run.runId];
|
|
39
|
+
const at = createdAtOf(run.payload);
|
|
40
|
+
if (state.sentRunHashes?.[run.runId] === hash && (latest === undefined || at > latest.at))
|
|
41
|
+
latest = { runId: run.runId, at };
|
|
42
|
+
if (state.sentRunHashes?.[run.runId] === hash)
|
|
43
|
+
onPlatform += 1;
|
|
44
|
+
else if (refusal !== undefined && refusal.payloadHash === hash)
|
|
45
|
+
refused.push({ runId: run.runId, reason: refusal.reason });
|
|
46
|
+
else
|
|
47
|
+
pending += 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
linked,
|
|
52
|
+
runs: runs.length,
|
|
53
|
+
onPlatform,
|
|
54
|
+
pending,
|
|
55
|
+
refused: refused.slice(0, MAX_NAMED_REFUSALS),
|
|
56
|
+
refusedMore: Math.max(0, refused.length - MAX_NAMED_REFUSALS),
|
|
57
|
+
...(state.lastPushAt === undefined ? {} : { lastPushAt: state.lastPushAt }),
|
|
58
|
+
...(state.lastError === undefined || 0 === state.lastError.length
|
|
59
|
+
? {}
|
|
60
|
+
: { lastError: state.lastError }),
|
|
61
|
+
...(latest === undefined ? {} : { latestOnPlatform: latest.runId }),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** A run artifact's `createdAt`, or 0 when it has none. */
|
|
65
|
+
function createdAtOf(payload) {
|
|
66
|
+
const at = 'object' === typeof payload && null !== payload
|
|
67
|
+
? payload['createdAt']
|
|
68
|
+
: undefined;
|
|
69
|
+
return 'number' === typeof at ? at : 0;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Where this project's dashboard lives, if `reticle link` recorded one.
|
|
73
|
+
*
|
|
74
|
+
* Read from the link file rather than derived from the API url, because the API origin and the
|
|
75
|
+
* console origin are different hosts in every deployment that is not a laptop. Synchronous and
|
|
76
|
+
* best-effort, like every other read in this file: a missing or malformed link file means no link
|
|
77
|
+
* in the HUD, never a failed tool call.
|
|
78
|
+
*/
|
|
79
|
+
export function readDashboardUrl(reticleRoot) {
|
|
80
|
+
return linkField(reticleRoot, 'dashboardUrl');
|
|
81
|
+
}
|
|
82
|
+
/** The platform project this folder is linked to, from the same link file. */
|
|
83
|
+
export function readLinkedProjectId(reticleRoot) {
|
|
84
|
+
return linkField(reticleRoot, 'projectId');
|
|
85
|
+
}
|
|
86
|
+
function linkField(reticleRoot, field) {
|
|
87
|
+
try {
|
|
88
|
+
const raw = JSON.parse(readFileSync(join(reticleRoot, ReticleDir.CLOUD_LINK_FILE), 'utf8'));
|
|
89
|
+
if ('object' !== typeof raw || null === raw)
|
|
90
|
+
return undefined;
|
|
91
|
+
const value = raw[field];
|
|
92
|
+
return 'string' === typeof value && value.length > 0 ? value : undefined;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** How the sync loop records a refused credential in its state. */
|
|
99
|
+
const REFUSED_SYNC = /^status 40[13]\b/;
|
|
100
|
+
/** What precedes the answer's body in that record: `status 401: `. */
|
|
101
|
+
const REFUSED_PREFIX = /^status \d+: /;
|
|
102
|
+
/** The refused credential, in words: what a person has to act on. */
|
|
103
|
+
export const KEY_REFUSED = "the platform refused this project's API key: it was revoked, or its owner no longer has access to the workspace";
|
|
104
|
+
/** The refusals the platform explains in its own words (its `error.code`). */
|
|
105
|
+
const EXPLAINED_REFUSALS = new Set([
|
|
106
|
+
'removed_from_workspace',
|
|
107
|
+
'key_lost_access',
|
|
108
|
+
]);
|
|
109
|
+
/**
|
|
110
|
+
* Why a credential was refused: the platform's own sentence when it names the reason ("You were
|
|
111
|
+
* removed from Acme.", a key whose owner lost the project), else ours. Reads an answer body.
|
|
112
|
+
*/
|
|
113
|
+
export function refusalSaid(body) {
|
|
114
|
+
try {
|
|
115
|
+
const error = JSON.parse(body)
|
|
116
|
+
?.error;
|
|
117
|
+
if ('string' === typeof error?.code &&
|
|
118
|
+
EXPLAINED_REFUSALS.has(error.code) &&
|
|
119
|
+
'string' === typeof error.message &&
|
|
120
|
+
0 < error.message.length)
|
|
121
|
+
return error.message;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Not the platform's JSON: our own sentence stands.
|
|
125
|
+
}
|
|
126
|
+
return KEY_REFUSED;
|
|
127
|
+
}
|
|
128
|
+
/** Why the platform refused this project's key at the last sync, or undefined. Never throws. */
|
|
129
|
+
export function keyRefusalAtLastSync(reticleRoot) {
|
|
130
|
+
return keyRefusalIn(readCloudState(reticleRoot).lastError);
|
|
131
|
+
}
|
|
132
|
+
/** The refusal a recorded sync error carries, in words, or undefined when it is another failure. */
|
|
133
|
+
function keyRefusalIn(error) {
|
|
134
|
+
if ('string' !== typeof error || !REFUSED_SYNC.test(error))
|
|
135
|
+
return undefined;
|
|
136
|
+
return refusalSaid(error.replace(REFUSED_PREFIX, ''));
|
|
137
|
+
}
|
|
138
|
+
/** Whether the platform refused this project's key at the last sync. Never throws. */
|
|
139
|
+
export function keyRefusedAtLastSync(reticleRoot) {
|
|
140
|
+
return keyRefusalAtLastSync(reticleRoot) !== undefined;
|
|
141
|
+
}
|
|
142
|
+
/** The dashboard's page for one run: the console's `/runs/:runId` route, at the dashboard's origin. */
|
|
143
|
+
export const DASHBOARD_RUN_PATH = '/runs/';
|
|
144
|
+
export const DASHBOARD_PLAN_PATH = '/plans/';
|
|
145
|
+
export function dashboardRunUrl(dashboardUrl, runId) {
|
|
146
|
+
return `${dashboardOrigin(dashboardUrl)}${DASHBOARD_RUN_PATH}${encodeURIComponent(runId)}`;
|
|
147
|
+
}
|
|
148
|
+
function dashboardOrigin(dashboardUrl) {
|
|
149
|
+
try {
|
|
150
|
+
return new URL(dashboardUrl).origin;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return dashboardUrl.replace(/\/+$/, ''); // not a url: use it as given
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** The line a command prints once its run reached the platform. */
|
|
157
|
+
export function seeRunLine(dashboardUrl, runId) {
|
|
158
|
+
return `See it in your dashboard: ${dashboardRunUrl(dashboardUrl, runId)}`;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* A saved Harness plan's page on the dashboard, beside its runs, under its project: opened under
|
|
162
|
+
* another project's sticky scope the page answered "We could not find that plan" to its owner.
|
|
163
|
+
*/
|
|
164
|
+
export function dashboardPlanUrl({ dashboardUrl, planId, projectId, }) {
|
|
165
|
+
const page = `${dashboardOrigin(dashboardUrl)}${DASHBOARD_PLAN_PATH}${encodeURIComponent(planId)}`;
|
|
166
|
+
return projectId === undefined ? page : `${page}?project=${encodeURIComponent(projectId)}`;
|
|
167
|
+
}
|
|
168
|
+
/** This project's summary, read from its `.reticle`. Never throws: an unreadable record is empty. */
|
|
169
|
+
export function readSyncSummary(reticleRoot, linked) {
|
|
170
|
+
let runs = [];
|
|
171
|
+
try {
|
|
172
|
+
runs = diskSource(reticleRoot).runs();
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
runs = [];
|
|
176
|
+
}
|
|
177
|
+
return summarizeSync({ linked, runs, state: readCloudState(reticleRoot) });
|
|
178
|
+
}
|
|
179
|
+
/** One status for the whole project: the worst thing true of it. */
|
|
180
|
+
export function overallStatus(summary) {
|
|
181
|
+
if (!summary.linked)
|
|
182
|
+
return SyncStatus.LOCAL_ONLY;
|
|
183
|
+
if (0 < summary.refused.length)
|
|
184
|
+
return SyncStatus.REFUSED;
|
|
185
|
+
if (0 < summary.pending || summary.lastError !== undefined)
|
|
186
|
+
return SyncStatus.PENDING;
|
|
187
|
+
return SyncStatus.ON_PLATFORM;
|
|
188
|
+
}
|
|
189
|
+
/** The summary in one sentence an agent can repeat to a person. */
|
|
190
|
+
export function describeSync(summary, now) {
|
|
191
|
+
if (!summary.linked)
|
|
192
|
+
return `${String(summary.runs)} run(s) exist only on this machine; nothing is synced until the project is linked (npx @reticlehq/server connect).`;
|
|
193
|
+
const ago = summary.lastPushAt === undefined
|
|
194
|
+
? 'nothing pushed yet'
|
|
195
|
+
: `last push ${String(Math.max(0, Math.round((now - summary.lastPushAt) / 1000)))}s ago`;
|
|
196
|
+
const parts = [`${String(summary.onPlatform)} of ${String(summary.runs)} run(s) on the platform`];
|
|
197
|
+
if (0 < summary.pending)
|
|
198
|
+
parts.push(`${String(summary.pending)} waiting for the next push`);
|
|
199
|
+
const named = summary.refused.map((r) => `${r.runId}: ${r.reason}`);
|
|
200
|
+
if (0 < named.length)
|
|
201
|
+
parts.push(`refused by the platform: ${named.join('; ')}${0 < summary.refusedMore ? ` (+${String(summary.refusedMore)} more)` : ''}`);
|
|
202
|
+
const refusal = keyRefusalIn(summary.lastError);
|
|
203
|
+
if (refusal !== undefined)
|
|
204
|
+
parts.push(`the last push was refused: ${refusal}`);
|
|
205
|
+
else if (summary.lastError !== undefined)
|
|
206
|
+
parts.push(`the last push failed: ${summary.lastError}`);
|
|
207
|
+
return `${parts.join('; ')} (${ago}).`;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Every project folder this machine knows with runs or flows the platform never got, linked by its OWN link
|
|
211
|
+
* file or not. `reticle sync` and `doctor` print these; a daemon tracks the same through its cycle.
|
|
212
|
+
*/
|
|
213
|
+
export async function machineUnsyncedRoots(fs, home, env) {
|
|
214
|
+
const roots = [
|
|
215
|
+
...knownProjectCandidates().map((c) => join(c.directory, ReticleDir.ROOT)),
|
|
216
|
+
// And what no project claimed: nothing sends it, and nothing named it after the first warning.
|
|
217
|
+
...unmatchedRoots(home),
|
|
218
|
+
];
|
|
219
|
+
const cloudOf = (root) => resolveProjectCloud(fs, root, home, env);
|
|
220
|
+
return unsyncedRoots(roots, async (root) => {
|
|
221
|
+
const cloud = await cloudOf(root);
|
|
222
|
+
return null !== cloud.config && null !== cloud.projectId;
|
|
223
|
+
}, async (root) => (await cloudOf(root)).policy.flows);
|
|
224
|
+
}
|
|
@@ -17,7 +17,12 @@ import { sessionIdShape } from '../../surface/tools/tool-kit.js';
|
|
|
17
17
|
import { asNumber, asString } from '@reticlehq/core';
|
|
18
18
|
import { sessionRoot } from '../project/session-root.js';
|
|
19
19
|
import { MemoryUnavailable, readProjectMemory } from './project-memory.js';
|
|
20
|
+
import { MemoryAction, addMemoryStatement, fetchPlatformFlow, pushFlow, setAsideStatement, } from './platform-memory.js';
|
|
21
|
+
import { flowsForSession } from '../../language/flows/flow-store-for-session.js';
|
|
22
|
+
import { safeSessionTarget } from '../project/session-root.js';
|
|
20
23
|
import { homedir } from 'node:os';
|
|
24
|
+
const NEEDS_NAME = 'needs `name`: the flow’s name';
|
|
25
|
+
const NEEDS_STATEMENT = 'needs `subject` and `statement`';
|
|
21
26
|
/**
|
|
22
27
|
* Enough to orient on, not enough to flood a context.
|
|
23
28
|
*
|
|
@@ -30,12 +35,19 @@ const ADVICE = {
|
|
|
30
35
|
[MemoryUnavailable.NOT_LINKED]: 'this project is not linked to a Reticle workspace, so there is no shared memory to read. Run `npx @reticlehq/server login` in the project to link it.',
|
|
31
36
|
[MemoryUnavailable.DISABLED]: 'this project is linked but memory sync is turned off in .reticle/cloud.json, so nothing is being shared. Enable `sync.memory` to use it.',
|
|
32
37
|
[MemoryUnavailable.UNREACHABLE]: 'the workspace could not be reached, or refused the key. Nothing is wrong with this project — try again, or check the link with `reticle status`.',
|
|
38
|
+
[MemoryUnavailable.UNVERIFIED]: 'the server answered, but the answer could not be shown to be about THIS project, so none of it is being reported. This is not an empty corpus: do NOT conclude this project knows nothing. Check the link with `reticle status`, and retry once the workspace is reachable.',
|
|
39
|
+
[MemoryUnavailable.UNREADABLE]: 'the workspace answered about THIS project, but the body was a shape this build cannot read entries out of. Retrying will not change it — this is not an empty corpus and not a link problem. Check the workspace version, and that `reticle runs memory` from the same terminal returns a `{ projectId, entries }` body.',
|
|
33
40
|
};
|
|
34
41
|
export const MEMORY_TOOLS = [
|
|
35
42
|
{
|
|
36
43
|
name: ReticleTool.MEMORY,
|
|
37
|
-
description: 'Ask what THIS PROJECT already knows — the shared memory its team has built up, written by every engineer who verified something and readable by every agent since. Use it BEFORE re-deriving how a feature is supposed to behave: a colleague may already have proved it, and a statement marked `proved` was established by a real verdict rather than written down. With { subject } it narrows to one area (a flow name, or a route like "checkout"); without, it returns across the project. Each entry carries the flow and the source file it is about, so a claim can be checked. The read is recorded as an agent consultation, which is what the dashboard\'s per-flow fetch counts are built from. Returns { subject, known, total } or { error, reason, advice } when this project is not linked to a workspace.'
|
|
44
|
+
description: 'Ask what THIS PROJECT already knows — the shared memory its team has built up, written by every engineer who verified something and readable by every agent since. Use it BEFORE re-deriving how a feature is supposed to behave: a colleague may already have proved it, and a statement marked `proved` was established by a real verdict rather than written down. With { subject } it narrows to one area (a flow name, or a route like "checkout"); without, it returns across the project. Each entry carries the flow and the source file it is about, so a claim can be checked. The read is recorded as an agent consultation, which is what the dashboard\'s per-flow fetch counts are built from. Returns { subject, known, total } or { error, reason, advice } when this project is not linked to a workspace. ' +
|
|
45
|
+
'Other actions, each answered by the platform: "flow" { name } reads one saved flow from the platform (a teammate\'s too); "add" { subject, statement } writes a statement (lands as proposed); "push-flow" { name } uploads this machine\'s saved flow, replacing the platform copy; "set-aside" { id } marks a statement stale so nobody relies on it (it is kept, not deleted).',
|
|
38
46
|
inputSchema: {
|
|
47
|
+
action: z.enum(Object.values(MemoryAction)).optional(),
|
|
48
|
+
name: z.string().optional().describe('flow / push-flow: the flow name.'),
|
|
49
|
+
statement: z.string().optional().describe('add: what is true, in prose.'),
|
|
50
|
+
id: z.string().optional().describe('set-aside: the statement id.'),
|
|
39
51
|
subject: z
|
|
40
52
|
.string()
|
|
41
53
|
.optional()
|
|
@@ -46,6 +58,10 @@ export const MEMORY_TOOLS = [
|
|
|
46
58
|
...sessionIdShape,
|
|
47
59
|
},
|
|
48
60
|
outputSchema: {
|
|
61
|
+
flow: z.unknown().optional(),
|
|
62
|
+
added: z.unknown().optional(),
|
|
63
|
+
pushed: z.string().optional(),
|
|
64
|
+
setAside: z.string().optional(),
|
|
49
65
|
subject: z.string().nullable().optional(),
|
|
50
66
|
known: z.array(z.unknown()).optional(),
|
|
51
67
|
total: z.number().optional(),
|
|
@@ -63,8 +79,37 @@ export const MEMORY_TOOLS = [
|
|
|
63
79
|
* has now been fixed three times in this codebase; routing through sessionRoot is what stops
|
|
64
80
|
* a fourth.
|
|
65
81
|
*/
|
|
66
|
-
const
|
|
82
|
+
const sid = asString(args['sessionId']);
|
|
83
|
+
const root = sessionRoot(deps, sid);
|
|
67
84
|
const subject = asString(args['subject']);
|
|
85
|
+
const action = asString(args['action']) ?? MemoryAction.READ;
|
|
86
|
+
const name = asString(args['name']);
|
|
87
|
+
if (MemoryAction.SET_ASIDE === action) {
|
|
88
|
+
const id = asString(args['id']);
|
|
89
|
+
if (id === undefined || 0 === id.trim().length)
|
|
90
|
+
return { error: `${action} needs \`id\`: the statement id from a read` };
|
|
91
|
+
return setAsideStatement(deps.fs, root, id);
|
|
92
|
+
}
|
|
93
|
+
if (MemoryAction.FLOW === action) {
|
|
94
|
+
if (name === undefined)
|
|
95
|
+
return { error: `${action} ${NEEDS_NAME}` };
|
|
96
|
+
return fetchPlatformFlow(deps.fs, root, name);
|
|
97
|
+
}
|
|
98
|
+
if (MemoryAction.PUSH_FLOW === action) {
|
|
99
|
+
if (name === undefined)
|
|
100
|
+
return { error: `${action} ${NEEDS_NAME}` };
|
|
101
|
+
const target = safeSessionTarget(deps, sid);
|
|
102
|
+
const saved = await flowsForSession(deps, target).flows.load(name, target.projectId);
|
|
103
|
+
if (!saved.ok)
|
|
104
|
+
return { error: `no saved flow named "${name}" on this machine`, reason: saved.code };
|
|
105
|
+
return pushFlow(deps.fs, root, saved.value, target.projectId);
|
|
106
|
+
}
|
|
107
|
+
if (MemoryAction.ADD === action) {
|
|
108
|
+
const statement = asString(args['statement']);
|
|
109
|
+
if (subject === undefined || statement === undefined || 0 === statement.trim().length)
|
|
110
|
+
return { error: `${action} ${NEEDS_STATEMENT}` };
|
|
111
|
+
return addMemoryStatement(deps.fs, root, { subject, statement });
|
|
112
|
+
}
|
|
68
113
|
const result = await readProjectMemory(deps.fs, root, homedir(), process.env, {
|
|
69
114
|
subject,
|
|
70
115
|
limit: asNumber(args['limit']) ?? DEFAULT_LIMIT,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { FileSystemPort } from '../project/fs/fs-port.js';
|
|
2
|
+
import type { FlowFile } from '@reticlehq/core';
|
|
3
|
+
/** What `reticle_memory` can be asked to do. `read` is the default and needs no `action`. */
|
|
4
|
+
export declare const MemoryAction: {
|
|
5
|
+
readonly READ: "read";
|
|
6
|
+
readonly FLOW: "flow";
|
|
7
|
+
readonly ADD: "add";
|
|
8
|
+
readonly SET_ASIDE: "set-aside";
|
|
9
|
+
readonly PUSH_FLOW: "push-flow";
|
|
10
|
+
};
|
|
11
|
+
export type MemoryAction = (typeof MemoryAction)[keyof typeof MemoryAction];
|
|
12
|
+
/** Why the platform would not set a statement aside, each from its own answer. */
|
|
13
|
+
export declare const SetAsideRefused: {
|
|
14
|
+
readonly NO_SUCH_STATEMENT: "no-such-statement";
|
|
15
|
+
readonly NOT_ALLOWED: "not-allowed";
|
|
16
|
+
readonly REFUSED: "refused";
|
|
17
|
+
};
|
|
18
|
+
export type PlatformAnswer = Record<string, unknown>;
|
|
19
|
+
/** One saved flow from the platform: a teammate's, or this project's as the platform holds it. */
|
|
20
|
+
export declare function fetchPlatformFlow(fs: FileSystemPort, root: string, name: string): Promise<PlatformAnswer>;
|
|
21
|
+
/** Add one statement to the project's memory. It lands as a proposal; only a passing check proves it. */
|
|
22
|
+
export declare function addMemoryStatement(fs: FileSystemPort, root: string, entry: {
|
|
23
|
+
subject: string;
|
|
24
|
+
statement: string;
|
|
25
|
+
flowName?: string | undefined;
|
|
26
|
+
}): Promise<PlatformAnswer>;
|
|
27
|
+
/** Put this machine's saved flow on the platform now, replacing the platform's copy of that name. */
|
|
28
|
+
export declare function pushFlow(fs: FileSystemPort, root: string, flow: FlowFile, projectId: string | undefined): Promise<PlatformAnswer>;
|
|
29
|
+
/**
|
|
30
|
+
* Set one statement aside: the platform keeps it, marked stale, and stops offering it as known. The
|
|
31
|
+
* one change a project key may make to a statement; proving one takes a passing check, and new
|
|
32
|
+
* words on a settled one are the team's to agree.
|
|
33
|
+
*/
|
|
34
|
+
export declare function setAsideStatement(fs: FileSystemPort, root: string, intentId: string): Promise<PlatformAnswer>;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent's writes to the platform, and its read of one flow, beside `readProjectMemory`.
|
|
3
|
+
*
|
|
4
|
+
* Every call here is answered by the platform before the tool answers, so an agent is told whether
|
|
5
|
+
* the platform has it rather than trusting a later sync cycle to carry it. Each reads the link of the
|
|
6
|
+
* project being driven (its `.reticle`, not the daemon's) and names that project on the wire.
|
|
7
|
+
*/
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { cloudFetch, syncFlowToCloud, SyncOutcome } from '../cloud/cloud-sync.js';
|
|
10
|
+
import { resolveProjectCloud } from '../cloud/cloud-config.js';
|
|
11
|
+
import { MemoryUnavailable } from './project-memory.js';
|
|
12
|
+
/** What `reticle_memory` can be asked to do. `read` is the default and needs no `action`. */
|
|
13
|
+
export const MemoryAction = {
|
|
14
|
+
READ: 'read',
|
|
15
|
+
FLOW: 'flow',
|
|
16
|
+
ADD: 'add',
|
|
17
|
+
SET_ASIDE: 'set-aside',
|
|
18
|
+
PUSH_FLOW: 'push-flow',
|
|
19
|
+
};
|
|
20
|
+
/** Why the platform would not set a statement aside, each from its own answer. */
|
|
21
|
+
export const SetAsideRefused = {
|
|
22
|
+
NO_SUCH_STATEMENT: 'no-such-statement',
|
|
23
|
+
NOT_ALLOWED: 'not-allowed',
|
|
24
|
+
REFUSED: 'refused',
|
|
25
|
+
};
|
|
26
|
+
/** The status a statement set aside takes on the platform: kept, but no longer relied on. */
|
|
27
|
+
const STALE = 'stale';
|
|
28
|
+
const MEMORY_PATH = '/v1/memory';
|
|
29
|
+
const FLOWS_PATH = '/v1/flows';
|
|
30
|
+
const NOT_FOUND = 'not-found';
|
|
31
|
+
const HTTP_NOT_FOUND = 404;
|
|
32
|
+
const HTTP_FORBIDDEN = 403;
|
|
33
|
+
const HTTP_BAD_REQUEST = 400;
|
|
34
|
+
const unavailable = (reason, error) => ({ error, reason });
|
|
35
|
+
const UNREACHABLE = unavailable(MemoryUnavailable.UNREACHABLE, 'the platform could not be reached, or refused this project’s key');
|
|
36
|
+
/** The link, or the reason there is none. Writes honour `sync.memory` / `sync.flows` like the sync. */
|
|
37
|
+
async function linked(fs, root, allowed) {
|
|
38
|
+
const cloud = await resolveProjectCloud(fs, root, homedir(), process.env);
|
|
39
|
+
const { config } = cloud;
|
|
40
|
+
if (null === config)
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
answer: unavailable(MemoryUnavailable.NOT_LINKED, 'this project is not linked to the platform'),
|
|
44
|
+
};
|
|
45
|
+
if (!allowed(cloud))
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
answer: unavailable(MemoryUnavailable.DISABLED, 'this kind of sync is off in .reticle/cloud.json'),
|
|
49
|
+
};
|
|
50
|
+
return { ok: true, cloud: { ...cloud, config } };
|
|
51
|
+
}
|
|
52
|
+
const headers = (apiKey) => ({
|
|
53
|
+
'content-type': 'application/json',
|
|
54
|
+
authorization: `Bearer ${apiKey}`,
|
|
55
|
+
});
|
|
56
|
+
const projectQuery = (projectId) => null === projectId ? '' : `?projectId=${encodeURIComponent(projectId)}`;
|
|
57
|
+
/** One saved flow from the platform: a teammate's, or this project's as the platform holds it. */
|
|
58
|
+
export async function fetchPlatformFlow(fs, root, name) {
|
|
59
|
+
const link = await linked(fs, root, (c) => c.policy.flows);
|
|
60
|
+
if (!link.ok)
|
|
61
|
+
return link.answer;
|
|
62
|
+
const { config, projectId } = link.cloud;
|
|
63
|
+
try {
|
|
64
|
+
const res = await cloudFetch(`${config.url}${FLOWS_PATH}/${encodeURIComponent(name)}${projectQuery(projectId)}`, { method: 'GET', headers: headers(config.apiKey) });
|
|
65
|
+
if (HTTP_NOT_FOUND === res.status)
|
|
66
|
+
return unavailable(NOT_FOUND, `the platform holds no flow named "${name}" for this project`);
|
|
67
|
+
if (200 !== res.status)
|
|
68
|
+
return UNREACHABLE;
|
|
69
|
+
const flow = await res.json();
|
|
70
|
+
return { flow };
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return UNREACHABLE;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Add one statement to the project's memory. It lands as a proposal; only a passing check proves it. */
|
|
77
|
+
export async function addMemoryStatement(fs, root, entry) {
|
|
78
|
+
const link = await linked(fs, root, (c) => c.policy.memory);
|
|
79
|
+
if (!link.ok)
|
|
80
|
+
return link.answer;
|
|
81
|
+
const { config, projectId } = link.cloud;
|
|
82
|
+
try {
|
|
83
|
+
const res = await cloudFetch(`${config.url}${MEMORY_PATH}`, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: headers(config.apiKey),
|
|
86
|
+
body: JSON.stringify({
|
|
87
|
+
subject: entry.subject,
|
|
88
|
+
statement: entry.statement,
|
|
89
|
+
...(entry.flowName === undefined ? {} : { flowName: entry.flowName }),
|
|
90
|
+
...(null === projectId ? {} : { projectId }),
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
if (res.status >= 300)
|
|
94
|
+
return UNREACHABLE;
|
|
95
|
+
const added = await res.json();
|
|
96
|
+
return { added };
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return UNREACHABLE;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Put this machine's saved flow on the platform now, replacing the platform's copy of that name. */
|
|
103
|
+
export async function pushFlow(fs, root, flow, projectId) {
|
|
104
|
+
const link = await linked(fs, root, (c) => c.policy.flows);
|
|
105
|
+
if (!link.ok)
|
|
106
|
+
return link.answer;
|
|
107
|
+
const result = await syncFlowToCloud(flow, link.cloud.config, projectId, cloudFetch);
|
|
108
|
+
return SyncOutcome.SYNCED === result.outcome ? { pushed: flow.name } : UNREACHABLE;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Set one statement aside: the platform keeps it, marked stale, and stops offering it as known. The
|
|
112
|
+
* one change a project key may make to a statement; proving one takes a passing check, and new
|
|
113
|
+
* words on a settled one are the team's to agree.
|
|
114
|
+
*/
|
|
115
|
+
export async function setAsideStatement(fs, root, intentId) {
|
|
116
|
+
const link = await linked(fs, root, (c) => c.policy.memory);
|
|
117
|
+
if (!link.ok)
|
|
118
|
+
return link.answer;
|
|
119
|
+
const { config } = link.cloud;
|
|
120
|
+
try {
|
|
121
|
+
const res = await cloudFetch(`${config.url}${MEMORY_PATH}/${encodeURIComponent(intentId)}`, {
|
|
122
|
+
method: 'PATCH',
|
|
123
|
+
headers: headers(config.apiKey),
|
|
124
|
+
body: JSON.stringify({ status: STALE }),
|
|
125
|
+
});
|
|
126
|
+
if (HTTP_NOT_FOUND === res.status)
|
|
127
|
+
return unavailable(SetAsideRefused.NO_SUCH_STATEMENT, `the platform holds no statement "${intentId}" in this project. Read reticle_memory again for the current ids.`);
|
|
128
|
+
if (HTTP_FORBIDDEN === res.status)
|
|
129
|
+
return unavailable(SetAsideRefused.NOT_ALLOWED, 'the platform refused: the teammate who made this project’s key may not change flows or memory. Ask the user to set it aside on the dashboard (Memory), and meanwhile do not rely on it.');
|
|
130
|
+
if (HTTP_BAD_REQUEST === res.status)
|
|
131
|
+
return unavailable(SetAsideRefused.REFUSED, 'the platform refused the change: with a project key a statement can only be set aside.');
|
|
132
|
+
if (res.status >= 300)
|
|
133
|
+
return UNREACHABLE;
|
|
134
|
+
return { setAside: intentId };
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return UNREACHABLE;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -7,6 +7,25 @@ export declare const MemoryUnavailable: {
|
|
|
7
7
|
readonly DISABLED: "memory-sync-disabled";
|
|
8
8
|
/** The server was reached and said no, or could not be reached at all. */
|
|
9
9
|
readonly UNREACHABLE: "unreachable";
|
|
10
|
+
/**
|
|
11
|
+
* The server answered, and the answer could not be shown to be about THIS project: its envelope
|
|
12
|
+
* named another one, or named none at all.
|
|
13
|
+
*
|
|
14
|
+
* Its own reason rather than an empty list, because the two are opposite facts about the corpus.
|
|
15
|
+
* "This project knows nothing" is something an agent can act on; "we cannot tell whose knowledge
|
|
16
|
+
* this is" is something it must not, and an empty list reports the first while meaning the second.
|
|
17
|
+
*/
|
|
18
|
+
readonly UNVERIFIED: "unverified";
|
|
19
|
+
/**
|
|
20
|
+
* The server answered about THIS project, and the body is a shape this build cannot read entries
|
|
21
|
+
* out of — no `entries` field, or one that is not a list.
|
|
22
|
+
*
|
|
23
|
+
* Apart from `UNREACHABLE` on purpose. That reason's advice is "try again, or check the link", and
|
|
24
|
+
* neither applies: the workspace WAS reached, its answer IS this project's, and the shape will be
|
|
25
|
+
* the same on the second attempt. Sending an agent to retry it costs a round trip and teaches it
|
|
26
|
+
* to distrust a link that is fine, which is what a reason is for.
|
|
27
|
+
*/
|
|
28
|
+
readonly UNREADABLE: "unreadable";
|
|
10
29
|
};
|
|
11
30
|
export type MemoryUnavailable = (typeof MemoryUnavailable)[keyof typeof MemoryUnavailable];
|
|
12
31
|
export interface KnownThing {
|
|
@@ -12,8 +12,13 @@
|
|
|
12
12
|
* question the fetch counters exist to answer and could not while nothing was reading.
|
|
13
13
|
*/
|
|
14
14
|
import { cloudFetch } from '../cloud/cloud-sync.js';
|
|
15
|
+
import { callingClientName } from '../../hooks/coding-agents.js';
|
|
15
16
|
import { resolveProjectCloud } from '../cloud/cloud-config.js';
|
|
16
|
-
|
|
17
|
+
import { isReadableMemoryScope, MemoryReadHeader, memoryReadUrl, scopedMemoryEntries, scopeOfMemoryResponse, } from '../cloud/memory-scope.js';
|
|
18
|
+
/**
|
|
19
|
+
* Named so a read from the tool surface is distinguishable from the CLI's and from replay's. The
|
|
20
|
+
* reader is the MCP client that made the call when one can be named; this only when none can.
|
|
21
|
+
*/
|
|
17
22
|
const MCP_AGENT_ID = 'reticle-mcp';
|
|
18
23
|
/** Why a lookup returned nothing. Each one is a different thing for the agent to do next. */
|
|
19
24
|
export const MemoryUnavailable = {
|
|
@@ -23,6 +28,25 @@ export const MemoryUnavailable = {
|
|
|
23
28
|
DISABLED: 'memory-sync-disabled',
|
|
24
29
|
/** The server was reached and said no, or could not be reached at all. */
|
|
25
30
|
UNREACHABLE: 'unreachable',
|
|
31
|
+
/**
|
|
32
|
+
* The server answered, and the answer could not be shown to be about THIS project: its envelope
|
|
33
|
+
* named another one, or named none at all.
|
|
34
|
+
*
|
|
35
|
+
* Its own reason rather than an empty list, because the two are opposite facts about the corpus.
|
|
36
|
+
* "This project knows nothing" is something an agent can act on; "we cannot tell whose knowledge
|
|
37
|
+
* this is" is something it must not, and an empty list reports the first while meaning the second.
|
|
38
|
+
*/
|
|
39
|
+
UNVERIFIED: 'unverified',
|
|
40
|
+
/**
|
|
41
|
+
* The server answered about THIS project, and the body is a shape this build cannot read entries
|
|
42
|
+
* out of — no `entries` field, or one that is not a list.
|
|
43
|
+
*
|
|
44
|
+
* Apart from `UNREACHABLE` on purpose. That reason's advice is "try again, or check the link", and
|
|
45
|
+
* neither applies: the workspace WAS reached, its answer IS this project's, and the shape will be
|
|
46
|
+
* the same on the second attempt. Sending an agent to retry it costs a round trip and teaches it
|
|
47
|
+
* to distrust a link that is fine, which is what a reason is for.
|
|
48
|
+
*/
|
|
49
|
+
UNREADABLE: 'unreadable',
|
|
26
50
|
};
|
|
27
51
|
/** Defensive: the wire is somebody else's server, so every field is checked before it is trusted. */
|
|
28
52
|
const asKnown = (raw) => {
|
|
@@ -48,25 +72,55 @@ const asKnown = (raw) => {
|
|
|
48
72
|
* twice returns the same order — an unstable list reads as the corpus churning when it has not.
|
|
49
73
|
*/
|
|
50
74
|
const PROVED = 'proved';
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
const AGREED = 'agreed';
|
|
76
|
+
/** Set aside on the dashboard or by `reticle_memory {set-aside}`: nobody stands by it any more. */
|
|
77
|
+
const SET_ASIDE = 'stale';
|
|
78
|
+
/** Then agreed, then what a person wrote (no flow behind it), then flow intents. */
|
|
79
|
+
const RANKS = [
|
|
80
|
+
(t) => PROVED === t.status,
|
|
81
|
+
(t) => AGREED === t.status,
|
|
82
|
+
(t) => null === t.flowName,
|
|
83
|
+
() => true,
|
|
54
84
|
];
|
|
85
|
+
export const rankKnown = (things) => things
|
|
86
|
+
.map((thing, at) => ({ thing, at, rank: RANKS.findIndex((fits) => fits(thing)) }))
|
|
87
|
+
.sort((a, b) => a.rank - b.rank || a.at - b.at)
|
|
88
|
+
.map((r) => r.thing);
|
|
89
|
+
/**
|
|
90
|
+
* What a read can show: each statement once (a persona's intent saved on six pages pushed a
|
|
91
|
+
* person's own fact past the cap) and nothing set aside (it ranked second seconds after).
|
|
92
|
+
*/
|
|
93
|
+
const liveAndDistinct = (things) => {
|
|
94
|
+
const seen = new Set();
|
|
95
|
+
return rankKnown(things.filter((t) => SET_ASIDE !== t.status)).filter((t) => {
|
|
96
|
+
const key = t.statement.trim();
|
|
97
|
+
if (seen.has(key))
|
|
98
|
+
return false;
|
|
99
|
+
seen.add(key);
|
|
100
|
+
return true;
|
|
101
|
+
});
|
|
102
|
+
};
|
|
55
103
|
export async function readProjectMemory(fs, root, home, env, opts) {
|
|
56
104
|
const cloud = await resolveProjectCloud(fs, root, home, env);
|
|
57
105
|
if (null === cloud.config)
|
|
58
106
|
return { ok: false, reason: MemoryUnavailable.NOT_LINKED };
|
|
59
107
|
if (!cloud.policy.memory)
|
|
60
108
|
return { ok: false, reason: MemoryUnavailable.DISABLED };
|
|
61
|
-
|
|
109
|
+
// Scoped to the LINKED project, not to whatever the key happens to cover. A workspace can hold
|
|
110
|
+
// more than one repo, and a read that named no project could be answered with another one's
|
|
111
|
+
// established knowledge — indistinguishable from this project's, and acted on. See memory-scope.
|
|
112
|
+
const url = memoryReadUrl(cloud.config.url, {
|
|
113
|
+
projectId: cloud.projectId,
|
|
114
|
+
subject: opts.subject,
|
|
115
|
+
});
|
|
62
116
|
try {
|
|
63
|
-
const res = await cloudFetch(
|
|
117
|
+
const res = await cloudFetch(url, {
|
|
64
118
|
method: 'GET',
|
|
65
119
|
headers: {
|
|
66
120
|
authorization: `Bearer ${cloud.config.apiKey}`,
|
|
67
121
|
// What makes this read COUNT as an agent consulting the corpus rather than a human
|
|
68
122
|
// browsing — the distinction the dashboard's "times an agent consulted it" rests on.
|
|
69
|
-
|
|
123
|
+
[MemoryReadHeader.AGENT]: callingClientName() ?? MCP_AGENT_ID,
|
|
70
124
|
},
|
|
71
125
|
});
|
|
72
126
|
if (200 !== res.status)
|
|
@@ -75,18 +129,31 @@ export async function readProjectMemory(fs, root, home, env, opts) {
|
|
|
75
129
|
// property yields the function, and every downstream field is undefined — a silent "the project
|
|
76
130
|
// knows nothing" that is indistinguishable from the honest empty case. It cost a live drive to
|
|
77
131
|
// find once already.
|
|
78
|
-
const body =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
132
|
+
const body = await res.json();
|
|
133
|
+
// The envelope first, and it decides everything. The platform names the project on the response
|
|
134
|
+
// and NOT on each entry, so an entry-level filter alone keeps a whole sibling workspace while
|
|
135
|
+
// looking like it did something — see `memory-scope.ts`. A response that names another project,
|
|
136
|
+
// or names none, is UNVERIFIED: not empty, and not this project's.
|
|
137
|
+
const entries = scopedMemoryEntries(body, cloud.projectId);
|
|
138
|
+
if (entries === undefined) {
|
|
139
|
+
return {
|
|
140
|
+
ok: false,
|
|
141
|
+
reason: isReadableMemoryScope(scopeOfMemoryResponse(body, cloud.projectId))
|
|
142
|
+
? MemoryUnavailable.UNREADABLE // scoped fine, but no readable `entries` — a shape we do not know
|
|
143
|
+
: MemoryUnavailable.UNVERIFIED,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// The entry-level pass is redundant against the envelope check above and kept for a server that
|
|
147
|
+
// labels entries instead. `total` is counted AFTER it, so a truncated list still tells the truth
|
|
148
|
+
// about how many of THIS project's statements there were.
|
|
149
|
+
const known = liveAndDistinct(entries.map(asKnown).filter((k) => k !== null));
|
|
83
150
|
return {
|
|
84
151
|
ok: true,
|
|
85
152
|
subject: opts.subject ?? null,
|
|
86
153
|
// Capped for the agent's context, but `total` always reports the truth so the cap is never
|
|
87
154
|
// silent — a truncated list that looks complete is how an agent concludes a project knows
|
|
88
155
|
// less than it does.
|
|
89
|
-
known:
|
|
156
|
+
known: known.slice(0, opts.limit),
|
|
90
157
|
total: known.length,
|
|
91
158
|
};
|
|
92
159
|
}
|