@ulpi/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +200 -0
  3. package/dist/auth-PN7TMQHV-2W4ICG64.js +15 -0
  4. package/dist/chunk-247GVVKK.js +2259 -0
  5. package/dist/chunk-2CLNOKPA.js +793 -0
  6. package/dist/chunk-2HEE5OKX.js +79 -0
  7. package/dist/chunk-2MZER6ND.js +415 -0
  8. package/dist/chunk-3SBPZRB5.js +772 -0
  9. package/dist/chunk-4VNS5WPM.js +42 -0
  10. package/dist/chunk-6JCMYYBT.js +1546 -0
  11. package/dist/chunk-6OCEY7JY.js +422 -0
  12. package/dist/chunk-74WVVWJ4.js +375 -0
  13. package/dist/chunk-7AL4DOEJ.js +131 -0
  14. package/dist/chunk-7LXY5UVC.js +330 -0
  15. package/dist/chunk-DBMUNBNB.js +3048 -0
  16. package/dist/chunk-JWUUVXIV.js +13694 -0
  17. package/dist/chunk-KIKPIH6N.js +4048 -0
  18. package/dist/chunk-KLEASXUR.js +70 -0
  19. package/dist/chunk-MIAQVCFW.js +39 -0
  20. package/dist/chunk-NNUWU6CV.js +1610 -0
  21. package/dist/chunk-PKD4ASEM.js +115 -0
  22. package/dist/chunk-Q4HIY43N.js +4230 -0
  23. package/dist/chunk-QJ5GSMEC.js +146 -0
  24. package/dist/chunk-SIAQVRKG.js +2163 -0
  25. package/dist/chunk-SPOI23SB.js +197 -0
  26. package/dist/chunk-YM2HV4IA.js +505 -0
  27. package/dist/codemap-RRJIDBQ5.js +636 -0
  28. package/dist/config-EGAXXCGL.js +127 -0
  29. package/dist/dist-6G7JC2RA.js +90 -0
  30. package/dist/dist-7LHZ65GC.js +418 -0
  31. package/dist/dist-LZKZFPVX.js +140 -0
  32. package/dist/dist-R5F4MX3I.js +107 -0
  33. package/dist/dist-R5ZJ4LX5.js +56 -0
  34. package/dist/dist-RJGCUS3L.js +87 -0
  35. package/dist/dist-RKOGLK7R.js +151 -0
  36. package/dist/dist-W7K4WPAF.js +597 -0
  37. package/dist/export-import-4A5MWLIA.js +53 -0
  38. package/dist/history-ATTUKOHO.js +934 -0
  39. package/dist/index.js +2120 -0
  40. package/dist/init-AY5C2ZAS.js +393 -0
  41. package/dist/launchd-LF2QMSKZ.js +148 -0
  42. package/dist/log-TVTUXAYD.js +75 -0
  43. package/dist/mcp-installer-NQCGKQ23.js +124 -0
  44. package/dist/memory-J3G24QHS.js +406 -0
  45. package/dist/ollama-3XCUZMZT-FYKHW4TZ.js +7 -0
  46. package/dist/openai-E7G2YAHU-UYY4ZWON.js +8 -0
  47. package/dist/projects-ATHDD3D6.js +271 -0
  48. package/dist/review-ADUPV3PN.js +152 -0
  49. package/dist/rules-E427DKYJ.js +134 -0
  50. package/dist/server-MOYPE4SM-N7SE2AN7.js +18 -0
  51. package/dist/server-X5P6WH2M-7K2RY34N.js +11 -0
  52. package/dist/skills/ulpi-generate-guardian/SKILL.md +511 -0
  53. package/dist/skills/ulpi-generate-guardian/references/framework-rules.md +692 -0
  54. package/dist/skills/ulpi-generate-guardian/references/language-rules.md +596 -0
  55. package/dist/skills-CX73O3IV.js +76 -0
  56. package/dist/status-4DFHDJMN.js +66 -0
  57. package/dist/templates/biome.yml +24 -0
  58. package/dist/templates/conventional-commits.yml +18 -0
  59. package/dist/templates/django.yml +30 -0
  60. package/dist/templates/docker.yml +30 -0
  61. package/dist/templates/eslint.yml +13 -0
  62. package/dist/templates/express.yml +20 -0
  63. package/dist/templates/fastapi.yml +23 -0
  64. package/dist/templates/git-flow.yml +26 -0
  65. package/dist/templates/github-flow.yml +27 -0
  66. package/dist/templates/go.yml +33 -0
  67. package/dist/templates/jest.yml +24 -0
  68. package/dist/templates/laravel.yml +30 -0
  69. package/dist/templates/monorepo.yml +26 -0
  70. package/dist/templates/nestjs.yml +21 -0
  71. package/dist/templates/nextjs.yml +31 -0
  72. package/dist/templates/nodejs.yml +33 -0
  73. package/dist/templates/npm.yml +15 -0
  74. package/dist/templates/php.yml +25 -0
  75. package/dist/templates/pnpm.yml +15 -0
  76. package/dist/templates/prettier.yml +23 -0
  77. package/dist/templates/prisma.yml +21 -0
  78. package/dist/templates/python.yml +33 -0
  79. package/dist/templates/quality-of-life.yml +111 -0
  80. package/dist/templates/ruby.yml +25 -0
  81. package/dist/templates/rust.yml +34 -0
  82. package/dist/templates/typescript.yml +14 -0
  83. package/dist/templates/vitest.yml +24 -0
  84. package/dist/templates/yarn.yml +15 -0
  85. package/dist/templates-U7T6MARD.js +156 -0
  86. package/dist/ui-L7UAWXDY.js +167 -0
  87. package/dist/ui.html +698 -0
  88. package/dist/ulpi-RMMCUAGP-JCJ273T6.js +161 -0
  89. package/dist/uninstall-6SW35IK4.js +25 -0
  90. package/dist/update-M2B4RLGH.js +61 -0
  91. package/dist/version-checker-ANCS3IHR.js +10 -0
  92. package/package.json +92 -0
