@goondocks/myco 0.6.4 → 0.9.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/.claude-plugin/marketplace.json +2 -3
- package/.claude-plugin/plugin.json +3 -3
- package/CONTRIBUTING.md +37 -30
- package/README.md +64 -28
- package/bin/myco-run +2 -0
- package/dist/agent-run-EFICNTAU.js +34 -0
- package/dist/agent-run-EFICNTAU.js.map +1 -0
- package/dist/agent-tasks-RXJ7Z5NG.js +180 -0
- package/dist/agent-tasks-RXJ7Z5NG.js.map +1 -0
- package/dist/chunk-2T7RPVPP.js +116 -0
- package/dist/chunk-2T7RPVPP.js.map +1 -0
- package/dist/chunk-3K5WGSJ4.js +165 -0
- package/dist/chunk-3K5WGSJ4.js.map +1 -0
- package/dist/chunk-46PWOKSI.js +26 -0
- package/dist/chunk-46PWOKSI.js.map +1 -0
- package/dist/chunk-4LPQ26CK.js +277 -0
- package/dist/chunk-4LPQ26CK.js.map +1 -0
- package/dist/chunk-5PEUFJ6U.js +92 -0
- package/dist/chunk-5PEUFJ6U.js.map +1 -0
- package/dist/chunk-5VZ52A4T.js +136 -0
- package/dist/chunk-5VZ52A4T.js.map +1 -0
- package/dist/chunk-BUSP3OJB.js +103 -0
- package/dist/chunk-BUSP3OJB.js.map +1 -0
- package/dist/chunk-D7TYRPRM.js +7312 -0
- package/dist/chunk-D7TYRPRM.js.map +1 -0
- package/dist/chunk-DCXRSSBP.js +22 -0
- package/dist/chunk-DCXRSSBP.js.map +1 -0
- package/dist/chunk-E4VLWIJC.js +2 -0
- package/dist/chunk-FFAYUQ5N.js +39 -0
- package/dist/chunk-FFAYUQ5N.js.map +1 -0
- package/dist/chunk-IB76KGBY.js +2 -0
- package/dist/chunk-JMJJEQ3P.js +486 -0
- package/dist/chunk-JMJJEQ3P.js.map +1 -0
- package/dist/{chunk-N33KUCFP.js → chunk-JTYZRPX5.js} +1 -9
- package/dist/chunk-JTYZRPX5.js.map +1 -0
- package/dist/{chunk-NLUE6CYG.js → chunk-JYOOJCPQ.js} +33 -17
- package/dist/chunk-JYOOJCPQ.js.map +1 -0
- package/dist/{chunk-Z74SDEKE.js → chunk-KB4DGYIY.js} +91 -9
- package/dist/chunk-KB4DGYIY.js.map +1 -0
- package/dist/{chunk-ERG2IEWX.js → chunk-KH64DHOY.js} +3 -7413
- package/dist/chunk-KH64DHOY.js.map +1 -0
- package/dist/chunk-KV4OC4H3.js +498 -0
- package/dist/chunk-KV4OC4H3.js.map +1 -0
- package/dist/chunk-KYLDNM7H.js +66 -0
- package/dist/chunk-KYLDNM7H.js.map +1 -0
- package/dist/chunk-LPUQPDC2.js +19 -0
- package/dist/chunk-LPUQPDC2.js.map +1 -0
- package/dist/chunk-M5XWW7UI.js +97 -0
- package/dist/chunk-M5XWW7UI.js.map +1 -0
- package/dist/chunk-MHSCMET3.js +275 -0
- package/dist/chunk-MHSCMET3.js.map +1 -0
- package/dist/chunk-MYX5NCRH.js +45 -0
- package/dist/chunk-MYX5NCRH.js.map +1 -0
- package/dist/chunk-OXZSXYAT.js +877 -0
- package/dist/chunk-OXZSXYAT.js.map +1 -0
- package/dist/chunk-PB6TOLRQ.js +35 -0
- package/dist/chunk-PB6TOLRQ.js.map +1 -0
- package/dist/chunk-PT5IC642.js +162 -0
- package/dist/chunk-PT5IC642.js.map +1 -0
- package/dist/chunk-QIK2XSDQ.js +187 -0
- package/dist/chunk-QIK2XSDQ.js.map +1 -0
- package/dist/chunk-RJ6ZQKG5.js +26 -0
- package/dist/chunk-RJ6ZQKG5.js.map +1 -0
- package/dist/{chunk-YIQLYIHW.js → chunk-TRUJLI6K.js} +29 -43
- package/dist/chunk-TRUJLI6K.js.map +1 -0
- package/dist/chunk-U3IBO3O3.js +41 -0
- package/dist/chunk-U3IBO3O3.js.map +1 -0
- package/dist/{chunk-7WHF2OIZ.js → chunk-UBZPD4HN.js} +25 -7
- package/dist/chunk-UBZPD4HN.js.map +1 -0
- package/dist/{chunk-HIN3UVOG.js → chunk-V7XG6V6C.js} +20 -11
- package/dist/chunk-V7XG6V6C.js.map +1 -0
- package/dist/chunk-WGTCA2NU.js +84 -0
- package/dist/chunk-WGTCA2NU.js.map +1 -0
- package/dist/{chunk-O6PERU7U.js → chunk-XNOCTDHF.js} +2 -2
- package/dist/chunk-YDN4OM33.js +80 -0
- package/dist/chunk-YDN4OM33.js.map +1 -0
- package/dist/cli-ODLFRIYS.js +128 -0
- package/dist/cli-ODLFRIYS.js.map +1 -0
- package/dist/client-EYOTW3JU.js +19 -0
- package/dist/client-MXRNQ5FI.js +13 -0
- package/dist/{config-IBS6KOLQ.js → config-UR5BSGVX.js} +21 -34
- package/dist/config-UR5BSGVX.js.map +1 -0
- package/dist/detect-H5OPI7GD.js +17 -0
- package/dist/detect-H5OPI7GD.js.map +1 -0
- package/dist/detect-providers-Q42OD4OS.js +26 -0
- package/dist/detect-providers-Q42OD4OS.js.map +1 -0
- package/dist/doctor-JLKTXDEH.js +258 -0
- package/dist/doctor-JLKTXDEH.js.map +1 -0
- package/dist/executor-ONSDHPGX.js +1441 -0
- package/dist/executor-ONSDHPGX.js.map +1 -0
- package/dist/init-6GWY345B.js +198 -0
- package/dist/init-6GWY345B.js.map +1 -0
- package/dist/init-wizard-UONLDYLI.js +294 -0
- package/dist/init-wizard-UONLDYLI.js.map +1 -0
- package/dist/llm-BV3QNVRD.js +17 -0
- package/dist/llm-BV3QNVRD.js.map +1 -0
- package/dist/loader-SH67XD54.js +28 -0
- package/dist/loader-SH67XD54.js.map +1 -0
- package/dist/loader-XVXKZZDH.js +18 -0
- package/dist/loader-XVXKZZDH.js.map +1 -0
- package/dist/{chunk-H7PRCVGQ.js → logs-QZVYF6FP.js} +74 -5
- package/dist/logs-QZVYF6FP.js.map +1 -0
- package/dist/main-BMCL7CPO.js +4393 -0
- package/dist/main-BMCL7CPO.js.map +1 -0
- package/dist/openai-embeddings-C265WRNK.js +14 -0
- package/dist/openai-embeddings-C265WRNK.js.map +1 -0
- package/dist/openrouter-U6VFCRX2.js +14 -0
- package/dist/openrouter-U6VFCRX2.js.map +1 -0
- package/dist/post-compact-OWFSOITU.js +26 -0
- package/dist/post-compact-OWFSOITU.js.map +1 -0
- package/dist/post-tool-use-DOUM7CGQ.js +56 -0
- package/dist/post-tool-use-DOUM7CGQ.js.map +1 -0
- package/dist/post-tool-use-failure-SG3C7PE6.js +28 -0
- package/dist/post-tool-use-failure-SG3C7PE6.js.map +1 -0
- package/dist/pre-compact-3J33CHXQ.js +25 -0
- package/dist/pre-compact-3J33CHXQ.js.map +1 -0
- package/dist/provider-check-3WBPZADE.js +12 -0
- package/dist/provider-check-3WBPZADE.js.map +1 -0
- package/dist/registry-J4XTWARS.js +25 -0
- package/dist/registry-J4XTWARS.js.map +1 -0
- package/dist/resolution-events-TFEQPVKS.js +12 -0
- package/dist/resolution-events-TFEQPVKS.js.map +1 -0
- package/dist/resolve-3FEUV462.js +9 -0
- package/dist/resolve-3FEUV462.js.map +1 -0
- package/dist/{restart-XCMILOL5.js → restart-2VM33WOB.js} +10 -6
- package/dist/{restart-XCMILOL5.js.map → restart-2VM33WOB.js.map} +1 -1
- package/dist/search-ZGQR5MDE.js +91 -0
- package/dist/search-ZGQR5MDE.js.map +1 -0
- package/dist/{server-6UDN35QN.js → server-6KMBJCHZ.js} +308 -517
- package/dist/server-6KMBJCHZ.js.map +1 -0
- package/dist/session-Z2FXDDG6.js +68 -0
- package/dist/session-Z2FXDDG6.js.map +1 -0
- package/dist/session-end-FLVX32LE.js +38 -0
- package/dist/session-end-FLVX32LE.js.map +1 -0
- package/dist/session-start-UCLK7PXE.js +169 -0
- package/dist/session-start-UCLK7PXE.js.map +1 -0
- package/dist/setup-digest-4KDSXAIV.js +15 -0
- package/dist/setup-digest-4KDSXAIV.js.map +1 -0
- package/dist/setup-llm-GKMCHURK.js +81 -0
- package/dist/setup-llm-GKMCHURK.js.map +1 -0
- package/dist/src/agent/definitions/agent.yaml +35 -0
- package/dist/src/agent/definitions/tasks/digest-only.yaml +84 -0
- package/dist/src/agent/definitions/tasks/extract-only.yaml +87 -0
- package/dist/src/agent/definitions/tasks/full-intelligence.yaml +472 -0
- package/dist/src/agent/definitions/tasks/graph-maintenance.yaml +92 -0
- package/dist/src/agent/definitions/tasks/review-session.yaml +132 -0
- package/dist/src/agent/definitions/tasks/supersession-sweep.yaml +86 -0
- package/dist/src/agent/definitions/tasks/title-summary.yaml +88 -0
- package/dist/src/agent/prompts/agent.md +121 -0
- package/dist/src/agent/prompts/orchestrator.md +91 -0
- package/dist/src/cli.js +1 -8
- package/dist/src/cli.js.map +1 -1
- package/dist/src/daemon/main.js +1 -8
- package/dist/src/daemon/main.js.map +1 -1
- package/dist/src/hooks/post-tool-use.js +3 -50
- package/dist/src/hooks/post-tool-use.js.map +1 -1
- package/dist/src/hooks/session-end.js +3 -32
- package/dist/src/hooks/session-end.js.map +1 -1
- package/dist/src/hooks/session-start.js +2 -8
- package/dist/src/hooks/session-start.js.map +1 -1
- package/dist/src/hooks/stop.js +3 -42
- package/dist/src/hooks/stop.js.map +1 -1
- package/dist/src/hooks/user-prompt-submit.js +3 -53
- package/dist/src/hooks/user-prompt-submit.js.map +1 -1
- package/dist/src/mcp/server.js +1 -8
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/prompts/digest-system.md +1 -1
- package/dist/src/symbionts/manifests/claude-code.yaml +16 -0
- package/dist/src/symbionts/manifests/cursor.yaml +14 -0
- package/dist/stats-IUJPZSVZ.js +94 -0
- package/dist/stats-IUJPZSVZ.js.map +1 -0
- package/dist/stop-XRQLLXST.js +42 -0
- package/dist/stop-XRQLLXST.js.map +1 -0
- package/dist/stop-failure-2CAJJKRG.js +26 -0
- package/dist/stop-failure-2CAJJKRG.js.map +1 -0
- package/dist/subagent-start-MWWQTZMQ.js +26 -0
- package/dist/subagent-start-MWWQTZMQ.js.map +1 -0
- package/dist/subagent-stop-PJXYGRXB.js +28 -0
- package/dist/subagent-stop-PJXYGRXB.js.map +1 -0
- package/dist/task-completed-4LFRJVGI.js +27 -0
- package/dist/task-completed-4LFRJVGI.js.map +1 -0
- package/dist/ui/assets/index-DZrElonz.js +744 -0
- package/dist/ui/assets/index-TkeiYbZB.css +1 -0
- package/dist/ui/favicon.svg +7 -7
- package/dist/ui/fonts/Inter-Variable.woff2 +0 -0
- package/dist/ui/fonts/JetBrainsMono-Variable.woff2 +0 -0
- package/dist/ui/fonts/Newsreader-Italic-Variable.woff2 +0 -0
- package/dist/ui/fonts/Newsreader-Variable.woff2 +0 -0
- package/dist/ui/index.html +2 -2
- package/dist/user-prompt-submit-KSM3AR6P.js +59 -0
- package/dist/user-prompt-submit-KSM3AR6P.js.map +1 -0
- package/dist/{verify-TOWQHPBX.js → verify-UDAYVX37.js} +17 -22
- package/dist/verify-UDAYVX37.js.map +1 -0
- package/dist/{version-36RVCQA6.js → version-KLBN4HZT.js} +3 -4
- package/dist/version-KLBN4HZT.js.map +1 -0
- package/hooks/hooks.json +82 -5
- package/package.json +6 -3
- package/skills/myco/SKILL.md +10 -10
- package/skills/myco/references/cli-usage.md +15 -13
- package/skills/myco/references/vault-status.md +3 -3
- package/skills/myco/references/wisdom.md +4 -4
- package/skills/myco-curate/SKILL.md +86 -0
- package/dist/chunk-2ZIBCEYO.js +0 -113
- package/dist/chunk-2ZIBCEYO.js.map +0 -1
- package/dist/chunk-4RMSHZE4.js +0 -107
- package/dist/chunk-4RMSHZE4.js.map +0 -1
- package/dist/chunk-4XVKZ3WA.js +0 -1078
- package/dist/chunk-4XVKZ3WA.js.map +0 -1
- package/dist/chunk-6FQISQNA.js +0 -61
- package/dist/chunk-6FQISQNA.js.map +0 -1
- package/dist/chunk-7WHF2OIZ.js.map +0 -1
- package/dist/chunk-ERG2IEWX.js.map +0 -1
- package/dist/chunk-FPRXMJLT.js +0 -56
- package/dist/chunk-FPRXMJLT.js.map +0 -1
- package/dist/chunk-GENQ5QGP.js +0 -37
- package/dist/chunk-GENQ5QGP.js.map +0 -1
- package/dist/chunk-H7PRCVGQ.js.map +0 -1
- package/dist/chunk-HIN3UVOG.js.map +0 -1
- package/dist/chunk-HYVT345Y.js +0 -159
- package/dist/chunk-HYVT345Y.js.map +0 -1
- package/dist/chunk-J4D4CROB.js +0 -143
- package/dist/chunk-J4D4CROB.js.map +0 -1
- package/dist/chunk-MDLSAFPP.js +0 -99
- package/dist/chunk-MDLSAFPP.js.map +0 -1
- package/dist/chunk-N33KUCFP.js.map +0 -1
- package/dist/chunk-NL6WQO56.js +0 -65
- package/dist/chunk-NL6WQO56.js.map +0 -1
- package/dist/chunk-NLUE6CYG.js.map +0 -1
- package/dist/chunk-P723N2LP.js +0 -147
- package/dist/chunk-P723N2LP.js.map +0 -1
- package/dist/chunk-QLUE3BUL.js +0 -161
- package/dist/chunk-QLUE3BUL.js.map +0 -1
- package/dist/chunk-QN4W3JUA.js +0 -43
- package/dist/chunk-QN4W3JUA.js.map +0 -1
- package/dist/chunk-RGVBGTD6.js +0 -21
- package/dist/chunk-RGVBGTD6.js.map +0 -1
- package/dist/chunk-TWSTAVLO.js +0 -132
- package/dist/chunk-TWSTAVLO.js.map +0 -1
- package/dist/chunk-UP4P4OAA.js +0 -4423
- package/dist/chunk-UP4P4OAA.js.map +0 -1
- package/dist/chunk-YIQLYIHW.js.map +0 -1
- package/dist/chunk-YTFXA4RX.js +0 -86
- package/dist/chunk-YTFXA4RX.js.map +0 -1
- package/dist/chunk-Z74SDEKE.js.map +0 -1
- package/dist/cli-IHILSS6N.js +0 -97
- package/dist/cli-IHILSS6N.js.map +0 -1
- package/dist/client-AGFNR2S4.js +0 -12
- package/dist/config-IBS6KOLQ.js.map +0 -1
- package/dist/curate-3D4GHKJH.js +0 -78
- package/dist/curate-3D4GHKJH.js.map +0 -1
- package/dist/detect-providers-XEP4QA3R.js +0 -35
- package/dist/detect-providers-XEP4QA3R.js.map +0 -1
- package/dist/digest-7HLJXL77.js +0 -85
- package/dist/digest-7HLJXL77.js.map +0 -1
- package/dist/init-ARQ53JOR.js +0 -109
- package/dist/init-ARQ53JOR.js.map +0 -1
- package/dist/logs-IENORIYR.js +0 -84
- package/dist/logs-IENORIYR.js.map +0 -1
- package/dist/main-6AGPIMH2.js +0 -5715
- package/dist/main-6AGPIMH2.js.map +0 -1
- package/dist/rebuild-Q2ACEB6F.js +0 -64
- package/dist/rebuild-Q2ACEB6F.js.map +0 -1
- package/dist/reprocess-CDEFGQOV.js +0 -79
- package/dist/reprocess-CDEFGQOV.js.map +0 -1
- package/dist/search-7W25SKCB.js +0 -120
- package/dist/search-7W25SKCB.js.map +0 -1
- package/dist/server-6UDN35QN.js.map +0 -1
- package/dist/session-F326AWCH.js +0 -44
- package/dist/session-F326AWCH.js.map +0 -1
- package/dist/session-start-K6IGAC7H.js +0 -192
- package/dist/session-start-K6IGAC7H.js.map +0 -1
- package/dist/setup-digest-X5PN27F4.js +0 -15
- package/dist/setup-llm-S5OHQJXK.js +0 -15
- package/dist/src/prompts/classification.md +0 -43
- package/dist/stats-TTSDXGJV.js +0 -58
- package/dist/stats-TTSDXGJV.js.map +0 -1
- package/dist/templates-XPRBOWCE.js +0 -38
- package/dist/templates-XPRBOWCE.js.map +0 -1
- package/dist/ui/assets/index-08wKT7wS.css +0 -1
- package/dist/ui/assets/index-CMSMi4Jb.js +0 -369
- package/dist/verify-TOWQHPBX.js.map +0 -1
- package/skills/setup/SKILL.md +0 -174
- package/skills/setup/references/model-recommendations.md +0 -83
- /package/dist/{client-AGFNR2S4.js.map → chunk-E4VLWIJC.js.map} +0 -0
- /package/dist/{setup-digest-X5PN27F4.js.map → chunk-IB76KGBY.js.map} +0 -0
- /package/dist/{chunk-O6PERU7U.js.map → chunk-XNOCTDHF.js.map} +0 -0
- /package/dist/{setup-llm-S5OHQJXK.js.map → client-EYOTW3JU.js.map} +0 -0
- /package/dist/{version-36RVCQA6.js.map → client-MXRNQ5FI.js.map} +0 -0
|
@@ -88,7 +88,7 @@ Read the last line of `<vault>/digest/trace.jsonl`. Each line is a JSON object w
|
|
|
88
88
|
- `cycleId` — short identifier for the cycle
|
|
89
89
|
- `timestamp` — ISO timestamp of when the cycle ran
|
|
90
90
|
- `tiersGenerated` — which tiers were written
|
|
91
|
-
- `substrateCount` — number of
|
|
91
|
+
- `substrateCount` — number of records processed as input
|
|
92
92
|
- `durationMs` — how long the cycle took
|
|
93
93
|
|
|
94
94
|
**Metabolism config:**
|
|
@@ -127,7 +127,7 @@ Check for these problems when assessing vault health:
|
|
|
127
127
|
| **Stale buffers** | `.jsonl` files in `<vault>/buffer/` older than 24 hours | Events were captured but never processed — LLM may have been unavailable |
|
|
128
128
|
| **Missing index** | `<vault>/index.db` does not exist | FTS search will not work; suggest `node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js rebuild` |
|
|
129
129
|
| **Missing vectors** | `<vault>/vectors.db` does not exist | Semantic search disabled; embeddings may be unconfigured |
|
|
130
|
-
| **Old config version** | `version` in `myco.yaml` is less than `2` | Vault may need migration; suggest running
|
|
130
|
+
| **Old config version** | `version` in `myco.yaml` is less than `2` | Vault may need migration; suggest running `myco init` |
|
|
131
131
|
|
|
132
132
|
Report all issues found, or "None found." if the vault is clean.
|
|
133
133
|
|
|
@@ -221,4 +221,4 @@ Lineage tracks parent-child relationships between sessions. A high count of `sem
|
|
|
221
221
|
| Stale buffers | Check if LLM provider was down during those sessions; events will process on next daemon start |
|
|
222
222
|
| Missing index | Run `node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js rebuild` to regenerate FTS and vector indexes |
|
|
223
223
|
| Provider unreachable | Ensure the provider is running (e.g., `ollama serve`); verify model name in `myco.yaml`; reconfigure with CLI commands |
|
|
224
|
-
| Config version < 2 | Run
|
|
224
|
+
| Config version < 2 | Run `myco init` to migrate the vault configuration |
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
When you notice patterns in vault spores — recurring themes, conflicting advice, outdated observations — use these tools to keep the vault clean and its knowledge sharp.
|
|
4
4
|
|
|
5
|
-
## Automatic
|
|
5
|
+
## Automatic Intelligence
|
|
6
6
|
|
|
7
7
|
Myco automatically checks for supersession every time a new spore is written. After the spore is saved and embedded, a fire-and-forget pipeline searches for semantically similar active spores of the same observation type and asks the LLM whether any are now outdated. If so, they're marked superseded automatically. This means most vault hygiene happens without manual intervention.
|
|
8
8
|
|
|
9
9
|
For vault-wide cleanup (e.g., after a large refactor), use the CLI:
|
|
10
10
|
```sh
|
|
11
|
-
node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js
|
|
12
|
-
node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js
|
|
11
|
+
node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js agent --dry-run # preview
|
|
12
|
+
node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js agent # execute
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Supersede
|
|
16
16
|
|
|
17
|
-
Use `myco_supersede` for manual supersession when you spot a stale spore that automatic
|
|
17
|
+
Use `myco_supersede` for manual supersession when you spot a stale spore that automatic intelligence missed.
|
|
18
18
|
|
|
19
19
|
**Signals:**
|
|
20
20
|
- A decision was reversed in a later session
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: myco-curate
|
|
3
|
+
description: >-
|
|
4
|
+
Trigger the Myco intelligence agent to process unprocessed session data,
|
|
5
|
+
extract observations, and maintain the vault knowledge graph
|
|
6
|
+
user-invocable: true
|
|
7
|
+
allowed-tools: Bash
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Myco Curate — Run the Intelligence Agent
|
|
11
|
+
|
|
12
|
+
This skill triggers an intelligence agent run via the daemon API. The intelligence agent processes unprocessed prompt batches, extracts observations (spores), and maintains the vault's knowledge graph.
|
|
13
|
+
|
|
14
|
+
## Arguments
|
|
15
|
+
|
|
16
|
+
The user may provide:
|
|
17
|
+
- **task name** — which intelligence task to run (e.g., "full-intelligence", "extraction-only")
|
|
18
|
+
- **instruction** — free-text instruction to guide the agent's focus
|
|
19
|
+
|
|
20
|
+
Parse the user's message for these. Both are optional.
|
|
21
|
+
|
|
22
|
+
## Step 1: Resolve Daemon Port
|
|
23
|
+
|
|
24
|
+
Read the daemon.json file to find the running daemon's port:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cat "$(node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js stats 2>/dev/null | grep -oP 'path: \K.*' || echo ~/.myco/vaults/myco)/daemon.json" 2>/dev/null
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If that fails, use the vault directory from the environment. The daemon.json contains `{ "pid": ..., "port": ... }`. Extract the `port` value.
|
|
31
|
+
|
|
32
|
+
If the daemon is not running, tell the user:
|
|
33
|
+
|
|
34
|
+
> "The Myco daemon is not running. Start a new session or run `node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js restart` to start it."
|
|
35
|
+
|
|
36
|
+
## Step 2: Trigger Agent Run
|
|
37
|
+
|
|
38
|
+
Send a POST request to the daemon API:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
curl -s -X POST http://localhost:<port>/api/agent/run \
|
|
42
|
+
-H 'Content-Type: application/json' \
|
|
43
|
+
-d '{"task": "<task-name-or-null>", "instruction": "<instruction-or-null>"}'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Omit `task` and `instruction` fields from the JSON body if they were not provided by the user.
|
|
47
|
+
|
|
48
|
+
Report the response to the user. The response will be `{ "ok": true, "message": "Intelligence agent started" }`.
|
|
49
|
+
|
|
50
|
+
## Step 3: Check Run Status
|
|
51
|
+
|
|
52
|
+
The intelligence agent runs in the background. To check its progress, poll the runs endpoint:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
curl -s http://localhost:<port>/api/agent/runs?limit=1
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This returns the most recent run. Show the user:
|
|
59
|
+
- **Run ID** — the unique identifier
|
|
60
|
+
- **Status** — pending, running, completed, failed, or skipped
|
|
61
|
+
- **Task** — which task was executed
|
|
62
|
+
- **Tokens used** — total tokens consumed (if completed)
|
|
63
|
+
- **Cost** — USD cost (if completed)
|
|
64
|
+
- **Error** — error message (if failed)
|
|
65
|
+
|
|
66
|
+
If the run is still `running`, tell the user they can check again later or wait.
|
|
67
|
+
|
|
68
|
+
## Step 4: Show Reports (if completed)
|
|
69
|
+
|
|
70
|
+
If the run completed, fetch the decision reports:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
curl -s http://localhost:<port>/api/agent/runs/<run-id>/reports
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Summarize the reports for the user:
|
|
77
|
+
- How many actions were taken
|
|
78
|
+
- What types of actions (extraction, consolidation, supersession, etc.)
|
|
79
|
+
- Key observations or decisions made
|
|
80
|
+
|
|
81
|
+
## Constraints
|
|
82
|
+
|
|
83
|
+
- Always use the daemon API, never call the executor directly from the skill.
|
|
84
|
+
- The intelligence agent runs asynchronously — the POST returns immediately.
|
|
85
|
+
- If the user asks for a specific task, pass it in the `task` field.
|
|
86
|
+
- If the user provides natural language guidance, pass it in the `instruction` field.
|
package/dist/chunk-2ZIBCEYO.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
VaultWriter,
|
|
4
|
-
indexNote,
|
|
5
|
-
supersedeSpore
|
|
6
|
-
} from "./chunk-UP4P4OAA.js";
|
|
7
|
-
import {
|
|
8
|
-
generateEmbedding
|
|
9
|
-
} from "./chunk-RGVBGTD6.js";
|
|
10
|
-
import {
|
|
11
|
-
stripFrontmatter
|
|
12
|
-
} from "./chunk-GENQ5QGP.js";
|
|
13
|
-
import {
|
|
14
|
-
DIGEST_TIERS,
|
|
15
|
-
EMBEDDING_INPUT_LIMIT
|
|
16
|
-
} from "./chunk-J4D4CROB.js";
|
|
17
|
-
|
|
18
|
-
// src/mcp/tools/context.ts
|
|
19
|
-
import fs from "fs";
|
|
20
|
-
import path from "path";
|
|
21
|
-
var DEFAULT_CONTEXT_TIER = 3e3;
|
|
22
|
-
function tryReadExtract(filePath, tier, fallback) {
|
|
23
|
-
let raw;
|
|
24
|
-
try {
|
|
25
|
-
raw = fs.readFileSync(filePath, "utf-8");
|
|
26
|
-
} catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
const { body, frontmatter } = stripFrontmatter(raw);
|
|
30
|
-
const generated = frontmatter.generated;
|
|
31
|
-
return {
|
|
32
|
-
content: body,
|
|
33
|
-
tier,
|
|
34
|
-
fallback,
|
|
35
|
-
generated
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
function handleMycoContext(vaultDir, input) {
|
|
39
|
-
const requestedTier = input.tier ?? DEFAULT_CONTEXT_TIER;
|
|
40
|
-
const digestDir = path.join(vaultDir, "digest");
|
|
41
|
-
const exact = tryReadExtract(path.join(digestDir, `extract-${requestedTier}.md`), requestedTier, false);
|
|
42
|
-
if (exact) return exact;
|
|
43
|
-
const candidates = [...DIGEST_TIERS].sort((a, b) => Math.abs(a - requestedTier) - Math.abs(b - requestedTier));
|
|
44
|
-
for (const tier of candidates) {
|
|
45
|
-
const result = tryReadExtract(path.join(digestDir, `extract-${tier}.md`), tier, true);
|
|
46
|
-
if (result) return result;
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
content: "Digest context is not yet available. The first digest cycle has not completed.",
|
|
50
|
-
tier: requestedTier,
|
|
51
|
-
fallback: false
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/vault/consolidation.ts
|
|
56
|
-
import { randomBytes } from "crypto";
|
|
57
|
-
async function consolidateSpores(input, deps) {
|
|
58
|
-
const { vaultDir, index, vectorIndex, embeddingProvider } = deps;
|
|
59
|
-
const writer = new VaultWriter(vaultDir);
|
|
60
|
-
const wisdomId = `${input.observationType}-wisdom-${randomBytes(4).toString("hex")}`;
|
|
61
|
-
const sourceLinks = input.sourceSporeIds.map((id) => `- [[${id}]]`).join("\n");
|
|
62
|
-
const sourcesSection = input.sourceSporeIds.length > 0 ? `
|
|
63
|
-
|
|
64
|
-
## Sources
|
|
65
|
-
|
|
66
|
-
Consolidated from:
|
|
67
|
-
${sourceLinks}` : "";
|
|
68
|
-
const fullContent = `${input.consolidatedContent}${sourcesSection}`;
|
|
69
|
-
const wisdomPath = writer.writeSpore({
|
|
70
|
-
id: wisdomId,
|
|
71
|
-
observation_type: input.observationType,
|
|
72
|
-
tags: [...input.tags ?? [], "wisdom", "consolidated"],
|
|
73
|
-
content: fullContent
|
|
74
|
-
});
|
|
75
|
-
writer.updateNoteFrontmatter(wisdomPath, {
|
|
76
|
-
consolidated_from: input.sourceSporeIds
|
|
77
|
-
}, true);
|
|
78
|
-
const sourceNotes = index.queryByIds(input.sourceSporeIds);
|
|
79
|
-
const sourceNoteMap = new Map(sourceNotes.map((n) => [n.id, n]));
|
|
80
|
-
let sourcesArchived = 0;
|
|
81
|
-
for (const sourceId of input.sourceSporeIds) {
|
|
82
|
-
const note = sourceNoteMap.get(sourceId);
|
|
83
|
-
if (!note) continue;
|
|
84
|
-
const superseded = supersedeSpore(sourceId, wisdomId, note.path, {
|
|
85
|
-
index,
|
|
86
|
-
vectorIndex,
|
|
87
|
-
vaultDir
|
|
88
|
-
});
|
|
89
|
-
if (superseded) sourcesArchived++;
|
|
90
|
-
}
|
|
91
|
-
indexNote(index, vaultDir, wisdomPath);
|
|
92
|
-
if (vectorIndex && embeddingProvider) {
|
|
93
|
-
generateEmbedding(embeddingProvider, fullContent.slice(0, EMBEDDING_INPUT_LIMIT)).then(
|
|
94
|
-
(emb) => vectorIndex.upsert(wisdomId, emb.embedding, {
|
|
95
|
-
type: "spore",
|
|
96
|
-
observation_type: input.observationType,
|
|
97
|
-
importance: "high"
|
|
98
|
-
})
|
|
99
|
-
).catch(() => {
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
return {
|
|
103
|
-
wisdom_id: wisdomId,
|
|
104
|
-
wisdom_path: wisdomPath,
|
|
105
|
-
sources_archived: sourcesArchived
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export {
|
|
110
|
-
consolidateSpores,
|
|
111
|
-
handleMycoContext
|
|
112
|
-
};
|
|
113
|
-
//# sourceMappingURL=chunk-2ZIBCEYO.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp/tools/context.ts","../src/vault/consolidation.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { stripFrontmatter } from '../../vault/frontmatter.js';\nimport { DIGEST_TIERS } from '../../constants.js';\n\n/** Default tier when none is requested. */\nconst DEFAULT_CONTEXT_TIER = 3000;\n\ninterface ContextInput {\n tier?: number;\n}\n\nexport interface ContextResult {\n content: string;\n tier: number;\n fallback: boolean;\n generated?: string;\n}\n\n/**\n * Try to read a digest extract file. Returns null if the file doesn't exist.\n * Strips YAML frontmatter and extracts the generated timestamp.\n */\nfunction tryReadExtract(filePath: string, tier: number, fallback: boolean): ContextResult | null {\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n\n const { body, frontmatter } = stripFrontmatter(raw);\n const generated = frontmatter.generated as string | undefined;\n\n return {\n content: body,\n tier,\n fallback,\n generated,\n };\n}\n\nexport function handleMycoContext(vaultDir: string, input: ContextInput): ContextResult {\n const requestedTier = input.tier ?? DEFAULT_CONTEXT_TIER;\n const digestDir = path.join(vaultDir, 'digest');\n\n // Try exact tier first\n const exact = tryReadExtract(path.join(digestDir, `extract-${requestedTier}.md`), requestedTier, false);\n if (exact) return exact;\n\n // Fall back to nearest available tier\n const candidates = [...DIGEST_TIERS]\n .sort((a, b) => Math.abs(a - requestedTier) - Math.abs(b - requestedTier));\n\n for (const tier of candidates) {\n const result = tryReadExtract(path.join(digestDir, `extract-${tier}.md`), tier, true);\n if (result) return result;\n }\n\n return {\n content: 'Digest context is not yet available. The first digest cycle has not completed.',\n tier: requestedTier,\n fallback: false,\n };\n}\n","/**\n * Shared consolidation core — creates a wisdom note from a set of source spores\n * and marks each source as superseded.\n *\n * Used by both the MCP tool (`myco_consolidate`) and the daemon's automatic\n * consolidation pass so the logic lives in exactly one place.\n */\n\nimport { VaultWriter } from './writer.js';\nimport { supersedeSpore } from './curation.js';\nimport { indexNote } from '../index/rebuild.js';\nimport type { MycoIndex } from '../index/sqlite.js';\nimport type { VectorIndex } from '../index/vectors.js';\nimport type { EmbeddingProvider } from '../intelligence/llm.js';\nimport { generateEmbedding } from '../intelligence/embeddings.js';\nimport { EMBEDDING_INPUT_LIMIT } from '../constants.js';\nimport { randomBytes } from 'node:crypto';\n\nexport interface ConsolidateInput {\n sourceSporeIds: string[];\n consolidatedContent: string;\n observationType: string;\n tags?: string[];\n}\n\nexport interface ConsolidateResult {\n wisdom_id: string;\n wisdom_path: string;\n sources_archived: number;\n}\n\nexport interface ConsolidateDeps {\n vaultDir: string;\n index: MycoIndex;\n vectorIndex: VectorIndex | null;\n embeddingProvider: EmbeddingProvider | null;\n}\n\n/**\n * Create a consolidated wisdom note from a list of source spore IDs, then\n * mark each source spore as superseded.\n *\n * - The wisdom note is written via VaultWriter.writeSpore() with 'wisdom' and\n * 'consolidated' tags appended.\n * - `consolidated_from` is added to the wisdom note's frontmatter.\n * - Each source spore is updated atomically via `supersedeSpore` (frontmatter\n * update + notice append + re-index + vector deletion).\n * - The wisdom note is indexed and, if deps are available, embedded with\n * importance 'high' (fire-and-forget).\n *\n * Source spores missing from the index are silently skipped.\n */\nexport async function consolidateSpores(\n input: ConsolidateInput,\n deps: ConsolidateDeps,\n): Promise<ConsolidateResult> {\n const { vaultDir, index, vectorIndex, embeddingProvider } = deps;\n const writer = new VaultWriter(vaultDir);\n\n const wisdomId = `${input.observationType}-wisdom-${randomBytes(4).toString('hex')}`;\n\n // Build content with a ## Sources section containing Obsidian wikilinks\n const sourceLinks = input.sourceSporeIds.map((id) => `- [[${id}]]`).join('\\n');\n const sourcesSection = input.sourceSporeIds.length > 0\n ? `\\n\\n## Sources\\n\\nConsolidated from:\\n${sourceLinks}`\n : '';\n const fullContent = `${input.consolidatedContent}${sourcesSection}`;\n\n // Write the wisdom spore note\n const wisdomPath = writer.writeSpore({\n id: wisdomId,\n observation_type: input.observationType,\n tags: [...(input.tags ?? []), 'wisdom', 'consolidated'],\n content: fullContent,\n });\n\n // Add consolidated_from to the wisdom note's frontmatter\n writer.updateNoteFrontmatter(wisdomPath, {\n consolidated_from: input.sourceSporeIds,\n }, true);\n\n // Supersede each source spore (atomic frontmatter update + notice + re-index + vector delete)\n const sourceNotes = index.queryByIds(input.sourceSporeIds);\n const sourceNoteMap = new Map(sourceNotes.map((n) => [n.id, n]));\n let sourcesArchived = 0;\n for (const sourceId of input.sourceSporeIds) {\n const note = sourceNoteMap.get(sourceId);\n if (!note) continue;\n\n const superseded = supersedeSpore(sourceId, wisdomId, note.path, {\n index,\n vectorIndex,\n vaultDir,\n });\n\n if (superseded) sourcesArchived++;\n }\n\n // Index the new wisdom note\n indexNote(index, vaultDir, wisdomPath);\n\n // Embed the wisdom note (fire-and-forget — embedding failure is non-fatal)\n if (vectorIndex && embeddingProvider) {\n generateEmbedding(embeddingProvider, fullContent.slice(0, EMBEDDING_INPUT_LIMIT))\n .then((emb) =>\n vectorIndex.upsert(wisdomId, emb.embedding, {\n type: 'spore',\n observation_type: input.observationType,\n importance: 'high',\n }),\n )\n .catch(() => { /* embedding failure is non-fatal */ });\n }\n\n return {\n wisdom_id: wisdomId,\n wisdom_path: wisdomPath,\n sources_archived: sourcesArchived,\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-4RMSHZE4.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
-
|
|
3
|
-
// src/index/vectors.ts
|
|
4
|
-
import Database from "better-sqlite3";
|
|
5
|
-
import * as sqliteVec from "sqlite-vec";
|
|
6
|
-
var VectorIndex = class {
|
|
7
|
-
db;
|
|
8
|
-
dimensions;
|
|
9
|
-
constructor(dbPath, dimensions) {
|
|
10
|
-
this.dimensions = dimensions;
|
|
11
|
-
this.db = new Database(dbPath);
|
|
12
|
-
sqliteVec.load(this.db);
|
|
13
|
-
this.init();
|
|
14
|
-
}
|
|
15
|
-
init() {
|
|
16
|
-
this.db.exec(`
|
|
17
|
-
CREATE TABLE IF NOT EXISTS vec_metadata (
|
|
18
|
-
id TEXT PRIMARY KEY,
|
|
19
|
-
type TEXT NOT NULL DEFAULT '',
|
|
20
|
-
importance TEXT NOT NULL DEFAULT '',
|
|
21
|
-
session_id TEXT NOT NULL DEFAULT '',
|
|
22
|
-
file_path TEXT NOT NULL DEFAULT '',
|
|
23
|
-
branch TEXT NOT NULL DEFAULT '',
|
|
24
|
-
created TEXT NOT NULL DEFAULT (datetime('now'))
|
|
25
|
-
);
|
|
26
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS vec_embeddings USING vec0(
|
|
27
|
-
id TEXT PRIMARY KEY,
|
|
28
|
-
embedding float[${this.dimensions}]
|
|
29
|
-
);
|
|
30
|
-
`);
|
|
31
|
-
}
|
|
32
|
-
upsert(id, embedding, metadata = {}) {
|
|
33
|
-
this.db.prepare("DELETE FROM vec_metadata WHERE id = ?").run(id);
|
|
34
|
-
this.db.prepare("DELETE FROM vec_embeddings WHERE id = ?").run(id);
|
|
35
|
-
this.db.prepare(
|
|
36
|
-
"INSERT INTO vec_metadata (id, type, importance, session_id, file_path, branch) VALUES (?, ?, ?, ?, ?, ?)"
|
|
37
|
-
).run(id, metadata.type ?? "", metadata.importance ?? "", metadata.session_id ?? "", metadata.file_path ?? "", metadata.branch ?? "");
|
|
38
|
-
this.db.prepare("INSERT INTO vec_embeddings (id, embedding) VALUES (?, ?)").run(id, new Float32Array(embedding));
|
|
39
|
-
}
|
|
40
|
-
search(query, options = {}) {
|
|
41
|
-
const limit = options.limit ?? 10;
|
|
42
|
-
const knnParams = [new Float32Array(query), limit * 4];
|
|
43
|
-
const knnRows = this.db.prepare(`
|
|
44
|
-
SELECT id, distance
|
|
45
|
-
FROM vec_embeddings
|
|
46
|
-
WHERE embedding MATCH ?
|
|
47
|
-
ORDER BY distance
|
|
48
|
-
LIMIT ?
|
|
49
|
-
`).all(...knnParams);
|
|
50
|
-
if (knnRows.length === 0) return [];
|
|
51
|
-
const metaConditions = ["id IN (" + knnRows.map(() => "?").join(",") + ")"];
|
|
52
|
-
const metaParams = knnRows.map((r) => r.id);
|
|
53
|
-
if (options.type) {
|
|
54
|
-
metaConditions.push("type = ?");
|
|
55
|
-
metaParams.push(options.type);
|
|
56
|
-
}
|
|
57
|
-
if (options.importance) {
|
|
58
|
-
metaConditions.push("importance = ?");
|
|
59
|
-
metaParams.push(options.importance);
|
|
60
|
-
}
|
|
61
|
-
const metaRows = this.db.prepare(`
|
|
62
|
-
SELECT id, type, importance, session_id, file_path, branch
|
|
63
|
-
FROM vec_metadata
|
|
64
|
-
WHERE ${metaConditions.join(" AND ")}
|
|
65
|
-
`).all(...metaParams);
|
|
66
|
-
const metaMap = new Map(metaRows.map((m) => [m.id, m]));
|
|
67
|
-
const scored = knnRows.filter((r) => metaMap.has(r.id)).map((r) => {
|
|
68
|
-
const m = metaMap.get(r.id);
|
|
69
|
-
return {
|
|
70
|
-
id: r.id,
|
|
71
|
-
similarity: 1 - r.distance,
|
|
72
|
-
metadata: { type: m.type, importance: m.importance, session_id: m.session_id, file_path: m.file_path, branch: m.branch }
|
|
73
|
-
};
|
|
74
|
-
});
|
|
75
|
-
if (scored.length === 0) return [];
|
|
76
|
-
const topScore = scored[0].similarity;
|
|
77
|
-
const threshold = options.relativeThreshold ?? 0.5;
|
|
78
|
-
const floor = topScore * threshold;
|
|
79
|
-
return scored.filter((r) => r.similarity >= floor).slice(0, limit);
|
|
80
|
-
}
|
|
81
|
-
/** Retrieve the stored embedding for a given ID, or null if not found. */
|
|
82
|
-
getEmbedding(id) {
|
|
83
|
-
const row = this.db.prepare("SELECT embedding FROM vec_embeddings WHERE id = ?").get(id);
|
|
84
|
-
if (!row) return null;
|
|
85
|
-
return Array.from(new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4));
|
|
86
|
-
}
|
|
87
|
-
/** Check whether an embedding exists for the given ID. */
|
|
88
|
-
has(id) {
|
|
89
|
-
const row = this.db.prepare("SELECT 1 FROM vec_metadata WHERE id = ?").get(id);
|
|
90
|
-
return row !== void 0;
|
|
91
|
-
}
|
|
92
|
-
delete(id) {
|
|
93
|
-
this.db.prepare("DELETE FROM vec_metadata WHERE id = ?").run(id);
|
|
94
|
-
this.db.prepare("DELETE FROM vec_embeddings WHERE id = ?").run(id);
|
|
95
|
-
}
|
|
96
|
-
count() {
|
|
97
|
-
return this.db.prepare("SELECT COUNT(*) as c FROM vec_metadata").get().c;
|
|
98
|
-
}
|
|
99
|
-
close() {
|
|
100
|
-
this.db.close();
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
export {
|
|
105
|
-
VectorIndex
|
|
106
|
-
};
|
|
107
|
-
//# sourceMappingURL=chunk-4RMSHZE4.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index/vectors.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport * as sqliteVec from 'sqlite-vec';\n\nexport interface VectorSearchResult {\n id: string;\n similarity: number;\n metadata: Record<string, string>;\n}\n\nexport interface VectorSearchOptions {\n limit?: number;\n /** Drop results below this fraction of the top result's score (0-1). Default 0.5. */\n relativeThreshold?: number;\n type?: string;\n importance?: string;\n}\n\nexport class VectorIndex {\n private db: Database.Database;\n private dimensions: number;\n\n constructor(dbPath: string, dimensions: number) {\n this.dimensions = dimensions;\n this.db = new Database(dbPath);\n sqliteVec.load(this.db);\n this.init();\n }\n\n private init(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS vec_metadata (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL DEFAULT '',\n importance TEXT NOT NULL DEFAULT '',\n session_id TEXT NOT NULL DEFAULT '',\n file_path TEXT NOT NULL DEFAULT '',\n branch TEXT NOT NULL DEFAULT '',\n created TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE VIRTUAL TABLE IF NOT EXISTS vec_embeddings USING vec0(\n id TEXT PRIMARY KEY,\n embedding float[${this.dimensions}]\n );\n `);\n }\n\n upsert(id: string, embedding: number[], metadata: Record<string, string> = {}): void {\n this.db.prepare('DELETE FROM vec_metadata WHERE id = ?').run(id);\n this.db.prepare('DELETE FROM vec_embeddings WHERE id = ?').run(id);\n\n this.db.prepare(\n 'INSERT INTO vec_metadata (id, type, importance, session_id, file_path, branch) VALUES (?, ?, ?, ?, ?, ?)',\n ).run(id, metadata.type ?? '', metadata.importance ?? '', metadata.session_id ?? '', metadata.file_path ?? '', metadata.branch ?? '');\n\n this.db.prepare('INSERT INTO vec_embeddings (id, embedding) VALUES (?, ?)').run(id, new Float32Array(embedding));\n }\n\n search(query: number[], options: VectorSearchOptions = {}): VectorSearchResult[] {\n const limit = options.limit ?? 10;\n\n // vec0 KNN queries require LIMIT to be a direct constraint on the virtual table.\n // JOINs with additional WHERE filters confuse the query planner, so we use a\n // subquery to get KNN candidates first, then filter by metadata in the outer query.\n const knnParams: unknown[] = [new Float32Array(query), limit * 4];\n const knnRows = this.db.prepare(`\n SELECT id, distance\n FROM vec_embeddings\n WHERE embedding MATCH ?\n ORDER BY distance\n LIMIT ?\n `).all(...knnParams) as Array<{ id: string; distance: number }>;\n\n if (knnRows.length === 0) return [];\n\n // Now fetch metadata for the candidates and apply optional filters\n const metaConditions: string[] = ['id IN (' + knnRows.map(() => '?').join(',') + ')'];\n const metaParams: unknown[] = knnRows.map((r) => r.id);\n\n if (options.type) { metaConditions.push('type = ?'); metaParams.push(options.type); }\n if (options.importance) { metaConditions.push('importance = ?'); metaParams.push(options.importance); }\n\n const metaRows = this.db.prepare(`\n SELECT id, type, importance, session_id, file_path, branch\n FROM vec_metadata\n WHERE ${metaConditions.join(' AND ')}\n `).all(...metaParams) as Array<{ id: string; type: string; importance: string; session_id: string; file_path: string; branch: string }>;\n\n const metaMap = new Map(metaRows.map((m) => [m.id, m]));\n\n const scored = knnRows\n .filter((r) => metaMap.has(r.id))\n .map((r) => {\n const m = metaMap.get(r.id)!;\n return {\n id: r.id,\n similarity: 1 - r.distance,\n metadata: { type: m.type, importance: m.importance, session_id: m.session_id, file_path: m.file_path, branch: m.branch },\n };\n });\n\n if (scored.length === 0) return [];\n\n // Relative threshold: drop results below a fraction of the best score.\n // Adapts automatically to any embedding model's score distribution.\n const topScore = scored[0].similarity;\n const threshold = options.relativeThreshold ?? 0.5;\n const floor = topScore * threshold;\n\n return scored\n .filter((r) => r.similarity >= floor)\n .slice(0, limit);\n }\n\n /** Retrieve the stored embedding for a given ID, or null if not found. */\n getEmbedding(id: string): number[] | null {\n const row = this.db.prepare('SELECT embedding FROM vec_embeddings WHERE id = ?').get(id) as { embedding: Buffer } | undefined;\n if (!row) return null;\n return Array.from(new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4));\n }\n\n /** Check whether an embedding exists for the given ID. */\n has(id: string): boolean {\n const row = this.db.prepare('SELECT 1 FROM vec_metadata WHERE id = ?').get(id);\n return row !== undefined;\n }\n\n delete(id: string): void {\n this.db.prepare('DELETE FROM vec_metadata WHERE id = ?').run(id);\n this.db.prepare('DELETE FROM vec_embeddings WHERE id = ?').run(id);\n }\n\n count(): number {\n return (this.db.prepare('SELECT COUNT(*) as c FROM vec_metadata').get() as { c: number }).c;\n }\n\n close(): void { this.db.close(); }\n}\n"],"mappings":"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","names":[]}
|