@mindrian_os/install 1.13.0-beta.11
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/.claude-plugin/plugin.json +21 -0
- package/.mcp.json +9 -0
- package/CHANGELOG.md +3333 -0
- package/LICENSE +123 -0
- package/README.md +673 -0
- package/agents/brain-query.md +80 -0
- package/agents/framework-runner.md +237 -0
- package/agents/grading.md +188 -0
- package/agents/investor.md +128 -0
- package/agents/larry-extended.md +135 -0
- package/agents/opportunity-scanner.md +91 -0
- package/agents/persona-analyst.md +132 -0
- package/agents/research.md +89 -0
- package/agents/reverse-salient-agent.md +27 -0
- package/bin/cli.js +142 -0
- package/bin/mindrian-mcp-server.cjs +182 -0
- package/bin/mindrian-tools.cjs +765 -0
- package/commands/act.md +439 -0
- package/commands/admin.md +404 -0
- package/commands/analyze-needs.md +42 -0
- package/commands/analyze-systems.md +39 -0
- package/commands/analyze-timing.md +42 -0
- package/commands/auto-explore.md +64 -0
- package/commands/beautiful-question.md +40 -0
- package/commands/brain-derive.md +78 -0
- package/commands/build-knowledge.md +42 -0
- package/commands/build-thesis.md +46 -0
- package/commands/causal.md +234 -0
- package/commands/challenge-assumptions.md +33 -0
- package/commands/compare-ventures.md +83 -0
- package/commands/dashboard.md +110 -0
- package/commands/deep-grade.md +82 -0
- package/commands/diagnose.md +58 -0
- package/commands/diagnostics.md +151 -0
- package/commands/doctor.md +151 -0
- package/commands/dominant-designs.md +40 -0
- package/commands/explain-decision.md +87 -0
- package/commands/explore-domains.md +42 -0
- package/commands/explore-futures.md +40 -0
- package/commands/explore-trends.md +42 -0
- package/commands/export.md +103 -0
- package/commands/file-meeting.md +724 -0
- package/commands/find-analogies.md +188 -0
- package/commands/find-bottlenecks.md +62 -0
- package/commands/find-connections.md +76 -0
- package/commands/funding.md +81 -0
- package/commands/grade.md +203 -0
- package/commands/graph.md +128 -0
- package/commands/hat-briefing.md +125 -0
- package/commands/heal.md +196 -0
- package/commands/help.md +399 -0
- package/commands/hmi-status.md +172 -0
- package/commands/jtbd.md +241 -0
- package/commands/leadership.md +73 -0
- package/commands/lean-canvas.md +40 -0
- package/commands/macro-trends.md +40 -0
- package/commands/map-unknowns.md +40 -0
- package/commands/memory.md +173 -0
- package/commands/models.md +175 -0
- package/commands/mos-reason.md +285 -0
- package/commands/mullins.md +120 -0
- package/commands/new-project.md +481 -0
- package/commands/onboard.md +434 -0
- package/commands/operator.md +149 -0
- package/commands/opportunities.md +144 -0
- package/commands/organize.md +497 -0
- package/commands/persona.md +198 -0
- package/commands/pipeline.md +112 -0
- package/commands/present.md +91 -0
- package/commands/publish.md +201 -0
- package/commands/query.md +124 -0
- package/commands/radar.md +72 -0
- package/commands/reanalyze.md +91 -0
- package/commands/research.md +196 -0
- package/commands/room.md +352 -0
- package/commands/rooms.md +598 -0
- package/commands/root-cause.md +40 -0
- package/commands/rs-experts.md +85 -0
- package/commands/rs-explain.md +100 -0
- package/commands/rs-fetch.md +94 -0
- package/commands/rs-thesis.md +85 -0
- package/commands/scenario-plan.md +40 -0
- package/commands/scheduled-tasks.md +285 -0
- package/commands/score-innovation.md +43 -0
- package/commands/scout.md +239 -0
- package/commands/setup.md +618 -0
- package/commands/snapshot.md +147 -0
- package/commands/speakers.md +84 -0
- package/commands/splash.md +28 -0
- package/commands/status.md +75 -0
- package/commands/structure-argument.md +42 -0
- package/commands/suggest-next.md +80 -0
- package/commands/systems-thinking.md +40 -0
- package/commands/think-hats.md +42 -0
- package/commands/update.md +181 -0
- package/commands/user-needs.md +40 -0
- package/commands/validate.md +40 -0
- package/commands/value-proposition.md +61 -0
- package/commands/vault.md +180 -0
- package/commands/visualize.md +52 -0
- package/commands/whitespace.md +507 -0
- package/commands/wiki.md +69 -0
- package/hooks/hooks.json +381 -0
- package/hooks/run-hook.cmd +64 -0
- package/lib/__init__.py +0 -0
- package/lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/lib/agents/auto-explore-agent.cjs +1043 -0
- package/lib/agents/reverse-salient-agent.cjs +679 -0
- package/lib/agents/tension-hook-agent.cjs +544 -0
- package/lib/brain/ROOM.md +44 -0
- package/lib/brain/chain-recommender.cjs +301 -0
- package/lib/chat/chat-context.js +185 -0
- package/lib/chat/chat-panel.js +721 -0
- package/lib/chat/fabric-chat.cjs +288 -0
- package/lib/chat/generative-tools.js +219 -0
- package/lib/conversation/ROOM.md +39 -0
- package/lib/conversation/classifier-rules.json +38 -0
- package/lib/conversation/classifier.cjs +264 -0
- package/lib/conversation/operator.cjs +287 -0
- package/lib/copy/115-spec-strings.cjs +55 -0
- package/lib/core/__init__.py +0 -0
- package/lib/core/__nav-stub.cjs +14 -0
- package/lib/core/__pycache__/__init__.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs-math.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_cache.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_corpus.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_hybrid.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_math.cpython-312.pyc +0 -0
- package/lib/core/__pycache__/rs_rooms.cpython-312.pyc +0 -0
- package/lib/core/artifact-id.cjs +148 -0
- package/lib/core/asset-ops.cjs +151 -0
- package/lib/core/auto-commit-throttle.cjs +129 -0
- package/lib/core/bearer-token.cjs +199 -0
- package/lib/core/brain-client.cjs +865 -0
- package/lib/core/brain-derivation-prompts.cjs +326 -0
- package/lib/core/brain-derivation-queue.cjs +431 -0
- package/lib/core/brain-derivation.cjs +580 -0
- package/lib/core/brain-md-schema.cjs +528 -0
- package/lib/core/brain-md-staleness.cjs +357 -0
- package/lib/core/brain-response-sanitize.cjs +188 -0
- package/lib/core/bridge-writer.cjs +477 -0
- package/lib/core/chat-context-builder.cjs +253 -0
- package/lib/core/cross-room-aggregator.cjs +762 -0
- package/lib/core/daily-briefing.cjs +438 -0
- package/lib/core/decision-capture.cjs +618 -0
- package/lib/core/deep-links.cjs +82 -0
- package/lib/core/dispatch-optimizer.cjs +354 -0
- package/lib/core/dual-path-detector.cjs +84 -0
- package/lib/core/dual-path-detector.test.cjs +334 -0
- package/lib/core/exports-log.cjs +79 -0
- package/lib/core/feynman-minto-invariants.cjs +605 -0
- package/lib/core/folder-memory-async.cjs +338 -0
- package/lib/core/folder-memory-shared.cjs +890 -0
- package/lib/core/folder-memory.cjs +416 -0
- package/lib/core/framework-chain-composer.cjs +411 -0
- package/lib/core/frontmatter-schemas.cjs +330 -0
- package/lib/core/git-ops.cjs +141 -0
- package/lib/core/graph-ops.cjs +258 -0
- package/lib/core/hat-persistence.cjs +362 -0
- package/lib/core/index.cjs +60 -0
- package/lib/core/integration-registry.cjs +232 -0
- package/lib/core/intelligence-cascade.cjs +661 -0
- package/lib/core/lazygraph-ops.cjs +1057 -0
- package/lib/core/lru-cache.cjs +139 -0
- package/lib/core/mcp-profiles.cjs +182 -0
- package/lib/core/meeting-ops.cjs +54 -0
- package/lib/core/memory-ops.cjs +600 -0
- package/lib/core/migrations/ROOM.md +33 -0
- package/lib/core/migrations/phase-109-nodes-provenance.cjs +339 -0
- package/lib/core/migrations/phase-109-session-focus.cjs +99 -0
- package/lib/core/model-profiles.cjs +246 -0
- package/lib/core/mullins-scaffold.cjs +160 -0
- package/lib/core/nav-dial.cjs +316 -0
- package/lib/core/navigation/ROOM.md +15 -0
- package/lib/core/navigation/explanation.cjs +43 -0
- package/lib/core/navigation/focus.cjs +135 -0
- package/lib/core/navigation/ingestion.cjs +82 -0
- package/lib/core/navigation/insights.cjs +350 -0
- package/lib/core/navigation/memory-events.cjs +118 -0
- package/lib/core/navigation/neighborhood.cjs +78 -0
- package/lib/core/navigation/packet.cjs +182 -0
- package/lib/core/navigation/room-home.cjs +127 -0
- package/lib/core/navigation/transitions.cjs +82 -0
- package/lib/core/navigation-engine-shared.cjs +242 -0
- package/lib/core/navigation-engine.cjs +664 -0
- package/lib/core/navigation.cjs +60 -0
- package/lib/core/nl-graph-queries.cjs +164 -0
- package/lib/core/offer-presenter.cjs +406 -0
- package/lib/core/opportunity-extractor.cjs +183 -0
- package/lib/core/opportunity-ops.cjs +1371 -0
- package/lib/core/persona-ops.cjs +537 -0
- package/lib/core/persona-taxonomy.cjs +190 -0
- package/lib/core/platform-gates.cjs +120 -0
- package/lib/core/platform.cjs +257 -0
- package/lib/core/proactive-intelligence.cjs +528 -0
- package/lib/core/problem-type-router.cjs +315 -0
- package/lib/core/reasoning-ops.cjs +639 -0
- package/lib/core/reverse-salient-persona-suffix.cjs +115 -0
- package/lib/core/room-classifier-strict-mode.cjs +229 -0
- package/lib/core/room-db.cjs +127 -0
- package/lib/core/room-ops-async.cjs +92 -0
- package/lib/core/room-ops-shared.cjs +64 -0
- package/lib/core/room-ops-sync.cjs +70 -0
- package/lib/core/room-ops.cjs +32 -0
- package/lib/core/room-type-detector.cjs +386 -0
- package/lib/core/rs-brain-substrate-prompts.cjs +129 -0
- package/lib/core/rs-brain-substrate.cjs +570 -0
- package/lib/core/rs-breakthrough-scorer.cjs +255 -0
- package/lib/core/rs-canon-violations.cjs +82 -0
- package/lib/core/rs-chain-feeder.cjs +343 -0
- package/lib/core/rs-commercial-assessor.cjs +280 -0
- package/lib/core/rs-differential-scorer.cjs +376 -0
- package/lib/core/rs-domain-analyzer.cjs +385 -0
- package/lib/core/rs-egress-prompts.cjs +113 -0
- package/lib/core/rs-egress-telemetry.cjs +225 -0
- package/lib/core/rs-egress-violations.cjs +53 -0
- package/lib/core/rs-expert-mapper.cjs +467 -0
- package/lib/core/rs-fetcher-academic.cjs +697 -0
- package/lib/core/rs-fetcher-experts.cjs +314 -0
- package/lib/core/rs-fetcher-industry.cjs +731 -0
- package/lib/core/rs-fetcher-patents.cjs +564 -0
- package/lib/core/rs-innovation-classifier.cjs +194 -0
- package/lib/core/rs-mind-map.cjs +656 -0
- package/lib/core/rs-neo4j-writer.cjs +388 -0
- package/lib/core/rs-nl-to-query.cjs +425 -0
- package/lib/core/rs-pinecone-bridge.cjs +303 -0
- package/lib/core/rs-preprocessor.cjs +350 -0
- package/lib/core/rs-query-matrix.cjs +316 -0
- package/lib/core/rs-query-to-text.cjs +438 -0
- package/lib/core/rs-sqlite-mirror.cjs +443 -0
- package/lib/core/rs-thesis-generator.cjs +188 -0
- package/lib/core/rs_cache.py +479 -0
- package/lib/core/rs_corpus.py +468 -0
- package/lib/core/rs_hybrid.py +586 -0
- package/lib/core/rs_math.py +287 -0
- package/lib/core/rs_rooms.py +193 -0
- package/lib/core/scheduled-scanner.cjs +463 -0
- package/lib/core/scratchpad-ops.cjs +201 -0
- package/lib/core/section-8-trace-schema.cjs +138 -0
- package/lib/core/section-registry.cjs +111 -0
- package/lib/core/session-state.cjs +144 -0
- package/lib/core/shallow-doc-parser.cjs +174 -0
- package/lib/core/shallow-doc-parser.test.cjs +226 -0
- package/lib/core/skill-activation-router.cjs +284 -0
- package/lib/core/state-ops.cjs +46 -0
- package/lib/core/statusline-cache.cjs +266 -0
- package/lib/core/token-estimator.cjs +348 -0
- package/lib/core/user-archetype.cjs +239 -0
- package/lib/core/user-md-ops.cjs +524 -0
- package/lib/core/visual-ops.cjs +624 -0
- package/lib/core/write-lock.cjs +149 -0
- package/lib/graph/canvas-graph.js +467 -0
- package/lib/graph/constellation-config.cjs +299 -0
- package/lib/graph/graph-detail-panel.js +165 -0
- package/lib/hmi/ROOM.md +47 -0
- package/lib/hmi/across-session-memory.cjs +604 -0
- package/lib/hmi/cross-room-memory.cjs +575 -0
- package/lib/hmi/decoy-tier.cjs +395 -0
- package/lib/hmi/jtbd-classifier.cjs +219 -0
- package/lib/hmi/jtbd-state.cjs +199 -0
- package/lib/hmi/jtbd-taxonomy.json +392 -0
- package/lib/hmi/selector-dispatcher.cjs +546 -0
- package/lib/hmi/selector-telemetry.cjs +263 -0
- package/lib/hmi/shape-f0-renderer.cjs +139 -0
- package/lib/hmi/shape-f1-fallback.cjs +80 -0
- package/lib/hmi/shape-f1-renderer.cjs +138 -0
- package/lib/hmi/shape-f2-renderer.cjs +132 -0
- package/lib/hmi/shape-f3-renderer.cjs +66 -0
- package/lib/hmi/shape-f4-renderer.cjs +72 -0
- package/lib/hmi/shape-f5-renderer.cjs +155 -0
- package/lib/hmi/shape-f6-plan-review-renderer.cjs +312 -0
- package/lib/hmi/shape-f6-renderer.cjs +144 -0
- package/lib/hmi/shape-g-renderer.cjs +219 -0
- package/lib/hmi/shape-h-renderer.cjs +222 -0
- package/lib/hmi/tier-check.cjs +63 -0
- package/lib/import/PRECONDITIONS.md +41 -0
- package/lib/import/branding.cjs +210 -0
- package/lib/import/branding.test.cjs +235 -0
- package/lib/import/classifications-sync.cjs +104 -0
- package/lib/import/classifications-sync.test.cjs +129 -0
- package/lib/import/enricher.cjs +296 -0
- package/lib/import/enricher.test.cjs +273 -0
- package/lib/import/integration.test.cjs +376 -0
- package/lib/import/manifest.cjs +129 -0
- package/lib/import/manifest.schema.json +185 -0
- package/lib/import/manifest.test.cjs +123 -0
- package/lib/import/meeting-detector.cjs +92 -0
- package/lib/import/meeting-detector.test.cjs +100 -0
- package/lib/import/person-detector.cjs +229 -0
- package/lib/import/person-detector.test.cjs +149 -0
- package/lib/import/report.cjs +186 -0
- package/lib/import/report.test.cjs +186 -0
- package/lib/import/room-md-scaffolder.cjs +49 -0
- package/lib/import/router.cjs +224 -0
- package/lib/import/router.test.cjs +356 -0
- package/lib/import/run-all-tests.cjs +36 -0
- package/lib/import/smoke-test.cjs +213 -0
- package/lib/import/smoke-test.test.cjs +148 -0
- package/lib/import/test-fixtures/collision-vault/preexisting-room/STATE.md +8 -0
- package/lib/import/test-fixtures/collision-vault/preexisting-room/problem-definition/onboarding/onboarding.md +7 -0
- package/lib/import/test-fixtures/collision-vault/source/onboarding.md +5 -0
- package/lib/import/test-fixtures/obsidian-vault/.obsidian/workspace.json +1 -0
- package/lib/import/test-fixtures/obsidian-vault/notes/with-wikilinks.md +4 -0
- package/lib/import/test-fixtures/tiny-vault/notes/2026-01-15-team-sync.md +9 -0
- package/lib/import/test-fixtures/tiny-vault/notes/empty.md +3 -0
- package/lib/import/test-fixtures/tiny-vault/notes/onboarding.md +5 -0
- package/lib/import/test-fixtures/tiny-vault/notes/pricing.md +5 -0
- package/lib/import/test-fixtures/tiny-vault/notes/random.md +4 -0
- package/lib/import/undo.test.cjs +199 -0
- package/lib/import/vault-scanner.cjs +105 -0
- package/lib/import/vault-scanner.test.cjs +67 -0
- package/lib/mcp/app-html/dashboard.html +316 -0
- package/lib/mcp/app-html/graph.html +428 -0
- package/lib/mcp/app-html/mindrian-platform.html +1841 -0
- package/lib/mcp/app-html/wiki.html +383 -0
- package/lib/mcp/app-views.cjs +322 -0
- package/lib/mcp/brain-router.cjs +418 -0
- package/lib/mcp/capability-registry.cjs +62 -0
- package/lib/mcp/larry-context.cjs +46 -0
- package/lib/mcp/larry-server-instructions.md +114 -0
- package/lib/mcp/pipeline-state.cjs +275 -0
- package/lib/mcp/prompts.cjs +302 -0
- package/lib/mcp/resources.cjs +227 -0
- package/lib/mcp/session-catchup.cjs +327 -0
- package/lib/mcp/surface-detect.cjs +75 -0
- package/lib/mcp/tool-router.cjs +1034 -0
- package/lib/memory/aaak-compress.cjs +403 -0
- package/lib/memory/aaak-compress.test.cjs +288 -0
- package/lib/memory/async-artifact-auto-commit.test.cjs +223 -0
- package/lib/memory/bearer-token.test.cjs +315 -0
- package/lib/memory/brain-cache-lru.test.cjs +259 -0
- package/lib/memory/brain-client-query-shape.test.cjs +160 -0
- package/lib/memory/brain-derivation-graceful-degradation.test.cjs +1019 -0
- package/lib/memory/brain-derivation-queue.test.cjs +539 -0
- package/lib/memory/brain-derivation.test.cjs +634 -0
- package/lib/memory/brain-derive-command.test.cjs +534 -0
- package/lib/memory/brain-md-invariants-validator.test.cjs +704 -0
- package/lib/memory/brain-md-schema.test.cjs +467 -0
- package/lib/memory/brain-md-staleness.test.cjs +525 -0
- package/lib/memory/brain-server-resolution.test.cjs +314 -0
- package/lib/memory/chain-recommender.test.cjs +233 -0
- package/lib/memory/chat-context.test.cjs +128 -0
- package/lib/memory/command-registry.test.cjs +220 -0
- package/lib/memory/cross-room-aggregator.test.cjs +909 -0
- package/lib/memory/dashboard-server.test.cjs +256 -0
- package/lib/memory/debouncer-drain-at-prompt.test.cjs +389 -0
- package/lib/memory/decision-capture.test.cjs +632 -0
- package/lib/memory/decision-capture.worker.cjs +70 -0
- package/lib/memory/explain-decision-command.test.cjs +521 -0
- package/lib/memory/explain-decision-footer.test.cjs +316 -0
- package/lib/memory/explored-materials-store.cjs +392 -0
- package/lib/memory/feynman-minto-guardian.test.cjs +736 -0
- package/lib/memory/feynman-minto-invariants.test.cjs +511 -0
- package/lib/memory/feynman-prompts-drift.test.cjs +144 -0
- package/lib/memory/feynman-prompts.cjs +151 -0
- package/lib/memory/feynman-prompts.test.cjs +96 -0
- package/lib/memory/folder-memory-quadruple.test.cjs +548 -0
- package/lib/memory/folder-memory.test.cjs +503 -0
- package/lib/memory/framework-chain-composer.test.cjs +515 -0
- package/lib/memory/frontmatter-schema-validator.test.cjs +290 -0
- package/lib/memory/heal-command.test.cjs +604 -0
- package/lib/memory/index-artifact-transaction.test.cjs +333 -0
- package/lib/memory/lazygraph-rs-discoveries-view.test.cjs +122 -0
- package/lib/memory/mcp-input-validation.test.cjs +240 -0
- package/lib/memory/mcp-server-brain-deps.test.cjs +270 -0
- package/lib/memory/mcp-stack-fallback.test.cjs +433 -0
- package/lib/memory/minto-debouncer.test.cjs +407 -0
- package/lib/memory/minto-debouncer.worker.cjs +46 -0
- package/lib/memory/minto-migration-v88.test.cjs +265 -0
- package/lib/memory/minto-schema-v88.test.cjs +390 -0
- package/lib/memory/mos-status-renderer.test.cjs +631 -0
- package/lib/memory/narrative-schema.cjs +376 -0
- package/lib/memory/narrative-schema.test.cjs +209 -0
- package/lib/memory/nav-dial.test.cjs +414 -0
- package/lib/memory/navigation-engine-core.test.cjs +722 -0
- package/lib/memory/navigation-invariants.test.cjs +483 -0
- package/lib/memory/offer-presenter.test.cjs +554 -0
- package/lib/memory/on-stop-snapshot.test.cjs +404 -0
- package/lib/memory/pending-tension-store.cjs +373 -0
- package/lib/memory/post-compact-reinjection.test.cjs +854 -0
- package/lib/memory/post-write-triple.test.cjs +317 -0
- package/lib/memory/pre-compact-snapshot.test.cjs +495 -0
- package/lib/memory/problem-type-router.test.cjs +656 -0
- package/lib/memory/query-efficiency-telemetry.test.cjs +370 -0
- package/lib/memory/recompile-room-references.test.cjs +392 -0
- package/lib/memory/recompile-room-references.worker.cjs +42 -0
- package/lib/memory/record-decision-dual-write.test.cjs +454 -0
- package/lib/memory/room-classifier-strict-mode.test.cjs +417 -0
- package/lib/memory/room-minto-hook.test.cjs +398 -0
- package/lib/memory/rs-discovery-engine.test.cjs +323 -0
- package/lib/memory/run-feynman-tests.cjs +1247 -0
- package/lib/memory/security-trifecta.test.cjs +312 -0
- package/lib/memory/session-start-brain-staleness.test.cjs +363 -0
- package/lib/memory/session-start-triple-injection.test.cjs +514 -0
- package/lib/memory/sessionstart-banner-formatter.cjs +318 -0
- package/lib/memory/sessionstart-minto-banner.test.cjs +373 -0
- package/lib/memory/skill-activation-router.test.cjs +419 -0
- package/lib/memory/stamp-artifact-write.test.cjs +304 -0
- package/lib/memory/statusline-active-room.test.cjs +315 -0
- package/lib/memory/statusline-minto-segment.test.cjs +292 -0
- package/lib/memory/sync-async-entry-points.test.cjs +204 -0
- package/lib/memory/test-bridge-writer-enhanced.cjs +452 -0
- package/lib/memory/test-rs-brain-substrate-shape.cjs +529 -0
- package/lib/memory/test-rs-brain-substrate.cjs +636 -0
- package/lib/memory/test-rs-breakthrough-scorer.cjs +375 -0
- package/lib/memory/test-rs-canon-violations.cjs +218 -0
- package/lib/memory/test-rs-chain-feeder-core.cjs +344 -0
- package/lib/memory/test-rs-chain-feeder-skill-spawn.cjs +297 -0
- package/lib/memory/test-rs-commercial-assessor.cjs +385 -0
- package/lib/memory/test-rs-differential-scorer.cjs +480 -0
- package/lib/memory/test-rs-discovery-engine.cjs +603 -0
- package/lib/memory/test-rs-domain-analyzer.cjs +492 -0
- package/lib/memory/test-rs-egress-primitives.cjs +420 -0
- package/lib/memory/test-rs-expert-mapper.cjs +547 -0
- package/lib/memory/test-rs-explain-command.cjs +443 -0
- package/lib/memory/test-rs-fetcher-academic.cjs +848 -0
- package/lib/memory/test-rs-fetcher-experts.cjs +496 -0
- package/lib/memory/test-rs-fetcher-industry.cjs +702 -0
- package/lib/memory/test-rs-fetcher-patents.cjs +674 -0
- package/lib/memory/test-rs-innovation-classifier.cjs +301 -0
- package/lib/memory/test-rs-mind-map.cjs +646 -0
- package/lib/memory/test-rs-neo4j-writer.cjs +518 -0
- package/lib/memory/test-rs-nl-to-query.cjs +449 -0
- package/lib/memory/test-rs-pinecone-bridge.cjs +277 -0
- package/lib/memory/test-rs-preprocessor.cjs +433 -0
- package/lib/memory/test-rs-query-matrix.cjs +391 -0
- package/lib/memory/test-rs-query-to-text.cjs +551 -0
- package/lib/memory/test-rs-sqlite-mirror.cjs +649 -0
- package/lib/memory/test-rs-thesis-generator.cjs +360 -0
- package/lib/memory/triple-context-formatter.cjs +473 -0
- package/lib/memory/triple-context-formatter.test.cjs +442 -0
- package/lib/memory/user-md-persona.test.cjs +565 -0
- package/lib/memory/userpromptsubmit-integration.test.cjs +690 -0
- package/lib/memory/validators/README.md +157 -0
- package/lib/memory/validators/brain-md-invariants.cjs +475 -0
- package/lib/memory/validators/brain-substrate-invariants.cjs +285 -0
- package/lib/memory/validators/external-academic-invariants.cjs +249 -0
- package/lib/memory/validators/external-industry-invariants.cjs +271 -0
- package/lib/memory/validators/external-patents-invariants.cjs +266 -0
- package/lib/memory/validators/minto-invariants.cjs +62 -0
- package/lib/memory/validators/navigation-invariants.cjs +340 -0
- package/lib/memory/validators/queue-health.cjs +95 -0
- package/lib/memory/validators/snapshot-integrity.cjs +129 -0
- package/lib/memory/validators/stale-lifecycle.cjs +116 -0
- package/lib/memory/vault-section-minto-generator-atomic.test.cjs +556 -0
- package/lib/memory/vault-section-minto-generator-atomic.worker.cjs +73 -0
- package/lib/memory/write-lock-atomic.test.cjs +137 -0
- package/lib/memory/write-lock-atomic.worker.cjs +55 -0
- package/lib/parity/check-parity.cjs +83 -0
- package/lib/presentation/presentation-server.cjs +101 -0
- package/lib/presentation/presentation-watcher.cjs +123 -0
- package/lib/quickview/hub-server.cjs +719 -0
- package/lib/quickview/server.cjs +533 -0
- package/lib/render/JTBD-PALETTES.md +145 -0
- package/lib/render/ROOM.md +59 -0
- package/lib/render/render-v2.cjs +486 -0
- package/lib/render/render-v2.test.cjs +267 -0
- package/lib/render/render.cjs +65 -0
- package/lib/state/ROOM.md +46 -0
- package/lib/state/state-md-parser.cjs +215 -0
- package/lib/statusline/ROOM.md +38 -0
- package/lib/statusline/banner-suppression.cjs +50 -0
- package/lib/statusline/surface-detect.cjs +85 -0
- package/lib/update-bootstrap.sh.template +145 -0
- package/lib/vault/frontmatter-schema.cjs +297 -0
- package/lib/vault/room-scanner.cjs +352 -0
- package/lib/vault/wikilink-builder.cjs +231 -0
- package/lib/vault/wikilink-builder.test.cjs +182 -0
- package/lib/wiki/graph-links.cjs +281 -0
- package/lib/wiki/page-renderer.cjs +229 -0
- package/lib/wiki/wiki-chat.cjs +81 -0
- package/lib/wiki/wiki-layout.cjs +1459 -0
- package/lib/wiki/wiki-search.cjs +142 -0
- package/lib/wiki/wiki-server.cjs +678 -0
- package/lib/wiki/wiki-watcher.cjs +105 -0
- package/lib/workflow/ROOM.md +47 -0
- package/lib/workflow/command-resolver.cjs +155 -0
- package/lib/workflow/command-resolver.test.cjs +235 -0
- package/package.json +44 -0
- package/pipelines/analogy/01-decompose.md +80 -0
- package/pipelines/analogy/02-abstract.md +87 -0
- package/pipelines/analogy/03-search.md +135 -0
- package/pipelines/analogy/04-transfer.md +101 -0
- package/pipelines/analogy/05-validate.md +106 -0
- package/pipelines/analogy/CHAIN.md +56 -0
- package/pipelines/discovery/01-explore-domains.md +44 -0
- package/pipelines/discovery/02-think-hats.md +50 -0
- package/pipelines/discovery/03-analyze-needs.md +54 -0
- package/pipelines/discovery/CHAIN.md +37 -0
- package/pipelines/thesis/01-structure-argument.md +45 -0
- package/pipelines/thesis/02-challenge-assumptions.md +48 -0
- package/pipelines/thesis/03-build-thesis.md +54 -0
- package/pipelines/thesis/CHAIN.md +37 -0
- package/references/brain/causal-directives.md +91 -0
- package/references/brain/causal-enrichment.cypher +165 -0
- package/references/brain/command-triggers-schema.md +226 -0
- package/references/brain/graph-architecture.md +317 -0
- package/references/brain/query-patterns.md +460 -0
- package/references/brain/room-hierarchy-schema.md +218 -0
- package/references/brain/schema.md +76 -0
- package/references/capability-radar/capabilities-index.md +241 -0
- package/references/capability-radar/changelog-cache.md +81 -0
- package/references/causal/causal-schema.md +103 -0
- package/references/design/email-template-standard.md +155 -0
- package/references/design/graph-visualization-standard.md +178 -0
- package/references/document-generation.md +179 -0
- package/references/hsi/HSI-TOOLS-REFERENCE.md +222 -0
- package/references/import-config.md +141 -0
- package/references/integrations/detection-patterns.md +101 -0
- package/references/meeting/artifact-template.md +377 -0
- package/references/meeting/cross-meeting-intelligence.md +216 -0
- package/references/meeting/cross-relationship-patterns.md +202 -0
- package/references/meeting/live-join-interface.md +244 -0
- package/references/meeting/section-mapping.md +192 -0
- package/references/meeting/segment-classification.md +258 -0
- package/references/meeting/speaker-profile-template.md +219 -0
- package/references/meeting/summary-template.md +348 -0
- package/references/meeting/transcript-patterns.md +226 -0
- package/references/methodology/analyze-needs.md +135 -0
- package/references/methodology/analyze-systems.md +121 -0
- package/references/methodology/analyze-timing.md +149 -0
- package/references/methodology/beautiful-question.md +109 -0
- package/references/methodology/build-knowledge.md +161 -0
- package/references/methodology/build-thesis.md +237 -0
- package/references/methodology/challenge-assumptions.md +127 -0
- package/references/methodology/diagnose.md +169 -0
- package/references/methodology/dominant-designs.md +212 -0
- package/references/methodology/explore-domains.md +147 -0
- package/references/methodology/explore-futures.md +163 -0
- package/references/methodology/explore-trends.md +129 -0
- package/references/methodology/find-bottlenecks.md +131 -0
- package/references/methodology/grade.md +211 -0
- package/references/methodology/index.md +97 -0
- package/references/methodology/leadership.md +200 -0
- package/references/methodology/lean-canvas.md +116 -0
- package/references/methodology/macro-trends.md +192 -0
- package/references/methodology/map-unknowns.md +137 -0
- package/references/methodology/mullins-7-domains.md +104 -0
- package/references/methodology/problem-types.md +65 -0
- package/references/methodology/root-cause.md +178 -0
- package/references/methodology/sapphire-encoding.md +355 -0
- package/references/methodology/scenario-plan.md +178 -0
- package/references/methodology/score-innovation.md +154 -0
- package/references/methodology/structure-argument.md +158 -0
- package/references/methodology/systems-thinking.md +159 -0
- package/references/methodology/think-hats.md +147 -0
- package/references/methodology/triz-matrix.json +751 -0
- package/references/methodology/triz-principles.md +501 -0
- package/references/methodology/user-needs.md +199 -0
- package/references/methodology/validate.md +163 -0
- package/references/methodology/value-proposition.md +244 -0
- package/references/opportunities/funding-lifecycle.md +103 -0
- package/references/opportunities/grant-api-patterns.md +99 -0
- package/references/opportunities/opportunity-template.md +84 -0
- package/references/personality/assessment-philosophy.md +72 -0
- package/references/personality/lexicon.md +100 -0
- package/references/personality/persona-chains.md +56 -0
- package/references/personality/pws-lexicon-full.md +499 -0
- package/references/personality/voice-dna.md +156 -0
- package/references/personas/hat-perspectives.md +76 -0
- package/references/personas/persona-template.md +63 -0
- package/references/pipeline/act-output-contract.md +88 -0
- package/references/pipeline/chains-index.md +39 -0
- package/references/pws-profile-generation.md +79 -0
- package/references/reasoning/reasoning-schema.md +143 -0
- package/references/reasoning/reasoning-template.md +68 -0
- package/references/reasoning/run-template.md +38 -0
- package/references/research/RESEARCH_14_CLAUDE_CODE_SOURCE_ARCHITECTURE.md +209 -0
- package/references/research/RESEARCH_15_V1.8_OPTIMIZATION_JTBD.md +375 -0
- package/references/research/RESEARCH_16_NATIVE_FIRST_PLUGIN_ARCHITECTURE.md +575 -0
- package/references/research/RESEARCH_17_MCP_UI_FRAMEWORKS.md +272 -0
- package/references/taxonomy/TAXONOMY.md +192 -0
- package/references/templates/MINTO.md +36 -0
- package/references/user-research/2026-04-05-leah-lawrence-session.md +202 -0
- package/references/vault-kit/README.md +35 -0
- package/references/vault-kit/app.json +12 -0
- package/references/vault-kit/appearance.json +12 -0
- package/references/vault-kit/graph.json +35 -0
- package/references/vault-kit/snippets/mindrian-destijl.css +297 -0
- package/references/vault-kit/templates/new-artifact.md +37 -0
- package/references/vault-kit/templates/new-meeting-note.md +35 -0
- package/references/vault-kit/templates/new-team-profile.md +29 -0
- package/references/vault-kit/templates/new-xref.md +35 -0
- package/references/visual/symbol-system.md +151 -0
- package/skills/MOSDeckEngine/SKILL.md +325 -0
- package/skills/brain-connector/SKILL.md +114 -0
- package/skills/context-engine/SKILL.md +147 -0
- package/skills/conversation-mode/SKILL.md +102 -0
- package/skills/larry-personality/SKILL.md +219 -0
- package/skills/larry-personality/framework-chains.md +92 -0
- package/skills/larry-personality/mode-engine.md +185 -0
- package/skills/mullins-scaffold/SKILL.md +61 -0
- package/skills/mullins-scaffold/scaffold.json +146 -0
- package/skills/pws-methodology/SKILL.md +49 -0
- package/skills/room-passive/SKILL.md +165 -0
- package/skills/room-proactive/SKILL.md +250 -0
- package/skills/ui-system/SKILL.md +277 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
rs_cache.py -- Pinecone rs-external Index + 30-day Lazy TTL Cache (Phase 89)
|
|
4
|
+
============================================================================
|
|
5
|
+
|
|
6
|
+
Velma-pattern cache for external research corpora: fetch once, embed once,
|
|
7
|
+
query forever (within 30 days). Wraps the Pinecone integrated-embedding API
|
|
8
|
+
so scripts/rs-engine.py --mode external can skip re-fetching and
|
|
9
|
+
re-embedding on repeat runs of the same topic.
|
|
10
|
+
|
|
11
|
+
Architecture (RESEARCH Q3):
|
|
12
|
+
- Dedicated index 'rs-external' (separate from pws-brain Brain IP index).
|
|
13
|
+
- Per-topic namespace 'external:{topic-slug}' holds the embedded corpus.
|
|
14
|
+
- Records carry metadata: source, doi, title, year, fetched_at, abstract.
|
|
15
|
+
- Text field is 'abstract' per Pinecone fieldMap convention (Pinecone MCP
|
|
16
|
+
rule: consistent schema per index; changing field_map requires a new
|
|
17
|
+
index name).
|
|
18
|
+
- Integrated embedding via multilingual-e5-large (1024-dim), matching the
|
|
19
|
+
pws-brain Brain index so embeddings are semantically compatible.
|
|
20
|
+
|
|
21
|
+
Freshness policy:
|
|
22
|
+
- TTL 30 days. On query, if max(fetched_at) across the namespace is within
|
|
23
|
+
TTL, skip fetch+upsert and use the cached namespace directly (warm path).
|
|
24
|
+
- Outside TTL or empty namespace, cold path: fetcher runs, upserts, then
|
|
25
|
+
proceeds. Lazy invalidation on query -- no cron job (CLAUDE.md decision:
|
|
26
|
+
plugin runs entirely in Claude's environment, no background daemons).
|
|
27
|
+
|
|
28
|
+
Public API:
|
|
29
|
+
namespace_slug(topic) -> "external:{topic-slug}"
|
|
30
|
+
ensure_index() -> pinecone Index handle
|
|
31
|
+
get_namespace_freshness(namespace) -> age in days, or None if empty
|
|
32
|
+
upsert_corpus(topic, documents) -> namespace name
|
|
33
|
+
query_namespace(namespace, query, top_k) -> search results
|
|
34
|
+
fetch_all_from_namespace(namespace, limit) -> list of {id, values, metadata}
|
|
35
|
+
|
|
36
|
+
Three-surface coverage (CLAUDE.md tri-polar rule):
|
|
37
|
+
CLI Consumed by scripts/rs-engine.py --mode external.
|
|
38
|
+
Desktop ReverseSalientAgent invokes rs-engine.py as a child process
|
|
39
|
+
(Plan 89-07).
|
|
40
|
+
Cowork Cache is per-namespace, not per-room, so team members running
|
|
41
|
+
the same topic share the warm path transparently.
|
|
42
|
+
|
|
43
|
+
Canon alignment:
|
|
44
|
+
Part 8 Graph Boundary: rs-external is SIGNAL egress only. User-specific
|
|
45
|
+
room content is NEVER written here. What ships to Pinecone is the
|
|
46
|
+
abstract text of public papers (already public via OpenAlex/arXiv) plus
|
|
47
|
+
their public metadata (DOI, title, year). No user artifacts, no user
|
|
48
|
+
decisions, no user meetings.
|
|
49
|
+
|
|
50
|
+
License: BSL-1.1 (see LICENSE at repo root).
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
from __future__ import annotations
|
|
54
|
+
|
|
55
|
+
import os
|
|
56
|
+
import re
|
|
57
|
+
import sys
|
|
58
|
+
import time
|
|
59
|
+
from datetime import datetime, timezone, timedelta
|
|
60
|
+
from typing import Any, Dict, List, Optional, Sequence
|
|
61
|
+
|
|
62
|
+
# --- Guarded imports ---------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
from pinecone import Pinecone # type: ignore
|
|
66
|
+
except ImportError:
|
|
67
|
+
print(
|
|
68
|
+
"rs_cache: pinecone SDK not installed. "
|
|
69
|
+
"Run: pip install -r requirements-hsi.txt",
|
|
70
|
+
file=sys.stderr,
|
|
71
|
+
)
|
|
72
|
+
raise
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# --- Constants ---------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
INDEX_NAME = "rs-external"
|
|
78
|
+
DEFAULT_EMBED_MODEL = "multilingual-e5-large"
|
|
79
|
+
EMBED_MODEL = os.environ.get("RS_EMBEDDING_MODEL", DEFAULT_EMBED_MODEL)
|
|
80
|
+
# multilingual-e5-large renders to MiniLM-style local fallback elsewhere;
|
|
81
|
+
# Pinecone only supports the integrated model name for create_index_for_model.
|
|
82
|
+
# When RS_EMBEDDING_MODEL is 'minilm' the rs-external path is a no-op and
|
|
83
|
+
# rs-engine.py should route through its local compute_embeddings path.
|
|
84
|
+
PINECONE_EMBED_MODEL = DEFAULT_EMBED_MODEL
|
|
85
|
+
|
|
86
|
+
TTL_DAYS = 30
|
|
87
|
+
MAX_NAMESPACE_VECTORS = 10_000
|
|
88
|
+
# Pinecone inference batch size for integrated embedding.
|
|
89
|
+
UPSERT_BATCH_SIZE = 96
|
|
90
|
+
# Pinecone list() page size cap.
|
|
91
|
+
LIST_BATCH_SIZE = 96
|
|
92
|
+
# Ready poll timeout for index creation.
|
|
93
|
+
INDEX_READY_TIMEOUT_SEC = 300
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# --- Slug ------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def namespace_slug(topic: str) -> str:
|
|
100
|
+
"""Return the canonical namespace name for a topic.
|
|
101
|
+
|
|
102
|
+
The slug lowercases, replaces non-alphanumeric runs with a single hyphen,
|
|
103
|
+
strips leading/trailing hyphens, and prefixes with "external:" so
|
|
104
|
+
namespaces written by this module cannot collide with any Mode A
|
|
105
|
+
room-local namespace pattern.
|
|
106
|
+
|
|
107
|
+
Plan verify block 2 asserts:
|
|
108
|
+
namespace_slug('Quantum Biology & Sensing!') == 'external:quantum-biology-sensing'
|
|
109
|
+
"""
|
|
110
|
+
s = (topic or "").strip().lower()
|
|
111
|
+
s = re.sub(r"[^a-z0-9]+", "-", s).strip("-")
|
|
112
|
+
return f"external:{s}"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# --- Pinecone client + index lifecycle ---------------------------------------
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _pc() -> Pinecone:
|
|
119
|
+
api_key = os.environ.get("PINECONE_API_KEY")
|
|
120
|
+
if not api_key:
|
|
121
|
+
raise RuntimeError(
|
|
122
|
+
"PINECONE_API_KEY not set. rs-external cache requires a Pinecone "
|
|
123
|
+
"API key. Set PINECONE_API_KEY in your environment or run "
|
|
124
|
+
"rs-engine.py with RS_EMBEDDING_MODEL=minilm to skip the Pinecone "
|
|
125
|
+
"path (Mode A / local fallback only)."
|
|
126
|
+
)
|
|
127
|
+
return Pinecone(api_key=api_key)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def ensure_index() -> Any:
|
|
131
|
+
"""Create the rs-external index if missing, then return an Index handle.
|
|
132
|
+
|
|
133
|
+
fieldMap convention (Pinecone MCP rule): the text field is "abstract".
|
|
134
|
+
Once the index exists with a given field_map, changing it would require
|
|
135
|
+
a new index name -- this function NEVER recreates. Plan 89-03 Risk 2.
|
|
136
|
+
"""
|
|
137
|
+
pc = _pc()
|
|
138
|
+
try:
|
|
139
|
+
exists = pc.has_index(INDEX_NAME)
|
|
140
|
+
except Exception:
|
|
141
|
+
# Fallback for SDK versions that do not expose has_index directly.
|
|
142
|
+
names = [getattr(i, "name", None) for i in pc.list_indexes()]
|
|
143
|
+
exists = INDEX_NAME in names
|
|
144
|
+
|
|
145
|
+
if not exists:
|
|
146
|
+
pc.create_index_for_model(
|
|
147
|
+
name=INDEX_NAME,
|
|
148
|
+
cloud="aws",
|
|
149
|
+
region="us-east-1",
|
|
150
|
+
embed={
|
|
151
|
+
"model": PINECONE_EMBED_MODEL,
|
|
152
|
+
"field_map": {"text": "abstract"},
|
|
153
|
+
},
|
|
154
|
+
)
|
|
155
|
+
# Poll until ready. The describe_index response exposes `.status` as
|
|
156
|
+
# an object with `.ready` attribute (see scripts/consolidate-pinecone.py
|
|
157
|
+
# line 147 for the pattern in use). Plan 89-03 wrote this as a dict
|
|
158
|
+
# lookup which would raise AttributeError on the real SDK -- Rule 1.
|
|
159
|
+
deadline = time.time() + INDEX_READY_TIMEOUT_SEC
|
|
160
|
+
while True:
|
|
161
|
+
desc = pc.describe_index(INDEX_NAME)
|
|
162
|
+
ready = False
|
|
163
|
+
try:
|
|
164
|
+
ready = bool(desc.status.ready) # type: ignore[attr-defined]
|
|
165
|
+
except AttributeError:
|
|
166
|
+
status = getattr(desc, "status", {}) or {}
|
|
167
|
+
if isinstance(status, dict):
|
|
168
|
+
ready = bool(status.get("ready"))
|
|
169
|
+
if ready:
|
|
170
|
+
break
|
|
171
|
+
if time.time() > deadline:
|
|
172
|
+
raise RuntimeError(
|
|
173
|
+
f"rs_cache: index {INDEX_NAME!r} did not become ready "
|
|
174
|
+
f"within {INDEX_READY_TIMEOUT_SEC}s"
|
|
175
|
+
)
|
|
176
|
+
time.sleep(2)
|
|
177
|
+
|
|
178
|
+
return pc.Index(INDEX_NAME)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# --- Freshness -------------------------------------------------------------
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _namespace_vector_count(idx: Any, namespace: str) -> int:
|
|
185
|
+
"""Return the vector_count for the namespace, or 0 if absent.
|
|
186
|
+
|
|
187
|
+
describe_index_stats returns a DescribeIndexStatsResponse; both attribute
|
|
188
|
+
access (.namespaces) and .to_dict() shapes are supported across SDK
|
|
189
|
+
versions. This function tolerates both.
|
|
190
|
+
"""
|
|
191
|
+
try:
|
|
192
|
+
stats = idx.describe_index_stats()
|
|
193
|
+
except Exception:
|
|
194
|
+
return 0
|
|
195
|
+
|
|
196
|
+
ns_map: Dict[str, Any] = {}
|
|
197
|
+
# Attribute form.
|
|
198
|
+
namespaces_attr = getattr(stats, "namespaces", None)
|
|
199
|
+
if isinstance(namespaces_attr, dict):
|
|
200
|
+
ns_map = namespaces_attr
|
|
201
|
+
else:
|
|
202
|
+
try:
|
|
203
|
+
d = stats.to_dict()
|
|
204
|
+
ns_map = d.get("namespaces", {}) or {}
|
|
205
|
+
except Exception:
|
|
206
|
+
ns_map = {}
|
|
207
|
+
|
|
208
|
+
entry = ns_map.get(namespace)
|
|
209
|
+
if not entry:
|
|
210
|
+
return 0
|
|
211
|
+
if isinstance(entry, dict):
|
|
212
|
+
return int(entry.get("vector_count", 0) or 0)
|
|
213
|
+
return int(getattr(entry, "vector_count", 0) or 0)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _parse_fetched_at(raw: Any) -> Optional[datetime]:
|
|
217
|
+
"""Parse an ISO-8601 fetched_at string. Tolerates trailing 'Z'."""
|
|
218
|
+
if not raw:
|
|
219
|
+
return None
|
|
220
|
+
if isinstance(raw, datetime):
|
|
221
|
+
return raw
|
|
222
|
+
if not isinstance(raw, str):
|
|
223
|
+
return None
|
|
224
|
+
s = raw.strip()
|
|
225
|
+
if not s:
|
|
226
|
+
return None
|
|
227
|
+
# Python's fromisoformat accepts offsets but not trailing 'Z' until 3.11.
|
|
228
|
+
if s.endswith("Z"):
|
|
229
|
+
s = s[:-1] + "+00:00"
|
|
230
|
+
try:
|
|
231
|
+
dt = datetime.fromisoformat(s)
|
|
232
|
+
except ValueError:
|
|
233
|
+
return None
|
|
234
|
+
if dt.tzinfo is None:
|
|
235
|
+
dt = dt.replace(tzinfo=timezone.utc)
|
|
236
|
+
return dt
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def get_namespace_freshness(namespace: str) -> Optional[float]:
|
|
240
|
+
"""Return age-in-days of the namespace's max fetched_at.
|
|
241
|
+
|
|
242
|
+
Returns None if:
|
|
243
|
+
- The namespace does not exist or is empty.
|
|
244
|
+
- No fetched_at metadata is present on any sampled record.
|
|
245
|
+
- Any error occurs reaching Pinecone (treated as "unknown -> refetch").
|
|
246
|
+
|
|
247
|
+
Sampling strategy: the integrated-embedding index does not accept raw
|
|
248
|
+
vectors to .query() (that API is for inference-disabled indexes). We
|
|
249
|
+
sample one record via list() + fetch() and read its fetched_at
|
|
250
|
+
metadata. All records in a namespace share a common upsert timestamp
|
|
251
|
+
(upsert_corpus stamps them with a single `now`), so one sample is
|
|
252
|
+
sufficient for warm-vs-cold decisions under the 30-day TTL.
|
|
253
|
+
|
|
254
|
+
Plan 89-03 proposed a raw-vector query for this purpose -- that would
|
|
255
|
+
raise on an integrated-embedding index. Rule 1 bug fix: sample via
|
|
256
|
+
list+fetch instead. The behavioral contract (age or None) is preserved.
|
|
257
|
+
"""
|
|
258
|
+
try:
|
|
259
|
+
idx = ensure_index()
|
|
260
|
+
except Exception as e:
|
|
261
|
+
print(f"rs_cache: freshness check skipped ({e})", file=sys.stderr)
|
|
262
|
+
return None
|
|
263
|
+
|
|
264
|
+
if _namespace_vector_count(idx, namespace) == 0:
|
|
265
|
+
return None
|
|
266
|
+
|
|
267
|
+
sample_id: Optional[str] = None
|
|
268
|
+
try:
|
|
269
|
+
for ids_batch in idx.list(namespace=namespace, limit=1):
|
|
270
|
+
if ids_batch:
|
|
271
|
+
sample_id = ids_batch[0]
|
|
272
|
+
break
|
|
273
|
+
except Exception:
|
|
274
|
+
return None
|
|
275
|
+
|
|
276
|
+
if not sample_id:
|
|
277
|
+
return None
|
|
278
|
+
|
|
279
|
+
try:
|
|
280
|
+
fetched = idx.fetch(ids=[sample_id], namespace=namespace)
|
|
281
|
+
except Exception:
|
|
282
|
+
return None
|
|
283
|
+
|
|
284
|
+
vectors_map: Dict[str, Any] = {}
|
|
285
|
+
vectors_attr = getattr(fetched, "vectors", None)
|
|
286
|
+
if isinstance(vectors_attr, dict):
|
|
287
|
+
vectors_map = vectors_attr
|
|
288
|
+
else:
|
|
289
|
+
try:
|
|
290
|
+
vectors_map = fetched.to_dict().get("vectors", {}) or {}
|
|
291
|
+
except Exception:
|
|
292
|
+
vectors_map = {}
|
|
293
|
+
|
|
294
|
+
rec = vectors_map.get(sample_id)
|
|
295
|
+
if rec is None:
|
|
296
|
+
return None
|
|
297
|
+
|
|
298
|
+
metadata: Dict[str, Any] = {}
|
|
299
|
+
if isinstance(rec, dict):
|
|
300
|
+
metadata = rec.get("metadata", {}) or {}
|
|
301
|
+
else:
|
|
302
|
+
metadata = getattr(rec, "metadata", {}) or {}
|
|
303
|
+
|
|
304
|
+
fetched_at = _parse_fetched_at(metadata.get("fetched_at"))
|
|
305
|
+
if fetched_at is None:
|
|
306
|
+
return None
|
|
307
|
+
|
|
308
|
+
now = datetime.now(timezone.utc)
|
|
309
|
+
delta = now - fetched_at
|
|
310
|
+
return max(0.0, delta.total_seconds() / 86400.0)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
# --- Upsert ------------------------------------------------------------------
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _build_records(documents: Sequence[Dict[str, Any]], stamp: str) -> List[Dict[str, Any]]:
|
|
317
|
+
records: List[Dict[str, Any]] = []
|
|
318
|
+
for d in documents:
|
|
319
|
+
external_id = (d.get("external_id") or "").strip()
|
|
320
|
+
if not external_id:
|
|
321
|
+
# Skip records without a stable id -- they cannot be retrieved
|
|
322
|
+
# deterministically and would pollute the namespace.
|
|
323
|
+
continue
|
|
324
|
+
abstract = (d.get("abstract") or "").strip()
|
|
325
|
+
if not abstract:
|
|
326
|
+
continue
|
|
327
|
+
rec: Dict[str, Any] = {
|
|
328
|
+
"_id": external_id,
|
|
329
|
+
"abstract": abstract,
|
|
330
|
+
"source": (d.get("source") or "unknown")[:64],
|
|
331
|
+
"doi": (d.get("doi") or "")[:256],
|
|
332
|
+
"title": (d.get("title") or "")[:500],
|
|
333
|
+
"year": int(d.get("year") or 0),
|
|
334
|
+
"fetched_at": stamp,
|
|
335
|
+
}
|
|
336
|
+
records.append(rec)
|
|
337
|
+
return records
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def upsert_corpus(topic: str, documents: Sequence[Dict[str, Any]]) -> str:
|
|
341
|
+
"""Upsert fetched docs into the topic's namespace. Returns the namespace.
|
|
342
|
+
|
|
343
|
+
Guardrail: raises ValueError when the corpus exceeds MAX_NAMESPACE_VECTORS
|
|
344
|
+
so a single topic cannot silently balloon into a 100k-vector namespace.
|
|
345
|
+
Plan 89-03 Risk 3 mitigation -- the caller should shard by year or
|
|
346
|
+
scope the topic tighter before re-running.
|
|
347
|
+
|
|
348
|
+
fetched_at is stamped once per call. All records in the batch share the
|
|
349
|
+
same timestamp, which lets get_namespace_freshness sample any one record
|
|
350
|
+
and infer the whole namespace's TTL position.
|
|
351
|
+
"""
|
|
352
|
+
if len(documents) > MAX_NAMESPACE_VECTORS:
|
|
353
|
+
raise ValueError(
|
|
354
|
+
f"rs_cache: topic {topic!r} has {len(documents)} docs > "
|
|
355
|
+
f"{MAX_NAMESPACE_VECTORS}. Shard by year or tighten the topic."
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
idx = ensure_index()
|
|
359
|
+
ns = namespace_slug(topic)
|
|
360
|
+
stamp = datetime.now(timezone.utc).isoformat()
|
|
361
|
+
records = _build_records(documents, stamp)
|
|
362
|
+
|
|
363
|
+
if not records:
|
|
364
|
+
# Nothing usable; keep behavior predictable and do not touch the
|
|
365
|
+
# namespace. Upstream will treat this as a miss next run.
|
|
366
|
+
return ns
|
|
367
|
+
|
|
368
|
+
for i in range(0, len(records), UPSERT_BATCH_SIZE):
|
|
369
|
+
batch = records[i:i + UPSERT_BATCH_SIZE]
|
|
370
|
+
idx.upsert_records(namespace=ns, records=batch)
|
|
371
|
+
|
|
372
|
+
return ns
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# --- Query ------------------------------------------------------------------
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def query_namespace(
|
|
379
|
+
namespace: str,
|
|
380
|
+
query_text: str,
|
|
381
|
+
top_k: int = 100,
|
|
382
|
+
) -> Any:
|
|
383
|
+
"""Run a text query against the namespace. Integrated embedding at search
|
|
384
|
+
time -- Pinecone embeds the query with the same multilingual-e5-large
|
|
385
|
+
model used at upsert.
|
|
386
|
+
|
|
387
|
+
Returns the raw SearchRecordsResponse. Callers walk `.result.hits` (or
|
|
388
|
+
equivalent) to extract ids and scores.
|
|
389
|
+
"""
|
|
390
|
+
idx = ensure_index()
|
|
391
|
+
return idx.search(
|
|
392
|
+
namespace=namespace,
|
|
393
|
+
query={"inputs": {"text": query_text}, "top_k": max(1, int(top_k))},
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def fetch_all_from_namespace(
|
|
398
|
+
namespace: str,
|
|
399
|
+
limit: int = MAX_NAMESPACE_VECTORS,
|
|
400
|
+
) -> List[Dict[str, Any]]:
|
|
401
|
+
"""Retrieve records (id + values + metadata) from a namespace.
|
|
402
|
+
|
|
403
|
+
Used by scripts/rs-engine.py --mode external warm path to build the
|
|
404
|
+
semantic similarity matrix from cached vectors instead of re-embedding
|
|
405
|
+
on every run.
|
|
406
|
+
|
|
407
|
+
Pinecone `fetch` returns records with `.values` (1024-dim embedding) and
|
|
408
|
+
`.metadata` (abstract, title, doi, year, source, fetched_at). On an
|
|
409
|
+
integrated-embedding index, values are populated at upsert time.
|
|
410
|
+
|
|
411
|
+
`limit` caps results; the function returns up to `limit` records in
|
|
412
|
+
list() order (Pinecone does not guarantee ordering). Use
|
|
413
|
+
MAX_NAMESPACE_VECTORS when the caller wants everything.
|
|
414
|
+
"""
|
|
415
|
+
if limit <= 0:
|
|
416
|
+
return []
|
|
417
|
+
|
|
418
|
+
idx = ensure_index()
|
|
419
|
+
out: List[Dict[str, Any]] = []
|
|
420
|
+
|
|
421
|
+
for ids_batch in idx.list(namespace=namespace, limit=LIST_BATCH_SIZE):
|
|
422
|
+
if not ids_batch:
|
|
423
|
+
continue
|
|
424
|
+
try:
|
|
425
|
+
fetched = idx.fetch(ids=ids_batch, namespace=namespace)
|
|
426
|
+
except Exception as e:
|
|
427
|
+
print(f"rs_cache: fetch batch failed ({e})", file=sys.stderr)
|
|
428
|
+
continue
|
|
429
|
+
|
|
430
|
+
vectors_map: Dict[str, Any] = {}
|
|
431
|
+
vectors_attr = getattr(fetched, "vectors", None)
|
|
432
|
+
if isinstance(vectors_attr, dict):
|
|
433
|
+
vectors_map = vectors_attr
|
|
434
|
+
else:
|
|
435
|
+
try:
|
|
436
|
+
vectors_map = fetched.to_dict().get("vectors", {}) or {}
|
|
437
|
+
except Exception:
|
|
438
|
+
vectors_map = {}
|
|
439
|
+
|
|
440
|
+
for rid, rec in vectors_map.items():
|
|
441
|
+
if isinstance(rec, dict):
|
|
442
|
+
values = rec.get("values") or []
|
|
443
|
+
metadata = rec.get("metadata", {}) or {}
|
|
444
|
+
else:
|
|
445
|
+
values = list(getattr(rec, "values", []) or [])
|
|
446
|
+
metadata = getattr(rec, "metadata", {}) or {}
|
|
447
|
+
out.append({
|
|
448
|
+
"id": rid,
|
|
449
|
+
"values": list(values) if values is not None else [],
|
|
450
|
+
"metadata": dict(metadata) if isinstance(metadata, dict) else {},
|
|
451
|
+
})
|
|
452
|
+
if len(out) >= limit:
|
|
453
|
+
return out
|
|
454
|
+
|
|
455
|
+
return out
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
# --- TTL helpers (public for callers that want policy control) ------------
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def is_fresh(age_days: Optional[float], ttl_days: int = TTL_DAYS) -> bool:
|
|
462
|
+
"""True when the namespace age is known and under the TTL."""
|
|
463
|
+
if age_days is None:
|
|
464
|
+
return False
|
|
465
|
+
return age_days <= ttl_days
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
__all__ = [
|
|
469
|
+
"INDEX_NAME",
|
|
470
|
+
"TTL_DAYS",
|
|
471
|
+
"MAX_NAMESPACE_VECTORS",
|
|
472
|
+
"namespace_slug",
|
|
473
|
+
"ensure_index",
|
|
474
|
+
"get_namespace_freshness",
|
|
475
|
+
"upsert_corpus",
|
|
476
|
+
"query_namespace",
|
|
477
|
+
"fetch_all_from_namespace",
|
|
478
|
+
"is_fresh",
|
|
479
|
+
]
|