cognitive-core 0.2.0 → 0.2.2
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/settings.json +111 -2
- package/.sessionlog/settings.json +4 -0
- package/dist/atlas.d.ts +10 -0
- package/dist/atlas.d.ts.map +1 -1
- package/dist/atlas.js +65 -0
- package/dist/atlas.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/learning/index.d.ts +1 -1
- package/dist/learning/index.d.ts.map +1 -1
- package/dist/learning/index.js.map +1 -1
- package/dist/learning/pipeline.d.ts +4 -31
- package/dist/learning/pipeline.d.ts.map +1 -1
- package/dist/learning/pipeline.js +12 -64
- package/dist/learning/pipeline.js.map +1 -1
- package/dist/learning/unified-pipeline.d.ts +30 -0
- package/dist/learning/unified-pipeline.d.ts.map +1 -1
- package/dist/learning/unified-pipeline.js +207 -0
- package/dist/learning/unified-pipeline.js.map +1 -1
- package/dist/memory/candidate-retrieval.d.ts.map +1 -1
- package/dist/memory/candidate-retrieval.js +3 -1
- package/dist/memory/candidate-retrieval.js.map +1 -1
- package/dist/memory/curated-loader.d.ts +21 -4
- package/dist/memory/curated-loader.d.ts.map +1 -1
- package/dist/memory/curated-loader.js +53 -16
- package/dist/memory/curated-loader.js.map +1 -1
- package/dist/memory/index.d.ts +2 -1
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +3 -1
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/playbook.d.ts +6 -0
- package/dist/memory/playbook.d.ts.map +1 -1
- package/dist/memory/playbook.js +15 -0
- package/dist/memory/playbook.js.map +1 -1
- package/dist/memory/source-resolver.d.ts +120 -0
- package/dist/memory/source-resolver.d.ts.map +1 -0
- package/dist/memory/source-resolver.js +300 -0
- package/dist/memory/source-resolver.js.map +1 -0
- package/dist/types/config.d.ts +141 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +40 -0
- package/dist/types/config.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/error-classifier.js +8 -8
- package/dist/utils/error-classifier.js.map +1 -1
- package/dist/workspace/efficacy-toolkit.d.ts +164 -0
- package/dist/workspace/efficacy-toolkit.d.ts.map +1 -0
- package/dist/workspace/efficacy-toolkit.js +281 -0
- package/dist/workspace/efficacy-toolkit.js.map +1 -0
- package/dist/workspace/index.d.ts +2 -1
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +3 -1
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/templates/index.d.ts +3 -0
- package/dist/workspace/templates/index.d.ts.map +1 -1
- package/dist/workspace/templates/index.js +6 -0
- package/dist/workspace/templates/index.js.map +1 -1
- package/dist/workspace/templates/playbook-decay-detection.d.ts +46 -0
- package/dist/workspace/templates/playbook-decay-detection.d.ts.map +1 -0
- package/dist/workspace/templates/playbook-decay-detection.js +197 -0
- package/dist/workspace/templates/playbook-decay-detection.js.map +1 -0
- package/dist/workspace/templates/playbook-efficacy-audit.d.ts +46 -0
- package/dist/workspace/templates/playbook-efficacy-audit.d.ts.map +1 -0
- package/dist/workspace/templates/playbook-efficacy-audit.js +160 -0
- package/dist/workspace/templates/playbook-efficacy-audit.js.map +1 -0
- package/dist/workspace/templates/playbook-lifecycle-review.d.ts +51 -0
- package/dist/workspace/templates/playbook-lifecycle-review.d.ts.map +1 -0
- package/dist/workspace/templates/playbook-lifecycle-review.js +187 -0
- package/dist/workspace/templates/playbook-lifecycle-review.js.map +1 -0
- package/dist/workspace/types.d.ts +12 -54
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/types.js.map +1 -1
- package/package.json +8 -2
- package/playbooks/compound-engineering/adversarial-review.json +51 -0
- package/playbooks/compound-engineering/agent-native-architecture.json +59 -0
- package/playbooks/compound-engineering/agent-native-review.json +54 -0
- package/playbooks/compound-engineering/api-contract-review.json +52 -0
- package/playbooks/compound-engineering/brainstorm-requirements.json +55 -0
- package/playbooks/compound-engineering/bug-reproduction.json +62 -0
- package/playbooks/compound-engineering/confidence-calibration.json +49 -0
- package/playbooks/compound-engineering/correctness-review.json +49 -0
- package/playbooks/compound-engineering/data-migration-safety.json +59 -0
- package/playbooks/compound-engineering/deployment-verification.json +63 -0
- package/playbooks/compound-engineering/error-recovery-patterns.json +53 -0
- package/playbooks/compound-engineering/implementation-planning.json +64 -0
- package/playbooks/compound-engineering/issue-pattern-analysis.json +53 -0
- package/playbooks/compound-engineering/knowledge-compounding.json +63 -0
- package/playbooks/compound-engineering/learnings-research.json +54 -0
- package/playbooks/compound-engineering/maintainability-review.json +49 -0
- package/playbooks/compound-engineering/performance-review.json +54 -0
- package/playbooks/compound-engineering/plan-adversarial-review.json +56 -0
- package/playbooks/compound-engineering/plan-feasibility-review.json +56 -0
- package/playbooks/compound-engineering/project-standards-review.json +52 -0
- package/playbooks/compound-engineering/reliability-review.json +53 -0
- package/playbooks/compound-engineering/review-orchestration.json +64 -0
- package/playbooks/compound-engineering/security-review.json +54 -0
- package/playbooks/compound-engineering/systematic-execution.json +64 -0
- package/playbooks/compound-engineering/testing-review.json +50 -0
- package/src/atlas.ts +96 -0
- package/src/index.ts +27 -0
- package/src/learning/index.ts +1 -0
- package/src/learning/unified-pipeline.ts +271 -1
- package/src/memory/candidate-retrieval.ts +2 -1
- package/src/memory/curated-loader.ts +69 -16
- package/src/memory/index.ts +16 -0
- package/src/memory/playbook.ts +19 -0
- package/src/memory/source-resolver.ts +422 -0
- package/src/types/config.ts +46 -0
- package/src/types/index.ts +4 -0
- package/src/utils/error-classifier.ts +8 -8
- package/src/workspace/efficacy-toolkit.ts +496 -0
- package/src/workspace/index.ts +29 -0
- package/src/workspace/templates/index.ts +24 -0
- package/src/workspace/templates/playbook-decay-detection.ts +272 -0
- package/src/workspace/templates/playbook-efficacy-audit.ts +246 -0
- package/src/workspace/templates/playbook-lifecycle-review.ts +274 -0
- package/src/workspace/types.ts +22 -78
- package/tests/fixtures/behavioral-trajectories.ts +210 -0
- package/tests/integration/curated-sources-e2e.test.ts +502 -0
- package/tests/integration/pipeline-data-correctness.test.ts +794 -0
- package/tests/learning/meta-learner.test.ts +418 -0
- package/tests/learning/pipeline-memory-updates.test.ts +721 -0
- package/tests/learning/unified-pipeline-efficacy.test.ts +232 -0
- package/tests/memory/candidate-retrieval.test.ts +167 -0
- package/tests/memory/compound-engineering-seed.test.ts +338 -0
- package/tests/memory/curated-loader-extended.test.ts +225 -0
- package/tests/memory/meta.test.ts +399 -0
- package/tests/memory/playbook-quality-validation.test.ts +430 -0
- package/tests/memory/source-resolver.test.ts +700 -0
- package/tests/search/evaluator.test.ts +257 -0
- package/tests/search/verification-runner.test.ts +357 -0
- package/tests/utils/error-classifier.test.ts +149 -0
- package/tests/utils/trajectory-helpers.test.ts +163 -0
- package/tests/workspace/efficacy-toolkit.test.ts +404 -0
- package/tests/workspace/templates/playbook-efficacy.test.ts +377 -0
- package/.claude/settings.local.json +0 -11
- package/dist/learning/llm-extractor.d.ts +0 -88
- package/dist/learning/llm-extractor.d.ts.map +0 -1
- package/dist/learning/llm-extractor.js +0 -372
- package/dist/learning/llm-extractor.js.map +0 -1
- package/dist/learning/loop-coordinator.d.ts +0 -61
- package/dist/learning/loop-coordinator.d.ts.map +0 -1
- package/dist/learning/loop-coordinator.js +0 -96
- package/dist/learning/loop-coordinator.js.map +0 -1
- package/references/agent-workspace/CLAUDE.md +0 -74
- package/references/agent-workspace/README.md +0 -587
- package/references/agent-workspace/media/banner.png +0 -0
- package/references/agent-workspace/package-lock.json +0 -2061
- package/references/agent-workspace/package.json +0 -54
- package/references/agent-workspace/src/handle.ts +0 -122
- package/references/agent-workspace/src/index.ts +0 -32
- package/references/agent-workspace/src/manager.ts +0 -102
- package/references/agent-workspace/src/readers/json.ts +0 -71
- package/references/agent-workspace/src/readers/markdown.ts +0 -37
- package/references/agent-workspace/src/readers/raw.ts +0 -27
- package/references/agent-workspace/src/types.ts +0 -68
- package/references/agent-workspace/src/validation.ts +0 -93
- package/references/agent-workspace/src/writers/json.ts +0 -17
- package/references/agent-workspace/src/writers/markdown.ts +0 -27
- package/references/agent-workspace/src/writers/raw.ts +0 -22
- package/references/agent-workspace/tests/errors.test.ts +0 -652
- package/references/agent-workspace/tests/handle.test.ts +0 -144
- package/references/agent-workspace/tests/manager.test.ts +0 -124
- package/references/agent-workspace/tests/readers.test.ts +0 -205
- package/references/agent-workspace/tests/validation.test.ts +0 -196
- package/references/agent-workspace/tests/writers.test.ts +0 -108
- package/references/agent-workspace/tsconfig.json +0 -20
- package/references/agent-workspace/tsup.config.ts +0 -9
- package/references/minimem/.claude/settings.json +0 -7
- package/references/minimem/.sudocode/issues.jsonl +0 -18
- package/references/minimem/.sudocode/specs.jsonl +0 -1
- package/references/minimem/CLAUDE.md +0 -310
- package/references/minimem/README.md +0 -556
- package/references/minimem/claude-plugin/.claude-plugin/plugin.json +0 -10
- package/references/minimem/claude-plugin/.mcp.json +0 -7
- package/references/minimem/claude-plugin/README.md +0 -158
- package/references/minimem/claude-plugin/commands/recall.md +0 -47
- package/references/minimem/claude-plugin/commands/remember.md +0 -41
- package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +0 -272
- package/references/minimem/claude-plugin/hooks/hooks.json +0 -27
- package/references/minimem/claude-plugin/hooks/session-end.sh +0 -86
- package/references/minimem/claude-plugin/hooks/session-start.sh +0 -85
- package/references/minimem/claude-plugin/skills/memory/SKILL.md +0 -108
- package/references/minimem/package-lock.json +0 -5373
- package/references/minimem/package.json +0 -60
- package/references/minimem/scripts/postbuild.js +0 -35
- package/references/minimem/src/__tests__/edge-cases.test.ts +0 -371
- package/references/minimem/src/__tests__/errors.test.ts +0 -265
- package/references/minimem/src/__tests__/helpers.ts +0 -199
- package/references/minimem/src/__tests__/internal.test.ts +0 -407
- package/references/minimem/src/__tests__/knowledge.test.ts +0 -287
- package/references/minimem/src/__tests__/minimem.integration.test.ts +0 -1127
- package/references/minimem/src/__tests__/session.test.ts +0 -190
- package/references/minimem/src/cli/__tests__/commands.test.ts +0 -759
- package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +0 -141
- package/references/minimem/src/cli/commands/append.ts +0 -76
- package/references/minimem/src/cli/commands/config.ts +0 -262
- package/references/minimem/src/cli/commands/conflicts.ts +0 -413
- package/references/minimem/src/cli/commands/daemon.ts +0 -169
- package/references/minimem/src/cli/commands/index.ts +0 -12
- package/references/minimem/src/cli/commands/init.ts +0 -88
- package/references/minimem/src/cli/commands/mcp.ts +0 -177
- package/references/minimem/src/cli/commands/push-pull.ts +0 -213
- package/references/minimem/src/cli/commands/search.ts +0 -158
- package/references/minimem/src/cli/commands/status.ts +0 -84
- package/references/minimem/src/cli/commands/sync-init.ts +0 -290
- package/references/minimem/src/cli/commands/sync.ts +0 -70
- package/references/minimem/src/cli/commands/upsert.ts +0 -197
- package/references/minimem/src/cli/config.ts +0 -584
- package/references/minimem/src/cli/index.ts +0 -264
- package/references/minimem/src/cli/shared.ts +0 -161
- package/references/minimem/src/cli/sync/__tests__/central.test.ts +0 -152
- package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +0 -209
- package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +0 -118
- package/references/minimem/src/cli/sync/__tests__/detection.test.ts +0 -207
- package/references/minimem/src/cli/sync/__tests__/integration.test.ts +0 -476
- package/references/minimem/src/cli/sync/__tests__/registry.test.ts +0 -363
- package/references/minimem/src/cli/sync/__tests__/state.test.ts +0 -255
- package/references/minimem/src/cli/sync/__tests__/validation.test.ts +0 -193
- package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +0 -178
- package/references/minimem/src/cli/sync/central.ts +0 -292
- package/references/minimem/src/cli/sync/conflicts.ts +0 -204
- package/references/minimem/src/cli/sync/daemon.ts +0 -407
- package/references/minimem/src/cli/sync/detection.ts +0 -138
- package/references/minimem/src/cli/sync/index.ts +0 -107
- package/references/minimem/src/cli/sync/operations.ts +0 -373
- package/references/minimem/src/cli/sync/registry.ts +0 -279
- package/references/minimem/src/cli/sync/state.ts +0 -355
- package/references/minimem/src/cli/sync/validation.ts +0 -206
- package/references/minimem/src/cli/sync/watcher.ts +0 -234
- package/references/minimem/src/cli/version.ts +0 -34
- package/references/minimem/src/core/index.ts +0 -9
- package/references/minimem/src/core/indexer.ts +0 -628
- package/references/minimem/src/core/searcher.ts +0 -221
- package/references/minimem/src/db/schema.ts +0 -183
- package/references/minimem/src/db/sqlite-vec.ts +0 -24
- package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +0 -431
- package/references/minimem/src/embeddings/batch-gemini.ts +0 -392
- package/references/minimem/src/embeddings/batch-openai.ts +0 -409
- package/references/minimem/src/embeddings/embeddings.ts +0 -434
- package/references/minimem/src/index.ts +0 -109
- package/references/minimem/src/internal.ts +0 -299
- package/references/minimem/src/minimem.ts +0 -1276
- package/references/minimem/src/search/__tests__/hybrid.test.ts +0 -247
- package/references/minimem/src/search/graph.ts +0 -234
- package/references/minimem/src/search/hybrid.ts +0 -151
- package/references/minimem/src/search/search.ts +0 -256
- package/references/minimem/src/server/__tests__/mcp.test.ts +0 -341
- package/references/minimem/src/server/__tests__/tools.test.ts +0 -364
- package/references/minimem/src/server/mcp.ts +0 -326
- package/references/minimem/src/server/tools.ts +0 -720
- package/references/minimem/src/session.ts +0 -460
- package/references/minimem/tsconfig.json +0 -19
- package/references/minimem/tsup.config.ts +0 -26
- package/references/minimem/vitest.config.ts +0 -24
- package/references/sessionlog/.husky/pre-commit +0 -1
- package/references/sessionlog/.lintstagedrc.json +0 -4
- package/references/sessionlog/.prettierignore +0 -4
- package/references/sessionlog/.prettierrc.json +0 -11
- package/references/sessionlog/LICENSE +0 -21
- package/references/sessionlog/README.md +0 -453
- package/references/sessionlog/eslint.config.js +0 -58
- package/references/sessionlog/package-lock.json +0 -3672
- package/references/sessionlog/package.json +0 -65
- package/references/sessionlog/src/__tests__/agent-hooks.test.ts +0 -570
- package/references/sessionlog/src/__tests__/agent-registry.test.ts +0 -127
- package/references/sessionlog/src/__tests__/claude-code-hooks.test.ts +0 -225
- package/references/sessionlog/src/__tests__/claude-generator.test.ts +0 -46
- package/references/sessionlog/src/__tests__/commit-msg.test.ts +0 -86
- package/references/sessionlog/src/__tests__/cursor-agent.test.ts +0 -224
- package/references/sessionlog/src/__tests__/e2e-live.test.ts +0 -890
- package/references/sessionlog/src/__tests__/event-log.test.ts +0 -183
- package/references/sessionlog/src/__tests__/flush-sentinel.test.ts +0 -105
- package/references/sessionlog/src/__tests__/gemini-agent.test.ts +0 -375
- package/references/sessionlog/src/__tests__/git-hooks.test.ts +0 -78
- package/references/sessionlog/src/__tests__/hook-managers.test.ts +0 -121
- package/references/sessionlog/src/__tests__/lifecycle-tasks.test.ts +0 -759
- package/references/sessionlog/src/__tests__/opencode-agent.test.ts +0 -338
- package/references/sessionlog/src/__tests__/redaction.test.ts +0 -136
- package/references/sessionlog/src/__tests__/session-repo.test.ts +0 -353
- package/references/sessionlog/src/__tests__/session-store.test.ts +0 -166
- package/references/sessionlog/src/__tests__/setup-ccweb.test.ts +0 -466
- package/references/sessionlog/src/__tests__/skill-live.test.ts +0 -461
- package/references/sessionlog/src/__tests__/summarize.test.ts +0 -348
- package/references/sessionlog/src/__tests__/task-plan-e2e.test.ts +0 -610
- package/references/sessionlog/src/__tests__/task-plan-live.test.ts +0 -632
- package/references/sessionlog/src/__tests__/transcript-timestamp.test.ts +0 -121
- package/references/sessionlog/src/__tests__/types.test.ts +0 -166
- package/references/sessionlog/src/__tests__/utils.test.ts +0 -333
- package/references/sessionlog/src/__tests__/validation.test.ts +0 -103
- package/references/sessionlog/src/__tests__/worktree.test.ts +0 -57
- package/references/sessionlog/src/agent/agents/claude-code.ts +0 -1089
- package/references/sessionlog/src/agent/agents/cursor.ts +0 -361
- package/references/sessionlog/src/agent/agents/gemini-cli.ts +0 -632
- package/references/sessionlog/src/agent/agents/opencode.ts +0 -540
- package/references/sessionlog/src/agent/registry.ts +0 -143
- package/references/sessionlog/src/agent/session-types.ts +0 -113
- package/references/sessionlog/src/agent/types.ts +0 -220
- package/references/sessionlog/src/cli.ts +0 -597
- package/references/sessionlog/src/commands/clean.ts +0 -133
- package/references/sessionlog/src/commands/disable.ts +0 -84
- package/references/sessionlog/src/commands/doctor.ts +0 -145
- package/references/sessionlog/src/commands/enable.ts +0 -202
- package/references/sessionlog/src/commands/explain.ts +0 -261
- package/references/sessionlog/src/commands/reset.ts +0 -105
- package/references/sessionlog/src/commands/resume.ts +0 -180
- package/references/sessionlog/src/commands/rewind.ts +0 -195
- package/references/sessionlog/src/commands/setup-ccweb.ts +0 -275
- package/references/sessionlog/src/commands/status.ts +0 -172
- package/references/sessionlog/src/config.ts +0 -165
- package/references/sessionlog/src/events/event-log.ts +0 -126
- package/references/sessionlog/src/git-operations.ts +0 -558
- package/references/sessionlog/src/hooks/git-hooks.ts +0 -165
- package/references/sessionlog/src/hooks/lifecycle.ts +0 -391
- package/references/sessionlog/src/index.ts +0 -650
- package/references/sessionlog/src/security/redaction.ts +0 -283
- package/references/sessionlog/src/session/state-machine.ts +0 -452
- package/references/sessionlog/src/store/checkpoint-store.ts +0 -509
- package/references/sessionlog/src/store/native-store.ts +0 -173
- package/references/sessionlog/src/store/provider-types.ts +0 -99
- package/references/sessionlog/src/store/session-store.ts +0 -266
- package/references/sessionlog/src/strategy/attribution.ts +0 -296
- package/references/sessionlog/src/strategy/common.ts +0 -207
- package/references/sessionlog/src/strategy/content-overlap.ts +0 -228
- package/references/sessionlog/src/strategy/manual-commit.ts +0 -988
- package/references/sessionlog/src/strategy/types.ts +0 -279
- package/references/sessionlog/src/summarize/claude-generator.ts +0 -115
- package/references/sessionlog/src/summarize/summarize.ts +0 -432
- package/references/sessionlog/src/types.ts +0 -508
- package/references/sessionlog/src/utils/chunk-files.ts +0 -49
- package/references/sessionlog/src/utils/commit-message.ts +0 -65
- package/references/sessionlog/src/utils/detect-agent.ts +0 -36
- package/references/sessionlog/src/utils/hook-managers.ts +0 -125
- package/references/sessionlog/src/utils/ide-tags.ts +0 -32
- package/references/sessionlog/src/utils/paths.ts +0 -79
- package/references/sessionlog/src/utils/preview-rewind.ts +0 -80
- package/references/sessionlog/src/utils/rewind-conflict.ts +0 -121
- package/references/sessionlog/src/utils/shadow-branch.ts +0 -109
- package/references/sessionlog/src/utils/string-utils.ts +0 -46
- package/references/sessionlog/src/utils/todo-extract.ts +0 -188
- package/references/sessionlog/src/utils/trailers.ts +0 -187
- package/references/sessionlog/src/utils/transcript-parse.ts +0 -177
- package/references/sessionlog/src/utils/transcript-timestamp.ts +0 -59
- package/references/sessionlog/src/utils/tree-ops.ts +0 -219
- package/references/sessionlog/src/utils/tty.ts +0 -72
- package/references/sessionlog/src/utils/validation.ts +0 -65
- package/references/sessionlog/src/utils/worktree.ts +0 -58
- package/references/sessionlog/src/wire-types.ts +0 -59
- package/references/sessionlog/templates/setup-env.sh +0 -153
- package/references/sessionlog/tsconfig.json +0 -18
- package/references/sessionlog/vitest.config.ts +0 -12
- package/references/skill-tree/.claude/settings.json +0 -6
- package/references/skill-tree/.sudocode/issues.jsonl +0 -19
- package/references/skill-tree/.sudocode/specs.jsonl +0 -3
- package/references/skill-tree/CLAUDE.md +0 -126
- package/references/skill-tree/README.md +0 -372
- package/references/skill-tree/docs/GAPS_v1.md +0 -221
- package/references/skill-tree/docs/INTEGRATION_PLAN.md +0 -467
- package/references/skill-tree/docs/TODOS.md +0 -91
- package/references/skill-tree/docs/anthropic_skill_guide.md +0 -1364
- package/references/skill-tree/docs/design/federated-skill-trees.md +0 -524
- package/references/skill-tree/docs/design/multi-agent-sync.md +0 -759
- package/references/skill-tree/docs/scraper/BRAINSTORM.md +0 -583
- package/references/skill-tree/docs/scraper/POC_PLAN.md +0 -420
- package/references/skill-tree/docs/scraper/README.md +0 -170
- package/references/skill-tree/examples/basic-usage.ts +0 -164
- package/references/skill-tree/package-lock.json +0 -1852
- package/references/skill-tree/package.json +0 -66
- package/references/skill-tree/scraper/README.md +0 -123
- package/references/skill-tree/scraper/docs/DESIGN.md +0 -683
- package/references/skill-tree/scraper/docs/PLAN.md +0 -336
- package/references/skill-tree/scraper/drizzle.config.ts +0 -10
- package/references/skill-tree/scraper/package-lock.json +0 -6329
- package/references/skill-tree/scraper/package.json +0 -68
- package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +0 -7
- package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +0 -7
- package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +0 -27
- package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +0 -21
- package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +0 -54
- package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +0 -24
- package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +0 -93
- package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +0 -22
- package/references/skill-tree/scraper/tsup.config.ts +0 -14
- package/references/skill-tree/scraper/vitest.config.ts +0 -17
- package/references/skill-tree/scripts/convert-to-vitest.ts +0 -166
- package/references/skill-tree/skills/skill-writer/SKILL.md +0 -339
- package/references/skill-tree/skills/skill-writer/references/examples.md +0 -326
- package/references/skill-tree/skills/skill-writer/references/patterns.md +0 -210
- package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +0 -123
- package/references/skill-tree/test/run-all.ts +0 -106
- package/references/skill-tree/test/utils.ts +0 -128
- package/references/skill-tree/vitest.config.ts +0 -16
|
@@ -1,1127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for Minimem
|
|
3
|
-
*
|
|
4
|
-
* These tests exercise the full e2e flow:
|
|
5
|
-
* - Real SQLite database
|
|
6
|
-
* - Real file system operations
|
|
7
|
-
* - Mocked embeddings (deterministic, no API calls)
|
|
8
|
-
*
|
|
9
|
-
* Run with Node.js native test runner:
|
|
10
|
-
* npm run test:integration
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import fs from "node:fs/promises";
|
|
14
|
-
import os from "node:os";
|
|
15
|
-
import path from "node:path";
|
|
16
|
-
import { after, before, describe, it } from "node:test";
|
|
17
|
-
import assert from "node:assert";
|
|
18
|
-
|
|
19
|
-
import { Minimem } from "../minimem.js";
|
|
20
|
-
import { createMockFetch } from "./helpers.js";
|
|
21
|
-
|
|
22
|
-
describe("Minimem E2E Integration", () => {
|
|
23
|
-
let tempDir: string;
|
|
24
|
-
let minimem: Minimem;
|
|
25
|
-
let originalFetch: typeof fetch;
|
|
26
|
-
let mockFetch: ReturnType<typeof createMockFetch>;
|
|
27
|
-
|
|
28
|
-
before(async () => {
|
|
29
|
-
// Create temp directory
|
|
30
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "minimem-e2e-"));
|
|
31
|
-
await fs.mkdir(path.join(tempDir, "memory"));
|
|
32
|
-
|
|
33
|
-
// Create test memory files
|
|
34
|
-
await fs.writeFile(
|
|
35
|
-
path.join(tempDir, "MEMORY.md"),
|
|
36
|
-
`# Memory
|
|
37
|
-
|
|
38
|
-
## Important Decisions
|
|
39
|
-
- We decided to use PostgreSQL for the database
|
|
40
|
-
- API design follows REST principles
|
|
41
|
-
- All meetings should have action items
|
|
42
|
-
|
|
43
|
-
## Project Notes
|
|
44
|
-
- Project alpha is the main focus
|
|
45
|
-
- Beta testing starts next month
|
|
46
|
-
`
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
await fs.writeFile(
|
|
50
|
-
path.join(tempDir, "memory", "2024-01-15.md"),
|
|
51
|
-
`# Daily Log - 2024-01-15
|
|
52
|
-
|
|
53
|
-
## Meeting Notes
|
|
54
|
-
Had a meeting about the API design. Key decisions:
|
|
55
|
-
- Use REST for external APIs
|
|
56
|
-
- GraphQL for internal services
|
|
57
|
-
- Authentication via JWT tokens
|
|
58
|
-
|
|
59
|
-
## Todo
|
|
60
|
-
- [ ] Review PR #123
|
|
61
|
-
- [ ] Fix bug in user authentication
|
|
62
|
-
- [x] Deploy to staging
|
|
63
|
-
`
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
await fs.writeFile(
|
|
67
|
-
path.join(tempDir, "memory", "2024-01-16.md"),
|
|
68
|
-
`# Daily Log - 2024-01-16
|
|
69
|
-
|
|
70
|
-
## Bug Fix
|
|
71
|
-
Fixed critical bug in the database connection pool.
|
|
72
|
-
The error was caused by not properly closing connections.
|
|
73
|
-
|
|
74
|
-
## Feature Work
|
|
75
|
-
Started working on the new user dashboard feature.
|
|
76
|
-
Design review scheduled for tomorrow.
|
|
77
|
-
`
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
// Mock fetch
|
|
81
|
-
originalFetch = globalThis.fetch;
|
|
82
|
-
mockFetch = createMockFetch();
|
|
83
|
-
globalThis.fetch = mockFetch as unknown as typeof fetch;
|
|
84
|
-
|
|
85
|
-
// Set fake API key
|
|
86
|
-
process.env.OPENAI_API_KEY = "test-api-key-for-integration-tests";
|
|
87
|
-
|
|
88
|
-
// Create Minimem instance
|
|
89
|
-
minimem = await Minimem.create({
|
|
90
|
-
memoryDir: tempDir,
|
|
91
|
-
embedding: {
|
|
92
|
-
provider: "openai",
|
|
93
|
-
model: "text-embedding-3-small",
|
|
94
|
-
},
|
|
95
|
-
watch: { enabled: false }, // Disable watching for tests
|
|
96
|
-
hybrid: { enabled: true },
|
|
97
|
-
query: { minScore: 0.0 }, // Lower threshold for testing
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
after(async () => {
|
|
102
|
-
// Cleanup
|
|
103
|
-
minimem?.close();
|
|
104
|
-
globalThis.fetch = originalFetch;
|
|
105
|
-
delete process.env.OPENAI_API_KEY;
|
|
106
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it("indexes memory files and creates database", async () => {
|
|
110
|
-
// Trigger sync (happens lazily on first search or explicit call)
|
|
111
|
-
await minimem.sync();
|
|
112
|
-
|
|
113
|
-
const status = await minimem.status();
|
|
114
|
-
|
|
115
|
-
assert.equal(status.memoryDir, tempDir);
|
|
116
|
-
assert.equal(status.provider, "openai");
|
|
117
|
-
assert.equal(status.model, "text-embedding-3-small");
|
|
118
|
-
assert.ok(status.fileCount >= 3, `Expected at least 3 files, got ${status.fileCount}`);
|
|
119
|
-
assert.ok(status.chunkCount > 0, `Expected chunks, got ${status.chunkCount}`);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it("searches and returns relevant results for 'database'", async () => {
|
|
123
|
-
const results = await minimem.search("database connection bug fix");
|
|
124
|
-
|
|
125
|
-
assert.ok(results.length > 0, "Expected search results");
|
|
126
|
-
|
|
127
|
-
// Should find the bug fix entry
|
|
128
|
-
const hasBugFix = results.some(r =>
|
|
129
|
-
r.snippet.toLowerCase().includes("bug") ||
|
|
130
|
-
r.snippet.toLowerCase().includes("database")
|
|
131
|
-
);
|
|
132
|
-
assert.ok(hasBugFix, "Expected to find database/bug related content");
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("searches and returns relevant results for 'meeting'", async () => {
|
|
136
|
-
const results = await minimem.search("meeting API design decisions");
|
|
137
|
-
|
|
138
|
-
assert.ok(results.length > 0, "Expected search results");
|
|
139
|
-
|
|
140
|
-
// Should find meeting notes
|
|
141
|
-
const hasMeeting = results.some(r =>
|
|
142
|
-
r.snippet.toLowerCase().includes("meeting") ||
|
|
143
|
-
r.snippet.toLowerCase().includes("api")
|
|
144
|
-
);
|
|
145
|
-
assert.ok(hasMeeting, "Expected to find meeting/API related content");
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it("returns results with correct metadata", async () => {
|
|
149
|
-
const results = await minimem.search("project alpha beta");
|
|
150
|
-
|
|
151
|
-
assert.ok(results.length > 0, "Expected search results");
|
|
152
|
-
|
|
153
|
-
for (const result of results) {
|
|
154
|
-
// Each result should have required fields
|
|
155
|
-
assert.ok(typeof result.path === "string", "Result should have path");
|
|
156
|
-
assert.ok(typeof result.startLine === "number", "Result should have startLine");
|
|
157
|
-
assert.ok(typeof result.endLine === "number", "Result should have endLine");
|
|
158
|
-
assert.ok(typeof result.score === "number", "Result should have score");
|
|
159
|
-
assert.ok(typeof result.snippet === "string", "Result should have snippet");
|
|
160
|
-
assert.ok(result.score >= 0 && result.score <= 1, "Score should be between 0 and 1");
|
|
161
|
-
assert.ok(result.startLine <= result.endLine, "startLine should be <= endLine");
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it("respects maxResults parameter", async () => {
|
|
166
|
-
const results = await minimem.search("meeting todo bug", { maxResults: 2 });
|
|
167
|
-
|
|
168
|
-
assert.ok(results.length <= 2, `Expected at most 2 results, got ${results.length}`);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it("respects minScore parameter", async () => {
|
|
172
|
-
const lowThreshold = await minimem.search("test", { minScore: 0.0 });
|
|
173
|
-
const highThreshold = await minimem.search("test", { minScore: 0.99 });
|
|
174
|
-
|
|
175
|
-
// High threshold should return fewer or equal results
|
|
176
|
-
assert.ok(
|
|
177
|
-
highThreshold.length <= lowThreshold.length,
|
|
178
|
-
"Higher minScore should return fewer results"
|
|
179
|
-
);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it("handles empty query gracefully", async () => {
|
|
183
|
-
const results = await minimem.search("");
|
|
184
|
-
assert.deepEqual(results, [], "Empty query should return empty results");
|
|
185
|
-
|
|
186
|
-
const whitespaceResults = await minimem.search(" ");
|
|
187
|
-
assert.deepEqual(whitespaceResults, [], "Whitespace query should return empty results");
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it("syncs new files when sync is called", async () => {
|
|
191
|
-
// Add a new file
|
|
192
|
-
await fs.writeFile(
|
|
193
|
-
path.join(tempDir, "memory", "2024-01-17.md"),
|
|
194
|
-
`# Daily Log - 2024-01-17
|
|
195
|
-
|
|
196
|
-
## New Feature
|
|
197
|
-
Implemented the epsilon feature for the gamma module.
|
|
198
|
-
This was an urgent request from the product team.
|
|
199
|
-
`
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
// Force sync
|
|
203
|
-
await minimem.sync({ force: true });
|
|
204
|
-
|
|
205
|
-
// Search for new content
|
|
206
|
-
const results = await minimem.search("epsilon gamma urgent feature");
|
|
207
|
-
|
|
208
|
-
assert.ok(results.length > 0, "Expected to find newly synced content");
|
|
209
|
-
const hasNewContent = results.some(r =>
|
|
210
|
-
r.snippet.toLowerCase().includes("epsilon") ||
|
|
211
|
-
r.snippet.toLowerCase().includes("gamma")
|
|
212
|
-
);
|
|
213
|
-
assert.ok(hasNewContent, "Expected to find epsilon/gamma content from new file");
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it("removes stale entries when files are deleted", async () => {
|
|
217
|
-
// Delete the file we just added
|
|
218
|
-
await fs.rm(path.join(tempDir, "memory", "2024-01-17.md"));
|
|
219
|
-
|
|
220
|
-
// Force sync
|
|
221
|
-
await minimem.sync({ force: true });
|
|
222
|
-
|
|
223
|
-
// The epsilon/gamma content should be gone or ranked lower
|
|
224
|
-
const results = await minimem.search("epsilon gamma urgent");
|
|
225
|
-
|
|
226
|
-
// Either no results or none containing epsilon
|
|
227
|
-
const hasEpsilon = results.some(r => r.snippet.toLowerCase().includes("epsilon"));
|
|
228
|
-
assert.ok(!hasEpsilon, "Deleted file content should not appear in results");
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it("caches embeddings for repeated content", async () => {
|
|
232
|
-
const initialCallCount = mockFetch.mock.callCount();
|
|
233
|
-
|
|
234
|
-
// Search twice with same query
|
|
235
|
-
await minimem.search("database connection");
|
|
236
|
-
await minimem.search("database connection");
|
|
237
|
-
|
|
238
|
-
const finalCallCount = mockFetch.mock.callCount();
|
|
239
|
-
|
|
240
|
-
// Second search should use cached query embedding
|
|
241
|
-
// (may still make 1 call for query, but not re-embed all chunks)
|
|
242
|
-
assert.ok(
|
|
243
|
-
finalCallCount - initialCallCount <= 2,
|
|
244
|
-
"Expected caching to reduce API calls"
|
|
245
|
-
);
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
describe("Minimem File Operations", () => {
|
|
250
|
-
let tempDir: string;
|
|
251
|
-
let minimem: Minimem;
|
|
252
|
-
let originalFetch: typeof fetch;
|
|
253
|
-
|
|
254
|
-
before(async () => {
|
|
255
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "minimem-files-"));
|
|
256
|
-
await fs.mkdir(path.join(tempDir, "memory"));
|
|
257
|
-
|
|
258
|
-
originalFetch = globalThis.fetch;
|
|
259
|
-
globalThis.fetch = createMockFetch() as unknown as typeof fetch;
|
|
260
|
-
process.env.OPENAI_API_KEY = "test-key";
|
|
261
|
-
|
|
262
|
-
minimem = await Minimem.create({
|
|
263
|
-
memoryDir: tempDir,
|
|
264
|
-
embedding: { provider: "openai" },
|
|
265
|
-
watch: { enabled: false },
|
|
266
|
-
});
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
after(async () => {
|
|
270
|
-
minimem?.close();
|
|
271
|
-
globalThis.fetch = originalFetch;
|
|
272
|
-
delete process.env.OPENAI_API_KEY;
|
|
273
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
it("lists memory files", async () => {
|
|
277
|
-
await fs.writeFile(path.join(tempDir, "MEMORY.md"), "# Test");
|
|
278
|
-
await fs.writeFile(path.join(tempDir, "memory", "note.md"), "# Note");
|
|
279
|
-
|
|
280
|
-
const files = await minimem.listFiles();
|
|
281
|
-
|
|
282
|
-
assert.ok(files.includes("MEMORY.md"), "Should list MEMORY.md");
|
|
283
|
-
assert.ok(files.some(f => f.includes("note.md")), "Should list note.md");
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
it("reads file content", async () => {
|
|
287
|
-
await fs.writeFile(path.join(tempDir, "MEMORY.md"), "Line 1\nLine 2\nLine 3");
|
|
288
|
-
|
|
289
|
-
const content = await minimem.readFile("MEMORY.md");
|
|
290
|
-
|
|
291
|
-
assert.equal(content, "Line 1\nLine 2\nLine 3");
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
it("reads specific lines", async () => {
|
|
295
|
-
await fs.writeFile(
|
|
296
|
-
path.join(tempDir, "MEMORY.md"),
|
|
297
|
-
"Line 1\nLine 2\nLine 3\nLine 4\nLine 5"
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
const result = await minimem.readLines("MEMORY.md", { from: 2, lines: 2 });
|
|
301
|
-
|
|
302
|
-
assert.ok(result !== null);
|
|
303
|
-
assert.equal(result.content, "Line 2\nLine 3");
|
|
304
|
-
assert.equal(result.startLine, 2);
|
|
305
|
-
assert.equal(result.endLine, 3);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it("writes new file", async () => {
|
|
309
|
-
await minimem.writeFile("memory/new-file.md", "# New Content\nTest");
|
|
310
|
-
|
|
311
|
-
const content = await fs.readFile(
|
|
312
|
-
path.join(tempDir, "memory", "new-file.md"),
|
|
313
|
-
"utf-8"
|
|
314
|
-
);
|
|
315
|
-
assert.equal(content, "# New Content\nTest");
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it("appends to existing file", async () => {
|
|
319
|
-
await fs.writeFile(path.join(tempDir, "memory", "append.md"), "First line");
|
|
320
|
-
|
|
321
|
-
await minimem.appendFile("memory/append.md", "Second line");
|
|
322
|
-
|
|
323
|
-
const content = await fs.readFile(
|
|
324
|
-
path.join(tempDir, "memory", "append.md"),
|
|
325
|
-
"utf-8"
|
|
326
|
-
);
|
|
327
|
-
assert.ok(content.includes("First line"));
|
|
328
|
-
assert.ok(content.includes("Second line"));
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
it("appends to today's log", async () => {
|
|
332
|
-
const today = new Date().toISOString().split("T")[0];
|
|
333
|
-
|
|
334
|
-
const resultPath = await minimem.appendToday("Today's note");
|
|
335
|
-
|
|
336
|
-
assert.equal(resultPath, `memory/${today}.md`);
|
|
337
|
-
|
|
338
|
-
const content = await fs.readFile(
|
|
339
|
-
path.join(tempDir, `memory/${today}.md`),
|
|
340
|
-
"utf-8"
|
|
341
|
-
);
|
|
342
|
-
assert.ok(content.includes("Today's note"));
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
it("rejects invalid memory paths", async () => {
|
|
346
|
-
await assert.rejects(
|
|
347
|
-
() => minimem.writeFile("../outside.md", "content"),
|
|
348
|
-
/Invalid memory path/
|
|
349
|
-
);
|
|
350
|
-
|
|
351
|
-
await assert.rejects(
|
|
352
|
-
() => minimem.writeFile("src/code.ts", "content"),
|
|
353
|
-
/Invalid memory path/
|
|
354
|
-
);
|
|
355
|
-
});
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
describe("Minimem BM25-Only Mode", () => {
|
|
359
|
-
let tempDir: string;
|
|
360
|
-
let minimem: Minimem;
|
|
361
|
-
|
|
362
|
-
before(async () => {
|
|
363
|
-
// Create temp directory
|
|
364
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "minimem-bm25-"));
|
|
365
|
-
await fs.mkdir(path.join(tempDir, "memory"));
|
|
366
|
-
|
|
367
|
-
// Create test memory files with distinct keywords
|
|
368
|
-
await fs.writeFile(
|
|
369
|
-
path.join(tempDir, "MEMORY.md"),
|
|
370
|
-
`# Memory
|
|
371
|
-
|
|
372
|
-
## Database Decisions
|
|
373
|
-
We chose PostgreSQL for the main database.
|
|
374
|
-
SQLite is used for local development.
|
|
375
|
-
Redis handles caching requirements.
|
|
376
|
-
|
|
377
|
-
## API Architecture
|
|
378
|
-
REST endpoints for external clients.
|
|
379
|
-
GraphQL for internal microservices.
|
|
380
|
-
WebSocket connections for real-time features.
|
|
381
|
-
`
|
|
382
|
-
);
|
|
383
|
-
|
|
384
|
-
await fs.writeFile(
|
|
385
|
-
path.join(tempDir, "memory", "meetings.md"),
|
|
386
|
-
`# Meeting Notes
|
|
387
|
-
|
|
388
|
-
## Sprint Planning
|
|
389
|
-
Discussed authentication requirements.
|
|
390
|
-
JWT tokens will be used for API authentication.
|
|
391
|
-
OAuth integration for third-party login.
|
|
392
|
-
|
|
393
|
-
## Design Review
|
|
394
|
-
Reviewed the dashboard wireframes.
|
|
395
|
-
Mobile-first approach approved.
|
|
396
|
-
Accessibility requirements confirmed.
|
|
397
|
-
`
|
|
398
|
-
);
|
|
399
|
-
|
|
400
|
-
await fs.writeFile(
|
|
401
|
-
path.join(tempDir, "memory", "bugs.md"),
|
|
402
|
-
`# Bug Tracker
|
|
403
|
-
|
|
404
|
-
## Critical Issues
|
|
405
|
-
Memory leak in connection pooling.
|
|
406
|
-
Fixed by properly closing database handles.
|
|
407
|
-
|
|
408
|
-
## Performance
|
|
409
|
-
Slow queries on user search.
|
|
410
|
-
Added index on email column.
|
|
411
|
-
Response time improved by 80%.
|
|
412
|
-
`
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
// Ensure no API keys are set for this test
|
|
416
|
-
delete process.env.OPENAI_API_KEY;
|
|
417
|
-
delete process.env.GOOGLE_API_KEY;
|
|
418
|
-
delete process.env.GEMINI_API_KEY;
|
|
419
|
-
|
|
420
|
-
// Create Minimem instance with explicit "none" provider (BM25-only)
|
|
421
|
-
minimem = await Minimem.create({
|
|
422
|
-
memoryDir: tempDir,
|
|
423
|
-
embedding: {
|
|
424
|
-
provider: "none",
|
|
425
|
-
},
|
|
426
|
-
watch: { enabled: false },
|
|
427
|
-
hybrid: { enabled: true },
|
|
428
|
-
query: { minScore: 0.0 },
|
|
429
|
-
});
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
after(async () => {
|
|
433
|
-
minimem?.close();
|
|
434
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
it("creates instance in BM25-only mode", async () => {
|
|
438
|
-
const status = await minimem.status();
|
|
439
|
-
|
|
440
|
-
assert.equal(status.provider, "none");
|
|
441
|
-
assert.equal(status.model, "bm25-only");
|
|
442
|
-
assert.equal(status.bm25Only, true);
|
|
443
|
-
assert.equal(status.ftsAvailable, true);
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
it("indexes files without embeddings", async () => {
|
|
447
|
-
await minimem.sync();
|
|
448
|
-
|
|
449
|
-
const status = await minimem.status();
|
|
450
|
-
|
|
451
|
-
assert.ok(status.fileCount >= 3, `Expected at least 3 files, got ${status.fileCount}`);
|
|
452
|
-
assert.ok(status.chunkCount > 0, `Expected chunks, got ${status.chunkCount}`);
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
it("finds results for 'PostgreSQL database'", async () => {
|
|
456
|
-
const results = await minimem.search("PostgreSQL database");
|
|
457
|
-
|
|
458
|
-
assert.ok(results.length > 0, "Expected search results for 'PostgreSQL database'");
|
|
459
|
-
|
|
460
|
-
// Should find the database decisions section
|
|
461
|
-
const hasPostgres = results.some(r =>
|
|
462
|
-
r.snippet.toLowerCase().includes("postgresql")
|
|
463
|
-
);
|
|
464
|
-
assert.ok(hasPostgres, "Expected to find PostgreSQL in results");
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
it("finds results for 'authentication JWT'", async () => {
|
|
468
|
-
const results = await minimem.search("authentication JWT tokens");
|
|
469
|
-
|
|
470
|
-
assert.ok(results.length > 0, "Expected search results for 'authentication JWT'");
|
|
471
|
-
|
|
472
|
-
// Should find the meeting notes about authentication
|
|
473
|
-
const hasAuth = results.some(r =>
|
|
474
|
-
r.snippet.toLowerCase().includes("jwt") ||
|
|
475
|
-
r.snippet.toLowerCase().includes("authentication")
|
|
476
|
-
);
|
|
477
|
-
assert.ok(hasAuth, "Expected to find JWT/authentication in results");
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
it("finds results for 'connection pooling'", async () => {
|
|
481
|
-
const results = await minimem.search("connection pooling");
|
|
482
|
-
|
|
483
|
-
assert.ok(results.length > 0, "Expected search results for 'connection pooling'");
|
|
484
|
-
|
|
485
|
-
// Should find the bug tracker content
|
|
486
|
-
const hasBug = results.some(r =>
|
|
487
|
-
r.snippet.toLowerCase().includes("connection") ||
|
|
488
|
-
r.snippet.toLowerCase().includes("pooling")
|
|
489
|
-
);
|
|
490
|
-
assert.ok(hasBug, "Expected to find connection/pooling in results");
|
|
491
|
-
});
|
|
492
|
-
|
|
493
|
-
it("returns no results for non-existent terms", async () => {
|
|
494
|
-
const results = await minimem.search("xyzzy quantum blockchain cryptocurrency");
|
|
495
|
-
|
|
496
|
-
// Should have no or very low scoring results
|
|
497
|
-
const highScoreResults = results.filter(r => r.score > 0.3);
|
|
498
|
-
assert.equal(highScoreResults.length, 0, "Expected no high-scoring results for nonsense query");
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
it("respects maxResults parameter", async () => {
|
|
502
|
-
const results = await minimem.search("database API", { maxResults: 2 });
|
|
503
|
-
|
|
504
|
-
assert.ok(results.length <= 2, `Expected at most 2 results, got ${results.length}`);
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
it("syncs new files correctly", async () => {
|
|
508
|
-
// Add a new file
|
|
509
|
-
await fs.writeFile(
|
|
510
|
-
path.join(tempDir, "memory", "deployment.md"),
|
|
511
|
-
`# Deployment Guide
|
|
512
|
-
|
|
513
|
-
## Production Setup
|
|
514
|
-
Kubernetes cluster configuration.
|
|
515
|
-
Docker images pushed to ECR registry.
|
|
516
|
-
Terraform manages infrastructure.
|
|
517
|
-
`
|
|
518
|
-
);
|
|
519
|
-
|
|
520
|
-
await minimem.sync({ force: true });
|
|
521
|
-
|
|
522
|
-
// Search for new content
|
|
523
|
-
const results = await minimem.search("Kubernetes Docker deployment");
|
|
524
|
-
|
|
525
|
-
assert.ok(results.length > 0, "Expected to find newly synced content");
|
|
526
|
-
const hasDeployment = results.some(r =>
|
|
527
|
-
r.snippet.toLowerCase().includes("kubernetes") ||
|
|
528
|
-
r.snippet.toLowerCase().includes("docker")
|
|
529
|
-
);
|
|
530
|
-
assert.ok(hasDeployment, "Expected to find Kubernetes/Docker content");
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
it("removes deleted files from index", async () => {
|
|
534
|
-
// Delete the deployment file
|
|
535
|
-
await fs.rm(path.join(tempDir, "memory", "deployment.md"));
|
|
536
|
-
|
|
537
|
-
await minimem.sync({ force: true });
|
|
538
|
-
|
|
539
|
-
// Search for deleted content
|
|
540
|
-
const results = await minimem.search("Kubernetes Docker Terraform");
|
|
541
|
-
|
|
542
|
-
// Should not find the deleted content
|
|
543
|
-
const hasKubernetes = results.some(r =>
|
|
544
|
-
r.snippet.toLowerCase().includes("kubernetes")
|
|
545
|
-
);
|
|
546
|
-
assert.ok(!hasKubernetes, "Deleted file content should not appear in results");
|
|
547
|
-
});
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
describe("Minimem Auto-Fallback to BM25", () => {
|
|
551
|
-
let tempDir: string;
|
|
552
|
-
let minimem: Minimem;
|
|
553
|
-
|
|
554
|
-
before(async () => {
|
|
555
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "minimem-autobm25-"));
|
|
556
|
-
await fs.mkdir(path.join(tempDir, "memory"));
|
|
557
|
-
|
|
558
|
-
await fs.writeFile(
|
|
559
|
-
path.join(tempDir, "MEMORY.md"),
|
|
560
|
-
`# Test Memory
|
|
561
|
-
Important notes about the project.
|
|
562
|
-
Database uses PostgreSQL.
|
|
563
|
-
`
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
// Ensure no API keys
|
|
567
|
-
delete process.env.OPENAI_API_KEY;
|
|
568
|
-
delete process.env.GOOGLE_API_KEY;
|
|
569
|
-
delete process.env.GEMINI_API_KEY;
|
|
570
|
-
|
|
571
|
-
// Use "auto" provider - should fall back to BM25-only
|
|
572
|
-
minimem = await Minimem.create({
|
|
573
|
-
memoryDir: tempDir,
|
|
574
|
-
embedding: {
|
|
575
|
-
provider: "auto",
|
|
576
|
-
},
|
|
577
|
-
watch: { enabled: false },
|
|
578
|
-
hybrid: { enabled: true },
|
|
579
|
-
});
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
after(async () => {
|
|
583
|
-
minimem?.close();
|
|
584
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
it("auto-falls back to BM25-only when no API keys available", async () => {
|
|
588
|
-
const status = await minimem.status();
|
|
589
|
-
|
|
590
|
-
assert.equal(status.provider, "none");
|
|
591
|
-
assert.equal(status.bm25Only, true);
|
|
592
|
-
assert.ok(status.fallbackReason?.includes("BM25"), "Should have fallback reason");
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
it("search still works in auto-fallback mode", async () => {
|
|
596
|
-
await minimem.sync();
|
|
597
|
-
|
|
598
|
-
const results = await minimem.search("PostgreSQL database");
|
|
599
|
-
|
|
600
|
-
assert.ok(results.length > 0, "Expected search results");
|
|
601
|
-
const hasDb = results.some(r =>
|
|
602
|
-
r.snippet.toLowerCase().includes("postgresql") ||
|
|
603
|
-
r.snippet.toLowerCase().includes("database")
|
|
604
|
-
);
|
|
605
|
-
assert.ok(hasDb, "Expected to find PostgreSQL/database in results");
|
|
606
|
-
});
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
describe("Minimem Staleness Detection", () => {
|
|
610
|
-
let tempDir: string;
|
|
611
|
-
let minimem: Minimem;
|
|
612
|
-
let originalFetch: typeof global.fetch;
|
|
613
|
-
|
|
614
|
-
before(async () => {
|
|
615
|
-
originalFetch = global.fetch;
|
|
616
|
-
global.fetch = createMockFetch() as unknown as typeof global.fetch;
|
|
617
|
-
|
|
618
|
-
// Set fake API key (required by provider validation)
|
|
619
|
-
process.env.OPENAI_API_KEY = "test-api-key-for-staleness-tests";
|
|
620
|
-
|
|
621
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "minimem-stale-test-"));
|
|
622
|
-
|
|
623
|
-
await fs.writeFile(
|
|
624
|
-
path.join(tempDir, "MEMORY.md"),
|
|
625
|
-
"# Original Content\n\nThis is the original memory content."
|
|
626
|
-
);
|
|
627
|
-
|
|
628
|
-
// Create with watch disabled - this is the scenario we're testing
|
|
629
|
-
minimem = await Minimem.create({
|
|
630
|
-
memoryDir: tempDir,
|
|
631
|
-
embedding: { provider: "openai" },
|
|
632
|
-
watch: { enabled: false },
|
|
633
|
-
hybrid: { enabled: true },
|
|
634
|
-
query: { minScore: 0.0 }, // Lower threshold for testing
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
// Initial sync
|
|
638
|
-
await minimem.sync();
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
after(async () => {
|
|
642
|
-
global.fetch = originalFetch;
|
|
643
|
-
delete process.env.OPENAI_API_KEY;
|
|
644
|
-
minimem?.close();
|
|
645
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
it("detects modified files without watcher", async () => {
|
|
649
|
-
// First search - should find original content
|
|
650
|
-
const results1 = await minimem.search("original content");
|
|
651
|
-
assert.ok(results1.length > 0, "Should find original content");
|
|
652
|
-
|
|
653
|
-
// Modify the file externally (simulating user edit)
|
|
654
|
-
await fs.writeFile(
|
|
655
|
-
path.join(tempDir, "MEMORY.md"),
|
|
656
|
-
"# Updated Content\n\nThis is completely new modified content about bananas."
|
|
657
|
-
);
|
|
658
|
-
|
|
659
|
-
// Search again - should detect staleness and re-sync
|
|
660
|
-
const results2 = await minimem.search("bananas");
|
|
661
|
-
assert.ok(results2.length > 0, "Should find new content after mtime-based staleness detection");
|
|
662
|
-
const hasBananas = results2.some(r => r.snippet.toLowerCase().includes("banana"));
|
|
663
|
-
assert.ok(hasBananas, "Should have indexed the new content");
|
|
664
|
-
});
|
|
665
|
-
|
|
666
|
-
it("detects new files without watcher", async () => {
|
|
667
|
-
// Add a new file
|
|
668
|
-
await fs.mkdir(path.join(tempDir, "memory"), { recursive: true });
|
|
669
|
-
await fs.writeFile(
|
|
670
|
-
path.join(tempDir, "memory", "new-topic.md"),
|
|
671
|
-
"# New Topic\n\nThis document discusses elephants and their habitats."
|
|
672
|
-
);
|
|
673
|
-
|
|
674
|
-
// Search - should detect the new file and sync
|
|
675
|
-
const results = await minimem.search("elephants habitats");
|
|
676
|
-
assert.ok(results.length > 0, "Should find content from new file");
|
|
677
|
-
const hasElephants = results.some(r => r.snippet.toLowerCase().includes("elephant"));
|
|
678
|
-
assert.ok(hasElephants, "Should have indexed the new file");
|
|
679
|
-
});
|
|
680
|
-
|
|
681
|
-
it("detects deleted files without watcher", async () => {
|
|
682
|
-
// Delete the file we just created
|
|
683
|
-
await fs.rm(path.join(tempDir, "memory", "new-topic.md"));
|
|
684
|
-
|
|
685
|
-
// Search - should detect the deletion and re-sync
|
|
686
|
-
const results = await minimem.search("elephants");
|
|
687
|
-
|
|
688
|
-
// After re-sync, the deleted content should no longer be found
|
|
689
|
-
// (or have lower relevance since it's not in the index anymore)
|
|
690
|
-
const hasElephants = results.some(r => r.snippet.toLowerCase().includes("elephant"));
|
|
691
|
-
assert.ok(!hasElephants, "Should not find content from deleted file after staleness detection");
|
|
692
|
-
});
|
|
693
|
-
});
|
|
694
|
-
|
|
695
|
-
describe("Minimem Type Filtering", () => {
|
|
696
|
-
let tempDir: string;
|
|
697
|
-
let minimem: Minimem;
|
|
698
|
-
let originalFetch: typeof global.fetch;
|
|
699
|
-
|
|
700
|
-
before(async () => {
|
|
701
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "minimem-type-filter-"));
|
|
702
|
-
await fs.mkdir(path.join(tempDir, "memory"));
|
|
703
|
-
|
|
704
|
-
// Create memory files with different observation types
|
|
705
|
-
await fs.writeFile(
|
|
706
|
-
path.join(tempDir, "MEMORY.md"),
|
|
707
|
-
`# Memory
|
|
708
|
-
|
|
709
|
-
## API Design Decision
|
|
710
|
-
<!-- type: decision -->
|
|
711
|
-
We decided to use REST for external APIs and GraphQL for internal services.
|
|
712
|
-
Authentication will use JWT tokens.
|
|
713
|
-
|
|
714
|
-
## General Notes
|
|
715
|
-
Some general project notes without a type tag.
|
|
716
|
-
The project uses TypeScript and Node.js.
|
|
717
|
-
`
|
|
718
|
-
);
|
|
719
|
-
|
|
720
|
-
await fs.writeFile(
|
|
721
|
-
path.join(tempDir, "memory", "bugs.md"),
|
|
722
|
-
`# Bug Tracker
|
|
723
|
-
|
|
724
|
-
## Login Bug
|
|
725
|
-
<!-- type: bugfix -->
|
|
726
|
-
Fixed critical login failure caused by expired JWT token not being refreshed.
|
|
727
|
-
Root cause was missing refresh token rotation logic.
|
|
728
|
-
|
|
729
|
-
## Dashboard Crash
|
|
730
|
-
<!-- type: bugfix -->
|
|
731
|
-
Fixed dashboard crash when user had no recent activity.
|
|
732
|
-
Added null check for empty activity arrays.
|
|
733
|
-
`
|
|
734
|
-
);
|
|
735
|
-
|
|
736
|
-
await fs.writeFile(
|
|
737
|
-
path.join(tempDir, "memory", "features.md"),
|
|
738
|
-
`# Features
|
|
739
|
-
|
|
740
|
-
## Search Feature
|
|
741
|
-
<!-- type: feature -->
|
|
742
|
-
Implemented full-text search with BM25 ranking.
|
|
743
|
-
Users can now search across all memory files.
|
|
744
|
-
|
|
745
|
-
## Export Feature
|
|
746
|
-
<!-- type: feature -->
|
|
747
|
-
Added CSV and JSON export for memory entries.
|
|
748
|
-
`
|
|
749
|
-
);
|
|
750
|
-
|
|
751
|
-
originalFetch = global.fetch;
|
|
752
|
-
global.fetch = createMockFetch() as unknown as typeof global.fetch;
|
|
753
|
-
process.env.OPENAI_API_KEY = "test-key-type-filter";
|
|
754
|
-
|
|
755
|
-
minimem = await Minimem.create({
|
|
756
|
-
memoryDir: tempDir,
|
|
757
|
-
embedding: { provider: "openai" },
|
|
758
|
-
watch: { enabled: false },
|
|
759
|
-
hybrid: { enabled: true },
|
|
760
|
-
query: { minScore: 0.0 },
|
|
761
|
-
});
|
|
762
|
-
|
|
763
|
-
await minimem.sync();
|
|
764
|
-
});
|
|
765
|
-
|
|
766
|
-
after(async () => {
|
|
767
|
-
minimem?.close();
|
|
768
|
-
global.fetch = originalFetch;
|
|
769
|
-
delete process.env.OPENAI_API_KEY;
|
|
770
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
it("returns all results when no type filter is specified", async () => {
|
|
774
|
-
const results = await minimem.search("API login search export");
|
|
775
|
-
|
|
776
|
-
assert.ok(results.length > 0, "Expected search results without type filter");
|
|
777
|
-
});
|
|
778
|
-
|
|
779
|
-
it("filters results by type: decision", async () => {
|
|
780
|
-
const results = await minimem.search("API design REST GraphQL JWT", { type: "decision" });
|
|
781
|
-
|
|
782
|
-
assert.ok(results.length > 0, "Expected decision results");
|
|
783
|
-
|
|
784
|
-
// Every result should come from the decision chunk
|
|
785
|
-
for (const r of results) {
|
|
786
|
-
assert.ok(
|
|
787
|
-
r.snippet.toLowerCase().includes("rest") ||
|
|
788
|
-
r.snippet.toLowerCase().includes("graphql") ||
|
|
789
|
-
r.snippet.toLowerCase().includes("decision") ||
|
|
790
|
-
r.snippet.toLowerCase().includes("jwt"),
|
|
791
|
-
`Decision result should contain relevant content, got: ${r.snippet.slice(0, 80)}`
|
|
792
|
-
);
|
|
793
|
-
}
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
it("filters results by type: bugfix", async () => {
|
|
797
|
-
const results = await minimem.search("login crash bug fix", { type: "bugfix" });
|
|
798
|
-
|
|
799
|
-
assert.ok(results.length > 0, "Expected bugfix results");
|
|
800
|
-
|
|
801
|
-
// Should only find bug-related content
|
|
802
|
-
const hasDecision = results.some(r =>
|
|
803
|
-
r.snippet.toLowerCase().includes("rest for external apis")
|
|
804
|
-
);
|
|
805
|
-
assert.ok(!hasDecision, "Bugfix filter should not return decision content");
|
|
806
|
-
});
|
|
807
|
-
|
|
808
|
-
it("filters results by type: feature", async () => {
|
|
809
|
-
const results = await minimem.search("search export feature", { type: "feature" });
|
|
810
|
-
|
|
811
|
-
assert.ok(results.length > 0, "Expected feature results");
|
|
812
|
-
|
|
813
|
-
// Should only find feature-related content
|
|
814
|
-
const hasBugfix = results.some(r =>
|
|
815
|
-
r.snippet.toLowerCase().includes("login failure") ||
|
|
816
|
-
r.snippet.toLowerCase().includes("dashboard crash")
|
|
817
|
-
);
|
|
818
|
-
assert.ok(!hasBugfix, "Feature filter should not return bugfix content");
|
|
819
|
-
});
|
|
820
|
-
|
|
821
|
-
it("returns empty results for non-matching type filter", async () => {
|
|
822
|
-
const results = await minimem.search("API design REST", { type: "discovery" });
|
|
823
|
-
|
|
824
|
-
// Should have no results since nothing is tagged as "discovery"
|
|
825
|
-
assert.equal(results.length, 0, "Expected no results for unused type");
|
|
826
|
-
});
|
|
827
|
-
|
|
828
|
-
it("type filter works with maxResults", async () => {
|
|
829
|
-
const results = await minimem.search("bug fix crash login", {
|
|
830
|
-
type: "bugfix",
|
|
831
|
-
maxResults: 1,
|
|
832
|
-
});
|
|
833
|
-
|
|
834
|
-
assert.ok(results.length <= 1, `Expected at most 1 result, got ${results.length}`);
|
|
835
|
-
});
|
|
836
|
-
});
|
|
837
|
-
|
|
838
|
-
describe("Minimem Privacy Tags", () => {
|
|
839
|
-
let tempDir: string;
|
|
840
|
-
let minimem: Minimem;
|
|
841
|
-
let originalFetch: typeof global.fetch;
|
|
842
|
-
|
|
843
|
-
before(async () => {
|
|
844
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "minimem-privacy-"));
|
|
845
|
-
await fs.mkdir(path.join(tempDir, "memory"));
|
|
846
|
-
|
|
847
|
-
// Create memory files with private content
|
|
848
|
-
await fs.writeFile(
|
|
849
|
-
path.join(tempDir, "MEMORY.md"),
|
|
850
|
-
`# Memory
|
|
851
|
-
|
|
852
|
-
## API Configuration
|
|
853
|
-
API endpoint: api.example.com/v2
|
|
854
|
-
Rate limit: 1000 requests per minute
|
|
855
|
-
|
|
856
|
-
<private>
|
|
857
|
-
API_KEY=sk-secret-key-12345
|
|
858
|
-
DB_PASSWORD=hunter2
|
|
859
|
-
AWS_SECRET=AKIAIOSFODNN7EXAMPLE
|
|
860
|
-
</private>
|
|
861
|
-
|
|
862
|
-
## Public Notes
|
|
863
|
-
The API uses versioned endpoints.
|
|
864
|
-
Documentation is at docs.example.com.
|
|
865
|
-
`
|
|
866
|
-
);
|
|
867
|
-
|
|
868
|
-
await fs.writeFile(
|
|
869
|
-
path.join(tempDir, "memory", "credentials.md"),
|
|
870
|
-
`# Service Credentials
|
|
871
|
-
|
|
872
|
-
## Production Database
|
|
873
|
-
Host: db.prod.example.com
|
|
874
|
-
Port: 5432
|
|
875
|
-
|
|
876
|
-
<private>
|
|
877
|
-
username: admin
|
|
878
|
-
password: super-secret-password-123
|
|
879
|
-
connection_string: postgres://admin:super-secret-password-123@db.prod.example.com:5432/main
|
|
880
|
-
</private>
|
|
881
|
-
|
|
882
|
-
## Staging Database
|
|
883
|
-
Host: db.staging.example.com
|
|
884
|
-
Port: 5432
|
|
885
|
-
`
|
|
886
|
-
);
|
|
887
|
-
|
|
888
|
-
originalFetch = global.fetch;
|
|
889
|
-
global.fetch = createMockFetch() as unknown as typeof global.fetch;
|
|
890
|
-
process.env.OPENAI_API_KEY = "test-key-privacy";
|
|
891
|
-
|
|
892
|
-
minimem = await Minimem.create({
|
|
893
|
-
memoryDir: tempDir,
|
|
894
|
-
embedding: { provider: "openai" },
|
|
895
|
-
watch: { enabled: false },
|
|
896
|
-
hybrid: { enabled: true },
|
|
897
|
-
query: { minScore: 0.0 },
|
|
898
|
-
});
|
|
899
|
-
|
|
900
|
-
await minimem.sync();
|
|
901
|
-
});
|
|
902
|
-
|
|
903
|
-
after(async () => {
|
|
904
|
-
minimem?.close();
|
|
905
|
-
global.fetch = originalFetch;
|
|
906
|
-
delete process.env.OPENAI_API_KEY;
|
|
907
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
908
|
-
});
|
|
909
|
-
|
|
910
|
-
it("does not include private content in search snippets", async () => {
|
|
911
|
-
const results = await minimem.search("API key password secret credentials");
|
|
912
|
-
|
|
913
|
-
// Check that no snippet contains the actual secret values
|
|
914
|
-
for (const r of results) {
|
|
915
|
-
assert.ok(
|
|
916
|
-
!r.snippet.includes("sk-secret-key-12345"),
|
|
917
|
-
"Snippet should not contain API key"
|
|
918
|
-
);
|
|
919
|
-
assert.ok(
|
|
920
|
-
!r.snippet.includes("hunter2"),
|
|
921
|
-
"Snippet should not contain DB password"
|
|
922
|
-
);
|
|
923
|
-
assert.ok(
|
|
924
|
-
!r.snippet.includes("super-secret-password-123"),
|
|
925
|
-
"Snippet should not contain production password"
|
|
926
|
-
);
|
|
927
|
-
assert.ok(
|
|
928
|
-
!r.snippet.includes("AKIAIOSFODNN7EXAMPLE"),
|
|
929
|
-
"Snippet should not contain AWS secret"
|
|
930
|
-
);
|
|
931
|
-
}
|
|
932
|
-
});
|
|
933
|
-
|
|
934
|
-
it("still indexes non-private content from files with private blocks", async () => {
|
|
935
|
-
const results = await minimem.search("API endpoint rate limit documentation");
|
|
936
|
-
|
|
937
|
-
assert.ok(results.length > 0, "Expected to find non-private content");
|
|
938
|
-
|
|
939
|
-
const hasPublic = results.some(r =>
|
|
940
|
-
r.snippet.toLowerCase().includes("api endpoint") ||
|
|
941
|
-
r.snippet.toLowerCase().includes("rate limit") ||
|
|
942
|
-
r.snippet.toLowerCase().includes("documentation") ||
|
|
943
|
-
r.snippet.toLowerCase().includes("api.example.com")
|
|
944
|
-
);
|
|
945
|
-
assert.ok(hasPublic, "Should find public content from files with private blocks");
|
|
946
|
-
});
|
|
947
|
-
|
|
948
|
-
it("indexes content around private blocks correctly", async () => {
|
|
949
|
-
const results = await minimem.search("staging database host port");
|
|
950
|
-
|
|
951
|
-
assert.ok(results.length > 0, "Expected to find staging database content");
|
|
952
|
-
|
|
953
|
-
const hasStaging = results.some(r =>
|
|
954
|
-
r.snippet.toLowerCase().includes("staging")
|
|
955
|
-
);
|
|
956
|
-
assert.ok(hasStaging, "Should find staging database content after private block");
|
|
957
|
-
});
|
|
958
|
-
});
|
|
959
|
-
|
|
960
|
-
describe("Minimem Schema Migration", () => {
|
|
961
|
-
let tempDir: string;
|
|
962
|
-
|
|
963
|
-
before(async () => {
|
|
964
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "minimem-migration-"));
|
|
965
|
-
});
|
|
966
|
-
|
|
967
|
-
after(async () => {
|
|
968
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
969
|
-
});
|
|
970
|
-
|
|
971
|
-
it("migrates from schema v2 to v3, preserving embedding cache", async () => {
|
|
972
|
-
const { DatabaseSync } = await import("node:sqlite");
|
|
973
|
-
const { ensureMemoryIndexSchema, SCHEMA_VERSION } = await import("../db/schema.js");
|
|
974
|
-
|
|
975
|
-
const dbPath = path.join(tempDir, "migration-test.db");
|
|
976
|
-
const db = new DatabaseSync(dbPath);
|
|
977
|
-
|
|
978
|
-
// Set up a v2 database manually
|
|
979
|
-
db.exec(`CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`);
|
|
980
|
-
db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', '2')`).run();
|
|
981
|
-
|
|
982
|
-
db.exec(`CREATE TABLE IF NOT EXISTS files (
|
|
983
|
-
path TEXT PRIMARY KEY,
|
|
984
|
-
source TEXT NOT NULL DEFAULT 'memory',
|
|
985
|
-
hash TEXT NOT NULL,
|
|
986
|
-
mtime INTEGER NOT NULL,
|
|
987
|
-
size INTEGER NOT NULL
|
|
988
|
-
)`);
|
|
989
|
-
db.exec(`CREATE TABLE IF NOT EXISTS chunks (
|
|
990
|
-
id TEXT PRIMARY KEY,
|
|
991
|
-
path TEXT NOT NULL,
|
|
992
|
-
source TEXT NOT NULL DEFAULT 'memory',
|
|
993
|
-
start_line INTEGER NOT NULL,
|
|
994
|
-
end_line INTEGER NOT NULL,
|
|
995
|
-
hash TEXT NOT NULL,
|
|
996
|
-
model TEXT NOT NULL,
|
|
997
|
-
text TEXT NOT NULL,
|
|
998
|
-
embedding TEXT NOT NULL,
|
|
999
|
-
updated_at INTEGER NOT NULL
|
|
1000
|
-
)`);
|
|
1001
|
-
|
|
1002
|
-
// Insert some data to verify migration drops tables
|
|
1003
|
-
db.prepare(`INSERT INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)`)
|
|
1004
|
-
.run("MEMORY.md", "memory", "abc123", 1000, 100);
|
|
1005
|
-
db.prepare(`INSERT INTO chunks (id, path, source, start_line, end_line, hash, model, text, embedding, updated_at)
|
|
1006
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1007
|
-
.run("chunk1", "MEMORY.md", "memory", 1, 5, "hash1", "test", "text", "[]", 1000);
|
|
1008
|
-
|
|
1009
|
-
// Create embedding cache with data that should be preserved
|
|
1010
|
-
db.exec(`CREATE TABLE IF NOT EXISTS embedding_cache (
|
|
1011
|
-
provider TEXT NOT NULL,
|
|
1012
|
-
model TEXT NOT NULL,
|
|
1013
|
-
provider_key TEXT NOT NULL,
|
|
1014
|
-
hash TEXT NOT NULL,
|
|
1015
|
-
embedding TEXT NOT NULL,
|
|
1016
|
-
dims INTEGER,
|
|
1017
|
-
updated_at INTEGER NOT NULL,
|
|
1018
|
-
PRIMARY KEY (provider, model, provider_key, hash)
|
|
1019
|
-
)`);
|
|
1020
|
-
db.prepare(`INSERT INTO embedding_cache (provider, model, provider_key, hash, embedding, dims, updated_at)
|
|
1021
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
|
1022
|
-
.run("openai", "text-embedding-3-small", "key1", "cachehash1", "[0.1, 0.2]", 2, 2000);
|
|
1023
|
-
|
|
1024
|
-
// Run migration by calling ensureMemoryIndexSchema
|
|
1025
|
-
const result = ensureMemoryIndexSchema({
|
|
1026
|
-
db,
|
|
1027
|
-
embeddingCacheTable: "embedding_cache",
|
|
1028
|
-
ftsTable: "chunks_fts",
|
|
1029
|
-
ftsEnabled: true,
|
|
1030
|
-
});
|
|
1031
|
-
|
|
1032
|
-
// Verify migration occurred
|
|
1033
|
-
assert.ok(result.migrated, "Migration should have been performed");
|
|
1034
|
-
|
|
1035
|
-
// Verify schema version is now current
|
|
1036
|
-
const versionRow = db.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get() as { value: string };
|
|
1037
|
-
assert.equal(versionRow.value, String(SCHEMA_VERSION), "Schema version should be updated");
|
|
1038
|
-
|
|
1039
|
-
// Verify old data was dropped (tables recreated empty)
|
|
1040
|
-
const fileCount = db.prepare(`SELECT COUNT(*) as count FROM files`).get() as { count: number };
|
|
1041
|
-
assert.equal(fileCount.count, 0, "Files table should be empty after migration");
|
|
1042
|
-
|
|
1043
|
-
const chunkCount = db.prepare(`SELECT COUNT(*) as count FROM chunks`).get() as { count: number };
|
|
1044
|
-
assert.equal(chunkCount.count, 0, "Chunks table should be empty after migration");
|
|
1045
|
-
|
|
1046
|
-
// Verify embedding cache was preserved
|
|
1047
|
-
const cacheCount = db.prepare(`SELECT COUNT(*) as count FROM embedding_cache`).get() as { count: number };
|
|
1048
|
-
assert.equal(cacheCount.count, 1, "Embedding cache should be preserved after migration");
|
|
1049
|
-
|
|
1050
|
-
const cacheRow = db.prepare(`SELECT hash, embedding FROM embedding_cache WHERE hash = ?`).get("cachehash1") as { hash: string; embedding: string } | undefined;
|
|
1051
|
-
assert.ok(cacheRow, "Cached embedding should still exist");
|
|
1052
|
-
assert.equal(cacheRow.embedding, "[0.1, 0.2]", "Cached embedding data should be intact");
|
|
1053
|
-
|
|
1054
|
-
// Verify the type column exists on chunks table
|
|
1055
|
-
const columns = db.prepare(`PRAGMA table_info(chunks)`).all() as Array<{ name: string }>;
|
|
1056
|
-
const hasTypeColumn = columns.some(c => c.name === "type");
|
|
1057
|
-
assert.ok(hasTypeColumn, "Chunks table should have 'type' column after migration");
|
|
1058
|
-
|
|
1059
|
-
// Verify type index exists
|
|
1060
|
-
const indexes = db.prepare(`PRAGMA index_list(chunks)`).all() as Array<{ name: string }>;
|
|
1061
|
-
const hasTypeIndex = indexes.some(idx => idx.name === "idx_chunks_type");
|
|
1062
|
-
assert.ok(hasTypeIndex, "Should have idx_chunks_type index after migration");
|
|
1063
|
-
|
|
1064
|
-
db.close();
|
|
1065
|
-
});
|
|
1066
|
-
|
|
1067
|
-
it("fresh database (no prior version) does not trigger migration flag", async () => {
|
|
1068
|
-
const { DatabaseSync } = await import("node:sqlite");
|
|
1069
|
-
const { ensureMemoryIndexSchema } = await import("../db/schema.js");
|
|
1070
|
-
|
|
1071
|
-
const dbPath = path.join(tempDir, "fresh-test.db");
|
|
1072
|
-
const db = new DatabaseSync(dbPath);
|
|
1073
|
-
|
|
1074
|
-
const result = ensureMemoryIndexSchema({
|
|
1075
|
-
db,
|
|
1076
|
-
embeddingCacheTable: "embedding_cache",
|
|
1077
|
-
ftsTable: "chunks_fts",
|
|
1078
|
-
ftsEnabled: true,
|
|
1079
|
-
});
|
|
1080
|
-
|
|
1081
|
-
// Fresh database should not report migration
|
|
1082
|
-
assert.ok(!result.migrated, "Fresh database should not report migration");
|
|
1083
|
-
|
|
1084
|
-
// But schema should be fully set up
|
|
1085
|
-
const columns = db.prepare(`PRAGMA table_info(chunks)`).all() as Array<{ name: string }>;
|
|
1086
|
-
const hasTypeColumn = columns.some(c => c.name === "type");
|
|
1087
|
-
assert.ok(hasTypeColumn, "Fresh database should have 'type' column");
|
|
1088
|
-
|
|
1089
|
-
db.close();
|
|
1090
|
-
});
|
|
1091
|
-
|
|
1092
|
-
it("same version does not re-migrate", async () => {
|
|
1093
|
-
const { DatabaseSync } = await import("node:sqlite");
|
|
1094
|
-
const { ensureMemoryIndexSchema, SCHEMA_VERSION } = await import("../db/schema.js");
|
|
1095
|
-
|
|
1096
|
-
const dbPath = path.join(tempDir, "same-version-test.db");
|
|
1097
|
-
const db = new DatabaseSync(dbPath);
|
|
1098
|
-
|
|
1099
|
-
// First call sets up schema
|
|
1100
|
-
ensureMemoryIndexSchema({
|
|
1101
|
-
db,
|
|
1102
|
-
embeddingCacheTable: "embedding_cache",
|
|
1103
|
-
ftsTable: "chunks_fts",
|
|
1104
|
-
ftsEnabled: true,
|
|
1105
|
-
});
|
|
1106
|
-
|
|
1107
|
-
// Insert some data
|
|
1108
|
-
db.prepare(`INSERT INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)`)
|
|
1109
|
-
.run("test.md", "memory", "hash", 1000, 50);
|
|
1110
|
-
|
|
1111
|
-
// Second call should not drop data
|
|
1112
|
-
const result = ensureMemoryIndexSchema({
|
|
1113
|
-
db,
|
|
1114
|
-
embeddingCacheTable: "embedding_cache",
|
|
1115
|
-
ftsTable: "chunks_fts",
|
|
1116
|
-
ftsEnabled: true,
|
|
1117
|
-
});
|
|
1118
|
-
|
|
1119
|
-
assert.ok(!result.migrated, "Same version should not trigger migration");
|
|
1120
|
-
|
|
1121
|
-
// Data should still exist
|
|
1122
|
-
const fileCount = db.prepare(`SELECT COUNT(*) as count FROM files`).get() as { count: number };
|
|
1123
|
-
assert.equal(fileCount.count, 1, "Files should be preserved when no migration needed");
|
|
1124
|
-
|
|
1125
|
-
db.close();
|
|
1126
|
-
});
|
|
1127
|
-
});
|