cmdr-agent 2.1.2 → 2.2.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 (105) hide show
  1. package/dist/bin/cmdr.js +4 -0
  2. package/dist/bin/cmdr.js.map +1 -1
  3. package/dist/package.json +1 -1
  4. package/dist/src/cli/args.d.ts +4 -0
  5. package/dist/src/cli/args.d.ts.map +1 -1
  6. package/dist/src/cli/args.js +15 -0
  7. package/dist/src/cli/args.js.map +1 -1
  8. package/dist/src/cli/commands.js +20 -0
  9. package/dist/src/cli/commands.js.map +1 -1
  10. package/dist/src/cli/ink/App.d.ts.map +1 -1
  11. package/dist/src/cli/ink/App.js +15 -0
  12. package/dist/src/cli/ink/App.js.map +1 -1
  13. package/dist/src/cli/repl.d.ts +4 -0
  14. package/dist/src/cli/repl.d.ts.map +1 -1
  15. package/dist/src/cli/repl.js +48 -19
  16. package/dist/src/cli/repl.js.map +1 -1
  17. package/dist/src/core/agent-runner.d.ts +5 -0
  18. package/dist/src/core/agent-runner.d.ts.map +1 -1
  19. package/dist/src/core/agent-runner.js +12 -2
  20. package/dist/src/core/agent-runner.js.map +1 -1
  21. package/dist/src/core/agent.d.ts +2 -1
  22. package/dist/src/core/agent.d.ts.map +1 -1
  23. package/dist/src/core/agent.js +5 -1
  24. package/dist/src/core/agent.js.map +1 -1
  25. package/dist/src/core/content-replacement.d.ts +44 -0
  26. package/dist/src/core/content-replacement.d.ts.map +1 -0
  27. package/dist/src/core/content-replacement.js +67 -0
  28. package/dist/src/core/content-replacement.js.map +1 -0
  29. package/dist/src/core/event-bus.d.ts +129 -0
  30. package/dist/src/core/event-bus.d.ts.map +1 -0
  31. package/dist/src/core/event-bus.js +103 -0
  32. package/dist/src/core/event-bus.js.map +1 -0
  33. package/dist/src/core/orchestrator.d.ts +17 -1
  34. package/dist/src/core/orchestrator.d.ts.map +1 -1
  35. package/dist/src/core/orchestrator.js +95 -1
  36. package/dist/src/core/orchestrator.js.map +1 -1
  37. package/dist/src/core/permissions.d.ts +31 -3
  38. package/dist/src/core/permissions.d.ts.map +1 -1
  39. package/dist/src/core/permissions.js +122 -11
  40. package/dist/src/core/permissions.js.map +1 -1
  41. package/dist/src/core/presets.d.ts.map +1 -1
  42. package/dist/src/core/presets.js +1 -0
  43. package/dist/src/core/presets.js.map +1 -1
  44. package/dist/src/core/types.d.ts +17 -1
  45. package/dist/src/core/types.d.ts.map +1 -1
  46. package/dist/src/llm/anthropic.d.ts +27 -0
  47. package/dist/src/llm/anthropic.d.ts.map +1 -0
  48. package/dist/src/llm/anthropic.js +269 -0
  49. package/dist/src/llm/anthropic.js.map +1 -0
  50. package/dist/src/llm/ollama.d.ts.map +1 -1
  51. package/dist/src/llm/ollama.js +16 -4
  52. package/dist/src/llm/ollama.js.map +1 -1
  53. package/dist/src/llm/openai.d.ts +25 -0
  54. package/dist/src/llm/openai.d.ts.map +1 -0
  55. package/dist/src/llm/openai.js +299 -0
  56. package/dist/src/llm/openai.js.map +1 -0
  57. package/dist/src/llm/provider-factory.d.ts +35 -0
  58. package/dist/src/llm/provider-factory.d.ts.map +1 -0
  59. package/dist/src/llm/provider-factory.js +73 -0
  60. package/dist/src/llm/provider-factory.js.map +1 -0
  61. package/dist/src/memory/consolidation.d.ts +37 -0
  62. package/dist/src/memory/consolidation.d.ts.map +1 -0
  63. package/dist/src/memory/consolidation.js +148 -0
  64. package/dist/src/memory/consolidation.js.map +1 -0
  65. package/dist/src/memory/memory-manager.d.ts +39 -0
  66. package/dist/src/memory/memory-manager.d.ts.map +1 -0
  67. package/dist/src/memory/memory-manager.js +96 -0
  68. package/dist/src/memory/memory-manager.js.map +1 -0
  69. package/dist/src/plugins/mcp-client.d.ts +14 -5
  70. package/dist/src/plugins/mcp-client.d.ts.map +1 -1
  71. package/dist/src/plugins/mcp-client.js +197 -43
  72. package/dist/src/plugins/mcp-client.js.map +1 -1
  73. package/dist/src/scheduling/task-scheduler.d.ts +51 -0
  74. package/dist/src/scheduling/task-scheduler.d.ts.map +1 -0
  75. package/dist/src/scheduling/task-scheduler.js +127 -0
  76. package/dist/src/scheduling/task-scheduler.js.map +1 -0
  77. package/dist/src/session/prompt-builder.d.ts +6 -0
  78. package/dist/src/session/prompt-builder.d.ts.map +1 -1
  79. package/dist/src/session/prompt-builder.js +21 -2
  80. package/dist/src/session/prompt-builder.js.map +1 -1
  81. package/dist/src/session/prompt-cache.d.ts +33 -0
  82. package/dist/src/session/prompt-cache.d.ts.map +1 -0
  83. package/dist/src/session/prompt-cache.js +54 -0
  84. package/dist/src/session/prompt-cache.js.map +1 -0
  85. package/dist/src/tools/built-in/diagnostics.d.ts +12 -0
  86. package/dist/src/tools/built-in/diagnostics.d.ts.map +1 -0
  87. package/dist/src/tools/built-in/diagnostics.js +119 -0
  88. package/dist/src/tools/built-in/diagnostics.js.map +1 -0
  89. package/dist/src/tools/built-in/git-worktree.d.ts +13 -0
  90. package/dist/src/tools/built-in/git-worktree.d.ts.map +1 -0
  91. package/dist/src/tools/built-in/git-worktree.js +75 -0
  92. package/dist/src/tools/built-in/git-worktree.js.map +1 -0
  93. package/dist/src/tools/built-in/index.d.ts +5 -1
  94. package/dist/src/tools/built-in/index.d.ts.map +1 -1
  95. package/dist/src/tools/built-in/index.js +8 -2
  96. package/dist/src/tools/built-in/index.js.map +1 -1
  97. package/dist/src/tools/built-in/memory.d.ts +15 -0
  98. package/dist/src/tools/built-in/memory.d.ts.map +1 -0
  99. package/dist/src/tools/built-in/memory.js +58 -0
  100. package/dist/src/tools/built-in/memory.js.map +1 -0
  101. package/dist/src/tools/built-in/notebook.d.ts +22 -0
  102. package/dist/src/tools/built-in/notebook.d.ts.map +1 -0
  103. package/dist/src/tools/built-in/notebook.js +207 -0
  104. package/dist/src/tools/built-in/notebook.js.map +1 -0
  105. package/package.json +1 -1
