wyrm-mcp 7.2.1 → 7.2.3

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.
Files changed (280) hide show
  1. package/LICENSE +26 -667
  2. package/NOTICE +14 -33
  3. package/dist/activation.d.ts +8 -9
  4. package/dist/activation.d.ts.map +1 -1
  5. package/dist/activation.js +1 -60
  6. package/dist/activation.js.map +1 -1
  7. package/dist/agent-daemon.d.ts +1 -1
  8. package/dist/agent-daemon.js +4 -281
  9. package/dist/agent-loop.d.ts +1 -1
  10. package/dist/agent-loop.js +7 -332
  11. package/dist/analytics.d.ts +1 -1
  12. package/dist/analytics.js +13 -236
  13. package/dist/attribution.d.ts +1 -1
  14. package/dist/attribution.js +1 -49
  15. package/dist/audit.d.ts +1 -1
  16. package/dist/audit.js +2 -457
  17. package/dist/auto-capture.js +3 -138
  18. package/dist/auto-orchestrator.d.ts +1 -1
  19. package/dist/auto-orchestrator.js +1 -325
  20. package/dist/autoconfig.d.ts +1 -1
  21. package/dist/autoconfig.js +39 -840
  22. package/dist/buddy-runner.d.ts +1 -1
  23. package/dist/buddy-runner.js +1 -109
  24. package/dist/buddy.d.ts +1 -1
  25. package/dist/buddy.js +14 -564
  26. package/dist/build-flags.d.ts +6 -8
  27. package/dist/build-flags.d.ts.map +1 -1
  28. package/dist/build-flags.js +1 -17
  29. package/dist/build-flags.js.map +1 -1
  30. package/dist/capabilities.d.ts +1 -1
  31. package/dist/capabilities.js +3 -183
  32. package/dist/capture.d.ts +1 -1
  33. package/dist/capture.js +1 -56
  34. package/dist/causality.d.ts +1 -1
  35. package/dist/causality.js +6 -107
  36. package/dist/cli.d.ts +1 -1
  37. package/dist/cli.js +20 -281
  38. package/dist/cloud/cli.js +5 -541
  39. package/dist/cloud/client.js +1 -221
  40. package/dist/cloud/crypto.js +1 -85
  41. package/dist/cloud/machine-id.d.ts +1 -1
  42. package/dist/cloud/machine-id.js +2 -113
  43. package/dist/cloud/recovery.js +1 -60
  44. package/dist/cloud/sync-engine.js +7 -543
  45. package/dist/cloud-backup.d.ts +1 -1
  46. package/dist/cloud-backup.js +5 -579
  47. package/dist/cloud-profile.d.ts +1 -1
  48. package/dist/cloud-profile.js +1 -138
  49. package/dist/cloud-sync-entrypoint.d.ts +1 -1
  50. package/dist/cloud-sync-entrypoint.js +1 -47
  51. package/dist/cloud-sync.d.ts +1 -1
  52. package/dist/cloud-sync.js +2 -309
  53. package/dist/constellation.d.ts +1 -1
  54. package/dist/constellation.js +12 -168
  55. package/dist/context-build-budgeted.d.ts +1 -1
  56. package/dist/context-build-budgeted.js +4 -144
  57. package/dist/context-ranking.d.ts +1 -1
  58. package/dist/context-ranking.js +1 -69
  59. package/dist/crypto.d.ts +1 -1
  60. package/dist/crypto.js +1 -179
  61. package/dist/daemon-write-endpoint.d.ts +1 -1
  62. package/dist/daemon-write-endpoint.js +1 -290
  63. package/dist/daemon-writer.d.ts +1 -1
  64. package/dist/daemon-writer.js +2 -406
  65. package/dist/database.d.ts +1 -1
  66. package/dist/database.js +43 -1110
  67. package/dist/deprecations.js +2 -162
  68. package/dist/design.d.ts +1 -1
  69. package/dist/design.js +13 -141
  70. package/dist/event-replication.d.ts +1 -1
  71. package/dist/event-replication.js +1 -112
  72. package/dist/events-sse.d.ts +1 -1
  73. package/dist/events-sse.js +7 -43
  74. package/dist/events.js +6 -238
  75. package/dist/failure-patterns.d.ts +1 -1
  76. package/dist/failure-patterns.js +42 -659
  77. package/dist/federation.d.ts +1 -1
  78. package/dist/federation.js +12 -236
  79. package/dist/goals.d.ts +1 -1
  80. package/dist/goals.js +13 -101
  81. package/dist/golden.js +3 -355
  82. package/dist/handlers/agent.d.ts +1 -1
  83. package/dist/handlers/agent.js +4 -165
  84. package/dist/handlers/alias-adapters.d.ts +1 -1
  85. package/dist/handlers/alias-adapters.js +1 -129
  86. package/dist/handlers/aliases.d.ts +1 -1
  87. package/dist/handlers/aliases.js +1 -171
  88. package/dist/handlers/audit.d.ts +1 -1
  89. package/dist/handlers/audit.js +1 -87
  90. package/dist/handlers/boundary.d.ts +1 -1
  91. package/dist/handlers/boundary.js +1 -221
  92. package/dist/handlers/capture.d.ts +1 -1
  93. package/dist/handlers/capture.js +73 -1109
  94. package/dist/handlers/causality.d.ts +1 -1
  95. package/dist/handlers/causality.js +7 -114
  96. package/dist/handlers/cloud.d.ts +1 -1
  97. package/dist/handlers/cloud.js +85 -382
  98. package/dist/handlers/companion.d.ts +1 -1
  99. package/dist/handlers/companion.js +28 -459
  100. package/dist/handlers/datalake.d.ts +1 -1
  101. package/dist/handlers/datalake.js +7 -187
  102. package/dist/handlers/dispatch-context.d.ts +1 -1
  103. package/dist/handlers/dispatch-context.js +0 -22
  104. package/dist/handlers/entity.d.ts +1 -1
  105. package/dist/handlers/entity.js +25 -256
  106. package/dist/handlers/events.d.ts +1 -1
  107. package/dist/handlers/events.js +16 -335
  108. package/dist/handlers/failure.d.ts +1 -1
  109. package/dist/handlers/failure.js +13 -340
  110. package/dist/handlers/goals.d.ts +1 -1
  111. package/dist/handlers/goals.js +4 -296
  112. package/dist/handlers/intelligence.d.ts +1 -1
  113. package/dist/handlers/intelligence.js +126 -674
  114. package/dist/handlers/invoicing.d.ts +1 -1
  115. package/dist/handlers/invoicing.js +1 -70
  116. package/dist/handlers/mcpclient.d.ts +1 -1
  117. package/dist/handlers/mcpclient.js +6 -137
  118. package/dist/handlers/orchestration.d.ts +1 -1
  119. package/dist/handlers/orchestration.js +40 -125
  120. package/dist/handlers/output-schemas.d.ts +1 -1
  121. package/dist/handlers/output-schemas.js +1 -24
  122. package/dist/handlers/presence.d.ts +1 -1
  123. package/dist/handlers/presence.js +3 -99
  124. package/dist/handlers/project.d.ts +1 -1
  125. package/dist/handlers/project.js +28 -182
  126. package/dist/handlers/prompts.d.ts +1 -1
  127. package/dist/handlers/prompts.js +6 -157
  128. package/dist/handlers/quest.d.ts +1 -1
  129. package/dist/handlers/quest.js +4 -224
  130. package/dist/handlers/recall.d.ts +1 -1
  131. package/dist/handlers/recall.js +11 -218
  132. package/dist/handlers/registry.d.ts +1 -1
  133. package/dist/handlers/registry.js +1 -167
  134. package/dist/handlers/resources.d.ts +1 -1
  135. package/dist/handlers/resources.js +1 -288
  136. package/dist/handlers/review.d.ts +1 -1
  137. package/dist/handlers/review.js +11 -74
  138. package/dist/handlers/run.d.ts +1 -1
  139. package/dist/handlers/run.js +17 -487
  140. package/dist/handlers/search.d.ts +1 -1
  141. package/dist/handlers/search.js +15 -326
  142. package/dist/handlers/session.d.ts +1 -1
  143. package/dist/handlers/session.js +28 -615
  144. package/dist/handlers/share.d.ts +1 -1
  145. package/dist/handlers/share.js +8 -184
  146. package/dist/handlers/shims.d.ts +1 -1
  147. package/dist/handlers/shims.js +1 -464
  148. package/dist/handlers/skill.d.ts +1 -1
  149. package/dist/handlers/skill.js +67 -449
  150. package/dist/handlers/survivors.d.ts +1 -1
  151. package/dist/handlers/survivors.js +1 -120
  152. package/dist/handlers/symbols.d.ts +1 -1
  153. package/dist/handlers/symbols.js +8 -109
  154. package/dist/handlers/syncops.d.ts +1 -1
  155. package/dist/handlers/syncops.js +4 -302
  156. package/dist/handlers/types.d.ts +1 -1
  157. package/dist/handlers/types.js +1 -27
  158. package/dist/harvest.d.ts +1 -1
  159. package/dist/harvest.js +5 -191
  160. package/dist/hours.d.ts +1 -1
  161. package/dist/hours.js +7 -156
  162. package/dist/http-auth.d.ts +1 -1
  163. package/dist/http-auth.js +3 -321
  164. package/dist/http-fast.js +21 -1137
  165. package/dist/icons.d.ts +1 -1
  166. package/dist/icons.js +1 -47
  167. package/dist/index.d.ts +1 -1
  168. package/dist/index.js +2 -924
  169. package/dist/index.js.map +1 -1
  170. package/dist/indexer.d.ts +1 -1
  171. package/dist/indexer.js +4 -145
  172. package/dist/intelligence.d.ts +1 -1
  173. package/dist/intelligence.js +31 -261
  174. package/dist/internal-dispatch.d.ts +1 -1
  175. package/dist/internal-dispatch.js +3 -212
  176. package/dist/keyset.d.ts +1 -1
  177. package/dist/keyset.js +1 -110
  178. package/dist/knowledge-graph.d.ts +1 -1
  179. package/dist/knowledge-graph.js +12 -176
  180. package/dist/license.d.ts +1 -1
  181. package/dist/license.js +2 -441
  182. package/dist/logger.d.ts +1 -1
  183. package/dist/logger.js +2 -199
  184. package/dist/maintenance.d.ts +1 -1
  185. package/dist/maintenance.js +2 -148
  186. package/dist/mcp-client.d.ts +1 -1
  187. package/dist/mcp-client.js +6 -262
  188. package/dist/memory-artifacts.d.ts +1 -1
  189. package/dist/memory-artifacts.js +30 -449
  190. package/dist/migrate-prompt.d.ts +1 -1
  191. package/dist/migrate-prompt.js +2 -124
  192. package/dist/migrations.d.ts +1 -1
  193. package/dist/migrations.js +40 -655
  194. package/dist/performance.js +1 -228
  195. package/dist/presence.d.ts +1 -1
  196. package/dist/presence.js +11 -140
  197. package/dist/priority-embed.d.ts +1 -1
  198. package/dist/priority-embed.js +5 -164
  199. package/dist/providers/embedding-provider.d.ts +1 -1
  200. package/dist/providers/embedding-provider.js +1 -196
  201. package/dist/readonly-gate.js +1 -29
  202. package/dist/rehydration.d.ts +1 -1
  203. package/dist/rehydration.js +9 -157
  204. package/dist/reindex.d.ts +1 -1
  205. package/dist/reindex.js +1 -88
  206. package/dist/render-target.d.ts +1 -1
  207. package/dist/render-target.js +21 -514
  208. package/dist/render.d.ts +1 -1
  209. package/dist/render.js +4 -280
  210. package/dist/repl-guard.d.ts +1 -1
  211. package/dist/repl-guard.js +1 -173
  212. package/dist/replication-daemon-entrypoint.d.ts +1 -1
  213. package/dist/replication-daemon-entrypoint.js +1 -31
  214. package/dist/replication-daemon.d.ts +1 -1
  215. package/dist/replication-daemon.js +2 -262
  216. package/dist/resilience.d.ts +1 -1
  217. package/dist/resilience.js +1 -591
  218. package/dist/reverse-bridge.d.ts +1 -1
  219. package/dist/reverse-bridge.js +5 -360
  220. package/dist/security.d.ts +1 -1
  221. package/dist/security.js +1 -244
  222. package/dist/session-seen.d.ts +1 -1
  223. package/dist/session-seen.js +3 -51
  224. package/dist/setup.d.ts +1 -1
  225. package/dist/setup.js +1 -260
  226. package/dist/skill-author.d.ts +1 -1
  227. package/dist/skill-author.js +5 -168
  228. package/dist/spec-kit.d.ts +1 -1
  229. package/dist/spec-kit.js +1 -191
  230. package/dist/sqlite-busy.d.ts +1 -1
  231. package/dist/sqlite-busy.js +1 -154
  232. package/dist/statusline.d.ts +1 -1
  233. package/dist/statusline.js +11 -315
  234. package/dist/sub-agent.d.ts +1 -1
  235. package/dist/sub-agent.js +13 -262
  236. package/dist/summarizer.js +13 -139
  237. package/dist/symbols.d.ts +1 -1
  238. package/dist/symbols.js +7 -283
  239. package/dist/sync.d.ts +1 -1
  240. package/dist/sync.js +5 -359
  241. package/dist/tasks-dispatch.js +1 -84
  242. package/dist/tasks.js +1 -282
  243. package/dist/token-budget.d.ts +1 -1
  244. package/dist/token-budget.js +1 -143
  245. package/dist/tool-analytics.d.ts +1 -1
  246. package/dist/tool-analytics.js +7 -129
  247. package/dist/tool-annotations.js +1 -365
  248. package/dist/tool-manifest-v2.json +1 -1
  249. package/dist/tool-manifest.json +1 -1
  250. package/dist/tool-profiles.d.ts +1 -1
  251. package/dist/tool-profiles.js +1 -75
  252. package/dist/trace-harvest.d.ts +1 -1
  253. package/dist/trace-harvest.js +6 -244
  254. package/dist/types.d.ts +1 -1
  255. package/dist/types.js +1 -30
  256. package/dist/ui-dashboard.d.ts +1 -1
  257. package/dist/ui-dashboard.js +41 -50
  258. package/dist/ulid.d.ts +1 -1
  259. package/dist/ulid.js +1 -81
  260. package/dist/validate.d.ts +1 -1
  261. package/dist/validate.js +1 -129
  262. package/dist/vault.js +1 -534
  263. package/dist/vectors.d.ts +1 -1
  264. package/dist/vectors.js +3 -184
  265. package/dist/version-check.d.ts +1 -1
  266. package/dist/version-check.js +4 -136
  267. package/dist/visibility.d.ts +1 -1
  268. package/dist/visibility.js +19 -155
  269. package/dist/wyrm-cli.d.ts +1 -1
  270. package/dist/wyrm-cli.js +98 -2464
  271. package/dist/wyrm-cli.js.map +1 -1
  272. package/dist/wyrm-guard.d.ts +1 -1
  273. package/dist/wyrm-guard.js +14 -424
  274. package/dist/wyrm-loop.js +3 -150
  275. package/dist/wyrm-manifest.json +1 -1
  276. package/dist/wyrm-statusline-daemon.js +1 -11
  277. package/dist/wyrm-statusline.js +4 -56
  278. package/dist/wyrm-ui.d.ts +1 -1
  279. package/dist/wyrm-ui.js +9 -77
  280. package/package.json +4 -2
