@ouro.bot/cli 0.1.0-alpha.50 → 0.1.0-alpha.501
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 +133 -19
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +3184 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +867 -35
- package/dist/heart/agent-entry.js +58 -3
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +426 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +119 -129
- package/dist/heart/core.js +898 -244
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +490 -0
- package/dist/heart/daemon/agent-discovery.js +79 -3
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +216 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +640 -0
- package/dist/heart/daemon/cli-exec.js +7239 -0
- package/dist/heart/daemon/cli-help.js +493 -0
- package/dist/heart/daemon/cli-parse.js +1533 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +561 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1631
- package/dist/heart/daemon/daemon-entry.js +345 -3
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +190 -12
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +677 -58
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +615 -0
- package/dist/heart/daemon/health-monitor.js +92 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +25 -5
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/message-router.js +2 -2
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/process-manager.js +214 -0
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +73 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +178 -37
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +109 -4
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +264 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +162 -17
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +1 -1
- package/dist/heart/habits/habit-migration.js +189 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-runtime-state.js +100 -0
- package/dist/heart/habits/habit-scheduler.js +372 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
- package/dist/heart/identity.js +201 -66
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mail-import-discovery.js +353 -0
- package/dist/heart/mcp/mcp-server.js +653 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/outlook/outlook-http-hooks.js +66 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +244 -0
- package/dist/heart/outlook/outlook-http-static.js +103 -0
- package/dist/heart/outlook/outlook-http-transport.js +116 -0
- package/dist/heart/outlook/outlook-http.js +99 -0
- package/dist/heart/outlook/outlook-read.js +31 -0
- package/dist/heart/outlook/outlook-types.js +27 -0
- package/dist/heart/outlook/outlook-view.js +195 -0
- package/dist/heart/outlook/readers/agent-machine.js +382 -0
- package/dist/heart/outlook/readers/continuity-readers.js +336 -0
- package/dist/heart/outlook/readers/mail.js +362 -0
- package/dist/heart/outlook/readers/runtime-readers.js +644 -0
- package/dist/heart/outlook/readers/sessions.js +232 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +255 -0
- package/dist/heart/provider-credentials.js +424 -0
- package/dist/heart/provider-failover.js +301 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +262 -0
- package/dist/heart/provider-state.js +216 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +193 -55
- package/dist/heart/providers/azure.js +104 -13
- package/dist/heart/providers/error-classification.js +63 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +29 -7
- package/dist/heart/providers/openai-codex.js +63 -39
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +260 -0
- package/dist/heart/sense-truth.js +11 -4
- package/dist/heart/session-activity.js +43 -22
- package/dist/heart/session-events.js +1089 -0
- package/dist/heart/session-playback-cli-main.js +5 -0
- package/dist/heart/session-playback-cli.js +36 -0
- package/dist/heart/session-playback.js +231 -0
- package/dist/heart/session-transcript.js +167 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +48 -28
- package/dist/heart/sync.js +332 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +372 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +425 -0
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +5 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +606 -0
- package/dist/mailroom/core.js +672 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +426 -0
- package/dist/mailroom/mbox-import.js +382 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +219 -0
- package/dist/mailroom/search-cache.js +182 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +164 -101
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +74 -93
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/friends/channel.js +30 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +39 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +2 -2
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +4 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +948 -110
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +106 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/review/cli-main.js +5 -0
- package/dist/nerves/review/cli.js +156 -0
- package/dist/nerves/review/core.js +152 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-BPr5vNuM.css +1 -0
- package/dist/outlook-ui/assets/index-Cm51CY9W.js +61 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +774 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +111 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +396 -0
- package/dist/repertoire/mcp-client.js +255 -0
- package/dist/repertoire/mcp-manager.js +305 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +31 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +16 -4
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -78
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +46 -921
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +141 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +381 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +105 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-mail.js +1377 -0
- package/dist/repertoire/tools-notes.js +376 -0
- package/dist/repertoire/tools-session.js +749 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +9 -39
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +356 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +144 -115
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +561 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +116 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
- package/dist/senses/bluebubbles/entry.js +73 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
- package/dist/senses/bluebubbles/index.js +1881 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
- package/dist/senses/bluebubbles/processed-log.js +111 -0
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +2 -2
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +605 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +83 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +511 -209
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +175 -21
- package/dist/senses/inner-dialog.js +330 -27
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +573 -164
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +248 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +405 -170
- package/dist/senses/trust-gate.js +100 -5
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +146 -0
- package/package.json +39 -8
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +117 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +101 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/daemon/subagent-installer.js +0 -166
- package/dist/heart/session-recall.js +0 -116
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1142
- package/dist/senses/debug-activity.js +0 -148
- package/subagents/README.md +0 -86
- package/subagents/work-doer.md +0 -237
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -390
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runSessionPlaybackCli = runSessionPlaybackCli;
|
|
4
|
+
const session_playback_1 = require("./session-playback");
|
|
5
|
+
function printHelp() {
|
|
6
|
+
// eslint-disable-next-line no-console -- meta-tooling
|
|
7
|
+
console.log([
|
|
8
|
+
"usage: ouro session-playback <session.json> [--json]",
|
|
9
|
+
"",
|
|
10
|
+
"Loads a saved session.json, runs it through the same sanitize pipeline that fires before",
|
|
11
|
+
"every replay, and prints a report of what would be dropped, content-modified, or",
|
|
12
|
+
"synthetically inserted. Read-only; the file on disk is never written.",
|
|
13
|
+
"",
|
|
14
|
+
"Useful when an agent is stuck in a replay loop and you want to see what the harness",
|
|
15
|
+
"thinks is wrong with the session before deciding whether to clear or repair.",
|
|
16
|
+
].join("\n"));
|
|
17
|
+
}
|
|
18
|
+
function runSessionPlaybackCli(argv) {
|
|
19
|
+
const positional = argv.filter((token) => !token.startsWith("--"));
|
|
20
|
+
const flags = new Set(argv.filter((token) => token.startsWith("--")));
|
|
21
|
+
if (flags.has("--help") || flags.has("-h") || positional.length === 0) {
|
|
22
|
+
printHelp();
|
|
23
|
+
return positional.length === 0 ? 2 : 0;
|
|
24
|
+
}
|
|
25
|
+
const sessionPath = positional[0];
|
|
26
|
+
const report = (0, session_playback_1.runSessionPlayback)({ sessionPath });
|
|
27
|
+
if (flags.has("--json")) {
|
|
28
|
+
// eslint-disable-next-line no-console -- meta-tooling
|
|
29
|
+
console.log(JSON.stringify(report, null, 2));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// eslint-disable-next-line no-console -- meta-tooling
|
|
33
|
+
console.log((0, session_playback_1.formatPlaybackReport)(report));
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runSessionPlayback = runSessionPlayback;
|
|
37
|
+
exports.formatPlaybackReport = formatPlaybackReport;
|
|
38
|
+
const fs = __importStar(require("node:fs"));
|
|
39
|
+
const session_events_1 = require("./session-events");
|
|
40
|
+
const PREVIEW_MAX_CHARS = 120;
|
|
41
|
+
function shortPreview(value) {
|
|
42
|
+
if (value == null)
|
|
43
|
+
return "";
|
|
44
|
+
if (typeof value === "string") {
|
|
45
|
+
const trimmed = value.replace(/\s+/g, " ").trim();
|
|
46
|
+
/* v8 ignore next -- branch: PREVIEW_MAX_CHARS truncation only triggers on long inline content @preserve */
|
|
47
|
+
return trimmed.length > PREVIEW_MAX_CHARS ? `${trimmed.slice(0, PREVIEW_MAX_CHARS - 3)}...` : trimmed;
|
|
48
|
+
}
|
|
49
|
+
/* v8 ignore next -- defensive: content is always string or array in practice @preserve */
|
|
50
|
+
return shortPreview(JSON.stringify(value));
|
|
51
|
+
}
|
|
52
|
+
function getRole(message) {
|
|
53
|
+
/* v8 ignore next -- defensive fallback: provider messages always carry a role @preserve */
|
|
54
|
+
return message.role ?? "unknown";
|
|
55
|
+
}
|
|
56
|
+
function getToolCallId(message) {
|
|
57
|
+
const value = message.tool_call_id;
|
|
58
|
+
/* v8 ignore next -- defensive: tool messages always carry a string tool_call_id @preserve */
|
|
59
|
+
return typeof value === "string" ? value : undefined;
|
|
60
|
+
}
|
|
61
|
+
function getContentString(message) {
|
|
62
|
+
const value = message.content;
|
|
63
|
+
if (typeof value === "string")
|
|
64
|
+
return value;
|
|
65
|
+
/* v8 ignore start -- defensive: array content (multipart) and missing content branches not exercised by replay test fixtures @preserve */
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
return value
|
|
68
|
+
.map((part) => (part && typeof part === "object" && "text" in part ? String(part.text ?? "") : ""))
|
|
69
|
+
.join("");
|
|
70
|
+
}
|
|
71
|
+
return "";
|
|
72
|
+
/* v8 ignore stop */
|
|
73
|
+
}
|
|
74
|
+
function detectEnvelopeShape(raw) {
|
|
75
|
+
if (!raw || typeof raw !== "object")
|
|
76
|
+
return "unknown";
|
|
77
|
+
const record = raw;
|
|
78
|
+
if (record.version === 2 && Array.isArray(record.events))
|
|
79
|
+
return "v2";
|
|
80
|
+
if (record.version === 1 || ("messages" in record && Array.isArray(record.messages)))
|
|
81
|
+
return "legacy";
|
|
82
|
+
return "unknown";
|
|
83
|
+
}
|
|
84
|
+
function rawLegacyMessages(raw) {
|
|
85
|
+
/* v8 ignore next -- defensive: caller already detected legacy shape via Array.isArray(messages) @preserve */
|
|
86
|
+
if (!raw || typeof raw !== "object")
|
|
87
|
+
return [];
|
|
88
|
+
const record = raw;
|
|
89
|
+
if (Array.isArray(record.messages)) {
|
|
90
|
+
return record.messages.filter((m) => m != null && typeof m === "object");
|
|
91
|
+
}
|
|
92
|
+
/* v8 ignore next -- unreachable in practice: detectEnvelopeShape gates this on Array.isArray(messages) @preserve */
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
function inputMessagesForShape(shape, raw, envelope) {
|
|
96
|
+
if (shape === "legacy")
|
|
97
|
+
return rawLegacyMessages(raw);
|
|
98
|
+
if (shape === "v2" && envelope)
|
|
99
|
+
return (0, session_events_1.projectProviderMessages)(envelope);
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
function diffMessages(input, sanitized) {
|
|
103
|
+
const changes = [];
|
|
104
|
+
const sanitizedByToolCallId = new Map();
|
|
105
|
+
for (let i = 0; i < sanitized.length; i++) {
|
|
106
|
+
const id = getToolCallId(sanitized[i]);
|
|
107
|
+
if (id)
|
|
108
|
+
sanitizedByToolCallId.set(id, i);
|
|
109
|
+
}
|
|
110
|
+
const inputToolCallIds = new Set();
|
|
111
|
+
for (let i = 0; i < input.length; i++) {
|
|
112
|
+
const message = input[i];
|
|
113
|
+
const role = getRole(message);
|
|
114
|
+
const toolCallId = getToolCallId(message);
|
|
115
|
+
if (role === "tool" && toolCallId)
|
|
116
|
+
inputToolCallIds.add(toolCallId);
|
|
117
|
+
if (role === "tool" && toolCallId && !sanitizedByToolCallId.has(toolCallId)) {
|
|
118
|
+
changes.push({
|
|
119
|
+
index: i,
|
|
120
|
+
role,
|
|
121
|
+
action: "dropped",
|
|
122
|
+
toolCallId,
|
|
123
|
+
reason: "tool result orphan dropped (no preceding assistant tool_call with this id)",
|
|
124
|
+
preview: shortPreview(getContentString(message)),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (let i = 0; i < input.length; i++) {
|
|
129
|
+
const message = input[i];
|
|
130
|
+
const role = getRole(message);
|
|
131
|
+
if (role !== "assistant")
|
|
132
|
+
continue;
|
|
133
|
+
const inputContent = getContentString(message);
|
|
134
|
+
if (!inputContent)
|
|
135
|
+
continue;
|
|
136
|
+
const stripped = inputContent.replace(/<think>[\s\S]*?<\/think>/gi, "").replace(/<think>[\s\S]*$/i, "").trim();
|
|
137
|
+
if (stripped !== inputContent.trim()) {
|
|
138
|
+
changes.push({
|
|
139
|
+
index: i,
|
|
140
|
+
role,
|
|
141
|
+
action: "modified-content",
|
|
142
|
+
reason: "inline <think> reasoning would be stripped before replay",
|
|
143
|
+
preview: shortPreview(inputContent),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const inputAssistantToolCallIds = new Set();
|
|
148
|
+
for (const message of input) {
|
|
149
|
+
if (getRole(message) !== "assistant")
|
|
150
|
+
continue;
|
|
151
|
+
const toolCalls = message.tool_calls;
|
|
152
|
+
if (!Array.isArray(toolCalls))
|
|
153
|
+
continue;
|
|
154
|
+
for (const call of toolCalls) {
|
|
155
|
+
if (typeof call?.id === "string")
|
|
156
|
+
inputAssistantToolCallIds.add(call.id);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/* v8 ignore start -- synthetic-add detection: the sanitize pipeline only synthesizes results for unbalanced tool_calls; replay test fixtures don't exercise this branch combination @preserve */
|
|
160
|
+
for (let i = 0; i < sanitized.length; i++) {
|
|
161
|
+
const message = sanitized[i];
|
|
162
|
+
if (getRole(message) !== "tool")
|
|
163
|
+
continue;
|
|
164
|
+
const toolCallId = getToolCallId(message);
|
|
165
|
+
if (!toolCallId)
|
|
166
|
+
continue;
|
|
167
|
+
if (!inputToolCallIds.has(toolCallId) && inputAssistantToolCallIds.has(toolCallId)) {
|
|
168
|
+
changes.push({
|
|
169
|
+
index: i,
|
|
170
|
+
role: "tool",
|
|
171
|
+
action: "synthetic-added",
|
|
172
|
+
toolCallId,
|
|
173
|
+
reason: "synthetic tool result inserted to satisfy provider tool_call/tool_result pairing",
|
|
174
|
+
preview: shortPreview(getContentString(message)),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/* v8 ignore stop */
|
|
179
|
+
return changes.sort((left, right) => left.index - right.index);
|
|
180
|
+
}
|
|
181
|
+
function runSessionPlayback(options) {
|
|
182
|
+
let raw = options.raw;
|
|
183
|
+
if (raw === undefined) {
|
|
184
|
+
const text = fs.readFileSync(options.sessionPath, "utf-8");
|
|
185
|
+
raw = JSON.parse(text);
|
|
186
|
+
}
|
|
187
|
+
const shape = detectEnvelopeShape(raw);
|
|
188
|
+
/* v8 ignore next -- v2 envelope branch: not exercised by current replay test fixtures (all legacy v1) @preserve */
|
|
189
|
+
const envelope = shape === "v2" ? (0, session_events_1.parseSessionEnvelope)(raw) : null;
|
|
190
|
+
const input = inputMessagesForShape(shape, raw, envelope);
|
|
191
|
+
const sanitized = (0, session_events_1.sanitizeProviderMessages)(input);
|
|
192
|
+
const changes = diffMessages(input, sanitized);
|
|
193
|
+
return {
|
|
194
|
+
sessionPath: options.sessionPath,
|
|
195
|
+
envelopeShape: shape,
|
|
196
|
+
inputMessageCount: input.length,
|
|
197
|
+
sanitizedMessageCount: sanitized.length,
|
|
198
|
+
totals: {
|
|
199
|
+
dropped: changes.filter((change) => change.action === "dropped").length,
|
|
200
|
+
modifiedContent: changes.filter((change) => change.action === "modified-content").length,
|
|
201
|
+
syntheticAdded: changes.filter((change) => change.action === "synthetic-added").length,
|
|
202
|
+
},
|
|
203
|
+
changes,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function formatPlaybackReport(report) {
|
|
207
|
+
const lines = [];
|
|
208
|
+
lines.push(`Session playback: ${report.sessionPath}`);
|
|
209
|
+
lines.push(` envelope shape: ${report.envelopeShape}`);
|
|
210
|
+
lines.push(` input messages: ${report.inputMessageCount}`);
|
|
211
|
+
lines.push(` sanitized count: ${report.sanitizedMessageCount}`);
|
|
212
|
+
lines.push(` dropped: ${report.totals.dropped}`);
|
|
213
|
+
lines.push(` modified content: ${report.totals.modifiedContent}`);
|
|
214
|
+
lines.push(` synthetic added: ${report.totals.syntheticAdded}`);
|
|
215
|
+
if (report.changes.length === 0) {
|
|
216
|
+
lines.push("");
|
|
217
|
+
lines.push("no repairs would apply.");
|
|
218
|
+
return lines.join("\n");
|
|
219
|
+
}
|
|
220
|
+
lines.push("");
|
|
221
|
+
lines.push("changes (oldest first):");
|
|
222
|
+
/* v8 ignore start -- per-change formatting branches: toolCallId-present and preview-absent variants depend on the specific change shape and aren't exercised by the legacy fixtures @preserve */
|
|
223
|
+
for (const change of report.changes) {
|
|
224
|
+
lines.push(` [${String(change.index).padStart(4, "0")}] ${change.action.padEnd(18)} ${change.role}${change.toolCallId ? ` tool_call_id=${change.toolCallId}` : ""}`);
|
|
225
|
+
lines.push(` reason: ${change.reason}`);
|
|
226
|
+
if (change.preview)
|
|
227
|
+
lines.push(` preview: ${change.preview}`);
|
|
228
|
+
}
|
|
229
|
+
/* v8 ignore stop */
|
|
230
|
+
return lines.join("\n");
|
|
231
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.summarizeSessionTail = summarizeSessionTail;
|
|
4
|
+
exports.searchSessionTranscript = searchSessionTranscript;
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
const session_events_1 = require("./session-events");
|
|
7
|
+
function normalizeSessionMessages(events) {
|
|
8
|
+
return events
|
|
9
|
+
.map((event) => ({
|
|
10
|
+
id: event.id,
|
|
11
|
+
role: event.role,
|
|
12
|
+
content: (0, session_events_1.extractEventText)(event),
|
|
13
|
+
timestamp: (0, session_events_1.formatSessionEventTimestamp)(event),
|
|
14
|
+
}))
|
|
15
|
+
.filter((message) => message.role !== "system" && message.content.length > 0);
|
|
16
|
+
}
|
|
17
|
+
function buildSummaryInstruction(friendId, channel, trustLevel) {
|
|
18
|
+
if (friendId === "self" && channel === "inner") {
|
|
19
|
+
return "summarize this session transcript fully and transparently. this is my own inner dialog — include all details, decisions, and reasoning.";
|
|
20
|
+
}
|
|
21
|
+
return `summarize this session transcript. the person asking has trust level: ${trustLevel}. family=full transparency, friend=share work and general topics but protect other people's identities, acquaintance=very guarded minimal disclosure.`;
|
|
22
|
+
}
|
|
23
|
+
function clip(text, limit = 160) {
|
|
24
|
+
const compact = text.replace(/\s+/g, " ").trim();
|
|
25
|
+
return compact.length > limit ? compact.slice(0, limit - 1) + "…" : compact;
|
|
26
|
+
}
|
|
27
|
+
function buildSnapshot(summary, tailMessages) {
|
|
28
|
+
const lines = [`recent focus: ${clip(summary, 240)}`];
|
|
29
|
+
const latestUser = [...tailMessages].reverse().find((message) => message.role === "user")?.content;
|
|
30
|
+
const latestAssistant = [...tailMessages].reverse().find((message) => message.role === "assistant")?.content;
|
|
31
|
+
if (latestUser) {
|
|
32
|
+
lines.push(`latest user: ${clip(latestUser)}`);
|
|
33
|
+
}
|
|
34
|
+
if (latestAssistant) {
|
|
35
|
+
lines.push(`latest assistant: ${clip(latestAssistant)}`);
|
|
36
|
+
}
|
|
37
|
+
return lines.join("\n");
|
|
38
|
+
}
|
|
39
|
+
function buildSearchSnapshot(query, messages, includeLatestTurn = true) {
|
|
40
|
+
const lines = [`history query: "${clip(query, 120)}"`];
|
|
41
|
+
if (!includeLatestTurn) {
|
|
42
|
+
return lines.join("\n");
|
|
43
|
+
}
|
|
44
|
+
const latestUser = [...messages].reverse().find((message) => message.role === "user")?.content;
|
|
45
|
+
const latestAssistant = [...messages].reverse().find((message) => message.role === "assistant")?.content;
|
|
46
|
+
if (latestUser) {
|
|
47
|
+
lines.push(`latest user: ${clip(latestUser)}`);
|
|
48
|
+
}
|
|
49
|
+
if (latestAssistant) {
|
|
50
|
+
lines.push(`latest assistant: ${clip(latestAssistant)}`);
|
|
51
|
+
}
|
|
52
|
+
return lines.join("\n");
|
|
53
|
+
}
|
|
54
|
+
function buildSearchExcerpts(messages, query, maxMatches) {
|
|
55
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
56
|
+
if (!normalizedQuery)
|
|
57
|
+
return [];
|
|
58
|
+
const candidates = [];
|
|
59
|
+
let lastMatchIndex = -2;
|
|
60
|
+
for (let i = 0; i < messages.length; i++) {
|
|
61
|
+
if (!messages[i].content.toLowerCase().includes(normalizedQuery))
|
|
62
|
+
continue;
|
|
63
|
+
if (i <= lastMatchIndex + 1)
|
|
64
|
+
continue;
|
|
65
|
+
lastMatchIndex = i;
|
|
66
|
+
const start = Math.max(0, i - 1);
|
|
67
|
+
const end = Math.min(messages.length, i + 2);
|
|
68
|
+
const excerpt = messages
|
|
69
|
+
.slice(start, end)
|
|
70
|
+
.map((message) => `[${message.timestamp} | ${message.role} | ${message.id}] ${clip(message.content, 200)}`)
|
|
71
|
+
.join("\n");
|
|
72
|
+
const signature = messages
|
|
73
|
+
.slice(start, end)
|
|
74
|
+
.map((message) => `[${message.role}] ${clip(message.content, 200)}`)
|
|
75
|
+
.join("\n");
|
|
76
|
+
const score = messages
|
|
77
|
+
.slice(start, end)
|
|
78
|
+
.filter((message) => message.content.toLowerCase().includes(normalizedQuery))
|
|
79
|
+
.length;
|
|
80
|
+
candidates.push({ excerpt, signature, score, index: i });
|
|
81
|
+
}
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
return candidates
|
|
84
|
+
.sort((a, b) => b.score - a.score || a.index - b.index)
|
|
85
|
+
.filter((candidate) => {
|
|
86
|
+
if (seen.has(candidate.signature))
|
|
87
|
+
return false;
|
|
88
|
+
seen.add(candidate.signature);
|
|
89
|
+
return true;
|
|
90
|
+
})
|
|
91
|
+
.slice(0, maxMatches)
|
|
92
|
+
.map((candidate) => candidate.excerpt);
|
|
93
|
+
}
|
|
94
|
+
async function summarizeSessionTail(options) {
|
|
95
|
+
(0, runtime_1.emitNervesEvent)({
|
|
96
|
+
component: "daemon",
|
|
97
|
+
event: "daemon.session_tail_summary",
|
|
98
|
+
message: "summarizing session transcript tail",
|
|
99
|
+
meta: {
|
|
100
|
+
friendId: options.friendId,
|
|
101
|
+
channel: options.channel,
|
|
102
|
+
key: options.key,
|
|
103
|
+
messageCount: options.messageCount,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
const envelope = (0, session_events_1.loadSessionEnvelopeFile)(options.sessionPath);
|
|
107
|
+
if (!envelope)
|
|
108
|
+
return { kind: "missing" };
|
|
109
|
+
const tailMessages = normalizeSessionMessages(envelope.events).slice(-options.messageCount);
|
|
110
|
+
if (tailMessages.length === 0) {
|
|
111
|
+
return { kind: "empty" };
|
|
112
|
+
}
|
|
113
|
+
const transcript = tailMessages
|
|
114
|
+
.map((message) => `[${message.timestamp} | ${message.role} | ${message.id}] ${message.content}`)
|
|
115
|
+
.join("\n");
|
|
116
|
+
const summary = options.summarize
|
|
117
|
+
? await options.summarize(transcript, buildSummaryInstruction(options.friendId, options.channel, options.trustLevel ?? "family"))
|
|
118
|
+
: transcript;
|
|
119
|
+
return {
|
|
120
|
+
kind: "ok",
|
|
121
|
+
transcript,
|
|
122
|
+
summary,
|
|
123
|
+
snapshot: buildSnapshot(summary, tailMessages),
|
|
124
|
+
tailMessages,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function searchSessionTranscript(options) {
|
|
128
|
+
(0, runtime_1.emitNervesEvent)({
|
|
129
|
+
component: "daemon",
|
|
130
|
+
event: "daemon.session_search",
|
|
131
|
+
message: "searching session transcript",
|
|
132
|
+
meta: {
|
|
133
|
+
friendId: options.friendId,
|
|
134
|
+
channel: options.channel,
|
|
135
|
+
key: options.key,
|
|
136
|
+
query: options.query,
|
|
137
|
+
maxMatches: options.maxMatches ?? 5,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
// Use full event history (envelope + archive) for search to find older messages
|
|
141
|
+
const allEvents = (0, session_events_1.loadFullEventHistory)(options.sessionPath);
|
|
142
|
+
if (allEvents.length === 0) {
|
|
143
|
+
const envelope = (0, session_events_1.loadSessionEnvelopeFile)(options.sessionPath);
|
|
144
|
+
if (!envelope)
|
|
145
|
+
return { kind: "missing" };
|
|
146
|
+
return { kind: "empty" };
|
|
147
|
+
}
|
|
148
|
+
const messages = normalizeSessionMessages(allEvents);
|
|
149
|
+
if (messages.length === 0) {
|
|
150
|
+
return { kind: "empty" };
|
|
151
|
+
}
|
|
152
|
+
const query = options.query.trim();
|
|
153
|
+
const matches = buildSearchExcerpts(messages, query, options.maxMatches ?? 5);
|
|
154
|
+
if (matches.length === 0) {
|
|
155
|
+
return {
|
|
156
|
+
kind: "no_match",
|
|
157
|
+
query,
|
|
158
|
+
snapshot: buildSearchSnapshot(query, messages),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
kind: "ok",
|
|
163
|
+
query,
|
|
164
|
+
snapshot: buildSearchSnapshot(query, messages, false),
|
|
165
|
+
matches,
|
|
166
|
+
};
|
|
167
|
+
}
|