clementine-agent 1.0.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 (190) hide show
  1. package/.env.example +44 -0
  2. package/LICENSE +21 -0
  3. package/README.md +795 -0
  4. package/dist/agent/agent-manager.d.ts +69 -0
  5. package/dist/agent/agent-manager.js +441 -0
  6. package/dist/agent/assistant.d.ts +225 -0
  7. package/dist/agent/assistant.js +3888 -0
  8. package/dist/agent/auto-update.d.ts +32 -0
  9. package/dist/agent/auto-update.js +186 -0
  10. package/dist/agent/daily-planner.d.ts +24 -0
  11. package/dist/agent/daily-planner.js +379 -0
  12. package/dist/agent/execution-advisor.d.ts +10 -0
  13. package/dist/agent/execution-advisor.js +272 -0
  14. package/dist/agent/hooks.d.ts +45 -0
  15. package/dist/agent/hooks.js +564 -0
  16. package/dist/agent/insight-engine.d.ts +66 -0
  17. package/dist/agent/insight-engine.js +225 -0
  18. package/dist/agent/intent-classifier.d.ts +48 -0
  19. package/dist/agent/intent-classifier.js +214 -0
  20. package/dist/agent/link-extractor.d.ts +19 -0
  21. package/dist/agent/link-extractor.js +90 -0
  22. package/dist/agent/mcp-bridge.d.ts +62 -0
  23. package/dist/agent/mcp-bridge.js +435 -0
  24. package/dist/agent/metacognition.d.ts +66 -0
  25. package/dist/agent/metacognition.js +221 -0
  26. package/dist/agent/orchestrator.d.ts +81 -0
  27. package/dist/agent/orchestrator.js +790 -0
  28. package/dist/agent/profiles.d.ts +22 -0
  29. package/dist/agent/profiles.js +91 -0
  30. package/dist/agent/prompt-cache.d.ts +24 -0
  31. package/dist/agent/prompt-cache.js +68 -0
  32. package/dist/agent/prompt-evolver.d.ts +28 -0
  33. package/dist/agent/prompt-evolver.js +279 -0
  34. package/dist/agent/role-scaffolds.d.ts +28 -0
  35. package/dist/agent/role-scaffolds.js +433 -0
  36. package/dist/agent/safe-restart.d.ts +41 -0
  37. package/dist/agent/safe-restart.js +150 -0
  38. package/dist/agent/self-improve.d.ts +66 -0
  39. package/dist/agent/self-improve.js +1706 -0
  40. package/dist/agent/session-event-log.d.ts +114 -0
  41. package/dist/agent/session-event-log.js +233 -0
  42. package/dist/agent/skill-extractor.d.ts +72 -0
  43. package/dist/agent/skill-extractor.js +435 -0
  44. package/dist/agent/source-mods.d.ts +61 -0
  45. package/dist/agent/source-mods.js +230 -0
  46. package/dist/agent/source-preflight.d.ts +25 -0
  47. package/dist/agent/source-preflight.js +100 -0
  48. package/dist/agent/stall-guard.d.ts +62 -0
  49. package/dist/agent/stall-guard.js +109 -0
  50. package/dist/agent/strategic-planner.d.ts +60 -0
  51. package/dist/agent/strategic-planner.js +352 -0
  52. package/dist/agent/team-bus.d.ts +89 -0
  53. package/dist/agent/team-bus.js +556 -0
  54. package/dist/agent/team-router.d.ts +26 -0
  55. package/dist/agent/team-router.js +37 -0
  56. package/dist/agent/tool-loop-detector.d.ts +59 -0
  57. package/dist/agent/tool-loop-detector.js +242 -0
  58. package/dist/agent/workflow-runner.d.ts +36 -0
  59. package/dist/agent/workflow-runner.js +317 -0
  60. package/dist/agent/workflow-variables.d.ts +16 -0
  61. package/dist/agent/workflow-variables.js +62 -0
  62. package/dist/channels/discord-agent-bot.d.ts +101 -0
  63. package/dist/channels/discord-agent-bot.js +881 -0
  64. package/dist/channels/discord-bot-manager.d.ts +80 -0
  65. package/dist/channels/discord-bot-manager.js +262 -0
  66. package/dist/channels/discord-utils.d.ts +51 -0
  67. package/dist/channels/discord-utils.js +293 -0
  68. package/dist/channels/discord.d.ts +12 -0
  69. package/dist/channels/discord.js +1832 -0
  70. package/dist/channels/slack-agent-bot.d.ts +73 -0
  71. package/dist/channels/slack-agent-bot.js +320 -0
  72. package/dist/channels/slack-bot-manager.d.ts +66 -0
  73. package/dist/channels/slack-bot-manager.js +236 -0
  74. package/dist/channels/slack-utils.d.ts +39 -0
  75. package/dist/channels/slack-utils.js +189 -0
  76. package/dist/channels/slack.d.ts +11 -0
  77. package/dist/channels/slack.js +196 -0
  78. package/dist/channels/telegram.d.ts +10 -0
  79. package/dist/channels/telegram.js +235 -0
  80. package/dist/channels/webhook.d.ts +9 -0
  81. package/dist/channels/webhook.js +78 -0
  82. package/dist/channels/whatsapp.d.ts +11 -0
  83. package/dist/channels/whatsapp.js +181 -0
  84. package/dist/cli/chat.d.ts +14 -0
  85. package/dist/cli/chat.js +220 -0
  86. package/dist/cli/cron.d.ts +17 -0
  87. package/dist/cli/cron.js +552 -0
  88. package/dist/cli/dashboard.d.ts +15 -0
  89. package/dist/cli/dashboard.js +17677 -0
  90. package/dist/cli/index.d.ts +3 -0
  91. package/dist/cli/index.js +2474 -0
  92. package/dist/cli/routes/delegations.d.ts +19 -0
  93. package/dist/cli/routes/delegations.js +154 -0
  94. package/dist/cli/routes/digest.d.ts +17 -0
  95. package/dist/cli/routes/digest.js +375 -0
  96. package/dist/cli/routes/goals.d.ts +14 -0
  97. package/dist/cli/routes/goals.js +258 -0
  98. package/dist/cli/routes/workflows.d.ts +18 -0
  99. package/dist/cli/routes/workflows.js +97 -0
  100. package/dist/cli/setup.d.ts +8 -0
  101. package/dist/cli/setup.js +619 -0
  102. package/dist/cli/tunnel.d.ts +35 -0
  103. package/dist/cli/tunnel.js +141 -0
  104. package/dist/config.d.ts +145 -0
  105. package/dist/config.js +278 -0
  106. package/dist/events/bus.d.ts +43 -0
  107. package/dist/events/bus.js +136 -0
  108. package/dist/gateway/cron-scheduler.d.ts +166 -0
  109. package/dist/gateway/cron-scheduler.js +1767 -0
  110. package/dist/gateway/delivery-queue.d.ts +30 -0
  111. package/dist/gateway/delivery-queue.js +110 -0
  112. package/dist/gateway/heartbeat-scheduler.d.ts +99 -0
  113. package/dist/gateway/heartbeat-scheduler.js +1298 -0
  114. package/dist/gateway/heartbeat.d.ts +3 -0
  115. package/dist/gateway/heartbeat.js +3 -0
  116. package/dist/gateway/lanes.d.ts +24 -0
  117. package/dist/gateway/lanes.js +76 -0
  118. package/dist/gateway/notifications.d.ts +29 -0
  119. package/dist/gateway/notifications.js +75 -0
  120. package/dist/gateway/router.d.ts +210 -0
  121. package/dist/gateway/router.js +1330 -0
  122. package/dist/index.d.ts +12 -0
  123. package/dist/index.js +1015 -0
  124. package/dist/memory/chunker.d.ts +28 -0
  125. package/dist/memory/chunker.js +226 -0
  126. package/dist/memory/consolidation.d.ts +44 -0
  127. package/dist/memory/consolidation.js +171 -0
  128. package/dist/memory/context-assembler.d.ts +50 -0
  129. package/dist/memory/context-assembler.js +149 -0
  130. package/dist/memory/embeddings.d.ts +38 -0
  131. package/dist/memory/embeddings.js +180 -0
  132. package/dist/memory/graph-store.d.ts +66 -0
  133. package/dist/memory/graph-store.js +613 -0
  134. package/dist/memory/mmr.d.ts +21 -0
  135. package/dist/memory/mmr.js +75 -0
  136. package/dist/memory/search.d.ts +26 -0
  137. package/dist/memory/search.js +67 -0
  138. package/dist/memory/store.d.ts +530 -0
  139. package/dist/memory/store.js +2022 -0
  140. package/dist/security/integrity.d.ts +24 -0
  141. package/dist/security/integrity.js +58 -0
  142. package/dist/security/patterns.d.ts +34 -0
  143. package/dist/security/patterns.js +110 -0
  144. package/dist/security/scanner.d.ts +32 -0
  145. package/dist/security/scanner.js +263 -0
  146. package/dist/tools/admin-tools.d.ts +12 -0
  147. package/dist/tools/admin-tools.js +1278 -0
  148. package/dist/tools/external-tools.d.ts +11 -0
  149. package/dist/tools/external-tools.js +1327 -0
  150. package/dist/tools/goal-tools.d.ts +9 -0
  151. package/dist/tools/goal-tools.js +159 -0
  152. package/dist/tools/mcp-server.d.ts +13 -0
  153. package/dist/tools/mcp-server.js +141 -0
  154. package/dist/tools/memory-tools.d.ts +10 -0
  155. package/dist/tools/memory-tools.js +568 -0
  156. package/dist/tools/session-tools.d.ts +6 -0
  157. package/dist/tools/session-tools.js +146 -0
  158. package/dist/tools/shared.d.ts +216 -0
  159. package/dist/tools/shared.js +340 -0
  160. package/dist/tools/team-tools.d.ts +6 -0
  161. package/dist/tools/team-tools.js +447 -0
  162. package/dist/tools/tool-meta.d.ts +34 -0
  163. package/dist/tools/tool-meta.js +133 -0
  164. package/dist/tools/vault-tools.d.ts +8 -0
  165. package/dist/tools/vault-tools.js +457 -0
  166. package/dist/types.d.ts +716 -0
  167. package/dist/types.js +16 -0
  168. package/dist/vault-migrations/0001-add-execution-framework.d.ts +10 -0
  169. package/dist/vault-migrations/0001-add-execution-framework.js +47 -0
  170. package/dist/vault-migrations/0002-add-agentic-communication.d.ts +12 -0
  171. package/dist/vault-migrations/0002-add-agentic-communication.js +79 -0
  172. package/dist/vault-migrations/0003-update-execution-pipeline-narration.d.ts +11 -0
  173. package/dist/vault-migrations/0003-update-execution-pipeline-narration.js +73 -0
  174. package/dist/vault-migrations/helpers.d.ts +14 -0
  175. package/dist/vault-migrations/helpers.js +44 -0
  176. package/dist/vault-migrations/runner.d.ts +14 -0
  177. package/dist/vault-migrations/runner.js +139 -0
  178. package/dist/vault-migrations/types.d.ts +42 -0
  179. package/dist/vault-migrations/types.js +9 -0
  180. package/install.sh +320 -0
  181. package/package.json +84 -0
  182. package/scripts/postinstall.js +125 -0
  183. package/vault/00-System/AGENTS.md +66 -0
  184. package/vault/00-System/CRON.md +71 -0
  185. package/vault/00-System/HEARTBEAT.md +58 -0
  186. package/vault/00-System/MEMORY.md +16 -0
  187. package/vault/00-System/SOUL.md +96 -0
  188. package/vault/05-Tasks/TASKS.md +19 -0
  189. package/vault/06-Templates/_Daily-Template.md +28 -0
  190. package/vault/06-Templates/_People-Template.md +22 -0
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Clementine TypeScript — Goal MCP tools.
3
+ *
4
+ * Persistent goals that drive proactive agent behavior and
5
+ * can be linked to cron jobs for autonomous progress.
6
+ */
7
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
+ export declare function registerGoalTools(server: McpServer): void;
9
+ //# sourceMappingURL=goal-tools.d.ts.map
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Clementine TypeScript — Goal MCP tools.
3
+ *
4
+ * Persistent goals that drive proactive agent behavior and
5
+ * can be linked to cron jobs for autonomous progress.
6
+ */
7
+ import { randomBytes } from 'node:crypto';
8
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
9
+ import path from 'node:path';
10
+ import { z } from 'zod';
11
+ import { BASE_DIR, logger, textResult } from './shared.js';
12
+ const GOALS_DIR = path.join(BASE_DIR, 'goals');
13
+ const GOAL_TRIGGER_DIR = path.join(BASE_DIR, 'cron', 'goal-triggers');
14
+ function ensureGoalsDir() {
15
+ if (!existsSync(GOALS_DIR))
16
+ mkdirSync(GOALS_DIR, { recursive: true });
17
+ }
18
+ export function registerGoalTools(server) {
19
+ server.tool('goal_create', 'Create a new persistent goal that survives across sessions. Goals drive proactive agent behavior and can be linked to cron jobs.', {
20
+ title: z.string().describe('Short goal title'),
21
+ description: z.string().describe('Detailed description of what this goal aims to achieve'),
22
+ owner: z.string().optional().describe('Agent slug that owns this goal (default: "clementine")'),
23
+ priority: z.enum(['high', 'medium', 'low']).optional().describe('Priority level (default: "medium")'),
24
+ targetDate: z.string().optional().describe('Target completion date (YYYY-MM-DD)'),
25
+ nextActions: z.array(z.string()).optional().describe('Initial next actions to take'),
26
+ reviewFrequency: z.enum(['daily', 'weekly', 'on-demand']).optional().describe('How often to review (default: "weekly")'),
27
+ linkedCronJobs: z.array(z.string()).optional().describe('Cron job names that contribute to this goal'),
28
+ autoSchedule: z.boolean().optional().describe('Allow the daily planner to auto-create/adjust cron jobs for this goal (default: false)'),
29
+ }, async ({ title, description, owner, priority, targetDate, nextActions, reviewFrequency, linkedCronJobs, autoSchedule }) => {
30
+ ensureGoalsDir();
31
+ const id = randomBytes(4).toString('hex');
32
+ const now = new Date().toISOString();
33
+ const goal = {
34
+ id, title, description,
35
+ status: 'active',
36
+ owner: owner || 'clementine',
37
+ priority: priority || 'medium',
38
+ createdAt: now, updatedAt: now, targetDate,
39
+ progressNotes: [],
40
+ nextActions: nextActions || [],
41
+ blockers: [],
42
+ reviewFrequency: reviewFrequency || 'weekly',
43
+ linkedCronJobs: linkedCronJobs || [],
44
+ ...(autoSchedule ? { autoSchedule } : {}),
45
+ };
46
+ writeFileSync(path.join(GOALS_DIR, `${id}.json`), JSON.stringify(goal, null, 2));
47
+ logger.info({ goalId: id, title }, 'Goal created');
48
+ return textResult(`Goal created: "${title}" (ID: ${id})`);
49
+ });
50
+ server.tool('goal_update', 'Update an existing persistent goal — add progress notes, change status, update next actions, or add blockers.', {
51
+ id: z.string().describe('Goal ID'),
52
+ status: z.enum(['active', 'paused', 'completed', 'blocked']).optional().describe('New status'),
53
+ progressNote: z.string().optional().describe('Progress note to append (what was accomplished)'),
54
+ nextActions: z.array(z.string()).optional().describe('Replace next actions list'),
55
+ blockers: z.array(z.string()).optional().describe('Replace blockers list'),
56
+ linkedCronJobs: z.array(z.string()).optional().describe('Replace linked cron jobs'),
57
+ priority: z.enum(['high', 'medium', 'low']).optional().describe('Change priority'),
58
+ autoSchedule: z.boolean().optional().describe('Allow the daily planner to auto-create/adjust cron jobs for this goal'),
59
+ }, async ({ id, status, progressNote, nextActions, blockers, linkedCronJobs, priority, autoSchedule }) => {
60
+ const filePath = path.join(GOALS_DIR, `${id}.json`);
61
+ if (!existsSync(filePath))
62
+ return textResult(`Goal not found: ${id}`);
63
+ const goal = JSON.parse(readFileSync(filePath, 'utf-8'));
64
+ if (status)
65
+ goal.status = status;
66
+ if (progressNote)
67
+ goal.progressNotes.push(`[${new Date().toISOString().slice(0, 16)}] ${progressNote}`);
68
+ if (nextActions)
69
+ goal.nextActions = nextActions;
70
+ if (blockers)
71
+ goal.blockers = blockers;
72
+ if (linkedCronJobs)
73
+ goal.linkedCronJobs = linkedCronJobs;
74
+ if (priority)
75
+ goal.priority = priority;
76
+ if (autoSchedule !== undefined)
77
+ goal.autoSchedule = autoSchedule;
78
+ goal.updatedAt = new Date().toISOString();
79
+ writeFileSync(filePath, JSON.stringify(goal, null, 2));
80
+ logger.info({ goalId: id, status: goal.status }, 'Goal updated');
81
+ return textResult(`Goal "${goal.title}" updated (status: ${goal.status})`);
82
+ });
83
+ server.tool('goal_list', 'List persistent goals, optionally filtered by owner or status.', {
84
+ owner: z.string().optional().describe('Filter by owner agent slug'),
85
+ status: z.enum(['active', 'paused', 'completed', 'blocked']).optional().describe('Filter by status'),
86
+ }, async ({ owner, status }) => {
87
+ ensureGoalsDir();
88
+ const files = readdirSync(GOALS_DIR).filter(f => f.endsWith('.json'));
89
+ let goals = files.map(f => {
90
+ try {
91
+ return JSON.parse(readFileSync(path.join(GOALS_DIR, f), 'utf-8'));
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }).filter(Boolean);
97
+ if (owner)
98
+ goals = goals.filter((g) => g.owner === owner);
99
+ if (status)
100
+ goals = goals.filter((g) => g.status === status);
101
+ if (goals.length === 0)
102
+ return textResult('No goals found matching the criteria.');
103
+ const lines = goals.map((g) => {
104
+ const nextAct = g.nextActions?.length > 0 ? ` | Next: ${g.nextActions[0]}` : '';
105
+ const linked = g.linkedCronJobs?.length > 0 ? ` | Crons: ${g.linkedCronJobs.join(', ')}` : '';
106
+ return `- [${g.status.toUpperCase()}] **${g.title}** (${g.id}) — ${g.priority} priority, owner: ${g.owner}${nextAct}${linked}`;
107
+ });
108
+ return textResult(`Goals (${goals.length}):\n${lines.join('\n')}`);
109
+ });
110
+ server.tool('goal_get', 'Get a single persistent goal with full history — progress notes, next actions, blockers, and linked cron jobs.', { id: z.string().describe('Goal ID') }, async ({ id }) => {
111
+ const filePath = path.join(GOALS_DIR, `${id}.json`);
112
+ if (!existsSync(filePath))
113
+ return textResult(`Goal not found: ${id}`);
114
+ const goal = JSON.parse(readFileSync(filePath, 'utf-8'));
115
+ const sections = [
116
+ `# ${goal.title}`,
117
+ `**ID:** ${goal.id} | **Status:** ${goal.status} | **Priority:** ${goal.priority} | **Owner:** ${goal.owner}`,
118
+ `**Created:** ${goal.createdAt} | **Updated:** ${goal.updatedAt}${goal.targetDate ? ` | **Target:** ${goal.targetDate}` : ''}`,
119
+ `**Review:** ${goal.reviewFrequency}`,
120
+ `\n## Description\n${goal.description}`,
121
+ ];
122
+ if (goal.progressNotes?.length > 0)
123
+ sections.push(`\n## Progress Notes\n${goal.progressNotes.map((n) => `- ${n}`).join('\n')}`);
124
+ if (goal.nextActions?.length > 0)
125
+ sections.push(`\n## Next Actions\n${goal.nextActions.map((a) => `- [ ] ${a}`).join('\n')}`);
126
+ if (goal.blockers?.length > 0)
127
+ sections.push(`\n## Blockers\n${goal.blockers.map((b) => `- ${b}`).join('\n')}`);
128
+ if (goal.linkedCronJobs?.length > 0)
129
+ sections.push(`\n## Linked Cron Jobs\n${goal.linkedCronJobs.map((c) => `- ${c}`).join('\n')}`);
130
+ return textResult(sections.join('\n'));
131
+ });
132
+ server.tool('goal_work', 'Spawn a focused background work session on a specific goal. The daemon picks up the trigger and runs a goal-directed session asynchronously — results are delivered via notifications.', {
133
+ goal_id: z.string().describe('ID of the goal to work on'),
134
+ focus: z.string().optional().describe('Specific aspect to focus on. Defaults to the goal\'s first nextAction.'),
135
+ max_turns: z.number().optional().default(15).describe('Max agent turns for this work session'),
136
+ }, async ({ goal_id, focus, max_turns }) => {
137
+ ensureGoalsDir();
138
+ const goalPath = path.join(GOALS_DIR, `${goal_id}.json`);
139
+ if (!existsSync(goalPath))
140
+ return textResult(`Goal not found: ${goal_id}. Use goal_list to see available goals.`);
141
+ const goal = JSON.parse(readFileSync(goalPath, 'utf-8'));
142
+ if (goal.status !== 'active')
143
+ return textResult(`Goal "${goal.title}" is ${goal.status} — only active goals can be worked on.`);
144
+ mkdirSync(GOAL_TRIGGER_DIR, { recursive: true });
145
+ const trigger = {
146
+ goalId: goal_id,
147
+ focus: focus || goal.nextActions?.[0] || goal.description,
148
+ maxTurns: max_turns,
149
+ triggeredAt: new Date().toISOString(),
150
+ };
151
+ const triggerFile = path.join(GOAL_TRIGGER_DIR, `${Date.now()}-${goal_id}.trigger.json`);
152
+ writeFileSync(triggerFile, JSON.stringify(trigger, null, 2));
153
+ logger.info({ goalId: goal_id, focus: trigger.focus }, 'Goal work session triggered');
154
+ return textResult(`Triggered goal work session for "${goal.title}" (${goal_id}).\n` +
155
+ `Focus: ${trigger.focus}\n` +
156
+ `The daemon will pick it up within a few seconds. Results delivered via notifications.`);
157
+ });
158
+ }
159
+ //# sourceMappingURL=goal-tools.js.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Clementine TypeScript — MCP stdio server entry point.
3
+ *
4
+ * All tool implementations live in separate modules.
5
+ * This file handles server initialization, startup sync, user tools,
6
+ * plugins, and the stdio transport connection.
7
+ *
8
+ * Usage:
9
+ * npx tsx src/tools/mcp-server.ts
10
+ */
11
+ export { getStore, textResult, externalResult, incrementalSync, ACTIVE_AGENT_SLUG } from './shared.js';
12
+ export type { MemoryStoreType } from './shared.js';
13
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Clementine TypeScript — MCP stdio server entry point.
3
+ *
4
+ * All tool implementations live in separate modules.
5
+ * This file handles server initialization, startup sync, user tools,
6
+ * plugins, and the stdio transport connection.
7
+ *
8
+ * Usage:
9
+ * npx tsx src/tools/mcp-server.ts
10
+ */
11
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
12
+ import path from 'node:path';
13
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
14
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
15
+ import { z } from 'zod';
16
+ import { BASE_DIR, VAULT_DIR, env, getStore, getStoreSync, logger, textResult, externalResult, } from './shared.js';
17
+ // Re-export for any code that imports from mcp-server.ts directly
18
+ export { getStore, textResult, externalResult, incrementalSync, ACTIVE_AGENT_SLUG } from './shared.js';
19
+ // ── Tool modules ────────────────────────────────────────────────────────
20
+ import { registerMemoryTools } from './memory-tools.js';
21
+ import { registerVaultTools } from './vault-tools.js';
22
+ import { registerExternalTools } from './external-tools.js';
23
+ import { registerAdminTools } from './admin-tools.js';
24
+ import { registerGoalTools } from './goal-tools.js';
25
+ import { registerTeamTools } from './team-tools.js';
26
+ import { registerSessionTools } from './session-tools.js';
27
+ // ── Server ──────────────────────────────────────────────────────────────
28
+ const serverName = (env['ASSISTANT_NAME'] ?? 'Clementine').toLowerCase() + '-tools';
29
+ const server = new McpServer({ name: serverName, version: '1.0.0' });
30
+ // Register all tool groups
31
+ registerMemoryTools(server);
32
+ registerVaultTools(server);
33
+ registerExternalTools(server);
34
+ registerAdminTools(server);
35
+ registerGoalTools(server);
36
+ registerTeamTools(server);
37
+ registerSessionTools(server);
38
+ // ── Main ────────────────────────────────────────────────────────────────
39
+ async function main() {
40
+ // Initialize memory store and run full sync on startup
41
+ try {
42
+ const store = await getStore();
43
+ const stats = store.fullSync();
44
+ logger.info({ filesScanned: stats.filesScanned, filesUpdated: stats.filesUpdated, chunksTotal: stats.chunksTotal }, 'Startup sync complete');
45
+ const decayed = store.decaySalience();
46
+ const pruned = store.pruneStaleData();
47
+ if (decayed > 0 || pruned.episodicPruned > 0 || pruned.accessLogPruned > 0 || pruned.transcriptsPruned > 0) {
48
+ logger.info({ decayed, ...pruned }, 'Startup maintenance complete');
49
+ }
50
+ }
51
+ catch (err) {
52
+ logger.warn({ err }, 'Startup sync failed (non-fatal)');
53
+ }
54
+ // Graceful shutdown
55
+ const shutdown = (signal) => {
56
+ logger.info({ signal }, 'MCP server shutting down');
57
+ try {
58
+ const s = getStoreSync();
59
+ if (s && typeof s.close === 'function')
60
+ s.close();
61
+ }
62
+ catch { /* */ }
63
+ process.exit(0);
64
+ };
65
+ process.on('SIGINT', () => shutdown('SIGINT'));
66
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
67
+ // Auto-register user tool scripts from ~/.clementine/tools/
68
+ const userToolsDir = path.join(BASE_DIR, 'tools');
69
+ if (existsSync(userToolsDir)) {
70
+ for (const file of readdirSync(userToolsDir).filter(f => f.endsWith('.sh') || f.endsWith('.py'))) {
71
+ const toolName = file.replace(/\.(sh|py)$/, '').replace(/[^a-z0-9_]/gi, '_');
72
+ const filePath = path.join(userToolsDir, file);
73
+ const metaPath = filePath + '.meta.json';
74
+ let desc = `Custom tool: ${toolName}`;
75
+ let argsDesc = 'Optional arguments string';
76
+ if (existsSync(metaPath)) {
77
+ try {
78
+ const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
79
+ desc = meta.description || desc;
80
+ argsDesc = meta.args_description || argsDesc;
81
+ }
82
+ catch { /* defaults */ }
83
+ }
84
+ else {
85
+ try {
86
+ const firstLines = readFileSync(filePath, 'utf-8').split('\n').slice(0, 3);
87
+ const commentLine = firstLines.find(l => l.startsWith('#') && !l.startsWith('#!'));
88
+ if (commentLine)
89
+ desc = commentLine.slice(1).trim();
90
+ }
91
+ catch { /* default */ }
92
+ }
93
+ try {
94
+ server.tool(toolName, desc, { args: z.string().optional().describe(argsDesc) }, async ({ args }) => {
95
+ const { execSync } = await import('node:child_process');
96
+ try {
97
+ const result = execSync(`"${filePath}" ${args || ''}`, {
98
+ encoding: 'utf-8', timeout: 30000, cwd: BASE_DIR,
99
+ env: { ...process.env, CLEMENTINE_HOME: BASE_DIR },
100
+ });
101
+ return textResult(result.trim() || '(no output)');
102
+ }
103
+ catch (err) {
104
+ return textResult(`Tool error: ${err.stderr || err.message || String(err)}`.slice(0, 500));
105
+ }
106
+ });
107
+ logger.info({ tool: toolName, file }, 'Registered user tool');
108
+ }
109
+ catch (err) {
110
+ logger.warn({ tool: toolName, err }, 'Failed to register user tool');
111
+ }
112
+ }
113
+ }
114
+ // Auto-register plugin modules from ~/.clementine/plugins/
115
+ const pluginsDir = path.join(BASE_DIR, 'plugins');
116
+ if (existsSync(pluginsDir)) {
117
+ for (const file of readdirSync(pluginsDir).filter(f => f.endsWith('.js') || f.endsWith('.mjs'))) {
118
+ try {
119
+ const plugin = await import(path.join(pluginsDir, file));
120
+ if (typeof plugin.register === 'function') {
121
+ await plugin.register(server, z, { textResult, externalResult, getStore, BASE_DIR, VAULT_DIR, logger });
122
+ logger.info({ plugin: file }, 'Loaded plugin');
123
+ }
124
+ else {
125
+ logger.warn({ plugin: file }, 'Plugin missing register() export — skipped');
126
+ }
127
+ }
128
+ catch (err) {
129
+ logger.warn({ err, plugin: file }, 'Failed to load plugin');
130
+ }
131
+ }
132
+ }
133
+ const transport = new StdioServerTransport();
134
+ await server.connect(transport);
135
+ logger.info('MCP server connected via stdio');
136
+ }
137
+ main().catch(err => {
138
+ logger.fatal({ err }, 'MCP server failed to start');
139
+ process.exit(1);
140
+ });
141
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Clementine TypeScript — Memory MCP tools.
3
+ *
4
+ * working_memory, memory_read/write/search/recall, memory_connections,
5
+ * memory_timeline, transcript_search, memory_report/correct/consolidate,
6
+ * graph memory tools
7
+ */
8
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ export declare function registerMemoryTools(server: McpServer): void;
10
+ //# sourceMappingURL=memory-tools.d.ts.map