@@ -1,851 +1,50 @@
1
- /**
2
- * Wyrm Auto-Configure - Universal AI Client Detection & Setup
3
- *
4
- * Automatically detects installed AI clients (VS Code Copilot, Claude Desktop,
5
- * Cursor, Windsurf, Zed, etc.) and configures Wyrm's MCP server in each.
6
- * Handles provider switching seamlessly change your AI, Wyrm follows.
7
- *
8
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
9
- * @license AGPL-3.0-or-later dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
10
- * @module autoconfig
11
- * @version 3.0.0
12
- */
13
- import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, chmodSync } from 'fs';
14
- import { homedir, platform } from 'os';
15
- import { join, dirname, resolve } from 'path';
16
- import { fileURLToPath } from 'url';
17
- import { spawnSync } from 'child_process';
18
- // ==================== CLIENT DEFINITIONS ====================
19
- function getConfigPaths() {
20
- const home = homedir();
21
- const os = platform();
22
- // Base config directories per OS
23
- const vscodeBase = os === 'darwin'
24
- ? join(home, 'Library', 'Application Support', 'Code', 'User')
25
- : os === 'win32'
26
- ? join(home, 'AppData', 'Roaming', 'Code', 'User')
27
- : join(home, '.config', 'Code', 'User');
28
- const vscodeInsidersBase = os === 'darwin'
29
- ? join(home, 'Library', 'Application Support', 'Code - Insiders', 'User')
30
- : os === 'win32'
31
- ? join(home, 'AppData', 'Roaming', 'Code - Insiders', 'User')
32
- : join(home, '.config', 'Code - Insiders', 'User');
33
- const claudeBase = os === 'darwin'
34
- ? join(home, 'Library', 'Application Support', 'Claude')
35
- : os === 'win32'
36
- ? join(home, 'AppData', 'Roaming', 'Claude')
37
- : join(home, '.config', 'claude');
38
- const cursorBase = os === 'darwin'
39
- ? join(home, '.cursor')
40
- : os === 'win32'
41
- ? join(home, '.cursor')
42
- : join(home, '.cursor');
43
- const windsurfBase = os === 'darwin'
44
- ? join(home, '.codeium', 'windsurf')
45
- : os === 'win32'
46
- ? join(home, '.codeium', 'windsurf')
47
- : join(home, '.codeium', 'windsurf');
48
- const zedBase = os === 'darwin'
49
- ? join(home, '.config', 'zed')
50
- : os === 'win32'
51
- ? join(home, 'AppData', 'Roaming', 'Zed')
52
- : join(home, '.config', 'zed');
53
- const continueBase = join(home, '.continue');
54
- return [
55
- {
56
- id: 'vscode-copilot',
57
- name: 'VS Code (Copilot)',
58
- icon: '💻',
59
- configPath: join(vscodeBase, 'settings.json'),
60
- configFormat: 'vscode',
61
- mcpKey: 'mcp.servers',
62
- detected: false,
63
- configured: false,
64
- },
65
- {
66
- id: 'vscode-insiders',
67
- name: 'VS Code Insiders',
68
- icon: '🟢',
69
- configPath: join(vscodeInsidersBase, 'settings.json'),
70
- configFormat: 'vscode',
71
- mcpKey: 'mcp.servers',
72
- detected: false,
73
- configured: false,
74
- },
75
- {
76
- id: 'claude-desktop',
77
- name: 'Claude Desktop',
78
- icon: '🤖',
79
- configPath: join(claudeBase, 'claude_desktop_config.json'),
80
- configFormat: 'mcp-json',
81
- mcpKey: 'mcpServers',
82
- detected: false,
83
- configured: false,
84
- },
85
- {
86
- id: 'cursor',
87
- name: 'Cursor',
88
- icon: '📐',
89
- configPath: join(cursorBase, 'mcp.json'),
90
- configFormat: 'mcp-json',
91
- mcpKey: 'mcpServers',
92
- detected: false,
93
- configured: false,
94
- },
95
- {
96
- id: 'windsurf',
97
- name: 'Windsurf',
98
- icon: '🏄',
99
- configPath: join(windsurfBase, 'mcp_config.json'),
100
- configFormat: 'mcp-json',
101
- mcpKey: 'mcpServers',
102
- detected: false,
103
- configured: false,
104
- },
105
- {
106
- id: 'zed',
107
- name: 'Zed',
108
- icon: '⚡',
109
- configPath: join(zedBase, 'settings.json'),
110
- configFormat: 'zed',
111
- mcpKey: 'context_servers',
112
- detected: false,
113
- configured: false,
114
- },
115
- {
116
- id: 'continue',
117
- name: 'Continue',
118
- icon: '🔄',
119
- configPath: join(continueBase, 'config.json'),
120
- configFormat: 'mcp-json',
121
- mcpKey: 'mcpServers',
122
- detected: false,
123
- configured: false,
124
- },
125
- ];
126
- }
127
- // ==================== DETECTION ====================
128
- /**
129
- * Detect which AI clients are installed by checking for their config directories
130
- */
131
- export function detectClients() {
132
- const clients = getConfigPaths();
133
- for (const client of clients) {
134
- // Check if config directory exists (the client is installed)
135
- const configDir = dirname(client.configPath);
136
- client.detected = existsSync(configDir);
137
- // Check if Wyrm is already configured
138
- if (client.detected && existsSync(client.configPath)) {
139
- try {
140
- const content = readFileSync(client.configPath, 'utf-8');
141
- const config = parseJsonWithComments(content);
142
- client.configured = hasWyrmConfig(config, client);
143
- }
144
- catch {
145
- client.configured = false;
146
- }
147
- }
148
- // Try to detect version
149
- if (client.detected) {
150
- client.version = detectClientVersion(client);
151
- }
152
- }
153
- return clients;
154
- }
155
- /**
156
- * Detect the version of an AI client
157
- */
158
- function detectClientVersion(client) {
159
- try {
160
- switch (client.id) {
161
- case 'vscode-copilot':
162
- case 'vscode-insiders': {
163
- const cmd = client.id === 'vscode-insiders' ? 'code-insiders' : 'code';
164
- const result = spawnSync(cmd, ['--version'], { encoding: 'utf-8', timeout: 5000 });
165
- if (result.stdout)
166
- return result.stdout.split('\n')[0];
167
- break;
168
- }
169
- case 'cursor': {
170
- const result = spawnSync('cursor', ['--version'], { encoding: 'utf-8', timeout: 5000 });
171
- if (result.stdout)
172
- return result.stdout.split('\n')[0];
173
- break;
174
- }
175
- }
176
- }
177
- catch {
178
- // Version detection is optional
179
- }
180
- return undefined;
181
- }
182
- /**
183
- * Check if Wyrm is already configured in a client's config
184
- */
185
- function hasWyrmConfig(config, client) {
186
- switch (client.configFormat) {
187
- case 'vscode': {
188
- const mcp = config['mcp'];
189
- const servers = mcp?.['servers'];
190
- return servers?.['wyrm'] !== undefined;
191
- }
192
- case 'mcp-json': {
193
- const servers = config[client.mcpKey];
194
- return servers?.['wyrm'] !== undefined;
195
- }
196
- case 'zed': {
197
- const servers = config[client.mcpKey];
198
- return servers?.['wyrm'] !== undefined;
199
- }
200
- default:
201
- return false;
202
- }
203
- }
204
- // ==================== CONFIGURATION ====================
205
- /**
206
- * Auto-detect Wyrm server path
207
- */
208
- export function findWyrmServerPath() {
209
- // 1. Check if wyrm-mcp binary is in PATH
210
- try {
211
- const result = spawnSync('which', ['wyrm-mcp'], { encoding: 'utf-8', timeout: 5000 });
212
- if (result.stdout?.trim()) {
213
- return result.stdout.trim();
214
- }
215
- }
216
- catch { }
217
- // 2. Check common npm global install locations
218
- try {
219
- const result = spawnSync('npm', ['root', '-g'], { encoding: 'utf-8', timeout: 5000 });
220
- const globalDir = result.stdout?.trim();
221
- if (globalDir) {
222
- const globalPath = join(globalDir, 'wyrm-mcp', 'dist', 'index.js');
223
- if (existsSync(globalPath))
224
- return globalPath;
225
- }
226
- }
227
- catch { }
228
- // 3. Check local development path (relative to this file)
229
- const devPath = resolve(__dirname, 'index.js');
230
- if (existsSync(devPath))
231
- return devPath;
232
- // 4. Check ~/.wyrm/node_modules
233
- const wyrmModulesPath = join(homedir(), '.wyrm', 'node_modules', 'wyrm-mcp', 'dist', 'index.js');
234
- if (existsSync(wyrmModulesPath))
235
- return wyrmModulesPath;
236
- // 5. Check common project locations
237
- const projectLocations = [
238
- join(homedir(), 'Git Projects', 'Wyrm', 'packages', 'mcp-server', 'dist', 'index.js'),
239
- join(homedir(), 'projects', 'Wyrm', 'packages', 'mcp-server', 'dist', 'index.js'),
240
- join(homedir(), 'dev', 'Wyrm', 'packages', 'mcp-server', 'dist', 'index.js'),
241
- ];
242
- for (const loc of projectLocations) {
243
- if (existsSync(loc))
244
- return loc;
245
- }
246
- // 6. Fallback to npx
247
- return 'wyrm-mcp';
248
- }
249
- /**
250
- * Get the default Wyrm database path
251
- */
252
- export function getDefaultDbPath() {
253
- return join(homedir(), '.wyrm', 'wyrm.db');
254
- }
255
- /**
256
- * Build the Wyrm MCP config object for a specific client format
257
- */
258
- function buildWyrmMcpConfig(client, wyrmConfig) {
259
- const serverPath = wyrmConfig.serverPath;
260
- const isNpx = serverPath === 'wyrm-mcp';
261
- const isJsFile = serverPath.endsWith('.js');
262
- switch (client.configFormat) {
263
- case 'vscode':
264
- return {
265
- command: isNpx ? 'npx' : 'node',
266
- args: isNpx ? ['wyrm-mcp'] : [serverPath],
267
- env: {
268
- WYRM_DB: wyrmConfig.dbPath,
269
- },
270
- };
271
- case 'mcp-json':
272
- return {
273
- command: isNpx ? 'npx' : 'node',
274
- args: isNpx ? ['wyrm-mcp'] : [serverPath],
275
- env: {
276
- WYRM_DB: wyrmConfig.dbPath,
277
- },
278
- };
279
- case 'zed':
280
- return {
281
- command: isNpx ? 'npx' : 'node',
282
- args: isNpx ? ['wyrm-mcp'] : [serverPath],
283
- env: {
284
- WYRM_DB: wyrmConfig.dbPath,
285
- },
286
- };
287
- default:
288
- return {};
289
- }
290
- }
291
- /**
292
- * Configure Wyrm in a single AI client
293
- */
294
- export function configureClient(client, wyrmConfig) {
295
- if (!client.detected) {
296
- return {
297
- client,
298
- action: 'skipped',
299
- message: `${client.name} not detected`,
300
- };
301
- }
302
- try {
303
- // Ensure config directory exists
304
- const configDir = dirname(client.configPath);
305
- if (!existsSync(configDir)) {
306
- mkdirSync(configDir, { recursive: true });
307
- }
308
- // Read existing config or create new
309
- let config = {};
310
- let existed = false;
311
- if (existsSync(client.configPath)) {
312
- try {
313
- const content = readFileSync(client.configPath, 'utf-8');
314
- config = parseJsonWithComments(content);
315
- existed = true;
316
- }
317
- catch {
318
- // If config exists but is invalid, start fresh
319
- config = {};
320
- }
321
- }
322
- // Create backup before modifying
323
- let backupPath;
324
- if (existed) {
325
- backupPath = `${client.configPath}.wyrm-backup`;
326
- writeFileSync(backupPath, readFileSync(client.configPath));
327
- }
328
- // Build Wyrm MCP entry
329
- const wyrmEntry = buildWyrmMcpConfig(client, wyrmConfig);
330
- // Inject into config based on format
331
- switch (client.configFormat) {
332
- case 'vscode': {
333
- // VS Code: { "mcp": { "servers": { "wyrm": {...} } } }
334
- if (!config['mcp'])
335
- config['mcp'] = {};
336
- const mcp = config['mcp'];
337
- if (!mcp['servers'])
338
- mcp['servers'] = {};
339
- const servers = mcp['servers'];
340
- servers['wyrm'] = wyrmEntry;
341
- break;
342
- }
343
- case 'mcp-json': {
344
- // MCP JSON: { "mcpServers": { "wyrm": {...} } }
345
- if (!config[client.mcpKey])
346
- config[client.mcpKey] = {};
347
- const servers = config[client.mcpKey];
348
- servers['wyrm'] = wyrmEntry;
349
- break;
350
- }
351
- case 'zed': {
352
- // Zed: { "context_servers": { "wyrm": {...} } }
353
- if (!config[client.mcpKey])
354
- config[client.mcpKey] = {};
355
- const servers = config[client.mcpKey];
356
- servers['wyrm'] = wyrmEntry;
357
- break;
358
- }
359
- }
360
- // Write config back
361
- writeFileSync(client.configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
362
- const action = client.configured ? 'updated' : 'configured';
363
- client.configured = true;
364
- return {
365
- client,
366
- action,
367
- message: `${client.name} ${action === 'configured' ? 'configured' : 'updated'} successfully`,
368
- backup: backupPath,
369
- };
370
- }
371
- catch (error) {
372
- return {
373
- client,
374
- action: 'failed',
375
- message: `Failed to configure ${client.name}: ${error}`,
376
- };
377
- }
378
- }
379
- /**
380
- * Remove Wyrm from a single AI client
381
- */
382
- export function removeFromClient(client) {
383
- if (!client.detected || !client.configured) {
384
- return {
385
- client,
386
- action: 'skipped',
387
- message: `${client.name} not configured`,
388
- };
389
- }
390
- try {
391
- if (!existsSync(client.configPath)) {
392
- return { client, action: 'skipped', message: `${client.name} config not found` };
393
- }
394
- const content = readFileSync(client.configPath, 'utf-8');
395
- const config = parseJsonWithComments(content);
396
- // Create backup
397
- const backupPath = `${client.configPath}.wyrm-backup`;
398
- writeFileSync(backupPath, content);
399
- // Remove Wyrm entry
400
- switch (client.configFormat) {
401
- case 'vscode': {
402
- const mcp = config['mcp'];
403
- const servers = mcp?.['servers'];
404
- if (servers)
405
- delete servers['wyrm'];
406
- break;
407
- }
408
- case 'mcp-json':
409
- case 'zed': {
410
- const servers = config[client.mcpKey];
411
- if (servers)
412
- delete servers['wyrm'];
413
- break;
414
- }
415
- }
416
- writeFileSync(client.configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
417
- client.configured = false;
418
- return {
419
- client,
420
- action: 'configured',
421
- message: `Removed Wyrm from ${client.name}`,
422
- backup: backupPath,
423
- };
424
- }
425
- catch (error) {
426
- return {
427
- client,
428
- action: 'failed',
429
- message: `Failed to remove from ${client.name}: ${error}`,
430
- };
431
- }
432
- }
433
- // ==================== ORCHESTRATION ====================
434
- // ==================== CLAUDE CODE CLI HOOKS ====================
435
- /** Synthetic "client" so hook install/removal renders in the setup summary. */
436
- function claudeHooksClient() {
437
- return {
438
- id: 'claude-code-hooks',
439
- name: 'Claude Code (auto-memory)',
440
- icon: '🪝',
441
- configPath: join(homedir(), '.claude', 'settings.json'),
442
- configFormat: 'mcp-json',
443
- mcpKey: '',
444
- detected: true,
445
- configured: false,
446
- };
447
- }
448
- /**
449
- * Wyrm's Claude Code CLI hooks, each mapped to the lifecycle events it fires on:
450
- * - capture (SessionEnd, PreCompact) : auto-remember every session [save side]
451
- * - rehydrate (SessionStart) : restore prior context [load side]
452
- * - prune (SessionEnd) : opt-in housekeeping (no-op unless
453
- * WYRM_AUTO_PRUNE=1; see the script)
454
- * - tool-trace(PostToolUse) : opt-in Live Memory tool_call trace
455
- * (no-op unless WYRM_TRACE_TOOL_CALLS=1)
456
- */
457
- const CLAUDE_HOOK_SPECS = [
458
- { script: 'wyrm-session-capture.mjs', events: ['SessionEnd', 'PreCompact'] },
459
- { script: 'wyrm-session-rehydrate.mjs', events: ['SessionStart'] },
460
- { script: 'wyrm-session-prune.mjs', events: ['SessionEnd'] },
461
- { script: 'wyrm-tool-call-trace.mjs', events: ['PostToolUse'] },
462
- ];
463
- /**
464
- * Install Wyrm's Claude Code CLI hooks so every session is auto-remembered
465
- * (capture), auto-restored (rehydrate), and optionally tidied (prune). Ships
466
- * the hook scripts next to the user's other hooks and merges the hook entries
467
- * into ~/.claude/settings.json WITHOUT clobbering any hooks already there.
468
- * Idempotent. No-op (returns null) when the Claude Code CLI isn't present.
469
- */
470
- export function installClaudeCodeHooks() {
471
- const claudeDir = join(homedir(), '.claude');
472
- if (!existsSync(claudeDir))
473
- return null; // Claude Code CLI not installed here
474
- const client = claudeHooksClient();
475
- try {
476
- const hooksDir = join(claudeDir, 'hooks');
477
- if (!existsSync(hooksDir))
478
- mkdirSync(hooksDir, { recursive: true });
479
- // Hook scripts live next to dist/ (one level below the package root).
480
- const here = dirname(fileURLToPath(import.meta.url));
481
- const scriptsDir = join(here, '..', 'scripts', 'hooks');
482
- const settingsPath = client.configPath;
483
- let settings = {};
484
- if (existsSync(settingsPath)) {
485
- try {
486
- settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
487
- }
488
- catch {
489
- settings = {};
490
- }
491
- }
492
- const hooks = (settings.hooks ?? {});
493
- let added = false;
494
- const missing = [];
495
- for (const spec of CLAUDE_HOOK_SPECS) {
496
- const src = join(scriptsDir, spec.script);
497
- if (!existsSync(src)) {
498
- missing.push(spec.script);
499
- continue;
500
- } // skip, don't abort the rest
501
- const dest = join(hooksDir, spec.script);
502
- copyFileSync(src, dest);
503
- try {
504
- chmodSync(dest, 0o755);
505
- }
506
- catch { /* non-fatal */ }
507
- const cmd = `node ${dest}`;
508
- for (const event of spec.events) {
509
- const groups = Array.isArray(hooks[event]) ? hooks[event] : [];
510
- const present = groups.some((g) => Array.isArray(g.hooks) && g.hooks.some((h) => h.command === cmd));
511
- if (!present) {
512
- groups.push({ hooks: [{ type: 'command', command: cmd, timeout: 30 }] });
513
- added = true;
514
- }
515
- hooks[event] = groups;
516
- }
517
- }
518
- settings.hooks = hooks;
519
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
520
- client.configured = true;
521
- const note = missing.length ? ` (missing from package: ${missing.join(', ')})` : '';
522
- return { client, action: added ? 'configured' : 'skipped', message: (added ? 'auto-memory hooks installed' : 'already installed') + note };
523
- }
524
- catch (err) {
525
- return { client, action: 'failed', message: err instanceof Error ? err.message : String(err) };
526
- }
527
- }
528
- /**
529
- * Install Wyrm's buddy statusline into Claude Code (`statusLine` in settings.json)
530
- * so the dragon + live memory (project · open quests · blocked failures · truths)
531
- * is visible in the TUI AT ALL TIMES — not just when a tool is called. Won't
532
- * clobber a non-Wyrm statusline the user already configured.
533
- */
534
- export function installClaudeStatusline() {
535
- const claudeDir = join(homedir(), '.claude');
536
- if (!existsSync(claudeDir))
537
- return null;
538
- const client = claudeHooksClient();
539
- try {
540
- const here = dirname(fileURLToPath(import.meta.url)); // dist/
541
- const cmd = `node ${join(here, 'wyrm-statusline.js')}`;
542
- const settingsPath = client.configPath;
543
- let settings = {};
544
- if (existsSync(settingsPath)) {
545
- try {
546
- settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
547
- }
548
- catch {
549
- settings = {};
550
- }
551
- }
552
- const existing = settings.statusLine;
553
- if (existing?.command && !/wyrm-statusline/.test(existing.command)) {
554
- return { client, action: 'skipped', message: `a non-Wyrm statusLine is already set (${existing.command}); not overwriting` };
555
- }
556
- const already = existing?.command === cmd;
557
- settings.statusLine = { type: 'command', command: cmd, padding: 0 };
558
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
559
- return { client, action: already ? 'skipped' : 'configured', message: already ? 'buddy statusline already installed' : 'Wyrm buddy statusline installed — persistent in the Claude Code TUI' };
560
- }
561
- catch (err) {
562
- return { client, action: 'failed', message: err instanceof Error ? err.message : String(err) };
563
- }
564
- }
565
- /** Remove the Wyrm statusline from settings.json (leaves any non-Wyrm one). */
566
- export function removeClaudeStatusline() {
567
- const settingsPath = join(homedir(), '.claude', 'settings.json');
568
- if (!existsSync(settingsPath))
569
- return null;
570
- const client = claudeHooksClient();
571
- try {
572
- const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
573
- const sl = settings.statusLine;
574
- if (sl?.command && /wyrm-statusline/.test(sl.command)) {
575
- delete settings.statusLine;
576
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
577
- return { client, action: 'configured', message: 'Wyrm statusline removed' };
578
- }
579
- return { client, action: 'skipped', message: 'no Wyrm statusline set' };
580
- }
581
- catch (err) {
582
- return { client, action: 'failed', message: err instanceof Error ? err.message : String(err) };
583
- }
584
- }
585
- /** Remove all Wyrm hooks from ~/.claude/settings.json (leaves other hooks). */
586
- export function removeClaudeCodeHooks() {
587
- const settingsPath = join(homedir(), '.claude', 'settings.json');
588
- if (!existsSync(settingsPath))
589
- return null;
590
- const client = claudeHooksClient();
591
- try {
592
- const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
593
- const hooksDir = join(homedir(), '.claude', 'hooks');
594
- const ourCmds = new Set(CLAUDE_HOOK_SPECS.map((s) => `node ${join(hooksDir, s.script)}`));
595
- const ourEvents = new Set(CLAUDE_HOOK_SPECS.flatMap((s) => s.events));
596
- const hooks = settings.hooks;
597
- if (hooks) {
598
- for (const event of ourEvents) {
599
- if (!Array.isArray(hooks[event]))
600
- continue;
601
- hooks[event] = hooks[event]
602
- .map((g) => ({ ...g, hooks: Array.isArray(g.hooks) ? g.hooks.filter((h) => !ourCmds.has(h.command ?? '')) : g.hooks }))
603
- .filter((g) => !Array.isArray(g.hooks) || g.hooks.length > 0);
604
- if (hooks[event].length === 0)
605
- delete hooks[event];
606
- }
607
- if (Object.keys(hooks).length === 0)
608
- delete settings.hooks;
609
- }
610
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
611
- return { client, action: 'configured', message: 'auto-memory hooks removed' };
612
- }
613
- catch (err) {
614
- return { client, action: 'failed', message: err instanceof Error ? err.message : String(err) };
615
- }
616
- }
617
- /**
618
- * Auto-configure Wyrm in ALL detected AI clients
619
- */
620
- export function autoConfigureAll(wyrmConfig) {
621
- const config = {
622
- serverPath: wyrmConfig?.serverPath || findWyrmServerPath(),
623
- dbPath: wyrmConfig?.dbPath || getDefaultDbPath(),
624
- httpPort: wyrmConfig?.httpPort,
625
- };
626
- // Ensure .wyrm directory exists
627
- const wyrmDir = join(homedir(), '.wyrm');
628
- if (!existsSync(wyrmDir)) {
629
- mkdirSync(wyrmDir, { recursive: true });
630
- }
631
- // Save Wyrm's own config for future reference
632
- saveWyrmMeta(config);
633
- const clients = detectClients();
634
- const results = [];
635
- for (const client of clients) {
636
- results.push(configureClient(client, config));
637
- }
638
- // Install Claude Code CLI auto-capture hooks (no-op if the CLI isn't present).
639
- const hookResult = installClaudeCodeHooks();
640
- if (hookResult)
641
- results.push(hookResult);
642
- return results;
643
- }
644
- /**
645
- * Remove Wyrm from ALL AI clients
646
- */
647
- export function removeFromAll() {
648
- const clients = detectClients();
649
- const results = [];
650
- for (const client of clients) {
651
- results.push(removeFromClient(client));
652
- }
653
- const hookResult = removeClaudeCodeHooks();
654
- if (hookResult)
655
- results.push(hookResult);
656
- return results;
657
- }
658
- /**
659
- * Configure Wyrm in specific clients only
660
- */
661
- export function configureSpecific(clientIds, wyrmConfig) {
662
- const config = {
663
- serverPath: wyrmConfig?.serverPath || findWyrmServerPath(),
664
- dbPath: wyrmConfig?.dbPath || getDefaultDbPath(),
665
- httpPort: wyrmConfig?.httpPort,
666
- };
667
- saveWyrmMeta(config);
668
- const clients = detectClients();
669
- const results = [];
670
- for (const client of clients) {
671
- if (clientIds.includes(client.id)) {
672
- results.push(configureClient(client, config));
673
- }
674
- }
675
- return results;
676
- }
677
- /**
678
- * Save Wyrm's meta configuration for auto-updates
679
- */
680
- function saveWyrmMeta(config) {
681
- const metaPath = join(homedir(), '.wyrm', 'wyrm-config.json');
682
- const clients = detectClients().filter(c => c.configured).map(c => c.id);
683
- const meta = {
684
- version: '3.0.0',
685
- serverPath: config.serverPath,
686
- dbPath: config.dbPath,
687
- httpPort: config.httpPort,
688
- configuredClients: clients,
689
- lastSetup: new Date().toISOString(),
690
- autoUpdate: true,
691
- };
692
- writeFileSync(metaPath, JSON.stringify(meta, null, 2) + '\n', 'utf-8');
693
- }
694
- /**
695
- * Load Wyrm's meta configuration
696
- */
697
- export function loadWyrmMeta() {
698
- const metaPath = join(homedir(), '.wyrm', 'wyrm-config.json');
699
- if (!existsSync(metaPath))
700
- return null;
701
- try {
702
- return JSON.parse(readFileSync(metaPath, 'utf-8'));
703
- }
704
- catch {
705
- return null;
706
- }
707
- }
708
- /**
709
- * Re-configure all previously configured clients (for use after updates)
710
- */
711
- export function reconfAll() {
712
- const meta = loadWyrmMeta();
713
- if (!meta) {
714
- return autoConfigureAll();
715
- }
716
- return configureSpecific(meta.configuredClients, {
717
- serverPath: meta.serverPath,
718
- dbPath: meta.dbPath,
719
- httpPort: meta.httpPort,
720
- });
721
- }
722
- // ==================== SYSTEM PROMPT INJECTION ====================
723
- const WYRM_MARKER_START = '<!-- wyrm:start -->';
724
- const WYRM_MARKER_END = '<!-- wyrm:end -->';
725
- export const WYRM_INJECT_BLOCK = `${WYRM_MARKER_START}
726
- ## Wyrm Memory + Agent (auto-managed — do not edit this section)
1
+ import{existsSync as u,readFileSync as p,writeFileSync as f,mkdirSync as k,copyFileSync as J,chmodSync as B}from"fs";import{homedir as m,platform as I}from"os";import{join as n,dirname as y,resolve as T}from"path";import{fileURLToPath as O}from"url";import{spawnSync as P}from"child_process";function U(){const e=m(),t=I(),s=t==="darwin"?n(e,"Library","Application Support","Code","User"):t==="win32"?n(e,"AppData","Roaming","Code","User"):n(e,".config","Code","User"),o=t==="darwin"?n(e,"Library","Application Support","Code - Insiders","User"):t==="win32"?n(e,"AppData","Roaming","Code - Insiders","User"):n(e,".config","Code - Insiders","User"),c=t==="darwin"?n(e,"Library","Application Support","Claude"):t==="win32"?n(e,"AppData","Roaming","Claude"):n(e,".config","claude"),r=t==="darwin"?n(e,".cursor"):t==="win32"?n(e,".cursor"):n(e,".cursor"),i=t==="darwin"?n(e,".codeium","windsurf"):t==="win32"?n(e,".codeium","windsurf"):n(e,".codeium","windsurf"),a=t==="darwin"?n(e,".config","zed"):t==="win32"?n(e,"AppData","Roaming","Zed"):n(e,".config","zed"),d=n(e,".continue");return[{id:"vscode-copilot",name:"VS Code (Copilot)",icon:"\u{1F4BB}",configPath:n(s,"settings.json"),configFormat:"vscode",mcpKey:"mcp.servers",detected:!1,configured:!1},{id:"vscode-insiders",name:"VS Code Insiders",icon:"\u{1F7E2}",configPath:n(o,"settings.json"),configFormat:"vscode",mcpKey:"mcp.servers",detected:!1,configured:!1},{id:"claude-desktop",name:"Claude Desktop",icon:"\u{1F916}",configPath:n(c,"claude_desktop_config.json"),configFormat:"mcp-json",mcpKey:"mcpServers",detected:!1,configured:!1},{id:"cursor",name:"Cursor",icon:"\u{1F4D0}",configPath:n(r,"mcp.json"),configFormat:"mcp-json",mcpKey:"mcpServers",detected:!1,configured:!1},{id:"windsurf",name:"Windsurf",icon:"\u{1F3C4}",configPath:n(i,"mcp_config.json"),configFormat:"mcp-json",mcpKey:"mcpServers",detected:!1,configured:!1},{id:"zed",name:"Zed",icon:"\u26A1",configPath:n(a,"settings.json"),configFormat:"zed",mcpKey:"context_servers",detected:!1,configured:!1},{id:"continue",name:"Continue",icon:"\u{1F504}",configPath:n(d,"config.json"),configFormat:"mcp-json",mcpKey:"mcpServers",detected:!1,configured:!1}]}function w(){const e=U();for(const t of e){const s=y(t.configPath);if(t.detected=u(s),t.detected&&u(t.configPath))try{const o=p(t.configPath,"utf-8"),c=W(o);t.configured=Y(c,t)}catch{t.configured=!1}t.detected&&(t.version=z(t))}return e}function z(e){try{switch(e.id){case"vscode-copilot":case"vscode-insiders":{const t=e.id==="vscode-insiders"?"code-insiders":"code",s=P(t,["--version"],{encoding:"utf-8",timeout:5e3});if(s.stdout)return s.stdout.split(`
2
+ `)[0];break}case"cursor":{const t=P("cursor",["--version"],{encoding:"utf-8",timeout:5e3});if(t.stdout)return t.stdout.split(`
3
+ `)[0];break}}}catch{}}function Y(e,t){switch(t.configFormat){case"vscode":return e.mcp?.servers?.wyrm!==void 0;case"mcp-json":return e[t.mcpKey]?.wyrm!==void 0;case"zed":return e[t.mcpKey]?.wyrm!==void 0;default:return!1}}function K(){try{const o=P("which",["wyrm-mcp"],{encoding:"utf-8",timeout:5e3});if(o.stdout?.trim())return o.stdout.trim()}catch{}try{const c=P("npm",["root","-g"],{encoding:"utf-8",timeout:5e3}).stdout?.trim();if(c){const r=n(c,"wyrm-mcp","dist","index.js");if(u(r))return r}}catch{}const e=T(__dirname,"index.js");if(u(e))return e;const t=n(m(),".wyrm","node_modules","wyrm-mcp","dist","index.js");if(u(t))return t;const s=[n(m(),"Git Projects","Wyrm","packages","mcp-server","dist","index.js"),n(m(),"projects","Wyrm","packages","mcp-server","dist","index.js"),n(m(),"dev","Wyrm","packages","mcp-server","dist","index.js")];for(const o of s)if(u(o))return o;return"wyrm-mcp"}function F(){return n(m(),".wyrm","wyrm.db")}function q(e,t){const s=t.serverPath,o=s==="wyrm-mcp",c=s.endsWith(".js");switch(e.configFormat){case"vscode":return{command:o?"npx":"node",args:o?["wyrm-mcp"]:[s],env:{WYRM_DB:t.dbPath}};case"mcp-json":return{command:o?"npx":"node",args:o?["wyrm-mcp"]:[s],env:{WYRM_DB:t.dbPath}};case"zed":return{command:o?"npx":"node",args:o?["wyrm-mcp"]:[s],env:{WYRM_DB:t.dbPath}};default:return{}}}function R(e,t){if(!e.detected)return{client:e,action:"skipped",message:`${e.name} not detected`};try{const s=y(e.configPath);u(s)||k(s,{recursive:!0});let o={},c=!1;if(u(e.configPath))try{const d=p(e.configPath,"utf-8");o=W(d),c=!0}catch{o={}}let r;c&&(r=`${e.configPath}.wyrm-backup`,f(r,p(e.configPath)));const i=q(e,t);switch(e.configFormat){case"vscode":{o.mcp||(o.mcp={});const d=o.mcp;d.servers||(d.servers={});const l=d.servers;l.wyrm=i;break}case"mcp-json":{o[e.mcpKey]||(o[e.mcpKey]={});const d=o[e.mcpKey];d.wyrm=i;break}case"zed":{o[e.mcpKey]||(o[e.mcpKey]={});const d=o[e.mcpKey];d.wyrm=i;break}}f(e.configPath,JSON.stringify(o,null,2)+`
4
+ `,"utf-8");const a=e.configured?"updated":"configured";return e.configured=!0,{client:e,action:a,message:`${e.name} ${a==="configured"?"configured":"updated"} successfully`,backup:r}}catch(s){return{client:e,action:"failed",message:`Failed to configure ${e.name}: ${s}`}}}function H(e){if(!e.detected||!e.configured)return{client:e,action:"skipped",message:`${e.name} not configured`};try{if(!u(e.configPath))return{client:e,action:"skipped",message:`${e.name} config not found`};const t=p(e.configPath,"utf-8"),s=W(t),o=`${e.configPath}.wyrm-backup`;switch(f(o,t),e.configFormat){case"vscode":{const r=s.mcp?.servers;r&&delete r.wyrm;break}case"mcp-json":case"zed":{const c=s[e.mcpKey];c&&delete c.wyrm;break}}return f(e.configPath,JSON.stringify(s,null,2)+`
5
+ `,"utf-8"),e.configured=!1,{client:e,action:"configured",message:`Removed Wyrm from ${e.name}`,backup:o}}catch(t){return{client:e,action:"failed",message:`Failed to remove from ${e.name}: ${t}`}}}function b(){return{id:"claude-code-hooks",name:"Claude Code (auto-memory)",icon:"\u{1FA9D}",configPath:n(m(),".claude","settings.json"),configFormat:"mcp-json",mcpKey:"",detected:!0,configured:!1}}const x=[{script:"wyrm-session-capture.mjs",events:["SessionEnd","PreCompact"]},{script:"wyrm-session-rehydrate.mjs",events:["SessionStart"]},{script:"wyrm-session-prune.mjs",events:["SessionEnd"]},{script:"wyrm-tool-call-trace.mjs",events:["PostToolUse"]}];function V(){const e=n(m(),".claude");if(!u(e))return null;const t=b();try{const s=n(e,"hooks");u(s)||k(s,{recursive:!0});const o=y(O(import.meta.url)),c=n(o,"..","scripts","hooks"),r=t.configPath;let i={};if(u(r))try{i=JSON.parse(p(r,"utf-8"))}catch{i={}}const a=i.hooks??{};let d=!1;const l=[];for(const h of x){const v=n(c,h.script);if(!u(v)){l.push(h.script);continue}const S=n(s,h.script);J(v,S);try{B(S,493)}catch{}const A=`node ${S}`;for(const _ of h.events){const j=Array.isArray(a[_])?a[_]:[];j.some(D=>Array.isArray(D.hooks)&&D.hooks.some(N=>N.command===A))||(j.push({hooks:[{type:"command",command:A,timeout:30}]}),d=!0),a[_]=j}}i.hooks=a,f(r,JSON.stringify(i,null,2)+`
6
+ `,"utf-8"),t.configured=!0;const g=l.length?` (missing from package: ${l.join(", ")})`:"";return{client:t,action:d?"configured":"skipped",message:(d?"auto-memory hooks installed":"already installed")+g}}catch(s){return{client:t,action:"failed",message:s instanceof Error?s.message:String(s)}}}function ne(){const e=n(m(),".claude");if(!u(e))return null;const t=b();try{const s=y(O(import.meta.url)),o=`node ${n(s,"wyrm-statusline.js")}`,c=t.configPath;let r={};if(u(c))try{r=JSON.parse(p(c,"utf-8"))}catch{r={}}const i=r.statusLine;if(i?.command&&!/wyrm-statusline/.test(i.command))return{client:t,action:"skipped",message:`a non-Wyrm statusLine is already set (${i.command}); not overwriting`};const a=i?.command===o;return r.statusLine={type:"command",command:o,padding:0},f(c,JSON.stringify(r,null,2)+`
7
+ `,"utf-8"),{client:t,action:a?"skipped":"configured",message:a?"buddy statusline already installed":"Wyrm buddy statusline installed \u2014 persistent in the Claude Code TUI"}}catch(s){return{client:t,action:"failed",message:s instanceof Error?s.message:String(s)}}}function ce(){const e=n(m(),".claude","settings.json");if(!u(e))return null;const t=b();try{const s=JSON.parse(p(e,"utf-8")),o=s.statusLine;return o?.command&&/wyrm-statusline/.test(o.command)?(delete s.statusLine,f(e,JSON.stringify(s,null,2)+`
8
+ `,"utf-8"),{client:t,action:"configured",message:"Wyrm statusline removed"}):{client:t,action:"skipped",message:"no Wyrm statusline set"}}catch(s){return{client:t,action:"failed",message:s instanceof Error?s.message:String(s)}}}function G(){const e=n(m(),".claude","settings.json");if(!u(e))return null;const t=b();try{const s=JSON.parse(p(e,"utf-8")),o=n(m(),".claude","hooks"),c=new Set(x.map(a=>`node ${n(o,a.script)}`)),r=new Set(x.flatMap(a=>a.events)),i=s.hooks;if(i){for(const a of r)Array.isArray(i[a])&&(i[a]=i[a].map(d=>({...d,hooks:Array.isArray(d.hooks)?d.hooks.filter(l=>!c.has(l.command??"")):d.hooks})).filter(d=>!Array.isArray(d.hooks)||d.hooks.length>0),i[a].length===0&&delete i[a]);Object.keys(i).length===0&&delete s.hooks}return f(e,JSON.stringify(s,null,2)+`
9
+ `,"utf-8"),{client:t,action:"configured",message:"auto-memory hooks removed"}}catch(s){return{client:t,action:"failed",message:s instanceof Error?s.message:String(s)}}}function Q(e){const t={serverPath:e?.serverPath||K(),dbPath:e?.dbPath||F(),httpPort:e?.httpPort},s=n(m(),".wyrm");u(s)||k(s,{recursive:!0}),E(t);const o=w(),c=[];for(const i of o)c.push(R(i,t));const r=V();return r&&c.push(r),c}function ie(){const e=w(),t=[];for(const o of e)t.push(H(o));const s=G();return s&&t.push(s),t}function Z(e,t){const s={serverPath:t?.serverPath||K(),dbPath:t?.dbPath||F(),httpPort:t?.httpPort};E(s);const o=w(),c=[];for(const r of o)e.includes(r.id)&&c.push(R(r,s));return c}function E(e){const t=n(m(),".wyrm","wyrm-config.json"),s=w().filter(c=>c.configured).map(c=>c.id),o={version:"3.0.0",serverPath:e.serverPath,dbPath:e.dbPath,httpPort:e.httpPort,configuredClients:s,lastSetup:new Date().toISOString(),autoUpdate:!0};f(t,JSON.stringify(o,null,2)+`
10
+ `,"utf-8")}function L(){const e=n(m(),".wyrm","wyrm-config.json");if(!u(e))return null;try{return JSON.parse(p(e,"utf-8"))}catch{return null}}function ae(){const e=L();return e?Z(e.configuredClients,{serverPath:e.serverPath,dbPath:e.dbPath,httpPort:e.httpPort}):Q()}const M="<!-- wyrm:start -->",C="<!-- wyrm:end -->",$=`${M}
11
+ ## Wyrm Memory + Agent (auto-managed \u2014 do not edit this section)
727
12
 
728
- **Session start** call \`wyrm_session_prime\` first to load project context (ground truths, open quests, recent sessions, scaffolds) before responding.
13
+ **Session start** \u2014 call \`wyrm_session_prime\` first to load project context (ground truths, open quests, recent sessions, scaffolds) before responding.
729
14
 
730
- **Set goals declaratively** when the operator describes a multi-step or recurring objective ("ship v2", "audit auth weekly", "keep dependencies updated"), call \`wyrm_goal_set\` with a clear \`success_criteria\`. Goals persist across sessions and the agent loop will pursue them.
15
+ **Set goals declaratively** \u2014 when the operator describes a multi-step or recurring objective ("ship v2", "audit auth weekly", "keep dependencies updated"), call \`wyrm_goal_set\` with a clear \`success_criteria\`. Goals persist across sessions and the agent loop will pursue them.
731
16
 
732
- **Bootstrap the autonomous agent** if the operator wants ongoing autonomous work, call \`wyrm_agent_init\` once. This starts the \`wyrm-loop\` background daemon that runs OODA iterations on active goals every \`interval_seconds\` (default 10 min). The same call can seed the first goal via \`seed_goal\`. Verify with \`wyrm_agent_status\`; stop with \`wyrm_agent_stop\`.
17
+ **Bootstrap the autonomous agent** \u2014 if the operator wants ongoing autonomous work, call \`wyrm_agent_init\` once. This starts the \`wyrm-loop\` background daemon that runs OODA iterations on active goals every \`interval_seconds\` (default 10 min). The same call can seed the first goal via \`seed_goal\`. Verify with \`wyrm_agent_status\`; stop with \`wyrm_agent_stop\`.
733
18
 
734
- **Counter-pattern check** before proposing a fix in an area with prior failures, call \`wyrm_failure_check\` first. Wyrm blocks repeated identical mistakes.
19
+ **Counter-pattern check** \u2014 before proposing a fix in an area with prior failures, call \`wyrm_failure_check\` first. Wyrm blocks repeated identical mistakes.
735
20
 
736
- **Record what failed** when a fix doesn't work, call \`wyrm_failure_record\` so future sessions don't repeat it.
21
+ **Record what failed** \u2014 when a fix doesn't work, call \`wyrm_failure_record\` so future sessions don't repeat it.
737
22
 
738
- **Cite memory in answers** when surfacing memory, name the source (e.g., "per truth tech_stack.database = PostgreSQL 15" or "session #142 noted X"). Tagged citations help the operator audit trust.
23
+ **Cite memory in answers** \u2014 when surfacing memory, name the source (e.g., "per truth tech_stack.database = PostgreSQL 15" or "session #142 noted X"). Tagged citations help the operator audit trust.
739
24
 
740
- **Attribute Wyrm visibly** when you used Wyrm to answer something (loaded a truth, blocked a failure, cited a quest, primed from a past session), say so in plain English. Example: _"Wyrm reminded me that you decided on PostgreSQL last week, so I'm building this for Postgres"_. Operators often don't realise Wyrm is contributing naming the contribution makes the value visible. Do NOT silently absorb Wyrm data and present it as your own knowledge.
25
+ **Attribute Wyrm visibly** \u2014 when you used Wyrm to answer something (loaded a truth, blocked a failure, cited a quest, primed from a past session), say so in plain English. Example: _"Wyrm reminded me that you decided on PostgreSQL last week, so I'm building this for Postgres"_. Operators often don't realise Wyrm is contributing \u2014 naming the contribution makes the value visible. Do NOT silently absorb Wyrm data and present it as your own knowledge.
741
26
 
742
- **Explain Wyrm on request** if the operator asks "what does Wyrm do?", "what is Wyrm?", "is Wyrm even working?", or seems confused about Wyrm's role, call \`wyrm_intro\` for a plain-English explanation. For "what has Wyrm done for me?" call \`wyrm_digest\`. These tools speak to humans, not to you.
27
+ **Explain Wyrm on request** \u2014 if the operator asks "what does Wyrm do?", "what is Wyrm?", "is Wyrm even working?", or seems confused about Wyrm's role, call \`wyrm_intro\` for a plain-English explanation. For "what has Wyrm done for me?" call \`wyrm_digest\`. These tools speak to humans, not to you.
743
28
 
744
- **Know what Wyrm can do** call \`wyrm_capabilities\` once per session to get the full feature inventory (counter-patterns, ground truths, scaffolds, agent loop, outbound MCP, federation, audit chain, ). Reach for the right tool the first time instead of re-discovering the surface mid-conversation.
29
+ **Know what Wyrm can do** \u2014 call \`wyrm_capabilities\` once per session to get the full feature inventory (counter-patterns, ground truths, scaffolds, agent loop, outbound MCP, federation, audit chain, \u2026). Reach for the right tool the first time instead of re-discovering the surface mid-conversation.
745
30
 
746
- **Keep wyrm-mcp current** \`wyrm_check_update\` returns whether a newer version is on npm (cached 24h). When one is, surface it to the operator and offer \`wyrm_self_update\` (with \`confirm:true\`) to upgrade.
31
+ **Keep wyrm-mcp current** \u2014 \`wyrm_check_update\` returns whether a newer version is on npm (cached 24h). When one is, surface it to the operator and offer \`wyrm_self_update\` (with \`confirm:true\`) to upgrade.
747
32
 
748
- **Buddy companion** call \`wyrm_buddy\` for warm, data-grounded check-ins. At session start (after \`wyrm_session_prime\`) for long-running work, and when the operator completes a quest or hits a milestone. The buddy speaks in a chosen persona but every claim sources a real DB row speak it verbatim, never invent additional encouragement. Auto-federates with other registered MCPs that expose \`*_buddy\` tools.
749
- ${WYRM_MARKER_END}`;
750
- /**
751
- * Inject Wyrm's session-prime instruction block into AI client instruction files.
752
- * Supports copilot (.github/copilot-instructions.md) and cursor (.cursor/rules).
753
- * Uses marker comments to manage the block idempotently (safe to call multiple times).
754
- */
755
- export function injectSystemPrompt(projectPath, clients) {
756
- const result = { injected: [], skipped: [], errors: [] };
757
- const writeWithMarker = (filePath, label) => {
758
- try {
759
- const dir = dirname(filePath);
760
- if (!existsSync(dir))
761
- mkdirSync(dir, { recursive: true });
762
- if (existsSync(filePath)) {
763
- const existing = readFileSync(filePath, 'utf-8');
764
- const startIdx = existing.indexOf(WYRM_MARKER_START);
765
- const endIdx = existing.indexOf(WYRM_MARKER_END);
766
- if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
767
- // Replace existing block
768
- const before = existing.slice(0, startIdx);
769
- const after = existing.slice(endIdx + WYRM_MARKER_END.length);
770
- writeFileSync(filePath, `${before}${WYRM_INJECT_BLOCK}${after}`, 'utf-8');
771
- }
772
- else {
773
- // Append block (ensure newline separation)
774
- const sep = existing.endsWith('\n') ? '\n' : '\n\n';
775
- writeFileSync(filePath, `${existing}${sep}${WYRM_INJECT_BLOCK}\n`, 'utf-8');
776
- }
777
- }
778
- else {
779
- writeFileSync(filePath, `${WYRM_INJECT_BLOCK}\n`, 'utf-8');
780
- }
781
- result.injected.push(label);
782
- }
783
- catch (e) {
784
- result.errors.push(`${label}: ${e}`);
785
- }
786
- };
787
- const allClients = clients.length === 0
788
- ? ['copilot', 'cursor']
789
- : clients;
790
- for (const client of allClients) {
791
- const lc = client.toLowerCase();
792
- if (lc === 'copilot' || lc === 'vscode-copilot') {
793
- const filePath = join(projectPath, '.github', 'copilot-instructions.md');
794
- writeWithMarker(filePath, '.github/copilot-instructions.md');
795
- }
796
- else if (lc === 'cursor') {
797
- const filePath = join(projectPath, '.cursor', 'rules');
798
- writeWithMarker(filePath, '.cursor/rules');
799
- }
800
- else {
801
- result.skipped.push(client);
802
- }
803
- }
804
- return result;
805
- }
806
- // ==================== UTILITIES ====================
807
- /**
808
- * Parse JSON with comments (JSONC) - handles VS Code settings files
809
- */
810
- function parseJsonWithComments(text) {
811
- // Strip single-line comments
812
- let cleaned = text.replace(/\/\/.*$/gm, '');
813
- // Strip multi-line comments
814
- cleaned = cleaned.replace(/\/\*[\s\S]*?\*\//g, '');
815
- // Handle trailing commas (common in VS Code settings)
816
- cleaned = cleaned.replace(/,\s*([\]}])/g, '$1');
817
- return JSON.parse(cleaned);
818
- }
819
- /**
820
- * Get a friendly status summary of all AI clients
821
- */
822
- export function getStatusSummary() {
823
- const clients = detectClients();
824
- const detected = clients.filter(c => c.detected);
825
- const configured = clients.filter(c => c.configured);
826
- let summary = `󱅝 Wyrm Auto-Configure Status\n\n`;
827
- summary += ` Detected: ${detected.length}/${clients.length} AI clients\n`;
828
- summary += ` Configured: ${configured.length}/${detected.length} clients\n\n`;
829
- for (const client of clients) {
830
- const status = !client.detected
831
- ? ' ○' // Not installed
832
- : client.configured
833
- ? ' ●' // Configured
834
- : ' ◐'; // Installed but not configured
835
- const versionStr = client.version ? ` (${client.version})` : '';
836
- const statusLabel = !client.detected
837
- ? 'not found'
838
- : client.configured
839
- ? 'configured ✓'
840
- : 'detected — not configured';
841
- summary += `${status} ${client.icon} ${client.name}${versionStr}: ${statusLabel}\n`;
842
- }
843
- const meta = loadWyrmMeta();
844
- if (meta) {
845
- summary += `\n Server: ${meta.serverPath}\n`;
846
- summary += ` DB: ${meta.dbPath}\n`;
847
- summary += ` Last: ${new Date(meta.lastSetup).toLocaleString()}\n`;
848
- }
849
- return summary;
850
- }
851
- //# sourceMappingURL=autoconfig.js.map
33
+ **Buddy companion** \u2014 call \`wyrm_buddy\` for warm, data-grounded check-ins. At session start (after \`wyrm_session_prime\`) for long-running work, and when the operator completes a quest or hits a milestone. The buddy speaks in a chosen persona but every claim sources a real DB row \u2014 speak it verbatim, never invent additional encouragement. Auto-federates with other registered MCPs that expose \`*_buddy\` tools.
34
+ ${C}`;function de(e,t){const s={injected:[],skipped:[],errors:[]},o=(r,i)=>{try{const a=y(r);if(u(a)||k(a,{recursive:!0}),u(r)){const d=p(r,"utf-8"),l=d.indexOf(M),g=d.indexOf(C);if(l!==-1&&g!==-1&&g>l){const h=d.slice(0,l),v=d.slice(g+C.length);f(r,`${h}${$}${v}`,"utf-8")}else{const h=d.endsWith(`
35
+ `)?`
36
+ `:`
37
+
38
+ `;f(r,`${d}${h}${$}
39
+ `,"utf-8")}}else f(r,`${$}
40
+ `,"utf-8");s.injected.push(i)}catch(a){s.errors.push(`${i}: ${a}`)}},c=t.length===0?["copilot","cursor"]:t;for(const r of c){const i=r.toLowerCase();if(i==="copilot"||i==="vscode-copilot"){const a=n(e,".github","copilot-instructions.md");o(a,".github/copilot-instructions.md")}else if(i==="cursor"){const a=n(e,".cursor","rules");o(a,".cursor/rules")}else s.skipped.push(r)}return s}function W(e){let t=e.replace(/\/\/.*$/gm,"");return t=t.replace(/\/\*[\s\S]*?\*\//g,""),t=t.replace(/,\s*([\]}])/g,"$1"),JSON.parse(t)}function ue(){const e=w(),t=e.filter(r=>r.detected),s=e.filter(r=>r.configured);let o=`\u{F115D} Wyrm Auto-Configure Status
41
+
42
+ `;o+=` Detected: ${t.length}/${e.length} AI clients
43
+ `,o+=` Configured: ${s.length}/${t.length} clients
44
+
45
+ `;for(const r of e){const i=r.detected?r.configured?" \u25CF":" \u25D0":" \u25CB",a=r.version?` (${r.version})`:"",d=r.detected?r.configured?"configured \u2713":"detected \u2014 not configured":"not found";o+=`${i} ${r.icon} ${r.name}${a}: ${d}
46
+ `}const c=L();return c&&(o+=`
47
+ Server: ${c.serverPath}
48
+ `,o+=` DB: ${c.dbPath}
49
+ `,o+=` Last: ${new Date(c.lastSetup).toLocaleString()}
50
+ `),o}export{$ as WYRM_INJECT_BLOCK,Q as autoConfigureAll,R as configureClient,Z as configureSpecific,w as detectClients,K as findWyrmServerPath,F as getDefaultDbPath,ue as getStatusSummary,de as injectSystemPrompt,V as installClaudeCodeHooks,ne as installClaudeStatusline,L as loadWyrmMeta,ae as reconfAll,G as removeClaudeCodeHooks,ce as removeClaudeStatusline,ie as removeFromAll,H as removeFromClient};