@variantree/watcher 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 (117) hide show
  1. package/dist/__tests__/git-snapshot.test.d.ts +2 -0
  2. package/dist/__tests__/git-snapshot.test.d.ts.map +1 -0
  3. package/dist/__tests__/git-snapshot.test.js +437 -0
  4. package/dist/__tests__/git-snapshot.test.js.map +1 -0
  5. package/dist/__tests__/integration.test.d.ts +10 -0
  6. package/dist/__tests__/integration.test.d.ts.map +1 -0
  7. package/dist/__tests__/integration.test.js +316 -0
  8. package/dist/__tests__/integration.test.js.map +1 -0
  9. package/dist/__tests__/watcher.test.d.ts +2 -0
  10. package/dist/__tests__/watcher.test.d.ts.map +1 -0
  11. package/dist/__tests__/watcher.test.js +375 -0
  12. package/dist/__tests__/watcher.test.js.map +1 -0
  13. package/dist/adapters/aider.d.ts +21 -0
  14. package/dist/adapters/aider.d.ts.map +1 -0
  15. package/dist/adapters/aider.js +42 -0
  16. package/dist/adapters/aider.js.map +1 -0
  17. package/dist/adapters/base.d.ts +3 -0
  18. package/dist/adapters/base.d.ts.map +1 -0
  19. package/dist/adapters/base.js +2 -0
  20. package/dist/adapters/base.js.map +1 -0
  21. package/dist/adapters/claude-code.d.ts +17 -0
  22. package/dist/adapters/claude-code.d.ts.map +1 -0
  23. package/dist/adapters/claude-code.js +58 -0
  24. package/dist/adapters/claude-code.js.map +1 -0
  25. package/dist/adapters/opencode.d.ts +3 -0
  26. package/dist/adapters/opencode.d.ts.map +1 -0
  27. package/dist/adapters/opencode.js +3 -0
  28. package/dist/adapters/opencode.js.map +1 -0
  29. package/dist/agents-md.d.ts +18 -0
  30. package/dist/agents-md.d.ts.map +1 -0
  31. package/dist/agents-md.js +93 -0
  32. package/dist/agents-md.js.map +1 -0
  33. package/dist/cli.d.ts +9 -0
  34. package/dist/cli.d.ts.map +1 -0
  35. package/dist/cli.js +511 -0
  36. package/dist/cli.js.map +1 -0
  37. package/dist/differ.d.ts +18 -0
  38. package/dist/differ.d.ts.map +1 -0
  39. package/dist/differ.js +23 -0
  40. package/dist/differ.js.map +1 -0
  41. package/dist/index.d.ts +17 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +23 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/node/blob-store.d.ts +16 -0
  46. package/dist/node/blob-store.d.ts.map +1 -0
  47. package/dist/node/blob-store.js +47 -0
  48. package/dist/node/blob-store.js.map +1 -0
  49. package/dist/node/fs-adapter.d.ts +17 -0
  50. package/dist/node/fs-adapter.d.ts.map +1 -0
  51. package/dist/node/fs-adapter.js +110 -0
  52. package/dist/node/fs-adapter.js.map +1 -0
  53. package/dist/node/git-snapshot.d.ts +46 -0
  54. package/dist/node/git-snapshot.d.ts.map +1 -0
  55. package/dist/node/git-snapshot.js +282 -0
  56. package/dist/node/git-snapshot.js.map +1 -0
  57. package/dist/node/session-launcher.d.ts +14 -0
  58. package/dist/node/session-launcher.d.ts.map +1 -0
  59. package/dist/node/session-launcher.js +28 -0
  60. package/dist/node/session-launcher.js.map +1 -0
  61. package/dist/node/storage.d.ts +17 -0
  62. package/dist/node/storage.d.ts.map +1 -0
  63. package/dist/node/storage.js +56 -0
  64. package/dist/node/storage.js.map +1 -0
  65. package/dist/sync.d.ts +16 -0
  66. package/dist/sync.d.ts.map +1 -0
  67. package/dist/sync.js +58 -0
  68. package/dist/sync.js.map +1 -0
  69. package/dist/tools/base.d.ts +52 -0
  70. package/dist/tools/base.d.ts.map +1 -0
  71. package/dist/tools/base.js +10 -0
  72. package/dist/tools/base.js.map +1 -0
  73. package/dist/tools/claudecode/adapter.d.ts +26 -0
  74. package/dist/tools/claudecode/adapter.d.ts.map +1 -0
  75. package/dist/tools/claudecode/adapter.js +111 -0
  76. package/dist/tools/claudecode/adapter.js.map +1 -0
  77. package/dist/tools/claudecode/config.d.ts +8 -0
  78. package/dist/tools/claudecode/config.d.ts.map +1 -0
  79. package/dist/tools/claudecode/config.js +34 -0
  80. package/dist/tools/claudecode/config.js.map +1 -0
  81. package/dist/tools/claudecode/index.d.ts +9 -0
  82. package/dist/tools/claudecode/index.d.ts.map +1 -0
  83. package/dist/tools/claudecode/index.js +16 -0
  84. package/dist/tools/claudecode/index.js.map +1 -0
  85. package/dist/tools/claudecode/instructions.d.ts +7 -0
  86. package/dist/tools/claudecode/instructions.d.ts.map +1 -0
  87. package/dist/tools/claudecode/instructions.js +21 -0
  88. package/dist/tools/claudecode/instructions.js.map +1 -0
  89. package/dist/tools/index.d.ts +24 -0
  90. package/dist/tools/index.d.ts.map +1 -0
  91. package/dist/tools/index.js +42 -0
  92. package/dist/tools/index.js.map +1 -0
  93. package/dist/tools/instructions.d.ts +19 -0
  94. package/dist/tools/instructions.d.ts.map +1 -0
  95. package/dist/tools/instructions.js +93 -0
  96. package/dist/tools/instructions.js.map +1 -0
  97. package/dist/tools/opencode/adapter.d.ts +46 -0
  98. package/dist/tools/opencode/adapter.d.ts.map +1 -0
  99. package/dist/tools/opencode/adapter.js +166 -0
  100. package/dist/tools/opencode/adapter.js.map +1 -0
  101. package/dist/tools/opencode/config.d.ts +8 -0
  102. package/dist/tools/opencode/config.d.ts.map +1 -0
  103. package/dist/tools/opencode/config.js +37 -0
  104. package/dist/tools/opencode/config.js.map +1 -0
  105. package/dist/tools/opencode/index.d.ts +9 -0
  106. package/dist/tools/opencode/index.d.ts.map +1 -0
  107. package/dist/tools/opencode/index.js +16 -0
  108. package/dist/tools/opencode/index.js.map +1 -0
  109. package/dist/tools/opencode/instructions.d.ts +10 -0
  110. package/dist/tools/opencode/instructions.d.ts.map +1 -0
  111. package/dist/tools/opencode/instructions.js +26 -0
  112. package/dist/tools/opencode/instructions.js.map +1 -0
  113. package/dist/watcher.d.ts +40 -0
  114. package/dist/watcher.d.ts.map +1 -0
  115. package/dist/watcher.js +87 -0
  116. package/dist/watcher.js.map +1 -0
  117. package/package.json +46 -0