@@ -0,0 +1,299 @@
1
+ /**
2
+ * OpenAI-compatible LLM adapter for cmdr.
3
+ *
4
+ * Works with: OpenAI API, Groq, Together, OpenRouter, and any OpenAI-API-compatible provider.
5
+ * Uses the standard /v1/chat/completions endpoint.
6
+ */
7
+ export class OpenAIAdapter {
8
+ name;
9
+ baseUrl;
10
+ apiKey;
11
+ defaultHeaders;
12
+ constructor(options) {
13
+ this.apiKey = options.apiKey;
14
+ this.baseUrl = (options.baseUrl ?? 'https://api.openai.com/v1').replace(/\/$/, '');
15
+ this.name = options.name ?? 'openai';
16
+ this.defaultHeaders = options.headers ?? {};
17
+ }
18
+ // -----------------------------------------------------------------------
19
+ // LLMAdapter.chat
20
+ // -----------------------------------------------------------------------
21
+ async chat(messages, options) {
22
+ const body = {
23
+ model: options.model,
24
+ messages: this.convertMessages(messages, options.systemPrompt),
25
+ stream: false,
26
+ ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),
27
+ ...(options.maxTokens !== undefined ? { max_tokens: options.maxTokens } : {}),
28
+ };
29
+ if (options.tools && options.tools.length > 0) {
30
+ body.tools = options.tools.map(t => this.convertToolDef(t));
31
+ }
32
+ const res = await fetch(`${this.baseUrl}/chat/completions`, {
33
+ method: 'POST',
34
+ headers: {
35
+ 'Content-Type': 'application/json',
36
+ 'Authorization': `Bearer ${this.apiKey}`,
37
+ ...this.defaultHeaders,
38
+ },
39
+ body: JSON.stringify(body),
40
+ signal: options.abortSignal,
41
+ });
42
+ if (!res.ok) {
43
+ const text = await res.text();
44
+ throw new Error(`OpenAI API error (${res.status}): ${text.slice(0, 300)}`);
45
+ }
46
+ const data = await res.json();
47
+ const choice = data.choices[0];
48
+ if (!choice)
49
+ throw new Error('No choices in OpenAI response');
50
+ const content = this.parseAssistantMessage(choice.message);
51
+ const hasToolUse = content.some(b => b.type === 'tool_use');
52
+ const usage = {
53
+ input_tokens: data.usage?.prompt_tokens ?? 0,
54
+ output_tokens: data.usage?.completion_tokens ?? 0,
55
+ };
56
+ return {
57
+ id: data.id,
58
+ content,
59
+ model: data.model,
60
+ stop_reason: hasToolUse ? 'tool_use' : 'end_turn',
61
+ usage,
62
+ };
63
+ }
64
+ // -----------------------------------------------------------------------
65
+ // LLMAdapter.stream
66
+ // -----------------------------------------------------------------------
67
+ async *stream(messages, options) {
68
+ const body = {
69
+ model: options.model,
70
+ messages: this.convertMessages(messages, options.systemPrompt),
71
+ stream: true,
72
+ stream_options: { include_usage: true },
73
+ ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),
74
+ ...(options.maxTokens !== undefined ? { max_tokens: options.maxTokens } : {}),
75
+ };
76
+ if (options.tools && options.tools.length > 0) {
77
+ body.tools = options.tools.map(t => this.convertToolDef(t));
78
+ }
79
+ let res;
80
+ try {
81
+ res = await fetch(`${this.baseUrl}/chat/completions`, {
82
+ method: 'POST',
83
+ headers: {
84
+ 'Content-Type': 'application/json',
85
+ 'Authorization': `Bearer ${this.apiKey}`,
86
+ ...this.defaultHeaders,
87
+ },
88
+ body: JSON.stringify(body),
89
+ signal: options.abortSignal,
90
+ });
91
+ }
92
+ catch (err) {
93
+ yield { type: 'error', data: err instanceof Error ? err : new Error(String(err)) };
94
+ return;
95
+ }
96
+ if (!res.ok) {
97
+ const text = await res.text();
98
+ yield { type: 'error', data: new Error(`OpenAI API error (${res.status}): ${text.slice(0, 300)}`) };
99
+ return;
100
+ }
101
+ const reader = res.body?.getReader();
102
+ if (!reader) {
103
+ yield { type: 'error', data: new Error('No response body') };
104
+ return;
105
+ }
106
+ const decoder = new TextDecoder();
107
+ let buffer = '';
108
+ let fullText = '';
109
+ let totalUsage = { input_tokens: 0, output_tokens: 0 };
110
+ let model = options.model;
111
+ // Accumulate tool call deltas
112
+ const toolCallAccumulator = new Map();
113
+ try {
114
+ while (true) {
115
+ const { done, value } = await reader.read();
116
+ if (done)
117
+ break;
118
+ buffer += decoder.decode(value, { stream: true });
119
+ const lines = buffer.split('\n');
120
+ buffer = lines.pop() ?? '';
121
+ for (const line of lines) {
122
+ const trimmed = line.trim();
123
+ if (!trimmed || !trimmed.startsWith('data: '))
124
+ continue;
125
+ const payload = trimmed.slice(6);
126
+ if (payload === '[DONE]')
127
+ continue;
128
+ let chunk;
129
+ try {
130
+ chunk = JSON.parse(payload);
131
+ }
132
+ catch {
133
+ continue;
134
+ }
135
+ model = chunk.model || model;
136
+ if (chunk.usage) {
137
+ totalUsage = {
138
+ input_tokens: chunk.usage.prompt_tokens ?? 0,
139
+ output_tokens: chunk.usage.completion_tokens ?? 0,
140
+ };
141
+ }
142
+ const choice = chunk.choices?.[0];
143
+ if (!choice)
144
+ continue;
145
+ // Text content
146
+ if (choice.delta.content) {
147
+ fullText += choice.delta.content;
148
+ yield { type: 'text', data: choice.delta.content };
149
+ }
150
+ // Tool call deltas
151
+ if (choice.delta.tool_calls) {
152
+ for (const tc of choice.delta.tool_calls) {
153
+ const existing = toolCallAccumulator.get(tc.index);
154
+ if (existing) {
155
+ if (tc.function?.arguments)
156
+ existing.arguments += tc.function.arguments;
157
+ }
158
+ else {
159
+ toolCallAccumulator.set(tc.index, {
160
+ id: tc.id ?? `call_${Date.now()}_${tc.index}`,
161
+ name: tc.function?.name ?? '',
162
+ arguments: tc.function?.arguments ?? '',
163
+ });
164
+ }
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ finally {
171
+ reader.releaseLock();
172
+ }
173
+ // Emit accumulated tool calls
174
+ for (const [, tc] of toolCallAccumulator) {
175
+ let args = {};
176
+ try {
177
+ args = JSON.parse(tc.arguments);
178
+ }
179
+ catch { /* malformed args */ }
180
+ const toolUseBlock = {
181
+ type: 'tool_use',
182
+ id: tc.id,
183
+ name: tc.name,
184
+ input: args,
185
+ };
186
+ yield { type: 'tool_use', data: toolUseBlock };
187
+ }
188
+ // Done event
189
+ const content = [];
190
+ if (fullText)
191
+ content.push({ type: 'text', text: fullText });
192
+ for (const [, tc] of toolCallAccumulator) {
193
+ let args = {};
194
+ try {
195
+ args = JSON.parse(tc.arguments);
196
+ }
197
+ catch { /* */ }
198
+ content.push({ type: 'tool_use', id: tc.id, name: tc.name, input: args });
199
+ }
200
+ yield {
201
+ type: 'done',
202
+ data: {
203
+ id: `openai_${Date.now()}`,
204
+ content,
205
+ model,
206
+ stop_reason: toolCallAccumulator.size > 0 ? 'tool_use' : 'end_turn',
207
+ usage: totalUsage,
208
+ },
209
+ };
210
+ }
211
+ // -----------------------------------------------------------------------
212
+ // Message conversion
213
+ // -----------------------------------------------------------------------
214
+ convertMessages(messages, systemPrompt) {
215
+ const result = [];
216
+ if (systemPrompt) {
217
+ result.push({ role: 'system', content: systemPrompt });
218
+ }
219
+ for (const msg of messages) {
220
+ if (msg.role === 'user') {
221
+ // Check if this is a tool result message
222
+ const toolResults = msg.content.filter((b) => b.type === 'tool_result');
223
+ if (toolResults.length > 0) {
224
+ for (const tr of toolResults) {
225
+ result.push({
226
+ role: 'tool',
227
+ tool_call_id: tr.tool_use_id,
228
+ content: tr.content,
229
+ });
230
+ }
231
+ }
232
+ else {
233
+ const text = msg.content
234
+ .filter((b) => b.type === 'text')
235
+ .map(b => b.text)
236
+ .join('');
237
+ if (text)
238
+ result.push({ role: 'user', content: text });
239
+ }
240
+ }
241
+ else if (msg.role === 'assistant') {
242
+ const text = msg.content
243
+ .filter((b) => b.type === 'text')
244
+ .map(b => b.text)
245
+ .join('');
246
+ const toolCalls = msg.content
247
+ .filter((b) => b.type === 'tool_use')
248
+ .map(tc => ({
249
+ id: tc.id,
250
+ type: 'function',
251
+ function: {
252
+ name: tc.name,
253
+ arguments: JSON.stringify(tc.input),
254
+ },
255
+ }));
256
+ const chatMsg = {
257
+ role: 'assistant',
258
+ ...(text ? { content: text } : { content: null }),
259
+ ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
260
+ };
261
+ result.push(chatMsg);
262
+ }
263
+ }
264
+ return result;
265
+ }
266
+ parseAssistantMessage(msg) {
267
+ const content = [];
268
+ if (msg.content) {
269
+ content.push({ type: 'text', text: msg.content });
270
+ }
271
+ if (msg.tool_calls) {
272
+ for (const tc of msg.tool_calls) {
273
+ let args = {};
274
+ try {
275
+ args = JSON.parse(tc.function.arguments);
276
+ }
277
+ catch { /* */ }
278
+ content.push({
279
+ type: 'tool_use',
280
+ id: tc.id,
281
+ name: tc.function.name,
282
+ input: args,
283
+ });
284
+ }
285
+ }
286
+ return content;
287
+ }
288
+ convertToolDef(tool) {
289
+ return {
290
+ type: 'function',
291
+ function: {
292
+ name: tool.name,
293
+ description: tool.description,
294
+ parameters: tool.inputSchema,
295
+ },
296
+ };
297
+ }
298
+ }
299
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/llm/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Provider factory — creates the appropriate LLM adapter based on configuration.
3
+ *
4
+ * Supports:
5
+ * - ollama: Local inference via Ollama (default)
6
+ * - openai: OpenAI API (also works with Groq, Together, OpenRouter)
7
+ * - anthropic: Anthropic Claude API
8
+ *
9
+ * API keys are read from environment variables:
10
+ * - OPENAI_API_KEY (or CMDR_OPENAI_API_KEY)
11
+ * - ANTHROPIC_API_KEY (or CMDR_ANTHROPIC_API_KEY)
12
+ *
13
+ * Custom base URLs:
14
+ * - OPENAI_BASE_URL (e.g. https://openrouter.ai/api/v1)
15
+ * - ANTHROPIC_BASE_URL
16
+ */
17
+ import type { LLMAdapter } from '../core/types.js';
18
+ export type ProviderName = 'ollama' | 'openai' | 'anthropic';
19
+ export interface ProviderOptions {
20
+ provider: ProviderName;
21
+ ollamaUrl?: string;
22
+ apiKey?: string;
23
+ baseUrl?: string;
24
+ }
25
+ /**
26
+ * Create an LLM adapter for the given provider.
27
+ * Throws if required configuration (e.g. API key) is missing.
28
+ */
29
+ export declare function createAdapter(options: ProviderOptions): LLMAdapter;
30
+ /**
31
+ * Detect provider from model name pattern.
32
+ * Returns undefined if can't determine — falls back to config default.
33
+ */
34
+ export declare function detectProviderFromModel(model: string): ProviderName | undefined;
35
+ //# sourceMappingURL=provider-factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-factory.d.ts","sourceRoot":"","sources":["../../../src/llm/provider-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAKlD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAA;AAE5D,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,UAAU,CAuClE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAS/E"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Provider factory — creates the appropriate LLM adapter based on configuration.
3
+ *
4
+ * Supports:
5
+ * - ollama: Local inference via Ollama (default)
6
+ * - openai: OpenAI API (also works with Groq, Together, OpenRouter)
7
+ * - anthropic: Anthropic Claude API
8
+ *
9
+ * API keys are read from environment variables:
10
+ * - OPENAI_API_KEY (or CMDR_OPENAI_API_KEY)
11
+ * - ANTHROPIC_API_KEY (or CMDR_ANTHROPIC_API_KEY)
12
+ *
13
+ * Custom base URLs:
14
+ * - OPENAI_BASE_URL (e.g. https://openrouter.ai/api/v1)
15
+ * - ANTHROPIC_BASE_URL
16
+ */
17
+ import { OllamaAdapter } from './ollama.js';
18
+ import { OpenAIAdapter } from './openai.js';
19
+ import { AnthropicAdapter } from './anthropic.js';
20
+ /**
21
+ * Create an LLM adapter for the given provider.
22
+ * Throws if required configuration (e.g. API key) is missing.
23
+ */
24
+ export function createAdapter(options) {
25
+ switch (options.provider) {
26
+ case 'ollama':
27
+ return new OllamaAdapter(options.ollamaUrl ?? 'http://localhost:11434');
28
+ case 'openai': {
29
+ const apiKey = options.apiKey
30
+ ?? process.env.CMDR_OPENAI_API_KEY
31
+ ?? process.env.OPENAI_API_KEY;
32
+ if (!apiKey) {
33
+ throw new Error('OpenAI API key required. Set OPENAI_API_KEY or CMDR_OPENAI_API_KEY environment variable.');
34
+ }
35
+ return new OpenAIAdapter({
36
+ apiKey,
37
+ baseUrl: options.baseUrl ?? process.env.OPENAI_BASE_URL,
38
+ name: 'openai',
39
+ });
40
+ }
41
+ case 'anthropic': {
42
+ const apiKey = options.apiKey
43
+ ?? process.env.CMDR_ANTHROPIC_API_KEY
44
+ ?? process.env.ANTHROPIC_API_KEY;
45
+ if (!apiKey) {
46
+ throw new Error('Anthropic API key required. Set ANTHROPIC_API_KEY or CMDR_ANTHROPIC_API_KEY environment variable.');
47
+ }
48
+ return new AnthropicAdapter({
49
+ apiKey,
50
+ baseUrl: options.baseUrl ?? process.env.ANTHROPIC_BASE_URL,
51
+ });
52
+ }
53
+ default:
54
+ throw new Error(`Unknown provider: ${options.provider}`);
55
+ }
56
+ }
57
+ /**
58
+ * Detect provider from model name pattern.
59
+ * Returns undefined if can't determine — falls back to config default.
60
+ */
61
+ export function detectProviderFromModel(model) {
62
+ // Claude models → Anthropic
63
+ if (/^claude-/i.test(model))
64
+ return 'anthropic';
65
+ // GPT/o1/o3 models → OpenAI
66
+ if (/^(gpt-|o1|o3|chatgpt)/i.test(model))
67
+ return 'openai';
68
+ // Models with colons are typically Ollama tags (e.g. qwen2.5-coder:14b)
69
+ if (model.includes(':'))
70
+ return 'ollama';
71
+ return undefined;
72
+ }
73
+ //# sourceMappingURL=provider-factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-factory.js","sourceRoot":"","sources":["../../../src/llm/provider-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAWjD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAwB;IACpD,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,SAAS,IAAI,wBAAwB,CAAC,CAAA;QAEzE,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;mBACxB,OAAO,CAAC,GAAG,CAAC,mBAAmB;mBAC/B,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;YAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F,CAAA;YACH,CAAC;YACD,OAAO,IAAI,aAAa,CAAC;gBACvB,MAAM;gBACN,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe;gBACvD,IAAI,EAAE,QAAQ;aACf,CAAC,CAAA;QACJ,CAAC;QAED,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;mBACxB,OAAO,CAAC,GAAG,CAAC,sBAAsB;mBAClC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAA;YAClC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CACb,mGAAmG,CACpG,CAAA;YACH,CAAC;YACD,OAAO,IAAI,gBAAgB,CAAC;gBAC1B,MAAM;gBACN,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;aAC3D,CAAC,CAAA;QACJ,CAAC;QAED;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC5D,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,4BAA4B;IAC5B,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAA;IAC/C,4BAA4B;IAC5B,IAAI,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAA;IACzD,wEAAwE;IACxE,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAA;IAExC,OAAO,SAAS,CAAA;AAClB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Memory Consolidation — the "auto-dream" system for cmdr.
3
+ *
4
+ * After a session ends, consolidation reviews the conversation to extract
5
+ * learnings and update MEMORY.md files. This follows a 4-stage pipeline:
6
+ *
7
+ * 1. Orient — Identify what the session was about (project, topic, scope)
8
+ * 2. Gather — Extract actionable learnings from the conversation
9
+ * 3. Consolidate — Merge new learnings with existing memory, dedup
10
+ * 4. Prune — Remove stale or contradicted entries, enforce size budget
11
+ *
12
+ * Triggered automatically at session end or via /compact command.
13
+ */
14
+ import type { LLMAdapter, LLMMessage } from '../core/types.js';
15
+ import type { MemoryManager } from './memory-manager.js';
16
+ interface ConsolidationResult {
17
+ learningsFound: number;
18
+ memoryUpdated: boolean;
19
+ scope: 'project' | 'user';
20
+ }
21
+ export declare class MemoryConsolidator {
22
+ private readonly memoryManager;
23
+ private readonly adapter;
24
+ private readonly model;
25
+ constructor(memoryManager: MemoryManager, adapter: LLMAdapter, model: string);
26
+ /**
27
+ * Run the full consolidation pipeline on a completed session's messages.
28
+ * Returns info about what was updated.
29
+ */
30
+ consolidate(messages: LLMMessage[], scope?: 'project' | 'user'): Promise<ConsolidationResult>;
31
+ /** Stage 2: Extract learnings from conversation messages. */
32
+ private gatherLearnings;
33
+ /** Stage 3 & 4: Merge new learnings with existing memory. */
34
+ private consolidateMemory;
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=consolidation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidation.d.ts","sourceRoot":"","sources":["../../../src/memory/consolidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAA6B,MAAM,kBAAkB,CAAA;AACzF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AA+BxD,UAAU,mBAAmB;IAC3B,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,OAAO,CAAA;IACtB,KAAK,EAAE,SAAS,GAAG,MAAM,CAAA;CAC1B;AAED,qBAAa,kBAAkB;IAE3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAFL,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM;IAGhC;;;OAGG;IACG,WAAW,CACf,QAAQ,EAAE,UAAU,EAAE,EACtB,KAAK,GAAE,SAAS,GAAG,MAAkB,GACpC,OAAO,CAAC,mBAAmB,CAAC;IAgC/B,6DAA6D;YAC/C,eAAe;IAyC7B,6DAA6D;YAC/C,iBAAiB;CA+BhC"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Memory Consolidation — the "auto-dream" system for cmdr.
3
+ *
4
+ * After a session ends, consolidation reviews the conversation to extract
5
+ * learnings and update MEMORY.md files. This follows a 4-stage pipeline:
6
+ *
7
+ * 1. Orient — Identify what the session was about (project, topic, scope)
8
+ * 2. Gather — Extract actionable learnings from the conversation
9
+ * 3. Consolidate — Merge new learnings with existing memory, dedup
10
+ * 4. Prune — Remove stale or contradicted entries, enforce size budget
11
+ *
12
+ * Triggered automatically at session end or via /compact command.
13
+ */
14
+ const GATHER_PROMPT = `You are a memory consolidation agent. Analyze this conversation and extract key learnings.
15
+
16
+ Focus on:
17
+ - Project conventions discovered (naming, structure, patterns)
18
+ - User preferences observed (style, tools, workflow)
19
+ - Technical decisions made and their rationale
20
+ - Bugs found and solutions applied
21
+ - Common patterns that should be remembered
22
+
23
+ Output a bulleted list of concise, actionable learnings. Each item should be self-contained.
24
+ Do NOT include conversation-specific details that won't be useful in future sessions.
25
+ Do NOT include transient information (file paths of temporary files, specific error messages that were fixed).
26
+
27
+ If there are no meaningful learnings to extract, output exactly: NO_LEARNINGS`;
28
+ const CONSOLIDATE_PROMPT = `You are a memory manager. Given existing memory and new learnings, produce a consolidated MEMORY.md.
29
+
30
+ Rules:
31
+ - Merge duplicates: if a new learning matches an existing entry, keep the more specific/recent one
32
+ - Remove contradictions: if a new learning contradicts an old one, keep the new one
33
+ - Group by topic: use ## headers (preferences, conventions, patterns, decisions)
34
+ - Keep each entry as a concise bullet point
35
+ - Stay under {MAX_LINES} lines total
36
+ - Preserve date annotations where useful
37
+
38
+ Output the final consolidated markdown content. No preamble, just the content.`;
39
+ const MAX_MEMORY_LINES = 150;
40
+ export class MemoryConsolidator {
41
+ memoryManager;
42
+ adapter;
43
+ model;
44
+ constructor(memoryManager, adapter, model) {
45
+ this.memoryManager = memoryManager;
46
+ this.adapter = adapter;
47
+ this.model = model;
48
+ }
49
+ /**
50
+ * Run the full consolidation pipeline on a completed session's messages.
51
+ * Returns info about what was updated.
52
+ */
53
+ async consolidate(messages, scope = 'project') {
54
+ // Skip tiny sessions — not enough to learn from
55
+ if (messages.length < 4) {
56
+ return { learningsFound: 0, memoryUpdated: false, scope };
57
+ }
58
+ // Stage 1 & 2: Gather learnings from conversation
59
+ const learnings = await this.gatherLearnings(messages);
60
+ if (!learnings || learnings === 'NO_LEARNINGS') {
61
+ return { learningsFound: 0, memoryUpdated: false, scope };
62
+ }
63
+ const learningsList = learnings.split('\n').filter(l => l.trim().startsWith('-') || l.trim().startsWith('*'));
64
+ if (learningsList.length === 0) {
65
+ return { learningsFound: 0, memoryUpdated: false, scope };
66
+ }
67
+ // Stage 3 & 4: Consolidate with existing memory
68
+ const existingMemory = await this.memoryManager.read(scope);
69
+ const consolidated = await this.consolidateMemory(existingMemory, learnings);
70
+ if (consolidated && consolidated.trim()) {
71
+ await this.memoryManager.write(scope, consolidated);
72
+ }
73
+ return {
74
+ learningsFound: learningsList.length,
75
+ memoryUpdated: true,
76
+ scope,
77
+ };
78
+ }
79
+ /** Stage 2: Extract learnings from conversation messages. */
80
+ async gatherLearnings(messages) {
81
+ // Build a condensed transcript for the LLM
82
+ const transcript = messages
83
+ .filter(m => !m.isMeta && !m.isVisibleInTranscriptOnly)
84
+ .map(m => {
85
+ const texts = m.content
86
+ .filter((b) => b.type === 'text')
87
+ .map(b => b.text)
88
+ .join('');
89
+ return `[${m.role}]: ${texts.slice(0, 2000)}`;
90
+ })
91
+ .join('\n\n');
92
+ // Limit transcript size for the LLM call
93
+ const truncated = transcript.length > 12_000
94
+ ? transcript.slice(0, 6000) + '\n\n...(middle omitted)...\n\n' + transcript.slice(-6000)
95
+ : transcript;
96
+ const chatMessages = [
97
+ { role: 'user', content: [{ type: 'text', text: `Here is the conversation to analyze:\n\n${truncated}` }] },
98
+ ];
99
+ const options = {
100
+ model: this.model,
101
+ systemPrompt: GATHER_PROMPT,
102
+ maxTokens: 1024,
103
+ temperature: 0.3,
104
+ };
105
+ try {
106
+ const response = await this.adapter.chat(chatMessages, options);
107
+ const text = response.content
108
+ .filter((b) => b.type === 'text')
109
+ .map(b => b.text)
110
+ .join('');
111
+ return text.trim();
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }
117
+ /** Stage 3 & 4: Merge new learnings with existing memory. */
118
+ async consolidateMemory(existing, newLearnings) {
119
+ const prompt = CONSOLIDATE_PROMPT.replace('{MAX_LINES}', String(MAX_MEMORY_LINES));
120
+ const chatMessages = [
121
+ {
122
+ role: 'user',
123
+ content: [{
124
+ type: 'text',
125
+ text: `## Existing Memory\n\n${existing || '(empty — first session)'}\n\n## New Learnings\n\n${newLearnings}`,
126
+ }],
127
+ },
128
+ ];
129
+ const options = {
130
+ model: this.model,
131
+ systemPrompt: prompt,
132
+ maxTokens: 2048,
133
+ temperature: 0.2,
134
+ };
135
+ try {
136
+ const response = await this.adapter.chat(chatMessages, options);
137
+ const text = response.content
138
+ .filter((b) => b.type === 'text')
139
+ .map(b => b.text)
140
+ .join('');
141
+ return text.trim();
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ }
147
+ }
148
+ //# sourceMappingURL=consolidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidation.js","sourceRoot":"","sources":["../../../src/memory/consolidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,MAAM,aAAa,GAAG;;;;;;;;;;;;;8EAawD,CAAA;AAE9E,MAAM,kBAAkB,GAAG;;;;;;;;;;+EAUoD,CAAA;AAE/E,MAAM,gBAAgB,GAAG,GAAG,CAAA;AAQ5B,MAAM,OAAO,kBAAkB;IAEV;IACA;IACA;IAHnB,YACmB,aAA4B,EAC5B,OAAmB,EACnB,KAAa;QAFb,kBAAa,GAAb,aAAa,CAAe;QAC5B,YAAO,GAAP,OAAO,CAAY;QACnB,UAAK,GAAL,KAAK,CAAQ;IAC7B,CAAC;IAEJ;;;OAGG;IACH,KAAK,CAAC,WAAW,CACf,QAAsB,EACtB,QAA4B,SAAS;QAErC,gDAAgD;QAChD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QAC3D,CAAC;QAED,kDAAkD;QAClD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,cAAc,EAAE,CAAC;YAC/C,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QAC3D,CAAC;QAED,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;QAC7G,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QAC3D,CAAC;QAED,gDAAgD;QAChD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC3D,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,cAAc,EAAE,SAAS,CAAC,CAAA;QAE5E,IAAI,YAAY,IAAI,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;YACxC,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,YAAY,CAAC,CAAA;QACrD,CAAC;QAED,OAAO;YACL,cAAc,EAAE,aAAa,CAAC,MAAM;YACpC,aAAa,EAAE,IAAI;YACnB,KAAK;SACN,CAAA;IACH,CAAC;IAED,6DAA6D;IACrD,KAAK,CAAC,eAAe,CAAC,QAAsB;QAClD,2CAA2C;QAC3C,MAAM,UAAU,GAAG,QAAQ;aACxB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,yBAAyB,CAAC;aACtD,GAAG,CAAC,CAAC,CAAC,EAAE;YACP,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO;iBACpB,MAAM,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;iBAChD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBAChB,IAAI,CAAC,EAAE,CAAC,CAAA;YACX,OAAO,IAAI,CAAC,CAAC,IAAI,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAA;QAC/C,CAAC,CAAC;aACD,IAAI,CAAC,MAAM,CAAC,CAAA;QAEf,yCAAyC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,GAAG,MAAM;YAC1C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,gCAAgC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;YACxF,CAAC,CAAC,UAAU,CAAA;QAEd,MAAM,YAAY,GAAiB;YACjC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2CAA2C,SAAS,EAAE,EAAE,CAAC,EAAE;SAC5G,CAAA;QAED,MAAM,OAAO,GAAmB;YAC9B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,aAAa;YAC3B,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,GAAG;SACjB,CAAA;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;YAC/D,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO;iBAC1B,MAAM,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;iBAChD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBAChB,IAAI,CAAC,EAAE,CAAC,CAAA;YACX,OAAO,IAAI,CAAC,IAAI,EAAE,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,6DAA6D;IACrD,KAAK,CAAC,iBAAiB,CAAC,QAAgB,EAAE,YAAoB;QACpE,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAA;QAElF,MAAM,YAAY,GAAiB;YACjC;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,yBAAyB,QAAQ,IAAI,yBAAyB,2BAA2B,YAAY,EAAE;qBAC9G,CAAC;aACH;SACF,CAAA;QAED,MAAM,OAAO,GAAmB;YAC9B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,MAAM;YACpB,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,GAAG;SACjB,CAAA;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;YAC/D,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO;iBAC1B,MAAM,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;iBAChD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBAChB,IAAI,CAAC,EAAE,CAAC,CAAA;YACX,OAAO,IAAI,CAAC,IAAI,EAAE,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;CACF"}