cmdr-agent 2.5.5 → 3.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.
- package/README.md +42 -2
- package/dist/bin/cmdr.js +64 -3
- package/dist/bin/cmdr.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/src/cli/args.d.ts +11 -2
- package/dist/src/cli/args.d.ts.map +1 -1
- package/dist/src/cli/args.js +49 -8
- package/dist/src/cli/args.js.map +1 -1
- package/dist/src/cli/buddy.d.ts +49 -0
- package/dist/src/cli/buddy.d.ts.map +1 -0
- package/dist/src/cli/buddy.js +187 -0
- package/dist/src/cli/buddy.js.map +1 -0
- package/dist/src/cli/commands.js +105 -11
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/daemon.d.ts +45 -0
- package/dist/src/cli/daemon.d.ts.map +1 -0
- package/dist/src/cli/daemon.js +157 -0
- package/dist/src/cli/daemon.js.map +1 -0
- package/dist/src/cli/ink/App.d.ts.map +1 -1
- package/dist/src/cli/ink/App.js +257 -1
- package/dist/src/cli/ink/App.js.map +1 -1
- package/dist/src/cli/repl.d.ts +5 -3
- package/dist/src/cli/repl.d.ts.map +1 -1
- package/dist/src/cli/repl.js +72 -20
- package/dist/src/cli/repl.js.map +1 -1
- package/dist/src/core/agent.d.ts +2 -0
- package/dist/src/core/agent.d.ts.map +1 -1
- package/dist/src/core/agent.js +13 -0
- package/dist/src/core/agent.js.map +1 -1
- package/dist/src/core/types.d.ts +16 -1
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/types.js +6 -0
- package/dist/src/core/types.js.map +1 -1
- package/dist/src/index.d.ts +13 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/llm/anthropic.d.ts.map +1 -1
- package/dist/src/llm/anthropic.js +11 -0
- package/dist/src/llm/anthropic.js.map +1 -1
- package/dist/src/llm/ollama.d.ts.map +1 -1
- package/dist/src/llm/ollama.js +8 -1
- package/dist/src/llm/ollama.js.map +1 -1
- package/dist/src/llm/openai.d.ts.map +1 -1
- package/dist/src/llm/openai.js +21 -6
- package/dist/src/llm/openai.js.map +1 -1
- package/dist/src/memory/index-manager.d.ts +65 -0
- package/dist/src/memory/index-manager.d.ts.map +1 -0
- package/dist/src/memory/index-manager.js +241 -0
- package/dist/src/memory/index-manager.js.map +1 -0
- package/dist/src/server/index.d.ts +20 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +281 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/session/branch-manager.d.ts +39 -0
- package/dist/src/session/branch-manager.d.ts.map +1 -0
- package/dist/src/session/branch-manager.js +142 -0
- package/dist/src/session/branch-manager.js.map +1 -0
- package/dist/src/session/checkpoint-manager.d.ts +28 -0
- package/dist/src/session/checkpoint-manager.d.ts.map +1 -0
- package/dist/src/session/checkpoint-manager.js +96 -0
- package/dist/src/session/checkpoint-manager.js.map +1 -0
- package/dist/src/tools/built-in/browser.d.ts +32 -0
- package/dist/src/tools/built-in/browser.d.ts.map +1 -0
- package/dist/src/tools/built-in/browser.js +168 -0
- package/dist/src/tools/built-in/browser.js.map +1 -0
- package/dist/src/tools/built-in/git-diff.d.ts +1 -0
- package/dist/src/tools/built-in/git-diff.d.ts.map +1 -1
- package/dist/src/tools/built-in/git-diff.js +7 -2
- package/dist/src/tools/built-in/git-diff.js.map +1 -1
- package/dist/src/tools/built-in/index.d.ts +7 -1
- package/dist/src/tools/built-in/index.d.ts.map +1 -1
- package/dist/src/tools/built-in/index.js +19 -1
- package/dist/src/tools/built-in/index.js.map +1 -1
- package/dist/src/tools/built-in/rag-search.d.ts +12 -0
- package/dist/src/tools/built-in/rag-search.d.ts.map +1 -0
- package/dist/src/tools/built-in/rag-search.js +37 -0
- package/dist/src/tools/built-in/rag-search.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cmdr serve — HTTP/SSE server exposing the agent API.
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* POST /v1/chat — JSON request/response
|
|
6
|
+
* POST /v1/stream — SSE streaming response
|
|
7
|
+
* GET /health — health check
|
|
8
|
+
* GET /v1/models — list available models
|
|
9
|
+
*
|
|
10
|
+
* Uses Node.js built-in http module (no Express).
|
|
11
|
+
*/
|
|
12
|
+
import { createServer } from 'node:http';
|
|
13
|
+
import { Agent } from '../core/agent.js';
|
|
14
|
+
import { createAdapter } from '../llm/provider-factory.js';
|
|
15
|
+
import { ToolRegistry } from '../tools/registry.js';
|
|
16
|
+
import { registerBuiltInTools } from '../tools/built-in/index.js';
|
|
17
|
+
import { PermissionManager } from '../core/permissions.js';
|
|
18
|
+
import { SOLO_CODER } from '../core/presets.js';
|
|
19
|
+
import { discoverProject } from '../session/project-context.js';
|
|
20
|
+
import { buildSystemPrompt } from '../session/prompt-builder.js';
|
|
21
|
+
import { discoverOllamaModels } from '../llm/model-registry.js';
|
|
22
|
+
import { MemoryManager } from '../memory/memory-manager.js';
|
|
23
|
+
/** Read request body as JSON, with a size limit. */
|
|
24
|
+
async function readBody(req, maxBytes = 10 * 1024 * 1024) {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const chunks = [];
|
|
27
|
+
let size = 0;
|
|
28
|
+
req.on('data', (chunk) => {
|
|
29
|
+
size += chunk.length;
|
|
30
|
+
if (size > maxBytes) {
|
|
31
|
+
req.destroy();
|
|
32
|
+
reject(new Error('Request body too large'));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
chunks.push(chunk);
|
|
36
|
+
});
|
|
37
|
+
req.on('end', () => {
|
|
38
|
+
try {
|
|
39
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
40
|
+
resolve(JSON.parse(body));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
reject(new Error('Invalid JSON'));
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
req.on('error', reject);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function sendJson(res, status, data) {
|
|
50
|
+
const body = JSON.stringify(data);
|
|
51
|
+
res.writeHead(status, {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
'Content-Length': Buffer.byteLength(body),
|
|
54
|
+
});
|
|
55
|
+
res.end(body);
|
|
56
|
+
}
|
|
57
|
+
function sendError(res, status, message) {
|
|
58
|
+
sendJson(res, status, { error: message });
|
|
59
|
+
}
|
|
60
|
+
/** Set CORS headers for development use. */
|
|
61
|
+
function setCorsHeaders(res) {
|
|
62
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
63
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
64
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
65
|
+
}
|
|
66
|
+
export async function startServer(options) {
|
|
67
|
+
const cwd = process.cwd();
|
|
68
|
+
// Resolve provider
|
|
69
|
+
const provider = options.provider ?? 'ollama';
|
|
70
|
+
const adapter = createAdapter({ provider, ollamaUrl: options.ollamaUrl });
|
|
71
|
+
// Discover project context
|
|
72
|
+
const projectContext = await discoverProject(cwd);
|
|
73
|
+
// Memory
|
|
74
|
+
const memoryManager = new MemoryManager(cwd);
|
|
75
|
+
const memoryPrompt = await memoryManager.getMemoryPrompt();
|
|
76
|
+
// System prompt
|
|
77
|
+
const systemPrompt = buildSystemPrompt({
|
|
78
|
+
basePrompt: SOLO_CODER.systemPrompt,
|
|
79
|
+
projectContext,
|
|
80
|
+
model: options.model,
|
|
81
|
+
memoryPrompt: memoryPrompt || undefined,
|
|
82
|
+
});
|
|
83
|
+
// Tools
|
|
84
|
+
const toolRegistry = new ToolRegistry();
|
|
85
|
+
registerBuiltInTools(toolRegistry);
|
|
86
|
+
// Permission manager (yolo for server mode — approvals aren't interactive)
|
|
87
|
+
const permissionManager = new PermissionManager('yolo');
|
|
88
|
+
// Discover models for Ollama
|
|
89
|
+
if (provider === 'ollama') {
|
|
90
|
+
const ollamaAdapter = adapter;
|
|
91
|
+
const healthy = await ollamaAdapter.healthCheck();
|
|
92
|
+
if (!healthy) {
|
|
93
|
+
console.error(`Cannot connect to Ollama at ${options.ollamaUrl}`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
await discoverOllamaModels(options.ollamaUrl);
|
|
97
|
+
}
|
|
98
|
+
/** Create a fresh agent for each request. */
|
|
99
|
+
function createAgent(model) {
|
|
100
|
+
const allowedToolNames = Array.from(new Set([
|
|
101
|
+
...(SOLO_CODER.tools ?? []),
|
|
102
|
+
...toolRegistry.list().map(t => t.name),
|
|
103
|
+
]));
|
|
104
|
+
return new Agent({
|
|
105
|
+
...SOLO_CODER,
|
|
106
|
+
model,
|
|
107
|
+
systemPrompt,
|
|
108
|
+
tools: allowedToolNames,
|
|
109
|
+
}, adapter, toolRegistry, cwd, permissionManager);
|
|
110
|
+
}
|
|
111
|
+
const server = createServer(async (req, res) => {
|
|
112
|
+
setCorsHeaders(res);
|
|
113
|
+
// Handle CORS preflight
|
|
114
|
+
if (req.method === 'OPTIONS') {
|
|
115
|
+
res.writeHead(204);
|
|
116
|
+
res.end();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const url = req.url ?? '/';
|
|
120
|
+
try {
|
|
121
|
+
// GET /health
|
|
122
|
+
if (req.method === 'GET' && url === '/health') {
|
|
123
|
+
sendJson(res, 200, {
|
|
124
|
+
status: 'ok',
|
|
125
|
+
model: options.model,
|
|
126
|
+
provider,
|
|
127
|
+
uptime: process.uptime(),
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// GET /v1/models
|
|
132
|
+
if (req.method === 'GET' && url === '/v1/models') {
|
|
133
|
+
if (provider === 'ollama') {
|
|
134
|
+
const ollamaAdapter = adapter;
|
|
135
|
+
const models = await ollamaAdapter.listModels();
|
|
136
|
+
sendJson(res, 200, { models });
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
sendJson(res, 200, { models: [options.model] });
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// POST /v1/chat — non-streaming chat
|
|
144
|
+
if (req.method === 'POST' && url === '/v1/chat') {
|
|
145
|
+
const body = await readBody(req);
|
|
146
|
+
if (!body?.message) {
|
|
147
|
+
sendError(res, 400, 'Missing "message" field');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const model = body.model ?? options.model;
|
|
151
|
+
const agent = createAgent(model);
|
|
152
|
+
const startTime = Date.now();
|
|
153
|
+
const toolsCalled = [];
|
|
154
|
+
let currentToolStart = 0;
|
|
155
|
+
let currentToolName = '';
|
|
156
|
+
let fullOutput = '';
|
|
157
|
+
for await (const event of agent.stream(body.message)) {
|
|
158
|
+
switch (event.type) {
|
|
159
|
+
case 'text':
|
|
160
|
+
fullOutput += event.data;
|
|
161
|
+
break;
|
|
162
|
+
case 'tool_use': {
|
|
163
|
+
const block = event.data;
|
|
164
|
+
currentToolName = block.name;
|
|
165
|
+
currentToolStart = Date.now();
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case 'tool_result': {
|
|
169
|
+
toolsCalled.push({ name: currentToolName, duration_ms: Date.now() - currentToolStart });
|
|
170
|
+
currentToolName = '';
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const state = agent.getState();
|
|
176
|
+
const tokens = state.tokenUsage;
|
|
177
|
+
sendJson(res, 200, {
|
|
178
|
+
model,
|
|
179
|
+
response: fullOutput,
|
|
180
|
+
tools_called: toolsCalled,
|
|
181
|
+
tokens: { input: tokens.input_tokens, output: tokens.output_tokens },
|
|
182
|
+
duration_ms: Date.now() - startTime,
|
|
183
|
+
});
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// POST /v1/stream — SSE streaming
|
|
187
|
+
if (req.method === 'POST' && url === '/v1/stream') {
|
|
188
|
+
const body = await readBody(req);
|
|
189
|
+
if (!body?.message) {
|
|
190
|
+
sendError(res, 400, 'Missing "message" field');
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const model = body.model ?? options.model;
|
|
194
|
+
const agent = createAgent(model);
|
|
195
|
+
const startTime = Date.now();
|
|
196
|
+
const toolsCalled = [];
|
|
197
|
+
let currentToolStart = 0;
|
|
198
|
+
let currentToolName = '';
|
|
199
|
+
res.writeHead(200, {
|
|
200
|
+
'Content-Type': 'text/event-stream',
|
|
201
|
+
'Cache-Control': 'no-cache',
|
|
202
|
+
'Connection': 'keep-alive',
|
|
203
|
+
'Access-Control-Allow-Origin': '*',
|
|
204
|
+
});
|
|
205
|
+
const sendEvent = (data) => {
|
|
206
|
+
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
207
|
+
};
|
|
208
|
+
try {
|
|
209
|
+
for await (const event of agent.stream(body.message)) {
|
|
210
|
+
switch (event.type) {
|
|
211
|
+
case 'text':
|
|
212
|
+
sendEvent({ type: 'text', data: event.data, timestamp: Date.now() });
|
|
213
|
+
break;
|
|
214
|
+
case 'tool_use': {
|
|
215
|
+
const block = event.data;
|
|
216
|
+
currentToolName = block.name;
|
|
217
|
+
currentToolStart = Date.now();
|
|
218
|
+
sendEvent({ type: 'tool_use', tool: block.name, input: block.input, timestamp: Date.now() });
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case 'tool_result': {
|
|
222
|
+
const block = event.data;
|
|
223
|
+
const duration_ms = Date.now() - currentToolStart;
|
|
224
|
+
toolsCalled.push({ name: currentToolName, duration_ms });
|
|
225
|
+
sendEvent({ type: 'tool_result', tool: currentToolName, output: block.content, is_error: block.is_error, duration_ms, timestamp: Date.now() });
|
|
226
|
+
currentToolName = '';
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
case 'error': {
|
|
230
|
+
const err = event.data;
|
|
231
|
+
sendEvent({ type: 'error', message: err.message, timestamp: Date.now() });
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
239
|
+
sendEvent({ type: 'error', message: msg, timestamp: Date.now() });
|
|
240
|
+
}
|
|
241
|
+
const state = agent.getState();
|
|
242
|
+
const tokens = state.tokenUsage;
|
|
243
|
+
sendEvent({
|
|
244
|
+
type: 'done',
|
|
245
|
+
tokens: { input: tokens.input_tokens, output: tokens.output_tokens },
|
|
246
|
+
duration_ms: Date.now() - startTime,
|
|
247
|
+
});
|
|
248
|
+
res.end();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// 404 for anything else
|
|
252
|
+
sendError(res, 404, `Not found: ${url}`);
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
256
|
+
console.error(`[cmdr serve] Error:`, msg);
|
|
257
|
+
if (!res.headersSent) {
|
|
258
|
+
sendError(res, 500, msg);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
server.listen(options.port, options.host, () => {
|
|
263
|
+
console.log(`cmdr serve running on http://${options.host}:${options.port}`);
|
|
264
|
+
console.log(` Model: ${options.model}`);
|
|
265
|
+
console.log(` Provider: ${provider}`);
|
|
266
|
+
console.log(` Endpoints:`);
|
|
267
|
+
console.log(` GET /health — health check`);
|
|
268
|
+
console.log(` GET /v1/models — list models`);
|
|
269
|
+
console.log(` POST /v1/chat — JSON chat`);
|
|
270
|
+
console.log(` POST /v1/stream — SSE streaming`);
|
|
271
|
+
});
|
|
272
|
+
// Graceful shutdown
|
|
273
|
+
const shutdown = () => {
|
|
274
|
+
console.log('\nShutting down cmdr serve...');
|
|
275
|
+
server.close();
|
|
276
|
+
process.exit(0);
|
|
277
|
+
};
|
|
278
|
+
process.on('SIGINT', shutdown);
|
|
279
|
+
process.on('SIGTERM', shutdown);
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BranchManager — fork, switch, and merge conversation branches.
|
|
3
|
+
*
|
|
4
|
+
* Branches are persisted as JSON files under:
|
|
5
|
+
* ~/.cmdr/sessions/{sessionId}/branches/{branch-id}.json
|
|
6
|
+
*
|
|
7
|
+
* Each branch stores a snapshot of the conversation at fork time,
|
|
8
|
+
* plus any messages added after the fork.
|
|
9
|
+
*/
|
|
10
|
+
import type { LLMMessage } from '../core/types.js';
|
|
11
|
+
export interface Branch {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly model: string;
|
|
15
|
+
readonly messages: LLMMessage[];
|
|
16
|
+
readonly messageCount: number;
|
|
17
|
+
readonly createdAt: string;
|
|
18
|
+
readonly parentBranch?: string;
|
|
19
|
+
readonly forkPoint: number;
|
|
20
|
+
}
|
|
21
|
+
export declare class BranchManager {
|
|
22
|
+
private sessionId;
|
|
23
|
+
private currentBranchId;
|
|
24
|
+
constructor(sessionId: string);
|
|
25
|
+
get activeBranch(): string | null;
|
|
26
|
+
/** Fork the conversation at the current point. */
|
|
27
|
+
fork(name: string, messages: LLMMessage[], model: string, parentBranch?: string): Promise<Branch>;
|
|
28
|
+
/** Switch to a branch by ID. Returns the branch data or null. */
|
|
29
|
+
switch(id: string): Promise<Branch | null>;
|
|
30
|
+
/** List all branches for this session, newest first. */
|
|
31
|
+
list(): Promise<Omit<Branch, 'messages'>[]>;
|
|
32
|
+
/** Merge branch messages onto a target (appends after fork point). */
|
|
33
|
+
merge(sourceId: string, targetMessages: LLMMessage[]): Promise<LLMMessage[] | null>;
|
|
34
|
+
/** Delete a branch by ID. */
|
|
35
|
+
delete(id: string): Promise<boolean>;
|
|
36
|
+
/** Save the current state of a branch (update messages). */
|
|
37
|
+
update(id: string, messages: LLMMessage[], model: string): Promise<boolean>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=branch-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-manager.d.ts","sourceRoot":"","sources":["../../../src/session/branch-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAKlD,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAMD,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,eAAe,CAAsB;gBAEjC,SAAS,EAAE,MAAM;IAI7B,IAAI,YAAY,IAAI,MAAM,GAAG,IAAI,CAEhC;IAED,kDAAkD;IAC5C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBvG,iEAAiE;IAC3D,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAchD,wDAAwD;IAClD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;IAmCjD,sEAAsE;IAChE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IASzF,6BAA6B;IACvB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAa1C,4DAA4D;IACtD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAmBlF"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BranchManager — fork, switch, and merge conversation branches.
|
|
3
|
+
*
|
|
4
|
+
* Branches are persisted as JSON files under:
|
|
5
|
+
* ~/.cmdr/sessions/{sessionId}/branches/{branch-id}.json
|
|
6
|
+
*
|
|
7
|
+
* Each branch stores a snapshot of the conversation at fork time,
|
|
8
|
+
* plus any messages added after the fork.
|
|
9
|
+
*/
|
|
10
|
+
import { readFile, writeFile, mkdir, readdir, unlink } from 'fs/promises';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { homedir } from 'os';
|
|
14
|
+
const CMDR_DIR = join(homedir(), '.cmdr');
|
|
15
|
+
const SESSIONS_DIR = join(CMDR_DIR, 'sessions');
|
|
16
|
+
function branchDir(sessionId) {
|
|
17
|
+
return join(SESSIONS_DIR, sessionId, 'branches');
|
|
18
|
+
}
|
|
19
|
+
export class BranchManager {
|
|
20
|
+
sessionId;
|
|
21
|
+
currentBranchId = null;
|
|
22
|
+
constructor(sessionId) {
|
|
23
|
+
this.sessionId = sessionId;
|
|
24
|
+
}
|
|
25
|
+
get activeBranch() {
|
|
26
|
+
return this.currentBranchId;
|
|
27
|
+
}
|
|
28
|
+
/** Fork the conversation at the current point. */
|
|
29
|
+
async fork(name, messages, model, parentBranch) {
|
|
30
|
+
const dir = branchDir(this.sessionId);
|
|
31
|
+
await mkdir(dir, { recursive: true });
|
|
32
|
+
const id = `br_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
33
|
+
const branch = {
|
|
34
|
+
id,
|
|
35
|
+
name,
|
|
36
|
+
model,
|
|
37
|
+
messages: [...messages],
|
|
38
|
+
messageCount: messages.length,
|
|
39
|
+
createdAt: new Date().toISOString(),
|
|
40
|
+
parentBranch,
|
|
41
|
+
forkPoint: messages.length,
|
|
42
|
+
};
|
|
43
|
+
await writeFile(join(dir, `${id}.json`), JSON.stringify(branch, null, 2), 'utf-8');
|
|
44
|
+
this.currentBranchId = id;
|
|
45
|
+
return branch;
|
|
46
|
+
}
|
|
47
|
+
/** Switch to a branch by ID. Returns the branch data or null. */
|
|
48
|
+
async switch(id) {
|
|
49
|
+
const filePath = join(branchDir(this.sessionId), `${id}.json`);
|
|
50
|
+
if (!existsSync(filePath))
|
|
51
|
+
return null;
|
|
52
|
+
try {
|
|
53
|
+
const data = await readFile(filePath, 'utf-8');
|
|
54
|
+
const branch = JSON.parse(data);
|
|
55
|
+
this.currentBranchId = id;
|
|
56
|
+
return branch;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** List all branches for this session, newest first. */
|
|
63
|
+
async list() {
|
|
64
|
+
const dir = branchDir(this.sessionId);
|
|
65
|
+
if (!existsSync(dir))
|
|
66
|
+
return [];
|
|
67
|
+
try {
|
|
68
|
+
const files = await readdir(dir);
|
|
69
|
+
const branches = [];
|
|
70
|
+
for (const file of files) {
|
|
71
|
+
if (!file.endsWith('.json'))
|
|
72
|
+
continue;
|
|
73
|
+
try {
|
|
74
|
+
const data = await readFile(join(dir, file), 'utf-8');
|
|
75
|
+
const br = JSON.parse(data);
|
|
76
|
+
branches.push({
|
|
77
|
+
id: br.id,
|
|
78
|
+
name: br.name,
|
|
79
|
+
model: br.model,
|
|
80
|
+
messageCount: br.messageCount,
|
|
81
|
+
createdAt: br.createdAt,
|
|
82
|
+
parentBranch: br.parentBranch,
|
|
83
|
+
forkPoint: br.forkPoint,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// skip malformed files
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return branches.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Merge branch messages onto a target (appends after fork point). */
|
|
97
|
+
async merge(sourceId, targetMessages) {
|
|
98
|
+
const source = await this.switch(sourceId);
|
|
99
|
+
if (!source)
|
|
100
|
+
return null;
|
|
101
|
+
// Messages added after fork point
|
|
102
|
+
const newMessages = source.messages.slice(source.forkPoint);
|
|
103
|
+
return [...targetMessages, ...newMessages];
|
|
104
|
+
}
|
|
105
|
+
/** Delete a branch by ID. */
|
|
106
|
+
async delete(id) {
|
|
107
|
+
const filePath = join(branchDir(this.sessionId), `${id}.json`);
|
|
108
|
+
if (!existsSync(filePath))
|
|
109
|
+
return false;
|
|
110
|
+
try {
|
|
111
|
+
await unlink(filePath);
|
|
112
|
+
if (this.currentBranchId === id)
|
|
113
|
+
this.currentBranchId = null;
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Save the current state of a branch (update messages). */
|
|
121
|
+
async update(id, messages, model) {
|
|
122
|
+
const filePath = join(branchDir(this.sessionId), `${id}.json`);
|
|
123
|
+
if (!existsSync(filePath))
|
|
124
|
+
return false;
|
|
125
|
+
try {
|
|
126
|
+
const data = await readFile(filePath, 'utf-8');
|
|
127
|
+
const branch = JSON.parse(data);
|
|
128
|
+
const updated = {
|
|
129
|
+
...branch,
|
|
130
|
+
messages: [...messages],
|
|
131
|
+
messageCount: messages.length,
|
|
132
|
+
model,
|
|
133
|
+
};
|
|
134
|
+
await writeFile(filePath, JSON.stringify(updated, null, 2), 'utf-8');
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=branch-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-manager.js","sourceRoot":"","sources":["../../../src/session/branch-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CheckpointManager — save and restore conversation snapshots.
|
|
3
|
+
*
|
|
4
|
+
* Checkpoints are persisted as JSON files under:
|
|
5
|
+
* ~/.cmdr/sessions/{sessionId}/checkpoints/{checkpoint-id}.json
|
|
6
|
+
*/
|
|
7
|
+
import type { LLMMessage } from '../core/types.js';
|
|
8
|
+
export interface Checkpoint {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
readonly model: string;
|
|
12
|
+
readonly messages: LLMMessage[];
|
|
13
|
+
readonly messageCount: number;
|
|
14
|
+
readonly createdAt: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class CheckpointManager {
|
|
17
|
+
private sessionId;
|
|
18
|
+
constructor(sessionId: string);
|
|
19
|
+
/** Save a checkpoint with an optional label. */
|
|
20
|
+
save(label: string, messages: LLMMessage[], model: string): Promise<Checkpoint>;
|
|
21
|
+
/** Restore a checkpoint by ID. Returns null if not found. */
|
|
22
|
+
restore(id: string): Promise<Checkpoint | null>;
|
|
23
|
+
/** List all checkpoints for this session, newest first. */
|
|
24
|
+
list(): Promise<Omit<Checkpoint, 'messages'>[]>;
|
|
25
|
+
/** Delete a checkpoint by ID. Returns true if deleted. */
|
|
26
|
+
delete(id: string): Promise<boolean>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=checkpoint-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint-manager.d.ts","sourceRoot":"","sources":["../../../src/session/checkpoint-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAKlD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAMD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,SAAS,CAAQ;gBAEb,SAAS,EAAE,MAAM;IAI7B,gDAAgD;IAC1C,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAkBrF,6DAA6D;IACvD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAYrD,2DAA2D;IACrD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC;IAiCrD,0DAA0D;IACpD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAW3C"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CheckpointManager — save and restore conversation snapshots.
|
|
3
|
+
*
|
|
4
|
+
* Checkpoints are persisted as JSON files under:
|
|
5
|
+
* ~/.cmdr/sessions/{sessionId}/checkpoints/{checkpoint-id}.json
|
|
6
|
+
*/
|
|
7
|
+
import { readFile, writeFile, mkdir, readdir, unlink } from 'fs/promises';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
const CMDR_DIR = join(homedir(), '.cmdr');
|
|
12
|
+
const SESSIONS_DIR = join(CMDR_DIR, 'sessions');
|
|
13
|
+
function checkpointDir(sessionId) {
|
|
14
|
+
return join(SESSIONS_DIR, sessionId, 'checkpoints');
|
|
15
|
+
}
|
|
16
|
+
export class CheckpointManager {
|
|
17
|
+
sessionId;
|
|
18
|
+
constructor(sessionId) {
|
|
19
|
+
this.sessionId = sessionId;
|
|
20
|
+
}
|
|
21
|
+
/** Save a checkpoint with an optional label. */
|
|
22
|
+
async save(label, messages, model) {
|
|
23
|
+
const dir = checkpointDir(this.sessionId);
|
|
24
|
+
await mkdir(dir, { recursive: true });
|
|
25
|
+
const id = `cp_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
26
|
+
const checkpoint = {
|
|
27
|
+
id,
|
|
28
|
+
label,
|
|
29
|
+
model,
|
|
30
|
+
messages: [...messages],
|
|
31
|
+
messageCount: messages.length,
|
|
32
|
+
createdAt: new Date().toISOString(),
|
|
33
|
+
};
|
|
34
|
+
await writeFile(join(dir, `${id}.json`), JSON.stringify(checkpoint, null, 2), 'utf-8');
|
|
35
|
+
return checkpoint;
|
|
36
|
+
}
|
|
37
|
+
/** Restore a checkpoint by ID. Returns null if not found. */
|
|
38
|
+
async restore(id) {
|
|
39
|
+
const filePath = join(checkpointDir(this.sessionId), `${id}.json`);
|
|
40
|
+
if (!existsSync(filePath))
|
|
41
|
+
return null;
|
|
42
|
+
try {
|
|
43
|
+
const data = await readFile(filePath, 'utf-8');
|
|
44
|
+
return JSON.parse(data);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** List all checkpoints for this session, newest first. */
|
|
51
|
+
async list() {
|
|
52
|
+
const dir = checkpointDir(this.sessionId);
|
|
53
|
+
if (!existsSync(dir))
|
|
54
|
+
return [];
|
|
55
|
+
try {
|
|
56
|
+
const files = await readdir(dir);
|
|
57
|
+
const checkpoints = [];
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
if (!file.endsWith('.json'))
|
|
60
|
+
continue;
|
|
61
|
+
try {
|
|
62
|
+
const data = await readFile(join(dir, file), 'utf-8');
|
|
63
|
+
const cp = JSON.parse(data);
|
|
64
|
+
checkpoints.push({
|
|
65
|
+
id: cp.id,
|
|
66
|
+
label: cp.label,
|
|
67
|
+
model: cp.model,
|
|
68
|
+
messageCount: cp.messageCount,
|
|
69
|
+
createdAt: cp.createdAt,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// skip malformed files
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return checkpoints.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Delete a checkpoint by ID. Returns true if deleted. */
|
|
83
|
+
async delete(id) {
|
|
84
|
+
const filePath = join(checkpointDir(this.sessionId), `${id}.json`);
|
|
85
|
+
if (!existsSync(filePath))
|
|
86
|
+
return false;
|
|
87
|
+
try {
|
|
88
|
+
await unlink(filePath);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=checkpoint-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint-manager.js","sourceRoot":"","sources":["../../../src/session/checkpoint-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser tools — optional Playwright-based browser automation.
|
|
3
|
+
*
|
|
4
|
+
* These tools are only registered when `--browser` is passed and
|
|
5
|
+
* playwright-core is available. Each tool dynamically imports
|
|
6
|
+
* playwright-core to avoid hard dependency.
|
|
7
|
+
*/
|
|
8
|
+
import type { ToolDefinition } from '../../core/types.js';
|
|
9
|
+
export declare const browserOpenTool: ToolDefinition<{
|
|
10
|
+
url: string;
|
|
11
|
+
waitUntil?: "load" | "domcontentloaded" | "networkidle" | undefined;
|
|
12
|
+
}>;
|
|
13
|
+
export declare const browserScreenshotTool: ToolDefinition<{
|
|
14
|
+
path?: string | undefined;
|
|
15
|
+
fullPage?: boolean | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const browserClickTool: ToolDefinition<{
|
|
18
|
+
selector: string;
|
|
19
|
+
}>;
|
|
20
|
+
export declare const browserFillTool: ToolDefinition<{
|
|
21
|
+
value: string;
|
|
22
|
+
selector: string;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const browserTextTool: ToolDefinition<{
|
|
25
|
+
selector?: string | undefined;
|
|
26
|
+
}>;
|
|
27
|
+
export declare const BROWSER_TOOLS: ToolDefinition<any>[];
|
|
28
|
+
/** Check if playwright-core is available. */
|
|
29
|
+
export declare function isPlaywrightAvailable(): Promise<boolean>;
|
|
30
|
+
/** Close the browser if open (for cleanup). */
|
|
31
|
+
export declare function closeBrowser(): Promise<void>;
|
|
32
|
+
//# sourceMappingURL=browser.d.ts.map
|