squish-memory 1.0.2 → 1.1.5
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.example +130 -0
- package/CHANGELOG.md +55 -0
- package/README.md +150 -287
- package/config/hooks/claude-code-hooks.json +39 -0
- package/config/hooks/cursor-hooks.json +30 -0
- package/config/hooks/opencode-hooks.json +30 -0
- package/config/hooks/windsurf-hooks.json +30 -0
- package/config/mcp-mode-semantics.json +23 -21
- package/config/plugin-manifest.json +101 -152
- package/{plugin.json → config/plugin.json} +2 -2
- package/config/settings.json +52 -51
- package/{commands → core/commands}/init.md +39 -39
- package/dist/config.d.ts +28 -4
- package/dist/config.js +97 -29
- package/dist/core/adapters/config/claude-code.d.ts +45 -0
- package/dist/core/adapters/config/claude-code.js +113 -0
- package/dist/core/adapters/config/cursor.d.ts +26 -0
- package/dist/core/adapters/config/cursor.js +74 -0
- package/dist/core/adapters/config/opencode.d.ts +23 -0
- package/dist/core/adapters/config/opencode.js +73 -0
- package/dist/core/adapters/config/windsurf.d.ts +26 -0
- package/dist/core/adapters/config/windsurf.js +74 -0
- package/dist/core/adapters/index.d.ts +45 -0
- package/dist/core/adapters/index.js +84 -0
- package/dist/core/adapters/scripts/install-adapter.d.ts +19 -0
- package/dist/core/adapters/scripts/install-adapter.js +149 -0
- package/dist/core/adapters/timeline.d.ts +23 -0
- package/dist/core/adapters/timeline.js +88 -0
- package/dist/core/adapters/types.d.ts +157 -0
- package/dist/core/adapters/types.js +50 -0
- package/dist/{algorithms → core/algorithms}/analytics/token-estimator.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/analytics/token-estimator.js +3 -3
- package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.js +1 -1
- package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.js +7 -10
- package/dist/{algorithms → core/algorithms}/handlers/approve-merge.js +4 -4
- package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/get-stats.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/list-proposals.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/preview-merge.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/reject-merge.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.js +3 -3
- package/dist/core/algorithms/index.d.ts +21 -0
- package/dist/core/algorithms/index.js +26 -0
- package/dist/core/algorithms/operations/cache-maintenance.d.ts +12 -0
- package/dist/core/algorithms/operations/cache-maintenance.js +157 -0
- package/dist/{algorithms → core/algorithms}/safety/safety-checks.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.d.ts +19 -1
- package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.js +74 -123
- package/dist/core/algorithms/types.d.ts +133 -0
- package/dist/core/algorithms/types.js +5 -0
- package/dist/core/associations.d.ts +1 -2
- package/dist/core/associations.js +1 -2
- package/dist/core/autosave.d.ts +19 -0
- package/dist/core/autosave.js +16 -0
- package/dist/{commands → core/commands}/managed-sync.js +5 -5
- package/dist/core/commands/mcp-server.js +739 -0
- package/dist/core/context/agent-context.d.ts +106 -0
- package/dist/core/context/agent-context.js +274 -0
- package/dist/core/{context-paging.d.ts → context/context-paging.d.ts} +2 -12
- package/dist/core/{context-paging.js → context/context-paging.js} +19 -39
- package/dist/core/context/context-window.d.ts +40 -0
- package/dist/core/context/context-window.js +177 -0
- package/dist/core/context/context.js +22 -0
- package/dist/core/embeddings.d.ts +1 -1
- package/dist/core/embeddings.js +54 -2
- package/dist/core/error-handling.d.ts +63 -0
- package/dist/core/error-handling.js +173 -0
- package/dist/core/external-folder/index.d.ts +102 -0
- package/dist/core/external-folder/index.js +294 -0
- package/dist/core/hooks/agent-hooks.d.ts +74 -0
- package/dist/core/hooks/agent-hooks.js +244 -0
- package/dist/core/hooks/auto-tagger.d.ts +19 -0
- package/dist/core/hooks/auto-tagger.js +155 -0
- package/dist/core/hooks/capture-filter.d.ts +41 -0
- package/dist/core/hooks/capture-filter.js +128 -0
- package/dist/core/index.d.ts +6 -6
- package/dist/core/index.js +6 -6
- package/dist/core/{agent-memory.js → ingestion/agent-memory.js} +5 -7
- package/dist/core/{core-memory.js → ingestion/core-memory.js} +4 -4
- package/dist/core/ingestion/learnings.d.ts +57 -0
- package/dist/core/ingestion/learnings.js +202 -0
- package/dist/core/lib/db-client.d.ts +114 -0
- package/dist/core/lib/db-client.js +130 -0
- package/dist/core/lib/schemas.d.ts +129 -0
- package/dist/core/lib/schemas.js +87 -0
- package/dist/core/{utils.d.ts → lib/utils.d.ts} +1 -0
- package/dist/core/{utils.js → lib/utils.js} +31 -15
- package/dist/core/lib/validation.d.ts +38 -0
- package/dist/core/lib/validation.js +151 -0
- package/dist/core/lifecycle.d.ts +7 -0
- package/dist/core/lifecycle.js +140 -20
- package/dist/core/local-embeddings.d.ts +6 -1
- package/dist/core/local-embeddings.js +6 -15
- package/dist/core/logger.js +7 -1
- package/dist/core/mcp/tools.js +35 -3
- package/dist/core/memory/categorizer.js +1 -0
- package/dist/core/memory/conflict-detector.js +1 -1
- package/dist/core/memory/consolidation.d.ts +1 -10
- package/dist/core/memory/consolidation.js +2 -11
- package/dist/core/memory/context-collector.js +1 -1
- package/dist/core/memory/edit-workflow.js +1 -1
- package/dist/core/memory/entity-resolver.js +7 -7
- package/dist/core/memory/fact-extractor.js +12 -12
- package/dist/core/memory/feedback-tracker.js +1 -1
- package/dist/core/memory/hooks.d.ts +88 -0
- package/dist/core/memory/hooks.js +174 -0
- package/dist/core/memory/hybrid-retrieval.js +2 -2
- package/dist/core/memory/hybrid-search.d.ts +1 -6
- package/dist/core/memory/hybrid-search.js +70 -84
- package/dist/core/memory/importance.d.ts +8 -13
- package/dist/core/memory/importance.js +47 -74
- package/dist/core/memory/loader.d.ts +31 -0
- package/dist/core/memory/loader.js +141 -0
- package/dist/core/memory/markdown/markdown-storage.d.ts +72 -0
- package/dist/core/memory/markdown/markdown-storage.js +243 -0
- package/dist/core/memory/memories.d.ts +12 -4
- package/dist/core/memory/memories.js +192 -180
- package/dist/core/memory/memory-lifecycle.d.ts +8 -0
- package/dist/core/memory/memory-lifecycle.js +55 -0
- package/dist/core/memory/migrate.d.ts +21 -0
- package/dist/core/memory/migrate.js +134 -0
- package/dist/core/memory/normalization.d.ts +22 -0
- package/dist/core/memory/normalization.js +26 -0
- package/dist/core/memory/progressive-disclosure.js +1 -1
- package/dist/core/memory/query-rewriter.js +9 -9
- package/dist/core/memory/serialization.d.ts +4 -0
- package/dist/core/memory/serialization.js +49 -0
- package/dist/core/memory/stats.d.ts +5 -0
- package/dist/core/memory/stats.js +63 -12
- package/dist/core/memory/temporal-facts.js +21 -0
- package/dist/core/memory/write-gate.js +1 -1
- package/dist/core/obsidian-vault.d.ts +30 -0
- package/dist/core/obsidian-vault.js +94 -0
- package/dist/core/places/index.d.ts +14 -0
- package/dist/core/places/index.js +14 -0
- package/dist/core/places/memory-places.d.ts +68 -0
- package/dist/core/places/memory-places.js +261 -0
- package/dist/core/places/places.d.ts +88 -0
- package/dist/core/places/places.js +314 -0
- package/dist/core/places/rules.d.ts +74 -0
- package/dist/core/places/rules.js +240 -0
- package/dist/core/places/walking.d.ts +56 -0
- package/dist/core/places/walking.js +121 -0
- package/dist/core/projects.d.ts +5 -0
- package/dist/core/projects.js +39 -18
- package/dist/core/responses.d.ts +96 -0
- package/dist/core/responses.js +122 -0
- package/dist/core/scheduler/cron-scheduler.js +29 -7
- package/dist/core/scheduler/index.d.ts +1 -1
- package/dist/core/scheduler/index.js +1 -1
- package/dist/core/scheduler/job-runner.js +1 -1
- package/dist/core/search/conversations.js +40 -42
- package/dist/core/search/entities.js +6 -9
- package/dist/core/search/graph-boost.d.ts +7 -0
- package/dist/core/search/graph-boost.js +23 -0
- package/dist/core/search/qmd-search.js +4 -4
- package/dist/core/security/encrypt.d.ts +6 -0
- package/dist/core/security/encrypt.js +47 -0
- package/dist/core/{governance.d.ts → security/governance.d.ts} +6 -1
- package/dist/core/security/governance.js +79 -0
- package/dist/core/session/auto-load.js +6 -6
- package/dist/core/session/index.d.ts +1 -1
- package/dist/core/session/index.js +1 -1
- package/dist/core/session/self-iteration-job.d.ts +20 -0
- package/dist/core/session/self-iteration-job.js +282 -0
- package/dist/core/session/session-hooks.d.ts +18 -0
- package/dist/core/session/session-hooks.js +58 -0
- package/dist/core/session-hooks/self-iteration-job.js +35 -35
- package/dist/core/{cache.js → storage/cache.js} +2 -2
- package/dist/core/sync/qmd-sync.d.ts +1 -13
- package/dist/core/sync/qmd-sync.js +1 -13
- package/dist/core/toon.d.ts +43 -0
- package/dist/core/toon.js +160 -0
- package/dist/core/utils/memory-operations.js +1 -1
- package/dist/core/utils/vector-operations.d.ts +71 -0
- package/dist/core/utils/vector-operations.js +129 -0
- package/dist/db/adapter.d.ts +3 -3
- package/dist/db/adapter.js +99 -88
- package/dist/db/bootstrap.js +820 -522
- package/dist/{drizzle → db/drizzle}/schema-sqlite.d.ts +74 -25
- package/dist/{drizzle → db/drizzle}/schema-sqlite.js +91 -24
- package/dist/{drizzle → db/drizzle}/schema.d.ts +79 -32
- package/dist/{drizzle → db/drizzle}/schema.js +106 -35
- package/dist/db/drizzle.config.d.ts +3 -0
- package/dist/db/drizzle.config.js +12 -0
- package/dist/db/index.d.ts +1 -5
- package/dist/db/index.js +51 -8
- package/dist/db/neon.d.ts +8 -0
- package/dist/db/neon.js +20 -0
- package/dist/db/schema/index.d.ts +40 -0
- package/dist/db/schema/index.js +105 -0
- package/dist/db/schema/tables/context-sessions.d.ts +9 -0
- package/dist/db/schema/tables/context-sessions.js +37 -0
- package/dist/db/schema/tables/conversations.d.ts +9 -0
- package/dist/db/schema/tables/conversations.js +47 -0
- package/dist/db/schema/tables/core-memory.d.ts +9 -0
- package/dist/db/schema/tables/core-memory.js +41 -0
- package/dist/db/schema/tables/entities.d.ts +9 -0
- package/dist/db/schema/tables/entities.js +39 -0
- package/dist/db/schema/tables/entity-relations.d.ts +9 -0
- package/dist/db/schema/tables/entity-relations.js +31 -0
- package/dist/db/schema/tables/learnings.d.ts +9 -0
- package/dist/db/schema/tables/learnings.js +66 -0
- package/dist/db/schema/tables/memories.d.ts +9 -0
- package/dist/db/schema/tables/memories.js +161 -0
- package/dist/db/schema/tables/memory-associations.d.ts +9 -0
- package/dist/db/schema/tables/memory-associations.js +39 -0
- package/dist/db/schema/tables/memory-hash-cache.d.ts +9 -0
- package/dist/db/schema/tables/memory-hash-cache.js +29 -0
- package/dist/db/schema/tables/memory-merge-history.d.ts +9 -0
- package/dist/db/schema/tables/memory-merge-history.js +33 -0
- package/dist/db/schema/tables/memory-merge-proposals.d.ts +9 -0
- package/dist/db/schema/tables/memory-merge-proposals.js +39 -0
- package/dist/db/schema/tables/messages.d.ts +9 -0
- package/dist/db/schema/tables/messages.js +41 -0
- package/dist/db/schema/tables/namespaces.d.ts +9 -0
- package/dist/db/schema/tables/namespaces.js +37 -0
- package/dist/db/schema/tables/projects.d.ts +9 -0
- package/dist/db/schema/tables/projects.js +31 -0
- package/dist/db/schema/tables/users.d.ts +9 -0
- package/dist/db/schema/tables/users.js +27 -0
- package/dist/db/schema.d.ts +1 -1
- package/dist/db/schema.js +2 -2
- package/dist/db/supabase.d.ts +9 -0
- package/dist/db/supabase.js +24 -0
- package/dist/index.d.ts +2 -14
- package/dist/index.js +1320 -640
- package/dist/vendor/sql.js/sql-wasm.wasm +0 -0
- package/dist/webui/server.d.ts +5 -0
- package/dist/{api/web/web.js → webui/server.js} +511 -508
- package/generated/mcp/manifest.json +1 -1
- package/{.mcp.json → mcp.json.example} +1 -1
- package/package.json +159 -181
- package/scripts/README.md +60 -0
- package/scripts/copy-runtime-assets.mjs +26 -0
- package/scripts/generate-mcp.mjs +264 -264
- package/scripts/github-release.sh +4 -4
- package/scripts/install-claude-code.sh +85 -0
- package/scripts/install-cursor.sh +56 -0
- package/scripts/install-hooks.sh +73 -0
- package/scripts/install-interactive.mjs +357 -677
- package/scripts/install-opencode.sh +75 -0
- package/scripts/install-windsurf.sh +67 -0
- package/skills/squish-memory/SKILL.md +104 -114
- package/skills/squish-memory/{install.mjs → scripts/install.mjs} +2 -2
- package/skills/squish-memory/{install.sh → scripts/install.sh} +2 -2
- package/skills/squish-memory/write_skill.js +2 -0
- package/.claude-plugin/marketplace.json +0 -20
- package/.claude-plugin/plugin.json +0 -32
- package/.env.mcp.example +0 -60
- package/QUICK-START.md +0 -71
- package/bin/squish-add.mjs +0 -32
- package/bin/squish-rm.mjs +0 -21
- package/commands/observe.md +0 -5
- package/dist/api/web/index.d.ts +0 -3
- package/dist/api/web/index.js +0 -4
- package/dist/api/web/web-server.d.ts +0 -3
- package/dist/api/web/web-server.js +0 -6
- package/dist/api/web/web.d.ts +0 -4
- package/dist/commands/mcp-server.js +0 -393
- package/dist/core/context.js +0 -24
- package/dist/core/governance.js +0 -64
- package/dist/core/observations.d.ts +0 -26
- package/dist/core/observations.js +0 -110
- package/dist/core/requirements.d.ts +0 -20
- package/dist/core/requirements.js +0 -35
- package/hooks/hooks.json +0 -52
- package/hooks/post-tool-use.js +0 -26
- package/hooks/session-end.js +0 -28
- package/hooks/session-start.js +0 -33
- package/hooks/user-prompt-submit.js +0 -26
- package/hooks/utils.js +0 -153
- package/npx-installer.js +0 -208
- package/packages/plugin-claude-code/README.md +0 -73
- package/packages/plugin-claude-code/dist/plugin-wrapper.d.ts +0 -35
- package/packages/plugin-claude-code/dist/plugin-wrapper.js +0 -191
- package/packages/plugin-claude-code/package.json +0 -31
- package/packages/plugin-openclaw/README.md +0 -70
- package/packages/plugin-openclaw/dist/index.d.ts +0 -49
- package/packages/plugin-openclaw/dist/index.js +0 -262
- package/packages/plugin-openclaw/openclaw.plugin.json +0 -94
- package/packages/plugin-openclaw/package.json +0 -31
- package/packages/plugin-opencode/install.mjs +0 -217
- package/packages/plugin-opencode/package.json +0 -21
- package/scripts/db/check-db.mjs +0 -88
- package/scripts/db/fix-all-columns.mjs +0 -52
- package/scripts/db/fix-schema-all.mjs +0 -55
- package/scripts/db/fix-schema-full.mjs +0 -46
- package/scripts/db/fix-schema.mjs +0 -38
- package/scripts/db/init-db.mjs +0 -13
- package/scripts/db/recreate-db.mjs +0 -14
- package/scripts/install-mcp.mjs +0 -116
- package/scripts/install-web.sh +0 -120
- package/scripts/install.mjs +0 -340
- package/scripts/openclaw-bootstrap.mjs +0 -127
- package/scripts/package-release.sh +0 -71
- package/scripts/test/test-all-systems.mjs +0 -139
- package/scripts/test/test-memory-system.mjs +0 -139
- package/scripts/test/test-v0.5.0.mjs +0 -210
- package/skills/memory-guide/SKILL.md +0 -332
- package/skills/squish-cli/SKILL.md +0 -240
- package/skills/squish-mcp/SKILL.md +0 -355
- package/skills/squish-memory/claude-desktop.json +0 -12
- package/skills/squish-memory/openclaw.json +0 -13
- package/skills/squish-memory/opencode.json +0 -14
- package/skills/squish-memory/skill.json +0 -32
- /package/{commands → core/commands}/context-paging.md +0 -0
- /package/{commands → core/commands}/context-status.md +0 -0
- /package/{commands → core/commands}/context.md +0 -0
- /package/{commands → core/commands}/core-memory.md +0 -0
- /package/{commands → core/commands}/health.md +0 -0
- /package/{commands → core/commands}/merge.md +0 -0
- /package/{commands → core/commands}/recall.md +0 -0
- /package/{commands → core/commands}/remember.md +0 -0
- /package/{commands → core/commands}/search.md +0 -0
- /package/dist/{algorithms → core/algorithms}/detection/hash-filters.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/detection/hash-filters.js +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/approve-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/get-stats.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/list-proposals.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/preview-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/reject-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/safety/safety-checks.js +0 -0
- /package/dist/{algorithms → core/algorithms}/utils/response-builder.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/utils/response-builder.js +0 -0
- /package/dist/{commands → core/commands}/managed-sync.d.ts +0 -0
- /package/dist/{commands → core/commands}/mcp-server.d.ts +0 -0
- /package/dist/core/{context.d.ts → context/context.d.ts} +0 -0
- /package/dist/core/{agent-memory.d.ts → ingestion/agent-memory.d.ts} +0 -0
- /package/dist/core/{core-memory.d.ts → ingestion/core-memory.d.ts} +0 -0
- /package/dist/core/{privacy.d.ts → security/privacy.d.ts} +0 -0
- /package/dist/core/{privacy.js → security/privacy.js} +0 -0
- /package/dist/core/{secret-detector.d.ts → security/secret-detector.d.ts} +0 -0
- /package/dist/core/{secret-detector.js → security/secret-detector.js} +0 -0
- /package/dist/core/{cache.d.ts → storage/cache.d.ts} +0 -0
- /package/dist/core/{database.d.ts → storage/database.d.ts} +0 -0
- /package/dist/core/{database.js → storage/database.js} +0 -0
|
@@ -1,677 +1,357 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Squish
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
:
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
value: 'local',
|
|
359
|
-
label: `${icons.brain} Local Embeddings`,
|
|
360
|
-
hint: 'Uses local CPU (default, free, private)'
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
value: 'openai',
|
|
364
|
-
label: `${icons.cloud} OpenAI Embeddings`,
|
|
365
|
-
hint: 'Requires OPENAI_API_KEY (better quality)'
|
|
366
|
-
},
|
|
367
|
-
{
|
|
368
|
-
value: 'cohere',
|
|
369
|
-
label: `${icons.cloud} Cohere Embeddings`,
|
|
370
|
-
hint: 'Requires COHERE_API_KEY'
|
|
371
|
-
}
|
|
372
|
-
]
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
if (isCancel(embeddings)) {
|
|
376
|
-
cancel('Installation cancelled');
|
|
377
|
-
process.exit(0);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
return { mode, embeddings };
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
async function wizardReview(installConfig) {
|
|
384
|
-
const { components, plugins, config } = installConfig;
|
|
385
|
-
|
|
386
|
-
let summary = `${c.white("Installation Summary:")}\n\n`;
|
|
387
|
-
|
|
388
|
-
summary += `${c.cyan("Components:")}\n`;
|
|
389
|
-
if (components.includes('cli')) summary += ` ${icons.check} CLI\n`;
|
|
390
|
-
if (components.includes('mcp')) summary += ` ${icons.check} MCP Server\n`;
|
|
391
|
-
if (components.includes('plugins')) summary += ` ${icons.check} AI Agent Plugins\n`;
|
|
392
|
-
|
|
393
|
-
if (components.includes('plugins') && plugins.length > 0) {
|
|
394
|
-
summary += `\n${c.cyan("Plugins:")}\n`;
|
|
395
|
-
plugins.forEach(p => {
|
|
396
|
-
summary += ` ${icons.check} ${p}\n`;
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
summary += `\n${c.cyan("Configuration:")}\n`;
|
|
401
|
-
summary += ` ${icons.settings} Mode: ${config.mode}\n`;
|
|
402
|
-
summary += ` ${icons.brain} Embeddings: ${config.embeddings}\n`;
|
|
403
|
-
|
|
404
|
-
note(summary, 'Review');
|
|
405
|
-
|
|
406
|
-
const shouldInstall = await confirm({
|
|
407
|
-
message: 'Proceed with installation?',
|
|
408
|
-
initialValue: true
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
if (isCancel(shouldInstall) || !shouldInstall) {
|
|
412
|
-
cancel('Installation cancelled');
|
|
413
|
-
process.exit(0);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
return shouldInstall;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
async function performInstallation(installConfig, options = {}) {
|
|
420
|
-
const { components, plugins, config } = installConfig;
|
|
421
|
-
const s = spinner();
|
|
422
|
-
|
|
423
|
-
if (options.dryRun) {
|
|
424
|
-
console.log();
|
|
425
|
-
note(`${c.yellow("Dry-run mode - no changes made")}\n\nRemove --dry-run flag to perform actual installation.`, 'Preview');
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Install dependencies
|
|
430
|
-
if (components.length > 0 || plugins.length > 0) {
|
|
431
|
-
s.start('Installing dependencies...');
|
|
432
|
-
|
|
433
|
-
const depResult = spawnSync(
|
|
434
|
-
process.execPath,
|
|
435
|
-
[path.join(root, "scripts", "dependency-manager.mjs")],
|
|
436
|
-
{ encoding: "utf8", stdio: "pipe", timeout: 120000 }
|
|
437
|
-
);
|
|
438
|
-
|
|
439
|
-
if (depResult.status !== 0) {
|
|
440
|
-
s.stop(c.red(`${icons.cross} Dependency installation failed`));
|
|
441
|
-
if (options.verbose && depResult.stderr) {
|
|
442
|
-
console.log(c.gray(`Error: ${depResult.stderr}`));
|
|
443
|
-
}
|
|
444
|
-
process.exit(1);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
s.stop(c.green(`${icons.check} Dependencies installed`));
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Install CLI
|
|
451
|
-
if (components.includes('cli')) {
|
|
452
|
-
s.start('Setting up CLI...');
|
|
453
|
-
// CLI is already available via npm install, but we could add global link
|
|
454
|
-
s.stop(c.green(`${icons.check} CLI ready`));
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Install plugins
|
|
458
|
-
if (components.includes('plugins') && plugins.length > 0) {
|
|
459
|
-
// Handle OpenCode specially - use its own installer
|
|
460
|
-
const opencodeIndex = plugins.indexOf('opencode');
|
|
461
|
-
if (opencodeIndex > -1) {
|
|
462
|
-
plugins.splice(opencodeIndex, 1);
|
|
463
|
-
|
|
464
|
-
s.start('Installing OpenCode plugin...');
|
|
465
|
-
const opencodeResult = spawnSync(
|
|
466
|
-
process.execPath,
|
|
467
|
-
[path.join(root, "packages", "plugin-opencode", "install.mjs")],
|
|
468
|
-
{ encoding: "utf8", stdio: "pipe", timeout: 60000 }
|
|
469
|
-
);
|
|
470
|
-
|
|
471
|
-
if (opencodeResult.status !== 0) {
|
|
472
|
-
s.stop(c.red(`${icons.cross} OpenCode plugin installation failed`));
|
|
473
|
-
if (options.verbose && opencodeResult.stderr) {
|
|
474
|
-
console.log(c.gray(`Error: ${opencodeResult.stderr}`));
|
|
475
|
-
}
|
|
476
|
-
} else {
|
|
477
|
-
s.stop(c.green(`${icons.check} OpenCode plugin installed`));
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Install remaining plugins using general installer
|
|
482
|
-
if (plugins.length > 0) {
|
|
483
|
-
s.start(`Installing ${plugins.length} plugin(s)...`);
|
|
484
|
-
|
|
485
|
-
const installResult = spawnSync(
|
|
486
|
-
process.execPath,
|
|
487
|
-
[path.join(root, "scripts", "install-plugin.mjs"), "--client=" + plugins.join(",")],
|
|
488
|
-
{ encoding: "utf8", stdio: "pipe", timeout: 300000 }
|
|
489
|
-
);
|
|
490
|
-
|
|
491
|
-
if (installResult.status !== 0) {
|
|
492
|
-
s.stop(c.red(`${icons.cross} Plugin installation failed`));
|
|
493
|
-
if (options.verbose && installResult.stderr) {
|
|
494
|
-
console.log(c.gray(`Error: ${installResult.stderr}`));
|
|
495
|
-
}
|
|
496
|
-
process.exit(1);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
s.stop(c.green(`${icons.check} Plugins installed`));
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Save configuration
|
|
504
|
-
if (config) {
|
|
505
|
-
s.start('Saving configuration...');
|
|
506
|
-
// Save config to ~/.squish/config.json
|
|
507
|
-
const configPath = path.join(os.homedir(), '.squish', 'config.json');
|
|
508
|
-
const configDir = path.dirname(configPath);
|
|
509
|
-
|
|
510
|
-
if (!fs.existsSync(configDir)) {
|
|
511
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
fs.writeFileSync(configPath, JSON.stringify({
|
|
515
|
-
mode: config.mode,
|
|
516
|
-
embeddingsProvider: config.embeddings,
|
|
517
|
-
installedAt: new Date().toISOString(),
|
|
518
|
-
version: '1.0.0'
|
|
519
|
-
}, null, 2));
|
|
520
|
-
|
|
521
|
-
s.stop(c.green(`${icons.check} Configuration saved`));
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
async function runWizard(options = {}) {
|
|
526
|
-
printLogo();
|
|
527
|
-
|
|
528
|
-
intro(c.cyan(`${icons.squish} Squish Memory Installer`));
|
|
529
|
-
|
|
530
|
-
// Step 1: Component selection
|
|
531
|
-
const components = await wizardComponentSelection();
|
|
532
|
-
|
|
533
|
-
if (components.length === 0) {
|
|
534
|
-
cancel('No components selected. Exiting.');
|
|
535
|
-
process.exit(0);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
// Step 2: Plugin selection (if chosen)
|
|
539
|
-
let plugins = [];
|
|
540
|
-
if (components.includes('plugins')) {
|
|
541
|
-
plugins = await wizardPluginSelection();
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// Step 3: Configuration
|
|
545
|
-
const config = await wizardConfiguration();
|
|
546
|
-
|
|
547
|
-
// Step 4: Review
|
|
548
|
-
const installConfig = { components, plugins, config };
|
|
549
|
-
await wizardReview(installConfig);
|
|
550
|
-
|
|
551
|
-
// Step 5: Install
|
|
552
|
-
console.log();
|
|
553
|
-
await performInstallation(installConfig, options);
|
|
554
|
-
|
|
555
|
-
// Success
|
|
556
|
-
console.log();
|
|
557
|
-
outro(c.green(`${icons.check} Installation Complete!`));
|
|
558
|
-
|
|
559
|
-
// Next steps
|
|
560
|
-
console.log();
|
|
561
|
-
console.log(c.white("What's next?"));
|
|
562
|
-
console.log(` ${c.cyan(icons.arrow)} Restart your AI assistant(s)`);
|
|
563
|
-
console.log(` ${c.cyan(icons.arrow)} Try: ${c.gray("squish health")}`);
|
|
564
|
-
console.log(` ${c.cyan(icons.arrow)} Try: ${c.cyan("squish remember \"Your first memory\"")}`);
|
|
565
|
-
console.log();
|
|
566
|
-
console.log(c.gray("Documentation: https://github.com/michielhdoteth/squish"));
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
async function handleNonInteractive(flags, options) {
|
|
570
|
-
const choices = getPluginChoices();
|
|
571
|
-
|
|
572
|
-
if (choices.length === 0) {
|
|
573
|
-
console.log(c.red("No plugins available"));
|
|
574
|
-
process.exit(1);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
let pluginIds = [];
|
|
578
|
-
let components = ['cli'];
|
|
579
|
-
|
|
580
|
-
if (flags.quick) {
|
|
581
|
-
// Quick install: CLI + all plugins
|
|
582
|
-
pluginIds = choices.map(c => c.value);
|
|
583
|
-
components = ['cli', 'plugins'];
|
|
584
|
-
if (options.verbose) {
|
|
585
|
-
printLogo();
|
|
586
|
-
console.log(`${c.cyan("[QUICK MODE]")} Installing CLI + all plugins...\n`);
|
|
587
|
-
}
|
|
588
|
-
} else if (flags.all) {
|
|
589
|
-
pluginIds = choices.map(c => c.value);
|
|
590
|
-
components = ['cli', 'mcp', 'plugins'];
|
|
591
|
-
if (options.verbose) {
|
|
592
|
-
printLogo();
|
|
593
|
-
console.log(`${c.cyan("[AUTO MODE]")} Installing all components...\n`);
|
|
594
|
-
}
|
|
595
|
-
} else if (flags.select.length > 0) {
|
|
596
|
-
const validIds = choices.map(c => c.value);
|
|
597
|
-
const invalid = flags.select.filter(s => !validIds.includes(s));
|
|
598
|
-
|
|
599
|
-
if (invalid.length > 0) {
|
|
600
|
-
console.log(c.red(`Invalid plugins: ${invalid.join(", ")}`));
|
|
601
|
-
console.log(c.gray(`Available: ${validIds.join(", ")}`));
|
|
602
|
-
process.exit(1);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
pluginIds = flags.select;
|
|
606
|
-
components = ['cli', 'plugins'];
|
|
607
|
-
if (options.verbose) {
|
|
608
|
-
printLogo();
|
|
609
|
-
console.log(`${c.cyan("[AUTO MODE]")} Installing: ${pluginIds.join(", ")}...\n`);
|
|
610
|
-
}
|
|
611
|
-
} else {
|
|
612
|
-
console.log(c.yellow("Auto mode requires --all, --quick, or --select flag"));
|
|
613
|
-
const validIds = choices.map(c => c.value);
|
|
614
|
-
console.log(c.gray(`Available: ${validIds.join(", ")}`));
|
|
615
|
-
console.log(`Use ${c.cyan("--list")} to see all options`);
|
|
616
|
-
process.exit(1);
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
const installConfig = {
|
|
620
|
-
components,
|
|
621
|
-
plugins: pluginIds,
|
|
622
|
-
config: { mode: 'local', embeddings: 'local' }
|
|
623
|
-
};
|
|
624
|
-
|
|
625
|
-
await performInstallation(installConfig, options);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
async function main() {
|
|
629
|
-
const flags = parseArgs(process.argv);
|
|
630
|
-
|
|
631
|
-
if (flags.help) {
|
|
632
|
-
printHelp();
|
|
633
|
-
process.exit(0);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
if (flags.list) {
|
|
637
|
-
listPlugins();
|
|
638
|
-
process.exit(0);
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
const manifest = loadManifest();
|
|
642
|
-
if (!manifest) {
|
|
643
|
-
console.log(c.red("Error: Plugin manifest not found"));
|
|
644
|
-
console.log(c.gray(`Expected: ${manifestPath}`));
|
|
645
|
-
process.exit(1);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
const options = {
|
|
649
|
-
dryRun: flags.dryRun,
|
|
650
|
-
verbose: flags.verbose
|
|
651
|
-
};
|
|
652
|
-
|
|
653
|
-
// Non-interactive mode (only if explicitly requested and not in interactive mode)
|
|
654
|
-
if (!flags.interactive && (flags.auto || flags.quick || flags.select.length > 0 || shouldUseNonInteractive())) {
|
|
655
|
-
await handleNonInteractive(flags, options);
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
// Interactive wizard mode (default when no flags, or when --interactive is passed)
|
|
660
|
-
await runWizard(options);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
process.on("SIGINT", () => {
|
|
664
|
-
console.log(`\n${c.yellow("Installation cancelled.")}`);
|
|
665
|
-
process.exit(0);
|
|
666
|
-
});
|
|
667
|
-
|
|
668
|
-
process.on("SIGTERM", () => {
|
|
669
|
-
console.log(`\n${c.yellow("Installation cancelled.")}`);
|
|
670
|
-
process.exit(0);
|
|
671
|
-
});
|
|
672
|
-
|
|
673
|
-
main().catch((err) => {
|
|
674
|
-
console.log(c.red(`Fatal error: ${err.message}`));
|
|
675
|
-
console.error(err);
|
|
676
|
-
process.exit(1);
|
|
677
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Squish MCP Installer
|
|
5
|
+
* Installs Squish MCP configuration for various AI clients
|
|
6
|
+
* Supports: Claude Code, OpenCode, Codex, Cursor, VS Code, Windsurf
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* bun run install # Interactive wizard
|
|
10
|
+
* bun run install --all # Auto-install for all detected clients
|
|
11
|
+
* bun run install --clients=claude-code,opencode # Specific clients
|
|
12
|
+
* bun run install --dry-run # Preview without installing
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { intro, outro, confirm, multiselect, select, isCancel, cancel, spinner, note } from '@clack/prompts';
|
|
16
|
+
import picocolors from 'picocolors';
|
|
17
|
+
import fs from "node:fs";
|
|
18
|
+
import os from "node:os";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
|
|
21
|
+
const root = process.cwd();
|
|
22
|
+
const manifestPath = path.join(root, "config", "plugin-manifest.json");
|
|
23
|
+
|
|
24
|
+
const c = picocolors;
|
|
25
|
+
|
|
26
|
+
const icons = {
|
|
27
|
+
squish: "🐙",
|
|
28
|
+
check: "✓",
|
|
29
|
+
cross: "✗",
|
|
30
|
+
arrow: "→",
|
|
31
|
+
dot: "●",
|
|
32
|
+
mcp: "🔌",
|
|
33
|
+
settings: "⚙️"
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Client config file locations
|
|
37
|
+
const CLIENT_CONFIGS = {
|
|
38
|
+
"claude-code": { dir: path.join(os.homedir(), ".claude"), file: "mcp.json" },
|
|
39
|
+
opencode: { dir: path.join(os.homedir(), ".config", "opencode"), file: "mcp-servers.json" },
|
|
40
|
+
codex: { dir: path.join(os.homedir(), ".codex"), file: "mcp-servers.json" },
|
|
41
|
+
cursor: { dir: path.join(os.homedir(), ".cursor"), file: "mcp.json" },
|
|
42
|
+
vscode: { dir: path.join(os.homedir(), ".vscode", "mcp"), file: "servers.json" },
|
|
43
|
+
windsurf: { dir: path.join(os.homedir(), ".windsurf"), file: "mcp-servers.json" }
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// CLI argument parsing
|
|
47
|
+
function parseArgs() {
|
|
48
|
+
const args = process.argv.slice(2);
|
|
49
|
+
const options = {
|
|
50
|
+
all: false,
|
|
51
|
+
clients: [],
|
|
52
|
+
dryRun: false,
|
|
53
|
+
help: false
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
for (const arg of args) {
|
|
57
|
+
if (arg === '--all') options.all = true;
|
|
58
|
+
else if (arg === '--dry-run') options.dryRun = true;
|
|
59
|
+
else if (arg === '--help' || arg === '-h') options.help = true;
|
|
60
|
+
else if (arg.startsWith('--clients=')) {
|
|
61
|
+
options.clients = arg.slice(10).split(',').map(c => c.trim());
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return options;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function printHelp() {
|
|
69
|
+
printLogo();
|
|
70
|
+
console.log(c.white("Usage:"));
|
|
71
|
+
console.log(` ${c.cyan("bun run install")} # Interactive wizard`);
|
|
72
|
+
console.log(` ${c.cyan("bun run install --all")} # Auto-install for all detected clients`);
|
|
73
|
+
console.log(` ${c.cyan("bun run install --clients=claude-code,opencode")} # Specific clients`);
|
|
74
|
+
console.log(` ${c.cyan("bun run install --dry-run")} # Preview without installing\n`);
|
|
75
|
+
console.log(c.white("Options:"));
|
|
76
|
+
console.log(` ${c.cyan("--all")} Install for all supported clients`);
|
|
77
|
+
console.log(` ${c.cyan("--clients=")} Comma-separated list of clients`);
|
|
78
|
+
console.log(` ${c.cyan("--dry-run")} Preview changes without installing`);
|
|
79
|
+
console.log(` ${c.cyan("--help")} Show this help message\n`);
|
|
80
|
+
console.log(c.white("Supported clients:"));
|
|
81
|
+
console.log(` claude-code, opencode, codex, cursor, vscode, windsurf`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function printLogo() {
|
|
85
|
+
console.log(c.cyan(`
|
|
86
|
+
██████╗ ██████╗ ██╗ ██╗██╗███████╗██╗ ██╗
|
|
87
|
+
██╔════╝██╔═══██╗██║ ██║██║██╔════╝██║ ██║
|
|
88
|
+
██████╗██║ ██║██║ ██║██║███████╗███████║
|
|
89
|
+
╚════██║██║ ██║██║ ██║██║╚════██║██╔══██║
|
|
90
|
+
██████║╚██████╔╝╚██████╔╝██║███████║██║ ██║
|
|
91
|
+
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
|
92
|
+
`));
|
|
93
|
+
console.log(c.gray(" Universal Memory System for AI Agents\n"));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function loadManifest() {
|
|
97
|
+
if (!fs.existsSync(manifestPath)) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
102
|
+
} catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function detectClients() {
|
|
108
|
+
const detected = {};
|
|
109
|
+
for (const [client, config] of Object.entries(CLIENT_CONFIGS)) {
|
|
110
|
+
const configPath = path.join(config.dir, config.file);
|
|
111
|
+
detected[client] = fs.existsSync(config.dir);
|
|
112
|
+
}
|
|
113
|
+
return detected;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function expandPath(filePath) {
|
|
117
|
+
if (filePath.startsWith("~")) {
|
|
118
|
+
return path.join(os.homedir(), filePath.slice(2));
|
|
119
|
+
}
|
|
120
|
+
return filePath;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function ensureDir(dirPath) {
|
|
124
|
+
if (!fs.existsSync(dirPath)) {
|
|
125
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function backupFile(filePath) {
|
|
130
|
+
if (fs.existsSync(filePath)) {
|
|
131
|
+
const backupPath = `${filePath}.bak.${Date.now()}`;
|
|
132
|
+
fs.copyFileSync(filePath, backupPath);
|
|
133
|
+
console.log(c.gray(` Backed up: ${backupPath}`));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Generate MCP config for each client format
|
|
138
|
+
function generateMCPConfig(client, manifest) {
|
|
139
|
+
const target = manifest.targets[client];
|
|
140
|
+
if (!target) return null;
|
|
141
|
+
|
|
142
|
+
// OpenCode format: { "server-name": { type, command, enabled } }
|
|
143
|
+
if (target.format === "opencode") {
|
|
144
|
+
return {
|
|
145
|
+
[target.serverName]: {
|
|
146
|
+
type: target.type === "local" ? "local" : "stdio",
|
|
147
|
+
command: Array.isArray(target.command) ? target.command : [target.command],
|
|
148
|
+
enabled: target.enabled !== false
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Standard MCP format: { mcpServers: { "server-name": { type, command, args, env } } }
|
|
154
|
+
return {
|
|
155
|
+
mcpServers: {
|
|
156
|
+
[target.serverName]: {
|
|
157
|
+
command: target.command,
|
|
158
|
+
args: target.args || ["--stdio"],
|
|
159
|
+
env: target.env || {}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Merge MCP config with existing config
|
|
166
|
+
function mergeMCPConfig(client, manifest, options = {}) {
|
|
167
|
+
const target = manifest.targets[client];
|
|
168
|
+
if (!target) return { error: `Unknown client: ${client}` };
|
|
169
|
+
|
|
170
|
+
const configInfo = CLIENT_CONFIGS[client];
|
|
171
|
+
const configPath = expandPath(path.join(configInfo.dir, configInfo.file));
|
|
172
|
+
|
|
173
|
+
// Generate new config
|
|
174
|
+
const newConfig = generateMCPConfig(client, manifest);
|
|
175
|
+
if (!newConfig) return { error: "Failed to generate config" };
|
|
176
|
+
|
|
177
|
+
ensureDir(configInfo.dir);
|
|
178
|
+
|
|
179
|
+
let existingConfig = {};
|
|
180
|
+
if (fs.existsSync(configPath)) {
|
|
181
|
+
try {
|
|
182
|
+
existingConfig = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
183
|
+
} catch {
|
|
184
|
+
existingConfig = {};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Merge based on format
|
|
189
|
+
let merged;
|
|
190
|
+
if (target.format === "opencode") {
|
|
191
|
+
// OpenCode format: merge at root level
|
|
192
|
+
merged = { ...existingConfig, ...newConfig };
|
|
193
|
+
} else {
|
|
194
|
+
// Standard format: merge under mcpServers
|
|
195
|
+
merged = { ...existingConfig };
|
|
196
|
+
if (!merged.mcpServers) merged.mcpServers = {};
|
|
197
|
+
merged.mcpServers = { ...merged.mcpServers, ...newConfig.mcpServers };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Write config
|
|
201
|
+
if (!options.dryRun) {
|
|
202
|
+
backupFile(configPath);
|
|
203
|
+
fs.writeFileSync(configPath, JSON.stringify(merged, null, 2));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return { ok: true, configPath, merged };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function getClientChoices(manifest, detected) {
|
|
210
|
+
if (!manifest || !manifest.targets) return [];
|
|
211
|
+
|
|
212
|
+
const clientNames = {
|
|
213
|
+
"claude-code": "Claude Code",
|
|
214
|
+
opencode: "OpenCode",
|
|
215
|
+
codex: "Codex",
|
|
216
|
+
cursor: "Cursor",
|
|
217
|
+
vscode: "VS Code",
|
|
218
|
+
windsurf: "Windsurf"
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return Object.keys(manifest.targets).map(client => {
|
|
222
|
+
const isInstalled = detected[client];
|
|
223
|
+
const name = clientNames[client] || client;
|
|
224
|
+
let label = name;
|
|
225
|
+
if (isInstalled) label += ` ${c.green(icons.check)}`;
|
|
226
|
+
return {
|
|
227
|
+
value: client,
|
|
228
|
+
label: label,
|
|
229
|
+
hint: isInstalled ? "Config found" : "Not detected"
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function main() {
|
|
235
|
+
const opts = parseArgs();
|
|
236
|
+
|
|
237
|
+
if (opts.help) {
|
|
238
|
+
printHelp();
|
|
239
|
+
process.exit(0);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const manifest = loadManifest();
|
|
243
|
+
if (!manifest) {
|
|
244
|
+
console.log(c.red("Error: Plugin manifest not found"));
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const detected = detectClients();
|
|
249
|
+
const choices = getClientChoices(manifest, detected);
|
|
250
|
+
|
|
251
|
+
let clients;
|
|
252
|
+
|
|
253
|
+
// Non-interactive mode
|
|
254
|
+
if (opts.all) {
|
|
255
|
+
// Install for all supported clients
|
|
256
|
+
clients = choices.map(c => c.value);
|
|
257
|
+
printLogo();
|
|
258
|
+
console.log(c.cyan(`Auto-installing for all ${clients.length} clients...\n`));
|
|
259
|
+
} else if (opts.clients.length > 0) {
|
|
260
|
+
// Install for specific clients
|
|
261
|
+
clients = opts.clients;
|
|
262
|
+
printLogo();
|
|
263
|
+
console.log(c.cyan(`Installing for: ${clients.join(', ')}\n`));
|
|
264
|
+
} else if (process.stdin.isTTY) {
|
|
265
|
+
// Interactive mode
|
|
266
|
+
printLogo();
|
|
267
|
+
intro(c.cyan(`${icons.squish} Squish MCP Installer`));
|
|
268
|
+
|
|
269
|
+
// Select clients to install
|
|
270
|
+
clients = await multiselect({
|
|
271
|
+
message: 'Which AI agents do you want to install Squish MCP for?',
|
|
272
|
+
options: choices,
|
|
273
|
+
required: false
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
if (isCancel(clients) || !clients || clients.length === 0) {
|
|
277
|
+
console.log(c.yellow("No clients selected. Exiting."));
|
|
278
|
+
process.exit(0);
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
// Non-interactive without flags - show help
|
|
282
|
+
printHelp();
|
|
283
|
+
process.exit(0);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Dry run mode
|
|
287
|
+
if (opts.dryRun) {
|
|
288
|
+
console.log(c.yellow("\n--- DRY RUN MODE ---\n"));
|
|
289
|
+
for (const client of clients) {
|
|
290
|
+
const configInfo = CLIENT_CONFIGS[client];
|
|
291
|
+
console.log(` Would install for ${client}:`);
|
|
292
|
+
console.log(` Config: ${configInfo.dir}/${configInfo.file}`);
|
|
293
|
+
}
|
|
294
|
+
console.log("");
|
|
295
|
+
process.exit(0);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Non-interactive: skip review/confirm
|
|
299
|
+
const isInteractive = opts.all || opts.clients.length === 0 && process.stdin.isTTY;
|
|
300
|
+
|
|
301
|
+
if (isInteractive) {
|
|
302
|
+
// Review
|
|
303
|
+
let summary = `${c.white("Installation Summary:")}\n\n`;
|
|
304
|
+
summary += `${c.cyan("Installing Squish MCP for:")}\n`;
|
|
305
|
+
clients.forEach(client => {
|
|
306
|
+
const configInfo = CLIENT_CONFIGS[client];
|
|
307
|
+
summary += ` ${icons.check} ${client}\n`;
|
|
308
|
+
summary += ` ${c.gray(configInfo.dir)}\n`;
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
note(summary, 'Review');
|
|
312
|
+
|
|
313
|
+
const shouldInstall = await confirm({
|
|
314
|
+
message: 'Proceed with installation?',
|
|
315
|
+
initialValue: true
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
if (isCancel(shouldInstall) || !shouldInstall) {
|
|
319
|
+
console.log(c.yellow("Installation cancelled"));
|
|
320
|
+
process.exit(0);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Install
|
|
325
|
+
const s = spinner();
|
|
326
|
+
s.start('Installing MCP configurations...');
|
|
327
|
+
|
|
328
|
+
const results = [];
|
|
329
|
+
for (const client of clients) {
|
|
330
|
+
const result = mergeMCPConfig(client, manifest);
|
|
331
|
+
results.push({ client, ...result });
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const errors = results.filter(r => r.error);
|
|
335
|
+
const success = results.filter(r => r.ok);
|
|
336
|
+
|
|
337
|
+
if (errors.length > 0) {
|
|
338
|
+
s.stop(c.red(`${icons.cross} Some installations failed`));
|
|
339
|
+
errors.forEach(e => console.log(c.red(` ${e.client}: ${e.error}`)));
|
|
340
|
+
} else {
|
|
341
|
+
s.stop(c.green(`${icons.check} Installed for ${success.length} client(s)`));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Next steps
|
|
345
|
+
console.log();
|
|
346
|
+
console.log(c.white("What's next?"));
|
|
347
|
+
console.log(` ${c.cyan(icons.arrow)} Restart your AI assistant(s)`);
|
|
348
|
+
console.log(` ${c.cyan(icons.arrow)} Try: squish remember "Your first memory"`);
|
|
349
|
+
console.log();
|
|
350
|
+
|
|
351
|
+
outro(c.green(`${icons.check} Installation Complete!`));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
main().catch((err) => {
|
|
355
|
+
console.log(c.red(`Fatal error: ${err.message}`));
|
|
356
|
+
process.exit(1);
|
|
357
|
+
});
|