stellavault 0.1.0 → 0.2.1
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/package.json +1 -1
- package/packages/cli/bin/ekh.js +2 -2
- package/packages/cli/dist/commands/federate-cmd.js +61 -31
- package/packages/core/dist/api/dashboard.d.ts +3 -0
- package/packages/core/{src/api/dashboard.ts → dist/api/dashboard.js} +8 -11
- package/packages/core/dist/api/graph-data.d.ts +11 -0
- package/packages/core/dist/api/graph-data.js +255 -0
- package/packages/core/dist/api/pwa.d.ts +3 -0
- package/packages/core/{src/api/pwa.ts → dist/api/pwa.js} +27 -32
- package/packages/core/dist/api/server.d.ts +16 -0
- package/packages/core/dist/api/server.js +647 -0
- package/packages/core/dist/capture/voice.d.ts +24 -0
- package/packages/core/dist/capture/voice.js +135 -0
- package/packages/core/{src/cloud/index.ts → dist/cloud/index.d.ts} +1 -0
- package/packages/core/dist/cloud/index.js +2 -0
- package/packages/core/dist/cloud/sync.d.ts +29 -0
- package/packages/core/dist/cloud/sync.js +137 -0
- package/packages/core/dist/config.d.ts +27 -0
- package/packages/core/dist/config.js +55 -0
- package/packages/core/dist/federation/credits.d.ts +26 -0
- package/packages/core/dist/federation/credits.js +56 -0
- package/packages/core/dist/federation/identity.d.ts +14 -0
- package/packages/core/dist/federation/identity.js +74 -0
- package/packages/core/{src/federation/index.ts → dist/federation/index.d.ts} +1 -2
- package/packages/core/dist/federation/index.js +5 -0
- package/packages/core/dist/federation/node.d.ts +31 -0
- package/packages/core/dist/federation/node.js +216 -0
- package/packages/core/dist/federation/privacy.d.ts +8 -0
- package/packages/core/dist/federation/privacy.js +40 -0
- package/packages/core/dist/federation/reputation.d.ts +37 -0
- package/packages/core/dist/federation/reputation.js +139 -0
- package/packages/core/dist/federation/search.d.ts +19 -0
- package/packages/core/dist/federation/search.js +101 -0
- package/packages/core/dist/federation/sharing.d.ts +72 -0
- package/packages/core/dist/federation/sharing.js +246 -0
- package/packages/core/dist/federation/trust.d.ts +15 -0
- package/packages/core/dist/federation/trust.js +60 -0
- package/packages/core/dist/federation/types.d.ts +40 -0
- package/packages/core/dist/federation/types.js +3 -0
- package/packages/core/dist/i18n/index.d.ts +6 -0
- package/packages/core/dist/i18n/index.js +81 -0
- package/packages/core/{src/index.ts → dist/index.d.ts} +48 -67
- package/packages/core/dist/index.js +69 -0
- package/packages/core/dist/indexer/chunker.d.ts +14 -0
- package/packages/core/dist/indexer/chunker.js +148 -0
- package/packages/core/dist/indexer/embedder.d.ts +8 -0
- package/packages/core/dist/indexer/embedder.js +3 -0
- package/packages/core/dist/indexer/index.d.ts +28 -0
- package/packages/core/dist/indexer/index.js +74 -0
- package/packages/core/dist/indexer/local-embedder.d.ts +3 -0
- package/packages/core/dist/indexer/local-embedder.js +29 -0
- package/packages/core/dist/indexer/scanner.d.ts +11 -0
- package/packages/core/dist/indexer/scanner.js +137 -0
- package/packages/core/dist/indexer/watcher.d.ts +19 -0
- package/packages/core/dist/indexer/watcher.js +49 -0
- package/packages/core/dist/intelligence/contradiction-detector.d.ts +20 -0
- package/packages/core/dist/intelligence/contradiction-detector.js +115 -0
- package/packages/core/dist/intelligence/decay-engine.d.ts +27 -0
- package/packages/core/dist/intelligence/decay-engine.js +190 -0
- package/packages/core/dist/intelligence/duplicate-detector.d.ts +20 -0
- package/packages/core/dist/intelligence/duplicate-detector.js +55 -0
- package/packages/core/dist/intelligence/fsrs.d.ts +43 -0
- package/packages/core/dist/intelligence/fsrs.js +70 -0
- package/packages/core/dist/intelligence/gap-detector.d.ts +25 -0
- package/packages/core/dist/intelligence/gap-detector.js +78 -0
- package/packages/core/dist/intelligence/learning-path.d.ts +31 -0
- package/packages/core/dist/intelligence/learning-path.js +53 -0
- package/packages/core/dist/intelligence/notifications.d.ts +31 -0
- package/packages/core/dist/intelligence/notifications.js +65 -0
- package/packages/core/dist/intelligence/predictive-gaps.d.ts +14 -0
- package/packages/core/dist/intelligence/predictive-gaps.js +74 -0
- package/packages/core/dist/intelligence/semantic-versioning.d.ts +37 -0
- package/packages/core/dist/intelligence/semantic-versioning.js +68 -0
- package/packages/core/dist/intelligence/types.d.ts +28 -0
- package/packages/core/dist/intelligence/types.js +3 -0
- package/packages/core/dist/mcp/custom-tools.d.ts +29 -0
- package/packages/core/dist/mcp/custom-tools.js +70 -0
- package/packages/core/{src/mcp/index.ts → dist/mcp/index.d.ts} +1 -0
- package/packages/core/dist/mcp/index.js +2 -0
- package/packages/core/dist/mcp/server.d.ts +49 -0
- package/packages/core/dist/mcp/server.js +133 -0
- package/packages/core/dist/mcp/tools/agentic-graph.d.ts +87 -0
- package/packages/core/dist/mcp/tools/agentic-graph.js +88 -0
- package/packages/core/dist/mcp/tools/brief.d.ts +31 -0
- package/packages/core/dist/mcp/tools/brief.js +39 -0
- package/packages/core/dist/mcp/tools/decay.d.ts +33 -0
- package/packages/core/dist/mcp/tools/decay.js +32 -0
- package/packages/core/dist/mcp/tools/decision-journal.d.ts +78 -0
- package/packages/core/dist/mcp/tools/decision-journal.js +79 -0
- package/packages/core/dist/mcp/tools/export.d.ts +29 -0
- package/packages/core/dist/mcp/tools/export.js +60 -0
- package/packages/core/dist/mcp/tools/federated-search.d.ts +29 -0
- package/packages/core/dist/mcp/tools/federated-search.js +36 -0
- package/packages/core/dist/mcp/tools/generate-claude-md.d.ts +35 -0
- package/packages/core/dist/mcp/tools/generate-claude-md.js +107 -0
- package/packages/core/dist/mcp/tools/get-document.d.ts +35 -0
- package/packages/core/dist/mcp/tools/get-document.js +25 -0
- package/packages/core/dist/mcp/tools/get-related.d.ts +32 -0
- package/packages/core/dist/mcp/tools/get-related.js +33 -0
- package/packages/core/dist/mcp/tools/learning-path.d.ts +23 -0
- package/packages/core/dist/mcp/tools/learning-path.js +45 -0
- package/packages/core/dist/mcp/tools/list-topics.d.ts +15 -0
- package/packages/core/dist/mcp/tools/list-topics.js +18 -0
- package/packages/core/dist/mcp/tools/search.d.ts +39 -0
- package/packages/core/dist/mcp/tools/search.js +29 -0
- package/packages/core/dist/mcp/tools/snapshot.d.ts +47 -0
- package/packages/core/dist/mcp/tools/snapshot.js +84 -0
- package/packages/core/dist/multi-vault/index.d.ts +26 -0
- package/packages/core/dist/multi-vault/index.js +80 -0
- package/packages/core/dist/pack/creator.d.ts +21 -0
- package/packages/core/dist/pack/creator.js +105 -0
- package/packages/core/dist/pack/exporter.d.ts +4 -0
- package/packages/core/dist/pack/exporter.js +18 -0
- package/packages/core/dist/pack/importer.d.ts +10 -0
- package/packages/core/dist/pack/importer.js +55 -0
- package/packages/core/{src/pack/index.ts → dist/pack/index.d.ts} +1 -0
- package/packages/core/dist/pack/index.js +5 -0
- package/packages/core/dist/pack/marketplace.d.ts +14 -0
- package/packages/core/dist/pack/marketplace.js +90 -0
- package/packages/core/dist/pack/pii-masker.d.ts +7 -0
- package/packages/core/dist/pack/pii-masker.js +29 -0
- package/packages/core/dist/pack/types.d.ts +36 -0
- package/packages/core/dist/pack/types.js +3 -0
- package/packages/core/dist/plugins/index.d.ts +35 -0
- package/packages/core/dist/plugins/index.js +57 -0
- package/packages/core/dist/plugins/webhooks.d.ts +30 -0
- package/packages/core/dist/plugins/webhooks.js +79 -0
- package/packages/core/dist/search/bm25.d.ts +4 -0
- package/packages/core/dist/search/bm25.js +10 -0
- package/packages/core/dist/search/index.d.ts +13 -0
- package/packages/core/dist/search/index.js +63 -0
- package/packages/core/dist/search/rrf.d.ts +7 -0
- package/packages/core/dist/search/rrf.js +21 -0
- package/packages/core/dist/search/semantic.d.ts +5 -0
- package/packages/core/dist/search/semantic.js +6 -0
- package/packages/core/{src/store/index.ts → dist/store/index.d.ts} +1 -0
- package/packages/core/dist/store/index.js +2 -0
- package/packages/core/dist/store/sqlite-vec.d.ts +6 -0
- package/packages/core/dist/store/sqlite-vec.js +251 -0
- package/packages/core/dist/store/types.d.ts +20 -0
- package/packages/core/dist/store/types.js +3 -0
- package/packages/core/dist/team/index.d.ts +25 -0
- package/packages/core/dist/team/index.js +97 -0
- package/packages/core/dist/types/chunk.d.ts +23 -0
- package/packages/core/dist/types/chunk.js +3 -0
- package/packages/core/dist/types/document.d.ts +23 -0
- package/packages/core/dist/types/document.js +3 -0
- package/packages/core/dist/types/graph.d.ts +39 -0
- package/packages/core/dist/types/graph.js +3 -0
- package/packages/core/dist/types/index.d.ts +5 -0
- package/packages/core/dist/types/index.js +2 -0
- package/packages/core/dist/types/search.d.ts +39 -0
- package/packages/core/dist/types/search.js +3 -0
- package/packages/core/dist/utils/retry.d.ts +25 -0
- package/packages/core/dist/utils/retry.js +59 -0
- package/memory/MEMORY.md +0 -25
- package/packages/cli/dist/commands/brief-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/brief-cmd.js.map +0 -1
- package/packages/cli/dist/commands/capture-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/capture-cmd.js.map +0 -1
- package/packages/cli/dist/commands/card-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/card-cmd.js.map +0 -1
- package/packages/cli/dist/commands/clip-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/clip-cmd.js.map +0 -1
- package/packages/cli/dist/commands/cloud-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/cloud-cmd.js.map +0 -1
- package/packages/cli/dist/commands/contradictions-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/contradictions-cmd.js.map +0 -1
- package/packages/cli/dist/commands/decay-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/decay-cmd.js.map +0 -1
- package/packages/cli/dist/commands/digest-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/digest-cmd.js.map +0 -1
- package/packages/cli/dist/commands/duplicates-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/duplicates-cmd.js.map +0 -1
- package/packages/cli/dist/commands/federate-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/federate-cmd.js.map +0 -1
- package/packages/cli/dist/commands/gaps-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/gaps-cmd.js.map +0 -1
- package/packages/cli/dist/commands/graph-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/graph-cmd.js.map +0 -1
- package/packages/cli/dist/commands/index-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/index-cmd.js.map +0 -1
- package/packages/cli/dist/commands/init-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/init-cmd.js.map +0 -1
- package/packages/cli/dist/commands/learn-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/learn-cmd.js.map +0 -1
- package/packages/cli/dist/commands/pack-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/pack-cmd.js.map +0 -1
- package/packages/cli/dist/commands/review-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/review-cmd.js.map +0 -1
- package/packages/cli/dist/commands/search-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/search-cmd.js.map +0 -1
- package/packages/cli/dist/commands/serve-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/serve-cmd.js.map +0 -1
- package/packages/cli/dist/commands/status-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/status-cmd.js.map +0 -1
- package/packages/cli/dist/commands/sync-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/sync-cmd.js.map +0 -1
- package/packages/cli/dist/commands/vault-cmd.d.ts.map +0 -1
- package/packages/cli/dist/commands/vault-cmd.js.map +0 -1
- package/packages/cli/dist/index.d.ts.map +0 -1
- package/packages/cli/dist/index.js.map +0 -1
- package/packages/cli/src/commands/brief-cmd.ts +0 -87
- package/packages/cli/src/commands/capture-cmd.ts +0 -34
- package/packages/cli/src/commands/card-cmd.ts +0 -29
- package/packages/cli/src/commands/clip-cmd.ts +0 -172
- package/packages/cli/src/commands/cloud-cmd.ts +0 -75
- package/packages/cli/src/commands/contradictions-cmd.ts +0 -41
- package/packages/cli/src/commands/decay-cmd.ts +0 -57
- package/packages/cli/src/commands/digest-cmd.ts +0 -89
- package/packages/cli/src/commands/duplicates-cmd.ts +0 -38
- package/packages/cli/src/commands/federate-cmd.ts +0 -236
- package/packages/cli/src/commands/gaps-cmd.ts +0 -40
- package/packages/cli/src/commands/graph-cmd.ts +0 -88
- package/packages/cli/src/commands/index-cmd.ts +0 -65
- package/packages/cli/src/commands/init-cmd.ts +0 -145
- package/packages/cli/src/commands/learn-cmd.ts +0 -56
- package/packages/cli/src/commands/pack-cmd.ts +0 -121
- package/packages/cli/src/commands/review-cmd.ts +0 -125
- package/packages/cli/src/commands/search-cmd.ts +0 -45
- package/packages/cli/src/commands/serve-cmd.ts +0 -17
- package/packages/cli/src/commands/status-cmd.ts +0 -37
- package/packages/cli/src/commands/sync-cmd.ts +0 -68
- package/packages/cli/src/commands/vault-cmd.ts +0 -64
- package/packages/cli/src/index.ts +0 -187
- package/packages/core/src/api/graph-data.ts +0 -286
- package/packages/core/src/api/server.ts +0 -660
- package/packages/core/src/capture/voice.ts +0 -168
- package/packages/core/src/cloud/sync.ts +0 -167
- package/packages/core/src/config.ts +0 -82
- package/packages/core/src/federation/credits.ts +0 -80
- package/packages/core/src/federation/hyperswarm.d.ts +0 -19
- package/packages/core/src/federation/identity.ts +0 -90
- package/packages/core/src/federation/node.ts +0 -235
- package/packages/core/src/federation/privacy.ts +0 -52
- package/packages/core/src/federation/reputation.ts +0 -202
- package/packages/core/src/federation/search.ts +0 -129
- package/packages/core/src/federation/sharing.ts +0 -165
- package/packages/core/src/federation/trust.ts +0 -76
- package/packages/core/src/federation/types.ts +0 -25
- package/packages/core/src/i18n/index.ts +0 -85
- package/packages/core/src/indexer/chunker.ts +0 -180
- package/packages/core/src/indexer/embedder.ts +0 -9
- package/packages/core/src/indexer/index.ts +0 -113
- package/packages/core/src/indexer/local-embedder.ts +0 -35
- package/packages/core/src/indexer/scanner.ts +0 -142
- package/packages/core/src/indexer/watcher.ts +0 -62
- package/packages/core/src/intelligence/contradiction-detector.ts +0 -134
- package/packages/core/src/intelligence/decay-engine.ts +0 -229
- package/packages/core/src/intelligence/duplicate-detector.ts +0 -71
- package/packages/core/src/intelligence/fsrs.ts +0 -79
- package/packages/core/src/intelligence/gap-detector.ts +0 -109
- package/packages/core/src/intelligence/learning-path.ts +0 -86
- package/packages/core/src/intelligence/notifications.ts +0 -106
- package/packages/core/src/intelligence/predictive-gaps.ts +0 -94
- package/packages/core/src/intelligence/semantic-versioning.ts +0 -97
- package/packages/core/src/intelligence/types.ts +0 -28
- package/packages/core/src/mcp/custom-tools.ts +0 -97
- package/packages/core/src/mcp/server.ts +0 -142
- package/packages/core/src/mcp/tools/agentic-graph.ts +0 -96
- package/packages/core/src/mcp/tools/brief.ts +0 -49
- package/packages/core/src/mcp/tools/decay.ts +0 -40
- package/packages/core/src/mcp/tools/decision-journal.ts +0 -95
- package/packages/core/src/mcp/tools/export.ts +0 -72
- package/packages/core/src/mcp/tools/federated-search.ts +0 -43
- package/packages/core/src/mcp/tools/generate-claude-md.ts +0 -130
- package/packages/core/src/mcp/tools/get-document.ts +0 -26
- package/packages/core/src/mcp/tools/get-related.ts +0 -41
- package/packages/core/src/mcp/tools/learning-path.ts +0 -52
- package/packages/core/src/mcp/tools/list-topics.ts +0 -20
- package/packages/core/src/mcp/tools/search.ts +0 -35
- package/packages/core/src/mcp/tools/snapshot.ts +0 -98
- package/packages/core/src/multi-vault/index.ts +0 -118
- package/packages/core/src/pack/creator.ts +0 -127
- package/packages/core/src/pack/exporter.ts +0 -21
- package/packages/core/src/pack/importer.ts +0 -82
- package/packages/core/src/pack/marketplace.ts +0 -103
- package/packages/core/src/pack/pii-masker.ts +0 -38
- package/packages/core/src/pack/types.ts +0 -39
- package/packages/core/src/plugins/index.ts +0 -100
- package/packages/core/src/plugins/webhooks.ts +0 -110
- package/packages/core/src/search/bm25.ts +0 -16
- package/packages/core/src/search/index.ts +0 -83
- package/packages/core/src/search/rrf.ts +0 -31
- package/packages/core/src/search/semantic.ts +0 -15
- package/packages/core/src/store/sqlite-vec.ts +0 -290
- package/packages/core/src/store/types.ts +0 -22
- package/packages/core/src/team/index.ts +0 -126
- package/packages/core/src/types/chunk.ts +0 -25
- package/packages/core/src/types/document.ts +0 -24
- package/packages/core/src/types/graph.ts +0 -44
- package/packages/core/src/types/index.ts +0 -15
- package/packages/core/src/types/search.ts +0 -38
- package/packages/core/src/utils/retry.ts +0 -85
- package/packages/core/tests/api-card.test.ts +0 -60
- package/packages/core/tests/api-routes.test.ts +0 -98
- package/packages/core/tests/bm25.test.ts +0 -87
- package/packages/core/tests/chunker.test.ts +0 -48
- package/packages/core/tests/cluster.test.ts +0 -75
- package/packages/core/tests/constellation.test.ts +0 -77
- package/packages/core/tests/export-utils.test.ts +0 -97
- package/packages/core/tests/fsrs.test.ts +0 -96
- package/packages/core/tests/gesture-detector.test.ts +0 -45
- package/packages/core/tests/graph-data.test.ts +0 -87
- package/packages/core/tests/layout.test.ts +0 -83
- package/packages/core/tests/mcp.test.ts +0 -148
- package/packages/core/tests/pack.test.ts +0 -127
- package/packages/core/tests/pii-masker.test.ts +0 -42
- package/packages/core/tests/profile-card.test.ts +0 -62
- package/packages/core/tests/rrf.test.ts +0 -29
- package/packages/core/tests/search-integration.test.ts +0 -139
- package/packages/core/tests/store.test.ts +0 -80
- package/packages/graph/click-result.png +0 -0
- package/packages/graph/index.html +0 -17
- package/packages/graph/package.json +0 -32
- package/packages/graph/src/App.tsx +0 -7
- package/packages/graph/src/api/client.ts +0 -39
- package/packages/graph/src/components/ClusterFilter.tsx +0 -73
- package/packages/graph/src/components/ConstellationView.tsx +0 -232
- package/packages/graph/src/components/ExportPanel.tsx +0 -177
- package/packages/graph/src/components/Graph3D.tsx +0 -230
- package/packages/graph/src/components/GraphEdges.tsx +0 -100
- package/packages/graph/src/components/GraphNodes.tsx +0 -386
- package/packages/graph/src/components/HealthDashboard.tsx +0 -173
- package/packages/graph/src/components/Layout.tsx +0 -214
- package/packages/graph/src/components/MotionOverlay.tsx +0 -81
- package/packages/graph/src/components/MotionToggle.tsx +0 -33
- package/packages/graph/src/components/MultiverseView.tsx +0 -286
- package/packages/graph/src/components/NodeDetail.tsx +0 -232
- package/packages/graph/src/components/PulseParticle.tsx +0 -232
- package/packages/graph/src/components/SearchBar.tsx +0 -107
- package/packages/graph/src/components/StarField.tsx +0 -197
- package/packages/graph/src/components/StatusBar.tsx +0 -53
- package/packages/graph/src/components/Timeline.tsx +0 -148
- package/packages/graph/src/components/ToolsPanel.tsx +0 -512
- package/packages/graph/src/components/Tooltip.tsx +0 -100
- package/packages/graph/src/components/TypeFilter.tsx +0 -131
- package/packages/graph/src/embed/EmbedGraph.tsx +0 -144
- package/packages/graph/src/hooks/useConstellationLOD.ts +0 -76
- package/packages/graph/src/hooks/useDecay.ts +0 -37
- package/packages/graph/src/hooks/useExport.ts +0 -165
- package/packages/graph/src/hooks/useGraph.ts +0 -69
- package/packages/graph/src/hooks/useKeyboardNav.ts +0 -122
- package/packages/graph/src/hooks/useLayout.ts +0 -45
- package/packages/graph/src/hooks/useMotion.ts +0 -120
- package/packages/graph/src/hooks/usePulse.ts +0 -58
- package/packages/graph/src/hooks/useSearch.ts +0 -71
- package/packages/graph/src/lib/constellation.ts +0 -107
- package/packages/graph/src/lib/export-utils.ts +0 -48
- package/packages/graph/src/lib/gesture-detector.ts +0 -123
- package/packages/graph/src/lib/layout.worker.ts +0 -153
- package/packages/graph/src/lib/motion-controller.ts +0 -83
- package/packages/graph/src/lib/profile-card.ts +0 -122
- package/packages/graph/src/main.tsx +0 -4
- package/packages/graph/src/stores/graph-store.ts +0 -155
- package/packages/graph/success.png +0 -0
- package/packages/graph/test-click.mjs +0 -49
- package/packages/graph/test-explore.mjs +0 -102
- package/packages/graph/test-final.mjs +0 -61
- package/packages/graph/test-graph.mjs +0 -139
- package/packages/graph/test-hover.mjs +0 -48
- package/packages/graph/test-pulse.mjs +0 -68
- package/packages/graph/test-screenshot.mjs +0 -56
- package/packages/graph/test-v2.mjs +0 -97
- package/packages/graph/vite.config.ts +0 -15
- package/packages/sync/.env.example +0 -11
- package/packages/sync/.sync-state.json +0 -317
- package/packages/sync/.upload-state.json +0 -1009
- package/packages/sync/create-stella-network-notion.mjs +0 -151
- package/packages/sync/create-stellavault-project-notion.mjs +0 -322
- package/packages/sync/logs/sync-2026-03-28.log +0 -6
- package/packages/sync/logs/sync-2026-03-29.log +0 -12
- package/packages/sync/logs/sync-2026-03-30.log +0 -6
- package/packages/sync/logs/sync-2026-03-31.log +0 -6
- package/packages/sync/logs/sync-2026-04-01.log +0 -6
- package/packages/sync/logs/sync-2026-04-02.log +0 -6
- package/packages/sync/package-lock.json +0 -373
- package/packages/sync/package.json +0 -16
- package/packages/sync/run-sync.bat +0 -18
- package/packages/sync/run-sync.mjs +0 -46
- package/packages/sync/setup-scheduler.mjs +0 -119
- package/packages/sync/structured-sync.mjs +0 -187
- package/packages/sync/sync-to-obsidian.mjs +0 -264
- package/packages/sync/upload-pdca-to-notion.mjs +0 -495
- package/tsconfig.base.json +0 -18
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// Design Ref: §1 — FSRS-6 알고리즘 (순수 함수)
|
|
2
|
-
// Plan SC: SC-01 (R값 계산), SC-02 (stability 업데이트)
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* FSRS parameters tuned for knowledge notes (not flashcards).
|
|
6
|
-
* Knowledge notes have longer natural retention than flashcards.
|
|
7
|
-
*/
|
|
8
|
-
export const FSRS_PARAMS = {
|
|
9
|
-
initialStability: 7.0, // 7 days for new notes
|
|
10
|
-
difficulty: 5.0, // default difficulty (1~10)
|
|
11
|
-
// Stability growth factors
|
|
12
|
-
a: 0.4,
|
|
13
|
-
b: 0.6,
|
|
14
|
-
c: 0.2,
|
|
15
|
-
d: 1.0,
|
|
16
|
-
// Stability bonus for large/connected notes
|
|
17
|
-
sizeFactor: 0.5, // additional days per 1000 chars
|
|
18
|
-
connectionFactor: 1.0, // additional days per connection
|
|
19
|
-
} as const;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Compute retrievability R(t) using FSRS power forgetting curve.
|
|
23
|
-
* R(t) = (1 + t / (9 * S))^(-1)
|
|
24
|
-
*
|
|
25
|
-
* @param stabilityDays - Stability S (days until R drops to ~0.9)
|
|
26
|
-
* @param elapsedDays - Days since last access
|
|
27
|
-
* @returns Retrievability 0~1
|
|
28
|
-
*/
|
|
29
|
-
export function computeRetrievability(stabilityDays: number, elapsedDays: number): number {
|
|
30
|
-
if (elapsedDays <= 0) return 1.0;
|
|
31
|
-
if (stabilityDays <= 0) return 0.0;
|
|
32
|
-
return Math.pow(1 + elapsedDays / (9 * stabilityDays), -1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Update stability after an access event (successful recall).
|
|
37
|
-
* S' = S * (1 + a * D^(-b) * S^(-c) * (e^(d*(1-R)) - 1))
|
|
38
|
-
*
|
|
39
|
-
* @param currentS - Current stability
|
|
40
|
-
* @param difficulty - Note difficulty (1~10)
|
|
41
|
-
* @param currentR - Retrievability at access time
|
|
42
|
-
* @returns New stability (always >= currentS)
|
|
43
|
-
*/
|
|
44
|
-
export function updateStability(
|
|
45
|
-
currentS: number,
|
|
46
|
-
difficulty: number,
|
|
47
|
-
currentR: number,
|
|
48
|
-
): number {
|
|
49
|
-
const { a, b, c, d } = FSRS_PARAMS;
|
|
50
|
-
const growth = a
|
|
51
|
-
* Math.pow(difficulty, -b)
|
|
52
|
-
* Math.pow(currentS, -c)
|
|
53
|
-
* (Math.exp(d * (1 - currentR)) - 1);
|
|
54
|
-
const newS = currentS * (1 + Math.max(0, growth));
|
|
55
|
-
// Cap at 365 days (1 year max stability)
|
|
56
|
-
return Math.min(newS, 365);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Estimate initial stability based on note characteristics.
|
|
61
|
-
* Longer notes and more connected notes are more stable.
|
|
62
|
-
*/
|
|
63
|
-
export function estimateInitialStability(
|
|
64
|
-
contentLength: number,
|
|
65
|
-
connectionCount: number,
|
|
66
|
-
): number {
|
|
67
|
-
const base = FSRS_PARAMS.initialStability;
|
|
68
|
-
const sizeBonus = Math.min(contentLength / 1000, 10) * FSRS_PARAMS.sizeFactor;
|
|
69
|
-
const connBonus = Math.min(connectionCount, 10) * FSRS_PARAMS.connectionFactor;
|
|
70
|
-
return base + sizeBonus + connBonus;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Compute elapsed days between two ISO timestamps.
|
|
75
|
-
*/
|
|
76
|
-
export function elapsedDays(from: string, to: string = new Date().toISOString()): number {
|
|
77
|
-
const msPerDay = 86400000;
|
|
78
|
-
return Math.max(0, (new Date(to).getTime() - new Date(from).getTime()) / msPerDay);
|
|
79
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// Design Ref: F01 — 지식 갭 탐지기
|
|
2
|
-
// 클러스터 간 브릿지 노드 부족 영역 식별
|
|
3
|
-
|
|
4
|
-
import type { VectorStore } from '../store/types.js';
|
|
5
|
-
|
|
6
|
-
export interface KnowledgeGap {
|
|
7
|
-
clusterA: string;
|
|
8
|
-
clusterB: string;
|
|
9
|
-
bridgeCount: number; // 연결 노드 수 (적을수록 갭)
|
|
10
|
-
suggestedTopic: string; // 학습 추천 주제
|
|
11
|
-
severity: 'high' | 'medium' | 'low';
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface GapReport {
|
|
15
|
-
totalClusters: number;
|
|
16
|
-
totalGaps: number;
|
|
17
|
-
gaps: KnowledgeGap[];
|
|
18
|
-
isolatedNodes: Array<{ id: string; title: string; connections: number }>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 그래프 데이터에서 지식 갭을 탐지.
|
|
23
|
-
* - 클러스터 간 연결이 약한 영역
|
|
24
|
-
* - 고립된 노드 (연결 0~1개)
|
|
25
|
-
*/
|
|
26
|
-
export async function detectKnowledgeGaps(
|
|
27
|
-
store: VectorStore,
|
|
28
|
-
graphData?: any, // buildGraphData 결과 (없으면 직접 계산)
|
|
29
|
-
): Promise<GapReport> {
|
|
30
|
-
const docs = await store.getAllDocuments();
|
|
31
|
-
const embeddings = await store.getDocumentEmbeddings();
|
|
32
|
-
|
|
33
|
-
// 그래프 데이터가 없으면 간단히 계산
|
|
34
|
-
if (!graphData) {
|
|
35
|
-
const { buildGraphData } = await import('../api/graph-data.js');
|
|
36
|
-
graphData = await buildGraphData(store);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const { nodes, edges, clusters } = graphData;
|
|
40
|
-
|
|
41
|
-
// 1. 클러스터 간 연결 수 매트릭스
|
|
42
|
-
const clusterEdges = new Map<string, number>();
|
|
43
|
-
for (const edge of edges) {
|
|
44
|
-
const nodeA = nodes.find((n: any) => n.id === edge.source);
|
|
45
|
-
const nodeB = nodes.find((n: any) => n.id === edge.target);
|
|
46
|
-
if (!nodeA || !nodeB || nodeA.clusterId === nodeB.clusterId) continue;
|
|
47
|
-
|
|
48
|
-
const key = [
|
|
49
|
-
Math.min(nodeA.clusterId, nodeB.clusterId),
|
|
50
|
-
Math.max(nodeA.clusterId, nodeB.clusterId),
|
|
51
|
-
].join('-');
|
|
52
|
-
clusterEdges.set(key, (clusterEdges.get(key) ?? 0) + 1);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 2. 갭 식별 (클러스터 쌍 중 연결이 적은 것)
|
|
56
|
-
const gaps: KnowledgeGap[] = [];
|
|
57
|
-
const clusterLabels = new Map<number, string>(clusters.map((c: any) => [c.id, c.label as string]));
|
|
58
|
-
|
|
59
|
-
for (let i = 0; i < clusters.length; i++) {
|
|
60
|
-
for (let j = i + 1; j < clusters.length; j++) {
|
|
61
|
-
const key = `${Math.min(clusters[i].id, clusters[j].id)}-${Math.max(clusters[i].id, clusters[j].id)}`;
|
|
62
|
-
const bridgeCount = clusterEdges.get(key) ?? 0;
|
|
63
|
-
|
|
64
|
-
// 연결이 3개 미만이면 갭
|
|
65
|
-
if (bridgeCount < 3) {
|
|
66
|
-
const labelA = clusterLabels.get(clusters[i].id) ?? `Cluster ${clusters[i].id}`;
|
|
67
|
-
const labelB = clusterLabels.get(clusters[j].id) ?? `Cluster ${clusters[j].id}`;
|
|
68
|
-
|
|
69
|
-
// 제안 주제: 두 클러스터 이름에서 추출
|
|
70
|
-
const nameA = labelA.replace(/\s*\(\d+\)$/, '');
|
|
71
|
-
const nameB = labelB.replace(/\s*\(\d+\)$/, '');
|
|
72
|
-
|
|
73
|
-
gaps.push({
|
|
74
|
-
clusterA: labelA,
|
|
75
|
-
clusterB: labelB,
|
|
76
|
-
bridgeCount,
|
|
77
|
-
suggestedTopic: `${nameA} + ${nameB} 연결 지식`,
|
|
78
|
-
severity: bridgeCount === 0 ? 'high' : bridgeCount < 2 ? 'medium' : 'low',
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// 3. 고립 노드 (연결 1개 이하)
|
|
85
|
-
const connectionCounts = new Map<string, number>();
|
|
86
|
-
for (const edge of edges) {
|
|
87
|
-
connectionCounts.set(edge.source, (connectionCounts.get(edge.source) ?? 0) + 1);
|
|
88
|
-
connectionCounts.set(edge.target, (connectionCounts.get(edge.target) ?? 0) + 1);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const isolatedNodes = nodes
|
|
92
|
-
.filter((n: any) => (connectionCounts.get(n.id) ?? 0) <= 1)
|
|
93
|
-
.map((n: any) => ({
|
|
94
|
-
id: n.id,
|
|
95
|
-
title: n.label,
|
|
96
|
-
connections: connectionCounts.get(n.id) ?? 0,
|
|
97
|
-
}))
|
|
98
|
-
.slice(0, 20);
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
totalClusters: clusters.length,
|
|
102
|
-
totalGaps: gaps.filter(g => g.severity !== 'low').length,
|
|
103
|
-
gaps: gaps.sort((a, b) => {
|
|
104
|
-
const sev = { high: 0, medium: 1, low: 2 };
|
|
105
|
-
return sev[a.severity] - sev[b.severity];
|
|
106
|
-
}).slice(0, 15),
|
|
107
|
-
isolatedNodes,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
// AI Learning Path Generator (F-A11)
|
|
2
|
-
// Analyzes decay + gaps + relationships to recommend what to review/learn next
|
|
3
|
-
|
|
4
|
-
import type { DecayReport, DecayState } from './types.js';
|
|
5
|
-
|
|
6
|
-
export interface LearningItem {
|
|
7
|
-
documentId: string;
|
|
8
|
-
title: string;
|
|
9
|
-
reason: string;
|
|
10
|
-
priority: 'critical' | 'important' | 'suggested';
|
|
11
|
-
score: number; // 0-100, higher = more urgent
|
|
12
|
-
category: 'review' | 'explore' | 'bridge';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface LearningPath {
|
|
16
|
-
items: LearningItem[];
|
|
17
|
-
summary: {
|
|
18
|
-
reviewCount: number;
|
|
19
|
-
exploreCount: number;
|
|
20
|
-
bridgeCount: number;
|
|
21
|
-
estimatedMinutes: number;
|
|
22
|
-
};
|
|
23
|
-
generatedAt: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface LearningPathInput {
|
|
27
|
-
decayReport: DecayReport;
|
|
28
|
-
gaps?: Array<{ clusterA: string; clusterB: string; severity: string; suggestedTopic: string }>;
|
|
29
|
-
recentSearches?: string[];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function generateLearningPath(input: LearningPathInput, limit = 15): LearningPath {
|
|
33
|
-
const items: LearningItem[] = [];
|
|
34
|
-
|
|
35
|
-
// 1. Review: decaying notes (highest priority)
|
|
36
|
-
if (input.decayReport.topDecaying) {
|
|
37
|
-
for (const d of input.decayReport.topDecaying) {
|
|
38
|
-
const r = d.retrievability ?? 0;
|
|
39
|
-
const urgency = (1 - r) * 100;
|
|
40
|
-
items.push({
|
|
41
|
-
documentId: d.documentId,
|
|
42
|
-
title: d.title,
|
|
43
|
-
reason: r < 0.3
|
|
44
|
-
? `Critical: ${Math.round(r * 100)}% retrievability, ${d.daysSinceAccess}d since last access`
|
|
45
|
-
: `Fading: ${Math.round(r * 100)}% retrievability, review to strengthen memory`,
|
|
46
|
-
priority: r < 0.3 ? 'critical' : r < 0.5 ? 'important' : 'suggested',
|
|
47
|
-
score: Math.round(urgency),
|
|
48
|
-
category: 'review',
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// 2. Bridge: knowledge gaps
|
|
54
|
-
if (input.gaps) {
|
|
55
|
-
for (const gap of input.gaps) {
|
|
56
|
-
const severityScore = gap.severity === 'high' ? 80 : gap.severity === 'medium' ? 60 : 40;
|
|
57
|
-
items.push({
|
|
58
|
-
documentId: '',
|
|
59
|
-
title: gap.suggestedTopic || `${gap.clusterA} × ${gap.clusterB}`,
|
|
60
|
-
reason: `Gap between "${gap.clusterA}" and "${gap.clusterB}" — creating a bridge note strengthens your knowledge network`,
|
|
61
|
-
priority: gap.severity === 'high' ? 'important' : 'suggested',
|
|
62
|
-
score: severityScore,
|
|
63
|
-
category: 'bridge',
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Sort by score descending
|
|
69
|
-
items.sort((a, b) => b.score - a.score);
|
|
70
|
-
|
|
71
|
-
const selected = items.slice(0, limit);
|
|
72
|
-
const reviewCount = selected.filter(i => i.category === 'review').length;
|
|
73
|
-
const exploreCount = selected.filter(i => i.category === 'explore').length;
|
|
74
|
-
const bridgeCount = selected.filter(i => i.category === 'bridge').length;
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
items: selected,
|
|
78
|
-
summary: {
|
|
79
|
-
reviewCount,
|
|
80
|
-
exploreCount,
|
|
81
|
-
bridgeCount,
|
|
82
|
-
estimatedMinutes: reviewCount * 3 + exploreCount * 5 + bridgeCount * 8,
|
|
83
|
-
},
|
|
84
|
-
generatedAt: new Date().toISOString(),
|
|
85
|
-
};
|
|
86
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// Notification Center (F-A05)
|
|
2
|
-
// Configurable alerts for decay thresholds, gap detection, weekly digest
|
|
3
|
-
|
|
4
|
-
import type { DecayReport } from './types.js';
|
|
5
|
-
|
|
6
|
-
export interface NotificationConfig {
|
|
7
|
-
decay: {
|
|
8
|
-
enabled: boolean;
|
|
9
|
-
criticalThreshold: number; // R value (0-1), default 0.3
|
|
10
|
-
warningThreshold: number; // default 0.5
|
|
11
|
-
};
|
|
12
|
-
gaps: {
|
|
13
|
-
enabled: boolean;
|
|
14
|
-
minSeverity: 'low' | 'medium' | 'high'; // default 'medium'
|
|
15
|
-
};
|
|
16
|
-
digest: {
|
|
17
|
-
enabled: boolean;
|
|
18
|
-
frequency: 'daily' | 'weekly' | 'off'; // default 'weekly'
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface Notification {
|
|
23
|
-
id: string;
|
|
24
|
-
type: 'decay_critical' | 'decay_warning' | 'gap_detected' | 'digest';
|
|
25
|
-
title: string;
|
|
26
|
-
message: string;
|
|
27
|
-
timestamp: string;
|
|
28
|
-
priority: 'high' | 'medium' | 'low';
|
|
29
|
-
data?: Record<string, unknown>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const DEFAULT_CONFIG: NotificationConfig = {
|
|
33
|
-
decay: { enabled: true, criticalThreshold: 0.3, warningThreshold: 0.5 },
|
|
34
|
-
gaps: { enabled: true, minSeverity: 'medium' },
|
|
35
|
-
digest: { enabled: true, frequency: 'weekly' },
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export function checkNotifications(
|
|
39
|
-
decayReport: DecayReport,
|
|
40
|
-
gaps: Array<{ severity: string; clusterA: string; clusterB: string }>,
|
|
41
|
-
config: Partial<NotificationConfig> = {},
|
|
42
|
-
): Notification[] {
|
|
43
|
-
const cfg = {
|
|
44
|
-
decay: { ...DEFAULT_CONFIG.decay, ...config.decay },
|
|
45
|
-
gaps: { ...DEFAULT_CONFIG.gaps, ...config.gaps },
|
|
46
|
-
digest: { ...DEFAULT_CONFIG.digest, ...config.digest },
|
|
47
|
-
};
|
|
48
|
-
const notifications: Notification[] = [];
|
|
49
|
-
const now = new Date().toISOString();
|
|
50
|
-
|
|
51
|
-
// Decay alerts
|
|
52
|
-
if (cfg.decay.enabled && decayReport.topDecaying) {
|
|
53
|
-
const criticals = decayReport.topDecaying.filter(d => d.retrievability < cfg.decay.criticalThreshold);
|
|
54
|
-
const warnings = decayReport.topDecaying.filter(d =>
|
|
55
|
-
d.retrievability >= cfg.decay.criticalThreshold && d.retrievability < cfg.decay.warningThreshold
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
if (criticals.length > 0) {
|
|
59
|
-
notifications.push({
|
|
60
|
-
id: `decay-critical-${Date.now()}`,
|
|
61
|
-
type: 'decay_critical',
|
|
62
|
-
title: `${criticals.length} notes critically fading`,
|
|
63
|
-
message: criticals.slice(0, 3).map(d => `"${d.title}" (${Math.round(d.retrievability * 100)}%)`).join(', '),
|
|
64
|
-
timestamp: now,
|
|
65
|
-
priority: 'high',
|
|
66
|
-
data: { count: criticals.length, notes: criticals.slice(0, 5).map(d => d.title) },
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (warnings.length > 0) {
|
|
71
|
-
notifications.push({
|
|
72
|
-
id: `decay-warning-${Date.now()}`,
|
|
73
|
-
type: 'decay_warning',
|
|
74
|
-
title: `${warnings.length} notes starting to fade`,
|
|
75
|
-
message: `Average retrievability: ${Math.round(decayReport.averageR * 100)}%`,
|
|
76
|
-
timestamp: now,
|
|
77
|
-
priority: 'medium',
|
|
78
|
-
data: { count: warnings.length },
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Gap alerts
|
|
84
|
-
if (cfg.gaps.enabled) {
|
|
85
|
-
const severityOrder = { high: 3, medium: 2, low: 1 };
|
|
86
|
-
const minLevel = severityOrder[cfg.gaps.minSeverity] ?? 2;
|
|
87
|
-
const significantGaps = gaps.filter(g => (severityOrder[g.severity as keyof typeof severityOrder] ?? 0) >= minLevel);
|
|
88
|
-
|
|
89
|
-
if (significantGaps.length > 0) {
|
|
90
|
-
notifications.push({
|
|
91
|
-
id: `gap-${Date.now()}`,
|
|
92
|
-
type: 'gap_detected',
|
|
93
|
-
title: `${significantGaps.length} knowledge gaps detected`,
|
|
94
|
-
message: significantGaps.slice(0, 2).map(g => `${g.clusterA} ↔ ${g.clusterB}`).join(', '),
|
|
95
|
-
timestamp: now,
|
|
96
|
-
priority: significantGaps.some(g => g.severity === 'high') ? 'high' : 'medium',
|
|
97
|
-
data: { count: significantGaps.length },
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return notifications.sort((a, b) => {
|
|
103
|
-
const p = { high: 3, medium: 2, low: 1 };
|
|
104
|
-
return (p[b.priority] ?? 0) - (p[a.priority] ?? 0);
|
|
105
|
-
});
|
|
106
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
// Predictive Gap Analysis (F-A14)
|
|
2
|
-
// Based on graph topology, predict knowledge areas worth exploring
|
|
3
|
-
|
|
4
|
-
import type { VectorStore } from '../store/types.js';
|
|
5
|
-
|
|
6
|
-
export interface PredictedGap {
|
|
7
|
-
topic: string;
|
|
8
|
-
reason: string;
|
|
9
|
-
confidence: number; // 0-1
|
|
10
|
-
relatedTopics: string[];
|
|
11
|
-
category: 'adjacent' | 'bridging' | 'deepening';
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Analyze graph topology to predict knowledge worth acquiring.
|
|
16
|
-
* Uses degree centrality, cluster density, and tag co-occurrence.
|
|
17
|
-
*/
|
|
18
|
-
export async function predictKnowledgeGaps(
|
|
19
|
-
store: VectorStore,
|
|
20
|
-
limit = 10,
|
|
21
|
-
): Promise<PredictedGap[]> {
|
|
22
|
-
const docs = await store.getAllDocuments();
|
|
23
|
-
const topics = await store.getTopics();
|
|
24
|
-
|
|
25
|
-
if (docs.length < 10) return [];
|
|
26
|
-
|
|
27
|
-
const predictions: PredictedGap[] = [];
|
|
28
|
-
|
|
29
|
-
// 1. Find isolated tags (topics that appear rarely and could be expanded)
|
|
30
|
-
const topicCounts = new Map(topics.map(t => [t.topic, t.count]));
|
|
31
|
-
const avgCount = topics.reduce((s, t) => s + t.count, 0) / (topics.length || 1);
|
|
32
|
-
|
|
33
|
-
// Tags that appear 1-2 times — potential deepening opportunities
|
|
34
|
-
const sparseTopics = topics.filter(t => t.count <= 2 && t.count > 0);
|
|
35
|
-
for (const t of sparseTopics.slice(0, 5)) {
|
|
36
|
-
predictions.push({
|
|
37
|
-
topic: t.topic,
|
|
38
|
-
reason: `Only ${t.count} note(s) on "${t.topic}" — deepening this area would strengthen your knowledge network`,
|
|
39
|
-
confidence: 0.6,
|
|
40
|
-
relatedTopics: findCoOccurring(t.topic, docs),
|
|
41
|
-
category: 'deepening',
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 2. Find tag pairs that never co-occur but are both frequent
|
|
46
|
-
const frequentTopics = topics.filter(t => t.count >= avgCount).slice(0, 20);
|
|
47
|
-
const coOccurrence = new Map<string, Set<string>>();
|
|
48
|
-
|
|
49
|
-
for (const doc of docs) {
|
|
50
|
-
for (const tagA of doc.tags) {
|
|
51
|
-
if (!coOccurrence.has(tagA)) coOccurrence.set(tagA, new Set());
|
|
52
|
-
for (const tagB of doc.tags) {
|
|
53
|
-
if (tagA !== tagB) coOccurrence.get(tagA)!.add(tagB);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
for (let i = 0; i < frequentTopics.length; i++) {
|
|
59
|
-
for (let j = i + 1; j < frequentTopics.length; j++) {
|
|
60
|
-
const a = frequentTopics[i].topic;
|
|
61
|
-
const b = frequentTopics[j].topic;
|
|
62
|
-
const aCoOccurs = coOccurrence.get(a) ?? new Set();
|
|
63
|
-
|
|
64
|
-
if (!aCoOccurs.has(b)) {
|
|
65
|
-
predictions.push({
|
|
66
|
-
topic: `${a} × ${b}`,
|
|
67
|
-
reason: `"${a}" (${frequentTopics[i].count} notes) and "${b}" (${frequentTopics[j].count} notes) are both well-known but never connected — bridging them could reveal insights`,
|
|
68
|
-
confidence: 0.7,
|
|
69
|
-
relatedTopics: [a, b],
|
|
70
|
-
category: 'bridging',
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// 3. Adjacent topics — topics that co-occur with many of your topics but you don't have
|
|
77
|
-
// (This would ideally use external knowledge, but we approximate with tag patterns)
|
|
78
|
-
|
|
79
|
-
return predictions
|
|
80
|
-
.sort((a, b) => b.confidence - a.confidence)
|
|
81
|
-
.slice(0, limit);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function findCoOccurring(topic: string, docs: Array<{ tags: string[] }>): string[] {
|
|
85
|
-
const coTopics = new Map<string, number>();
|
|
86
|
-
for (const doc of docs) {
|
|
87
|
-
if (doc.tags.includes(topic)) {
|
|
88
|
-
for (const t of doc.tags) {
|
|
89
|
-
if (t !== topic) coTopics.set(t, (coTopics.get(t) ?? 0) + 1);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return [...coTopics.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([t]) => t);
|
|
94
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// Knowledge Semantic Versioning (F-A13)
|
|
2
|
-
// Track how a note's MEANING changes over time via embedding drift
|
|
3
|
-
|
|
4
|
-
export interface SemanticVersion {
|
|
5
|
-
documentId: string;
|
|
6
|
-
timestamp: string;
|
|
7
|
-
embeddingHash: string; // first 8 chars of embedding vector hash
|
|
8
|
-
drift: number; // cosine distance from previous version (0 = identical, 2 = opposite)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface SemanticChangelog {
|
|
12
|
-
documentId: string;
|
|
13
|
-
title: string;
|
|
14
|
-
versions: SemanticVersion[];
|
|
15
|
-
totalDrift: number; // cumulative semantic drift
|
|
16
|
-
stability: number; // 0-1, how stable the meaning has been
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Compute semantic drift between two embedding vectors.
|
|
21
|
-
* Returns cosine distance (0 = identical, 1 = orthogonal, 2 = opposite)
|
|
22
|
-
*/
|
|
23
|
-
export function computeSemanticDrift(vecA: number[], vecB: number[]): number {
|
|
24
|
-
if (vecA.length !== vecB.length || vecA.length === 0) return 0;
|
|
25
|
-
let dot = 0, na = 0, nb = 0;
|
|
26
|
-
for (let i = 0; i < vecA.length; i++) {
|
|
27
|
-
dot += vecA[i] * vecB[i];
|
|
28
|
-
na += vecA[i] * vecA[i];
|
|
29
|
-
nb += vecB[i] * vecB[i];
|
|
30
|
-
}
|
|
31
|
-
const denom = Math.sqrt(na) * Math.sqrt(nb);
|
|
32
|
-
const similarity = denom === 0 ? 0 : dot / denom;
|
|
33
|
-
return 1 - similarity; // cosine distance
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Hash an embedding vector for quick comparison
|
|
38
|
-
*/
|
|
39
|
-
export function hashEmbedding(vec: number[]): string {
|
|
40
|
-
let hash = 0;
|
|
41
|
-
for (let i = 0; i < Math.min(vec.length, 50); i++) {
|
|
42
|
-
hash = ((hash << 5) - hash + Math.round(vec[i] * 10000)) | 0;
|
|
43
|
-
}
|
|
44
|
-
return Math.abs(hash).toString(36).slice(0, 8);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Analyze semantic stability of a document given its embedding history.
|
|
49
|
-
* In practice, we compare current embedding vs initial embedding to measure total drift.
|
|
50
|
-
*/
|
|
51
|
-
export function analyzeSemanticStability(
|
|
52
|
-
currentVec: number[],
|
|
53
|
-
title: string,
|
|
54
|
-
documentId: string,
|
|
55
|
-
): SemanticChangelog {
|
|
56
|
-
// Single-point analysis (no history yet — foundation for future multi-version tracking)
|
|
57
|
-
const now = new Date().toISOString();
|
|
58
|
-
const hash = hashEmbedding(currentVec);
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
documentId,
|
|
62
|
-
title,
|
|
63
|
-
versions: [{
|
|
64
|
-
documentId,
|
|
65
|
-
timestamp: now,
|
|
66
|
-
embeddingHash: hash,
|
|
67
|
-
drift: 0,
|
|
68
|
-
}],
|
|
69
|
-
totalDrift: 0,
|
|
70
|
-
stability: 1.0,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Compare two sets of embeddings to find documents with the most semantic drift.
|
|
76
|
-
* Useful for "what changed the most since last index?"
|
|
77
|
-
*/
|
|
78
|
-
export function findMostDrifted(
|
|
79
|
-
previousEmbeddings: Map<string, number[]>,
|
|
80
|
-
currentEmbeddings: Map<string, number[]>,
|
|
81
|
-
titles: Map<string, string>,
|
|
82
|
-
limit = 10,
|
|
83
|
-
): Array<{ documentId: string; title: string; drift: number }> {
|
|
84
|
-
const drifts: Array<{ documentId: string; title: string; drift: number }> = [];
|
|
85
|
-
|
|
86
|
-
for (const [docId, currentVec] of currentEmbeddings) {
|
|
87
|
-
const prevVec = previousEmbeddings.get(docId);
|
|
88
|
-
if (!prevVec) continue;
|
|
89
|
-
|
|
90
|
-
const drift = computeSemanticDrift(prevVec, currentVec);
|
|
91
|
-
if (drift > 0.01) { // ignore trivial changes
|
|
92
|
-
drifts.push({ documentId: docId, title: titles.get(docId) ?? docId, drift: Math.round(drift * 1000) / 1000 });
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return drifts.sort((a, b) => b.drift - a.drift).slice(0, limit);
|
|
97
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// Design Ref: §2.2 — FSRS 감쇠 타입 정의
|
|
2
|
-
|
|
3
|
-
export interface DecayState {
|
|
4
|
-
documentId: string;
|
|
5
|
-
stability: number; // days until R drops to 0.9
|
|
6
|
-
difficulty: number; // 1~10
|
|
7
|
-
lastAccess: string; // ISO timestamp
|
|
8
|
-
retrievability: number; // 0~1 (computed)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface AccessEvent {
|
|
12
|
-
documentId: string;
|
|
13
|
-
type: 'view' | 'search' | 'mcp_query';
|
|
14
|
-
timestamp: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface DecayReport {
|
|
18
|
-
totalDocuments: number;
|
|
19
|
-
decayingCount: number; // R < 0.5
|
|
20
|
-
criticalCount: number; // R < 0.3
|
|
21
|
-
averageR: number;
|
|
22
|
-
topDecaying: Array<DecayState & { title: string; daysSinceAccess: number }>;
|
|
23
|
-
clusterHealth: Array<{
|
|
24
|
-
label: string;
|
|
25
|
-
avgR: number;
|
|
26
|
-
count: number;
|
|
27
|
-
}>;
|
|
28
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// Custom MCP Tool Builder (F-A16)
|
|
2
|
-
// Load YAML/JSON tool definitions without coding
|
|
3
|
-
|
|
4
|
-
import { readFileSync, existsSync, readdirSync } from 'node:fs';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
-
import type { SearchEngine } from '../search/index.js';
|
|
7
|
-
|
|
8
|
-
export interface CustomToolDef {
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
query_template: string; // e.g. "{{topic}} best practices"
|
|
12
|
-
output_format?: 'full' | 'titles' | 'snippets';
|
|
13
|
-
limit?: number;
|
|
14
|
-
filter_tags?: string[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface LoadedCustomTool {
|
|
18
|
-
name: string;
|
|
19
|
-
description: string;
|
|
20
|
-
inputSchema: {
|
|
21
|
-
type: 'object';
|
|
22
|
-
properties: Record<string, { type: string; description: string }>;
|
|
23
|
-
required?: string[];
|
|
24
|
-
};
|
|
25
|
-
handler: (args: Record<string, unknown>) => Promise<{ content: Array<{ type: 'text'; text: string }> }>;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function loadCustomTools(toolsDir: string, searchEngine: SearchEngine): LoadedCustomTool[] {
|
|
29
|
-
if (!existsSync(toolsDir)) return [];
|
|
30
|
-
|
|
31
|
-
const tools: LoadedCustomTool[] = [];
|
|
32
|
-
const files = readdirSync(toolsDir).filter(f => f.endsWith('.json') || f.endsWith('.yaml') || f.endsWith('.yml'));
|
|
33
|
-
|
|
34
|
-
for (const file of files) {
|
|
35
|
-
try {
|
|
36
|
-
const raw = readFileSync(join(toolsDir, file), 'utf-8');
|
|
37
|
-
let def: CustomToolDef;
|
|
38
|
-
|
|
39
|
-
if (file.endsWith('.json')) {
|
|
40
|
-
def = JSON.parse(raw);
|
|
41
|
-
} else {
|
|
42
|
-
// Simple YAML parser for basic key:value format
|
|
43
|
-
def = parseSimpleYaml(raw);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!def.name || !def.description || !def.query_template) continue;
|
|
47
|
-
|
|
48
|
-
// Extract template variables ({{var}})
|
|
49
|
-
const vars = [...def.query_template.matchAll(/\{\{(\w+)\}\}/g)].map(m => m[1]);
|
|
50
|
-
|
|
51
|
-
tools.push({
|
|
52
|
-
name: def.name,
|
|
53
|
-
description: def.description,
|
|
54
|
-
inputSchema: {
|
|
55
|
-
type: 'object',
|
|
56
|
-
properties: Object.fromEntries(vars.map(v => [v, { type: 'string', description: `Value for ${v}` }])),
|
|
57
|
-
required: vars,
|
|
58
|
-
},
|
|
59
|
-
handler: async (args) => {
|
|
60
|
-
let query = def.query_template;
|
|
61
|
-
for (const [key, val] of Object.entries(args)) {
|
|
62
|
-
query = query.replace(`{{${key}}}`, String(val));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const results = await searchEngine.search({ query, limit: def.limit ?? 5 });
|
|
66
|
-
const format = def.output_format ?? 'snippets';
|
|
67
|
-
|
|
68
|
-
let text: string;
|
|
69
|
-
if (format === 'titles') {
|
|
70
|
-
text = results.map(r => `- ${r.document.title}`).join('\n');
|
|
71
|
-
} else if (format === 'full') {
|
|
72
|
-
text = results.map(r => `## ${r.document.title}\n\n${r.document.content.slice(0, 1000)}`).join('\n\n---\n\n');
|
|
73
|
-
} else {
|
|
74
|
-
text = results.map(r => `**${r.document.title}** (${Math.round(r.score * 100)}%)\n${r.chunk.content.slice(0, 200)}...`).join('\n\n');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return { content: [{ type: 'text' as const, text: text || 'No results found.' }] };
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
} catch {
|
|
81
|
-
// Skip invalid tool files
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return tools;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function parseSimpleYaml(raw: string): CustomToolDef {
|
|
89
|
-
const result: Record<string, string> = {};
|
|
90
|
-
for (const line of raw.split('\n')) {
|
|
91
|
-
const match = line.match(/^(\w[\w_]*)\s*:\s*(.+)$/);
|
|
92
|
-
if (match) {
|
|
93
|
-
result[match[1]] = match[2].replace(/^["']|["']$/g, '').trim();
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return result as unknown as CustomToolDef;
|
|
97
|
-
}
|