@getrift/rift 0.1.0-beta.2 → 0.1.0-beta.20
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 +35 -9
- package/dist/src/auth/keychain.d.ts +9 -0
- package/dist/src/auth/keychain.d.ts.map +1 -1
- package/dist/src/auth/keychain.js +37 -0
- package/dist/src/auth/keychain.js.map +1 -1
- package/dist/src/capture/auto-capture.d.ts +7 -0
- package/dist/src/capture/auto-capture.d.ts.map +1 -1
- package/dist/src/capture/auto-capture.js +82 -15
- package/dist/src/capture/auto-capture.js.map +1 -1
- package/dist/src/capture/auto-repair.d.ts +110 -0
- package/dist/src/capture/auto-repair.d.ts.map +1 -0
- package/dist/src/capture/auto-repair.js +269 -0
- package/dist/src/capture/auto-repair.js.map +1 -0
- package/dist/src/capture/codex-cli-triage-provider.d.ts.map +1 -1
- package/dist/src/capture/codex-cli-triage-provider.js +4 -3
- package/dist/src/capture/codex-cli-triage-provider.js.map +1 -1
- package/dist/src/capture/observability.d.ts +42 -0
- package/dist/src/capture/observability.d.ts.map +1 -1
- package/dist/src/capture/observability.js +45 -4
- package/dist/src/capture/observability.js.map +1 -1
- package/dist/src/capture/recover-quarantine.d.ts +260 -0
- package/dist/src/capture/recover-quarantine.d.ts.map +1 -0
- package/dist/src/capture/recover-quarantine.js +522 -0
- package/dist/src/capture/recover-quarantine.js.map +1 -0
- package/dist/src/cli/commands/backfill.d.ts.map +1 -1
- package/dist/src/cli/commands/backfill.js +5 -2
- package/dist/src/cli/commands/backfill.js.map +1 -1
- package/dist/src/cli/commands/capture-recover.d.ts +40 -0
- package/dist/src/cli/commands/capture-recover.d.ts.map +1 -0
- package/dist/src/cli/commands/capture-recover.js +184 -0
- package/dist/src/cli/commands/capture-recover.js.map +1 -0
- package/dist/src/cli/commands/capture.d.ts.map +1 -1
- package/dist/src/cli/commands/capture.js +96 -5
- package/dist/src/cli/commands/capture.js.map +1 -1
- package/dist/src/cli/commands/doctor.d.ts +6 -0
- package/dist/src/cli/commands/doctor.d.ts.map +1 -0
- package/dist/src/cli/commands/doctor.js +242 -0
- package/dist/src/cli/commands/doctor.js.map +1 -0
- package/dist/src/cli/commands/feedback.d.ts +12 -0
- package/dist/src/cli/commands/feedback.d.ts.map +1 -1
- package/dist/src/cli/commands/feedback.js +93 -4
- package/dist/src/cli/commands/feedback.js.map +1 -1
- package/dist/src/cli/commands/mcp-install.js +5 -2
- package/dist/src/cli/commands/mcp-install.js.map +1 -1
- package/dist/src/cli/commands/menubar.d.ts +30 -0
- package/dist/src/cli/commands/menubar.d.ts.map +1 -0
- package/dist/src/cli/commands/menubar.js +180 -0
- package/dist/src/cli/commands/menubar.js.map +1 -0
- package/dist/src/cli/commands/onboard.d.ts +129 -0
- package/dist/src/cli/commands/onboard.d.ts.map +1 -1
- package/dist/src/cli/commands/onboard.js +752 -171
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/rebuild.d.ts.map +1 -1
- package/dist/src/cli/commands/rebuild.js +6 -3
- package/dist/src/cli/commands/rebuild.js.map +1 -1
- package/dist/src/cli/commands/reconcile.d.ts.map +1 -1
- package/dist/src/cli/commands/reconcile.js +12 -0
- package/dist/src/cli/commands/reconcile.js.map +1 -1
- package/dist/src/cli/commands/review.d.ts.map +1 -1
- package/dist/src/cli/commands/review.js +22 -7
- package/dist/src/cli/commands/review.js.map +1 -1
- package/dist/src/cli/commands/search.d.ts +2 -0
- package/dist/src/cli/commands/search.d.ts.map +1 -1
- package/dist/src/cli/commands/search.js +34 -4
- package/dist/src/cli/commands/search.js.map +1 -1
- package/dist/src/cli/commands/status.d.ts +9 -7
- package/dist/src/cli/commands/status.d.ts.map +1 -1
- package/dist/src/cli/commands/status.js +113 -12
- package/dist/src/cli/commands/status.js.map +1 -1
- package/dist/src/cli/commands/token-issue.d.ts.map +1 -1
- package/dist/src/cli/commands/token-issue.js +9 -1
- package/dist/src/cli/commands/token-issue.js.map +1 -1
- package/dist/src/cli/commands/triage.d.ts.map +1 -1
- package/dist/src/cli/commands/triage.js +7 -5
- package/dist/src/cli/commands/triage.js.map +1 -1
- package/dist/src/cli/commands/update.d.ts +80 -0
- package/dist/src/cli/commands/update.d.ts.map +1 -0
- package/dist/src/cli/commands/update.js +378 -0
- package/dist/src/cli/commands/update.js.map +1 -0
- package/dist/src/cli/default-config-path.d.ts +15 -0
- package/dist/src/cli/default-config-path.d.ts.map +1 -0
- package/dist/src/cli/default-config-path.js +27 -0
- package/dist/src/cli/default-config-path.js.map +1 -0
- package/dist/src/cli/feedback/feedback-config.d.ts +46 -0
- package/dist/src/cli/feedback/feedback-config.d.ts.map +1 -1
- package/dist/src/cli/feedback/feedback-config.js +130 -4
- package/dist/src/cli/feedback/feedback-config.js.map +1 -1
- package/dist/src/cli/feedback/feedback-history.d.ts +7 -0
- package/dist/src/cli/feedback/feedback-history.d.ts.map +1 -1
- package/dist/src/cli/feedback/feedback-history.js +39 -9
- package/dist/src/cli/feedback/feedback-history.js.map +1 -1
- package/dist/src/cli/feedback/feedback-payload.d.ts +22 -1
- package/dist/src/cli/feedback/feedback-payload.d.ts.map +1 -1
- package/dist/src/cli/feedback/feedback-payload.js.map +1 -1
- package/dist/src/cli/feedback/feedback-relay.d.ts +2 -2
- package/dist/src/cli/feedback/feedback-relay.d.ts.map +1 -1
- package/dist/src/cli/feedback/feedback-relay.js.map +1 -1
- package/dist/src/cli/feedback/invite.d.ts +17 -0
- package/dist/src/cli/feedback/invite.d.ts.map +1 -0
- package/dist/src/cli/feedback/invite.js +67 -0
- package/dist/src/cli/feedback/invite.js.map +1 -0
- package/dist/src/cli/feedback/relay-secret-store.d.ts +32 -0
- package/dist/src/cli/feedback/relay-secret-store.d.ts.map +1 -0
- package/dist/src/cli/feedback/relay-secret-store.js +137 -0
- package/dist/src/cli/feedback/relay-secret-store.js.map +1 -0
- package/dist/src/cli/http-client.d.ts +93 -1
- package/dist/src/cli/http-client.d.ts.map +1 -1
- package/dist/src/cli/http-client.js +254 -6
- package/dist/src/cli/http-client.js.map +1 -1
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +29 -6
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/postinstall-menubar.d.ts +22 -0
- package/dist/src/cli/postinstall-menubar.d.ts.map +1 -0
- package/dist/src/cli/postinstall-menubar.js +39 -0
- package/dist/src/cli/postinstall-menubar.js.map +1 -0
- package/dist/src/cli/status/friend-header.d.ts +8 -1
- package/dist/src/cli/status/friend-header.d.ts.map +1 -1
- package/dist/src/cli/status/friend-header.js +334 -26
- package/dist/src/cli/status/friend-header.js.map +1 -1
- package/dist/src/cli/ui.d.ts +47 -0
- package/dist/src/cli/ui.d.ts.map +1 -0
- package/dist/src/cli/ui.js +166 -0
- package/dist/src/cli/ui.js.map +1 -0
- package/dist/src/config/schema.d.ts +79 -0
- package/dist/src/config/schema.d.ts.map +1 -1
- package/dist/src/config/schema.js +44 -0
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/diagnostics/codex-preflight.d.ts +33 -0
- package/dist/src/diagnostics/codex-preflight.d.ts.map +1 -0
- package/dist/src/diagnostics/codex-preflight.js +75 -0
- package/dist/src/diagnostics/codex-preflight.js.map +1 -0
- package/dist/src/diagnostics/doctor.d.ts +106 -0
- package/dist/src/diagnostics/doctor.d.ts.map +1 -0
- package/dist/src/diagnostics/doctor.js +334 -0
- package/dist/src/diagnostics/doctor.js.map +1 -0
- package/dist/src/diagnostics/notify.d.ts +90 -0
- package/dist/src/diagnostics/notify.d.ts.map +1 -0
- package/dist/src/diagnostics/notify.js +177 -0
- package/dist/src/diagnostics/notify.js.map +1 -0
- package/dist/src/diagnostics/repair-prompt.d.ts +49 -0
- package/dist/src/diagnostics/repair-prompt.d.ts.map +1 -0
- package/dist/src/diagnostics/repair-prompt.js +223 -0
- package/dist/src/diagnostics/repair-prompt.js.map +1 -0
- package/dist/src/ingestion/inbox-core/conversation-fingerprint.d.ts +2 -0
- package/dist/src/ingestion/inbox-core/conversation-fingerprint.d.ts.map +1 -0
- package/dist/src/ingestion/inbox-core/conversation-fingerprint.js +27 -0
- package/dist/src/ingestion/inbox-core/conversation-fingerprint.js.map +1 -0
- package/dist/src/ingestion/inbox-core/conversation-key.d.ts +2 -0
- package/dist/src/ingestion/inbox-core/conversation-key.d.ts.map +1 -0
- package/dist/src/ingestion/inbox-core/conversation-key.js +31 -0
- package/dist/src/ingestion/inbox-core/conversation-key.js.map +1 -0
- package/dist/src/ingestion/inbox-core/extensions.d.ts +3 -0
- package/dist/src/ingestion/inbox-core/extensions.d.ts.map +1 -0
- package/dist/src/ingestion/inbox-core/extensions.js +16 -0
- package/dist/src/ingestion/inbox-core/extensions.js.map +1 -0
- package/dist/src/ingestion/inbox-core/idempotency.d.ts +2 -0
- package/dist/src/ingestion/inbox-core/idempotency.d.ts.map +1 -0
- package/dist/src/ingestion/inbox-core/idempotency.js +22 -0
- package/dist/src/ingestion/inbox-core/idempotency.js.map +1 -0
- package/dist/src/ingestion/inbox-core/index.d.ts +20 -0
- package/dist/src/ingestion/inbox-core/index.d.ts.map +1 -0
- package/dist/src/ingestion/inbox-core/index.js +20 -0
- package/dist/src/ingestion/inbox-core/index.js.map +1 -0
- package/dist/src/ingestion/inbox-core/source-detection.d.ts +2 -0
- package/dist/src/ingestion/inbox-core/source-detection.d.ts.map +1 -0
- package/dist/src/ingestion/inbox-core/source-detection.js +23 -0
- package/dist/src/ingestion/inbox-core/source-detection.js.map +1 -0
- package/dist/src/ingestion/inbox-core/source-sniffer.d.ts +11 -0
- package/dist/src/ingestion/inbox-core/source-sniffer.d.ts.map +1 -0
- package/dist/src/ingestion/inbox-core/source-sniffer.js +69 -0
- package/dist/src/ingestion/inbox-core/source-sniffer.js.map +1 -0
- package/dist/src/ingestion/inbox-core/zip-sniffer.d.ts +70 -0
- package/dist/src/ingestion/inbox-core/zip-sniffer.d.ts.map +1 -0
- package/dist/src/ingestion/inbox-core/zip-sniffer.js +161 -0
- package/dist/src/ingestion/inbox-core/zip-sniffer.js.map +1 -0
- package/dist/src/ingestion/inbox-watcher.d.ts.map +1 -1
- package/dist/src/ingestion/inbox-watcher.js +34 -50
- package/dist/src/ingestion/inbox-watcher.js.map +1 -1
- package/dist/src/ingestion/indexer.d.ts +7 -0
- package/dist/src/ingestion/indexer.d.ts.map +1 -1
- package/dist/src/ingestion/indexer.js +36 -2
- package/dist/src/ingestion/indexer.js.map +1 -1
- package/dist/src/ingestion/metadata-extraction.d.ts +8 -5
- package/dist/src/ingestion/metadata-extraction.d.ts.map +1 -1
- package/dist/src/ingestion/metadata-extraction.js +24 -5
- package/dist/src/ingestion/metadata-extraction.js.map +1 -1
- package/dist/src/ingestion/skip-quarantine.d.ts +10 -0
- package/dist/src/ingestion/skip-quarantine.d.ts.map +1 -0
- package/dist/src/ingestion/skip-quarantine.js +35 -0
- package/dist/src/ingestion/skip-quarantine.js.map +1 -0
- package/dist/src/jobs/handlers/compact.d.ts.map +1 -1
- package/dist/src/jobs/handlers/compact.js +30 -4
- package/dist/src/jobs/handlers/compact.js.map +1 -1
- package/dist/src/jobs/handlers/dedupe-conversations.d.ts +134 -0
- package/dist/src/jobs/handlers/dedupe-conversations.d.ts.map +1 -0
- package/dist/src/jobs/handlers/dedupe-conversations.js +371 -0
- package/dist/src/jobs/handlers/dedupe-conversations.js.map +1 -0
- package/dist/src/jobs/handlers/ingest.d.ts.map +1 -1
- package/dist/src/jobs/handlers/ingest.js +295 -41
- package/dist/src/jobs/handlers/ingest.js.map +1 -1
- package/dist/src/jobs/handlers/reconcile.d.ts +28 -0
- package/dist/src/jobs/handlers/reconcile.d.ts.map +1 -1
- package/dist/src/jobs/handlers/reconcile.js +145 -19
- package/dist/src/jobs/handlers/reconcile.js.map +1 -1
- package/dist/src/jobs/handlers/reindex.d.ts.map +1 -1
- package/dist/src/jobs/handlers/reindex.js +13 -2
- package/dist/src/jobs/handlers/reindex.js.map +1 -1
- package/dist/src/jobs/handlers/save.d.ts.map +1 -1
- package/dist/src/jobs/handlers/save.js +57 -3
- package/dist/src/jobs/handlers/save.js.map +1 -1
- package/dist/src/jobs/queue.d.ts +51 -1
- package/dist/src/jobs/queue.d.ts.map +1 -1
- package/dist/src/jobs/queue.js +466 -26
- package/dist/src/jobs/queue.js.map +1 -1
- package/dist/src/jobs/worker-entry.d.ts.map +1 -1
- package/dist/src/jobs/worker-entry.js +35 -7
- package/dist/src/jobs/worker-entry.js.map +1 -1
- package/dist/src/jobs/worker-process.d.ts +11 -0
- package/dist/src/jobs/worker-process.d.ts.map +1 -1
- package/dist/src/jobs/worker-process.js +37 -4
- package/dist/src/jobs/worker-process.js.map +1 -1
- package/dist/src/main.js +199 -46
- package/dist/src/main.js.map +1 -1
- package/dist/src/mcp/errors.d.ts.map +1 -1
- package/dist/src/mcp/errors.js +20 -1
- package/dist/src/mcp/errors.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +43 -3
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/context-pack.d.ts.map +1 -1
- package/dist/src/mcp/tools/context-pack.js +164 -23
- package/dist/src/mcp/tools/context-pack.js.map +1 -1
- package/dist/src/mcp/tools/search.d.ts +6 -2
- package/dist/src/mcp/tools/search.d.ts.map +1 -1
- package/dist/src/mcp/tools/search.js +35 -4
- package/dist/src/mcp/tools/search.js.map +1 -1
- package/dist/src/observability/embedding-events.d.ts +52 -0
- package/dist/src/observability/embedding-events.d.ts.map +1 -0
- package/dist/src/observability/embedding-events.js +149 -0
- package/dist/src/observability/embedding-events.js.map +1 -0
- package/dist/src/observability/index-events.d.ts +70 -0
- package/dist/src/observability/index-events.d.ts.map +1 -0
- package/dist/src/observability/index-events.js +148 -0
- package/dist/src/observability/index-events.js.map +1 -0
- package/dist/src/observability/onboarding-metric.d.ts +131 -0
- package/dist/src/observability/onboarding-metric.d.ts.map +1 -0
- package/dist/src/observability/onboarding-metric.js +351 -0
- package/dist/src/observability/onboarding-metric.js.map +1 -0
- package/dist/src/observability/tool-usage-stats.d.ts +77 -4
- package/dist/src/observability/tool-usage-stats.d.ts.map +1 -1
- package/dist/src/observability/tool-usage-stats.js +112 -32
- package/dist/src/observability/tool-usage-stats.js.map +1 -1
- package/dist/src/observability/tool-usage.d.ts +100 -7
- package/dist/src/observability/tool-usage.d.ts.map +1 -1
- package/dist/src/observability/tool-usage.js +196 -33
- package/dist/src/observability/tool-usage.js.map +1 -1
- package/dist/src/observability/version-check.d.ts +71 -0
- package/dist/src/observability/version-check.d.ts.map +1 -0
- package/dist/src/observability/version-check.js +198 -0
- package/dist/src/observability/version-check.js.map +1 -0
- package/dist/src/providers/basic-metadata-extraction.d.ts +60 -0
- package/dist/src/providers/basic-metadata-extraction.d.ts.map +1 -0
- package/dist/src/providers/basic-metadata-extraction.js +114 -0
- package/dist/src/providers/basic-metadata-extraction.js.map +1 -0
- package/dist/src/providers/codex-cli-metadata-extraction.d.ts +1 -0
- package/dist/src/providers/codex-cli-metadata-extraction.d.ts.map +1 -1
- package/dist/src/providers/codex-cli-metadata-extraction.js +6 -2
- package/dist/src/providers/codex-cli-metadata-extraction.js.map +1 -1
- package/dist/src/providers/codex-cli-model.d.ts +61 -0
- package/dist/src/providers/codex-cli-model.d.ts.map +1 -0
- package/dist/src/providers/codex-cli-model.js +194 -0
- package/dist/src/providers/codex-cli-model.js.map +1 -0
- package/dist/src/providers/codex-cli-runner.d.ts +39 -0
- package/dist/src/providers/codex-cli-runner.d.ts.map +1 -1
- package/dist/src/providers/codex-cli-runner.js +234 -48
- package/dist/src/providers/codex-cli-runner.js.map +1 -1
- package/dist/src/providers/conversation-generation.d.ts.map +1 -1
- package/dist/src/providers/conversation-generation.js +43 -6
- package/dist/src/providers/conversation-generation.js.map +1 -1
- package/dist/src/providers/ollama-embed.d.ts +2 -1
- package/dist/src/providers/ollama-embed.d.ts.map +1 -1
- package/dist/src/providers/ollama-embed.js +1 -0
- package/dist/src/providers/ollama-embed.js.map +1 -1
- package/dist/src/providers/openai-metadata-extraction.d.ts +3 -3
- package/dist/src/providers/openai-metadata-extraction.d.ts.map +1 -1
- package/dist/src/providers/openai-metadata-extraction.js +18 -3
- package/dist/src/providers/openai-metadata-extraction.js.map +1 -1
- package/dist/src/providers/placeholder-embed.d.ts +56 -0
- package/dist/src/providers/placeholder-embed.d.ts.map +1 -0
- package/dist/src/providers/placeholder-embed.js +64 -0
- package/dist/src/providers/placeholder-embed.js.map +1 -0
- package/dist/src/providers/stub.d.ts +2 -0
- package/dist/src/providers/stub.d.ts.map +1 -1
- package/dist/src/providers/stub.js +2 -0
- package/dist/src/providers/stub.js.map +1 -1
- package/dist/src/providers/types.d.ts +11 -0
- package/dist/src/providers/types.d.ts.map +1 -1
- package/dist/src/providers/voyage.d.ts +2 -1
- package/dist/src/providers/voyage.d.ts.map +1 -1
- package/dist/src/providers/voyage.js +1 -0
- package/dist/src/providers/voyage.js.map +1 -1
- package/dist/src/retrieval/compact.d.ts +116 -2
- package/dist/src/retrieval/compact.d.ts.map +1 -1
- package/dist/src/retrieval/compact.js +158 -5
- package/dist/src/retrieval/compact.js.map +1 -1
- package/dist/src/retrieval/context-pack.d.ts +114 -0
- package/dist/src/retrieval/context-pack.d.ts.map +1 -1
- package/dist/src/retrieval/context-pack.js +292 -8
- package/dist/src/retrieval/context-pack.js.map +1 -1
- package/dist/src/retrieval/current-truth.d.ts +360 -0
- package/dist/src/retrieval/current-truth.d.ts.map +1 -0
- package/dist/src/retrieval/current-truth.js +766 -0
- package/dist/src/retrieval/current-truth.js.map +1 -0
- package/dist/src/retrieval/git-state.d.ts +53 -0
- package/dist/src/retrieval/git-state.d.ts.map +1 -0
- package/dist/src/retrieval/git-state.js +174 -0
- package/dist/src/retrieval/git-state.js.map +1 -0
- package/dist/src/retrieval/lexical.d.ts.map +1 -1
- package/dist/src/retrieval/lexical.js +19 -3
- package/dist/src/retrieval/lexical.js.map +1 -1
- package/dist/src/retrieval/locator-boost.d.ts +37 -0
- package/dist/src/retrieval/locator-boost.d.ts.map +1 -0
- package/dist/src/retrieval/locator-boost.js +129 -0
- package/dist/src/retrieval/locator-boost.js.map +1 -0
- package/dist/src/retrieval/report-demotion.d.ts +46 -0
- package/dist/src/retrieval/report-demotion.d.ts.map +1 -0
- package/dist/src/retrieval/report-demotion.js +169 -0
- package/dist/src/retrieval/report-demotion.js.map +1 -0
- package/dist/src/retrieval/vector.d.ts.map +1 -1
- package/dist/src/retrieval/vector.js +11 -2
- package/dist/src/retrieval/vector.js.map +1 -1
- package/dist/src/server/app.d.ts.map +1 -1
- package/dist/src/server/app.js +92 -11
- package/dist/src/server/app.js.map +1 -1
- package/dist/src/server/routes/compact.d.ts.map +1 -1
- package/dist/src/server/routes/compact.js +4 -1
- package/dist/src/server/routes/compact.js.map +1 -1
- package/dist/src/server/routes/context.d.ts +1 -1
- package/dist/src/server/routes/context.d.ts.map +1 -1
- package/dist/src/server/routes/context.js +2 -1
- package/dist/src/server/routes/context.js.map +1 -1
- package/dist/src/server/routes/conversations-search.d.ts.map +1 -1
- package/dist/src/server/routes/conversations-search.js +28 -3
- package/dist/src/server/routes/conversations-search.js.map +1 -1
- package/dist/src/server/routes/enqueue.d.ts +11 -0
- package/dist/src/server/routes/enqueue.d.ts.map +1 -0
- package/dist/src/server/routes/enqueue.js +17 -0
- package/dist/src/server/routes/enqueue.js.map +1 -0
- package/dist/src/server/routes/friend-status.d.ts +339 -3
- package/dist/src/server/routes/friend-status.d.ts.map +1 -1
- package/dist/src/server/routes/friend-status.js +447 -13
- package/dist/src/server/routes/friend-status.js.map +1 -1
- package/dist/src/server/routes/ingest.d.ts.map +1 -1
- package/dist/src/server/routes/ingest.js +5 -2
- package/dist/src/server/routes/ingest.js.map +1 -1
- package/dist/src/server/routes/mcp-usage.d.ts +5 -4
- package/dist/src/server/routes/mcp-usage.d.ts.map +1 -1
- package/dist/src/server/routes/mcp-usage.js.map +1 -1
- package/dist/src/server/routes/reconcile.d.ts.map +1 -1
- package/dist/src/server/routes/reconcile.js +20 -1
- package/dist/src/server/routes/reconcile.js.map +1 -1
- package/dist/src/server/routes/reindex.d.ts.map +1 -1
- package/dist/src/server/routes/reindex.js +4 -1
- package/dist/src/server/routes/reindex.js.map +1 -1
- package/dist/src/server/routes/save.d.ts.map +1 -1
- package/dist/src/server/routes/save.js +4 -1
- package/dist/src/server/routes/save.js.map +1 -1
- package/dist/src/server/routes/search.d.ts +1 -1
- package/dist/src/server/routes/search.d.ts.map +1 -1
- package/dist/src/server/routes/search.js +253 -29
- package/dist/src/server/routes/search.js.map +1 -1
- package/dist/src/server/routes/triage.d.ts.map +1 -1
- package/dist/src/server/routes/triage.js +4 -1
- package/dist/src/server/routes/triage.js.map +1 -1
- package/dist/src/storage/rebuild.d.ts +35 -1
- package/dist/src/storage/rebuild.d.ts.map +1 -1
- package/dist/src/storage/rebuild.js +288 -64
- package/dist/src/storage/rebuild.js.map +1 -1
- package/dist/src/storage/tables.d.ts +29 -0
- package/dist/src/storage/tables.d.ts.map +1 -1
- package/dist/src/storage/tables.js +32 -1
- package/dist/src/storage/tables.js.map +1 -1
- package/operator/swiftbar/render-menu.py +524 -0
- package/operator/swiftbar/rift.10s.sh +176 -0
- package/package.json +9 -3
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import { toJobStatusView } from "../../jobs/types.js";
|
|
13
|
+
import { enqueueJob } from "./enqueue.js";
|
|
13
14
|
import { HISTORICAL_BACKFILL_CAPABILITY_HEADER, HISTORICAL_BACKFILL_OVERRIDE_HEADER, INTERNAL_HISTORICAL_TRIAGE_CODEX_ROUTE, CODEX_CLI_OVERRIDE_PROVIDER, hasHistoricalBackfillCapability, isHistoricalTriageIdempotencyKey, } from "../../providers/operator-overrides.js";
|
|
14
15
|
const TriageItemSchema = z
|
|
15
16
|
.object({
|
|
@@ -75,7 +76,9 @@ export function registerTriageRoute(server, queue, dataDir) {
|
|
|
75
76
|
if (parsed.data.idempotency_key !== undefined) {
|
|
76
77
|
opts.idempotency_key = parsed.data.idempotency_key;
|
|
77
78
|
}
|
|
78
|
-
const result = await queue
|
|
79
|
+
const result = await enqueueJob(reply, queue, "triage", opts);
|
|
80
|
+
if (!result)
|
|
81
|
+
return;
|
|
79
82
|
if ("conflict" in result) {
|
|
80
83
|
return reply.code(409).send({ error: "conflict" });
|
|
81
84
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triage.js","sourceRoot":"","sources":["../../../../src/server/routes/triage.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"triage.js","sourceRoot":"","sources":["../../../../src/server/routes/triage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { Config } from "../config/schema.js";
|
|
2
2
|
import type { EmbeddingProvider } from "../providers/types.js";
|
|
3
3
|
import type { TableName } from "./tables.js";
|
|
4
|
+
/**
|
|
5
|
+
* Shared duplicate-resolution policy for conversation raw files.
|
|
6
|
+
*
|
|
7
|
+
* Both repair paths — reconcile and full rebuild — must pick the SAME winner
|
|
8
|
+
* when several raw files compete for one row id or idempotency_key, otherwise
|
|
9
|
+
* the canonical conversation row could flip depending on which tool last ran,
|
|
10
|
+
* which is corrosive to trust and debugging. Policy: most-recent raw wins,
|
|
11
|
+
* ordered by filename (`<timestamp>_<id>.json`, ISO-8601-derived → lexicographic
|
|
12
|
+
* == chronological). Compare basenames so the ordering is stable regardless of
|
|
13
|
+
* which source folder a file lives in. Sorts most-recent FIRST (descending).
|
|
14
|
+
*/
|
|
15
|
+
export declare function compareRawRecencyDesc(aPath: string, bPath: string): number;
|
|
4
16
|
export interface RebuildDeps {
|
|
5
17
|
config: Config;
|
|
6
18
|
embeddingProvider: EmbeddingProvider;
|
|
@@ -11,6 +23,15 @@ export interface RebuildDeps {
|
|
|
11
23
|
export interface RebuildReport {
|
|
12
24
|
tables_rebuilt: TableName[];
|
|
13
25
|
rows_reindexed: number;
|
|
26
|
+
/**
|
|
27
|
+
* Conversation raw files skipped because a row with the same non-empty
|
|
28
|
+
* `idempotency_key` was already inserted into the rebuilt index under a
|
|
29
|
+
* different row id. Mirrors reconcile's `missing_skipped_duplicate_key`:
|
|
30
|
+
* without it, an orphan raw left on disk (e.g. one reconcile already
|
|
31
|
+
* skipped) would resurface as a duplicate every time the index is rebuilt
|
|
32
|
+
* from raw — rebuild groups by row id and would otherwise miss the dup.
|
|
33
|
+
*/
|
|
34
|
+
conversations_skipped_duplicate_key: number;
|
|
14
35
|
}
|
|
15
36
|
/**
|
|
16
37
|
* Full rebuild from raw disk state via shadow-table swap.
|
|
@@ -26,7 +47,20 @@ export interface ReembedOptions {
|
|
|
26
47
|
config?: Config;
|
|
27
48
|
localEmbeddingProvider?: EmbeddingProvider;
|
|
28
49
|
}
|
|
29
|
-
export declare function reembed(embeddingProvider: EmbeddingProvider, scope: ReindexScope, config?: Config, localEmbeddingProvider?: EmbeddingProvider): Promise<number>;
|
|
50
|
+
export declare function reembed(embeddingProvider: EmbeddingProvider, scope: ReindexScope, dataDir: string, config?: Config, localEmbeddingProvider?: EmbeddingProvider): Promise<number>;
|
|
51
|
+
/**
|
|
52
|
+
* Remove structured-doc rows whose source file no longer exists on disk.
|
|
53
|
+
* Scoped to filesystem-sourced rows (watched + scheduled_scan).
|
|
54
|
+
*
|
|
55
|
+
* Why: deletions between scheduled scans (or while a watcher is offline)
|
|
56
|
+
* leave ghost rows in the index, so search can return content that no
|
|
57
|
+
* longer exists. This pass closes that gap.
|
|
58
|
+
*
|
|
59
|
+
* Safety: skips rows whose owning source root is unreachable, so an
|
|
60
|
+
* unmounted drive cannot trigger mass deletion. If `config` is omitted
|
|
61
|
+
* the function still runs, but without the unmounted-root guard.
|
|
62
|
+
*/
|
|
63
|
+
export declare function removeStructuredDocOrphans(dataDir: string, config?: Config): Promise<number>;
|
|
30
64
|
export declare function extractIdFromFilename(filename: string): string | undefined;
|
|
31
65
|
/**
|
|
32
66
|
* Extract the ISO timestamp from a raw conversation filename.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rebuild.d.ts","sourceRoot":"","sources":["../../../src/storage/rebuild.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"rebuild.d.ts","sourceRoot":"","sources":["../../../src/storage/rebuild.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAW/D,OAAO,KAAK,EAIV,SAAS,EACV,MAAM,aAAa,CAAC;AAWrB;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,sBAAsB,CAAC,EAAE,iBAAiB,CAAC;CAC5C;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,SAAS,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;;OAOG;IACH,mCAAmC,EAAE,MAAM,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAgD3E;AA2TD,MAAM,MAAM,YAAY,GACpB,KAAK,GACL,eAAe,GACf,WAAW,GACX,iBAAiB,CAAC;AAEtB,MAAM,WAAW,cAAc;IAC7B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,YAAY,CAAC;IACpB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,iBAAiB,CAAC;CAC5C;AAED,wBAAsB,OAAO,CAC3B,iBAAiB,EAAE,iBAAiB,EACpC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,sBAAsB,CAAC,EAAE,iBAAiB,GACzC,OAAO,CAAC,MAAM,CAAC,CA2CjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAoDjB;AAyPD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,GACf,IAAI,GAAG,SAAS,CAclB"}
|
|
@@ -9,12 +9,30 @@
|
|
|
9
9
|
import fs from "node:fs";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { CONVERSATION_SOURCES } from "../providers/types.js";
|
|
12
|
+
import { RIFT_NONE_EMBEDDING_PROVIDER, isPlaceholderEmbeddingProvider, } from "../providers/placeholder-embed.js";
|
|
12
13
|
import { walkDirectory } from "../ingestion/scanner.js";
|
|
13
14
|
import { isSupported } from "../ingestion/extractor.js";
|
|
14
15
|
import { buildIgnoredPaths } from "../ingestion/ignored-paths.js";
|
|
15
16
|
import { fileId } from "../ingestion/indexer.js";
|
|
17
|
+
import { conversationContentFingerprint } from "../ingestion/inbox-core/conversation-fingerprint.js";
|
|
16
18
|
import { createShadowSwap } from "./shadow-swap.js";
|
|
19
|
+
import { recordEmbed } from "../observability/embedding-events.js";
|
|
20
|
+
import { appendIndexEvent, recordIndexWrite, } from "../observability/index-events.js";
|
|
17
21
|
const ALL_CONV_SOURCES = [...CONVERSATION_SOURCES, "inbox"];
|
|
22
|
+
/**
|
|
23
|
+
* Shared duplicate-resolution policy for conversation raw files.
|
|
24
|
+
*
|
|
25
|
+
* Both repair paths — reconcile and full rebuild — must pick the SAME winner
|
|
26
|
+
* when several raw files compete for one row id or idempotency_key, otherwise
|
|
27
|
+
* the canonical conversation row could flip depending on which tool last ran,
|
|
28
|
+
* which is corrosive to trust and debugging. Policy: most-recent raw wins,
|
|
29
|
+
* ordered by filename (`<timestamp>_<id>.json`, ISO-8601-derived → lexicographic
|
|
30
|
+
* == chronological). Compare basenames so the ordering is stable regardless of
|
|
31
|
+
* which source folder a file lives in. Sorts most-recent FIRST (descending).
|
|
32
|
+
*/
|
|
33
|
+
export function compareRawRecencyDesc(aPath, bPath) {
|
|
34
|
+
return path.basename(bPath).localeCompare(path.basename(aPath));
|
|
35
|
+
}
|
|
18
36
|
/**
|
|
19
37
|
* Full rebuild from raw disk state via shadow-table swap.
|
|
20
38
|
* Creates shadow tables for all four tables, populates them from
|
|
@@ -22,19 +40,45 @@ const ALL_CONV_SOURCES = [...CONVERSATION_SOURCES, "inbox"];
|
|
|
22
40
|
*/
|
|
23
41
|
export async function fullRebuild(deps) {
|
|
24
42
|
const swap = createShadowSwap(deps.dataDir);
|
|
25
|
-
const report = {
|
|
43
|
+
const report = {
|
|
44
|
+
tables_rebuilt: [],
|
|
45
|
+
rows_reindexed: 0,
|
|
46
|
+
conversations_skipped_duplicate_key: 0,
|
|
47
|
+
};
|
|
26
48
|
const swaps = new Map();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
49
|
+
// Per-table populate counts. Used to emit one post-commit "live"
|
|
50
|
+
// index-event per table so `index.last_update_at` is only credited
|
|
51
|
+
// after the swap actually installs the shadows. If `commitAllSwaps`
|
|
52
|
+
// throws, we never emit the live events and the lane correctly
|
|
53
|
+
// shows shadow-only successes (which `computeIndexHealth` ignores).
|
|
54
|
+
const populated = new Map();
|
|
55
|
+
await populateStructuredDocsShadows(deps, swap, swaps, populated, report);
|
|
56
|
+
await populateConversationShadows(deps, swap, swaps, populated, report);
|
|
57
|
+
await populateDigestShadow(deps, swap, swaps, populated, report);
|
|
30
58
|
await swap.commitAllSwaps(swaps);
|
|
59
|
+
// Post-commit: credit the lane with one "live" event per swapped
|
|
60
|
+
// table. The shadow events stay in the lane for debugging but do
|
|
61
|
+
// not bump `last_update_at` (see computeIndexHealth).
|
|
62
|
+
const commitTs = new Date().toISOString();
|
|
63
|
+
for (const [tableName, rowCount] of populated) {
|
|
64
|
+
appendIndexEvent(deps.dataDir, {
|
|
65
|
+
ts: commitTs,
|
|
66
|
+
table: tableName,
|
|
67
|
+
pipeline: "backfill",
|
|
68
|
+
operation: "shadow_swap_commit",
|
|
69
|
+
outcome: "success",
|
|
70
|
+
row_count: rowCount,
|
|
71
|
+
ms: 0,
|
|
72
|
+
phase: "live",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
31
75
|
report.tables_rebuilt.push("structured_docs", "structured_docs_local", "conversations_hot", "conversations_cold", "digests");
|
|
32
76
|
return report;
|
|
33
77
|
}
|
|
34
78
|
// ---------------------------------------------------------------------------
|
|
35
79
|
// Populate shadow tables from raw state
|
|
36
80
|
// ---------------------------------------------------------------------------
|
|
37
|
-
async function populateStructuredDocsShadows(deps, swap, swaps, report) {
|
|
81
|
+
async function populateStructuredDocsShadows(deps, swap, swaps, populated, report) {
|
|
38
82
|
const cloudShadow = await swap.createShadow("structured_docs");
|
|
39
83
|
const localShadow = await swap.createShadow("structured_docs_local");
|
|
40
84
|
swaps.set("structured_docs", cloudShadow);
|
|
@@ -75,7 +119,11 @@ async function populateStructuredDocsShadows(deps, swap, swaps, report) {
|
|
|
75
119
|
const targetShadow = isLocal ? localShadow : cloudShadow;
|
|
76
120
|
try {
|
|
77
121
|
const content = fs.readFileSync(canonical, "utf-8");
|
|
78
|
-
const embedding = await provider
|
|
122
|
+
const embedding = await recordEmbed(deps.dataDir, provider, {
|
|
123
|
+
pipeline: "backfill",
|
|
124
|
+
operation: "structured_doc_embedding",
|
|
125
|
+
input_count: 1,
|
|
126
|
+
}, () => provider.embed(content));
|
|
79
127
|
const row = {
|
|
80
128
|
id,
|
|
81
129
|
source_path: canonical,
|
|
@@ -89,7 +137,17 @@ async function populateStructuredDocsShadows(deps, swap, swaps, report) {
|
|
|
89
137
|
indexed_at: new Date().toISOString(),
|
|
90
138
|
metadata: "{}",
|
|
91
139
|
};
|
|
92
|
-
|
|
140
|
+
const targetTableName = isLocal
|
|
141
|
+
? "structured_docs_local"
|
|
142
|
+
: "structured_docs";
|
|
143
|
+
await recordIndexWrite(deps.dataDir, {
|
|
144
|
+
table: targetTableName,
|
|
145
|
+
pipeline: "backfill",
|
|
146
|
+
operation: "structured_doc_upsert",
|
|
147
|
+
row_count: 1,
|
|
148
|
+
phase: "shadow",
|
|
149
|
+
}, () => targetShadow.add([row]));
|
|
150
|
+
populated.set(targetTableName, (populated.get(targetTableName) ?? 0) + 1);
|
|
93
151
|
report.rows_reindexed++;
|
|
94
152
|
}
|
|
95
153
|
catch (err) {
|
|
@@ -98,60 +156,112 @@ async function populateStructuredDocsShadows(deps, swap, swaps, report) {
|
|
|
98
156
|
}
|
|
99
157
|
}
|
|
100
158
|
}
|
|
101
|
-
async function populateConversationShadows(deps, swap, swaps, report) {
|
|
159
|
+
async function populateConversationShadows(deps, swap, swaps, populated, report) {
|
|
102
160
|
const hotShadow = await swap.createShadow("conversations_hot");
|
|
103
161
|
const coldShadow = await swap.createShadow("conversations_cold");
|
|
104
162
|
swaps.set("conversations_hot", hotShadow);
|
|
105
163
|
swaps.set("conversations_cold", coldShadow);
|
|
106
164
|
const cutoff = new Date();
|
|
107
165
|
cutoff.setDate(cutoff.getDate() - (deps.config.compaction.age_threshold_days ?? 30));
|
|
166
|
+
// Durable dedup across the whole rebuild: a non-empty idempotency_key may
|
|
167
|
+
// only be inserted once. Mirrors reconcile's key-skip so a raw file that
|
|
168
|
+
// reconcile already declined to revive cannot reappear as a duplicate here.
|
|
169
|
+
const seenKeys = new Set();
|
|
170
|
+
// Group raw files by stable row id ACROSS ALL SOURCES first. Refresh-on-grow
|
|
171
|
+
// may leave more than one raw artifact for the same id on disk if pruning was
|
|
172
|
+
// interrupted; reinserting all of them duplicates the conversation. Keep only
|
|
173
|
+
// the most-recent raw per id (shared recency policy). Collecting globally —
|
|
174
|
+
// rather than per source folder — matters because `seenKeys` is global: if we
|
|
175
|
+
// sorted within each source folder, an older raw in an earlier folder could
|
|
176
|
+
// claim a key before a newer same-key raw in a later folder was ever seen.
|
|
177
|
+
const latestByRowId = new Map();
|
|
108
178
|
for (const source of ALL_CONV_SOURCES) {
|
|
109
179
|
const rawDir = path.join(deps.dataDir, "raw", "conversations", source);
|
|
110
180
|
if (!fs.existsSync(rawDir))
|
|
111
181
|
continue;
|
|
112
|
-
const
|
|
113
|
-
|
|
182
|
+
for (const file of fs.readdirSync(rawDir)) {
|
|
183
|
+
if (!file.endsWith(".json"))
|
|
184
|
+
continue;
|
|
114
185
|
const id = extractIdFromFilename(file);
|
|
115
186
|
if (!id)
|
|
116
187
|
continue;
|
|
117
188
|
const rawPath = path.join(rawDir, file);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const content = raw.content ?? summary;
|
|
122
|
-
const vec = await deps.embeddingProvider.embed(content || summary);
|
|
123
|
-
const row = {
|
|
124
|
-
id,
|
|
125
|
-
content,
|
|
126
|
-
summary,
|
|
127
|
-
embedding: vec,
|
|
128
|
-
source: raw.source ?? "claude_code",
|
|
129
|
-
domain: raw.domain ?? "tech",
|
|
130
|
-
intent: raw.intent ?? "build",
|
|
131
|
-
quality: raw.quality ?? "medium",
|
|
132
|
-
topics: JSON.stringify(raw.topics ?? []),
|
|
133
|
-
decisions: JSON.stringify(raw.decisions ?? []),
|
|
134
|
-
key_outputs: JSON.stringify(raw.key_outputs ?? []),
|
|
135
|
-
indexed_at: new Date().toISOString(),
|
|
136
|
-
idempotency_key: raw.idempotency_key ?? "",
|
|
137
|
-
};
|
|
138
|
-
const filenameTime = extractTimestampFromFilename(file);
|
|
139
|
-
const rowTime = filenameTime ?? fs.statSync(rawPath).mtime;
|
|
140
|
-
if (rowTime >= cutoff) {
|
|
141
|
-
await hotShadow.add([row]);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
await coldShadow.add([row]);
|
|
145
|
-
}
|
|
146
|
-
report.rows_reindexed++;
|
|
189
|
+
const prior = latestByRowId.get(id);
|
|
190
|
+
if (!prior || compareRawRecencyDesc(rawPath, prior) < 0) {
|
|
191
|
+
latestByRowId.set(id, rawPath);
|
|
147
192
|
}
|
|
148
|
-
|
|
149
|
-
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Process most-recent raw first (global order) so that when two row ids share
|
|
196
|
+
// one idempotency_key the newest wins and older duplicates are skipped —
|
|
197
|
+
// identical winner to reconcile via the shared recency comparator.
|
|
198
|
+
const ordered = [...latestByRowId.entries()].sort(([, a], [, b]) => compareRawRecencyDesc(a, b));
|
|
199
|
+
for (const [id, rawPath] of ordered) {
|
|
200
|
+
const file = path.basename(rawPath);
|
|
201
|
+
try {
|
|
202
|
+
const raw = JSON.parse(fs.readFileSync(rawPath, "utf-8"));
|
|
203
|
+
const key = typeof raw.idempotency_key === "string" ? raw.idempotency_key : "";
|
|
204
|
+
if (key && seenKeys.has(key)) {
|
|
205
|
+
report.conversations_skipped_duplicate_key++;
|
|
206
|
+
continue;
|
|
150
207
|
}
|
|
208
|
+
const summary = raw.summary ?? "";
|
|
209
|
+
const content = raw.content ?? summary;
|
|
210
|
+
const vec = await recordEmbed(deps.dataDir, deps.embeddingProvider, {
|
|
211
|
+
pipeline: "backfill",
|
|
212
|
+
operation: "conversation_embedding",
|
|
213
|
+
input_count: 1,
|
|
214
|
+
}, () => deps.embeddingProvider.embed(content || summary));
|
|
215
|
+
const fingerprint = typeof raw.conversation_fingerprint === "string" &&
|
|
216
|
+
raw.conversation_fingerprint.length > 0
|
|
217
|
+
? raw.conversation_fingerprint
|
|
218
|
+
: content
|
|
219
|
+
? conversationContentFingerprint(content)
|
|
220
|
+
: "";
|
|
221
|
+
const row = {
|
|
222
|
+
id,
|
|
223
|
+
content,
|
|
224
|
+
summary,
|
|
225
|
+
embedding: vec,
|
|
226
|
+
source: raw.source ?? "claude_code",
|
|
227
|
+
domain: raw.domain ?? "tech",
|
|
228
|
+
intent: raw.intent ?? "build",
|
|
229
|
+
quality: raw.quality ?? "medium",
|
|
230
|
+
topics: JSON.stringify(raw.topics ?? []),
|
|
231
|
+
decisions: JSON.stringify(raw.decisions ?? []),
|
|
232
|
+
key_outputs: JSON.stringify(raw.key_outputs ?? []),
|
|
233
|
+
indexed_at: new Date().toISOString(),
|
|
234
|
+
idempotency_key: raw.idempotency_key ?? "",
|
|
235
|
+
conversation_fingerprint: fingerprint,
|
|
236
|
+
// Metadata restored from raw → preserve its provider marker. Embedding
|
|
237
|
+
// recomputed here → marker reflects the provider that just ran.
|
|
238
|
+
metadata_provider: typeof raw.metadata_provider === "string" ? raw.metadata_provider : "",
|
|
239
|
+
embedding_provider: isPlaceholderEmbeddingProvider(deps.embeddingProvider)
|
|
240
|
+
? RIFT_NONE_EMBEDDING_PROVIDER
|
|
241
|
+
: "",
|
|
242
|
+
};
|
|
243
|
+
const filenameTime = extractTimestampFromFilename(file);
|
|
244
|
+
const rowTime = filenameTime ?? fs.statSync(rawPath).mtime;
|
|
245
|
+
const targetTable = rowTime >= cutoff ? "conversations_hot" : "conversations_cold";
|
|
246
|
+
const targetShadow = rowTime >= cutoff ? hotShadow : coldShadow;
|
|
247
|
+
await recordIndexWrite(deps.dataDir, {
|
|
248
|
+
table: targetTable,
|
|
249
|
+
pipeline: "backfill",
|
|
250
|
+
operation: "conversation_upsert",
|
|
251
|
+
row_count: 1,
|
|
252
|
+
phase: "shadow",
|
|
253
|
+
}, () => targetShadow.add([row]));
|
|
254
|
+
if (key)
|
|
255
|
+
seenKeys.add(key);
|
|
256
|
+
populated.set(targetTable, (populated.get(targetTable) ?? 0) + 1);
|
|
257
|
+
report.rows_reindexed++;
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
process.stderr.write(`rebuild: failed to index conversation ${id}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
151
261
|
}
|
|
152
262
|
}
|
|
153
263
|
}
|
|
154
|
-
async function populateDigestShadow(deps, swap, swaps, report) {
|
|
264
|
+
async function populateDigestShadow(deps, swap, swaps, populated, report) {
|
|
155
265
|
const shadow = await swap.createShadow("digests");
|
|
156
266
|
swaps.set("digests", shadow);
|
|
157
267
|
const digestDir = path.join(deps.dataDir, "raw", "digests");
|
|
@@ -164,7 +274,11 @@ async function populateDigestShadow(deps, swap, swaps, report) {
|
|
|
164
274
|
if (typeof raw.id !== "string" || !raw.id)
|
|
165
275
|
continue;
|
|
166
276
|
const summary = raw.summary ?? raw.content ?? "";
|
|
167
|
-
const vec = await deps.embeddingProvider
|
|
277
|
+
const vec = await recordEmbed(deps.dataDir, deps.embeddingProvider, {
|
|
278
|
+
pipeline: "backfill",
|
|
279
|
+
operation: "digest_embedding",
|
|
280
|
+
input_count: 1,
|
|
281
|
+
}, () => deps.embeddingProvider.embed(summary));
|
|
168
282
|
const row = {
|
|
169
283
|
id: raw.id,
|
|
170
284
|
content: raw.content ?? "",
|
|
@@ -175,7 +289,14 @@ async function populateDigestShadow(deps, swap, swaps, report) {
|
|
|
175
289
|
digest_type: raw.digest_type ?? "weekly",
|
|
176
290
|
created_at: raw.created_at ?? new Date().toISOString(),
|
|
177
291
|
};
|
|
178
|
-
await
|
|
292
|
+
await recordIndexWrite(deps.dataDir, {
|
|
293
|
+
table: "digests",
|
|
294
|
+
pipeline: "backfill",
|
|
295
|
+
operation: "digest_upsert",
|
|
296
|
+
row_count: 1,
|
|
297
|
+
phase: "shadow",
|
|
298
|
+
}, () => shadow.add([row]));
|
|
299
|
+
populated.set("digests", (populated.get("digests") ?? 0) + 1);
|
|
179
300
|
report.rows_reindexed++;
|
|
180
301
|
}
|
|
181
302
|
catch (err) {
|
|
@@ -184,27 +305,86 @@ async function populateDigestShadow(deps, swap, swaps, report) {
|
|
|
184
305
|
}
|
|
185
306
|
}
|
|
186
307
|
}
|
|
187
|
-
export async function reembed(embeddingProvider, scope, config, localEmbeddingProvider) {
|
|
308
|
+
export async function reembed(embeddingProvider, scope, dataDir, config, localEmbeddingProvider) {
|
|
188
309
|
let count = 0;
|
|
189
310
|
if (scope === "all" || scope === "structured_docs" || scope === "documents") {
|
|
190
|
-
count += await reembedStructuredDocs(embeddingProvider, config, localEmbeddingProvider);
|
|
311
|
+
count += await reembedStructuredDocs(embeddingProvider, dataDir, config, localEmbeddingProvider);
|
|
191
312
|
if (localEmbeddingProvider) {
|
|
192
|
-
count += await reembedLocalStructuredDocs(localEmbeddingProvider);
|
|
313
|
+
count += await reembedLocalStructuredDocs(localEmbeddingProvider, dataDir);
|
|
193
314
|
}
|
|
194
315
|
}
|
|
195
316
|
if (scope === "all" || scope === "conversations") {
|
|
196
|
-
count += await reembedTable("conversations_hot", embeddingProvider, (r) => r.content || r.summary, "indexed_at");
|
|
197
|
-
count += await reembedTable("conversations_cold", embeddingProvider, (r) => r.content || r.summary, "indexed_at");
|
|
198
|
-
count += await reembedTable("digests", embeddingProvider, (r) => r.summary || r.content, "created_at");
|
|
317
|
+
count += await reembedTable("conversations_hot", embeddingProvider, dataDir, "conversation_embedding", (r) => r.content || r.summary, "indexed_at");
|
|
318
|
+
count += await reembedTable("conversations_cold", embeddingProvider, dataDir, "conversation_embedding", (r) => r.content || r.summary, "indexed_at");
|
|
319
|
+
count += await reembedTable("digests", embeddingProvider, dataDir, "digest_embedding", (r) => r.summary || r.content, "created_at");
|
|
199
320
|
}
|
|
200
321
|
return count;
|
|
201
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Remove structured-doc rows whose source file no longer exists on disk.
|
|
325
|
+
* Scoped to filesystem-sourced rows (watched + scheduled_scan).
|
|
326
|
+
*
|
|
327
|
+
* Why: deletions between scheduled scans (or while a watcher is offline)
|
|
328
|
+
* leave ghost rows in the index, so search can return content that no
|
|
329
|
+
* longer exists. This pass closes that gap.
|
|
330
|
+
*
|
|
331
|
+
* Safety: skips rows whose owning source root is unreachable, so an
|
|
332
|
+
* unmounted drive cannot trigger mass deletion. If `config` is omitted
|
|
333
|
+
* the function still runs, but without the unmounted-root guard.
|
|
334
|
+
*/
|
|
335
|
+
export async function removeStructuredDocOrphans(dataDir, config) {
|
|
336
|
+
const { getTable } = await import("./tables.js");
|
|
337
|
+
const tableNames = ["structured_docs", "structured_docs_local"];
|
|
338
|
+
let removed = 0;
|
|
339
|
+
for (const tableName of tableNames) {
|
|
340
|
+
let table;
|
|
341
|
+
try {
|
|
342
|
+
table = getTable(tableName);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
const rows = (await table.query().toArray());
|
|
348
|
+
const rootReachable = new Map();
|
|
349
|
+
const isReachable = (root) => {
|
|
350
|
+
const cached = rootReachable.get(root);
|
|
351
|
+
if (cached !== undefined)
|
|
352
|
+
return cached;
|
|
353
|
+
const ok = fs.existsSync(root);
|
|
354
|
+
rootReachable.set(root, ok);
|
|
355
|
+
return ok;
|
|
356
|
+
};
|
|
357
|
+
for (const row of rows) {
|
|
358
|
+
if (row.source_type !== "filesystem_watched" &&
|
|
359
|
+
row.source_type !== "filesystem_scheduled_scan")
|
|
360
|
+
continue;
|
|
361
|
+
if (config) {
|
|
362
|
+
const owner = findOwningSource(row.source_path, config);
|
|
363
|
+
if (!owner)
|
|
364
|
+
continue;
|
|
365
|
+
if (!isReachable(owner.path))
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (fs.existsSync(row.source_path))
|
|
369
|
+
continue;
|
|
370
|
+
try {
|
|
371
|
+
await table.delete(`id = '${row.id}'`);
|
|
372
|
+
removed++;
|
|
373
|
+
process.stderr.write(`reindex: removed orphan ${tableName} row ${row.id} (source missing: ${row.source_path})\n`);
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
process.stderr.write(`reindex: failed to remove orphan ${row.id} in ${tableName}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return removed;
|
|
381
|
+
}
|
|
202
382
|
/**
|
|
203
383
|
* Re-embed structured_docs with per-source provider routing.
|
|
204
384
|
* Rows whose source_path falls under a local-extraction source use
|
|
205
385
|
* localEmbeddingProvider; everything else uses the cloud provider.
|
|
206
386
|
*/
|
|
207
|
-
async function reembedStructuredDocs(cloudProvider, config, localProvider) {
|
|
387
|
+
async function reembedStructuredDocs(cloudProvider, dataDir, config, localProvider) {
|
|
208
388
|
const { getTable } = await import("./tables.js");
|
|
209
389
|
const table = getTable("structured_docs");
|
|
210
390
|
const allRows = (await table.query().toArray());
|
|
@@ -212,10 +392,21 @@ async function reembedStructuredDocs(cloudProvider, config, localProvider) {
|
|
|
212
392
|
for (const row of allRows) {
|
|
213
393
|
try {
|
|
214
394
|
const provider = resolveProviderForPath(row.source_path, cloudProvider, config, localProvider);
|
|
215
|
-
const newEmbedding = await provider
|
|
395
|
+
const newEmbedding = await recordEmbed(dataDir, provider, {
|
|
396
|
+
pipeline: "reindex",
|
|
397
|
+
operation: "structured_doc_embedding",
|
|
398
|
+
input_count: 1,
|
|
399
|
+
}, () => provider.embed(row.content));
|
|
216
400
|
const oldTimestamp = row.indexed_at;
|
|
217
401
|
const newTimestamp = new Date().toISOString();
|
|
218
|
-
await
|
|
402
|
+
await recordIndexWrite(dataDir, {
|
|
403
|
+
table: "structured_docs",
|
|
404
|
+
pipeline: "reindex",
|
|
405
|
+
operation: "structured_doc_upsert",
|
|
406
|
+
row_count: 1,
|
|
407
|
+
}, () => table.add([
|
|
408
|
+
{ ...row, embedding: newEmbedding, indexed_at: newTimestamp },
|
|
409
|
+
]));
|
|
219
410
|
try {
|
|
220
411
|
await table.delete(`id = '${row.id}' AND indexed_at = '${oldTimestamp}'`);
|
|
221
412
|
count++;
|
|
@@ -224,7 +415,9 @@ async function reembedStructuredDocs(cloudProvider, config, localProvider) {
|
|
|
224
415
|
try {
|
|
225
416
|
await table.delete(`id = '${row.id}' AND indexed_at = '${newTimestamp}'`);
|
|
226
417
|
}
|
|
227
|
-
catch {
|
|
418
|
+
catch {
|
|
419
|
+
/* duplicate remains — reconcile will repair */
|
|
420
|
+
}
|
|
228
421
|
}
|
|
229
422
|
}
|
|
230
423
|
catch (err) {
|
|
@@ -237,17 +430,28 @@ async function reembedStructuredDocs(cloudProvider, config, localProvider) {
|
|
|
237
430
|
* Re-embed all rows in structured_docs_local using the local provider.
|
|
238
431
|
* Simpler than the cloud path: all rows use the same provider.
|
|
239
432
|
*/
|
|
240
|
-
async function reembedLocalStructuredDocs(localProvider) {
|
|
433
|
+
async function reembedLocalStructuredDocs(localProvider, dataDir) {
|
|
241
434
|
const { getTable } = await import("./tables.js");
|
|
242
435
|
const table = getTable("structured_docs_local");
|
|
243
436
|
const allRows = (await table.query().toArray());
|
|
244
437
|
let count = 0;
|
|
245
438
|
for (const row of allRows) {
|
|
246
439
|
try {
|
|
247
|
-
const newEmbedding = await localProvider
|
|
440
|
+
const newEmbedding = await recordEmbed(dataDir, localProvider, {
|
|
441
|
+
pipeline: "reindex",
|
|
442
|
+
operation: "structured_doc_local_embedding",
|
|
443
|
+
input_count: 1,
|
|
444
|
+
}, () => localProvider.embed(row.content));
|
|
248
445
|
const oldTimestamp = row.indexed_at;
|
|
249
446
|
const newTimestamp = new Date().toISOString();
|
|
250
|
-
await
|
|
447
|
+
await recordIndexWrite(dataDir, {
|
|
448
|
+
table: "structured_docs_local",
|
|
449
|
+
pipeline: "reindex",
|
|
450
|
+
operation: "structured_doc_local_upsert",
|
|
451
|
+
row_count: 1,
|
|
452
|
+
}, () => table.add([
|
|
453
|
+
{ ...row, embedding: newEmbedding, indexed_at: newTimestamp },
|
|
454
|
+
]));
|
|
251
455
|
try {
|
|
252
456
|
await table.delete(`id = '${row.id}' AND indexed_at = '${oldTimestamp}'`);
|
|
253
457
|
count++;
|
|
@@ -256,7 +460,9 @@ async function reembedLocalStructuredDocs(localProvider) {
|
|
|
256
460
|
try {
|
|
257
461
|
await table.delete(`id = '${row.id}' AND indexed_at = '${newTimestamp}'`);
|
|
258
462
|
}
|
|
259
|
-
catch {
|
|
463
|
+
catch {
|
|
464
|
+
/* duplicate remains — reconcile will repair */
|
|
465
|
+
}
|
|
260
466
|
}
|
|
261
467
|
}
|
|
262
468
|
catch (err) {
|
|
@@ -278,22 +484,31 @@ function resolveProviderForPath(sourcePath, cloudProvider, config, localProvider
|
|
|
278
484
|
return localProvider;
|
|
279
485
|
return cloudProvider;
|
|
280
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* True when `file` is the same as `root` or lives beneath it. Uses
|
|
489
|
+
* `path.relative` so sibling paths that merely share a string prefix
|
|
490
|
+
* (e.g. `/docs/app-old` vs root `/docs/app`) are correctly rejected.
|
|
491
|
+
*/
|
|
492
|
+
function isPathWithin(file, root) {
|
|
493
|
+
const rel = path.relative(root, file);
|
|
494
|
+
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
|
495
|
+
}
|
|
281
496
|
/**
|
|
282
497
|
* Find the most-specific source root that owns a given file path.
|
|
283
|
-
* Longest
|
|
498
|
+
* Longest matching root wins, so nested roots are correctly attributed.
|
|
284
499
|
*/
|
|
285
500
|
function findOwningSource(filePath, config) {
|
|
286
501
|
let best;
|
|
287
502
|
let bestLen = 0;
|
|
288
503
|
for (const s of config.sources) {
|
|
289
|
-
if (filePath
|
|
504
|
+
if (isPathWithin(filePath, s.path) && s.path.length > bestLen) {
|
|
290
505
|
best = s;
|
|
291
506
|
bestLen = s.path.length;
|
|
292
507
|
}
|
|
293
508
|
}
|
|
294
509
|
return best;
|
|
295
510
|
}
|
|
296
|
-
async function reembedTable(tableName, embeddingProvider, getText, timestampField) {
|
|
511
|
+
async function reembedTable(tableName, embeddingProvider, dataDir, operation, getText, timestampField) {
|
|
297
512
|
const { getTable } = await import("./tables.js");
|
|
298
513
|
const table = getTable(tableName);
|
|
299
514
|
const allRows = (await table.query().toArray());
|
|
@@ -301,10 +516,17 @@ async function reembedTable(tableName, embeddingProvider, getText, timestampFiel
|
|
|
301
516
|
for (const row of allRows) {
|
|
302
517
|
try {
|
|
303
518
|
const text = getText(row);
|
|
304
|
-
const newEmbedding = await embeddingProvider.embed(text);
|
|
519
|
+
const newEmbedding = await recordEmbed(dataDir, embeddingProvider, { pipeline: "reindex", operation, input_count: 1 }, () => embeddingProvider.embed(text));
|
|
305
520
|
const oldTimestamp = row[timestampField];
|
|
306
521
|
const newTimestamp = new Date().toISOString();
|
|
307
|
-
await
|
|
522
|
+
await recordIndexWrite(dataDir, {
|
|
523
|
+
table: tableName,
|
|
524
|
+
pipeline: "reindex",
|
|
525
|
+
operation: `${operation.replace(/_embedding$/, "")}_upsert`,
|
|
526
|
+
row_count: 1,
|
|
527
|
+
}, () => table.add([
|
|
528
|
+
{ ...row, embedding: newEmbedding, [timestampField]: newTimestamp },
|
|
529
|
+
]));
|
|
308
530
|
try {
|
|
309
531
|
await table.delete(`id = '${row.id}' AND ${timestampField} = '${oldTimestamp}'`);
|
|
310
532
|
count++;
|
|
@@ -313,7 +535,9 @@ async function reembedTable(tableName, embeddingProvider, getText, timestampFiel
|
|
|
313
535
|
try {
|
|
314
536
|
await table.delete(`id = '${row.id}' AND ${timestampField} = '${newTimestamp}'`);
|
|
315
537
|
}
|
|
316
|
-
catch {
|
|
538
|
+
catch {
|
|
539
|
+
/* duplicate remains — reconcile will repair */
|
|
540
|
+
}
|
|
317
541
|
}
|
|
318
542
|
}
|
|
319
543
|
catch (err) {
|