@@ -0,0 +1,127 @@
1
+ import {
2
+ loadUlpiSettings,
3
+ saveUlpiSettings
4
+ } from "./chunk-7LXY5UVC.js";
5
+ import "./chunk-4VNS5WPM.js";
6
+
7
+ // src/commands/config.ts
8
+ import chalk from "chalk";
9
+ function runConfig(args) {
10
+ const sub = args[0];
11
+ switch (sub) {
12
+ case "set":
13
+ return setConfig(args.slice(1));
14
+ case "get":
15
+ return getConfig(args.slice(1));
16
+ case "show":
17
+ return showConfig();
18
+ default:
19
+ console.log(`
20
+ Usage: ulpi config <command>
21
+
22
+ Commands:
23
+ set openai-key <key> Set OpenAI API key
24
+ set anthropic-key <key> Set Anthropic API key
25
+ set ulpi-key <key> Set ULPI API key
26
+ set ulpi-url <url> Set ULPI Cloud API URL
27
+ get openai-key Show OpenAI API key (masked)
28
+ get anthropic-key Show Anthropic API key (masked)
29
+ get ulpi-key Show ULPI API key (masked)
30
+ get ulpi-url Show ULPI Cloud API URL
31
+ show Show all settings
32
+ `.trim());
33
+ }
34
+ }
35
+ function setConfig(args) {
36
+ const key = args[0];
37
+ const value = args[1];
38
+ if (!key || !value) {
39
+ console.error(chalk.red("Usage: ulpi config set <key> <value>"));
40
+ return;
41
+ }
42
+ const settings = loadUlpiSettings();
43
+ if (!settings.apiKeys) settings.apiKeys = {};
44
+ switch (key) {
45
+ case "openai-key":
46
+ settings.apiKeys.openai = stripKeyPrefix(value);
47
+ saveUlpiSettings(settings);
48
+ console.log(chalk.green(`\u2713 OpenAI API key saved to ~/.ulpi/settings.json`));
49
+ break;
50
+ case "anthropic-key":
51
+ settings.apiKeys.anthropic = stripKeyPrefix(value);
52
+ saveUlpiSettings(settings);
53
+ console.log(chalk.green(`\u2713 Anthropic API key saved to ~/.ulpi/settings.json`));
54
+ break;
55
+ case "ulpi-key":
56
+ settings.apiKeys.ulpi = stripKeyPrefix(value);
57
+ saveUlpiSettings(settings);
58
+ console.log(chalk.green(`\u2713 ULPI API key saved to ~/.ulpi/settings.json`));
59
+ break;
60
+ case "ulpi-url":
61
+ settings.ulpiUrl = value;
62
+ saveUlpiSettings(settings);
63
+ console.log(chalk.green(`\u2713 ULPI Cloud API URL saved to ~/.ulpi/settings.json`));
64
+ break;
65
+ default:
66
+ console.error(chalk.red(`Unknown config key: ${key}`));
67
+ console.error(chalk.dim(" Available: openai-key, anthropic-key, ulpi-key, ulpi-url"));
68
+ }
69
+ }
70
+ function getConfig(args) {
71
+ const key = args[0];
72
+ if (!key) {
73
+ console.error(chalk.red("Usage: ulpi config get <key>"));
74
+ return;
75
+ }
76
+ const settings = loadUlpiSettings();
77
+ switch (key) {
78
+ case "openai-key": {
79
+ const val = settings.apiKeys?.openai;
80
+ console.log(val ? maskKey(val) : chalk.dim("(not set)"));
81
+ break;
82
+ }
83
+ case "anthropic-key": {
84
+ const val = settings.apiKeys?.anthropic;
85
+ console.log(val ? maskKey(val) : chalk.dim("(not set)"));
86
+ break;
87
+ }
88
+ case "ulpi-key": {
89
+ const val = settings.apiKeys?.ulpi;
90
+ console.log(val ? maskKey(val) : chalk.dim("(not set)"));
91
+ break;
92
+ }
93
+ case "ulpi-url": {
94
+ const val = settings.ulpiUrl;
95
+ console.log(val ?? chalk.dim("(not set \u2014 default: http://localhost:10271)"));
96
+ break;
97
+ }
98
+ default:
99
+ console.error(chalk.red(`Unknown config key: ${key}`));
100
+ }
101
+ }
102
+ function showConfig() {
103
+ const settings = loadUlpiSettings();
104
+ const masked = {
105
+ ...settings,
106
+ apiKeys: {
107
+ openai: settings.apiKeys?.openai ? maskKey(settings.apiKeys.openai) : void 0,
108
+ anthropic: settings.apiKeys?.anthropic ? maskKey(settings.apiKeys.anthropic) : void 0,
109
+ ulpi: settings.apiKeys?.ulpi ? maskKey(settings.apiKeys.ulpi) : void 0
110
+ }
111
+ };
112
+ console.log(JSON.stringify(masked, null, 2));
113
+ }
114
+ function stripKeyPrefix(value) {
115
+ const eqIdx = value.indexOf("=");
116
+ if (eqIdx !== -1 && value.slice(0, eqIdx).match(/^[A-Z_]+$/)) {
117
+ return value.slice(eqIdx + 1);
118
+ }
119
+ return value;
120
+ }
121
+ function maskKey(key) {
122
+ if (key.length <= 8) return "****";
123
+ return key.slice(0, 4) + "..." + key.slice(-4);
124
+ }
125
+ export {
126
+ runConfig
127
+ };
@@ -0,0 +1,90 @@
1
+ import {
2
+ ANNOTATION_TYPE_FEEDBACK_PREFIX,
3
+ ANNOTATION_TYPE_LABELS,
4
+ AnnotationTypeSchema,
5
+ BlockSchema,
6
+ BlockTypeSchema,
7
+ CaptureModeSchema,
8
+ ClassificationResultSchema,
9
+ CodemapBatchConfigSchema,
10
+ CodemapChunkingConfigSchema,
11
+ CodemapChunkingStrategySchema,
12
+ CodemapConfigSchema,
13
+ CodemapEmbeddingConfigSchema,
14
+ CodemapEmbeddingProviderSchema,
15
+ CodemapHybridConfigSchema,
16
+ CodemapHybridWeightsSchema,
17
+ CodemapSymbolTypeSchema,
18
+ DepgraphConfigSchema,
19
+ DepgraphPagerankConfigSchema,
20
+ DepgraphPersonalizationConfigSchema,
21
+ DiffChunkSchema,
22
+ DiffChunkTypeSchema,
23
+ InlineEditSchema,
24
+ MemoryClassifierConfigSchema,
25
+ MemoryConfigSchema,
26
+ MemoryEmbeddingConfigSchema,
27
+ MemoryEntrySchema,
28
+ MemoryImportanceSchema,
29
+ MemoryRankingConfigSchema,
30
+ MemoryRetentionConfigSchema,
31
+ MemorySourceSchema,
32
+ MemoryTypeSchema,
33
+ PlanSectionSchema,
34
+ PlanStatusSchema,
35
+ PriorityLevelSchema,
36
+ RepoInfoSchema,
37
+ ReviewAnnotationSchema,
38
+ ReviewDecisionSchema,
39
+ RiskLevelSchema,
40
+ SectionInstructionSchema,
41
+ SectionPrioritySchema,
42
+ SectionRiskSchema,
43
+ SectionStatusSchema
44
+ } from "./chunk-74WVVWJ4.js";
45
+ import "./chunk-KIKPIH6N.js";
46
+ import "./chunk-4VNS5WPM.js";
47
+ export {
48
+ ANNOTATION_TYPE_FEEDBACK_PREFIX,
49
+ ANNOTATION_TYPE_LABELS,
50
+ AnnotationTypeSchema,
51
+ BlockSchema,
52
+ BlockTypeSchema,
53
+ CaptureModeSchema,
54
+ ClassificationResultSchema,
55
+ CodemapBatchConfigSchema,
56
+ CodemapChunkingConfigSchema,
57
+ CodemapChunkingStrategySchema,
58
+ CodemapConfigSchema,
59
+ CodemapEmbeddingConfigSchema,
60
+ CodemapEmbeddingProviderSchema,
61
+ CodemapHybridConfigSchema,
62
+ CodemapHybridWeightsSchema,
63
+ CodemapSymbolTypeSchema,
64
+ DepgraphConfigSchema,
65
+ DepgraphPagerankConfigSchema,
66
+ DepgraphPersonalizationConfigSchema,
67
+ DiffChunkSchema,
68
+ DiffChunkTypeSchema,
69
+ InlineEditSchema,
70
+ MemoryClassifierConfigSchema,
71
+ MemoryConfigSchema,
72
+ MemoryEmbeddingConfigSchema,
73
+ MemoryEntrySchema,
74
+ MemoryImportanceSchema,
75
+ MemoryRankingConfigSchema,
76
+ MemoryRetentionConfigSchema,
77
+ MemorySourceSchema,
78
+ MemoryTypeSchema,
79
+ PlanSectionSchema,
80
+ PlanStatusSchema,
81
+ PriorityLevelSchema,
82
+ RepoInfoSchema,
83
+ ReviewAnnotationSchema,
84
+ ReviewDecisionSchema,
85
+ RiskLevelSchema,
86
+ SectionInstructionSchema,
87
+ SectionPrioritySchema,
88
+ SectionRiskSchema,
89
+ SectionStatusSchema
90
+ };
@@ -0,0 +1,418 @@
1
+ import {
2
+ CallToolRequestSchema,
3
+ ListToolsRequestSchema,
4
+ Server,
5
+ StdioServerTransport
6
+ } from "./chunk-JWUUVXIV.js";
7
+ import {
8
+ generateMemoryId,
9
+ getMemoryStats,
10
+ listCapturedSessions,
11
+ listEntries,
12
+ loadEntry,
13
+ readCapturedEvents,
14
+ rememberMemory,
15
+ removeEntry,
16
+ searchMemory,
17
+ updateEntry
18
+ } from "./chunk-6JCMYYBT.js";
19
+ import "./chunk-DBMUNBNB.js";
20
+ import "./chunk-NNUWU6CV.js";
21
+ import "./chunk-YM2HV4IA.js";
22
+ import "./chunk-74WVVWJ4.js";
23
+ import "./chunk-KIKPIH6N.js";
24
+ import "./chunk-2HEE5OKX.js";
25
+ import "./chunk-KLEASXUR.js";
26
+ import "./chunk-7LXY5UVC.js";
27
+ import "./chunk-4VNS5WPM.js";
28
+
29
+ // ../../packages/memory-mcp/dist/index.js
30
+ var searchMemoryTool = {
31
+ name: "search_memory",
32
+ description: "Search project memories by semantic similarity. Returns memories ranked by relevance, importance, and access frequency. Memories include decisions, patterns, bug root causes, preferences, constraints, context, lessons, and relationships.",
33
+ inputSchema: {
34
+ type: "object",
35
+ properties: {
36
+ query: { type: "string", description: "Natural language search query" },
37
+ type: {
38
+ type: "string",
39
+ description: "Filter by memory type",
40
+ enum: ["DECISION", "PATTERN", "BUG_ROOT_CAUSE", "PREFERENCE", "CONSTRAINT", "CONTEXT", "LESSON", "RELATIONSHIP"]
41
+ },
42
+ importance: {
43
+ type: "string",
44
+ description: "Filter by importance level",
45
+ enum: ["critical", "high", "medium", "low"]
46
+ },
47
+ limit: { type: "number", description: "Maximum results (default 10, max 50)" },
48
+ tags: {
49
+ type: "array",
50
+ items: { type: "string" },
51
+ description: "Filter by tags (matches any)"
52
+ },
53
+ since: { type: "string", description: "Only memories created after this ISO date" },
54
+ includeSuperseded: { type: "boolean", description: "Include superseded memories (default false)" }
55
+ },
56
+ required: ["query"]
57
+ }
58
+ };
59
+ async function handleSearchMemory(projectDir, args) {
60
+ const query = args.query;
61
+ const limit = typeof args.limit === "number" ? Math.min(Math.max(1, args.limit), 50) : 10;
62
+ const types = typeof args.type === "string" ? [args.type] : void 0;
63
+ const importance = typeof args.importance === "string" ? [args.importance] : void 0;
64
+ const tags = Array.isArray(args.tags) ? args.tags : void 0;
65
+ const since = typeof args.since === "string" ? args.since : void 0;
66
+ const includeSuperseded = typeof args.includeSuperseded === "boolean" ? args.includeSuperseded : void 0;
67
+ const result = await searchMemory(projectDir, {
68
+ query,
69
+ limit,
70
+ types,
71
+ importance,
72
+ tags,
73
+ since,
74
+ includeSuperseded
75
+ });
76
+ const payload = {
77
+ query: result.query,
78
+ durationMs: result.durationMs,
79
+ resultCount: result.results.length,
80
+ results: result.results.map((r) => ({
81
+ id: r.entry.id,
82
+ type: r.entry.type,
83
+ summary: r.entry.summary,
84
+ detail: r.entry.detail,
85
+ importance: r.entry.importance,
86
+ score: Math.round(r.score * 1e3) / 1e3,
87
+ finalScore: Math.round(r.finalScore * 1e3) / 1e3,
88
+ tags: r.entry.tags,
89
+ relatedFiles: r.entry.relatedFiles,
90
+ accessCount: r.entry.accessCount,
91
+ createdAt: r.entry.createdAt,
92
+ updatedAt: r.entry.updatedAt
93
+ })),
94
+ summary: result.results.length > 0 ? `Found ${result.results.length} memories for "${query}" in ${result.durationMs}ms` : `No memories found for "${query}"`
95
+ };
96
+ return {
97
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
98
+ };
99
+ }
100
+ var saveMemoryTool = {
101
+ name: "save_memory",
102
+ description: "Save an explicit memory. Use this to record decisions, patterns, bug root causes, preferences, constraints, context, lessons, or relationships discovered during a session.",
103
+ inputSchema: {
104
+ type: "object",
105
+ properties: {
106
+ summary: { type: "string", description: "The memory content (max 2000 chars)" },
107
+ type: {
108
+ type: "string",
109
+ description: "Memory type",
110
+ enum: ["DECISION", "PATTERN", "BUG_ROOT_CAUSE", "PREFERENCE", "CONSTRAINT", "CONTEXT", "LESSON", "RELATIONSHIP"]
111
+ },
112
+ detail: { type: "string", description: "Additional detail or context (max 10000 chars)" },
113
+ importance: {
114
+ type: "string",
115
+ description: "Importance level (default 'medium')",
116
+ enum: ["critical", "high", "medium", "low"]
117
+ },
118
+ tags: {
119
+ type: "array",
120
+ items: { type: "string" },
121
+ description: "Tags for categorization"
122
+ },
123
+ relatedFiles: {
124
+ type: "array",
125
+ items: { type: "string" },
126
+ description: "File paths related to this memory"
127
+ }
128
+ },
129
+ required: ["summary", "type"]
130
+ }
131
+ };
132
+ async function handleSaveMemory(projectDir, args) {
133
+ const summary = args.summary;
134
+ const type = args.type;
135
+ const detail = typeof args.detail === "string" ? args.detail : null;
136
+ const importance = typeof args.importance === "string" ? args.importance : "medium";
137
+ const tags = Array.isArray(args.tags) ? args.tags : [];
138
+ const relatedFiles = Array.isArray(args.relatedFiles) ? args.relatedFiles : [];
139
+ const now = (/* @__PURE__ */ new Date()).toISOString();
140
+ const id = generateMemoryId(type, summary);
141
+ const entry = {
142
+ id,
143
+ type,
144
+ summary,
145
+ detail,
146
+ importance,
147
+ tags,
148
+ relatedFiles,
149
+ source: {
150
+ type: "explicit"
151
+ },
152
+ createdAt: now,
153
+ updatedAt: now,
154
+ accessCount: 0
155
+ };
156
+ await rememberMemory(projectDir, entry);
157
+ const payload = {
158
+ id,
159
+ type,
160
+ importance,
161
+ summary: summary.length > 100 ? summary.slice(0, 100) + "..." : summary,
162
+ message: `Memory saved successfully (id: ${id})`
163
+ };
164
+ return {
165
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
166
+ };
167
+ }
168
+ var getTimelineTool = {
169
+ name: "get_timeline",
170
+ description: "Get a chronological timeline of memories. Returns memories sorted newest-first, optionally filtered by date and type.",
171
+ inputSchema: {
172
+ type: "object",
173
+ properties: {
174
+ since: { type: "string", description: "Only memories created after this ISO date" },
175
+ type: {
176
+ type: "string",
177
+ description: "Filter by memory type",
178
+ enum: ["DECISION", "PATTERN", "BUG_ROOT_CAUSE", "PREFERENCE", "CONSTRAINT", "CONTEXT", "LESSON", "RELATIONSHIP"]
179
+ },
180
+ limit: { type: "number", description: "Maximum results (default 20)" }
181
+ }
182
+ }
183
+ };
184
+ async function handleGetTimeline(projectDir, args) {
185
+ const since = typeof args.since === "string" ? args.since : void 0;
186
+ const type = typeof args.type === "string" ? args.type : void 0;
187
+ const limit = typeof args.limit === "number" ? Math.min(Math.max(1, args.limit), 100) : 20;
188
+ let entries = listEntries(projectDir);
189
+ if (type) {
190
+ entries = entries.filter((e) => e.type === type);
191
+ }
192
+ if (since) {
193
+ entries = entries.filter((e) => e.createdAt >= since);
194
+ }
195
+ entries.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
196
+ const trimmed = entries.slice(0, limit);
197
+ const payload = {
198
+ totalMatching: entries.length,
199
+ returned: trimmed.length,
200
+ entries: trimmed.map((e) => ({
201
+ id: e.id,
202
+ type: e.type,
203
+ summary: e.summary,
204
+ importance: e.importance,
205
+ tags: e.tags,
206
+ relatedFiles: e.relatedFiles,
207
+ accessCount: e.accessCount,
208
+ createdAt: e.createdAt,
209
+ updatedAt: e.updatedAt,
210
+ supersededBy: e.supersededBy
211
+ })),
212
+ summary: trimmed.length > 0 ? `Timeline: ${trimmed.length} memories (${entries.length} total matching)` : "No memories found matching the criteria"
213
+ };
214
+ return {
215
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
216
+ };
217
+ }
218
+ var getSessionContextTool = {
219
+ name: "get_session_context",
220
+ description: "Get captured context from a specific session, including session metadata, captured events, and any memories extracted from that session.",
221
+ inputSchema: {
222
+ type: "object",
223
+ properties: {
224
+ sessionId: { type: "string", description: "Session ID to look up (omit or 'latest' for most recent)" }
225
+ }
226
+ }
227
+ };
228
+ async function handleGetSessionContext(projectDir, args) {
229
+ const sessionId = typeof args.sessionId === "string" && args.sessionId !== "latest" ? args.sessionId : void 0;
230
+ const sessions = listCapturedSessions(projectDir);
231
+ if (sessions.length === 0) {
232
+ return {
233
+ content: [{ type: "text", text: JSON.stringify({
234
+ error: "No captured sessions found",
235
+ summary: "No sessions have been captured yet. Sessions are captured when memory is enabled in guards.yml."
236
+ }) }]
237
+ };
238
+ }
239
+ const target = sessionId ? sessions.find((s) => s.sessionId === sessionId) : sessions[sessions.length - 1];
240
+ if (!target) {
241
+ return {
242
+ content: [{ type: "text", text: JSON.stringify({
243
+ error: `Session not found: ${sessionId}`,
244
+ availableSessions: sessions.slice(-5).map((s) => ({
245
+ sessionId: s.sessionId,
246
+ capturedAt: s.capturedAt
247
+ })),
248
+ summary: `Session "${sessionId}" not found. Showing last 5 available sessions.`
249
+ }, null, 2) }]
250
+ };
251
+ }
252
+ const events = readCapturedEvents(projectDir, target.sessionId);
253
+ const allEntries = listEntries(projectDir);
254
+ const sessionMemories = allEntries.filter(
255
+ (e) => e.source.sessionId === target.sessionId
256
+ );
257
+ const payload = {
258
+ session: {
259
+ sessionId: target.sessionId,
260
+ projectDir: target.projectDir,
261
+ startedAt: target.startedAt,
262
+ endedAt: target.endedAt,
263
+ branch: target.branch,
264
+ sessionName: target.sessionName,
265
+ filesRead: target.filesRead,
266
+ filesWritten: target.filesWritten,
267
+ commandsRun: target.commandsRun,
268
+ transcriptCaptured: target.transcriptCaptured,
269
+ capturedAt: target.capturedAt
270
+ },
271
+ eventCount: events.length,
272
+ events: events.slice(0, 50).map((e) => ({
273
+ ts: e.ts,
274
+ event: e.event,
275
+ hookEvent: e.hookEvent,
276
+ toolName: e.toolName,
277
+ filePath: e.filePath,
278
+ command: e.command
279
+ })),
280
+ memoriesExtracted: sessionMemories.length,
281
+ memories: sessionMemories.map((m) => ({
282
+ id: m.id,
283
+ type: m.type,
284
+ summary: m.summary,
285
+ importance: m.importance,
286
+ tags: m.tags
287
+ })),
288
+ summary: `Session ${target.sessionId}: ${events.length} events, ${sessionMemories.length} memories extracted, ${target.filesRead} files read, ${target.filesWritten} files written`
289
+ };
290
+ return {
291
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
292
+ };
293
+ }
294
+ var forgetTool = {
295
+ name: "forget",
296
+ description: "Remove or supersede a memory. By default, marks the memory as superseded (soft delete). Use hard=true to permanently delete it.",
297
+ inputSchema: {
298
+ type: "object",
299
+ properties: {
300
+ memoryId: { type: "string", description: "The memory ID to forget" },
301
+ hard: { type: "boolean", description: "Permanently delete instead of marking superseded (default false)" },
302
+ supersededBy: { type: "string", description: "ID of the memory that replaces this one (optional)" }
303
+ },
304
+ required: ["memoryId"]
305
+ }
306
+ };
307
+ async function handleForget(projectDir, args) {
308
+ const memoryId = args.memoryId;
309
+ const hard = typeof args.hard === "boolean" ? args.hard : false;
310
+ const supersededBy = typeof args.supersededBy === "string" ? args.supersededBy : void 0;
311
+ const existing = loadEntry(projectDir, memoryId);
312
+ if (!existing) {
313
+ return {
314
+ content: [{ type: "text", text: JSON.stringify({
315
+ error: `Memory not found: ${memoryId}`,
316
+ summary: `No memory with ID "${memoryId}" exists`
317
+ }) }]
318
+ };
319
+ }
320
+ if (hard) {
321
+ const removed = removeEntry(projectDir, memoryId);
322
+ const payload2 = {
323
+ memoryId,
324
+ action: "deleted",
325
+ success: removed,
326
+ summary: removed ? `Memory ${memoryId} permanently deleted` : `Failed to delete memory ${memoryId}`
327
+ };
328
+ return {
329
+ content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }]
330
+ };
331
+ }
332
+ const updated = updateEntry(projectDir, memoryId, {
333
+ supersededBy: supersededBy ?? "forgotten",
334
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
335
+ });
336
+ const payload = {
337
+ memoryId,
338
+ action: "superseded",
339
+ supersededBy: supersededBy ?? "forgotten",
340
+ success: updated !== null,
341
+ summary: updated ? `Memory ${memoryId} marked as superseded` : `Failed to update memory ${memoryId}`
342
+ };
343
+ return {
344
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
345
+ };
346
+ }
347
+ var memoryStatsTool = {
348
+ name: "memory_stats",
349
+ description: "Get memory system statistics: total memories, counts by type and importance, total accesses, sessions captured, index size, and initialization status.",
350
+ inputSchema: {
351
+ type: "object",
352
+ properties: {}
353
+ }
354
+ };
355
+ async function handleMemoryStats(projectDir, _args) {
356
+ const stats = await getMemoryStats(projectDir);
357
+ const payload = {
358
+ ...stats,
359
+ summary: stats.initialized ? `Memory system: ${stats.totalMemories} memories, ${stats.sessionsCaptured} sessions captured, ${stats.sessionsClassified} classified, ${(stats.indexSizeBytes / 1024).toFixed(1)} KB index` : "Memory system not initialized. Enable memory in guards.yml and run a session to start capturing."
360
+ };
361
+ return {
362
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
363
+ };
364
+ }
365
+ var ALL_TOOLS = [
366
+ searchMemoryTool,
367
+ saveMemoryTool,
368
+ getTimelineTool,
369
+ getSessionContextTool,
370
+ forgetTool,
371
+ memoryStatsTool
372
+ ];
373
+ var HANDLERS = {
374
+ search_memory: handleSearchMemory,
375
+ save_memory: handleSaveMemory,
376
+ get_timeline: handleGetTimeline,
377
+ get_session_context: handleGetSessionContext,
378
+ forget: handleForget,
379
+ memory_stats: handleMemoryStats
380
+ };
381
+ function createMemoryMcpServer(options) {
382
+ const server = new Server(
383
+ { name: "memory", version: "0.1.0" },
384
+ { capabilities: { tools: {} } }
385
+ );
386
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
387
+ tools: ALL_TOOLS
388
+ }));
389
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
390
+ const { name, arguments: args } = request.params;
391
+ const handler = HANDLERS[name];
392
+ if (!handler) {
393
+ return {
394
+ content: [{ type: "text", text: JSON.stringify({ error: `Unknown tool: ${name}` }) }],
395
+ isError: true
396
+ };
397
+ }
398
+ try {
399
+ return await handler(options.projectDir, args ?? {});
400
+ } catch (err) {
401
+ const message = err instanceof Error ? err.message : String(err);
402
+ return {
403
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }],
404
+ isError: true
405
+ };
406
+ }
407
+ });
408
+ return server;
409
+ }
410
+ async function startMemoryMcpServer(options) {
411
+ const server = createMemoryMcpServer(options);
412
+ const transport = new StdioServerTransport();
413
+ await server.connect(transport);
414
+ }
415
+ export {
416
+ createMemoryMcpServer,
417
+ startMemoryMcpServer
418
+ };