mcp-context-sync 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +85 -0
  3. package/dist/cli.d.ts +12 -0
  4. package/dist/cli.js +255 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/db/connection.d.ts +3 -0
  7. package/dist/db/connection.js +44 -0
  8. package/dist/db/connection.js.map +1 -0
  9. package/dist/db/queries.d.ts +23 -0
  10. package/dist/db/queries.js +121 -0
  11. package/dist/db/queries.js.map +1 -0
  12. package/dist/db/schema.d.ts +2 -0
  13. package/dist/db/schema.js +103 -0
  14. package/dist/db/schema.js.map +1 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +56 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/lib/project-id.d.ts +13 -0
  19. package/dist/lib/project-id.js +27 -0
  20. package/dist/lib/project-id.js.map +1 -0
  21. package/dist/lib/snapshot-renderer.d.ts +9 -0
  22. package/dist/lib/snapshot-renderer.js +77 -0
  23. package/dist/lib/snapshot-renderer.js.map +1 -0
  24. package/dist/lib/types.d.ts +290 -0
  25. package/dist/lib/types.js +122 -0
  26. package/dist/lib/types.js.map +1 -0
  27. package/dist/lib/uuid.d.ts +1 -0
  28. package/dist/lib/uuid.js +5 -0
  29. package/dist/lib/uuid.js.map +1 -0
  30. package/dist/lib/validation.d.ts +18 -0
  31. package/dist/lib/validation.js +63 -0
  32. package/dist/lib/validation.js.map +1 -0
  33. package/dist/prompts/auto-resume.d.ts +3 -0
  34. package/dist/prompts/auto-resume.js +70 -0
  35. package/dist/prompts/auto-resume.js.map +1 -0
  36. package/dist/prompts/resume-work.d.ts +2 -0
  37. package/dist/prompts/resume-work.js +29 -0
  38. package/dist/prompts/resume-work.js.map +1 -0
  39. package/dist/prompts/sync-session.d.ts +2 -0
  40. package/dist/prompts/sync-session.js +33 -0
  41. package/dist/prompts/sync-session.js.map +1 -0
  42. package/dist/resources/project-decisions.d.ts +3 -0
  43. package/dist/resources/project-decisions.js +69 -0
  44. package/dist/resources/project-decisions.js.map +1 -0
  45. package/dist/resources/project-snapshot.d.ts +3 -0
  46. package/dist/resources/project-snapshot.js +49 -0
  47. package/dist/resources/project-snapshot.js.map +1 -0
  48. package/dist/resources/status.d.ts +3 -0
  49. package/dist/resources/status.js +25 -0
  50. package/dist/resources/status.js.map +1 -0
  51. package/dist/tools/amend-snapshot.d.ts +3 -0
  52. package/dist/tools/amend-snapshot.js +126 -0
  53. package/dist/tools/amend-snapshot.js.map +1 -0
  54. package/dist/tools/get-history.d.ts +3 -0
  55. package/dist/tools/get-history.js +58 -0
  56. package/dist/tools/get-history.js.map +1 -0
  57. package/dist/tools/list-projects.d.ts +3 -0
  58. package/dist/tools/list-projects.js +40 -0
  59. package/dist/tools/list-projects.js.map +1 -0
  60. package/dist/tools/log-decision.d.ts +3 -0
  61. package/dist/tools/log-decision.js +46 -0
  62. package/dist/tools/log-decision.js.map +1 -0
  63. package/dist/tools/resume.d.ts +3 -0
  64. package/dist/tools/resume.js +113 -0
  65. package/dist/tools/resume.js.map +1 -0
  66. package/dist/tools/search-snapshots.d.ts +3 -0
  67. package/dist/tools/search-snapshots.js +71 -0
  68. package/dist/tools/search-snapshots.js.map +1 -0
  69. package/dist/tools/sync.d.ts +3 -0
  70. package/dist/tools/sync.js +102 -0
  71. package/dist/tools/sync.js.map +1 -0
  72. package/package.json +48 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jon Pueyo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # context-sync-mcp
