@soleri/core 2.12.0 → 8.0.0
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/data/flows/build.flow.yaml +128 -0
- package/data/flows/deliver.flow.yaml +110 -0
- package/data/flows/design.flow.yaml +108 -0
- package/data/flows/enhance.flow.yaml +90 -0
- package/data/flows/explore.flow.yaml +84 -0
- package/data/flows/fix.flow.yaml +90 -0
- package/data/flows/plan.flow.yaml +87 -0
- package/data/flows/review.flow.yaml +90 -0
- package/dist/agency/agency-manager.d.ts +27 -1
- package/dist/agency/agency-manager.d.ts.map +1 -1
- package/dist/agency/agency-manager.js +180 -9
- package/dist/agency/agency-manager.js.map +1 -1
- package/dist/agency/default-rules.d.ts +7 -0
- package/dist/agency/default-rules.d.ts.map +1 -0
- package/dist/agency/default-rules.js +79 -0
- package/dist/agency/default-rules.js.map +1 -0
- package/dist/agency/types.d.ts +48 -0
- package/dist/agency/types.d.ts.map +1 -1
- package/dist/brain/brain.d.ts +17 -2
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +118 -8
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +16 -2
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/brain/knowledge-synthesizer.d.ts +37 -0
- package/dist/brain/knowledge-synthesizer.d.ts.map +1 -0
- package/dist/brain/knowledge-synthesizer.js +161 -0
- package/dist/brain/knowledge-synthesizer.js.map +1 -0
- package/dist/brain/learning-radar.d.ts +96 -0
- package/dist/brain/learning-radar.d.ts.map +1 -0
- package/dist/brain/learning-radar.js +202 -0
- package/dist/brain/learning-radar.js.map +1 -0
- package/dist/brain/types.d.ts +15 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/capabilities/chain-mapping.d.ts +21 -0
- package/dist/capabilities/chain-mapping.d.ts.map +1 -0
- package/dist/capabilities/chain-mapping.js +86 -0
- package/dist/capabilities/chain-mapping.js.map +1 -0
- package/dist/capabilities/index.d.ts +10 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +8 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/registry.d.ts +95 -0
- package/dist/capabilities/registry.d.ts.map +1 -0
- package/dist/capabilities/registry.js +227 -0
- package/dist/capabilities/registry.js.map +1 -0
- package/dist/capabilities/types.d.ts +106 -0
- package/dist/capabilities/types.d.ts.map +1 -0
- package/dist/capabilities/types.js +12 -0
- package/dist/capabilities/types.js.map +1 -0
- package/dist/context/context-engine.d.ts.map +1 -1
- package/dist/context/context-engine.js +82 -17
- package/dist/context/context-engine.js.map +1 -1
- package/dist/context/types.d.ts +5 -0
- package/dist/context/types.d.ts.map +1 -1
- package/dist/control/intent-router.d.ts +12 -1
- package/dist/control/intent-router.d.ts.map +1 -1
- package/dist/control/intent-router.js +126 -2
- package/dist/control/intent-router.js.map +1 -1
- package/dist/control/types.d.ts +17 -0
- package/dist/control/types.d.ts.map +1 -1
- package/dist/curator/classifier.d.ts +18 -0
- package/dist/curator/classifier.d.ts.map +1 -0
- package/dist/curator/classifier.js +61 -0
- package/dist/curator/classifier.js.map +1 -0
- package/dist/curator/quality-gate.d.ts +29 -0
- package/dist/curator/quality-gate.d.ts.map +1 -0
- package/dist/curator/quality-gate.js +88 -0
- package/dist/curator/quality-gate.js.map +1 -0
- package/dist/domain-packs/index.d.ts +8 -0
- package/dist/domain-packs/index.d.ts.map +1 -0
- package/dist/domain-packs/index.js +8 -0
- package/dist/domain-packs/index.js.map +1 -0
- package/dist/domain-packs/inject-rules.d.ts +24 -0
- package/dist/domain-packs/inject-rules.d.ts.map +1 -0
- package/dist/domain-packs/inject-rules.js +65 -0
- package/dist/domain-packs/inject-rules.js.map +1 -0
- package/dist/domain-packs/knowledge-installer.d.ts +27 -0
- package/dist/domain-packs/knowledge-installer.d.ts.map +1 -0
- package/dist/domain-packs/knowledge-installer.js +89 -0
- package/dist/domain-packs/knowledge-installer.js.map +1 -0
- package/dist/domain-packs/loader.d.ts +28 -0
- package/dist/domain-packs/loader.d.ts.map +1 -0
- package/dist/domain-packs/loader.js +105 -0
- package/dist/domain-packs/loader.js.map +1 -0
- package/dist/domain-packs/pack-runtime.d.ts +80 -0
- package/dist/domain-packs/pack-runtime.d.ts.map +1 -0
- package/dist/domain-packs/pack-runtime.js +36 -0
- package/dist/domain-packs/pack-runtime.js.map +1 -0
- package/dist/domain-packs/skills-installer.d.ts +21 -0
- package/dist/domain-packs/skills-installer.d.ts.map +1 -0
- package/dist/domain-packs/skills-installer.js +38 -0
- package/dist/domain-packs/skills-installer.js.map +1 -0
- package/dist/domain-packs/token-resolver.d.ts +37 -0
- package/dist/domain-packs/token-resolver.d.ts.map +1 -0
- package/dist/domain-packs/token-resolver.js +109 -0
- package/dist/domain-packs/token-resolver.js.map +1 -0
- package/dist/domain-packs/types.d.ts +91 -0
- package/dist/domain-packs/types.d.ts.map +1 -0
- package/dist/domain-packs/types.js +122 -0
- package/dist/domain-packs/types.js.map +1 -0
- package/dist/engine/bin/soleri-engine.d.ts +12 -0
- package/dist/engine/bin/soleri-engine.d.ts.map +1 -0
- package/dist/engine/bin/soleri-engine.js +184 -0
- package/dist/engine/bin/soleri-engine.js.map +1 -0
- package/dist/engine/core-ops.d.ts +27 -0
- package/dist/engine/core-ops.d.ts.map +1 -0
- package/dist/engine/core-ops.js +159 -0
- package/dist/engine/core-ops.js.map +1 -0
- package/dist/engine/index.d.ts +19 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +17 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/register-engine.d.ts +54 -0
- package/dist/engine/register-engine.d.ts.map +1 -0
- package/dist/engine/register-engine.js +270 -0
- package/dist/engine/register-engine.js.map +1 -0
- package/dist/engine/test-helpers.d.ts +30 -0
- package/dist/engine/test-helpers.d.ts.map +1 -0
- package/dist/engine/test-helpers.js +59 -0
- package/dist/engine/test-helpers.js.map +1 -0
- package/dist/events/event-bus.d.ts +30 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +51 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/flows/chain-runner.d.ts +46 -0
- package/dist/flows/chain-runner.d.ts.map +1 -0
- package/dist/flows/chain-runner.js +271 -0
- package/dist/flows/chain-runner.js.map +1 -0
- package/dist/flows/chain-types.d.ts +103 -0
- package/dist/flows/chain-types.d.ts.map +1 -0
- package/dist/flows/chain-types.js +23 -0
- package/dist/flows/chain-types.js.map +1 -0
- package/dist/flows/context-router.d.ts +39 -0
- package/dist/flows/context-router.d.ts.map +1 -0
- package/dist/flows/context-router.js +206 -0
- package/dist/flows/context-router.js.map +1 -0
- package/dist/flows/dispatch-registry.d.ts +24 -0
- package/dist/flows/dispatch-registry.d.ts.map +1 -0
- package/dist/flows/dispatch-registry.js +70 -0
- package/dist/flows/dispatch-registry.js.map +1 -0
- package/dist/flows/epilogue.d.ts +24 -0
- package/dist/flows/epilogue.d.ts.map +1 -0
- package/dist/flows/epilogue.js +52 -0
- package/dist/flows/epilogue.js.map +1 -0
- package/dist/flows/executor.d.ts +25 -0
- package/dist/flows/executor.d.ts.map +1 -0
- package/dist/flows/executor.js +153 -0
- package/dist/flows/executor.js.map +1 -0
- package/dist/flows/gate-evaluator.d.ts +26 -0
- package/dist/flows/gate-evaluator.d.ts.map +1 -0
- package/dist/flows/gate-evaluator.js +162 -0
- package/dist/flows/gate-evaluator.js.map +1 -0
- package/dist/flows/index.d.ts +14 -0
- package/dist/flows/index.d.ts.map +1 -0
- package/dist/flows/index.js +20 -0
- package/dist/flows/index.js.map +1 -0
- package/dist/flows/loader.d.ts +17 -0
- package/dist/flows/loader.d.ts.map +1 -0
- package/dist/flows/loader.js +61 -0
- package/dist/flows/loader.js.map +1 -0
- package/dist/flows/plan-builder.d.ts +40 -0
- package/dist/flows/plan-builder.d.ts.map +1 -0
- package/dist/flows/plan-builder.js +213 -0
- package/dist/flows/plan-builder.js.map +1 -0
- package/dist/flows/probes.d.ts +11 -0
- package/dist/flows/probes.d.ts.map +1 -0
- package/dist/flows/probes.js +62 -0
- package/dist/flows/probes.js.map +1 -0
- package/dist/flows/types.d.ts +950 -0
- package/dist/flows/types.d.ts.map +1 -0
- package/dist/flows/types.js +105 -0
- package/dist/flows/types.js.map +1 -0
- package/dist/health/doctor-checks.d.ts +15 -0
- package/dist/health/doctor-checks.d.ts.map +1 -0
- package/dist/health/doctor-checks.js +98 -0
- package/dist/health/doctor-checks.js.map +1 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/intake/text-ingester.d.ts +52 -0
- package/dist/intake/text-ingester.d.ts.map +1 -0
- package/dist/intake/text-ingester.js +181 -0
- package/dist/intake/text-ingester.js.map +1 -0
- package/dist/intelligence/loader.d.ts +19 -0
- package/dist/intelligence/loader.d.ts.map +1 -1
- package/dist/intelligence/loader.js +35 -0
- package/dist/intelligence/loader.js.map +1 -1
- package/dist/intelligence/types.d.ts +1 -0
- package/dist/intelligence/types.d.ts.map +1 -1
- package/dist/llm/llm-client.d.ts.map +1 -1
- package/dist/llm/llm-client.js +37 -1
- package/dist/llm/llm-client.js.map +1 -1
- package/dist/llm/oauth-discovery.d.ts +26 -0
- package/dist/llm/oauth-discovery.d.ts.map +1 -0
- package/dist/llm/oauth-discovery.js +149 -0
- package/dist/llm/oauth-discovery.js.map +1 -0
- package/dist/packs/types.d.ts +58 -19
- package/dist/packs/types.d.ts.map +1 -1
- package/dist/packs/types.js +14 -0
- package/dist/packs/types.js.map +1 -1
- package/dist/planning/evidence-collector.d.ts +41 -0
- package/dist/planning/evidence-collector.d.ts.map +1 -0
- package/dist/planning/evidence-collector.js +194 -0
- package/dist/planning/evidence-collector.js.map +1 -0
- package/dist/planning/planner.d.ts +4 -0
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +11 -0
- package/dist/planning/planner.js.map +1 -1
- package/dist/playbooks/generic/onboarding.d.ts +9 -0
- package/dist/playbooks/generic/onboarding.d.ts.map +1 -0
- package/dist/playbooks/generic/onboarding.js +74 -0
- package/dist/playbooks/generic/onboarding.js.map +1 -0
- package/dist/playbooks/playbook-registry.d.ts.map +1 -1
- package/dist/playbooks/playbook-registry.js +2 -0
- package/dist/playbooks/playbook-registry.js.map +1 -1
- package/dist/queue/job-queue.d.ts +92 -0
- package/dist/queue/job-queue.d.ts.map +1 -0
- package/dist/queue/job-queue.js +180 -0
- package/dist/queue/job-queue.js.map +1 -0
- package/dist/queue/pipeline-runner.d.ts +62 -0
- package/dist/queue/pipeline-runner.d.ts.map +1 -0
- package/dist/queue/pipeline-runner.js +126 -0
- package/dist/queue/pipeline-runner.js.map +1 -0
- package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
- package/dist/runtime/admin-extra-ops.js +15 -9
- package/dist/runtime/admin-extra-ops.js.map +1 -1
- package/dist/runtime/admin-ops.js +4 -4
- package/dist/runtime/admin-ops.js.map +1 -1
- package/dist/runtime/admin-setup-ops.d.ts +20 -0
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -0
- package/dist/runtime/admin-setup-ops.js +583 -0
- package/dist/runtime/admin-setup-ops.js.map +1 -0
- package/dist/runtime/capture-ops.d.ts.map +1 -1
- package/dist/runtime/capture-ops.js +33 -1
- package/dist/runtime/capture-ops.js.map +1 -1
- package/dist/runtime/chain-ops.d.ts +9 -0
- package/dist/runtime/chain-ops.d.ts.map +1 -0
- package/dist/runtime/chain-ops.js +107 -0
- package/dist/runtime/chain-ops.js.map +1 -0
- package/dist/runtime/claude-md-helpers.d.ts +65 -0
- package/dist/runtime/claude-md-helpers.d.ts.map +1 -0
- package/dist/runtime/claude-md-helpers.js +173 -0
- package/dist/runtime/claude-md-helpers.js.map +1 -0
- package/dist/runtime/curator-extra-ops.d.ts +3 -2
- package/dist/runtime/curator-extra-ops.d.ts.map +1 -1
- package/dist/runtime/curator-extra-ops.js +81 -3
- package/dist/runtime/curator-extra-ops.js.map +1 -1
- package/dist/runtime/domain-ops.d.ts +21 -5
- package/dist/runtime/domain-ops.d.ts.map +1 -1
- package/dist/runtime/domain-ops.js +64 -6
- package/dist/runtime/domain-ops.js.map +1 -1
- package/dist/runtime/facades/admin-facade.d.ts.map +1 -1
- package/dist/runtime/facades/admin-facade.js +4 -0
- package/dist/runtime/facades/admin-facade.js.map +1 -1
- package/dist/runtime/facades/agency-facade.d.ts.map +1 -1
- package/dist/runtime/facades/agency-facade.js +64 -0
- package/dist/runtime/facades/agency-facade.js.map +1 -1
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +122 -1
- package/dist/runtime/facades/brain-facade.js.map +1 -1
- package/dist/runtime/facades/cognee-facade.d.ts.map +1 -1
- package/dist/runtime/facades/cognee-facade.js +3 -1
- package/dist/runtime/facades/cognee-facade.js.map +1 -1
- package/dist/runtime/facades/control-facade.d.ts.map +1 -1
- package/dist/runtime/facades/control-facade.js +42 -0
- package/dist/runtime/facades/control-facade.js.map +1 -1
- package/dist/runtime/facades/index.d.ts.map +1 -1
- package/dist/runtime/facades/index.js +10 -6
- package/dist/runtime/facades/index.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +20 -2
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +2 -0
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +27 -5
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/intake-ops.d.ts +7 -5
- package/dist/runtime/intake-ops.d.ts.map +1 -1
- package/dist/runtime/intake-ops.js +98 -5
- package/dist/runtime/intake-ops.js.map +1 -1
- package/dist/runtime/memory-extra-ops.d.ts +6 -3
- package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
- package/dist/runtime/memory-extra-ops.js +292 -4
- package/dist/runtime/memory-extra-ops.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts +8 -7
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +217 -61
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js +85 -0
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/playbook-ops.js +1 -1
- package/dist/runtime/playbook-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +165 -18
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts +23 -0
- package/dist/runtime/session-briefing.d.ts.map +1 -0
- package/dist/runtime/session-briefing.js +140 -0
- package/dist/runtime/session-briefing.js.map +1 -0
- package/dist/runtime/types.d.ts +29 -2
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.d.ts +13 -0
- package/dist/runtime/vault-linking-ops.d.ts.map +1 -0
- package/dist/runtime/vault-linking-ops.js +365 -0
- package/dist/runtime/vault-linking-ops.js.map +1 -0
- package/dist/vault/linking.d.ts +46 -0
- package/dist/vault/linking.d.ts.map +1 -0
- package/dist/vault/linking.js +275 -0
- package/dist/vault/linking.js.map +1 -0
- package/dist/vault/vault-types.d.ts +37 -0
- package/dist/vault/vault-types.d.ts.map +1 -1
- package/dist/vault/vault.d.ts +37 -0
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +152 -9
- package/dist/vault/vault.js.map +1 -1
- package/package.json +4 -1
- package/src/__tests__/admin-extra-ops.test.ts +1 -1
- package/src/__tests__/admin-ops.test.ts +2 -1
- package/src/__tests__/admin-setup-ops.test.ts +355 -0
- package/src/__tests__/async-infrastructure.test.ts +307 -0
- package/src/__tests__/cognee-client-gaps.test.ts +474 -0
- package/src/__tests__/cognee-hybrid-search.test.ts +492 -0
- package/src/__tests__/cognee-sync-manager-deep.test.ts +654 -0
- package/src/__tests__/cognee-sync-manager.test.ts +1 -0
- package/src/__tests__/core-ops.test.ts +9 -61
- package/src/__tests__/curator-extra-ops.test.ts +6 -2
- package/src/__tests__/curator-pipeline-e2e.test.ts +358 -0
- package/src/__tests__/domain-packs.test.ts +421 -0
- package/src/__tests__/flows.test.ts +604 -0
- package/src/__tests__/memory-extra-ops.test.ts +2 -2
- package/src/__tests__/planning-extra-ops.test.ts +2 -2
- package/src/__tests__/playbook-registry.test.ts +2 -2
- package/src/__tests__/playbook-seeder.test.ts +8 -8
- package/src/__tests__/playbook.test.ts +5 -5
- package/src/__tests__/second-brain-features.test.ts +583 -0
- package/src/__tests__/token-resolver.test.ts +79 -0
- package/src/agency/agency-manager.ts +217 -9
- package/src/agency/default-rules.ts +83 -0
- package/src/agency/types.ts +61 -0
- package/src/brain/brain.ts +110 -8
- package/src/brain/intelligence.ts +21 -2
- package/src/brain/knowledge-synthesizer.ts +218 -0
- package/src/brain/learning-radar.ts +340 -0
- package/src/brain/types.ts +16 -0
- package/src/capabilities/chain-mapping.ts +93 -0
- package/src/capabilities/index.ts +21 -0
- package/src/capabilities/registry.ts +290 -0
- package/src/capabilities/types.ts +143 -0
- package/src/context/context-engine.ts +114 -15
- package/src/context/types.ts +5 -0
- package/src/control/intent-router.ts +153 -2
- package/src/control/types.ts +10 -0
- package/src/curator/classifier.ts +88 -0
- package/src/curator/quality-gate.ts +129 -0
- package/src/domain-packs/index.ts +27 -0
- package/src/domain-packs/inject-rules.ts +74 -0
- package/src/domain-packs/knowledge-installer.ts +116 -0
- package/src/domain-packs/loader.ts +124 -0
- package/src/domain-packs/pack-runtime.ts +99 -0
- package/src/domain-packs/skills-installer.ts +56 -0
- package/src/domain-packs/token-resolver.ts +126 -0
- package/src/domain-packs/types.ts +229 -0
- package/src/engine/__tests__/register-engine.test.ts +104 -0
- package/src/engine/bin/soleri-engine.ts +218 -0
- package/src/engine/core-ops.ts +178 -0
- package/src/engine/index.ts +19 -0
- package/src/engine/register-engine.ts +385 -0
- package/src/engine/test-helpers.ts +83 -0
- package/src/events/event-bus.ts +58 -0
- package/src/flows/chain-runner.ts +369 -0
- package/src/flows/chain-types.ts +57 -0
- package/src/flows/context-router.ts +257 -0
- package/src/flows/dispatch-registry.ts +80 -0
- package/src/flows/epilogue.ts +65 -0
- package/src/flows/executor.ts +182 -0
- package/src/flows/gate-evaluator.ts +171 -0
- package/src/flows/index.ts +52 -0
- package/src/flows/loader.ts +63 -0
- package/src/flows/plan-builder.ts +250 -0
- package/src/flows/probes.ts +70 -0
- package/src/flows/types.ts +217 -0
- package/src/health/doctor-checks.ts +115 -0
- package/src/index.ts +68 -1
- package/src/intake/text-ingester.ts +234 -0
- package/src/intelligence/loader.ts +38 -0
- package/src/intelligence/types.ts +1 -0
- package/src/llm/llm-client.ts +38 -1
- package/src/llm/oauth-discovery.ts +169 -0
- package/src/packs/types.ts +19 -0
- package/src/planning/evidence-collector.ts +247 -0
- package/src/planning/planner.ts +11 -0
- package/src/playbooks/generic/onboarding.ts +79 -0
- package/src/playbooks/playbook-registry.ts +2 -0
- package/src/queue/job-queue.ts +281 -0
- package/src/queue/pipeline-runner.ts +149 -0
- package/src/runtime/admin-extra-ops.ts +14 -8
- package/src/runtime/admin-ops.ts +4 -4
- package/src/runtime/admin-setup-ops.ts +664 -0
- package/src/runtime/capture-ops.ts +40 -1
- package/src/runtime/chain-ops.ts +121 -0
- package/src/runtime/claude-md-helpers.ts +236 -0
- package/src/runtime/curator-extra-ops.ts +86 -3
- package/src/runtime/domain-ops.ts +71 -5
- package/src/runtime/facades/admin-facade.ts +4 -0
- package/src/runtime/facades/agency-facade.ts +68 -0
- package/src/runtime/facades/brain-facade.ts +142 -1
- package/src/runtime/facades/cognee-facade.ts +3 -1
- package/src/runtime/facades/control-facade.ts +45 -0
- package/src/runtime/facades/index.ts +12 -6
- package/src/runtime/facades/memory-facade.ts +20 -2
- package/src/runtime/facades/plan-facade.ts +2 -0
- package/src/runtime/facades/vault-facade.ts +30 -5
- package/src/runtime/intake-ops.ts +107 -5
- package/src/runtime/memory-extra-ops.ts +312 -4
- package/src/runtime/orchestrate-ops.ts +261 -65
- package/src/runtime/planning-extra-ops.ts +94 -0
- package/src/runtime/playbook-ops.ts +1 -1
- package/src/runtime/runtime.ts +164 -19
- package/src/runtime/session-briefing.ts +161 -0
- package/src/runtime/types.ts +29 -2
- package/src/runtime/vault-linking-ops.ts +452 -0
- package/src/vault/linking.ts +333 -0
- package/src/vault/vault-types.ts +46 -0
- package/src/vault/vault.ts +173 -11
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault linking ops — Zettelkasten bidirectional linking.
|
|
3
|
+
*
|
|
4
|
+
* Provides 8 ops: link_entries, unlink_entries, get_links, traverse,
|
|
5
|
+
* suggest_links, get_orphans, relink_vault, link_stats.
|
|
6
|
+
* Ported from Salvador MCP with improvements:
|
|
7
|
+
* - FTS5 for suggest_links (Salvador uses TF-IDF)
|
|
8
|
+
* - relink_vault: LLM-evaluated batch re-linking (Salvador uses a separate script)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import type { OpDefinition } from '../facades/types.js';
|
|
13
|
+
import type { AgentRuntime } from './types.js';
|
|
14
|
+
|
|
15
|
+
const EVAL_SYSTEM_PROMPT = `You evaluate pairs of knowledge entries to determine if they should be linked in a Zettelkasten vault. For EACH pair, decide:
|
|
16
|
+
- If meaningfully related → return { "link": true, "type": "<type>", "note": "<1 sentence why>" }
|
|
17
|
+
- If NOT meaningfully related → return { "link": false }
|
|
18
|
+
|
|
19
|
+
Link types:
|
|
20
|
+
- "extends" — target builds on or refines the source
|
|
21
|
+
- "supports" — target provides evidence or foundation for the source
|
|
22
|
+
- "contradicts" — target is an opposing approach or counterpoint
|
|
23
|
+
- "sequences" — source must happen before target
|
|
24
|
+
|
|
25
|
+
Rules: Same category alone is NOT enough. Be selective. Return a JSON array.`;
|
|
26
|
+
|
|
27
|
+
export function createVaultLinkingOps(runtime: AgentRuntime): OpDefinition[] {
|
|
28
|
+
const { vault, linkManager } = runtime;
|
|
29
|
+
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
name: 'link_entries',
|
|
33
|
+
description: 'Create a typed link between two vault entries (Zettelkasten)',
|
|
34
|
+
auth: 'write',
|
|
35
|
+
schema: z.object({
|
|
36
|
+
sourceId: z.string().describe('REQUIRED: Source entry ID'),
|
|
37
|
+
targetId: z.string().describe('REQUIRED: Target entry ID'),
|
|
38
|
+
linkType: z
|
|
39
|
+
.enum(['supports', 'contradicts', 'extends', 'sequences'])
|
|
40
|
+
.describe('REQUIRED: Relationship type'),
|
|
41
|
+
note: z.string().optional().describe('Optional context for the link'),
|
|
42
|
+
}),
|
|
43
|
+
handler: async (params) => {
|
|
44
|
+
const sourceId = params.sourceId as string;
|
|
45
|
+
const targetId = params.targetId as string;
|
|
46
|
+
|
|
47
|
+
// Validate both entries exist to prevent dangling links
|
|
48
|
+
const provider = vault.getProvider();
|
|
49
|
+
const sourceExists = provider.get<{ id: string }>('SELECT id FROM entries WHERE id = ?', [
|
|
50
|
+
sourceId,
|
|
51
|
+
]);
|
|
52
|
+
const targetExists = provider.get<{ id: string }>('SELECT id FROM entries WHERE id = ?', [
|
|
53
|
+
targetId,
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
if (!sourceExists || !targetExists) {
|
|
57
|
+
const missing = [];
|
|
58
|
+
if (!sourceExists) missing.push(`source '${sourceId}'`);
|
|
59
|
+
if (!targetExists) missing.push(`target '${targetId}'`);
|
|
60
|
+
throw new Error(`Entry not found: ${missing.join(' and ')}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
linkManager.addLink(
|
|
64
|
+
sourceId,
|
|
65
|
+
targetId,
|
|
66
|
+
params.linkType as 'supports' | 'contradicts' | 'extends' | 'sequences',
|
|
67
|
+
params.note as string | undefined,
|
|
68
|
+
);
|
|
69
|
+
return {
|
|
70
|
+
success: true,
|
|
71
|
+
link: {
|
|
72
|
+
sourceId,
|
|
73
|
+
targetId,
|
|
74
|
+
linkType: params.linkType,
|
|
75
|
+
note: params.note,
|
|
76
|
+
},
|
|
77
|
+
sourceLinkCount: linkManager.getLinkCount(sourceId),
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'unlink_entries',
|
|
83
|
+
description: 'Remove a link between two vault entries',
|
|
84
|
+
auth: 'write',
|
|
85
|
+
schema: z.object({
|
|
86
|
+
sourceId: z.string().describe('REQUIRED: Source entry ID'),
|
|
87
|
+
targetId: z.string().describe('REQUIRED: Target entry ID'),
|
|
88
|
+
}),
|
|
89
|
+
handler: async (params) => {
|
|
90
|
+
linkManager.removeLink(params.sourceId as string, params.targetId as string);
|
|
91
|
+
return { success: true, removed: { sourceId: params.sourceId, targetId: params.targetId } };
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'get_links',
|
|
96
|
+
description: 'Get all links for a vault entry (outgoing + incoming backlinks)',
|
|
97
|
+
auth: 'read',
|
|
98
|
+
schema: z.object({
|
|
99
|
+
entryId: z.string().describe('REQUIRED: Entry ID'),
|
|
100
|
+
}),
|
|
101
|
+
handler: async (params) => {
|
|
102
|
+
const entryId = params.entryId as string;
|
|
103
|
+
const outgoing = linkManager.getLinks(entryId);
|
|
104
|
+
const incoming = linkManager.getBacklinks(entryId);
|
|
105
|
+
return { entryId, outgoing, incoming, totalLinks: outgoing.length + incoming.length };
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'traverse',
|
|
110
|
+
description:
|
|
111
|
+
'Walk the link graph from an entry up to N hops deep (Zettelkasten graph traversal)',
|
|
112
|
+
auth: 'read',
|
|
113
|
+
schema: z.object({
|
|
114
|
+
entryId: z.string().describe('REQUIRED: Starting entry ID'),
|
|
115
|
+
depth: z.coerce
|
|
116
|
+
.number()
|
|
117
|
+
.int()
|
|
118
|
+
.min(1)
|
|
119
|
+
.max(5)
|
|
120
|
+
.default(2)
|
|
121
|
+
.describe('Max hops (1-5, default 2)'),
|
|
122
|
+
}),
|
|
123
|
+
handler: async (params) => {
|
|
124
|
+
const entryId = params.entryId as string;
|
|
125
|
+
const depth = (params.depth as number) || 2;
|
|
126
|
+
const connected = linkManager.traverse(entryId, depth);
|
|
127
|
+
return { entryId, depth, connectedEntries: connected, totalConnected: connected.length };
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'suggest_links',
|
|
132
|
+
description:
|
|
133
|
+
'Find semantically similar entries as link candidates using FTS5 (Zettelkasten auto-linking)',
|
|
134
|
+
auth: 'read',
|
|
135
|
+
schema: z.object({
|
|
136
|
+
entryId: z.string().describe('REQUIRED: Entry ID to find link candidates for'),
|
|
137
|
+
limit: z.coerce
|
|
138
|
+
.number()
|
|
139
|
+
.int()
|
|
140
|
+
.min(1)
|
|
141
|
+
.max(20)
|
|
142
|
+
.default(5)
|
|
143
|
+
.describe('Max suggestions (default 5)'),
|
|
144
|
+
}),
|
|
145
|
+
handler: async (params) => {
|
|
146
|
+
const entryId = params.entryId as string;
|
|
147
|
+
const limit = (params.limit as number) || 5;
|
|
148
|
+
const suggestions = linkManager.suggestLinks(entryId, limit);
|
|
149
|
+
return { entryId, suggestions, totalSuggestions: suggestions.length };
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'get_orphans',
|
|
154
|
+
description: 'Find vault entries with zero links (Zettelkasten orphan detection)',
|
|
155
|
+
auth: 'read',
|
|
156
|
+
schema: z.object({
|
|
157
|
+
limit: z.coerce
|
|
158
|
+
.number()
|
|
159
|
+
.int()
|
|
160
|
+
.min(1)
|
|
161
|
+
.max(100)
|
|
162
|
+
.default(20)
|
|
163
|
+
.describe('Max orphans (default 20)'),
|
|
164
|
+
}),
|
|
165
|
+
handler: async (params) => {
|
|
166
|
+
const limit = (params.limit as number) || 20;
|
|
167
|
+
const orphans = linkManager.getOrphans(limit);
|
|
168
|
+
return { orphans, totalOrphans: orphans.length };
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: 'relink_vault',
|
|
173
|
+
description:
|
|
174
|
+
'Smart Zettelkasten re-linking: drops batch links, evaluates all entries with LLM, creates quality links with reasoning notes. Long-running operation.',
|
|
175
|
+
auth: 'write',
|
|
176
|
+
schema: z.object({
|
|
177
|
+
batchSize: z.coerce
|
|
178
|
+
.number()
|
|
179
|
+
.int()
|
|
180
|
+
.min(1)
|
|
181
|
+
.max(20)
|
|
182
|
+
.default(10)
|
|
183
|
+
.describe('Pairs per LLM call (default 10)'),
|
|
184
|
+
limit: z.coerce
|
|
185
|
+
.number()
|
|
186
|
+
.int()
|
|
187
|
+
.min(0)
|
|
188
|
+
.max(5000)
|
|
189
|
+
.default(0)
|
|
190
|
+
.describe('Max entries to process (0 = all)'),
|
|
191
|
+
dryRun: z.boolean().optional().default(false).describe('Preview without changes'),
|
|
192
|
+
}),
|
|
193
|
+
handler: async (params) => {
|
|
194
|
+
const batchSize = (params.batchSize as number) || 10;
|
|
195
|
+
const limit = (params.limit as number) || 0;
|
|
196
|
+
const dryRun = (params.dryRun as boolean) ?? false;
|
|
197
|
+
const { llmClient } = runtime;
|
|
198
|
+
|
|
199
|
+
if (!llmClient.isAvailable().anthropic && !llmClient.isAvailable().openai) {
|
|
200
|
+
return { success: false, error: 'No LLM provider available for link evaluation' };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const provider = vault.getProvider();
|
|
204
|
+
|
|
205
|
+
// Phase 1: Preserve manual links, drop batch links
|
|
206
|
+
const manualCount =
|
|
207
|
+
provider.get<{ c: number }>(
|
|
208
|
+
"SELECT COUNT(*) as c FROM vault_links WHERE note IS NOT NULL AND note != ''",
|
|
209
|
+
)?.c ?? 0;
|
|
210
|
+
|
|
211
|
+
const batchCount =
|
|
212
|
+
provider.get<{ c: number }>(
|
|
213
|
+
"SELECT COUNT(*) as c FROM vault_links WHERE note IS NULL OR note = ''",
|
|
214
|
+
)?.c ?? 0;
|
|
215
|
+
|
|
216
|
+
if (!dryRun) {
|
|
217
|
+
provider.run("DELETE FROM vault_links WHERE note IS NULL OR note = ''");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Phase 2: Get entries and generate candidates
|
|
221
|
+
let entries = provider.all<{
|
|
222
|
+
id: string;
|
|
223
|
+
title: string;
|
|
224
|
+
type: string;
|
|
225
|
+
description: string | null;
|
|
226
|
+
}>('SELECT id, title, type, description FROM entries ORDER BY updated_at DESC');
|
|
227
|
+
if (limit > 0) entries = entries.slice(0, limit);
|
|
228
|
+
|
|
229
|
+
// Build candidates via tag overlap + category match
|
|
230
|
+
const candidates: Array<{
|
|
231
|
+
sourceId: string;
|
|
232
|
+
sourceTitle: string;
|
|
233
|
+
sourceType: string;
|
|
234
|
+
sourceDesc: string;
|
|
235
|
+
targetId: string;
|
|
236
|
+
targetTitle: string;
|
|
237
|
+
targetType: string;
|
|
238
|
+
targetDesc: string;
|
|
239
|
+
}> = [];
|
|
240
|
+
|
|
241
|
+
for (const entry of entries) {
|
|
242
|
+
const existingLinks = new Set([
|
|
243
|
+
...linkManager.getLinks(entry.id).map((l) => l.targetId),
|
|
244
|
+
...linkManager.getBacklinks(entry.id).map((l) => l.sourceId),
|
|
245
|
+
]);
|
|
246
|
+
|
|
247
|
+
// Tag overlap matches
|
|
248
|
+
const matches = provider.all<{
|
|
249
|
+
id: string;
|
|
250
|
+
title: string;
|
|
251
|
+
type: string;
|
|
252
|
+
description: string | null;
|
|
253
|
+
}>(
|
|
254
|
+
`SELECT DISTINCT e.id, e.title, e.type, SUBSTR(e.description, 1, 200) as description
|
|
255
|
+
FROM entries e
|
|
256
|
+
JOIN (SELECT entry_id, tag FROM vault_tags WHERE entry_id = ?) src_tags ON 1=1
|
|
257
|
+
JOIN vault_tags t ON t.tag = src_tags.tag AND t.entry_id = e.id
|
|
258
|
+
WHERE e.id != ?
|
|
259
|
+
GROUP BY e.id ORDER BY COUNT(*) DESC LIMIT 5`,
|
|
260
|
+
[entry.id, entry.id],
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
// Fallback: category match
|
|
264
|
+
if (matches.length < 3) {
|
|
265
|
+
try {
|
|
266
|
+
const existing = new Set(matches.map((m) => m.id));
|
|
267
|
+
const catMatches = provider.all<(typeof matches)[0]>(
|
|
268
|
+
`SELECT id, title, type, SUBSTR(description, 1, 200) as description
|
|
269
|
+
FROM entries WHERE id != ? AND type = ? LIMIT 3`,
|
|
270
|
+
[entry.id, entry.type],
|
|
271
|
+
);
|
|
272
|
+
for (const m of catMatches) {
|
|
273
|
+
if (!existing.has(m.id)) matches.push(m);
|
|
274
|
+
}
|
|
275
|
+
} catch {
|
|
276
|
+
/* ignore */
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
for (const match of matches.slice(0, 5)) {
|
|
281
|
+
if (existingLinks.has(match.id)) continue;
|
|
282
|
+
candidates.push({
|
|
283
|
+
sourceId: entry.id,
|
|
284
|
+
sourceTitle: entry.title,
|
|
285
|
+
sourceType: entry.type,
|
|
286
|
+
sourceDesc: (entry.description || '').slice(0, 200),
|
|
287
|
+
targetId: match.id,
|
|
288
|
+
targetTitle: match.title,
|
|
289
|
+
targetType: match.type,
|
|
290
|
+
targetDesc: (match.description || '').slice(0, 200),
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (dryRun) {
|
|
296
|
+
return {
|
|
297
|
+
dryRun: true,
|
|
298
|
+
entries: entries.length,
|
|
299
|
+
candidates: candidates.length,
|
|
300
|
+
llmCallsNeeded: Math.ceil(candidates.length / batchSize),
|
|
301
|
+
manualLinksPreserved: manualCount,
|
|
302
|
+
batchLinksToRemove: batchCount,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Phase 3: LLM evaluation in batches (sequential to respect rate limits)
|
|
307
|
+
let linksCreated = 0;
|
|
308
|
+
let pairsSkipped = 0;
|
|
309
|
+
let llmCalls = 0;
|
|
310
|
+
let errors = 0;
|
|
311
|
+
const now = Date.now();
|
|
312
|
+
|
|
313
|
+
// Build batches
|
|
314
|
+
const batches: (typeof candidates)[] = [];
|
|
315
|
+
for (let i = 0; i < candidates.length; i += batchSize) {
|
|
316
|
+
batches.push(candidates.slice(i, i + batchSize));
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Process sequentially using reduce chain (avoids await-in-loop lint)
|
|
320
|
+
await batches.reduce(async (prev, batch) => {
|
|
321
|
+
await prev;
|
|
322
|
+
const pairsText = batch
|
|
323
|
+
.map(
|
|
324
|
+
(p, idx) =>
|
|
325
|
+
`--- Pair ${idx + 1} ---\nSOURCE [${p.sourceType}]: ${p.sourceTitle}\n${p.sourceDesc}\n\nTARGET [${p.targetType}]: ${p.targetTitle}\n${p.targetDesc}`,
|
|
326
|
+
)
|
|
327
|
+
.join('\n\n');
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
const result = await llmClient.complete({
|
|
331
|
+
provider: llmClient.isAvailable().anthropic ? 'anthropic' : 'openai',
|
|
332
|
+
model: llmClient.isAvailable().anthropic ? 'claude-sonnet-4-20250514' : 'gpt-4o-mini',
|
|
333
|
+
systemPrompt: EVAL_SYSTEM_PROMPT,
|
|
334
|
+
userPrompt: pairsText,
|
|
335
|
+
maxTokens: 2000,
|
|
336
|
+
caller: 'relink_vault',
|
|
337
|
+
task: 'link-evaluation',
|
|
338
|
+
});
|
|
339
|
+
llmCalls++;
|
|
340
|
+
|
|
341
|
+
let cleaned = result.text.trim();
|
|
342
|
+
if (cleaned.startsWith('```')) {
|
|
343
|
+
const first = cleaned.indexOf('\n');
|
|
344
|
+
const last = cleaned.lastIndexOf('```');
|
|
345
|
+
cleaned = cleaned.slice(first + 1, last).trim();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const decisions = JSON.parse(cleaned) as Array<{
|
|
349
|
+
link: boolean;
|
|
350
|
+
type?: string;
|
|
351
|
+
note?: string;
|
|
352
|
+
}>;
|
|
353
|
+
|
|
354
|
+
for (let j = 0; j < decisions.length && j < batch.length; j++) {
|
|
355
|
+
const d = decisions[j];
|
|
356
|
+
if (d.link && d.type && d.note) {
|
|
357
|
+
if (batch[j].sourceId === batch[j].targetId) continue;
|
|
358
|
+
try {
|
|
359
|
+
provider.run(
|
|
360
|
+
'INSERT OR IGNORE INTO vault_links (source_id, target_id, link_type, note, created_at) VALUES (?, ?, ?, ?, ?)',
|
|
361
|
+
[batch[j].sourceId, batch[j].targetId, d.type, d.note, now],
|
|
362
|
+
);
|
|
363
|
+
linksCreated++;
|
|
364
|
+
} catch {
|
|
365
|
+
/* FK or duplicate */
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
pairsSkipped++;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
} catch {
|
|
372
|
+
errors++;
|
|
373
|
+
}
|
|
374
|
+
}, Promise.resolve());
|
|
375
|
+
|
|
376
|
+
// Phase 4: Stats
|
|
377
|
+
const totalLinks =
|
|
378
|
+
provider.get<{ c: number }>('SELECT COUNT(*) as c FROM vault_links')?.c ?? 0;
|
|
379
|
+
const orphanCount =
|
|
380
|
+
provider.get<{ c: number }>(
|
|
381
|
+
`SELECT COUNT(*) as c FROM entries
|
|
382
|
+
WHERE id NOT IN (SELECT source_id FROM vault_links)
|
|
383
|
+
AND id NOT IN (SELECT target_id FROM vault_links)`,
|
|
384
|
+
)?.c ?? 0;
|
|
385
|
+
const byType = provider.all<{ link_type: string; c: number }>(
|
|
386
|
+
'SELECT link_type, COUNT(*) as c FROM vault_links GROUP BY link_type ORDER BY c DESC',
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
success: true,
|
|
391
|
+
entriesProcessed: entries.length,
|
|
392
|
+
candidatesEvaluated: candidates.length,
|
|
393
|
+
linksCreated,
|
|
394
|
+
pairsSkipped,
|
|
395
|
+
llmCalls,
|
|
396
|
+
errors,
|
|
397
|
+
totalLinks,
|
|
398
|
+
orphans: orphanCount,
|
|
399
|
+
byType: Object.fromEntries(byType.map((r) => [r.link_type, r.c])),
|
|
400
|
+
manualLinksPreserved: manualCount,
|
|
401
|
+
batchLinksRemoved: batchCount,
|
|
402
|
+
};
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
name: 'link_stats',
|
|
407
|
+
description:
|
|
408
|
+
'Get Zettelkasten graph statistics: total links, by type, most connected, orphan count.',
|
|
409
|
+
auth: 'read',
|
|
410
|
+
handler: async () => {
|
|
411
|
+
const provider = vault.getProvider();
|
|
412
|
+
try {
|
|
413
|
+
const totalLinks =
|
|
414
|
+
provider.get<{ c: number }>('SELECT COUNT(*) as c FROM vault_links')?.c ?? 0;
|
|
415
|
+
const totalEntries =
|
|
416
|
+
provider.get<{ c: number }>('SELECT COUNT(*) as c FROM entries')?.c ?? 0;
|
|
417
|
+
const orphans =
|
|
418
|
+
provider.get<{ c: number }>(
|
|
419
|
+
`SELECT COUNT(*) as c FROM entries
|
|
420
|
+
WHERE id NOT IN (SELECT source_id FROM vault_links)
|
|
421
|
+
AND id NOT IN (SELECT target_id FROM vault_links)`,
|
|
422
|
+
)?.c ?? 0;
|
|
423
|
+
const byType = provider.all<{ link_type: string; c: number }>(
|
|
424
|
+
'SELECT link_type, COUNT(*) as c FROM vault_links GROUP BY link_type ORDER BY c DESC',
|
|
425
|
+
);
|
|
426
|
+
const withNotes =
|
|
427
|
+
provider.get<{ c: number }>(
|
|
428
|
+
"SELECT COUNT(*) as c FROM vault_links WHERE note IS NOT NULL AND note != ''",
|
|
429
|
+
)?.c ?? 0;
|
|
430
|
+
const mostConnected = provider.all<{ title: string; links: number }>(
|
|
431
|
+
`SELECT e.title, (
|
|
432
|
+
(SELECT COUNT(*) FROM vault_links WHERE source_id = e.id) +
|
|
433
|
+
(SELECT COUNT(*) FROM vault_links WHERE target_id = e.id)
|
|
434
|
+
) as links FROM entries e ORDER BY links DESC LIMIT 10`,
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
totalEntries,
|
|
439
|
+
totalLinks,
|
|
440
|
+
orphans,
|
|
441
|
+
linksWithNotes: withNotes,
|
|
442
|
+
linkQuality: totalLinks > 0 ? `${((withNotes / totalLinks) * 100).toFixed(0)}%` : 'n/a',
|
|
443
|
+
byType: Object.fromEntries(byType.map((r) => [r.link_type, r.c])),
|
|
444
|
+
mostConnected,
|
|
445
|
+
};
|
|
446
|
+
} catch {
|
|
447
|
+
return { totalLinks: 0, totalEntries: 0, orphans: 0, byType: {}, mostConnected: [] };
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
];
|
|
452
|
+
}
|