@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,564 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Mindrian. BSL 1.1.
|
|
3
|
+
* Phase 89.2 Plan 03 -- Patents external-egress fetcher.
|
|
4
|
+
* Phase 94 Plan 05 amendment (2026-04-28): envelope wrap only.
|
|
5
|
+
* Free-tier paths (google_patents / uspto) preserved byte-identical;
|
|
6
|
+
* the wrap layer adds {tier, source, results} on top of the existing
|
|
7
|
+
* {patents, telemetry} return. tier='paid' annotates that a real
|
|
8
|
+
* keyless API tier produced data; backward-compat patents[] key is
|
|
9
|
+
* preserved for downstream consumers. Per Canon Part 4 the tier
|
|
10
|
+
* annotation feeds the section-8 trace web_research_tier field; per
|
|
11
|
+
* Canon Part 7 envelope wrap reuses the existing Phase 89.2 fetcher.
|
|
12
|
+
*
|
|
13
|
+
* Two sources covered with one Canon Part 8 chokepoint:
|
|
14
|
+
* google_patents no API key patents.google.com search-as-html;
|
|
15
|
+
* parser scrapes JSON-LD <script> tags
|
|
16
|
+
* (no cheerio; pure regex extraction)
|
|
17
|
+
* uspto no API key USPTO Open Data Portal search API;
|
|
18
|
+
* returns JSON
|
|
19
|
+
*
|
|
20
|
+
* Single chokepoint: buildPatentsQuery(query, source, opts) is the ONLY
|
|
21
|
+
* function that constructs an outbound URL. Every call invokes
|
|
22
|
+
* auditQueryString(query, 'patents') from rs-egress-prompts.cjs BEFORE
|
|
23
|
+
* the URL is returned. ExternalEgressViolation throws pre-egress on any
|
|
24
|
+
* FORBIDDEN_PATTERNS hit, so adversarial input never reaches the wire.
|
|
25
|
+
*
|
|
26
|
+
* Per-source rate-limit graceful degradation per Phase 88.6-03 pattern
|
|
27
|
+
* (mirrors lib/core/rs-fetcher-academic.cjs byte-for-byte):
|
|
28
|
+
* 429 / 503 -> recordTelemetry(status='rate_limited') + return empty
|
|
29
|
+
* for that source + continue with remaining sources
|
|
30
|
+
* timeout -> recordTelemetry(status='timeout') + continue
|
|
31
|
+
* parse err -> recordTelemetry(status='api_error') + continue
|
|
32
|
+
* budget==0 -> skip source (synthetic 'budget_exhausted' on returned
|
|
33
|
+
* telemetry; not in v1 ALLOWED_STATUSES so not persisted)
|
|
34
|
+
*
|
|
35
|
+
* NEVER throws on rate-limit. ONLY throws on Canon Part 8 violation.
|
|
36
|
+
*
|
|
37
|
+
* Network: native Node 18+ global fetch. AbortController gives a per-request
|
|
38
|
+
* 10s default timeout. NO node-fetch, NO axios, NO cheerio, NO additional
|
|
39
|
+
* npm dep.
|
|
40
|
+
*
|
|
41
|
+
* Output shape per patent (after dedupe):
|
|
42
|
+
* { patent_id, title, abstract, inventors[], assignee, filing_date,
|
|
43
|
+
* source, fetched_at }
|
|
44
|
+
*
|
|
45
|
+
* Pure CJS, zero npm deps, node built-ins only beyond the three rs-egress-*
|
|
46
|
+
* primitives shipped in Wave 1 (Plan 89.2-01).
|
|
47
|
+
*/
|
|
48
|
+
'use strict';
|
|
49
|
+
|
|
50
|
+
const { ExternalEgressViolation } = require('./rs-egress-violations.cjs');
|
|
51
|
+
const { auditQueryString } = require('./rs-egress-prompts.cjs');
|
|
52
|
+
const {
|
|
53
|
+
recordTelemetry,
|
|
54
|
+
computeRemainingBudget,
|
|
55
|
+
DEFAULT_BUDGETS,
|
|
56
|
+
} = require('./rs-egress-telemetry.cjs');
|
|
57
|
+
|
|
58
|
+
// ---------- Frozen invariants ----------
|
|
59
|
+
|
|
60
|
+
// Iteration order is deliberate: google_patents first because Google's
|
|
61
|
+
// canonicalized patent_id is the strongest dedupe signal. uspto second
|
|
62
|
+
// so its records back-fill any patents Google misses on the first sweep.
|
|
63
|
+
const SOURCES = Object.freeze(['google_patents', 'uspto']);
|
|
64
|
+
|
|
65
|
+
// Both sources are no-key. Object kept for parity with the academic
|
|
66
|
+
// fetcher pattern; consumers MUST NOT depend on its emptiness because
|
|
67
|
+
// future paid patents APIs (Patsnap, Derwent) may add env-gated rows.
|
|
68
|
+
const SOURCE_ENV_VARS = Object.freeze({});
|
|
69
|
+
|
|
70
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
71
|
+
|
|
72
|
+
const USER_AGENT = 'MindrianOS-Plugin/1.11.0 (https://github.com/jsagir/mindrian-os-plugin)';
|
|
73
|
+
|
|
74
|
+
// Per-source endpoint base URLs.
|
|
75
|
+
const ENDPOINTS = Object.freeze({
|
|
76
|
+
google_patents: 'https://patents.google.com/',
|
|
77
|
+
uspto: 'https://api.uspto.gov/ds-api/oa_actions/v1/records',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// ---------- buildPatentsQuery (THE chokepoint) ----------
|
|
81
|
+
//
|
|
82
|
+
// This is the ONLY function in the module that constructs an outbound URL.
|
|
83
|
+
// Every per-source dispatcher invokes it. auditQueryString runs before the
|
|
84
|
+
// URL is returned, so adversarial input throws ExternalEgressViolation
|
|
85
|
+
// pre-egress and the URL is never built (and never reaches fetch()).
|
|
86
|
+
//
|
|
87
|
+
// Returns one of:
|
|
88
|
+
// { skip: true, reason: 'api_key_missing' } when env var absent for gated source
|
|
89
|
+
// { skip: false, url, headers, method, source } when ready to fetch
|
|
90
|
+
//
|
|
91
|
+
// Throws:
|
|
92
|
+
// TypeError if query is not a non-empty string or source unknown
|
|
93
|
+
// ExternalEgressViolation if query matches FORBIDDEN_PATTERNS
|
|
94
|
+
|
|
95
|
+
function buildPatentsQuery(query, source, opts) {
|
|
96
|
+
if (typeof query !== 'string' || query.length === 0) {
|
|
97
|
+
throw new TypeError('buildPatentsQuery: query must be a non-empty string');
|
|
98
|
+
}
|
|
99
|
+
if (!SOURCES.includes(source)) {
|
|
100
|
+
throw new TypeError('buildPatentsQuery: unknown source: ' + String(source));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Canon Part 8 chokepoint: throws on adversarial query BEFORE URL build.
|
|
104
|
+
auditQueryString(query, 'patents');
|
|
105
|
+
|
|
106
|
+
// Env-var gate for paid sources (none today; preserved for shape parity).
|
|
107
|
+
const envVar = SOURCE_ENV_VARS[source];
|
|
108
|
+
if (envVar && !process.env[envVar]) {
|
|
109
|
+
return { skip: true, reason: 'api_key_missing' };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const headers = {
|
|
113
|
+
'User-Agent': USER_AGENT,
|
|
114
|
+
'Accept': source === 'google_patents' ? 'text/html' : 'application/json',
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const encoded = encodeURIComponent(query);
|
|
118
|
+
let url;
|
|
119
|
+
switch (source) {
|
|
120
|
+
case 'google_patents': {
|
|
121
|
+
// No-key path: HTML response carrying JSON-LD <script> tags. The
|
|
122
|
+
// ?q + ?oq pair mirrors what patents.google.com search uses; the
|
|
123
|
+
// parser is regex-based so the HTML/JSON-LD shape is the contract.
|
|
124
|
+
url = ENDPOINTS.google_patents
|
|
125
|
+
+ '?q=' + encoded
|
|
126
|
+
+ '&oq=' + encoded;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case 'uspto': {
|
|
130
|
+
// USPTO Open Data Portal. JSON response. ~50 req/day budget per
|
|
131
|
+
// 89.2-CONTEXT.md. No API key for basic search.
|
|
132
|
+
url = ENDPOINTS.uspto
|
|
133
|
+
+ '?searchText=' + encoded;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
default:
|
|
137
|
+
// SOURCES list is frozen; this path is unreachable but the linter
|
|
138
|
+
// appreciates the explicit fallthrough.
|
|
139
|
+
throw new TypeError('buildPatentsQuery: unhandled source: ' + source);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return { skip: false, url: url, headers: headers, method: 'GET', source: source };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ---------- fetchWithTimeout (the ONE native fetch call site) ----------
|
|
146
|
+
//
|
|
147
|
+
// Per the chokepoint exclusivity rule: every per-source dispatcher routes
|
|
148
|
+
// through this helper. This is the only place that touches global.fetch.
|
|
149
|
+
// Returns the raw Response on success; throws on network error or timeout.
|
|
150
|
+
|
|
151
|
+
async function fetchWithTimeout(built, opts) {
|
|
152
|
+
const timeoutMs = (opts && typeof opts.timeoutMs === 'number') ? opts.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
153
|
+
const controller = new AbortController();
|
|
154
|
+
const t = setTimeout(function () { controller.abort(); }, timeoutMs);
|
|
155
|
+
try {
|
|
156
|
+
const res = await fetch(built.url, {
|
|
157
|
+
method: built.method,
|
|
158
|
+
headers: built.headers,
|
|
159
|
+
signal: controller.signal,
|
|
160
|
+
});
|
|
161
|
+
return res;
|
|
162
|
+
} finally {
|
|
163
|
+
clearTimeout(t);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ---------- parseRateLimit ----------
|
|
168
|
+
//
|
|
169
|
+
// Pulls a remaining-budget signal out of common HTTP headers. Returns
|
|
170
|
+
// undefined if absent. The shape varies per source so we probe a few names.
|
|
171
|
+
|
|
172
|
+
function parseRateLimit(headers) {
|
|
173
|
+
if (!headers) return undefined;
|
|
174
|
+
const probes = ['x-ratelimit-remaining', 'X-RateLimit-Remaining', 'ratelimit-remaining'];
|
|
175
|
+
for (const k of probes) {
|
|
176
|
+
let v;
|
|
177
|
+
if (typeof headers.get === 'function') {
|
|
178
|
+
v = headers.get(k);
|
|
179
|
+
} else if (Object.prototype.hasOwnProperty.call(headers, k)) {
|
|
180
|
+
v = headers[k];
|
|
181
|
+
}
|
|
182
|
+
if (v !== undefined && v !== null) {
|
|
183
|
+
const n = parseInt(String(v), 10);
|
|
184
|
+
if (!Number.isNaN(n)) return n;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ---------- Dedup key + dedupe ----------
|
|
191
|
+
//
|
|
192
|
+
// patent_id is canonical (USPTO + Google Patents both emit the same
|
|
193
|
+
// patent_id for the same patent). First-seen wins so SOURCES iteration
|
|
194
|
+
// order determines tie-breaking; google_patents iterates first.
|
|
195
|
+
|
|
196
|
+
function dedupKey(p) {
|
|
197
|
+
if (p && typeof p.patent_id === 'string' && p.patent_id.trim().length > 0) {
|
|
198
|
+
return 'patent:' + p.patent_id.trim().toUpperCase();
|
|
199
|
+
}
|
|
200
|
+
// Defensive fallback: title + first-inventor lastname. Should never
|
|
201
|
+
// be needed for real responses but keeps dedupe deterministic on
|
|
202
|
+
// malformed inputs.
|
|
203
|
+
const titleNorm = (p && typeof p.title === 'string')
|
|
204
|
+
? p.title.toLowerCase().replace(/[^a-z0-9\s]+/g, ' ').replace(/\s+/g, ' ').trim()
|
|
205
|
+
: '';
|
|
206
|
+
let firstInventor = '';
|
|
207
|
+
if (p && Array.isArray(p.inventors) && p.inventors.length > 0) {
|
|
208
|
+
const a = String(p.inventors[0] || '');
|
|
209
|
+
const parts = a.split(/[\s,]+/);
|
|
210
|
+
firstInventor = parts.length > 0 ? parts[0].toLowerCase() : '';
|
|
211
|
+
}
|
|
212
|
+
if (titleNorm) {
|
|
213
|
+
return 'title:' + titleNorm + '|' + firstInventor;
|
|
214
|
+
}
|
|
215
|
+
return 'unknown:' + JSON.stringify(p || {});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function dedupe(patents) {
|
|
219
|
+
const seen = new Set();
|
|
220
|
+
const out = [];
|
|
221
|
+
for (const p of patents) {
|
|
222
|
+
const key = dedupKey(p);
|
|
223
|
+
if (seen.has(key)) continue;
|
|
224
|
+
seen.add(key);
|
|
225
|
+
out.push(p);
|
|
226
|
+
}
|
|
227
|
+
return out;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ---------- Per-source response parsers ----------
|
|
231
|
+
|
|
232
|
+
// Google Patents: HTML with embedded JSON-LD <script type="application/ld+json">
|
|
233
|
+
// blocks carrying patent metadata. Pure regex extraction; no cheerio.
|
|
234
|
+
//
|
|
235
|
+
// Throws on a completely empty body (treated as api_error upstream); returns
|
|
236
|
+
// [] when no JSON-LD blocks are found (graceful: the page rendered but had
|
|
237
|
+
// no @type=Patent records).
|
|
238
|
+
|
|
239
|
+
function parseGooglePatentsResponse(htmlText) {
|
|
240
|
+
const out = [];
|
|
241
|
+
if (typeof htmlText !== 'string' || htmlText.length === 0) {
|
|
242
|
+
throw new Error('google_patents: empty body');
|
|
243
|
+
}
|
|
244
|
+
const re = /<script type="application\/ld\+json">([\s\S]*?)<\/script>/gi;
|
|
245
|
+
let m;
|
|
246
|
+
while ((m = re.exec(htmlText)) !== null) {
|
|
247
|
+
let obj = null;
|
|
248
|
+
try {
|
|
249
|
+
obj = JSON.parse(m[1]);
|
|
250
|
+
} catch (_e) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (!obj || typeof obj !== 'object') continue;
|
|
254
|
+
if (obj['@type'] !== 'Patent' && obj['@type'] !== 'Product') continue;
|
|
255
|
+
const inventors = [];
|
|
256
|
+
if (Array.isArray(obj.inventor)) {
|
|
257
|
+
for (const inv of obj.inventor.slice(0, 10)) {
|
|
258
|
+
if (inv && typeof inv === 'object' && typeof inv.name === 'string') {
|
|
259
|
+
inventors.push(inv.name);
|
|
260
|
+
} else if (typeof inv === 'string') {
|
|
261
|
+
inventors.push(inv);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
let assignee = '';
|
|
266
|
+
if (obj.assignee && typeof obj.assignee === 'object' && typeof obj.assignee.name === 'string') {
|
|
267
|
+
assignee = obj.assignee.name;
|
|
268
|
+
} else if (typeof obj.assignee === 'string') {
|
|
269
|
+
assignee = obj.assignee;
|
|
270
|
+
}
|
|
271
|
+
out.push({
|
|
272
|
+
patent_id: typeof obj.patentNumber === 'string' ? obj.patentNumber : '',
|
|
273
|
+
title: typeof obj.name === 'string' ? obj.name : '',
|
|
274
|
+
abstract: typeof obj.description === 'string' ? obj.description : '',
|
|
275
|
+
inventors: inventors,
|
|
276
|
+
assignee: assignee,
|
|
277
|
+
filing_date: typeof obj.filingDate === 'string' ? obj.filingDate : '',
|
|
278
|
+
source: 'google_patents',
|
|
279
|
+
fetched_at: new Date().toISOString(),
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
return out;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// USPTO: JSON response with results[] (or records[] in legacy variants).
|
|
286
|
+
// Each record carries patentNumber + patentTitle + patentAbstract +
|
|
287
|
+
// inventorName[] + assigneeEntityName + filingDate.
|
|
288
|
+
|
|
289
|
+
function parseUsptoResponse(json) {
|
|
290
|
+
const out = [];
|
|
291
|
+
if (!json || typeof json !== 'object') return out;
|
|
292
|
+
// Accept either results[] (modern) or records[] (legacy) array shape.
|
|
293
|
+
const records = Array.isArray(json.results) ? json.results
|
|
294
|
+
: (Array.isArray(json.records) ? json.records : []);
|
|
295
|
+
for (const r of records) {
|
|
296
|
+
if (!r || typeof r !== 'object') continue;
|
|
297
|
+
let inventors = [];
|
|
298
|
+
if (Array.isArray(r.inventorName)) {
|
|
299
|
+
inventors = r.inventorName.slice(0, 10).map(String);
|
|
300
|
+
} else if (typeof r.inventorName === 'string') {
|
|
301
|
+
inventors = [r.inventorName];
|
|
302
|
+
}
|
|
303
|
+
out.push({
|
|
304
|
+
patent_id: typeof r.patentNumber === 'string' ? r.patentNumber : '',
|
|
305
|
+
title: typeof r.patentTitle === 'string' ? r.patentTitle : '',
|
|
306
|
+
abstract: typeof r.patentAbstract === 'string' ? r.patentAbstract : '',
|
|
307
|
+
inventors: inventors,
|
|
308
|
+
assignee: typeof r.assigneeEntityName === 'string' ? r.assigneeEntityName : '',
|
|
309
|
+
filing_date: typeof r.filingDate === 'string' ? r.filingDate : '',
|
|
310
|
+
source: 'uspto',
|
|
311
|
+
fetched_at: new Date().toISOString(),
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return out;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function parseSourceResponse(payload, source) {
|
|
318
|
+
switch (source) {
|
|
319
|
+
case 'google_patents': return parseGooglePatentsResponse(payload);
|
|
320
|
+
case 'uspto': return parseUsptoResponse(payload);
|
|
321
|
+
default: return [];
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ---------- normalizePatent ----------
|
|
326
|
+
//
|
|
327
|
+
// Final shape guarantee. Per-source parsers already produce this shape
|
|
328
|
+
// but normalizePatent is exposed so future call sites can canonicalize
|
|
329
|
+
// hand-constructed records.
|
|
330
|
+
|
|
331
|
+
function normalizePatent(raw) {
|
|
332
|
+
return {
|
|
333
|
+
patent_id: raw && raw.patent_id ? String(raw.patent_id) : '',
|
|
334
|
+
title: raw && raw.title ? String(raw.title) : '',
|
|
335
|
+
abstract: raw && raw.abstract ? String(raw.abstract) : '',
|
|
336
|
+
inventors: raw && Array.isArray(raw.inventors) ? raw.inventors.slice(0, 10).map(String) : [],
|
|
337
|
+
assignee: raw && raw.assignee ? String(raw.assignee) : '',
|
|
338
|
+
filing_date: raw && raw.filing_date ? String(raw.filing_date) : '',
|
|
339
|
+
source: raw && raw.source ? String(raw.source) : '',
|
|
340
|
+
fetched_at: raw && raw.fetched_at ? String(raw.fetched_at) : new Date().toISOString(),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ---------- fetchPatents ----------
|
|
345
|
+
//
|
|
346
|
+
// Top-level orchestrator. Iterates SOURCES in frozen order; per source
|
|
347
|
+
// iterates the input queries. Per (source, query) tuple:
|
|
348
|
+
// 1. Check budget. budget==0 -> skip source for this run.
|
|
349
|
+
// 2. Build query via chokepoint (throws ExternalEgressViolation on adversarial).
|
|
350
|
+
// 3. If skip (api_key_missing) -> recordTelemetry + continue.
|
|
351
|
+
// 4. fetchWithTimeout -> on timeout: recordTelemetry + continue.
|
|
352
|
+
// 5. status 429/503 -> recordTelemetry(rate_limited) + continue.
|
|
353
|
+
// 6. parse response. parse error -> recordTelemetry(api_error) + continue.
|
|
354
|
+
// 7. recordTelemetry(ok) + accumulate patents.
|
|
355
|
+
// After all sources, dedupe and return.
|
|
356
|
+
|
|
357
|
+
async function fetchPatents(queries, opts) {
|
|
358
|
+
if (!Array.isArray(queries)) {
|
|
359
|
+
throw new TypeError('fetchPatents: queries must be an array of non-empty strings');
|
|
360
|
+
}
|
|
361
|
+
for (const q of queries) {
|
|
362
|
+
if (typeof q !== 'string' || q.length === 0) {
|
|
363
|
+
throw new TypeError('fetchPatents: each query must be a non-empty string');
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
opts = opts || {};
|
|
367
|
+
const budgetOverrides = opts.budget || {};
|
|
368
|
+
|
|
369
|
+
// Pre-flight Canon Part 8 audit: scan ALL queries before iterating sources.
|
|
370
|
+
// Without this, an adversarial query in position N would run sources for
|
|
371
|
+
// queries 0..N-1 first (issuing real fetch() calls), then throw on N. The
|
|
372
|
+
// tests assert ZERO captured URLs on adversarial input, so the audit must
|
|
373
|
+
// happen before any source loop runs. SOURCES[0] is used as the surface
|
|
374
|
+
// anchor; the throw still carries meta.surface='patents' from the
|
|
375
|
+
// chokepoint helper.
|
|
376
|
+
for (const q of queries) {
|
|
377
|
+
auditQueryString(q, 'patents');
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const out = { patents: [], telemetry: [] };
|
|
381
|
+
|
|
382
|
+
for (const source of SOURCES) {
|
|
383
|
+
const budgetCap = (typeof budgetOverrides[source] === 'number')
|
|
384
|
+
? budgetOverrides[source]
|
|
385
|
+
: DEFAULT_BUDGETS[source];
|
|
386
|
+
const remaining = computeRemainingBudget(source, budgetCap);
|
|
387
|
+
if (remaining <= 0) {
|
|
388
|
+
// Skip source for this run; budget itself is the trace. We do NOT
|
|
389
|
+
// call recordTelemetry here (status 'budget_exhausted' is not in
|
|
390
|
+
// ALLOWED_STATUSES for the v1 telemetry primitive).
|
|
391
|
+
out.telemetry.push({ source: source, status: 'budget_exhausted' });
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
for (const query of queries) {
|
|
396
|
+
// Build (chokepoint). Throws ExternalEgressViolation if adversarial,
|
|
397
|
+
// but the pre-flight audit above has already cleared every query.
|
|
398
|
+
// Re-running here is defense-in-depth: if a future code path mutates
|
|
399
|
+
// queries between the pre-flight and the loop, this still throws.
|
|
400
|
+
const built = buildPatentsQuery(query, source, opts);
|
|
401
|
+
|
|
402
|
+
if (built.skip) {
|
|
403
|
+
// env var missing for gated source.
|
|
404
|
+
recordTelemetry({
|
|
405
|
+
source: source,
|
|
406
|
+
query_text: query,
|
|
407
|
+
status: built.reason,
|
|
408
|
+
});
|
|
409
|
+
out.telemetry.push({ source: source, status: built.reason });
|
|
410
|
+
// No need to keep iterating queries for a source with no key:
|
|
411
|
+
// every query will hit the same gate. Break early to save work.
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
let res = null;
|
|
416
|
+
try {
|
|
417
|
+
res = await fetchWithTimeout(built, opts);
|
|
418
|
+
} catch (err) {
|
|
419
|
+
if (err && err.name === 'AbortError') {
|
|
420
|
+
recordTelemetry({
|
|
421
|
+
source: source,
|
|
422
|
+
query_text: query,
|
|
423
|
+
status: 'timeout',
|
|
424
|
+
});
|
|
425
|
+
out.telemetry.push({ source: source, status: 'timeout' });
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
recordTelemetry({
|
|
429
|
+
source: source,
|
|
430
|
+
query_text: query,
|
|
431
|
+
status: 'network_error',
|
|
432
|
+
});
|
|
433
|
+
out.telemetry.push({ source: source, status: 'network_error' });
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!res.ok) {
|
|
438
|
+
const httpStatus = res.status || 0;
|
|
439
|
+
if (httpStatus === 429 || httpStatus === 503) {
|
|
440
|
+
recordTelemetry({
|
|
441
|
+
source: source,
|
|
442
|
+
query_text: query,
|
|
443
|
+
status: 'rate_limited',
|
|
444
|
+
http_status: httpStatus,
|
|
445
|
+
});
|
|
446
|
+
out.telemetry.push({ source: source, status: 'rate_limited', http_status: httpStatus });
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
recordTelemetry({
|
|
450
|
+
source: source,
|
|
451
|
+
query_text: query,
|
|
452
|
+
status: 'api_error',
|
|
453
|
+
http_status: httpStatus,
|
|
454
|
+
});
|
|
455
|
+
out.telemetry.push({ source: source, status: 'api_error', http_status: httpStatus });
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
let parsed = null;
|
|
460
|
+
try {
|
|
461
|
+
// google_patents returns HTML; uspto returns JSON.
|
|
462
|
+
const payload = (source === 'google_patents') ? await res.text() : await res.json();
|
|
463
|
+
parsed = parseSourceResponse(payload, source);
|
|
464
|
+
} catch (_err) {
|
|
465
|
+
recordTelemetry({
|
|
466
|
+
source: source,
|
|
467
|
+
query_text: query,
|
|
468
|
+
status: 'api_error',
|
|
469
|
+
http_status: res.status || 0,
|
|
470
|
+
});
|
|
471
|
+
out.telemetry.push({ source: source, status: 'api_error', http_status: res.status || 0 });
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const rateRemaining = parseRateLimit(res.headers);
|
|
476
|
+
const recOpts = {
|
|
477
|
+
source: source,
|
|
478
|
+
query_text: query,
|
|
479
|
+
status: 'ok',
|
|
480
|
+
http_status: res.status || 200,
|
|
481
|
+
};
|
|
482
|
+
if (typeof rateRemaining === 'number') {
|
|
483
|
+
recOpts.rate_limit_remaining = rateRemaining;
|
|
484
|
+
}
|
|
485
|
+
recordTelemetry(recOpts);
|
|
486
|
+
out.telemetry.push({ source: source, status: 'ok', http_status: res.status || 200 });
|
|
487
|
+
|
|
488
|
+
for (const p of parsed) {
|
|
489
|
+
out.patents.push(p);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// First-seen wins on dedupe; google_patents ran first so it wins
|
|
495
|
+
// patent_id ties.
|
|
496
|
+
out.patents = dedupe(out.patents);
|
|
497
|
+
|
|
498
|
+
// ---- Phase 94 Plan 05 amendment: envelope wrap ----
|
|
499
|
+
// Determine source tag from first telemetry row with status:'ok';
|
|
500
|
+
// fall back to SOURCES[0] when no source produced data so the
|
|
501
|
+
// envelope still has a valid source tag.
|
|
502
|
+
let source = SOURCES[0];
|
|
503
|
+
for (const t of out.telemetry) {
|
|
504
|
+
if (t && t.status === 'ok' && typeof t.source === 'string') {
|
|
505
|
+
source = t.source;
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
tier: 'paid',
|
|
511
|
+
source: source,
|
|
512
|
+
results: out.patents.slice(),
|
|
513
|
+
patents: out.patents,
|
|
514
|
+
telemetry: out.telemetry,
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// ---------- Per-source dispatchers ----------
|
|
519
|
+
//
|
|
520
|
+
// Convenience entry points for callers that want one source. Both
|
|
521
|
+
// route through fetchPatents internally (limiting SOURCES to the one
|
|
522
|
+
// requested) so the chokepoint exclusivity rule is preserved.
|
|
523
|
+
|
|
524
|
+
async function fetchOneSource(source, queries, opts) {
|
|
525
|
+
const orig = SOURCES.slice();
|
|
526
|
+
// Build a one-source orchestrator by delegating to fetchPatents with
|
|
527
|
+
// a budget map that zeroes out every other source. This keeps the
|
|
528
|
+
// chokepoint exclusivity invariant intact (no new fetch sites).
|
|
529
|
+
opts = opts || {};
|
|
530
|
+
const budget = Object.assign({}, opts.budget || {});
|
|
531
|
+
for (const s of orig) {
|
|
532
|
+
if (s !== source) budget[s] = 0;
|
|
533
|
+
}
|
|
534
|
+
const merged = Object.assign({}, opts, { budget: budget });
|
|
535
|
+
return fetchPatents(queries, merged);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
async function fetchGooglePatents(queries, opts) { return fetchOneSource('google_patents', queries, opts); }
|
|
539
|
+
async function fetchUspto(queries, opts) { return fetchOneSource('uspto', queries, opts); }
|
|
540
|
+
|
|
541
|
+
// ---------- Exports ----------
|
|
542
|
+
|
|
543
|
+
module.exports = {
|
|
544
|
+
fetchPatents,
|
|
545
|
+
buildPatentsQuery,
|
|
546
|
+
fetchGooglePatents,
|
|
547
|
+
fetchUspto,
|
|
548
|
+
// Test surface (private; do NOT consume in production).
|
|
549
|
+
_test: {
|
|
550
|
+
dedupe,
|
|
551
|
+
dedupKey,
|
|
552
|
+
normalizePatent,
|
|
553
|
+
fetchWithTimeout,
|
|
554
|
+
parseSourceResponse,
|
|
555
|
+
parseGooglePatentsResponse,
|
|
556
|
+
parseUsptoResponse,
|
|
557
|
+
parseRateLimit,
|
|
558
|
+
SOURCES,
|
|
559
|
+
SOURCE_ENV_VARS,
|
|
560
|
+
ENDPOINTS,
|
|
561
|
+
DEFAULT_TIMEOUT_MS,
|
|
562
|
+
USER_AGENT,
|
|
563
|
+
},
|
|
564
|
+
};
|