2
+
3
+ MCP server that synchronizes work context between AI coding agents. Switch seamlessly between Claude Code, Codex, Gemini CLI, Cursor, and others without losing context.
4
+
5
+ ## How it works
6
+
7
+ When you finish a work session, call `sync` to save a structured snapshot (summary, tasks, decisions, files modified, blockers, next steps). When you start a new session — even with a different agent — call `resume` to load the latest snapshot and continue where you left off.
8
+
9
+ ```
10
+ Claude Code ──sync──▶ SQLite ◀──resume── Codex
11
+
12
+ └──resume── Gemini CLI
13
+ ```
14
+
15
+ ## Installation
16
+
17
+ ### Local (recommended)
18
+
19
+ ```bash
20
+ cd context-sync
21
+ npm install
22
+ npm run build
23
+ ```
24
+
25
+ ### As MCP server
26
+
27
+ Add to your agent's MCP config:
28
+
29
+ ```json
30
+ {
31
+ "context-sync": {
32
+ "command": "node",
33
+ "args": ["/path/to/context-sync/dist/index.js"]
34
+ }
35
+ }
36
+ ```
37
+
38
+ Config file locations:
39
+ - **Claude Code:** `claude mcp add context-sync -- node /path/to/dist/index.js`
40
+ - **Codex:** `~/.codex/mcp.json`
41
+ - **Gemini CLI:** `~/.gemini/antigravity/mcp_config.json`
42
+
43
+ ## MCP Tools
44
+
45
+ | Tool | Description |
46
+ |------|-------------|
47
+ | `sync` | Save a structured snapshot of current work state |
48
+ | `resume` | Load the latest snapshot for a project |
49
+ | `log-decision` | Record an architectural decision |
50
+ | `get-history` | View timeline of snapshots and handoffs |
51
+ | `list-projects` | List all synced projects |
52
+ | `search-snapshots` | Full-text search across snapshots |
53
+ | `amend-snapshot` | Update the most recent snapshot |
54
+
55
+ ## CLI (fallback for agents that can't call MCP tools)
56
+
57
+ The CLI provides the same functionality as the MCP tools, for agents that run shell commands instead of calling MCP tools directly.
58
+
59
+ ```bash
60
+ # Resume latest snapshot
61
+ context-sync resume --project "C:/Users/me/myproject" --agent codex
62
+
63
+ # Save a snapshot
64
+ context-sync sync --json '{"projectDir":"C:/...","agent":"codex","summary":"...","tasksCompleted":[],"tasksRemaining":[],"nextSteps":"..."}'
65
+
66
+ # List all projects
67
+ context-sync list
68
+
69
+ # View handoff history
70
+ context-sync history --project "C:/Users/me/myproject"
71
+ ```
72
+
73
+ After `npm run build`, the CLI is available at `dist/cli.js` or via `npx context-sync` if installed globally.
74
+
75
+ ## Storage
76
+
77
+ SQLite database at `~/.agents/context-sync/data/context-sync.sqlite`. Created automatically on first use. WAL mode enabled for concurrent access.
78
+
79
+ ## Project identity
80
+
81
+ Projects are identified by a SHA-256 hash of the normalized path (lowercase, forward slashes, no trailing slash). This means all agents resolve to the same project regardless of OS or path format — as long as they use the same absolute path to the project root.
82
+
83
+ ## License
84
+
85
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI wrapper around the context-sync database.
4
+ * Fallback for agents that cannot call MCP tools directly (e.g. Codex/GPT).
5
+ *
6
+ * Usage:
7
+ * context-sync resume --project <path> [--agent <name>]
8
+ * context-sync sync --json '<json>'
9
+ * context-sync list
10
+ * context-sync history --project <path> [--limit <n>]
11
+ */
12
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,255 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI wrapper around the context-sync database.
4
+ * Fallback for agents that cannot call MCP tools directly (e.g. Codex/GPT).
5
+ *
6
+ * Usage:
7
+ * context-sync resume --project <path> [--agent <name>]
8
+ * context-sync sync --json '<json>'
9
+ * context-sync list
10
+ * context-sync history --project <path> [--limit <n>]
11
+ */
12
+ import { readFileSync } from 'node:fs';
13
+ import { getDatabase, closeDatabase } from './db/connection.js';
14
+ import { upsertProject, getProject, getNextSequenceNumber, insertSnapshot, insertDecision, insertHandoff, updateProjectSyncStats, getLatestSnapshot, getProjectAgents, listProjects, getHandoffsByProject, } from './db/queries.js';
15
+ import { projectIdFromPath, normalizePath, displayNameFromPath, } from './lib/project-id.js';
16
+ import { generateId } from './lib/uuid.js';
17
+ import { renderSnapshotMarkdown } from './lib/snapshot-renderer.js';
18
+ // ---------------------------------------------------------------------------
19
+ // Arg helpers
20
+ // ---------------------------------------------------------------------------
21
+ const argv = process.argv.slice(2);
22
+ function getFlag(name) {
23
+ const idx = argv.indexOf(`--${name}`);
24
+ if (idx === -1 || idx + 1 >= argv.length)
25
+ return undefined;
26
+ return argv[idx + 1];
27
+ }
28
+ function stripBom(s) {
29
+ return s.charCodeAt(0) === 0xfeff ? s.slice(1) : s;
30
+ }
31
+ function readJsonInput() {
32
+ // 1. Inline JSON (fragile in PowerShell due to quoting)
33
+ const fromFlag = getFlag('json');
34
+ if (fromFlag)
35
+ return fromFlag;
36
+ // 2. Read from a file (recommended for PowerShell)
37
+ const fromFile = getFlag('file');
38
+ if (fromFile)
39
+ return stripBom(readFileSync(fromFile, 'utf-8'));
40
+ // 3. Stdin pipe
41
+ try {
42
+ return stripBom(readFileSync(0, 'utf-8'));
43
+ }
44
+ catch {
45
+ return '';
46
+ }
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // resume
50
+ // ---------------------------------------------------------------------------
51
+ function cmdResume() {
52
+ const projectDir = getFlag('project');
53
+ const agent = getFlag('agent') ?? 'codex';
54
+ if (!projectDir) {
55
+ console.error('Usage: context-sync resume --project <path> [--agent <name>]');
56
+ process.exit(1);
57
+ }
58
+ const db = getDatabase();
59
+ const projectId = projectIdFromPath(projectDir);
60
+ const displayName = displayNameFromPath(projectDir);
61
+ const project = getProject(db, projectId);
62
+ if (!project) {
63
+ const all = listProjects(db);
64
+ console.error(`No data found for "${displayName}" (${normalizePath(projectDir)})`);
65
+ if (all.length > 0) {
66
+ console.error('\nAvailable projects:');
67
+ for (const p of all)
68
+ console.error(` ${p.normalized_path} (${p.snapshot_count} snapshots)`);
69
+ }
70
+ closeDatabase();
71
+ process.exit(1);
72
+ }
73
+ const snapshot = getLatestSnapshot(db, projectId);
74
+ if (!snapshot) {
75
+ console.error(`Project "${displayName}" exists but has no snapshots.`);
76
+ closeDatabase();
77
+ process.exit(1);
78
+ }
79
+ const now = new Date().toISOString();
80
+ db.transaction(() => {
81
+ insertHandoff(db, {
82
+ id: generateId(),
83
+ project_id: projectId,
84
+ snapshot_id: snapshot.id,
85
+ from_agent: snapshot.agent,
86
+ to_agent: agent,
87
+ from_timestamp: snapshot.created_at,
88
+ to_timestamp: now,
89
+ created_at: now,
90
+ });
91
+ updateProjectSyncStats(db, projectId);
92
+ })();
93
+ const agents = getProjectAgents(db, projectId);
94
+ console.log(renderSnapshotMarkdown(snapshot, displayName, {
95
+ totalSnapshots: project.snapshot_count,
96
+ totalHandoffs: project.handoff_count + 1,
97
+ agents,
98
+ }));
99
+ closeDatabase();
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // sync
103
+ // ---------------------------------------------------------------------------
104
+ function cmdSync() {
105
+ const raw = readJsonInput();
106
+ if (!raw.trim()) {
107
+ console.error('Usage: context-sync sync --file <path.json>');
108
+ console.error(' or: context-sync sync --json \'{"projectDir":"...","agent":"codex",...}\'');
109
+ console.error(' or: <json> | context-sync sync');
110
+ process.exit(1);
111
+ }
112
+ let input;
113
+ try {
114
+ input = JSON.parse(raw);
115
+ }
116
+ catch {
117
+ console.error('Error: invalid JSON input');
118
+ process.exit(1);
119
+ }
120
+ const projectDir = input.projectDir || '';
121
+ const agent = input.agent || 'codex';
122
+ if (!projectDir) {
123
+ console.error('Error: missing "projectDir" in JSON');
124
+ process.exit(1);
125
+ }
126
+ const db = getDatabase();
127
+ const projectId = projectIdFromPath(projectDir);
128
+ const normalized = normalizePath(projectDir);
129
+ const displayName = displayNameFromPath(projectDir);
130
+ const now = new Date().toISOString();
131
+ const decisions = input.decisions ?? [];
132
+ const { snapshotId, seqNum } = db.transaction(() => {
133
+ upsertProject(db, projectId, normalized, displayName);
134
+ const seqNum = getNextSequenceNumber(db, projectId);
135
+ const snapshotId = generateId();
136
+ insertSnapshot(db, {
137
+ id: snapshotId,
138
+ project_id: projectId,
139
+ sequence_number: seqNum,
140
+ agent,
141
+ summary: input.summary || '',
142
+ tasks_completed: JSON.stringify(input.tasksCompleted ?? []),
143
+ tasks_remaining: JSON.stringify(input.tasksRemaining ?? []),
144
+ decisions: JSON.stringify(decisions),
145
+ files_modified: JSON.stringify(input.filesModified ?? []),
146
+ blockers: JSON.stringify(input.blockers ?? []),
147
+ next_steps: input.nextSteps || '',
148
+ tags: JSON.stringify(input.tags ?? []),
149
+ created_at: now,
150
+ });
151
+ for (const d of decisions) {
152
+ insertDecision(db, {
153
+ id: generateId(),
154
+ project_id: projectId,
155
+ snapshot_id: snapshotId,
156
+ agent,
157
+ decision: d.decision,
158
+ reasoning: d.reasoning,
159
+ alternatives: JSON.stringify(d.alternatives ?? []),
160
+ category: null,
161
+ related_files: '[]',
162
+ created_at: now,
163
+ });
164
+ }
165
+ updateProjectSyncStats(db, projectId);
166
+ return { snapshotId, seqNum };
167
+ })();
168
+ console.log(`Snapshot #${seqNum} saved for "${displayName}"`);
169
+ console.log(` ID: ${snapshotId}`);
170
+ console.log(` Agent: ${agent}`);
171
+ console.log(` Path: ${normalized}`);
172
+ closeDatabase();
173
+ }
174
+ // ---------------------------------------------------------------------------
175
+ // list
176
+ // ---------------------------------------------------------------------------
177
+ function cmdList() {
178
+ const db = getDatabase();
179
+ const projects = listProjects(db);
180
+ if (projects.length === 0) {
181
+ console.log('No projects synced yet.');
182
+ }
183
+ else {
184
+ for (const p of projects) {
185
+ console.log(`${p.display_name}`);
186
+ console.log(` Path: ${p.normalized_path}`);
187
+ console.log(` Snapshots: ${p.snapshot_count} | Handoffs: ${p.handoff_count}`);
188
+ console.log(` Last sync: ${p.last_synced_at ?? 'never'}`);
189
+ console.log();
190
+ }
191
+ }
192
+ closeDatabase();
193
+ }
194
+ // ---------------------------------------------------------------------------
195
+ // history
196
+ // ---------------------------------------------------------------------------
197
+ function cmdHistory() {
198
+ const projectDir = getFlag('project');
199
+ const limit = parseInt(getFlag('limit') ?? '10', 10);
200
+ if (!projectDir) {
201
+ console.error('Usage: context-sync history --project <path> [--limit <n>]');
202
+ process.exit(1);
203
+ }
204
+ const db = getDatabase();
205
+ const projectId = projectIdFromPath(projectDir);
206
+ const handoffs = getHandoffsByProject(db, projectId, limit);
207
+ if (handoffs.length === 0) {
208
+ console.log('No handoff history for this project.');
209
+ }
210
+ else {
211
+ for (const h of handoffs) {
212
+ console.log(`${h.from_agent} -> ${h.to_agent} (${h.created_at})`);
213
+ }
214
+ }
215
+ closeDatabase();
216
+ }
217
+ // ---------------------------------------------------------------------------
218
+ // Main
219
+ // ---------------------------------------------------------------------------
220
+ function showHelp() {
221
+ console.log(`context-sync — Cross-agent context synchronization CLI
222
+
223
+ Commands:
224
+ resume Load latest snapshot --project <path> [--agent <name>]
225
+ sync Save work snapshot --file <path> | --json '<json>' | stdin
226
+ list List synced projects
227
+ history Show handoff timeline --project <path> [--limit <n>]
228
+
229
+ Examples:
230
+ context-sync resume --project "C:/Users/me/myproject" --agent codex
231
+ context-sync sync --file snapshot.json
232
+ context-sync list`);
233
+ }
234
+ switch (argv[0]) {
235
+ case 'resume':
236
+ cmdResume();
237
+ break;
238
+ case 'sync':
239
+ cmdSync();
240
+ break;
241
+ case 'list':
242
+ cmdList();
243
+ break;
244
+ case 'history':
245
+ cmdHistory();
246
+ break;
247
+ case '--help':
248
+ case '-h':
249
+ showHelp();
250
+ break;
251
+ default:
252
+ showHelp();
253
+ break;
254
+ }
255
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import Database from 'better-sqlite3';
2
+ export declare function getDatabase(): Database.Database;
3
+ export declare function closeDatabase(): void;
@@ -0,0 +1,44 @@
1
+ import Database from 'better-sqlite3';
2
+ import { mkdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { initSchema } from './schema.js';
6
+ let _db = null;
7
+ function getDbPath() {
8
+ const dataDir = join(homedir(), '.agents', 'context-sync', 'data');
9
+ mkdirSync(dataDir, { recursive: true });
10
+ return join(dataDir, 'context-sync.sqlite');
11
+ }
12
+ export function getDatabase() {
13
+ if (_db)
14
+ return _db;
15
+ const dbPath = getDbPath();
16
+ _db = new Database(dbPath);
17
+ // Enable performance optimizations
18
+ _db.pragma('journal_mode = WAL');
19
+ _db.pragma('synchronous = NORMAL');
20
+ _db.pragma('cache_size = -64000'); // 64MB cache
21
+ _db.pragma('temp_store = MEMORY');
22
+ _db.pragma('foreign_keys = ON');
23
+ initSchema(_db);
24
+ // Graceful shutdown on process exit
25
+ const cleanup = () => closeDatabase();
26
+ process.on('exit', cleanup);
27
+ process.on('SIGINT', cleanup);
28
+ process.on('SIGTERM', cleanup);
29
+ return _db;
30
+ }
31
+ export function closeDatabase() {
32
+ if (_db) {
33
+ try {
34
+ _db.close();
35
+ }
36
+ catch (err) {
37
+ // Ignore errors on close
38
+ }
39
+ finally {
40
+ _db = null;
41
+ }
42
+ }
43
+ }
44
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/db/connection.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,IAAI,GAAG,GAA6B,IAAI,CAAC;AAEzC,SAAS,SAAS;IAChB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;IACnE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,OAAO,IAAI,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IAEpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE3B,mCAAmC;IACnC,GAAG,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACjC,GAAG,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;IACnC,GAAG,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,aAAa;IAChD,GAAG,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAClC,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAEhC,UAAU,CAAC,GAAG,CAAC,CAAC;IAEhB,oCAAoC;IACpC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAE/B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,CAAC;YACH,GAAG,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,yBAAyB;QAC3B,CAAC;gBAAS,CAAC;YACT,GAAG,GAAG,IAAI,CAAC;QACb,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { ProjectRow, SnapshotRow, DecisionRow, HandoffRow } from '../lib/types.js';
3
+ export declare function upsertProject(db: Database.Database, id: string, normalizedPath: string, displayName: string): ProjectRow;
4
+ export declare function getProject(db: Database.Database, id: string): ProjectRow | undefined;
5
+ export declare function listProjects(db: Database.Database): ProjectRow[];
6
+ export declare function updateProjectSyncStats(db: Database.Database, projectId: string): void;
7
+ export declare function getNextSequenceNumber(db: Database.Database, projectId: string): number;
8
+ export declare function insertSnapshot(db: Database.Database, snapshot: Omit<SnapshotRow, 'amended_at' | 'amended_by'>): void;
9
+ export declare function getLatestSnapshot(db: Database.Database, projectId: string): SnapshotRow | undefined;
10
+ export declare function getSnapshotById(db: Database.Database, snapshotId: string): SnapshotRow | undefined;
11
+ export declare function getSnapshotsByProject(db: Database.Database, projectId: string, limit: number): SnapshotRow[];
12
+ export declare function updateSnapshot(db: Database.Database, snapshotId: string, fields: Partial<Pick<SnapshotRow, 'tasks_completed' | 'tasks_remaining' | 'decisions' | 'next_steps' | 'blockers' | 'tags' | 'amended_at' | 'amended_by'>>): void;
13
+ export declare function searchSnapshots(db: Database.Database, query: string, projectId?: string, agent?: string, since?: string, until?: string, limit?: number): SnapshotRow[];
14
+ export declare function insertDecision(db: Database.Database, row: DecisionRow): void;
15
+ export declare function getDecisionsByProject(db: Database.Database, projectId: string, limit?: number): DecisionRow[];
16
+ export declare function insertHandoff(db: Database.Database, row: HandoffRow): void;
17
+ export declare function getHandoffsByProject(db: Database.Database, projectId: string, limit?: number): HandoffRow[];
18
+ export declare function getProjectAgents(db: Database.Database, projectId: string): string[];
19
+ export declare function getTotalCounts(db: Database.Database): {
20
+ projects: number;
21
+ snapshots: number;
22
+ handoffs: number;
23
+ };
@@ -0,0 +1,121 @@
1
+ // ─── Prepared Statement Cache ────────────────────────────────────
2
+ const stmtCache = new Map();
3
+ function getStmt(db, key, sql) {
4
+ let stmt = stmtCache.get(key);
5
+ if (!stmt) {
6
+ stmt = db.prepare(sql);
7
+ stmtCache.set(key, stmt);
8
+ }
9
+ return stmt;
10
+ }
11
+ // ─── Projects ────────────────────────────────────────────────────
12
+ export function upsertProject(db, id, normalizedPath, displayName) {
13
+ const now = new Date().toISOString();
14
+ getStmt(db, 'upsertProject', `INSERT INTO projects (id, normalized_path, display_name, created_at)
15
+ VALUES (?, ?, ?, ?)
16
+ ON CONFLICT(id) DO NOTHING`).run(id, normalizedPath, displayName, now);
17
+ return getStmt(db, 'getProjectById', 'SELECT * FROM projects WHERE id = ?').get(id);
18
+ }
19
+ export function getProject(db, id) {
20
+ return getStmt(db, 'getProjectById', 'SELECT * FROM projects WHERE id = ?').get(id);
21
+ }
22
+ export function listProjects(db) {
23
+ return getStmt(db, 'listProjects', 'SELECT * FROM projects ORDER BY last_synced_at DESC').all();
24
+ }
25
+ export function updateProjectSyncStats(db, projectId) {
26
+ const now = new Date().toISOString();
27
+ getStmt(db, 'updateProjectSyncStats', `UPDATE projects SET
28
+ last_synced_at = ?,
29
+ snapshot_count = (SELECT COUNT(*) FROM snapshots WHERE project_id = ?),
30
+ handoff_count = (SELECT COUNT(*) FROM handoffs WHERE project_id = ?)
31
+ WHERE id = ?`).run(now, projectId, projectId, projectId);
32
+ }
33
+ // ─── Snapshots ───────────────────────────────────────────────────
34
+ export function getNextSequenceNumber(db, projectId) {
35
+ const row = getStmt(db, 'getNextSeq', 'SELECT MAX(sequence_number) as max_seq FROM snapshots WHERE project_id = ?').get(projectId);
36
+ return (row?.max_seq ?? 0) + 1;
37
+ }
38
+ export function insertSnapshot(db, snapshot) {
39
+ getStmt(db, 'insertSnapshot', `INSERT INTO snapshots (id, project_id, sequence_number, agent, summary,
40
+ tasks_completed, tasks_remaining, decisions, files_modified,
41
+ blockers, next_steps, tags, created_at)
42
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(snapshot.id, snapshot.project_id, snapshot.sequence_number, snapshot.agent, snapshot.summary, snapshot.tasks_completed, snapshot.tasks_remaining, snapshot.decisions, snapshot.files_modified, snapshot.blockers, snapshot.next_steps, snapshot.tags, snapshot.created_at);
43
+ }
44
+ export function getLatestSnapshot(db, projectId) {
45
+ return getStmt(db, 'getLatestSnapshot', 'SELECT * FROM snapshots WHERE project_id = ? ORDER BY sequence_number DESC LIMIT 1').get(projectId);
46
+ }
47
+ export function getSnapshotById(db, snapshotId) {
48
+ return getStmt(db, 'getSnapshotById', 'SELECT * FROM snapshots WHERE id = ?').get(snapshotId);
49
+ }
50
+ export function getSnapshotsByProject(db, projectId, limit) {
51
+ return getStmt(db, 'getSnapshotsByProject', 'SELECT * FROM snapshots WHERE project_id = ? ORDER BY sequence_number DESC LIMIT ?').all(projectId, limit);
52
+ }
53
+ export function updateSnapshot(db, snapshotId, fields) {
54
+ const sets = [];
55
+ const values = [];
56
+ for (const [key, value] of Object.entries(fields)) {
57
+ if (value !== undefined) {
58
+ sets.push(`${key} = ?`);
59
+ values.push(value);
60
+ }
61
+ }
62
+ if (sets.length === 0)
63
+ return;
64
+ values.push(snapshotId);
65
+ db.prepare(`UPDATE snapshots SET ${sets.join(', ')} WHERE id = ?`).run(...values);
66
+ }
67
+ export function searchSnapshots(db, query, projectId, agent, since, until, limit = 20) {
68
+ let sql = `SELECT s.* FROM snapshots s
69
+ JOIN snapshots_fts fts ON s.rowid = fts.rowid
70
+ WHERE snapshots_fts MATCH ?`;
71
+ const params = [query];
72
+ if (projectId) {
73
+ sql += ' AND s.project_id = ?';
74
+ params.push(projectId);
75
+ }
76
+ if (agent) {
77
+ sql += ' AND s.agent = ?';
78
+ params.push(agent);
79
+ }
80
+ if (since) {
81
+ sql += ' AND s.created_at >= ?';
82
+ params.push(since);
83
+ }
84
+ if (until) {
85
+ sql += ' AND s.created_at <= ?';
86
+ params.push(until);
87
+ }
88
+ sql += ' ORDER BY rank LIMIT ?';
89
+ params.push(limit);
90
+ return db.prepare(sql).all(...params);
91
+ }
92
+ // ─── Decisions ───────────────────────────────────────────────────
93
+ export function insertDecision(db, row) {
94
+ getStmt(db, 'insertDecision', `INSERT INTO decisions (id, project_id, snapshot_id, agent, decision,
95
+ reasoning, alternatives, category, related_files, created_at)
96
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(row.id, row.project_id, row.snapshot_id, row.agent, row.decision, row.reasoning, row.alternatives, row.category, row.related_files, row.created_at);
97
+ }
98
+ export function getDecisionsByProject(db, projectId, limit = 50) {
99
+ return getStmt(db, 'getDecisionsByProject', 'SELECT * FROM decisions WHERE project_id = ? ORDER BY created_at DESC LIMIT ?').all(projectId, limit);
100
+ }
101
+ // ─── Handoffs ────────────────────────────────────────────────────
102
+ export function insertHandoff(db, row) {
103
+ getStmt(db, 'insertHandoff', `INSERT INTO handoffs (id, project_id, snapshot_id, from_agent, to_agent,
104
+ from_timestamp, to_timestamp, created_at)
105
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(row.id, row.project_id, row.snapshot_id, row.from_agent, row.to_agent, row.from_timestamp, row.to_timestamp, row.created_at);
106
+ }
107
+ export function getHandoffsByProject(db, projectId, limit = 20) {
108
+ return getStmt(db, 'getHandoffsByProject', 'SELECT * FROM handoffs WHERE project_id = ? ORDER BY created_at DESC LIMIT ?').all(projectId, limit);
109
+ }
110
+ // ─── Stats ───────────────────────────────────────────────────────
111
+ export function getProjectAgents(db, projectId) {
112
+ const rows = getStmt(db, 'getProjectAgents', 'SELECT DISTINCT agent FROM snapshots WHERE project_id = ? ORDER BY agent').all(projectId);
113
+ return rows.map((r) => r.agent);
114
+ }
115
+ export function getTotalCounts(db) {
116
+ const p = getStmt(db, 'countProjects', 'SELECT COUNT(*) as c FROM projects').get();
117
+ const s = getStmt(db, 'countSnapshots', 'SELECT COUNT(*) as c FROM snapshots').get();
118
+ const h = getStmt(db, 'countHandoffs', 'SELECT COUNT(*) as c FROM handoffs').get();
119
+ return { projects: p.c, snapshots: s.c, handoffs: h.c };
120
+ }
121
+ //# sourceMappingURL=queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/db/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type Database from 'better-sqlite3';
2
+ export declare function initSchema(db: Database.Database): void;