mixdog 0.9.63 → 0.9.65
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 +3 -0
- package/package.json +9 -2
- package/scripts/code-graph-description-contract.mjs +3 -3
- package/scripts/verify-release-assets.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +11 -14
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
- package/src/runtime/agent/orchestrator/config.mjs +19 -124
- package/src/runtime/agent/orchestrator/context/collect.mjs +6 -6
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +2 -2
- package/src/runtime/agent/orchestrator/internal-agents.mjs +2 -2
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +333 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -277
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +460 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +14 -593
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -280
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +357 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-headers.mjs +216 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +2 -188
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/file-reattach.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +17 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +18 -26
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/delivered-completions.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +260 -0
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +72 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +163 -0
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -561
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +2 -154
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/cwd-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-locks.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +2 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +519 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +5 -449
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +212 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +1 -7
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +9 -36
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +15 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +429 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +2 -395
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/mutation-planner.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/next-call-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +72 -9
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +2 -444
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +505 -0
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/backend-dispatch.mjs +20 -5
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/telegram-format.mjs +1 -1
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +4 -4
- package/src/runtime/channels/tool-defs.mjs +2 -3
- package/src/runtime/memory/index.mjs +1 -5
- package/src/runtime/memory/lib/core-memory-candidates.mjs +357 -0
- package/src/runtime/memory/lib/core-memory-store.mjs +7 -357
- package/src/runtime/memory/lib/cycle-signatures.mjs +1 -1
- package/src/runtime/memory/lib/embedding-model-config.mjs +1 -1
- package/src/runtime/memory/lib/embedding-provider.mjs +1 -5
- package/src/runtime/memory/lib/embedding-worker.mjs +1 -5
- package/src/runtime/memory/lib/ko-morph.mjs +2 -2
- package/src/runtime/memory/lib/memory-config-flags.mjs +2 -5
- package/src/runtime/memory/lib/memory-cycle-requests.mjs +3 -7
- package/src/runtime/memory/lib/memory-cycle1.mjs +4 -8
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +2 -5
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -5
- package/src/runtime/memory/lib/memory-embed.mjs +2 -6
- package/src/runtime/memory/lib/memory-log.mjs +8 -0
- package/src/runtime/memory/lib/memory-ops-policy.mjs +4 -8
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +1 -1
- package/src/runtime/memory/lib/memory-recall-store.mjs +2 -193
- package/src/runtime/memory/lib/memory-score.mjs +1 -1
- package/src/runtime/memory/lib/memory-text-utils.mjs +2 -2
- package/src/runtime/memory/lib/memory.mjs +2 -6
- package/src/runtime/memory/lib/pg/adapter.mjs +2 -6
- package/src/runtime/memory/lib/pg/process.mjs +1 -5
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -5
- package/src/runtime/memory/lib/recall-format.mjs +2 -2
- package/src/runtime/memory/lib/recall-scoring.mjs +195 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -5
- package/src/runtime/memory/lib/trace-store.mjs +2 -6
- package/src/runtime/search/lib/http-fetch.mjs +6 -6
- package/src/runtime/search/lib/web-tools.mjs +2 -2
- package/src/runtime/shared/buffered-appender.mjs +1 -1
- package/src/runtime/shared/child-guardian.mjs +1 -1
- package/src/runtime/shared/child-spawn-gate.mjs +1 -1
- package/src/runtime/shared/config.mjs +4 -4
- package/src/runtime/shared/launcher-control.mjs +9 -10
- package/src/runtime/shared/llm/index.mjs +5 -20
- package/src/runtime/shared/markdown-frontmatter.mjs +1 -1
- package/src/runtime/shared/memory-snapshot.mjs +4 -4
- package/src/runtime/shared/pristine-execution.mjs +1 -1
- package/src/runtime/shared/process-lifecycle.mjs +0 -1
- package/src/runtime/shared/process-shutdown.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +2 -2
- package/src/runtime/shared/schedule-session-run.mjs +1 -1
- package/src/runtime/shared/schedules-db.mjs +1 -1
- package/src/runtime/shared/service-discovery.mjs +2 -2
- package/src/runtime/shared/staged-update.mjs +6 -6
- package/src/runtime/shared/tool-execution-contract.mjs +1 -1
- package/src/runtime/shared/tool-primitives.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +2 -2
- package/src/runtime/shared/turn-snapshot.mjs +184 -0
- package/src/runtime/shared/update-checker.mjs +1 -1
- package/src/runtime/shared/user-cwd.mjs +3 -3
- package/src/runtime/shared/user-data-guard.mjs +4 -4
- package/src/runtime/shared/workspace-router.mjs +5 -5
- package/src/session-runtime/config-helpers.mjs +2 -3
- package/src/session-runtime/config-lifecycle.mjs +1 -1
- package/src/session-runtime/hitch-profile.mjs +1 -1
- package/src/session-runtime/lifecycle-api.mjs +6 -4
- package/src/session-runtime/model-recency.mjs +5 -5
- package/src/session-runtime/plugin-mcp.mjs +1 -1
- package/src/session-runtime/provider-request-snapshot.mjs +338 -0
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/session-text.mjs +4 -4
- package/src/session-runtime/session-turn-api.mjs +7 -0
- package/src/session-runtime/tool-catalog-schema.mjs +197 -0
- package/src/session-runtime/tool-catalog.mjs +6 -483
- package/src/session-runtime/tool-defs.mjs +1 -1
- package/src/standalone/agent-task-status.mjs +1 -1
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/channel-admin.mjs +4 -4
- package/src/standalone/explore-tool.mjs +3 -3
- package/src/standalone/hook-bus/config.mjs +1 -1
- package/src/standalone/hook-bus/constants.mjs +1 -1
- package/src/standalone/hook-bus/rules.mjs +1 -1
- package/src/standalone/projects.mjs +1 -1
- package/src/standalone/provider-admin.mjs +2 -2
- package/src/tui/App.jsx +1 -1
- package/src/tui/app/app-format.mjs +2 -2
- package/src/tui/app/clipboard.mjs +3 -3
- package/src/tui/app/input-parsers.mjs +1 -1
- package/src/tui/app/text-layout.mjs +1 -1
- package/src/tui/app/transcript-row-estimate.mjs +360 -0
- package/src/tui/app/transcript-window.mjs +5 -347
- package/src/tui/app/use-mouse-input.mjs +1 -1
- package/src/tui/app/use-prompt-handlers.mjs +1 -1
- package/src/tui/components/tool-execution/surface-detail.mjs +9 -9
- package/src/tui/components/tool-execution/text-format.mjs +2 -2
- package/src/tui/components/tool-output-format.mjs +7 -7
- package/src/tui/display-width.mjs +4 -4
- package/src/tui/dist/index.mjs +187 -99
- package/src/tui/engine/agent-envelope.mjs +5 -5
- package/src/tui/engine/live-share.mjs +100 -0
- package/src/tui/engine/notification-plan.mjs +1 -1
- package/src/tui/engine/queue-helpers.mjs +3 -3
- package/src/tui/engine/render-timing.mjs +4 -5
- package/src/tui/engine/session-api-ext.mjs +6 -3
- package/src/tui/engine/tool-result-status.mjs +5 -5
- package/src/tui/engine/tool-result-text.mjs +1 -1
- package/src/tui/engine/transcript-spill.mjs +585 -0
- package/src/tui/engine/tui-steering-persist.mjs +1 -1
- package/src/tui/engine.mjs +29 -474
- package/src/tui/lib/voice-setup.mjs +1 -1
- package/src/tui/markdown/format-token.mjs +1 -1
- package/src/tui/markdown/render-ansi.mjs +1 -1
- package/src/tui/markdown/table-layout.mjs +4 -4
- package/src/tui/paste-attachments.mjs +1 -1
- package/src/tui/prompt-history-store.mjs +3 -3
- package/src/tui/statusline-ansi-bridge.mjs +2 -2
- package/src/tui/theme.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +2 -2
- package/src/ui/ansi.mjs +0 -9
- package/src/ui/statusline-format.mjs +2 -4
- package/scripts/_bench-cwc.json +0 -20
- package/scripts/_jitter-fuzz.jsx +0 -42
- package/scripts/_jitter-fuzz2.jsx +0 -30
- package/scripts/_jitter-probe.jsx +0 -35
- package/scripts/_jp2.jsx +0 -16
- package/scripts/_smoke_wd.mjs +0 -7
- package/scripts/abort-recovery-test.mjs +0 -175
- package/scripts/agent-dispatch-abort-compose-test.mjs +0 -31
- package/scripts/agent-live-arg-guard-smoke.mjs +0 -20
- package/scripts/agent-live-path-suffix-smoke.mjs +0 -34
- package/scripts/agent-live-toolcall-args-smoke.mjs +0 -45
- package/scripts/agent-loop-policy-test.mjs +0 -37
- package/scripts/agent-model-liveness-test.mjs +0 -763
- package/scripts/agent-parallel-smoke.mjs +0 -435
- package/scripts/agent-route-batch-test.mjs +0 -40
- package/scripts/agent-tag-reuse-smoke.mjs +0 -441
- package/scripts/agent-terminal-reap-test.mjs +0 -252
- package/scripts/agent-trace-io-test.mjs +0 -133
- package/scripts/ansi-color-capability-test.mjs +0 -90
- package/scripts/anthropic-admission-retry-integration-test.mjs +0 -119
- package/scripts/anthropic-maxtokens-test.mjs +0 -119
- package/scripts/anthropic-oauth-refresh-race-test.mjs +0 -397
- package/scripts/anthropic-transport-policy-test.mjs +0 -726
- package/scripts/apply-patch-edit-smoke.mjs +0 -71
- package/scripts/arg-guard-test.mjs +0 -93
- package/scripts/async-notify-settlement-test.mjs +0 -99
- package/scripts/atomic-lock-tryonce-test.mjs +0 -125
- package/scripts/background-task-meta-smoke.mjs +0 -38
- package/scripts/bench-run.mjs +0 -508
- package/scripts/boot-smoke.mjs +0 -137
- package/scripts/build-runtime-windows.ps1 +0 -242
- package/scripts/channel-daemon-smoke.mjs +0 -1103
- package/scripts/code-graph-aggregate-cwd-test.mjs +0 -158
- package/scripts/code-graph-disk-hit-test.mjs +0 -290
- package/scripts/code-graph-dispatch-test.mjs +0 -96
- package/scripts/code-graph-root-federation-test.mjs +0 -273
- package/scripts/compact-active-turn-test.mjs +0 -68
- package/scripts/compact-file-reattach-test.mjs +0 -88
- package/scripts/compact-pressure-test.mjs +0 -788
- package/scripts/compact-prior-context-flatten-test.mjs +0 -252
- package/scripts/compact-recall-digest-test.mjs +0 -57
- package/scripts/compact-smoke.mjs +0 -1017
- package/scripts/compact-trigger-migration-smoke.mjs +0 -261
- package/scripts/compacted-placeholder-scrub-test.mjs +0 -63
- package/scripts/context-mcp-metering-test.mjs +0 -1406
- package/scripts/debounced-skills-async-save-test.mjs +0 -57
- package/scripts/deferred-tool-loading-test.mjs +0 -250
- package/scripts/desktop-session-bridge-test.mjs +0 -1013
- package/scripts/dispatch-persist-recovery-test.mjs +0 -141
- package/scripts/embedding-worker-exit-test.mjs +0 -76
- package/scripts/execution-completion-dedup-test.mjs +0 -205
- package/scripts/execution-pending-resume-kick-test.mjs +0 -151
- package/scripts/execution-resume-esc-integration-test.mjs +0 -176
- package/scripts/explore-bench-tmp.mjs +0 -36
- package/scripts/explore-bench.mjs +0 -248
- package/scripts/explore-prompt-policy-test.mjs +0 -256
- package/scripts/explore-timeout-cancel-test.mjs +0 -345
- package/scripts/find-fuzzy-hidden-test.mjs +0 -267
- package/scripts/forwarder-rebind-tail-test.mjs +0 -67
- package/scripts/freevar-smoke.mjs +0 -98
- package/scripts/gemini-provider-test.mjs +0 -1448
- package/scripts/generate-oc-icons.mjs +0 -11
- package/scripts/grok-oauth-refresh-race-test.mjs +0 -273
- package/scripts/headless-pristine-execution-test.mjs +0 -614
- package/scripts/hook-bus-test.mjs +0 -552
- package/scripts/ingest-pure-conversation-smoke.mjs +0 -175
- package/scripts/internal-comms-bench-test.mjs +0 -226
- package/scripts/internal-comms-bench.mjs +0 -853
- package/scripts/internal-comms-smoke.mjs +0 -277
- package/scripts/internal-tools-normalization-test.mjs +0 -62
- package/scripts/interrupted-turn-history-test.mjs +0 -399
- package/scripts/lead-workflow-smoke.mjs +0 -592
- package/scripts/lifecycle-api-test.mjs +0 -137
- package/scripts/live-share-test.mjs +0 -148
- package/scripts/live-worker-smoke.mjs +0 -333
- package/scripts/log-writer-guard-smoke.mjs +0 -131
- package/scripts/maintenance-default-routes-test.mjs +0 -164
- package/scripts/max-output-recovery-persist-test.mjs +0 -81
- package/scripts/max-output-recovery-test.mjs +0 -368
- package/scripts/mcp-client-normalization-test.mjs +0 -45
- package/scripts/mcp-grace-deferred-test.mjs +0 -225
- package/scripts/memory-core-input-test.mjs +0 -167
- package/scripts/memory-cycle-routing-test.mjs +0 -111
- package/scripts/memory-meta-concurrency-test.mjs +0 -20
- package/scripts/memory-pg-recovery-test.mjs +0 -59
- package/scripts/memory-rule-contract-test.mjs +0 -93
- package/scripts/model-list-sanitize-test.mjs +0 -37
- package/scripts/mouse-tracking-restore-smoke.mjs +0 -107
- package/scripts/native-edit-wire-test.mjs +0 -152
- package/scripts/notify-completion-mirror-test.mjs +0 -73
- package/scripts/openai-oauth-refresh-race-test.mjs +0 -120
- package/scripts/openai-oauth-ws-1006-retry-test.mjs +0 -954
- package/scripts/openai-ws-early-settle-test.mjs +0 -216
- package/scripts/output-style-bench.mjs +0 -292
- package/scripts/output-style-smoke.mjs +0 -145
- package/scripts/parent-abort-link-test.mjs +0 -90
- package/scripts/patch-binary-cache-test.mjs +0 -181
- package/scripts/path-suffix-test.mjs +0 -57
- package/scripts/pending-completion-drop-test.mjs +0 -239
- package/scripts/pending-messages-lock-nonblocking-test.mjs +0 -62
- package/scripts/pretool-ask-runtime-test.mjs +0 -54
- package/scripts/process-lifecycle-test.mjs +0 -461
- package/scripts/prompt-immediate-render-test.mjs +0 -89
- package/scripts/prompt-input-parity-test.mjs +0 -145
- package/scripts/provider-admission-scheduler-test.mjs +0 -681
- package/scripts/provider-contract-test.mjs +0 -632
- package/scripts/provider-stream-stall-test.mjs +0 -276
- package/scripts/provider-toolcall-test.mjs +0 -3063
- package/scripts/reactive-compact-persist-smoke.mjs +0 -203
- package/scripts/recall-bench.mjs +0 -359
- package/scripts/resource-admission-test.mjs +0 -792
- package/scripts/result-classification-test.mjs +0 -75
- package/scripts/rg-runner-test.mjs +0 -240
- package/scripts/routing-corpus-test.mjs +0 -349
- package/scripts/sanitize-tool-pairs-test.mjs +0 -260
- package/scripts/session-bench-cache-break-test.mjs +0 -102
- package/scripts/session-bench.mjs +0 -1708
- package/scripts/session-context-bench.mjs +0 -344
- package/scripts/session-heartbeat-lifecycle-test.mjs +0 -68
- package/scripts/session-ingest-compaction-smoke.mjs +0 -279
- package/scripts/session-ingest-smoke.mjs +0 -177
- package/scripts/session-orphan-sweep-test.mjs +0 -109
- package/scripts/set-effort-config-test.mjs +0 -41
- package/scripts/shell-failure-diagnostics-test.mjs +0 -280
- package/scripts/shell-hardening-test.mjs +0 -209
- package/scripts/shell-jobs-windows-hide-test.mjs +0 -164
- package/scripts/ship-mode-test.mjs +0 -98
- package/scripts/smoke-loop-failure-summary-test.mjs +0 -38
- package/scripts/smoke-loop-failure-summary.mjs +0 -16
- package/scripts/smoke-loop-report.mjs +0 -221
- package/scripts/smoke-loop.mjs +0 -202
- package/scripts/smoke-runtime-negative.ps1 +0 -106
- package/scripts/statusline-quota-hysteresis-test.mjs +0 -62
- package/scripts/steering-drain-buckets-test.mjs +0 -467
- package/scripts/steering-fold-provenance-test.mjs +0 -71
- package/scripts/streaming-tail-window-test.mjs +0 -175
- package/scripts/submit-commandbusy-race-test.mjs +0 -257
- package/scripts/task-bench.mjs +0 -205
- package/scripts/terminal-bench-isolation-guards-test.mjs +0 -102
- package/scripts/termio-input-smoke.mjs +0 -199
- package/scripts/tool-result-hook-test.mjs +0 -48
- package/scripts/tool-smoke.mjs +0 -2453
- package/scripts/tool-tui-presentation-test.mjs +0 -286
- package/scripts/toolcall-args-test.mjs +0 -239
- package/scripts/tui-ambiguous-width-test.mjs +0 -113
- package/scripts/tui-background-failure-smoke.mjs +0 -73
- package/scripts/tui-perf-run.ps1 +0 -26
- package/scripts/tui-render-smoke.mjs +0 -90
- package/scripts/tui-runtime-load-bench-entry.jsx +0 -608
- package/scripts/tui-runtime-load-bench.mjs +0 -50
- package/scripts/tui-store-frame-batch-test.mjs +0 -99
- package/scripts/tui-transcript-jitter-harness-entry.jsx +0 -383
- package/scripts/tui-transcript-perf-test.mjs +0 -934
- package/scripts/usage-metrics-epoch-smoke.mjs +0 -114
- package/scripts/verify-release-assets-test.mjs +0 -281
- package/scripts/web-fetch-routing-test.mjs +0 -158
- package/scripts/webhook-smoke.mjs +0 -201
- package/scripts/windows-hide-spawn-options-test.mjs +0 -19
- package/scripts/worker-notify-rejection-test.mjs +0 -51
- package/scripts/write-backpressure-test.mjs +0 -147
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VALID_CATEGORY } from './memory.mjs'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function buildCategoryFilterClause(offset, categories, { tableAlias = '' } = {}) {
|
|
4
4
|
const cats = (Array.isArray(categories) ? categories : [categories])
|
|
5
5
|
.map(c => String(c ?? '').trim().toLowerCase())
|
|
6
6
|
.filter(c => VALID_CATEGORY.has(c))
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function __mixdogMemoryLog(...args) {
|
|
3
|
-
if (process.env.MIXDOG_QUIET_MEMORY_LOG) return true;
|
|
4
|
-
return __mixdogMemoryStderrWrite(...args);
|
|
5
|
-
}
|
|
1
|
+
import { __mixdogMemoryLog } from './memory-log.mjs';
|
|
6
2
|
|
|
7
3
|
import { buildFtsQuery, buildFtsPrefixQuery } from './memory-text-utils.mjs'
|
|
8
4
|
import { VALID_CATEGORY, embeddingToSql } from './memory.mjs'
|
|
@@ -12,194 +8,7 @@ import { recallReadQuery } from './memory-recall-read-query.mjs'
|
|
|
12
8
|
|
|
13
9
|
// Per-db cache of mv_hot_active populated state. The main recall path currently
|
|
14
10
|
// uses entries directly; this guard remains for explicit useHotActive callers.
|
|
15
|
-
|
|
16
|
-
const _mvHotActiveCache = new WeakMap() // db → { populated: boolean, ts: number }
|
|
17
|
-
const SEMANTIC_ONLY_MIN_SIM = 0.72
|
|
18
|
-
// Member-hit time gate: a chunk MEMBER whose own ts falls inside the requested
|
|
19
|
-
// [ts_from, ts_to] window is an in-window match even when its ROOT's ts sits
|
|
20
|
-
// outside it. Returns true when the member ts is within the (open-ended) window.
|
|
21
|
-
function memberTsInWindow(row, tsFrom, tsTo) {
|
|
22
|
-
const ts = Number(row?.ts)
|
|
23
|
-
if (!Number.isFinite(ts)) return true // undated member: don't drop on window
|
|
24
|
-
if (tsFrom != null && ts < tsFrom) return false
|
|
25
|
-
if (tsTo != null && ts > tsTo) return false
|
|
26
|
-
return true
|
|
27
|
-
}
|
|
28
|
-
// Cross-language semantic rescue: a query in one language against rows in
|
|
29
|
-
// another rarely clears SEMANTIC_ONLY_MIN_SIM on a small (384-dim) embedding
|
|
30
|
-
// model, yet the TOP dense ranks are still overwhelmingly relevant. Accept
|
|
31
|
-
// semantic-only rows that are both top-ranked in the dense leg AND above a
|
|
32
|
-
// softer floor, instead of dropping everything below 0.72.
|
|
33
|
-
const SEMANTIC_TOP_RANK_MAX = 3
|
|
34
|
-
// Floor for the top-rank rescue. 384-dim MiniLM-class embeddings put UNRELATED
|
|
35
|
-
// text at ~0.65-0.75 sim (measured: gibberish query "zzqqxx ... 999" scored
|
|
36
|
-
// 0.749 against real rows), so anything below ~0.70 is noise regardless of
|
|
37
|
-
// rank; cross-language relevant pairs measured 0.67-0.74. 0.70 keeps most of
|
|
38
|
-
// the cross-language rescue while rejecting pure-noise top ranks.
|
|
39
|
-
// The softer 0.70 floor SITS INSIDE the noise band (noise peaked at 0.749), so
|
|
40
|
-
// it only rescues rows that ALSO carry a lexical leg as corroboration. A
|
|
41
|
-
// semantic-only row (no sparse/trgm/exact) must clear SEMANTIC_TOP_RANK_STRICT_SIM
|
|
42
|
-
// instead — set above the measured 0.749 noise ceiling so unrelated top ranks
|
|
43
|
-
// (e.g. old narration surfacing for "embedding worker crash") stop leaking in.
|
|
44
|
-
const SEMANTIC_TOP_RANK_MIN_SIM = 0.70
|
|
45
|
-
const SEMANTIC_TOP_RANK_STRICT_SIM = 0.78
|
|
46
|
-
const SHORT_QUERY_TOKEN_MAX = 2
|
|
47
|
-
// Dense-similarity weighting for retrievalScore. Lexical RRF sums 1/(K+rank)
|
|
48
|
-
// per matching leg (K=60), so a row hitting 2 lexical legs at rank 1 scores
|
|
49
|
-
// rrf ≈ 2/(60+1) = 0.0328 — enough to bury a single semantically-close dense
|
|
50
|
-
// hit that never shares lexical terms. We add a normalized dense-similarity
|
|
51
|
-
// term so a strong dense-only match can outrank stale multi-leg lexical hits:
|
|
52
|
-
// denseTerm = W_DENSE * max(0, sim - SIM_FLOOR) / (1 - SIM_FLOOR) * freshness
|
|
53
|
-
// At sim=0.85: (0.85-0.60)/(1-0.60) = 0.625, so denseTerm = 0.04 * 0.625 = 0.025
|
|
54
|
-
// with freshness=1. That alone doesn't beat 0.0328, but combined with the
|
|
55
|
-
// row's own rrf contribution (a dense-only row still has 1/(60+rank) from its
|
|
56
|
-
// dense rank, e.g. rank 1 → 0.0164) the total ≈ 0.0164 + 0.025 = 0.0414,
|
|
57
|
-
// which clears the 0.0328 two-leg lexical baseline. W_DENSE=0.04 was chosen
|
|
58
|
-
// as the smallest round value satisfying this at sim=0.85; SIM_FLOOR=0.60
|
|
59
|
-
// matches the noise floor used elsewhere for MiniLM-class embeddings.
|
|
60
|
-
const SIM_FLOOR = 0.60
|
|
61
|
-
const W_DENSE = 0.04
|
|
62
|
-
// Recency nudge applied ONLY when a [ts_from, ts_to] window is active. Inside a
|
|
63
|
-
// fixed window absolute-age freshness is often disabled (applyFreshness=false)
|
|
64
|
-
// or too flat to separate early-window from late-window rows, so a 07-04 row
|
|
65
|
-
// could outrank a 07-05 row of comparable relevance under a 24h period. This
|
|
66
|
-
// term is a normalized position-in-window score (newest→1) scaled small enough
|
|
67
|
-
// to break comparable-relevance ties toward newer rows without overriding a
|
|
68
|
-
// clearly stronger lexical/semantic match.
|
|
69
|
-
// Kept below a single rank-1 RRF leg (~0.016) so it only breaks ties between
|
|
70
|
-
// comparable-relevance rows and never overrides a clearly stronger match.
|
|
71
|
-
const W_WINDOW_RECENCY = 0.008
|
|
72
|
-
// Rare-token display boost. A query token that appears in the RENDERED display
|
|
73
|
-
// of only a small fraction of the candidate set (an IDF-style rarity signal) is
|
|
74
|
-
// strong evidence a row is genuinely about that term — even for a
|
|
75
|
-
// cross-language row whose only lexical tie is one distinctive English token
|
|
76
|
-
// (e.g. "embedding" inside otherwise-Korean content). We add a boost when such
|
|
77
|
-
// a rare token is present in the fields that actually render (element/summary
|
|
78
|
-
// for roots, content for member-hit turns), so a low-lexical row surfaces above
|
|
79
|
-
// common-token neighbours. Scoped to display fields so we never promote a row
|
|
80
|
-
// whose match hides in un-rendered body text. RARE_DF_MAX gates "rare": tokens
|
|
81
|
-
// present in >34% of candidates are common and earn nothing.
|
|
82
|
-
// Scaled to at most one rank-1 RRF leg (1/(K+1) ≈ 0.0164 at K=60): a rare
|
|
83
|
-
// display token is a genuine relevance signal, but the IDF boost should only
|
|
84
|
-
// carry the weight of a single extra retrieval-leg agreement — enough to break
|
|
85
|
-
// ties toward the distinctive-token row without overriding a clearly stronger
|
|
86
|
-
// multi-leg lexical/semantic match. W_RARE * (1 - df/N) peaks below this cap.
|
|
87
|
-
const W_RARE = 0.016
|
|
88
|
-
const RARE_DF_MAX = 0.34
|
|
89
|
-
|
|
90
|
-
// Lowercased, de-duplicated query tokens (>= 2 chars) for DF/boost/gate use.
|
|
91
|
-
// Capped at 12 (mirrors buildExactTerms) so a paragraph-length query can't
|
|
92
|
-
// turn the per-row DF scan into O(tokens × candidateWindow) on display text.
|
|
93
|
-
function queryTokensLower(query) {
|
|
94
|
-
const clean = String(query ?? '').replace(/\s+/g, ' ').trim()
|
|
95
|
-
const toks = (clean.match(/[\p{L}\p{N}_./:-]+/gu) || [])
|
|
96
|
-
.map(t => t.toLowerCase())
|
|
97
|
-
.filter(t => Array.from(t).length >= 2)
|
|
98
|
-
return [...new Set(toks)].slice(0, 12)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// The text that actually renders as a result LINE for a row: element+summary
|
|
102
|
-
// for a root (its members render on their own lines), plus content for a
|
|
103
|
-
// member-hit turn (its own content is the rendered line). Deliberately excludes
|
|
104
|
-
// a ROOT's body content, which never renders when the row is shown as a summary
|
|
105
|
-
// line — matching there is incidental, not topical.
|
|
106
|
-
function rowDisplayText(row) {
|
|
107
|
-
const base = `${row?.element ?? ''} ${row?.summary ?? ''}`
|
|
108
|
-
const withBody = Number(row?.is_root) === 0 ? `${base} ${row?.content ?? ''}` : base
|
|
109
|
-
return withBody.toLowerCase()
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function windowRecencyFactor(ts, tsFrom, tsTo, nowMs) {
|
|
113
|
-
const t = Number(ts)
|
|
114
|
-
if (!Number.isFinite(t)) return 0
|
|
115
|
-
const hi = tsTo != null ? tsTo : nowMs
|
|
116
|
-
const lo = tsFrom != null ? tsFrom : hi - 86_400_000 // default 24h span when open-started
|
|
117
|
-
if (!(hi > lo)) return 0
|
|
118
|
-
return Math.max(0, Math.min(1, (t - lo) / (hi - lo)))
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function buildExactTerms(query) {
|
|
122
|
-
const clean = String(query ?? '').replace(/\s+/g, ' ').trim()
|
|
123
|
-
if (!clean) return []
|
|
124
|
-
const terms = []
|
|
125
|
-
const add = (value) => {
|
|
126
|
-
const term = String(value ?? '').trim()
|
|
127
|
-
.replace(/^[^\p{L}\p{N}_./:-]+|[^\p{L}\p{N}_./:-]+$/gu, '')
|
|
128
|
-
if (!term) return
|
|
129
|
-
const hasIdentifierShape = /[_./:-]/.test(term)
|
|
130
|
-
if (!hasIdentifierShape && /^[\d\s]+$/.test(term)) return
|
|
131
|
-
const symbolCount = Array.from(term).length
|
|
132
|
-
if (!hasIdentifierShape && symbolCount < 2) return
|
|
133
|
-
terms.push(term.slice(0, 80))
|
|
134
|
-
}
|
|
135
|
-
if (clean.length <= 80) add(clean)
|
|
136
|
-
const tokens = clean.match(/[\p{L}\p{N}_./:-]+/gu) || []
|
|
137
|
-
for (const token of tokens) add(token)
|
|
138
|
-
for (let i = 0; i < tokens.length - 1; i++) {
|
|
139
|
-
add(`${tokens[i]} ${tokens[i + 1]}`)
|
|
140
|
-
}
|
|
141
|
-
return [...new Set(terms.map(t => t.toLowerCase()))].slice(0, 12)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function countQueryTokens(query) {
|
|
145
|
-
const clean = String(query ?? '').replace(/\s+/g, ' ').trim()
|
|
146
|
-
if (!clean) return 0
|
|
147
|
-
return (clean.match(/[\p{L}\p{N}_./:-]+/gu) || [])
|
|
148
|
-
.filter(token => String(token ?? '').trim().length > 0)
|
|
149
|
-
.length
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function hasFullQueryTextMatch(query, row) {
|
|
153
|
-
const clean = String(query ?? '').replace(/\s+/g, ' ').trim().toLowerCase()
|
|
154
|
-
if (!clean || clean.length > 160) return false
|
|
155
|
-
const element = String(row?.element ?? '').toLowerCase()
|
|
156
|
-
const summary = String(row?.summary ?? '').toLowerCase()
|
|
157
|
-
const content = String(row?.content ?? '').toLowerCase()
|
|
158
|
-
return (element && element.includes(clean))
|
|
159
|
-
|| (summary && summary.includes(clean))
|
|
160
|
-
|| (content && content.includes(clean))
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function hasQueryTokenCoverage(row, queryTokenCount) {
|
|
164
|
-
if (queryTokenCount <= SHORT_QUERY_TOKEN_MAX) return true
|
|
165
|
-
const hits = Number(row?.exact_hits)
|
|
166
|
-
// Majority coverage, not full coverage. Requiring EVERY query token to hit
|
|
167
|
-
// made mixed-language queries (English "usage spike" plus a Korean noun for
|
|
168
|
-
// "cause") return nothing when one
|
|
169
|
-
// token has no lexical counterpart in the row — ~60% of tokens matching is
|
|
170
|
-
// strong enough lexical evidence alongside the semantic leg.
|
|
171
|
-
const required = Math.max(2, Math.ceil(queryTokenCount * 0.6))
|
|
172
|
-
return Number.isFinite(hits) && hits >= required
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function exactTextBoost(query, row, exactHits) {
|
|
176
|
-
const clean = String(query ?? '').trim().toLowerCase()
|
|
177
|
-
if (!clean) return 0
|
|
178
|
-
const element = String(row?.element ?? '').toLowerCase()
|
|
179
|
-
const summary = String(row?.summary ?? '').toLowerCase()
|
|
180
|
-
const content = String(row?.content ?? '').toLowerCase()
|
|
181
|
-
let boost = 0
|
|
182
|
-
if (element && element.includes(clean)) boost += 0.035
|
|
183
|
-
if (summary && summary.includes(clean)) boost += 0.025
|
|
184
|
-
if (content && content.includes(clean)) boost += 0.015
|
|
185
|
-
const hits = Number(exactHits)
|
|
186
|
-
if (Number.isFinite(hits) && hits > 0) boost += Math.min(0.03, hits * 0.008)
|
|
187
|
-
return boost
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
async function _checkMvHotActivePopulated(db) {
|
|
191
|
-
const cached = _mvHotActiveCache.get(db)
|
|
192
|
-
const now = Date.now()
|
|
193
|
-
if (cached && now - cached.ts < _MV_HOT_ACTIVE_TTL_MS) return cached.populated
|
|
194
|
-
const r = await recallReadQuery(
|
|
195
|
-
db,
|
|
196
|
-
`SELECT relispopulated FROM pg_class WHERE relname = 'mv_hot_active' LIMIT 1`,
|
|
197
|
-
)
|
|
198
|
-
if (!r.rows?.length) throw new Error('mv_hot_active not found in pg_class')
|
|
199
|
-
const populated = Boolean(r.rows[0].relispopulated)
|
|
200
|
-
_mvHotActiveCache.set(db, { populated, ts: now })
|
|
201
|
-
return populated
|
|
202
|
-
}
|
|
11
|
+
import { SEMANTIC_ONLY_MIN_SIM, memberTsInWindow, SEMANTIC_TOP_RANK_MAX, SEMANTIC_TOP_RANK_MIN_SIM, SEMANTIC_TOP_RANK_STRICT_SIM, SHORT_QUERY_TOKEN_MAX, SIM_FLOOR, W_DENSE, W_WINDOW_RECENCY, W_RARE, RARE_DF_MAX, queryTokensLower, rowDisplayText, windowRecencyFactor, buildExactTerms, countQueryTokens, hasFullQueryTextMatch, hasQueryTokenCoverage, exactTextBoost, _checkMvHotActivePopulated } from './recall-scoring.mjs';
|
|
203
12
|
|
|
204
13
|
export async function searchRelevantHybrid(db, query, options = {}) {
|
|
205
14
|
const clean = String(query ?? '').trim()
|
|
@@ -13,7 +13,7 @@ const MEMORY_TOKEN_STOPWORDS = new Set([
|
|
|
13
13
|
'\uC0AC\uC6A9\uC790', '\uC720\uC800', '\uC694\uCCAD', '\uC9C8\uBB38', '\uB2F5\uBCC0', '\uC5B8\uAE09', '\uB9D0\uC500', '\uC124\uBA85', '\uBCF4\uACE0', '\uBB34\uC2A8', '\uBB50\uC57C', '\uD588\uC9C0', 'user', 'asks', 'asked', 'request', 'requested', 'question', 'answer', 'reply', 'said', 'mentioned', 'explained', 'reported', 'what', 'huh',
|
|
14
14
|
])
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
function normalizeMemoryToken(token) {
|
|
17
17
|
let normalized = String(token ?? '').trim().toLowerCase()
|
|
18
18
|
if (!normalized) return ''
|
|
19
19
|
|
|
@@ -36,7 +36,7 @@ export function normalizeMemoryToken(token) {
|
|
|
36
36
|
return normalized
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
function tokenizeMemoryText(text) {
|
|
40
40
|
return cleanMemoryText(text)
|
|
41
41
|
.toLowerCase()
|
|
42
42
|
.split(/[^\p{L}\p{N}_]+/u)
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function __mixdogMemoryLog(...args) {
|
|
3
|
-
if (process.env.MIXDOG_QUIET_MEMORY_LOG) return true;
|
|
4
|
-
return __mixdogMemoryStderrWrite(...args);
|
|
5
|
-
}
|
|
1
|
+
import { __mixdogMemoryLog } from './memory-log.mjs';
|
|
6
2
|
|
|
7
3
|
// Native-PG-backed memory store. Schema, helpers, and lifecycle.
|
|
8
4
|
|
|
@@ -371,7 +367,7 @@ async function resetEmbeddingColumnsForDims(db, dimCount) {
|
|
|
371
367
|
// Validate that the halfvec column dimension stored in the DB matches
|
|
372
368
|
// dimCount from the current model config. Call after schema is confirmed
|
|
373
369
|
// complete and before any embedding operations.
|
|
374
|
-
|
|
370
|
+
async function validateEmbeddingDims(db, dimCount) {
|
|
375
371
|
const colDims = await getEmbeddingColumnDims(db, 'entries')
|
|
376
372
|
if (colDims == null) return // column absent — pre-schema DB; bootstrapSchema will handle
|
|
377
373
|
// pgvector halfvec stores dimension as atttypmod directly (unlike varchar which uses dims+4).
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function __mixdogMemoryLog(...args) {
|
|
3
|
-
if (process.env.MIXDOG_QUIET_MEMORY_LOG) return true;
|
|
4
|
-
return __mixdogMemoryStderrWrite(...args);
|
|
5
|
-
}
|
|
1
|
+
import { __mixdogMemoryLog } from '../memory-log.mjs';
|
|
6
2
|
|
|
7
3
|
const _poolClientErrorHandlers = new WeakMap()
|
|
8
4
|
|
|
@@ -112,7 +108,7 @@ const _bootstrapped = new Set()
|
|
|
112
108
|
|
|
113
109
|
const ADVISORY_LOCK_CLASSID = 0x6d696478 // "midx" — mixdog bootstrap namespace
|
|
114
110
|
const ADVISORY_OBJID_CREATE_DB = 1 // CREATE DATABASE mixdog
|
|
115
|
-
|
|
111
|
+
const ADVISORY_OBJID_SCHEMA_BOOTSTRAP = 2 // extensions + schema DDL
|
|
116
112
|
|
|
117
113
|
// ---------------------------------------------------------------------------
|
|
118
114
|
// In-process cache
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function __mixdogMemoryLog(...args) {
|
|
3
|
-
if (process.env.MIXDOG_QUIET_MEMORY_LOG) return true;
|
|
4
|
-
return __mixdogMemoryStderrWrite(...args);
|
|
5
|
-
}
|
|
1
|
+
import { __mixdogMemoryLog } from '../memory-log.mjs';
|
|
6
2
|
|
|
7
3
|
// pg-process.mjs — lower-level PG lifecycle helpers for mixdog 0.4.0
|
|
8
4
|
// Track B can wire these into the supervisor; pg-adapter calls them directly.
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function __mixdogMemoryLog(...args) {
|
|
3
|
-
if (process.env.MIXDOG_QUIET_MEMORY_LOG) return true;
|
|
4
|
-
return __mixdogMemoryStderrWrite(...args);
|
|
5
|
-
}
|
|
1
|
+
import { __mixdogMemoryLog } from '../memory-log.mjs';
|
|
6
2
|
|
|
7
3
|
/**
|
|
8
4
|
* supervisor-pg — PG child process lifecycle wired into the mixdog supervisor.
|
|
@@ -109,7 +109,7 @@ export function formatTs(tsMs) {
|
|
|
109
109
|
return String(tsMs ?? '').slice(0, 16)
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
const CORE_RECALL_STOPWORDS = new Set([
|
|
113
113
|
'about', 'after', 'again', 'before', 'check', 'color', 'decision', 'decided',
|
|
114
114
|
'earlier', 'memory', 'previous', 'routing', 'stored', 'tell', 'what',
|
|
115
115
|
])
|
|
@@ -258,7 +258,7 @@ function exactDuplicateKey(r) {
|
|
|
258
258
|
// Legacy object-identity-only ingest could mint duplicate rows on JSON reload.
|
|
259
259
|
// Keep the newest/highest-ranked exact body once, including short acknowledgments
|
|
260
260
|
// that shingle dedupe intentionally ignores.
|
|
261
|
-
|
|
261
|
+
function collapseExactDuplicateRows(rows) {
|
|
262
262
|
if (!Array.isArray(rows) || rows.length < 2) return rows
|
|
263
263
|
const seen = new Set()
|
|
264
264
|
const out = []
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// Hybrid-recall scoring constants and pure helpers, extracted from memory-recall-store.mjs.
|
|
2
|
+
import { buildFtsQuery, buildFtsPrefixQuery } from './memory-text-utils.mjs'
|
|
3
|
+
import { VALID_CATEGORY, embeddingToSql } from './memory.mjs'
|
|
4
|
+
import { freshnessFactor } from './memory-score.mjs'
|
|
5
|
+
import { buildRecallScopeFilter } from './memory-recall-scope-filter.mjs'
|
|
6
|
+
import { recallReadQuery } from './memory-recall-read-query.mjs'
|
|
7
|
+
|
|
8
|
+
const _MV_HOT_ACTIVE_TTL_MS = 60_000
|
|
9
|
+
const _mvHotActiveCache = new WeakMap() // db → { populated: boolean, ts: number }
|
|
10
|
+
export const SEMANTIC_ONLY_MIN_SIM = 0.72
|
|
11
|
+
// Member-hit time gate: a chunk MEMBER whose own ts falls inside the requested
|
|
12
|
+
// [ts_from, ts_to] window is an in-window match even when its ROOT's ts sits
|
|
13
|
+
// outside it. Returns true when the member ts is within the (open-ended) window.
|
|
14
|
+
export function memberTsInWindow(row, tsFrom, tsTo) {
|
|
15
|
+
const ts = Number(row?.ts)
|
|
16
|
+
if (!Number.isFinite(ts)) return true // undated member: don't drop on window
|
|
17
|
+
if (tsFrom != null && ts < tsFrom) return false
|
|
18
|
+
if (tsTo != null && ts > tsTo) return false
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
21
|
+
// Cross-language semantic rescue: a query in one language against rows in
|
|
22
|
+
// another rarely clears SEMANTIC_ONLY_MIN_SIM on a small (384-dim) embedding
|
|
23
|
+
// model, yet the TOP dense ranks are still overwhelmingly relevant. Accept
|
|
24
|
+
// semantic-only rows that are both top-ranked in the dense leg AND above a
|
|
25
|
+
// softer floor, instead of dropping everything below 0.72.
|
|
26
|
+
export const SEMANTIC_TOP_RANK_MAX = 3
|
|
27
|
+
// Floor for the top-rank rescue. 384-dim MiniLM-class embeddings put UNRELATED
|
|
28
|
+
// text at ~0.65-0.75 sim (measured: gibberish query "zzqqxx ... 999" scored
|
|
29
|
+
// 0.749 against real rows), so anything below ~0.70 is noise regardless of
|
|
30
|
+
// rank; cross-language relevant pairs measured 0.67-0.74. 0.70 keeps most of
|
|
31
|
+
// the cross-language rescue while rejecting pure-noise top ranks.
|
|
32
|
+
// The softer 0.70 floor SITS INSIDE the noise band (noise peaked at 0.749), so
|
|
33
|
+
// it only rescues rows that ALSO carry a lexical leg as corroboration. A
|
|
34
|
+
// semantic-only row (no sparse/trgm/exact) must clear SEMANTIC_TOP_RANK_STRICT_SIM
|
|
35
|
+
// instead — set above the measured 0.749 noise ceiling so unrelated top ranks
|
|
36
|
+
// (e.g. old narration surfacing for "embedding worker crash") stop leaking in.
|
|
37
|
+
export const SEMANTIC_TOP_RANK_MIN_SIM = 0.70
|
|
38
|
+
export const SEMANTIC_TOP_RANK_STRICT_SIM = 0.78
|
|
39
|
+
export const SHORT_QUERY_TOKEN_MAX = 2
|
|
40
|
+
// Dense-similarity weighting for retrievalScore. Lexical RRF sums 1/(K+rank)
|
|
41
|
+
// per matching leg (K=60), so a row hitting 2 lexical legs at rank 1 scores
|
|
42
|
+
// rrf ≈ 2/(60+1) = 0.0328 — enough to bury a single semantically-close dense
|
|
43
|
+
// hit that never shares lexical terms. We add a normalized dense-similarity
|
|
44
|
+
// term so a strong dense-only match can outrank stale multi-leg lexical hits:
|
|
45
|
+
// denseTerm = W_DENSE * max(0, sim - SIM_FLOOR) / (1 - SIM_FLOOR) * freshness
|
|
46
|
+
// At sim=0.85: (0.85-0.60)/(1-0.60) = 0.625, so denseTerm = 0.04 * 0.625 = 0.025
|
|
47
|
+
// with freshness=1. That alone doesn't beat 0.0328, but combined with the
|
|
48
|
+
// row's own rrf contribution (a dense-only row still has 1/(60+rank) from its
|
|
49
|
+
// dense rank, e.g. rank 1 → 0.0164) the total ≈ 0.0164 + 0.025 = 0.0414,
|
|
50
|
+
// which clears the 0.0328 two-leg lexical baseline. W_DENSE=0.04 was chosen
|
|
51
|
+
// as the smallest round value satisfying this at sim=0.85; SIM_FLOOR=0.60
|
|
52
|
+
// matches the noise floor used elsewhere for MiniLM-class embeddings.
|
|
53
|
+
export const SIM_FLOOR = 0.60
|
|
54
|
+
export const W_DENSE = 0.04
|
|
55
|
+
// Recency nudge applied ONLY when a [ts_from, ts_to] window is active. Inside a
|
|
56
|
+
// fixed window absolute-age freshness is often disabled (applyFreshness=false)
|
|
57
|
+
// or too flat to separate early-window from late-window rows, so a 07-04 row
|
|
58
|
+
// could outrank a 07-05 row of comparable relevance under a 24h period. This
|
|
59
|
+
// term is a normalized position-in-window score (newest→1) scaled small enough
|
|
60
|
+
// to break comparable-relevance ties toward newer rows without overriding a
|
|
61
|
+
// clearly stronger lexical/semantic match.
|
|
62
|
+
// Kept below a single rank-1 RRF leg (~0.016) so it only breaks ties between
|
|
63
|
+
// comparable-relevance rows and never overrides a clearly stronger match.
|
|
64
|
+
export const W_WINDOW_RECENCY = 0.008
|
|
65
|
+
// Rare-token display boost. A query token that appears in the RENDERED display
|
|
66
|
+
// of only a small fraction of the candidate set (an IDF-style rarity signal) is
|
|
67
|
+
// strong evidence a row is genuinely about that term — even for a
|
|
68
|
+
// cross-language row whose only lexical tie is one distinctive English token
|
|
69
|
+
// (e.g. "embedding" inside otherwise-Korean content). We add a boost when such
|
|
70
|
+
// a rare token is present in the fields that actually render (element/summary
|
|
71
|
+
// for roots, content for member-hit turns), so a low-lexical row surfaces above
|
|
72
|
+
// common-token neighbours. Scoped to display fields so we never promote a row
|
|
73
|
+
// whose match hides in un-rendered body text. RARE_DF_MAX gates "rare": tokens
|
|
74
|
+
// present in >34% of candidates are common and earn nothing.
|
|
75
|
+
// Scaled to at most one rank-1 RRF leg (1/(K+1) ≈ 0.0164 at K=60): a rare
|
|
76
|
+
// display token is a genuine relevance signal, but the IDF boost should only
|
|
77
|
+
// carry the weight of a single extra retrieval-leg agreement — enough to break
|
|
78
|
+
// ties toward the distinctive-token row without overriding a clearly stronger
|
|
79
|
+
// multi-leg lexical/semantic match. W_RARE * (1 - df/N) peaks below this cap.
|
|
80
|
+
export const W_RARE = 0.016
|
|
81
|
+
export const RARE_DF_MAX = 0.34
|
|
82
|
+
|
|
83
|
+
// Lowercased, de-duplicated query tokens (>= 2 chars) for DF/boost/gate use.
|
|
84
|
+
// Capped at 12 (mirrors buildExactTerms) so a paragraph-length query can't
|
|
85
|
+
// turn the per-row DF scan into O(tokens × candidateWindow) on display text.
|
|
86
|
+
export function queryTokensLower(query) {
|
|
87
|
+
const clean = String(query ?? '').replace(/\s+/g, ' ').trim()
|
|
88
|
+
const toks = (clean.match(/[\p{L}\p{N}_./:-]+/gu) || [])
|
|
89
|
+
.map(t => t.toLowerCase())
|
|
90
|
+
.filter(t => Array.from(t).length >= 2)
|
|
91
|
+
return [...new Set(toks)].slice(0, 12)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// The text that actually renders as a result LINE for a row: element+summary
|
|
95
|
+
// for a root (its members render on their own lines), plus content for a
|
|
96
|
+
// member-hit turn (its own content is the rendered line). Deliberately excludes
|
|
97
|
+
// a ROOT's body content, which never renders when the row is shown as a summary
|
|
98
|
+
// line — matching there is incidental, not topical.
|
|
99
|
+
export function rowDisplayText(row) {
|
|
100
|
+
const base = `${row?.element ?? ''} ${row?.summary ?? ''}`
|
|
101
|
+
const withBody = Number(row?.is_root) === 0 ? `${base} ${row?.content ?? ''}` : base
|
|
102
|
+
return withBody.toLowerCase()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function windowRecencyFactor(ts, tsFrom, tsTo, nowMs) {
|
|
106
|
+
const t = Number(ts)
|
|
107
|
+
if (!Number.isFinite(t)) return 0
|
|
108
|
+
const hi = tsTo != null ? tsTo : nowMs
|
|
109
|
+
const lo = tsFrom != null ? tsFrom : hi - 86_400_000 // default 24h span when open-started
|
|
110
|
+
if (!(hi > lo)) return 0
|
|
111
|
+
return Math.max(0, Math.min(1, (t - lo) / (hi - lo)))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function buildExactTerms(query) {
|
|
115
|
+
const clean = String(query ?? '').replace(/\s+/g, ' ').trim()
|
|
116
|
+
if (!clean) return []
|
|
117
|
+
const terms = []
|
|
118
|
+
const add = (value) => {
|
|
119
|
+
const term = String(value ?? '').trim()
|
|
120
|
+
.replace(/^[^\p{L}\p{N}_./:-]+|[^\p{L}\p{N}_./:-]+$/gu, '')
|
|
121
|
+
if (!term) return
|
|
122
|
+
const hasIdentifierShape = /[_./:-]/.test(term)
|
|
123
|
+
if (!hasIdentifierShape && /^[\d\s]+$/.test(term)) return
|
|
124
|
+
const symbolCount = Array.from(term).length
|
|
125
|
+
if (!hasIdentifierShape && symbolCount < 2) return
|
|
126
|
+
terms.push(term.slice(0, 80))
|
|
127
|
+
}
|
|
128
|
+
if (clean.length <= 80) add(clean)
|
|
129
|
+
const tokens = clean.match(/[\p{L}\p{N}_./:-]+/gu) || []
|
|
130
|
+
for (const token of tokens) add(token)
|
|
131
|
+
for (let i = 0; i < tokens.length - 1; i++) {
|
|
132
|
+
add(`${tokens[i]} ${tokens[i + 1]}`)
|
|
133
|
+
}
|
|
134
|
+
return [...new Set(terms.map(t => t.toLowerCase()))].slice(0, 12)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function countQueryTokens(query) {
|
|
138
|
+
const clean = String(query ?? '').replace(/\s+/g, ' ').trim()
|
|
139
|
+
if (!clean) return 0
|
|
140
|
+
return (clean.match(/[\p{L}\p{N}_./:-]+/gu) || [])
|
|
141
|
+
.filter(token => String(token ?? '').trim().length > 0)
|
|
142
|
+
.length
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function hasFullQueryTextMatch(query, row) {
|
|
146
|
+
const clean = String(query ?? '').replace(/\s+/g, ' ').trim().toLowerCase()
|
|
147
|
+
if (!clean || clean.length > 160) return false
|
|
148
|
+
const element = String(row?.element ?? '').toLowerCase()
|
|
149
|
+
const summary = String(row?.summary ?? '').toLowerCase()
|
|
150
|
+
const content = String(row?.content ?? '').toLowerCase()
|
|
151
|
+
return (element && element.includes(clean))
|
|
152
|
+
|| (summary && summary.includes(clean))
|
|
153
|
+
|| (content && content.includes(clean))
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function hasQueryTokenCoverage(row, queryTokenCount) {
|
|
157
|
+
if (queryTokenCount <= SHORT_QUERY_TOKEN_MAX) return true
|
|
158
|
+
const hits = Number(row?.exact_hits)
|
|
159
|
+
// Majority coverage, not full coverage. Requiring EVERY query token to hit
|
|
160
|
+
// made mixed-language queries (English "usage spike" plus a Korean noun for
|
|
161
|
+
// "cause") return nothing when one
|
|
162
|
+
// token has no lexical counterpart in the row — ~60% of tokens matching is
|
|
163
|
+
// strong enough lexical evidence alongside the semantic leg.
|
|
164
|
+
const required = Math.max(2, Math.ceil(queryTokenCount * 0.6))
|
|
165
|
+
return Number.isFinite(hits) && hits >= required
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function exactTextBoost(query, row, exactHits) {
|
|
169
|
+
const clean = String(query ?? '').trim().toLowerCase()
|
|
170
|
+
if (!clean) return 0
|
|
171
|
+
const element = String(row?.element ?? '').toLowerCase()
|
|
172
|
+
const summary = String(row?.summary ?? '').toLowerCase()
|
|
173
|
+
const content = String(row?.content ?? '').toLowerCase()
|
|
174
|
+
let boost = 0
|
|
175
|
+
if (element && element.includes(clean)) boost += 0.035
|
|
176
|
+
if (summary && summary.includes(clean)) boost += 0.025
|
|
177
|
+
if (content && content.includes(clean)) boost += 0.015
|
|
178
|
+
const hits = Number(exactHits)
|
|
179
|
+
if (Number.isFinite(hits) && hits > 0) boost += Math.min(0.03, hits * 0.008)
|
|
180
|
+
return boost
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export async function _checkMvHotActivePopulated(db) {
|
|
184
|
+
const cached = _mvHotActiveCache.get(db)
|
|
185
|
+
const now = Date.now()
|
|
186
|
+
if (cached && now - cached.ts < _MV_HOT_ACTIVE_TTL_MS) return cached.populated
|
|
187
|
+
const r = await recallReadQuery(
|
|
188
|
+
db,
|
|
189
|
+
`SELECT relispopulated FROM pg_class WHERE relname = 'mv_hot_active' LIMIT 1`,
|
|
190
|
+
)
|
|
191
|
+
if (!r.rows?.length) throw new Error('mv_hot_active not found in pg_class')
|
|
192
|
+
const populated = Boolean(r.rows[0].relispopulated)
|
|
193
|
+
_mvHotActiveCache.set(db, { populated, ts: now })
|
|
194
|
+
return populated
|
|
195
|
+
}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function __mixdogMemoryLog(...args) {
|
|
3
|
-
if (process.env.MIXDOG_QUIET_MEMORY_LOG) return true;
|
|
4
|
-
return __mixdogMemoryStderrWrite(...args);
|
|
5
|
-
}
|
|
1
|
+
import { __mixdogMemoryLog } from './memory-log.mjs';
|
|
6
2
|
|
|
7
3
|
// runtime-fetcher.mjs — P1 runtime fetcher for mixdog 0.4.0
|
|
8
4
|
// runtime-fetcher.mjs
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function __mixdogMemoryLog(...args) {
|
|
3
|
-
if (process.env.MIXDOG_QUIET_MEMORY_LOG) return true;
|
|
4
|
-
return __mixdogMemoryStderrWrite(...args);
|
|
5
|
-
}
|
|
1
|
+
import { __mixdogMemoryLog } from './memory-log.mjs';
|
|
6
2
|
|
|
7
3
|
// trace-store.mjs — native-PG trace analytics store for mixdog 0.4.0.
|
|
8
4
|
// Uses pg-adapter (schema='trace') so trace_events live in the trace schema.
|
|
@@ -173,7 +169,7 @@ async function migrateSchemaDrift(client) {
|
|
|
173
169
|
// Called once per openTraceDatabase boot, inside the BOOTSTRAP advisory-lock
|
|
174
170
|
// scope (see openTraceDatabase) so concurrent first-boot processes don't race
|
|
175
171
|
// this DDL. All statements remain IF NOT EXISTS as a second line of defense.
|
|
176
|
-
|
|
172
|
+
async function initAgentTables(client) {
|
|
177
173
|
// Repair schema drift on already-created tables before anything else
|
|
178
174
|
// (trace_events already exists at this point via init(); agent_sessions
|
|
179
175
|
// is created just below in this same function).
|
|
@@ -19,8 +19,8 @@ export function buildHeaders() {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308])
|
|
23
|
+
const MAX_REDIRECTS = 5
|
|
24
24
|
// Hard cap on response body size (10 MB) to prevent memory DoS from a
|
|
25
25
|
// hostile / misconfigured URL returning a huge body. Applied in two places:
|
|
26
26
|
// 1. Content-Length pre-check (cheap reject before reading bytes).
|
|
@@ -39,7 +39,7 @@ export function isFatalHttpPathPolicyError(error) {
|
|
|
39
39
|
return false
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
async function readBodyWithCap(response, maxBytes) {
|
|
43
43
|
// Reject non-text content-types early; decode by content-type charset.
|
|
44
44
|
const contentType = (response.headers.get('content-type') || '').toLowerCase()
|
|
45
45
|
if (contentType) {
|
|
@@ -96,7 +96,7 @@ export async function readBodyWithCap(response, maxBytes) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/** Binary-safe body reader for CDP Fetch fulfillment (no text-only filter). */
|
|
99
|
-
|
|
99
|
+
async function readBodyBytesWithCap(response, maxBytes) {
|
|
100
100
|
const contentLength = Number(response.headers.get('content-length') || 0)
|
|
101
101
|
if (contentLength > maxBytes) {
|
|
102
102
|
try { await response.body?.cancel() } catch {}
|
|
@@ -214,7 +214,7 @@ async function pinnedLoopbackFetch(url, options = {}) {
|
|
|
214
214
|
})
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
|
|
217
|
+
function assertLoopbackUrl(url) {
|
|
218
218
|
const parsed = new URL(url)
|
|
219
219
|
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
220
220
|
throw new Error(`Blocked non-HTTP protocol: ${parsed.protocol}`)
|
|
@@ -289,7 +289,7 @@ const CDP_FORBIDDEN_RESPONSE_HEADERS = new Set([
|
|
|
289
289
|
'content-encoding',
|
|
290
290
|
])
|
|
291
291
|
|
|
292
|
-
|
|
292
|
+
function headersToCdpPairs(headers) {
|
|
293
293
|
const out = []
|
|
294
294
|
headers.forEach((value, name) => {
|
|
295
295
|
const lower = name.toLowerCase()
|
|
@@ -564,7 +564,7 @@ async function mapWithPuppeteer(url, options, timeoutMs, signal) {
|
|
|
564
564
|
})
|
|
565
565
|
}
|
|
566
566
|
|
|
567
|
-
|
|
567
|
+
async function scrapeUrl(url, timeoutMs, usageState, signal) {
|
|
568
568
|
const normalizedUrl = normalizeUrl(url)
|
|
569
569
|
const host = new URL(normalizedUrl).host
|
|
570
570
|
const extractors = rankScrapeExtractors(host, usageState, DEFAULT_EXTRACTORS)
|
|
@@ -646,7 +646,7 @@ async function mapSite(url, { limit = 50, sameDomainOnly = true, search }, timeo
|
|
|
646
646
|
return mapWithPuppeteer(url, options, timeoutMs, signal)
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
-
|
|
649
|
+
async function crawlSite(
|
|
650
650
|
startUrl,
|
|
651
651
|
{ maxPages = 10, maxDepth = 1, sameDomainOnly = true },
|
|
652
652
|
timeoutMs,
|
|
@@ -182,7 +182,7 @@ export function getBufferedAppenderStats(path) {
|
|
|
182
182
|
* Synchronously drain any remaining buffered bytes for every known path.
|
|
183
183
|
* Intended for process exit hooks only — best-effort, never throws.
|
|
184
184
|
*/
|
|
185
|
-
|
|
185
|
+
function drainAllSync() {
|
|
186
186
|
for (const [path, q] of queues) {
|
|
187
187
|
drainPathSync(path);
|
|
188
188
|
}
|
|
@@ -43,7 +43,7 @@ let killing = false;
|
|
|
43
43
|
let orphanedAt = 0;
|
|
44
44
|
const timer = setInterval(() => {
|
|
45
45
|
if (!alive(childPid)) process.exit(0);
|
|
46
|
-
// Orphaned when the parent PID dies. Matches
|
|
46
|
+
// Orphaned when the parent PID dies. Matches mainstream CLIs: no console
|
|
47
47
|
// probe — a hidden shell spawn (windowsHide) plus tree-kill on cleanup, so
|
|
48
48
|
// orphan detection is pure parent-liveness.
|
|
49
49
|
if (alive(parentPid)) {
|
|
@@ -144,7 +144,7 @@ export function hasSpareCapacity() {
|
|
|
144
144
|
* @param {AbortSignal | null} [signal]
|
|
145
145
|
* @returns {Promise<T>}
|
|
146
146
|
*/
|
|
147
|
-
|
|
147
|
+
async function withGate(fn, signal = null) {
|
|
148
148
|
const release = await acquire(signal);
|
|
149
149
|
try {
|
|
150
150
|
return await fn({ signal: signal || null });
|