squish-memory 1.0.1 → 1.0.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/.env.mcp.example +4 -0
- package/README.md +35 -17
- package/config/plugin-manifest.json +1 -1
- package/dist/api/web/web.js +27 -1
- package/dist/commands/mcp-server.js +1 -1
- package/dist/core/mcp/server.js +27 -1
- package/dist/core/mcp/types.d.ts +4 -4
- package/dist/core/memory/memories.js +9 -6
- package/dist/core/scheduler/cron-scheduler.js +66 -13
- package/dist/db/adapter.js +88 -20
- package/dist/db/bootstrap.js +145 -71
- package/dist/index.d.ts +1 -1
- package/dist/index.js +195 -49
- package/generated/mcp/manifest.json +23 -23
- package/package.json +30 -18
- package/scripts/install-interactive.mjs +7 -4
- package/skills/memory-guide/SKILL.md +94 -18
- package/skills/squish-cli/SKILL.md +61 -21
- package/skills/squish-mcp/SKILL.md +46 -2
- package/skills/squish-memory/SKILL.md +30 -16
- package/dist/algorithms/analytics/token-estimator.d.ts.map +0 -1
- package/dist/algorithms/analytics/token-estimator.js.map +0 -1
- package/dist/algorithms/detection/hash-filters.d.ts.map +0 -1
- package/dist/algorithms/detection/hash-filters.js.map +0 -1
- package/dist/algorithms/detection/semantic-ranker.d.ts.map +0 -1
- package/dist/algorithms/detection/semantic-ranker.js.map +0 -1
- package/dist/algorithms/detection/two-stage-detector.d.ts.map +0 -1
- package/dist/algorithms/detection/two-stage-detector.js.map +0 -1
- package/dist/algorithms/handlers/approve-merge.d.ts.map +0 -1
- package/dist/algorithms/handlers/approve-merge.js.map +0 -1
- package/dist/algorithms/handlers/detect-duplicates.d.ts.map +0 -1
- package/dist/algorithms/handlers/detect-duplicates.js.map +0 -1
- package/dist/algorithms/handlers/get-stats.d.ts.map +0 -1
- package/dist/algorithms/handlers/get-stats.js.map +0 -1
- package/dist/algorithms/handlers/list-proposals.d.ts.map +0 -1
- package/dist/algorithms/handlers/list-proposals.js.map +0 -1
- package/dist/algorithms/handlers/preview-merge.d.ts.map +0 -1
- package/dist/algorithms/handlers/preview-merge.js.map +0 -1
- package/dist/algorithms/handlers/reject-merge.d.ts.map +0 -1
- package/dist/algorithms/handlers/reject-merge.js.map +0 -1
- package/dist/algorithms/handlers/reverse-merge.d.ts.map +0 -1
- package/dist/algorithms/handlers/reverse-merge.js.map +0 -1
- package/dist/algorithms/safety/safety-checks.d.ts.map +0 -1
- package/dist/algorithms/safety/safety-checks.js.map +0 -1
- package/dist/algorithms/strategies/merge-strategies.d.ts.map +0 -1
- package/dist/algorithms/strategies/merge-strategies.js.map +0 -1
- package/dist/algorithms/utils/response-builder.d.ts.map +0 -1
- package/dist/algorithms/utils/response-builder.js.map +0 -1
- package/dist/api/web/index.d.ts.map +0 -1
- package/dist/api/web/index.js.map +0 -1
- package/dist/api/web/web-server.d.ts.map +0 -1
- package/dist/api/web/web-server.js.map +0 -1
- package/dist/api/web/web.d.ts.map +0 -1
- package/dist/api/web/web.js.map +0 -1
- package/dist/commands/managed-sync.d.ts.map +0 -1
- package/dist/commands/managed-sync.js.map +0 -1
- package/dist/commands/mcp-server.d.ts.map +0 -1
- package/dist/commands/mcp-server.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/core/agent-memory.d.ts.map +0 -1
- package/dist/core/agent-memory.js.map +0 -1
- package/dist/core/associations.d.ts.map +0 -1
- package/dist/core/associations.js.map +0 -1
- package/dist/core/cache.d.ts.map +0 -1
- package/dist/core/cache.js.map +0 -1
- package/dist/core/consolidation.d.ts.map +0 -1
- package/dist/core/consolidation.js.map +0 -1
- package/dist/core/context-paging.d.ts.map +0 -1
- package/dist/core/context-paging.js.map +0 -1
- package/dist/core/context.d.ts.map +0 -1
- package/dist/core/context.js.map +0 -1
- package/dist/core/core-memory.d.ts.map +0 -1
- package/dist/core/core-memory.js.map +0 -1
- package/dist/core/database.d.ts.map +0 -1
- package/dist/core/database.js.map +0 -1
- package/dist/core/embeddings/google-multimodal.d.ts.map +0 -1
- package/dist/core/embeddings/google-multimodal.js.map +0 -1
- package/dist/core/embeddings/qmd-client.d.ts.map +0 -1
- package/dist/core/embeddings/qmd-client.js.map +0 -1
- package/dist/core/embeddings.d.ts.map +0 -1
- package/dist/core/embeddings.js.map +0 -1
- package/dist/core/governance.d.ts.map +0 -1
- package/dist/core/governance.js.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js.map +0 -1
- package/dist/core/layers/generator.d.ts.map +0 -1
- package/dist/core/layers/generator.js.map +0 -1
- package/dist/core/lifecycle.d.ts.map +0 -1
- package/dist/core/lifecycle.js.map +0 -1
- package/dist/core/local-embeddings.d.ts.map +0 -1
- package/dist/core/local-embeddings.js.map +0 -1
- package/dist/core/logger.d.ts.map +0 -1
- package/dist/core/logger.js.map +0 -1
- package/dist/core/mcp/client.d.ts.map +0 -1
- package/dist/core/mcp/client.js.map +0 -1
- package/dist/core/mcp/index.d.ts.map +0 -1
- package/dist/core/mcp/index.js.map +0 -1
- package/dist/core/mcp/server.d.ts.map +0 -1
- package/dist/core/mcp/server.js.map +0 -1
- package/dist/core/mcp/standalone-server.d.ts.map +0 -1
- package/dist/core/mcp/standalone-server.js.map +0 -1
- package/dist/core/mcp/tools.d.ts.map +0 -1
- package/dist/core/mcp/tools.js.map +0 -1
- package/dist/core/mcp/types.d.ts.map +0 -1
- package/dist/core/mcp/types.js.map +0 -1
- package/dist/core/memory/bridge-discovery.d.ts.map +0 -1
- package/dist/core/memory/bridge-discovery.js.map +0 -1
- package/dist/core/memory/categorizer.d.ts.map +0 -1
- package/dist/core/memory/categorizer.js.map +0 -1
- package/dist/core/memory/conflict-detector.d.ts.map +0 -1
- package/dist/core/memory/conflict-detector.js.map +0 -1
- package/dist/core/memory/consolidation.d.ts.map +0 -1
- package/dist/core/memory/consolidation.js.map +0 -1
- package/dist/core/memory/context-collector.d.ts.map +0 -1
- package/dist/core/memory/context-collector.js.map +0 -1
- package/dist/core/memory/contradiction-resolver.d.ts.map +0 -1
- package/dist/core/memory/contradiction-resolver.js.map +0 -1
- package/dist/core/memory/edit-workflow.d.ts.map +0 -1
- package/dist/core/memory/edit-workflow.js.map +0 -1
- package/dist/core/memory/entity-extractor.d.ts.map +0 -1
- package/dist/core/memory/entity-extractor.js.map +0 -1
- package/dist/core/memory/entity-resolver.d.ts.map +0 -1
- package/dist/core/memory/entity-resolver.js.map +0 -1
- package/dist/core/memory/fact-extractor.d.ts.map +0 -1
- package/dist/core/memory/fact-extractor.js.map +0 -1
- package/dist/core/memory/feedback-tracker.d.ts.map +0 -1
- package/dist/core/memory/feedback-tracker.js.map +0 -1
- package/dist/core/memory/hybrid-retrieval.d.ts.map +0 -1
- package/dist/core/memory/hybrid-retrieval.js.map +0 -1
- package/dist/core/memory/hybrid-scorer.d.ts.map +0 -1
- package/dist/core/memory/hybrid-scorer.js.map +0 -1
- package/dist/core/memory/hybrid-search.d.ts.map +0 -1
- package/dist/core/memory/hybrid-search.js.map +0 -1
- package/dist/core/memory/importance.d.ts.map +0 -1
- package/dist/core/memory/importance.js.map +0 -1
- package/dist/core/memory/index.d.ts.map +0 -1
- package/dist/core/memory/index.js.map +0 -1
- package/dist/core/memory/memories.d.ts.map +0 -1
- package/dist/core/memory/memories.js.map +0 -1
- package/dist/core/memory/memory-manager.d.ts.map +0 -1
- package/dist/core/memory/memory-manager.js.map +0 -1
- package/dist/core/memory/progressive-disclosure.d.ts.map +0 -1
- package/dist/core/memory/progressive-disclosure.js.map +0 -1
- package/dist/core/memory/query-processor.d.ts.map +0 -1
- package/dist/core/memory/query-processor.js.map +0 -1
- package/dist/core/memory/query-rewriter.d.ts.map +0 -1
- package/dist/core/memory/query-rewriter.js.map +0 -1
- package/dist/core/memory/response-analyzer.d.ts.map +0 -1
- package/dist/core/memory/response-analyzer.js.map +0 -1
- package/dist/core/memory/serialization.d.ts.map +0 -1
- package/dist/core/memory/serialization.js.map +0 -1
- package/dist/core/memory/stats.d.ts.map +0 -1
- package/dist/core/memory/stats.js.map +0 -1
- package/dist/core/memory/telemetry.d.ts.map +0 -1
- package/dist/core/memory/telemetry.js.map +0 -1
- package/dist/core/memory/temporal-facts.d.ts.map +0 -1
- package/dist/core/memory/temporal-facts.js.map +0 -1
- package/dist/core/memory/temporal-parser.d.ts.map +0 -1
- package/dist/core/memory/temporal-parser.js.map +0 -1
- package/dist/core/memory/trigger-detector.d.ts.map +0 -1
- package/dist/core/memory/trigger-detector.js.map +0 -1
- package/dist/core/memory/write-gate.d.ts.map +0 -1
- package/dist/core/memory/write-gate.js.map +0 -1
- package/dist/core/namespaces/index.d.ts.map +0 -1
- package/dist/core/namespaces/index.js.map +0 -1
- package/dist/core/namespaces/uri-parser.d.ts.map +0 -1
- package/dist/core/namespaces/uri-parser.js.map +0 -1
- package/dist/core/observations.d.ts.map +0 -1
- package/dist/core/observations.js.map +0 -1
- package/dist/core/privacy.d.ts.map +0 -1
- package/dist/core/privacy.js.map +0 -1
- package/dist/core/projects.d.ts.map +0 -1
- package/dist/core/projects.js.map +0 -1
- package/dist/core/redis.d.ts.map +0 -1
- package/dist/core/redis.js.map +0 -1
- package/dist/core/requirements.d.ts.map +0 -1
- package/dist/core/requirements.js.map +0 -1
- package/dist/core/scheduler/cron-scheduler.d.ts.map +0 -1
- package/dist/core/scheduler/cron-scheduler.js.map +0 -1
- package/dist/core/scheduler/heartbeat.d.ts.map +0 -1
- package/dist/core/scheduler/heartbeat.js.map +0 -1
- package/dist/core/scheduler/index.d.ts.map +0 -1
- package/dist/core/scheduler/index.js.map +0 -1
- package/dist/core/scheduler/job-runner.d.ts.map +0 -1
- package/dist/core/scheduler/job-runner.js.map +0 -1
- package/dist/core/search/conversations.d.ts.map +0 -1
- package/dist/core/search/conversations.js.map +0 -1
- package/dist/core/search/entities.d.ts.map +0 -1
- package/dist/core/search/entities.js.map +0 -1
- package/dist/core/search/folder-context.d.ts.map +0 -1
- package/dist/core/search/folder-context.js.map +0 -1
- package/dist/core/search/index.d.ts.map +0 -1
- package/dist/core/search/index.js.map +0 -1
- package/dist/core/search/qmd-search.d.ts.map +0 -1
- package/dist/core/search/qmd-search.js.map +0 -1
- package/dist/core/secret-detector.d.ts.map +0 -1
- package/dist/core/secret-detector.js.map +0 -1
- package/dist/core/session/auto-load.d.ts.map +0 -1
- package/dist/core/session/auto-load.js.map +0 -1
- package/dist/core/session/index.d.ts.map +0 -1
- package/dist/core/session/index.js.map +0 -1
- package/dist/core/session/types.d.ts.map +0 -1
- package/dist/core/session/types.js.map +0 -1
- package/dist/core/session-hooks/self-iteration-job.d.ts.map +0 -1
- package/dist/core/session-hooks/self-iteration-job.js.map +0 -1
- package/dist/core/session-hooks/session-hooks.d.ts.map +0 -1
- package/dist/core/session-hooks/session-hooks.js.map +0 -1
- package/dist/core/snapshots/cleanup.d.ts.map +0 -1
- package/dist/core/snapshots/cleanup.js.map +0 -1
- package/dist/core/snapshots/comparison.d.ts.map +0 -1
- package/dist/core/snapshots/comparison.js.map +0 -1
- package/dist/core/snapshots/creation.d.ts.map +0 -1
- package/dist/core/snapshots/creation.js.map +0 -1
- package/dist/core/snapshots/retrieval.d.ts.map +0 -1
- package/dist/core/snapshots/retrieval.js.map +0 -1
- package/dist/core/snapshots/stats.d.ts.map +0 -1
- package/dist/core/snapshots/stats.js.map +0 -1
- package/dist/core/snapshots.d.ts.map +0 -1
- package/dist/core/snapshots.js.map +0 -1
- package/dist/core/summarization/cleanup.d.ts.map +0 -1
- package/dist/core/summarization/cleanup.js.map +0 -1
- package/dist/core/summarization/queries.d.ts.map +0 -1
- package/dist/core/summarization/queries.js.map +0 -1
- package/dist/core/summarization/stats.d.ts.map +0 -1
- package/dist/core/summarization/stats.js.map +0 -1
- package/dist/core/summarization/strategies.d.ts.map +0 -1
- package/dist/core/summarization/strategies.js.map +0 -1
- package/dist/core/summarization.d.ts.map +0 -1
- package/dist/core/summarization.js.map +0 -1
- package/dist/core/sync/qmd-sync.d.ts.map +0 -1
- package/dist/core/sync/qmd-sync.js.map +0 -1
- package/dist/core/temporal-facts.d.ts.map +0 -1
- package/dist/core/temporal-facts.js.map +0 -1
- package/dist/core/tracing/collector.d.ts.map +0 -1
- package/dist/core/tracing/collector.js.map +0 -1
- package/dist/core/tracing/visualizer.d.ts.map +0 -1
- package/dist/core/tracing/visualizer.js.map +0 -1
- package/dist/core/utils/cleanup-operations.d.ts.map +0 -1
- package/dist/core/utils/cleanup-operations.js.map +0 -1
- package/dist/core/utils/content-extraction.d.ts.map +0 -1
- package/dist/core/utils/content-extraction.js.map +0 -1
- package/dist/core/utils/filter-builder.d.ts.map +0 -1
- package/dist/core/utils/filter-builder.js.map +0 -1
- package/dist/core/utils/history-traversal.d.ts.map +0 -1
- package/dist/core/utils/history-traversal.js.map +0 -1
- package/dist/core/utils/memory-operations.d.ts.map +0 -1
- package/dist/core/utils/memory-operations.js.map +0 -1
- package/dist/core/utils/query-operations.d.ts.map +0 -1
- package/dist/core/utils/query-operations.js.map +0 -1
- package/dist/core/utils/summarization-helpers.d.ts.map +0 -1
- package/dist/core/utils/summarization-helpers.js.map +0 -1
- package/dist/core/utils/temporal-queries.d.ts.map +0 -1
- package/dist/core/utils/temporal-queries.js.map +0 -1
- package/dist/core/utils/version-management.d.ts.map +0 -1
- package/dist/core/utils/version-management.js.map +0 -1
- package/dist/core/utils.d.ts.map +0 -1
- package/dist/core/utils.js.map +0 -1
- package/dist/core/worker.d.ts.map +0 -1
- package/dist/core/worker.js.map +0 -1
- package/dist/db/adapter.d.ts.map +0 -1
- package/dist/db/adapter.js.map +0 -1
- package/dist/db/bootstrap.d.ts.map +0 -1
- package/dist/db/bootstrap.js.map +0 -1
- package/dist/db/index.d.ts.map +0 -1
- package/dist/db/index.js.map +0 -1
- package/dist/db/schema.d.ts.map +0 -1
- package/dist/db/schema.js.map +0 -1
- package/dist/drizzle/schema-sqlite.d.ts.map +0 -1
- package/dist/drizzle/schema-sqlite.js.map +0 -1
- package/dist/drizzle/schema.d.ts.map +0 -1
- package/dist/drizzle/schema.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/packages/plugin-claude-code/dist/plugin-wrapper.d.ts.map +0 -1
- package/packages/plugin-claude-code/dist/plugin-wrapper.js.map +0 -1
- package/packages/plugin-openclaw/dist/index.d.ts.map +0 -1
- package/packages/plugin-openclaw/dist/index.js.map +0 -1
package/.env.mcp.example
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
SQUISH_MCP_PORT=8767
|
|
3
3
|
SQUISH_MCP_SERVER_ENABLED=true
|
|
4
4
|
|
|
5
|
+
# CORS Configuration (comma-separated origins, * wildcard for port)
|
|
6
|
+
# Default: localhost and 127.0.0.1 on any port
|
|
7
|
+
# SQUISH_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:8080
|
|
8
|
+
|
|
5
9
|
# Embeddings Provider: local | openai | ollama | google | none | auto
|
|
6
10
|
# Default: local (TF-IDF, no API needed)
|
|
7
11
|
SQUISH_EMBEDDINGS_PROVIDER=local
|
package/README.md
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
# Squish - Universal Two-Tier Memory for AI Agents
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/squish-memory)
|
|
4
|
+
[](https://www.npmjs.com/package/squish-memory)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
|
|
3
8
|
**Squish gives any AI agent persistent, intelligent memory through a two-tier architecture.** Without memory, agents forget everything between sessions. With Squish, they learn, adapt, and get smarter over time - regardless of which agent framework you use.
|
|
4
9
|
|
|
5
10
|
```bash
|
|
6
11
|
npm install squish-memory
|
|
7
12
|
```
|
|
8
13
|
|
|
14
|
+
**Works out-of-the-box.** No database setup required - local TF-IDF embeddings work instantly. Upgrade to vector search with OpenAI/Ollama when ready.
|
|
15
|
+
|
|
9
16
|
## Why Agents Need Memory
|
|
10
17
|
|
|
11
18
|
| Without Squish | With Squish |
|
|
@@ -18,8 +25,8 @@ npm install squish-memory
|
|
|
18
25
|
## How It Works
|
|
19
26
|
|
|
20
27
|
Squish uses a two-tier memory architecture for optimal performance:
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
28
|
+
- **Short-term Memory (QMD)**: Lightning-fast file-based search using QMD (BM25 + vector). Instant recall, optimized for recent/active context.
|
|
29
|
+
- **Long-term Memory (Database)**: SQLite (local) or PostgreSQL (team) for durable, searchable storage of important memories.
|
|
23
30
|
|
|
24
31
|
```
|
|
25
32
|
Agent Action -----> [Squish Memory Layer]
|
|
@@ -35,19 +42,18 @@ Agent Action -----> [Squish Memory Layer]
|
|
|
35
42
|
│ Write Gate │ <-- Validate, sanitize, score
|
|
36
43
|
└──────────────┘
|
|
37
44
|
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
└─────────────────────┘
|
|
45
|
+
┌───────────────┴───────────────┐
|
|
46
|
+
v v
|
|
47
|
+
┌──────────────┐ ┌──────────────┐
|
|
48
|
+
│ Short-term │ │ Long-term │
|
|
49
|
+
│ QMD (Files) │ │ SQLite/PG │
|
|
50
|
+
│ Fast recall │ │ Persistent │
|
|
51
|
+
└──────────────┘ └──────────────┘
|
|
52
|
+
| |
|
|
53
|
+
v v
|
|
54
|
+
┌──────────────────────────────────────────┐
|
|
55
|
+
│ Hybrid Retrieval: QMD + Vector Ranking │
|
|
56
|
+
└──────────────────────────────────────────┘
|
|
51
57
|
|
|
|
52
58
|
v
|
|
53
59
|
Agent Context
|
|
@@ -73,6 +79,18 @@ Agent Action -----> [Squish Memory Layer]
|
|
|
73
79
|
|
|
74
80
|
## Quick Start
|
|
75
81
|
|
|
82
|
+
### Simple Example
|
|
83
|
+
```bash
|
|
84
|
+
# Store a memory
|
|
85
|
+
squish remember "User prefers TypeScript"
|
|
86
|
+
|
|
87
|
+
# Search memories
|
|
88
|
+
squish search "preferences"
|
|
89
|
+
|
|
90
|
+
# Check health
|
|
91
|
+
squish health
|
|
92
|
+
```
|
|
93
|
+
|
|
76
94
|
### Universal Plugin Installer (Recommended)
|
|
77
95
|
```bash
|
|
78
96
|
# Install for your AI assistant(s)
|
|
@@ -288,8 +306,8 @@ DATABASE_URL=postgresql://user:pass@host/db
|
|
|
288
306
|
|
|
289
307
|
### Two-Tier Memory System
|
|
290
308
|
Squish employs a two-tier architecture for optimal performance and reliability:
|
|
291
|
-
- **
|
|
292
|
-
- **
|
|
309
|
+
- **Short-term (QMD)**: File-based search using QMD (BM25 + vectors). Ultra-fast for recent context and active memories.
|
|
310
|
+
- **Long-term (Database)**: SQLite (local) or PostgreSQL (team). Durable ACID-compliant storage for important memories that need persistence.
|
|
293
311
|
|
|
294
312
|
### Universal Interfaces
|
|
295
313
|
- **MCP Server**: Native integration for Claude Code, OpenClaw, and any MCP-compatible agent
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "squish-memory",
|
|
3
3
|
"name": "Squish Memory",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"description": "Universal two-tier memory system for AI agents with hybrid search, core memory, and MCP-first architecture",
|
|
6
6
|
"capabilities": ["mcp", "cli", "web"],
|
|
7
7
|
"targets": {
|
package/dist/api/web/web.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import cors from 'cors';
|
|
3
|
+
import rateLimit from 'express-rate-limit';
|
|
3
4
|
import { logger } from '../../core/logger.js';
|
|
4
5
|
import { getRecentMemories } from '../../core/memory/memories.js';
|
|
5
6
|
import { getObservationsForProject } from '../../core/observations.js';
|
|
@@ -7,7 +8,32 @@ import { getAllProjects, getProjectByPath } from '../../core/projects.js';
|
|
|
7
8
|
import { getDb } from '../../db/index.js';
|
|
8
9
|
const app = express();
|
|
9
10
|
const PORT = process.env.SQUISH_WEB_PORT || 37777;
|
|
10
|
-
|
|
11
|
+
const allowedOrigins = process.env.SQUISH_CORS_ORIGINS?.split(',').map(s => s.trim()) || ['http://localhost:*', 'http://127.0.0.1:*'];
|
|
12
|
+
const appCors = cors({
|
|
13
|
+
origin: (origin, callback) => {
|
|
14
|
+
if (!origin || allowedOrigins.some(allowed => {
|
|
15
|
+
if (allowed.endsWith(':*')) {
|
|
16
|
+
const prefix = allowed.slice(0, -1);
|
|
17
|
+
return origin.startsWith(prefix);
|
|
18
|
+
}
|
|
19
|
+
return origin === allowed;
|
|
20
|
+
})) {
|
|
21
|
+
callback(null, true);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
callback(new Error('Not allowed by CORS'));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const limiter = rateLimit({
|
|
29
|
+
windowMs: 15 * 60 * 1000,
|
|
30
|
+
max: 100,
|
|
31
|
+
message: { error: 'Too many requests, please try again later.' },
|
|
32
|
+
standardHeaders: true,
|
|
33
|
+
legacyHeaders: false,
|
|
34
|
+
});
|
|
35
|
+
app.use(appCors);
|
|
36
|
+
app.use(limiter);
|
|
11
37
|
app.use(express.json());
|
|
12
38
|
// Health check endpoint
|
|
13
39
|
app.get('/api/health', async (req, res) => {
|
|
@@ -21,7 +21,7 @@ import { getDb } from "../db/index.js";
|
|
|
21
21
|
import { getSchema } from "../db/schema.js";
|
|
22
22
|
import { eq } from "drizzle-orm";
|
|
23
23
|
const SERVER_NAME = "squish-memory";
|
|
24
|
-
const SERVER_VERSION = "1.0.
|
|
24
|
+
const SERVER_VERSION = "1.0.2";
|
|
25
25
|
function parseArgs() {
|
|
26
26
|
const args = process.argv.slice(2);
|
|
27
27
|
let mode = "stdio";
|
package/dist/core/mcp/server.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import cors from 'cors';
|
|
3
|
+
import rateLimit from 'express-rate-limit';
|
|
3
4
|
import { logger } from '../logger.js';
|
|
4
5
|
export class MCPServer {
|
|
5
6
|
app = express();
|
|
@@ -16,7 +17,32 @@ export class MCPServer {
|
|
|
16
17
|
this.setupRoutes();
|
|
17
18
|
}
|
|
18
19
|
setupMiddleware() {
|
|
19
|
-
|
|
20
|
+
const allowedOrigins = process.env.SQUISH_CORS_ORIGINS?.split(',').map(s => s.trim()) || ['http://localhost:*', 'http://127.0.0.1:*'];
|
|
21
|
+
const appCors = cors({
|
|
22
|
+
origin: (origin, callback) => {
|
|
23
|
+
if (!origin || allowedOrigins.some(allowed => {
|
|
24
|
+
if (allowed.endsWith(':*')) {
|
|
25
|
+
const prefix = allowed.slice(0, -1);
|
|
26
|
+
return origin.startsWith(prefix);
|
|
27
|
+
}
|
|
28
|
+
return origin === allowed;
|
|
29
|
+
})) {
|
|
30
|
+
callback(null, true);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
callback(new Error('Not allowed by CORS'));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const limiter = rateLimit({
|
|
38
|
+
windowMs: 15 * 60 * 1000,
|
|
39
|
+
max: 100,
|
|
40
|
+
message: { error: 'Too many requests, please try again later.' },
|
|
41
|
+
standardHeaders: true,
|
|
42
|
+
legacyHeaders: false,
|
|
43
|
+
});
|
|
44
|
+
this.app.use(appCors);
|
|
45
|
+
this.app.use(limiter);
|
|
20
46
|
this.app.use(express.json());
|
|
21
47
|
}
|
|
22
48
|
setupRoutes() {
|
package/dist/core/mcp/types.d.ts
CHANGED
|
@@ -30,29 +30,29 @@ export declare const MCPToolResultSchema: z.ZodObject<{
|
|
|
30
30
|
mimeType: z.ZodOptional<z.ZodString>;
|
|
31
31
|
}, "strip", z.ZodTypeAny, {
|
|
32
32
|
type: "text" | "image" | "resource";
|
|
33
|
-
data?: string | undefined;
|
|
34
33
|
text?: string | undefined;
|
|
34
|
+
data?: string | undefined;
|
|
35
35
|
mimeType?: string | undefined;
|
|
36
36
|
}, {
|
|
37
37
|
type: "text" | "image" | "resource";
|
|
38
|
-
data?: string | undefined;
|
|
39
38
|
text?: string | undefined;
|
|
39
|
+
data?: string | undefined;
|
|
40
40
|
mimeType?: string | undefined;
|
|
41
41
|
}>, "many">;
|
|
42
42
|
isError: z.ZodOptional<z.ZodBoolean>;
|
|
43
43
|
}, "strip", z.ZodTypeAny, {
|
|
44
44
|
content: {
|
|
45
45
|
type: "text" | "image" | "resource";
|
|
46
|
-
data?: string | undefined;
|
|
47
46
|
text?: string | undefined;
|
|
47
|
+
data?: string | undefined;
|
|
48
48
|
mimeType?: string | undefined;
|
|
49
49
|
}[];
|
|
50
50
|
isError?: boolean | undefined;
|
|
51
51
|
}, {
|
|
52
52
|
content: {
|
|
53
53
|
type: "text" | "image" | "resource";
|
|
54
|
-
data?: string | undefined;
|
|
55
54
|
text?: string | undefined;
|
|
55
|
+
data?: string | undefined;
|
|
56
56
|
mimeType?: string | undefined;
|
|
57
57
|
}[];
|
|
58
58
|
isError?: boolean | undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { eq } from 'drizzle-orm';
|
|
3
3
|
import { getDb } from '../../db/index.js';
|
|
4
4
|
import { getSchema } from '../../db/schema.js';
|
|
5
5
|
import { config } from '../../config.js';
|
|
@@ -143,14 +143,17 @@ export async function getMemoryById(id, incrementAccess = true) {
|
|
|
143
143
|
export async function getRecentMemories(projectPath, limit) {
|
|
144
144
|
try {
|
|
145
145
|
const db = createDatabaseClient(await getDb());
|
|
146
|
-
const
|
|
146
|
+
const sqlite = db.$client;
|
|
147
147
|
const project = await getProjectByPath(projectPath);
|
|
148
148
|
if (!project)
|
|
149
149
|
return [];
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
// Use raw SQL to avoid drizzle column name issues
|
|
151
|
+
const rows = sqlite.prepare(`
|
|
152
|
+
SELECT * FROM memories
|
|
153
|
+
WHERE project_id = ?
|
|
154
|
+
ORDER BY created_at DESC
|
|
155
|
+
LIMIT ?
|
|
156
|
+
`).all(project.id, limit);
|
|
154
157
|
return rows.map((row) => normalizeMemory(row));
|
|
155
158
|
}
|
|
156
159
|
catch (error) {
|
|
@@ -65,18 +65,61 @@ async function ensureDefaultJobs(db) {
|
|
|
65
65
|
},
|
|
66
66
|
];
|
|
67
67
|
for (const job of defaultJobs) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
let existing;
|
|
69
|
+
try {
|
|
70
|
+
existing = await db
|
|
71
|
+
.select()
|
|
72
|
+
.from(maintenanceJobs)
|
|
73
|
+
.where(eq(maintenanceJobs.jobName, job.jobName))
|
|
74
|
+
.limit(1);
|
|
75
|
+
}
|
|
76
|
+
catch (queryError) {
|
|
77
|
+
logger.error(`[Scheduler] Query failed for job ${job.jobName}:`, queryError.message);
|
|
78
|
+
// Try raw SQL fallback
|
|
79
|
+
try {
|
|
80
|
+
const rawDb = db.$client;
|
|
81
|
+
if (rawDb && typeof rawDb.prepare === 'function') {
|
|
82
|
+
existing = rawDb.prepare('SELECT * FROM maintenance_jobs WHERE job_name = ?').all(job.jobName);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (fallbackError) {
|
|
86
|
+
logger.error(`[Scheduler] Fallback query also failed:`, fallbackError.message);
|
|
87
|
+
throw queryError;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
73
90
|
if (existing.length === 0) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
91
|
+
try {
|
|
92
|
+
await db.insert(maintenanceJobs).values({
|
|
93
|
+
jobName: job.jobName,
|
|
94
|
+
jobType: job.jobType,
|
|
95
|
+
cronExpression: job.cronExpression,
|
|
96
|
+
enabled: job.enabled,
|
|
97
|
+
jobConfig: job.jobConfig,
|
|
98
|
+
totalRuns: 0,
|
|
99
|
+
successCount: 0,
|
|
100
|
+
failureCount: 0,
|
|
101
|
+
lastRunAt: null,
|
|
102
|
+
nextRunAt: null,
|
|
103
|
+
lastRunDuration: null,
|
|
104
|
+
lastRunStatus: null,
|
|
105
|
+
lastRunError: null,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (insertError) {
|
|
109
|
+
// Fallback to raw SQL if drizzle insert fails
|
|
110
|
+
logger.warn(`[Scheduler] Drizzle insert failed, using raw SQL: ${insertError.message}`);
|
|
111
|
+
const rawDb = db.$client;
|
|
112
|
+
if (rawDb && typeof rawDb.prepare === 'function') {
|
|
113
|
+
const stmt = rawDb.prepare(`
|
|
114
|
+
INSERT INTO maintenance_jobs
|
|
115
|
+
(id, job_name, job_type, cron_expression, enabled, job_config,
|
|
116
|
+
total_runs, success_count, failure_count, last_run_at, next_run_at,
|
|
117
|
+
last_run_duration, last_run_status, last_run_error)
|
|
118
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
119
|
+
`);
|
|
120
|
+
stmt.run(crypto.randomUUID(), job.jobName, job.jobType, job.cronExpression, job.enabled ? 1 : 0, JSON.stringify(job.jobConfig), 0, 0, 0, null, null, null, null, null);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
80
123
|
logger.info(`[Scheduler] Created default job: ${job.jobName}`);
|
|
81
124
|
// Register self-iteration handler
|
|
82
125
|
if (job.jobName === 'self_iteration') {
|
|
@@ -115,7 +158,7 @@ export async function scheduleJob(job) {
|
|
|
115
158
|
.set({ nextRunAt: nextRun })
|
|
116
159
|
.where(eq(maintenanceJobs.id, job.id));
|
|
117
160
|
}
|
|
118
|
-
logger.info(`[Scheduler] Scheduled ${job.jobName} with cron: ${job.cronExpression}
|
|
161
|
+
logger.info(`[Scheduler] Scheduled ${job.jobName} with cron: ${job.cronExpression}${nextRun ? `, next run: ${nextRun.toISOString()}` : ''}`);
|
|
119
162
|
}
|
|
120
163
|
export async function executeJob(job) {
|
|
121
164
|
const db = await getDb();
|
|
@@ -183,13 +226,23 @@ function getNextRunTime(cronExpression) {
|
|
|
183
226
|
try {
|
|
184
227
|
const now = new Date();
|
|
185
228
|
const parts = cronExpression.split(' ');
|
|
186
|
-
|
|
229
|
+
// Daily jobs: MM HH * * *
|
|
230
|
+
if (parts[2] === '*' && parts[3] === '*' && parts[4] === '*' && parts[1] !== '*') {
|
|
187
231
|
const next = new Date(now);
|
|
188
232
|
next.setHours(parseInt(parts[1]), parseInt(parts[0]), 0, 0);
|
|
189
233
|
if (next <= now)
|
|
190
234
|
next.setDate(next.getDate() + 1);
|
|
191
235
|
return next;
|
|
192
236
|
}
|
|
237
|
+
// Hourly jobs: MM * * * *
|
|
238
|
+
if (parts[1] === '*' && parts[2] === '*' && parts[3] === '*' && parts[4] === '*') {
|
|
239
|
+
const next = new Date(now);
|
|
240
|
+
next.setMinutes(parseInt(parts[0]), 0, 0);
|
|
241
|
+
if (next <= now)
|
|
242
|
+
next.setHours(next.getHours() + 1);
|
|
243
|
+
return next;
|
|
244
|
+
}
|
|
245
|
+
// Weekly jobs: MM HH * * D
|
|
193
246
|
if (parts[4] !== '*') {
|
|
194
247
|
const dayOfWeek = parseInt(parts[4]);
|
|
195
248
|
const next = new Date(now);
|
package/dist/db/adapter.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { config, getDataDir } from '../config.js';
|
|
2
2
|
import { ensurePostgresSchema, ensureSqliteSchema } from './bootstrap.js';
|
|
3
3
|
import { logger } from '../core/logger.js';
|
|
4
|
+
async function createBunSqliteDb(dbPath) {
|
|
5
|
+
// @ts-ignore - bun:sqlite module not found in types but works at runtime
|
|
6
|
+
const { drizzle } = await import('drizzle-orm/bun-sqlite');
|
|
7
|
+
const schemaModule = await import('../drizzle/schema-sqlite.js');
|
|
8
|
+
// Bun SQLite doesn't need file path for in-memory, but we'll use file path for persistence
|
|
9
|
+
// @ts-ignore - bun:sqlite module not found in types but works at runtime
|
|
10
|
+
const sqlite = new (await import('bun:sqlite')).default(dbPath);
|
|
11
|
+
// Enable foreign keys
|
|
12
|
+
sqlite.exec('PRAGMA foreign_keys = ON');
|
|
13
|
+
await ensureSqliteSchema(sqlite);
|
|
14
|
+
logger.info('SQLite initialized with bun:sqlite');
|
|
15
|
+
return drizzle(sqlite, { schema: schemaModule });
|
|
16
|
+
}
|
|
4
17
|
export async function createDb() {
|
|
5
18
|
if (config.isTeamMode) {
|
|
6
19
|
return createPostgresDb();
|
|
@@ -22,31 +35,41 @@ async function createPostgresDb() {
|
|
|
22
35
|
}
|
|
23
36
|
async function createSqliteDb() {
|
|
24
37
|
const dbPath = `${getDataDir()}/squish.db`;
|
|
25
|
-
// Try
|
|
38
|
+
// Try bun:sqlite first (Bun's built-in SQLite)
|
|
26
39
|
try {
|
|
27
|
-
return await
|
|
40
|
+
return await createBunSqliteDb(dbPath);
|
|
28
41
|
}
|
|
29
|
-
catch (
|
|
30
|
-
logger.warn('
|
|
31
|
-
error:
|
|
42
|
+
catch (bunSqliteError) {
|
|
43
|
+
logger.warn('bun:sqlite failed, trying better-sqlite3', {
|
|
44
|
+
error: bunSqliteError.message
|
|
32
45
|
});
|
|
33
|
-
//
|
|
46
|
+
// Try better-sqlite3 second (best performance)
|
|
34
47
|
try {
|
|
35
|
-
return await
|
|
48
|
+
return await createBetterSqliteDb(dbPath);
|
|
36
49
|
}
|
|
37
|
-
catch (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
betterSqliteError: betterSqliteError.message,
|
|
41
|
-
sqlJsError: sqlJsError.message
|
|
50
|
+
catch (betterSqliteError) {
|
|
51
|
+
logger.warn('better-sqlite3 failed, trying sql.js fallback', {
|
|
52
|
+
error: betterSqliteError.message
|
|
42
53
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
// Fallback to sql.js (pure JavaScript, no native module)
|
|
55
|
+
try {
|
|
56
|
+
return await createSqlJsDb(dbPath);
|
|
57
|
+
}
|
|
58
|
+
catch (sqlJsError) {
|
|
59
|
+
// All failed - this is critical, Squish cannot work without DB
|
|
60
|
+
logger.error('CRITICAL: SQLite database initialization failed', {
|
|
61
|
+
bunSqliteError: bunSqliteError.message,
|
|
62
|
+
betterSqliteError: betterSqliteError.message,
|
|
63
|
+
sqlJsError: sqlJsError.message
|
|
64
|
+
});
|
|
65
|
+
throw new Error(`Squish requires SQLite to function. Database initialization failed.\n` +
|
|
66
|
+
`Primary error (bun:sqlite): ${bunSqliteError.message}\n` +
|
|
67
|
+
`Secondary error (better-sqlite3): ${betterSqliteError.message}\n` +
|
|
68
|
+
`Fallback error (sql.js): ${sqlJsError.message}\n\n` +
|
|
69
|
+
`Solutions:\n` +
|
|
70
|
+
`1. Install build tools: npm install -g windows-build-tools (Windows)\n` +
|
|
71
|
+
`2. Or use PostgreSQL instead by setting DATABASE_URL environment variable`);
|
|
72
|
+
}
|
|
50
73
|
}
|
|
51
74
|
}
|
|
52
75
|
}
|
|
@@ -77,7 +100,7 @@ async function createSqlJsDb(dbPath) {
|
|
|
77
100
|
}
|
|
78
101
|
const sqlite = new SQL.Database(data);
|
|
79
102
|
// Enable foreign keys
|
|
80
|
-
sqlite.
|
|
103
|
+
sqlite.exec('PRAGMA foreign_keys = ON');
|
|
81
104
|
// Schema bootstrap
|
|
82
105
|
await ensureSqliteSchema(sqlite);
|
|
83
106
|
// Persist database on changes (sql.js is in-memory by default)
|
|
@@ -89,6 +112,51 @@ async function createSqlJsDb(dbPath) {
|
|
|
89
112
|
fs.writeFileSync(dbPath, Buffer.from(data));
|
|
90
113
|
return result;
|
|
91
114
|
};
|
|
115
|
+
// Add prepare method for compatibility with drizzle-orm/sql-js
|
|
116
|
+
sqlite.prepare = (query) => {
|
|
117
|
+
const stmt = sqlite.prepare(query);
|
|
118
|
+
const preparedStatement = {};
|
|
119
|
+
preparedStatement.bind = (bindParams) => {
|
|
120
|
+
bindParams.forEach((param, index) => {
|
|
121
|
+
stmt.bind(param, index + 1);
|
|
122
|
+
});
|
|
123
|
+
return preparedStatement;
|
|
124
|
+
};
|
|
125
|
+
preparedStatement.step = () => {
|
|
126
|
+
return stmt.step();
|
|
127
|
+
};
|
|
128
|
+
preparedStatement.getAsObject = () => {
|
|
129
|
+
return stmt.getAsObject();
|
|
130
|
+
};
|
|
131
|
+
preparedStatement.free = () => {
|
|
132
|
+
stmt.free();
|
|
133
|
+
};
|
|
134
|
+
preparedStatement.run = () => {
|
|
135
|
+
const result = stmt.step() ? { changes: sqlite.changes() } : { changes: 0 };
|
|
136
|
+
stmt.reset();
|
|
137
|
+
return result;
|
|
138
|
+
};
|
|
139
|
+
preparedStatement.get = (bindParams = []) => {
|
|
140
|
+
if (bindParams.length > 0) {
|
|
141
|
+
preparedStatement.bind(bindParams);
|
|
142
|
+
}
|
|
143
|
+
const row = stmt.step() ? stmt.getAsObject() : undefined;
|
|
144
|
+
stmt.reset();
|
|
145
|
+
return row;
|
|
146
|
+
};
|
|
147
|
+
preparedStatement.all = (bindParams = []) => {
|
|
148
|
+
if (bindParams.length > 0) {
|
|
149
|
+
preparedStatement.bind(bindParams);
|
|
150
|
+
}
|
|
151
|
+
const rows = [];
|
|
152
|
+
while (stmt.step()) {
|
|
153
|
+
rows.push(stmt.getAsObject());
|
|
154
|
+
}
|
|
155
|
+
stmt.reset();
|
|
156
|
+
return rows;
|
|
157
|
+
};
|
|
158
|
+
return preparedStatement;
|
|
159
|
+
};
|
|
92
160
|
logger.info('SQLite initialized with sql.js (pure JavaScript fallback)');
|
|
93
161
|
return drizzle(sqlite, { schema: schemaModule });
|
|
94
162
|
}
|