@@ -0,0 +1,375 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { MessageDiffer } from '../differ.js';
3
+ import { OpenCodeAdapter } from '../tools/opencode/adapter.js';
4
+ import { ClaudeCodeAdapter } from '../tools/claudecode/adapter.js';
5
+ import { ensureProjectInstructions } from '../tools/index.js';
6
+ import { VARIANTREE_MARKER } from '../tools/instructions.js';
7
+ import { NodeStorage } from '../node/storage.js';
8
+ import Database from 'better-sqlite3';
9
+ import fs from 'node:fs/promises';
10
+ import fsSync from 'node:fs';
11
+ import path from 'node:path';
12
+ import os from 'node:os';
13
+ // ─── MessageDiffer ────────────────────────────────────────────────────────
14
+ describe('MessageDiffer', () => {
15
+ let differ;
16
+ beforeEach(() => {
17
+ differ = new MessageDiffer();
18
+ });
19
+ it('should return all messages on first call', () => {
20
+ const msgs = [
21
+ { id: '1', role: 'user', content: 'hello', timestamp: 1 },
22
+ { id: '2', role: 'assistant', content: 'hi', timestamp: 2 },
23
+ ];
24
+ const result = differ.diff(msgs);
25
+ expect(result).toHaveLength(2);
26
+ expect(result[0].content).toBe('hello');
27
+ expect(result[1].content).toBe('hi');
28
+ });
29
+ it('should return only new messages on subsequent calls', () => {
30
+ const msgs1 = [
31
+ { id: '1', role: 'user', content: 'hello', timestamp: 1 },
32
+ ];
33
+ differ.diff(msgs1);
34
+ const msgs2 = [
35
+ { id: '1', role: 'user', content: 'hello', timestamp: 1 },
36
+ { id: '2', role: 'assistant', content: 'hi', timestamp: 2 },
37
+ ];
38
+ const result = differ.diff(msgs2);
39
+ expect(result).toHaveLength(1);
40
+ expect(result[0].content).toBe('hi');
41
+ });
42
+ it('should return empty when nothing changed', () => {
43
+ const msgs = [
44
+ { id: '1', role: 'user', content: 'hello', timestamp: 1 },
45
+ ];
46
+ differ.diff(msgs);
47
+ const result = differ.diff(msgs);
48
+ expect(result).toHaveLength(0);
49
+ });
50
+ it('should handle multiple new messages', () => {
51
+ differ.diff([]);
52
+ const msgs = [
53
+ { id: '1', role: 'user', content: 'a', timestamp: 1 },
54
+ { id: '2', role: 'assistant', content: 'b', timestamp: 2 },
55
+ { id: '3', role: 'user', content: 'c', timestamp: 3 },
56
+ ];
57
+ const result = differ.diff(msgs);
58
+ expect(result).toHaveLength(3);
59
+ });
60
+ it('should reset properly', () => {
61
+ const msgs = [
62
+ { id: '1', role: 'user', content: 'hello', timestamp: 1 },
63
+ ];
64
+ differ.diff(msgs);
65
+ differ.reset();
66
+ const result = differ.diff(msgs);
67
+ expect(result).toHaveLength(1);
68
+ });
69
+ });
70
+ // ─── OpenCodeAdapter ─────────────────────────────────────────────────────
71
+ describe('OpenCodeAdapter', () => {
72
+ let tmpDir;
73
+ let dbPath;
74
+ beforeEach(async () => {
75
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vt-opencode-'));
76
+ dbPath = path.join(tmpDir, 'opencode.db');
77
+ });
78
+ afterEach(async () => {
79
+ await fs.rm(tmpDir, { recursive: true, force: true });
80
+ });
81
+ function createTestDb(workspaceDir, messages) {
82
+ const db = new Database(dbPath);
83
+ db.exec(`CREATE TABLE project (id TEXT PRIMARY KEY)`);
84
+ db.exec(`INSERT INTO project VALUES ('proj1')`);
85
+ db.exec(`CREATE TABLE session (
86
+ id TEXT PRIMARY KEY,
87
+ project_id TEXT NOT NULL,
88
+ parent_id TEXT,
89
+ slug TEXT NOT NULL,
90
+ directory TEXT NOT NULL,
91
+ title TEXT NOT NULL,
92
+ version TEXT NOT NULL,
93
+ share_url TEXT,
94
+ summary_additions INTEGER,
95
+ summary_deletions INTEGER,
96
+ summary_files INTEGER,
97
+ summary_diffs TEXT,
98
+ revert TEXT,
99
+ permission TEXT,
100
+ time_created INTEGER NOT NULL,
101
+ time_updated INTEGER NOT NULL,
102
+ time_compacting INTEGER,
103
+ time_archived INTEGER,
104
+ workspace_id TEXT
105
+ )`);
106
+ db.exec(`CREATE TABLE message (
107
+ id TEXT PRIMARY KEY,
108
+ session_id TEXT NOT NULL,
109
+ time_created INTEGER NOT NULL,
110
+ time_updated INTEGER NOT NULL,
111
+ data TEXT NOT NULL
112
+ )`);
113
+ db.exec(`CREATE TABLE part (
114
+ id TEXT PRIMARY KEY,
115
+ message_id TEXT NOT NULL,
116
+ session_id TEXT NOT NULL,
117
+ time_created INTEGER NOT NULL,
118
+ time_updated INTEGER NOT NULL,
119
+ data TEXT NOT NULL
120
+ )`);
121
+ const lastTime = messages.length > 0 ? messages[messages.length - 1].time : 1000;
122
+ db.prepare(`INSERT INTO session VALUES (
123
+ 'ses_test1', 'proj1', NULL, 'test', ?,
124
+ 'Test Session', '1.0', NULL, NULL, NULL, NULL, NULL, NULL, NULL,
125
+ 1000, ?, NULL, NULL, NULL
126
+ )`).run(workspaceDir, lastTime);
127
+ const insertMsg = db.prepare(`INSERT INTO message VALUES (?, 'ses_test1', ?, ?, ?)`);
128
+ const insertPart = db.prepare(`INSERT INTO part VALUES (?, ?, 'ses_test1', ?, ?, ?)`);
129
+ messages.forEach((msg, i) => {
130
+ const msgId = `msg_${i}`;
131
+ insertMsg.run(msgId, msg.time, msg.time, JSON.stringify({ role: msg.role }));
132
+ insertPart.run(`prt_${i}`, msgId, msg.time, msg.time, JSON.stringify({ type: 'text', text: msg.content }));
133
+ });
134
+ db.close();
135
+ }
136
+ function makeAdapter() {
137
+ const adapter = new OpenCodeAdapter();
138
+ adapter.getDbPath = () => dbPath;
139
+ return adapter;
140
+ }
141
+ it('has correct adapter name', () => {
142
+ expect(new OpenCodeAdapter().name).toBe('opencode');
143
+ });
144
+ it('reads messages from SQLite', async () => {
145
+ createTestDb('/test/ws', [
146
+ { role: 'user', content: 'Add JWT auth', time: 1000 },
147
+ { role: 'assistant', content: 'Here is the middleware...', time: 2000 },
148
+ ]);
149
+ const result = await makeAdapter().readMessagesAsync('/test/ws');
150
+ expect(result).toHaveLength(2);
151
+ expect(result[0].role).toBe('user');
152
+ expect(result[0].content).toBe('Add JWT auth');
153
+ expect(result[1].role).toBe('assistant');
154
+ });
155
+ it('preserves message order by time_created', async () => {
156
+ createTestDb('/test/ws', [
157
+ { role: 'user', content: 'first', time: 100 },
158
+ { role: 'assistant', content: 'second', time: 200 },
159
+ { role: 'user', content: 'third', time: 300 },
160
+ ]);
161
+ const result = await makeAdapter().readMessagesAsync('/test/ws');
162
+ expect(result.map(m => m.content)).toEqual(['first', 'second', 'third']);
163
+ });
164
+ it('returns empty for wrong workspace directory', async () => {
165
+ createTestDb('/some/other/path', [{ role: 'user', content: 'hello', time: 100 }]);
166
+ const result = await makeAdapter().readMessagesAsync('/non/existent/path');
167
+ expect(result).toHaveLength(0);
168
+ });
169
+ it('returns empty when DB does not exist', async () => {
170
+ const adapter = new OpenCodeAdapter();
171
+ adapter.getDbPath = () => '/tmp/nonexistent-vt.db';
172
+ const result = await adapter.readMessagesAsync('/any/path');
173
+ expect(result).toHaveLength(0);
174
+ });
175
+ it('returns empty for session with no messages', async () => {
176
+ createTestDb('/test/ws', []);
177
+ const result = await makeAdapter().readMessagesAsync('/test/ws');
178
+ expect(result).toHaveLength(0);
179
+ });
180
+ it('uses message IDs from the database', async () => {
181
+ createTestDb('/test/ws', [{ role: 'user', content: 'hello', time: 100 }]);
182
+ const result = await makeAdapter().readMessagesAsync('/test/ws');
183
+ expect(result[0].id).toBe('msg_0');
184
+ });
185
+ it('getCurrentSessionId returns session ID for known directory', async () => {
186
+ createTestDb('/test/ws', [{ role: 'user', content: 'hi', time: 100 }]);
187
+ const id = await makeAdapter().getCurrentSessionId('/test/ws');
188
+ expect(id).toBe('ses_test1');
189
+ });
190
+ it('getCurrentSessionId returns null for unknown directory', async () => {
191
+ createTestDb('/test/ws', []);
192
+ const id = await makeAdapter().getCurrentSessionId('/some/other/dir');
193
+ expect(id).toBeNull();
194
+ });
195
+ it('reads messages by specific sessionId', async () => {
196
+ createTestDb('/test/ws', [
197
+ { role: 'user', content: 'pinned session msg', time: 1000 },
198
+ ]);
199
+ const result = await makeAdapter().readMessagesAsync('/test/ws', 'ses_test1');
200
+ expect(result).toHaveLength(1);
201
+ expect(result[0].content).toBe('pinned session msg');
202
+ });
203
+ it('returns empty when given a non-existent sessionId', async () => {
204
+ createTestDb('/test/ws', [{ role: 'user', content: 'hi', time: 100 }]);
205
+ const result = await makeAdapter().readMessagesAsync('/test/ws', 'ses_nonexistent');
206
+ expect(result).toHaveLength(0);
207
+ });
208
+ });
209
+ // ─── ClaudeCodeAdapter ────────────────────────────────────────────────────
210
+ describe('ClaudeCodeAdapter', () => {
211
+ let tmpDir;
212
+ let sessionFile;
213
+ beforeEach(async () => {
214
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vt-claude-'));
215
+ sessionFile = path.join(tmpDir, 'session.jsonl');
216
+ });
217
+ afterEach(async () => {
218
+ await fs.rm(tmpDir, { recursive: true, force: true });
219
+ });
220
+ function makeAdapter(sessionDir) {
221
+ const adapter = new ClaudeCodeAdapter();
222
+ // Point the adapter at our temp directory
223
+ adapter.getSessionDir = () => sessionDir;
224
+ return adapter;
225
+ }
226
+ function writeJsonl(lines) {
227
+ fsSync.writeFileSync(sessionFile, lines.map(l => JSON.stringify(l)).join('\n') + '\n', 'utf8');
228
+ }
229
+ it('has correct adapter name', () => {
230
+ expect(new ClaudeCodeAdapter().name).toBe('claudecode');
231
+ });
232
+ it('reads user and assistant messages from JSONL', async () => {
233
+ writeJsonl([
234
+ { message: { role: 'user', content: [{ type: 'text', text: 'Write tests' }] }, timestamp: '2024-01-01T00:00:00Z' },
235
+ { message: { role: 'assistant', content: [{ type: 'text', text: 'Here are tests' }] }, timestamp: '2024-01-01T00:00:01Z' },
236
+ ]);
237
+ const adapter = makeAdapter(tmpDir);
238
+ const result = await adapter.readMessagesAsync('/any/path', sessionFile);
239
+ expect(result).toHaveLength(2);
240
+ expect(result[0].role).toBe('user');
241
+ expect(result[0].content).toBe('Write tests');
242
+ expect(result[1].role).toBe('assistant');
243
+ expect(result[1].content).toBe('Here are tests');
244
+ });
245
+ it('handles string content (not array)', async () => {
246
+ writeJsonl([
247
+ { message: { role: 'user', content: 'plain string message' }, timestamp: '2024-01-01T00:00:00Z' },
248
+ ]);
249
+ const adapter = makeAdapter(tmpDir);
250
+ const result = await adapter.readMessagesAsync('/any/path', sessionFile);
251
+ expect(result[0].content).toBe('plain string message');
252
+ });
253
+ it('maps "human" role to "user"', async () => {
254
+ writeJsonl([
255
+ { message: { role: 'human', content: [{ type: 'text', text: 'hello' }] }, timestamp: '2024-01-01T00:00:00Z' },
256
+ ]);
257
+ const adapter = makeAdapter(tmpDir);
258
+ const result = await adapter.readMessagesAsync('/any/path', sessionFile);
259
+ expect(result[0].role).toBe('user');
260
+ });
261
+ it('skips lines without text content', async () => {
262
+ writeJsonl([
263
+ { message: { role: 'assistant', content: [{ type: 'tool_use', id: 'x' }] }, timestamp: '2024-01-01T00:00:00Z' },
264
+ { message: { role: 'user', content: [{ type: 'text', text: 'real message' }] }, timestamp: '2024-01-01T00:00:01Z' },
265
+ ]);
266
+ const adapter = makeAdapter(tmpDir);
267
+ const result = await adapter.readMessagesAsync('/any/path', sessionFile);
268
+ expect(result).toHaveLength(1);
269
+ expect(result[0].content).toBe('real message');
270
+ });
271
+ it('skips malformed JSON lines gracefully', async () => {
272
+ fsSync.writeFileSync(sessionFile, '{"message":{"role":"user","content":[{"type":"text","text":"ok"}]},"timestamp":"2024-01-01T00:00:00Z"}\n' +
273
+ 'NOT VALID JSON\n' +
274
+ '{"message":{"role":"assistant","content":[{"type":"text","text":"also ok"}]},"timestamp":"2024-01-01T00:00:01Z"}\n', 'utf8');
275
+ const adapter = makeAdapter(tmpDir);
276
+ const result = await adapter.readMessagesAsync('/any/path', sessionFile);
277
+ expect(result).toHaveLength(2);
278
+ });
279
+ it('returns empty for non-existent file', async () => {
280
+ const adapter = makeAdapter(tmpDir);
281
+ const result = await adapter.readMessagesAsync('/any/path', '/tmp/no-such-file.jsonl');
282
+ expect(result).toHaveLength(0);
283
+ });
284
+ });
285
+ // ─── ensureProjectInstructions ────────────────────────────────────────────
286
+ describe('ensureProjectInstructions', () => {
287
+ let tmpDir;
288
+ beforeEach(async () => {
289
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vt-instr-'));
290
+ });
291
+ afterEach(async () => {
292
+ await fs.rm(tmpDir, { recursive: true, force: true });
293
+ });
294
+ it('writes AGENTS.md for OpenCode', async () => {
295
+ ensureProjectInstructions(tmpDir);
296
+ const content = await fs.readFile(path.join(tmpDir, 'AGENTS.md'), 'utf8');
297
+ expect(content).toContain(VARIANTREE_MARKER);
298
+ expect(content).toContain('When to checkpoint');
299
+ });
300
+ it('writes CLAUDE.md for Claude Code', async () => {
301
+ ensureProjectInstructions(tmpDir);
302
+ const content = await fs.readFile(path.join(tmpDir, 'CLAUDE.md'), 'utf8');
303
+ expect(content).toContain(VARIANTREE_MARKER);
304
+ expect(content).toContain('When to checkpoint');
305
+ });
306
+ it('both files contain the same instruction body', async () => {
307
+ ensureProjectInstructions(tmpDir);
308
+ const agents = await fs.readFile(path.join(tmpDir, 'AGENTS.md'), 'utf8');
309
+ const claude = await fs.readFile(path.join(tmpDir, 'CLAUDE.md'), 'utf8');
310
+ // Strip the heading line (# AGENTS vs # CLAUDE) — the rest should match
311
+ const stripHeading = (s) => s.replace(/^# \w+\n\n/, '');
312
+ expect(stripHeading(agents)).toBe(stripHeading(claude));
313
+ });
314
+ it('is idempotent — does not duplicate instructions on repeated calls', async () => {
315
+ ensureProjectInstructions(tmpDir);
316
+ ensureProjectInstructions(tmpDir);
317
+ const agents = await fs.readFile(path.join(tmpDir, 'AGENTS.md'), 'utf8');
318
+ const markerCount = (agents.match(new RegExp(VARIANTREE_MARKER, 'g')) ?? []).length;
319
+ expect(markerCount).toBe(2); // one opening, one closing
320
+ });
321
+ it('appends to existing files that have no Variantree section', async () => {
322
+ await fs.writeFile(path.join(tmpDir, 'AGENTS.md'), '# My Project\n\nCustom rules here.\n', 'utf8');
323
+ ensureProjectInstructions(tmpDir);
324
+ const content = await fs.readFile(path.join(tmpDir, 'AGENTS.md'), 'utf8');
325
+ expect(content).toContain('Custom rules here.');
326
+ expect(content).toContain(VARIANTREE_MARKER);
327
+ });
328
+ });
329
+ // ─── NodeStorage ──────────────────────────────────────────────────────────
330
+ describe('NodeStorage', () => {
331
+ let tmpDir;
332
+ let storage;
333
+ beforeEach(async () => {
334
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vt-test-'));
335
+ storage = new NodeStorage(tmpDir);
336
+ });
337
+ afterEach(async () => {
338
+ await fs.rm(tmpDir, { recursive: true, force: true });
339
+ });
340
+ it('should save and load a workspace', async () => {
341
+ const workspace = {
342
+ id: 'ws-1', title: 'Test', branches: {}, checkpoints: {},
343
+ activeBranchId: 'b1', createdAt: Date.now(), updatedAt: Date.now(),
344
+ };
345
+ await storage.save('ws-1', workspace);
346
+ const loaded = await storage.load('ws-1');
347
+ expect(loaded).toBeTruthy();
348
+ expect(loaded.title).toBe('Test');
349
+ });
350
+ it('should return null for missing workspace', async () => {
351
+ const result = await storage.load('nonexistent');
352
+ expect(result).toBeNull();
353
+ });
354
+ it('should list workspace IDs', async () => {
355
+ await storage.save('a', { id: 'a' });
356
+ await storage.save('b', { id: 'b' });
357
+ const ids = await storage.list();
358
+ expect(ids).toContain('a');
359
+ expect(ids).toContain('b');
360
+ });
361
+ it('should delete a workspace', async () => {
362
+ await storage.save('x', { id: 'x' });
363
+ await storage.delete('x');
364
+ const result = await storage.load('x');
365
+ expect(result).toBeNull();
366
+ });
367
+ it('should persist to .variantree/workspace.json', async () => {
368
+ await storage.save('ws', { id: 'ws' });
369
+ const filePath = path.join(tmpDir, '.variantree', 'workspace.json');
370
+ const raw = await fs.readFile(filePath, 'utf8');
371
+ const data = JSON.parse(raw);
372
+ expect(data.ws).toBeTruthy();
373
+ });
374
+ });
375
+ //# sourceMappingURL=watcher.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.test.js","sourceRoot":"","sources":["../../src/__tests__/watcher.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @variantree/watcher — Aider Session Adapter
3
+ *
4
+ * Aider writes conversation history as markdown to:
5
+ * .aider.chat.history.md (in the project root)
6
+ *
7
+ * Format:
8
+ * #### user
9
+ * message content
10
+ *
11
+ * #### assistant
12
+ * response content
13
+ */
14
+ import type { Message } from '@variantree/core';
15
+ import type { SessionAdapter } from './base.js';
16
+ export declare class AiderAdapter implements SessionAdapter {
17
+ readonly name = "aider";
18
+ findSessionFile(workspacePath: string): Promise<string | null>;
19
+ parseMessages(raw: string): Message[];
20
+ }
21
+ //# sourceMappingURL=aider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aider.d.ts","sourceRoot":"","sources":["../../src/adapters/aider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,qBAAa,YAAa,YAAW,cAAc;IACjD,QAAQ,CAAC,IAAI,WAAW;IAElB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIpE,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,EAAE;CAsBtC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @variantree/watcher — Aider Session Adapter
3
+ *
4
+ * Aider writes conversation history as markdown to:
5
+ * .aider.chat.history.md (in the project root)
6
+ *
7
+ * Format:
8
+ * #### user
9
+ * message content
10
+ *
11
+ * #### assistant
12
+ * response content
13
+ */
14
+ import path from 'node:path';
15
+ export class AiderAdapter {
16
+ name = 'aider';
17
+ async findSessionFile(workspacePath) {
18
+ return path.join(workspacePath, '.aider.chat.history.md');
19
+ }
20
+ parseMessages(raw) {
21
+ const messages = [];
22
+ // Split on #### user or #### assistant headings
23
+ const blocks = raw.split(/^#### (user|assistant)\s*$/m).filter(Boolean);
24
+ // blocks = ['user', 'content...', 'assistant', 'content...', ...]
25
+ for (let i = 0; i + 1 < blocks.length; i += 2) {
26
+ const role = blocks[i].trim();
27
+ const content = blocks[i + 1].trim();
28
+ if (role !== 'user' && role !== 'assistant')
29
+ continue;
30
+ if (!content)
31
+ continue;
32
+ messages.push({
33
+ id: `aider-${messages.length}`,
34
+ role,
35
+ content,
36
+ timestamp: Date.now(),
37
+ });
38
+ }
39
+ return messages;
40
+ }
41
+ }
42
+ //# sourceMappingURL=aider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aider.js","sourceRoot":"","sources":["../../src/adapters/aider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,OAAO,YAAY;IACd,IAAI,GAAG,OAAO,CAAC;IAExB,KAAK,CAAC,eAAe,CAAC,aAAqB;QACzC,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,wBAAwB,CAAC,CAAC;IAC5D,CAAC;IAED,aAAa,CAAC,GAAW;QACvB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,gDAAgD;QAChD,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAExE,kEAAkE;QAClE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAA0B,CAAC;YACtD,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW;gBAAE,SAAS;YACtD,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,SAAS,QAAQ,CAAC,MAAM,EAAE;gBAC9B,IAAI;gBACJ,OAAO;gBACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ /** @deprecated Import from '@variantree/watcher' or '../tools/base.js' instead. */
2
+ export type { SessionAdapter } from '../tools/base.js';
3
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @variantree/watcher — Claude Code Session Adapter
3
+ *
4
+ * Claude Code stores conversations as JSON at:
5
+ * ~/.claude/projects/<project-hash>/conversations/<session-id>.json
6
+ *
7
+ * Format:
8
+ * { "messages": [{ "role": "human"|"assistant", "content": [{"type":"text","text":"..."}] }] }
9
+ */
10
+ import type { Message } from '@variantree/core';
11
+ import type { SessionAdapter } from './base.js';
12
+ export declare class ClaudeCodeAdapter implements SessionAdapter {
13
+ readonly name = "claude-code";
14
+ findSessionFile(workspacePath: string): Promise<string | null>;
15
+ parseMessages(raw: string): Message[];
16
+ }
17
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/adapters/claude-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAgBhD,qBAAa,iBAAkB,YAAW,cAAc;IACtD,QAAQ,CAAC,IAAI,iBAAiB;IAExB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA6BpE,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,EAAE;CAatC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @variantree/watcher — Claude Code Session Adapter
3
+ *
4
+ * Claude Code stores conversations as JSON at:
5
+ * ~/.claude/projects/<project-hash>/conversations/<session-id>.json
6
+ *
7
+ * Format:
8
+ * { "messages": [{ "role": "human"|"assistant", "content": [{"type":"text","text":"..."}] }] }
9
+ */
10
+ import fs from 'node:fs/promises';
11
+ import path from 'node:path';
12
+ import os from 'node:os';
13
+ import crypto from 'node:crypto';
14
+ export class ClaudeCodeAdapter {
15
+ name = 'claude-code';
16
+ async findSessionFile(workspacePath) {
17
+ // Claude Code hashes paths with SHA-256, using the first 16 chars
18
+ const hash = crypto.createHash('sha256').update(workspacePath).digest('hex').slice(0, 16);
19
+ const conversationsDir = path.join(os.homedir(), '.claude', 'projects', hash, 'conversations');
20
+ try {
21
+ const entries = await fs.readdir(conversationsDir);
22
+ const jsonFiles = entries
23
+ .filter((f) => f.endsWith('.json'))
24
+ .map((f) => path.join(conversationsDir, f));
25
+ if (jsonFiles.length === 0)
26
+ return null;
27
+ const stats = await Promise.all(jsonFiles.map(async (f) => ({ file: f, mtime: (await fs.stat(f)).mtime })));
28
+ stats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
29
+ return stats[0].file;
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ }
35
+ parseMessages(raw) {
36
+ try {
37
+ const session = JSON.parse(raw);
38
+ return (session.messages ?? []).map((m, i) => ({
39
+ id: `claude-${i}`,
40
+ role: m.role === 'human' ? 'user' : 'assistant',
41
+ content: extractText(m.content),
42
+ timestamp: Date.now(),
43
+ }));
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ }
49
+ }
50
+ function extractText(content) {
51
+ if (typeof content === 'string')
52
+ return content;
53
+ return content
54
+ .filter((b) => b.type === 'text' && b.text)
55
+ .map((b) => b.text)
56
+ .join('');
57
+ }
58
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/adapters/claude-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** @deprecated Import from '@variantree/watcher' or '../tools/opencode/index.js' instead. */
2
+ export { OpenCodeAdapter } from '../tools/opencode/adapter.js';
3
+ //# sourceMappingURL=opencode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** @deprecated Import from '@variantree/watcher' or '../tools/opencode/index.js' instead. */
2
+ export { OpenCodeAdapter } from '../tools/opencode/adapter.js';
3
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @variantree/watcher — AGENTS.md content
3
+ *
4
+ * Standing instructions written to the project root so OpenCode (and
5
+ * compatible tools) know when and how to use Variantree proactively.
6
+ *
7
+ * Shared between `variantree init` (CLI) and the MCP server bootstrap.
8
+ */
9
+ export declare const AGENTS_MD_SECTION = "<!-- variantree:agents -->\n## Variantree \u2014 AI Version Control\n\nYou have access to Variantree MCP tools for managing conversation context and\ncode snapshots. Use them **proactively** \u2014 don't wait for the user to ask.\n\n### On session start\n- If `.variantree/branch-context.md` exists, read it immediately for context\n on prior work done on this branch.\n\n### When to checkpoint\n- After completing a distinct task or sub-task (e.g. \"auth is working\",\n \"tests pass\", \"refactor done\").\n- When the user says \"done\", \"looks good\", \"ship it\", or \"let's move on\".\n- Before any branch, switch, or restore \u2014 the tools will warn you if you\n forget, but it's better to checkpoint proactively.\n\n### When to branch\n- When the user wants to explore an alternative approach (\"let's try X\n instead\", \"what if we used Y\").\n- When the user asks to experiment without losing current progress.\n\n### When to switch / restore\n- When the user wants to go back to a previous line of work or a known-good\n state (\"go back to main\", \"restore the working version\").\n\n### Handling unsaved-message warnings\nIf a tool returns an unsaved-message warning (e.g. \"4 messages will be lost\"):\n1. **STOP** \u2014 do NOT silently pass `force: true`.\n2. Tell the user exactly how many messages will be lost.\n3. Ask: *\"Should I checkpoint first to save them, or discard them and\n proceed?\"*\n4. Only use `force: true` after the user explicitly says to discard /\n proceed without saving.\n\n### Presenting results to the user\n**IMPORTANT:** Always relay the COMPLETE tool output to the user. Do not\nsummarise or omit details. Specifically:\n\n- **checkpoint:** Show messages synced count, snapshot diff (files added,\n modified, deleted), and total file count.\n- **branch / switch / restore:** Show files written and deleted, then show\n the full conversation context summary that was returned.\n- **status:** Show ALL fields: active branch, message count, every branch\n name, and every checkpoint label with snapshot indicator.\n- **tree:** Show the FULL tree output exactly as returned \u2014 branches AND\n checkpoints. Do not collapse or summarise it.\n- **log:** Show the full conversation history returned by the tool.\n\n### Tool reference\n| Tool | Purpose |\n|-------------|----------------------------------------------|\n| checkpoint | Sync conversation + snapshot code |\n| branch | Create a new branch from a checkpoint |\n| switch | Switch to an existing branch |\n| restore | Restore code to a specific checkpoint |\n| status | Show active branch, checkpoints |\n| tree | ASCII tree of branches and checkpoints |\n| log | Show conversation history for a branch |\n<!-- variantree:agents -->";
10
+ /**
11
+ * Write or merge the Variantree section into an AGENTS.md file.
12
+ *
13
+ * - If the file doesn't exist, creates it.
14
+ * - If it exists but has no Variantree section, appends.
15
+ * - If it already has the section, replaces it (safe update).
16
+ */
17
+ export declare function mergeAgentsMd(existingContent: string | null): string;
18
+ //# sourceMappingURL=agents-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-md.d.ts","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,eAAO,MAAM,iBAAiB,41FA2DpB,CAAC;AAEX;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAkBpE"}