contextgit 0.0.2 → 0.0.3

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 (163) hide show
  1. package/dist/bootstrap.d.ts +10 -0
  2. package/dist/bootstrap.d.ts.map +1 -0
  3. package/dist/bootstrap.js +43 -0
  4. package/dist/bootstrap.js.map +1 -0
  5. package/dist/commands/branch.d.ts +13 -0
  6. package/dist/commands/branch.d.ts.map +1 -0
  7. package/dist/commands/branch.js +52 -0
  8. package/dist/commands/branch.js.map +1 -0
  9. package/dist/commands/claim.d.ts +13 -0
  10. package/dist/commands/claim.d.ts.map +1 -0
  11. package/dist/commands/claim.js +50 -0
  12. package/dist/commands/claim.js.map +1 -0
  13. package/dist/commands/commit.d.ts +14 -0
  14. package/dist/commands/commit.d.ts.map +1 -0
  15. package/dist/commands/commit.js +71 -0
  16. package/dist/commands/commit.js.map +1 -0
  17. package/dist/commands/context.d.ts +9 -0
  18. package/dist/commands/context.d.ts.map +1 -0
  19. package/dist/commands/context.js +38 -0
  20. package/dist/commands/context.js.map +1 -0
  21. package/dist/commands/doctor.d.ts +6 -0
  22. package/dist/commands/doctor.d.ts.map +1 -0
  23. package/dist/commands/doctor.js +84 -0
  24. package/dist/commands/doctor.js.map +1 -0
  25. package/dist/commands/init.d.ts +10 -0
  26. package/dist/commands/init.d.ts.map +1 -0
  27. package/dist/commands/init.js +126 -0
  28. package/dist/commands/init.js.map +1 -0
  29. package/dist/commands/keygen.d.ts +10 -0
  30. package/dist/commands/keygen.d.ts.map +1 -0
  31. package/dist/commands/keygen.js +57 -0
  32. package/dist/commands/keygen.js.map +1 -0
  33. package/dist/commands/log.d.ts +13 -0
  34. package/dist/commands/log.d.ts.map +1 -0
  35. package/dist/commands/log.js +91 -0
  36. package/dist/commands/log.js.map +1 -0
  37. package/dist/commands/merge.d.ts +12 -0
  38. package/dist/commands/merge.d.ts.map +1 -0
  39. package/dist/commands/merge.js +29 -0
  40. package/dist/commands/merge.js.map +1 -0
  41. package/dist/commands/pull.d.ts +10 -0
  42. package/dist/commands/pull.d.ts.map +1 -0
  43. package/dist/commands/pull.js +123 -0
  44. package/dist/commands/pull.js.map +1 -0
  45. package/dist/commands/push.d.ts +10 -0
  46. package/dist/commands/push.d.ts.map +1 -0
  47. package/dist/commands/push.js +141 -0
  48. package/dist/commands/push.js.map +1 -0
  49. package/dist/commands/remote-show.d.ts +6 -0
  50. package/dist/commands/remote-show.d.ts.map +1 -0
  51. package/dist/commands/remote-show.js +71 -0
  52. package/dist/commands/remote-show.js.map +1 -0
  53. package/dist/commands/search.d.ts +11 -0
  54. package/dist/commands/search.d.ts.map +1 -0
  55. package/dist/commands/search.js +47 -0
  56. package/dist/commands/search.js.map +1 -0
  57. package/dist/commands/serve.d.ts +9 -0
  58. package/dist/commands/serve.d.ts.map +1 -0
  59. package/dist/commands/serve.js +51 -0
  60. package/dist/commands/serve.js.map +1 -0
  61. package/dist/commands/set-remote.d.ts +9 -0
  62. package/dist/commands/set-remote.d.ts.map +1 -0
  63. package/dist/commands/set-remote.js +26 -0
  64. package/dist/commands/set-remote.js.map +1 -0
  65. package/dist/commands/status.d.ts +6 -0
  66. package/dist/commands/status.d.ts.map +1 -0
  67. package/dist/commands/status.js +54 -0
  68. package/dist/commands/status.js.map +1 -0
  69. package/dist/commands/unclaim.d.ts +9 -0
  70. package/dist/commands/unclaim.d.ts.map +1 -0
  71. package/dist/commands/unclaim.js +22 -0
  72. package/dist/commands/unclaim.js.map +1 -0
  73. package/dist/config.d.ts +19 -0
  74. package/dist/config.d.ts.map +1 -0
  75. package/dist/config.js +58 -0
  76. package/dist/config.js.map +1 -0
  77. package/dist/git-hooks.d.ts +6 -0
  78. package/dist/git-hooks.d.ts.map +1 -0
  79. package/dist/git-hooks.js +58 -0
  80. package/dist/git-hooks.js.map +1 -0
  81. package/package.json +22 -19
  82. package/.claude/settings.local.json +0 -41
  83. package/.contextgit/config.json +0 -10
  84. package/.contextgit/system-prompt.md +0 -4
  85. package/.github/workflows/contextgit-ci.yml +0 -40
  86. package/CLAUDE.md +0 -123
  87. package/CLAUDE.md.next +0 -65
  88. package/docs/ContextGit_ARCHITECTURE_v3.md +0 -1141
  89. package/docs/ContextGit_DELTA.md +0 -84
  90. package/docs/ContextGit_PHASE1_PLAN.md +0 -177
  91. package/docs/ContextGit_PHASE2_PLAN.md +0 -535
  92. package/docs/ContextGit_PRD_v4.md +0 -488
  93. package/docs/decisions.md +0 -370
  94. package/packages/api/package.json +0 -25
  95. package/packages/api/src/bootstrap.ts +0 -64
  96. package/packages/api/src/config.ts +0 -45
  97. package/packages/api/src/index.ts +0 -17
  98. package/packages/api/src/middleware/auth.test.ts +0 -83
  99. package/packages/api/src/middleware/auth.ts +0 -41
  100. package/packages/api/src/remote-store.test.ts +0 -301
  101. package/packages/api/src/router.ts +0 -121
  102. package/packages/api/src/server-config.ts +0 -34
  103. package/packages/api/src/server.ts +0 -38
  104. package/packages/api/src/store-router.ts +0 -241
  105. package/packages/api/tsconfig.json +0 -8
  106. package/packages/cli/package.json +0 -29
  107. package/packages/cli/src/bootstrap.ts +0 -68
  108. package/packages/cli/src/commands/branch.ts +0 -58
  109. package/packages/cli/src/commands/claim.ts +0 -58
  110. package/packages/cli/src/commands/commit.ts +0 -79
  111. package/packages/cli/src/commands/context.ts +0 -46
  112. package/packages/cli/src/commands/doctor.ts +0 -99
  113. package/packages/cli/src/commands/init.ts +0 -141
  114. package/packages/cli/src/commands/keygen.ts +0 -65
  115. package/packages/cli/src/commands/log.ts +0 -103
  116. package/packages/cli/src/commands/merge.ts +0 -36
  117. package/packages/cli/src/commands/pull.ts +0 -145
  118. package/packages/cli/src/commands/push.ts +0 -158
  119. package/packages/cli/src/commands/remote-show.ts +0 -87
  120. package/packages/cli/src/commands/search.ts +0 -54
  121. package/packages/cli/src/commands/serve.ts +0 -61
  122. package/packages/cli/src/commands/set-remote.ts +0 -30
  123. package/packages/cli/src/commands/status.ts +0 -62
  124. package/packages/cli/src/commands/unclaim.ts +0 -28
  125. package/packages/cli/src/config.ts +0 -64
  126. package/packages/cli/src/git-hooks.ts +0 -61
  127. package/packages/cli/tsconfig.json +0 -9
  128. package/packages/core/package.json +0 -28
  129. package/packages/core/src/embeddings.test.ts +0 -58
  130. package/packages/core/src/embeddings.ts +0 -75
  131. package/packages/core/src/engine.ts +0 -274
  132. package/packages/core/src/index.ts +0 -6
  133. package/packages/core/src/snapshot.ts +0 -82
  134. package/packages/core/src/summarizer.test.ts +0 -120
  135. package/packages/core/src/summarizer.ts +0 -113
  136. package/packages/core/src/threads.ts +0 -29
  137. package/packages/core/src/types.ts +0 -240
  138. package/packages/core/tsconfig.json +0 -9
  139. package/packages/mcp/package.json +0 -31
  140. package/packages/mcp/src/auto-snapshot.ts +0 -83
  141. package/packages/mcp/src/config.ts +0 -53
  142. package/packages/mcp/src/git-sync.ts +0 -94
  143. package/packages/mcp/src/index.ts +0 -19
  144. package/packages/mcp/src/server.ts +0 -377
  145. package/packages/mcp/tsconfig.json +0 -9
  146. package/packages/store/package.json +0 -30
  147. package/packages/store/src/branch-merge.test.ts +0 -127
  148. package/packages/store/src/engine-integration.test.ts +0 -93
  149. package/packages/store/src/index.ts +0 -3
  150. package/packages/store/src/interface.ts +0 -62
  151. package/packages/store/src/local/claims.test.ts +0 -190
  152. package/packages/store/src/local/index.ts +0 -380
  153. package/packages/store/src/local/local-store.test.ts +0 -164
  154. package/packages/store/src/local/migrations.ts +0 -99
  155. package/packages/store/src/local/queries.ts +0 -760
  156. package/packages/store/src/local/schema.ts +0 -157
  157. package/packages/store/src/remote/index.ts +0 -300
  158. package/packages/store/tsconfig.json +0 -9
  159. package/pnpm-workspace.yaml +0 -2
  160. package/scripts/build.sh +0 -28
  161. package/tsconfig.base.json +0 -14
  162. package/vitest.config.ts +0 -15
  163. /package/{packages/cli/bin → bin}/run.js +0 -0
@@ -1,535 +0,0 @@
1
- # ContextGit — Phase 2 Implementation Plan
2
-
3
- ## Context
4
-
5
- Phase 1 is complete: core engine, LocalStore (SQLite + sqlite-vec), RemoteStore (HTTP client), MCP server (3 tools), CLI (3 commands), and REST API are built and dogfooded on the ContextGit repo itself and on an external project (Loqally). All three Phase 1 gates passed.
6
-
7
- Phase 2 (Weeks 5–8) makes ContextGit team-ready. It fills every Phase 1 gap and ships push/pull, auth, multi-agent scoped snapshots, git hooks, and CI integration.
8
-
9
- **What Phase 1 left incomplete:**
10
- - `gitCommitSha` / `gitBranch` fields exist in the DB schema and types but are never populated — agents write them manually
11
- - `context_branch` and `context_merge` MCP tools were planned but never built (engine is done)
12
- - CLI is missing: `branch`, `merge`, `search`, `status`, `push`, `pull`, `keygen`, `doctor`
13
- - REST API `/v1/store` routes are NOT mounted in production `createApp()` — only in integration tests — so `RemoteStore` gets 404 in any real deployment
14
- - No authentication on the REST API
15
- - No git hook installer
16
-
17
- ---
18
-
19
- ## Monorepo Changes for Phase 2
20
-
21
- No new packages. All work happens in existing packages:
22
-
23
- ```
24
- packages/
25
- ├── core/src/
26
- │ ├── types.ts ← add remote?, ciRunId?, pipelineName?, gitCommitSha?, gitBranch? to config/input types
27
- │ └── engine.ts ← pass new EngineCommitInput fields through to store
28
- ├── store/src/
29
- │ ├── interface.ts ← add options? param to getSessionSnapshot
30
- │ ├── local/
31
- │ │ ├── queries.ts ← add selectRecentCommitsByRole prepared statement
32
- │ │ └── index.ts ← role filter in getSessionSnapshot
33
- │ └── remote/index.ts ← add apiKey constructor param, Authorization header
34
- ├── mcp/src/
35
- │ ├── git-sync.ts ← CREATE: captureGitMetadata(), installGitHooks()
36
- │ └── server.ts ← fix double loadConfig(), add context_branch + context_merge tools
37
- ├── cli/src/commands/
38
- │ ├── init.ts ← add --hooks, --remote, --role flags
39
- │ ├── commit.ts ← add --ci-run-id, --pipeline flags + captureGitMetadata
40
- │ ├── branch.ts ← CREATE
41
- │ ├── merge.ts ← CREATE
42
- │ ├── search.ts ← CREATE
43
- │ ├── status.ts ← CREATE
44
- │ ├── push.ts ← CREATE
45
- │ ├── pull.ts ← CREATE
46
- │ ├── keygen.ts ← CREATE
47
- │ └── doctor.ts ← CREATE
48
- └── api/src/
49
- ├── server.ts ← mount /v1/store routes; add auth middleware
50
- └── middleware/
51
- └── auth.ts ← CREATE: Bearer token auth
52
-
53
- .github/workflows/
54
- └── contextgit-ci.yml ← CREATE: CI integration template
55
- ```
56
-
57
- ---
58
-
59
- ## Week 5 — Git Integration + MCP Completeness
60
-
61
- **Goal:** Every context commit is automatically enriched with git metadata. MCP covers the full engine surface.
62
-
63
- ### 5.1 — `packages/mcp/src/git-sync.ts` (new file)
64
-
65
- Two exports:
66
-
67
- **`captureGitMetadata(cwd: string): Promise<{ sha: string; branch: string } | null>`**
68
- - Calls `simpleGit(cwd).revparse(['HEAD'])` and `simpleGit(cwd).revparse(['--abbrev-ref', 'HEAD'])`
69
- - Returns `null` on any error — git capture must never block a commit
70
- - Used by both MCP `context_commit` handler and CLI `commit` command
71
-
72
- **`installGitHooks(projectRoot: string): Promise<void>`**
73
- - Writes hook scripts to `.git/hooks/` for `post-commit`, `post-checkout`, `post-merge`
74
- - Idempotent: check for a `# contextgit` sentinel comment before appending
75
- - Hook failures are completely silent — write errors to `~/.contextgit/hooks.log`, never stderr
76
- - `post-commit` script: `contextgit commit -m "git: $(git log -1 --pretty=%s)" --git-capture`
77
- - `post-checkout` script: `contextgit context --quiet` (confirm branch context loaded)
78
- - `post-merge` script: `contextgit commit -m "Merged into $(git rev-parse --abbrev-ref HEAD)"`
79
-
80
- ### 5.2 — SQLite concurrency mitigation in `LocalStore`
81
-
82
- `packages/store/src/local/index.ts` — alongside the existing WAL mode pragma, add:
83
- ```typescript
84
- db.pragma('journal_mode = WAL')
85
- db.pragma('busy_timeout = 5000') // Silently retry on concurrent write contention (1-in-1000 case)
86
- ```
87
-
88
- This is a single-line addition with no interface changes. It ensures that concurrent writes (e.g., a git hook firing while a CLI command is running) queue and retry for up to 5 seconds rather than immediately throwing `SQLITE_BUSY`.
89
-
90
- ### 5.3 — Native git metadata on every commit
91
-
92
- `packages/core/src/engine.ts`:
93
- - Add `gitCommitSha?: string` and `gitBranch?: string` to `EngineCommitInput`
94
- - Pass through to `EngineCommitStoreInput` → `CommitInput`
95
-
96
- `packages/mcp/src/server.ts` (in `context_commit` handler):
97
- ```typescript
98
- const git = await captureGitMetadata(process.cwd())
99
- await engine.commit({ ..., gitCommitSha: git?.sha, gitBranch: git?.branch })
100
- ```
101
-
102
- `packages/cli/src/commands/commit.ts`:
103
- - Same `captureGitMetadata()` call; import from `../../mcp/src/git-sync` or duplicate the 5-line helper inline
104
-
105
- ### 5.4 — Fix MCP server tech debt
106
-
107
- `packages/mcp/src/server.ts`:
108
- - **Double `loadConfig()` bug:** Called at bootstrap (~line 69) and again for `snapshotInterval` (~line 100). Fix: extend `ServerContext` to carry `config: ContextGitConfig`. `bootstrap()` returns it; remove the second `loadConfig()` call.
109
- - **Deprecated 4-arg `server.tool()`:** If no clean fix in MCP SDK `^1.0.0`, add `// TODO: MCP SDK deprecated 4-arg form; no non-deprecated alternative available as of SDK ^1.0.0` inline comment.
110
-
111
- ### 5.5 — `context_branch` and `context_merge` MCP tools
112
-
113
- `packages/mcp/src/server.ts` — add two new `server.tool()` calls:
114
-
115
- **`context_branch`:**
116
- - Input: `{ git_branch: string, name?: string }`
117
- - Calls `engine.branch(gitBranch, name)` — engine method is already implemented
118
- - Returns: `{ branchId, branchName }`
119
- - Call `autoSnapshot.onToolCall('context_branch')` first
120
-
121
- **`context_merge`:**
122
- - Input: `{ source_branch_id: string }`
123
- - Calls `engine.merge(sourceBranchId)`
124
- - Returns: `{ commitId }`
125
- - Call `autoSnapshot.onToolCall('context_merge')` first
126
-
127
- ### 5.6 — `contextgit init --hooks`
128
-
129
- `packages/cli/src/commands/init.ts`:
130
- - Add `--hooks` boolean flag
131
- - When set, call `installGitHooks(process.cwd())` after project creation
132
- - Without the flag, print: `Tip: run "contextgit init --hooks" to auto-capture context on every git commit`
133
-
134
- **Week 5 Validation Gate:**
135
- ```bash
136
- # In a test git repo with contextgit init --hooks:
137
- echo "test" > file.txt && git add . && git commit -m "test"
138
- # Verify: contextgit context shows a new commit with gitCommitSha populated
139
- ```
140
-
141
- ---
142
-
143
- ## Week 6 — CLI Completeness + Push/Pull
144
-
145
- **Goal:** Complete CLI surface. Enable the core team-sharing workflow.
146
-
147
- ### 6.1 — Fix production API (critical bug)
148
-
149
- `packages/api/src/server.ts` — in `createApp()`, after store is initialized:
150
- ```typescript
151
- app.use('/v1/store', createStoreRouter(store))
152
- ```
153
-
154
- Without this, `RemoteStore` gets 404 on every call in production. This is the single most important fix for team use.
155
-
156
- ### 6.2 — Add `remote?` to config
157
-
158
- `packages/core/src/types.ts`:
159
- ```typescript
160
- interface ContextGitConfig {
161
- // ... existing fields ...
162
- remote?: string // URL for push/pull target (separate from store backend)
163
- }
164
- ```
165
-
166
- - `config.store = 'local'` — use local SQLite for reads/writes (default)
167
- - `config.remote = 'http://...'` — remote API server for push/pull operations
168
-
169
- `packages/cli/src/commands/init.ts` — add `--remote <url>` flag, write to config if provided.
170
-
171
- ### 6.3 — `contextgit branch` and `contextgit merge`
172
-
173
- `packages/cli/src/commands/branch.ts`:
174
- ```
175
- contextgit branch <git-branch-name> [--name <display-name>]
176
- ```
177
- - Bootstrap engine, call `engine.branch(gitBranch, name)`, print new branch ID
178
-
179
- `packages/cli/src/commands/merge.ts`:
180
- ```
181
- contextgit merge <source-branch-id>
182
- ```
183
- - Bootstrap engine, call `engine.merge(sourceBranchId)`, print merge commit ID
184
-
185
- ### 6.4 — `contextgit search`
186
-
187
- `packages/cli/src/commands/search.ts`:
188
- ```
189
- contextgit search <query> [--limit 5] [--format table|json]
190
- ```
191
- - Run `store.fullTextSearch(query, projectId)` and `engine.semanticSearch(query, projectId, limit)` in parallel
192
- - Merge results (deduplicate by commit ID, rank by score)
193
- - Default output: a terminal table (respect `process.stdout.columns`)
194
- - `--format json` for programmatic use
195
-
196
- ### 6.5 — `contextgit status`
197
-
198
- `packages/cli/src/commands/status.ts`:
199
- ```
200
- contextgit status
201
- ```
202
- Output:
203
- ```
204
- Project: my-project (proj_abc123)
205
- Branch: feature/auth (ctx_branch_xyz)
206
- HEAD: "Fixed the login bug" (2 hours ago)
207
- Threads: 3 open
208
- Store: local (~/.contextgit/projects/proj_abc123.db)
209
- Remote: http://contextgit.company.com (configured)
210
- ```
211
-
212
- ### 6.6 — `contextgit push` and `contextgit pull`
213
-
214
- **Architecture:** Push/pull lives entirely in the CLI layer. Both `LocalStore` and `RemoteStore` implement `ContextStore`, so:
215
- - Push = `listCommits(localStore)` → diff by ID vs `listCommits(remoteStore)` → `createCommit(remoteStore)` for missing ones
216
- - Pull = reverse
217
-
218
- **Conflict resolution:** Skip if commit ID already exists on target (append-only ledger; commits are immutable once written, so duplicate IDs = already synced).
219
-
220
- `packages/cli/src/commands/push.ts`:
221
- ```
222
- contextgit push [--branch <id>]
223
- ```
224
- 1. Load `LocalStore(projectId)` and `RemoteStore(config.remote)` from config
225
- 2. List local commits on current branch (all pages via pagination)
226
- 3. List remote commits on same branch
227
- 4. `createCommit(remote, c)` for each commit not on remote
228
- 5. `indexEmbedding(remote, commitId, vector)` for each pushed commit
229
- 6. Print: `Pushed N commits to <remote-url>`
230
-
231
- `packages/cli/src/commands/pull.ts`:
232
- ```
233
- contextgit pull [--branch <id>]
234
- ```
235
- - Fetch all remote commits not present locally
236
- - Wrap ALL inserts in a single `better-sqlite3` transaction: `db.transaction(() => { ... })()`. All commits land atomically or none do — if the process dies mid-pull, the local store stays clean.
237
- - Re-index embeddings locally after the transaction commits (fire-and-forget)
238
- - Update `headCommitId` on local branch after pull
239
-
240
- **Week 6 Validation Gate:**
241
- ```bash
242
- # dir1: contextgit commit -m "hello from dir1"
243
- # dir1: contextgit push
244
- # dir2: contextgit pull
245
- # dir2: contextgit context → shows dir1 commit
246
- ```
247
-
248
- ---
249
-
250
- ## Week 7 — Auth + Multi-Agent
251
-
252
- **Goal:** Make the REST API safe for shared use. Enable agent-role-filtered snapshots.
253
-
254
- ### 7.1 — API key authentication
255
-
256
- **New DB:** `~/.contextgit/server.db` (separate from project DBs). One table:
257
- ```sql
258
- CREATE TABLE api_keys (
259
- id TEXT PRIMARY KEY,
260
- name TEXT NOT NULL,
261
- key_hash TEXT NOT NULL UNIQUE, -- SHA-256(raw_key)
262
- created_at INTEGER NOT NULL,
263
- last_used INTEGER
264
- );
265
- ```
266
-
267
- `packages/api/src/middleware/auth.ts`:
268
- - Read `Authorization: Bearer <token>` header
269
- - Hash the token with `crypto.createHash('sha256')`
270
- - Look up `key_hash` in `api_keys` table
271
- - 401 if missing or no match
272
- - Update `last_used` on success
273
- - Auth is only enforced when `CONTEXTGIT_AUTH=1` env var is set — local-only mode stays public
274
-
275
- `packages/api/src/server.ts`:
276
- ```typescript
277
- if (process.env.CONTEXTGIT_AUTH) {
278
- app.use(authMiddleware(serverDb))
279
- }
280
- app.use('/v1', router)
281
- app.use('/v1/store', createStoreRouter(store))
282
- ```
283
-
284
- `packages/store/src/remote/index.ts`:
285
- ```typescript
286
- constructor(baseUrl: string, private apiKey?: string) { ... }
287
- // In req():
288
- if (this.apiKey) headers['Authorization'] = `Bearer ${this.apiKey}`
289
- ```
290
-
291
- `packages/cli/src/commands/keygen.ts`:
292
- ```
293
- contextgit keygen [--name <label>]
294
- ```
295
- - Generate 32-byte random key, base64url encode
296
- - Store SHA-256 hash in `~/.contextgit/server.db`
297
- - Print key once (never stored in plaintext): `cgk_<base64url>`
298
- - Key goes in `config.apiKey` for CLI/MCP use
299
-
300
- **Week 7 Gate (auth):**
301
- ```bash
302
- CONTEXTGIT_AUTH=1 node packages/api/dist/server.js &
303
- curl http://localhost:3141/v1/snapshot # → 401
304
- curl -H "Authorization: Bearer cgk_..." http://localhost:3141/v1/snapshot # → 200
305
- ```
306
-
307
- ### 7.2 — Multi-agent scoped snapshots
308
-
309
- `packages/store/src/interface.ts`:
310
- ```typescript
311
- getSessionSnapshot(
312
- projectId: string,
313
- branchId: string,
314
- options?: { agentRole?: AgentRole }
315
- ): Promise<SessionSnapshot>
316
- ```
317
- (Backward-compatible — `options` is optional.)
318
-
319
- `packages/store/src/local/queries.ts`:
320
- ```typescript
321
- selectRecentCommitsByRole: db.prepare(`
322
- SELECT * FROM commits
323
- WHERE branch_id = ? AND agent_role = ?
324
- ORDER BY created_at DESC LIMIT 3
325
- `)
326
- ```
327
-
328
- `packages/store/src/local/index.ts`:
329
- - When `options?.agentRole` is set, use `selectRecentCommitsByRole` instead of the default `selectRecentCommits`
330
- - `openThreads` are never role-filtered (threads cross agent boundaries by design)
331
-
332
- `packages/mcp/src/server.ts` — `context_get` tool gains new parameter:
333
- ```typescript
334
- agent_role: z.enum(['orchestrator','dev','test','review','background','ci','solo']).optional()
335
- ```
336
-
337
- `packages/cli/src/commands/init.ts` — add `--role` flag:
338
- ```
339
- contextgit init [--role orchestrator|dev|test|review|ci|solo]
340
- ```
341
- Writes `agentRole` to `.contextgit/config.json`.
342
-
343
- **Week 7 Gate (multi-agent):**
344
- ```bash
345
- # Agent 1 (--role dev): contextgit commit -m "implement login"
346
- # Agent 2 (--role test): contextgit commit -m "test login"
347
- # context_get agent_role=dev → recentCommits shows only dev commits
348
- # context_get → recentCommits shows all commits
349
- ```
350
-
351
- ---
352
-
353
- ## Week 8 — CI Integration + Polish
354
-
355
- **Goal:** Ship a working CI story. Add diagnostics. Integration tests. Cut the Phase 2 release.
356
-
357
- ### 8.1 — CI metadata on commits
358
-
359
- `packages/core/src/engine.ts`:
360
- - Add `ciRunId?: string` and `pipelineName?: string` to `EngineCommitInput`
361
- - Pass through to `CommitInput` (fields already exist in DB schema and `CommitInput` type)
362
-
363
- `packages/cli/src/commands/commit.ts`:
364
- - Add `--ci-run-id <id>` and `--pipeline <name>` flags
365
-
366
- ### 8.2 — GitHub Actions templates
367
-
368
- `.github/workflows/contextgit-ci.yml` — template for users to copy into their repos:
369
- ```yaml
370
- name: ContextGit CI
371
-
372
- on: [push, pull_request]
373
-
374
- jobs:
375
- capture-context:
376
- runs-on: ubuntu-latest
377
- steps:
378
- - uses: actions/checkout@v4
379
- - uses: actions/setup-node@v4
380
- with: { node-version: '20' }
381
- - run: npx contextgit commit
382
- -m "CI run ${{ github.run_number }}: ${{ github.event.head_commit.message }}"
383
- --role ci
384
- --ci-run-id ${{ github.run_id }}
385
- --pipeline ${{ github.workflow }}
386
- env:
387
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
388
- CONTEXTGIT_REMOTE: ${{ secrets.CONTEXTGIT_REMOTE_URL }}
389
- CONTEXTGIT_API_KEY: ${{ secrets.CONTEXTGIT_API_KEY }}
390
- ```
391
-
392
- ### 8.3 — `contextgit doctor`
393
-
394
- `packages/cli/src/commands/doctor.ts`:
395
- ```
396
- contextgit doctor
397
- ```
398
- Checks and reports:
399
- - [ ] Config file present and valid JSON
400
- - [ ] DB reachable (local: file exists; remote: GET /v1/snapshot returns ≤ 401)
401
- - [ ] Git hooks installed (check `.git/hooks/post-commit` for sentinel comment)
402
- - [ ] API key configured (if `config.remote` is set)
403
- - [ ] Embedding model downloaded (check `~/.cache/huggingface` or equiv)
404
- - [ ] MCP server registered in `~/.claude.json` (check for `contextgit` entry)
405
- - [ ] SQLite `busy_timeout` pragma set (open DB, run `PRAGMA busy_timeout`, verify result > 0)
406
-
407
- ### 8.4 — Integration test suite
408
-
409
- New test files:
410
-
411
- `packages/cli/src/push-pull.test.ts`:
412
- - Two `LocalStore(':memory:')` instances bridged by an in-process Express server
413
- - Commit to store A → push to server → pull to store B → assert both stores have same commits
414
- - Embedding round-trip: index in A, pull to B, semantic search in B returns result
415
-
416
- `packages/api/src/auth.test.ts`:
417
- - Supertest against `createApp()` with `CONTEXTGIT_AUTH=1`
418
- - 401 on missing Authorization header
419
- - 401 on wrong key
420
- - 200 on valid key
421
- - `last_used` updates on successful auth
422
-
423
- `packages/store/src/role-filter.test.ts`:
424
- - Two agents write commits with different roles
425
- - `getSessionSnapshot(projectId, branchId, { agentRole: 'dev' })` returns only dev commits in `recentCommits`
426
- - `openThreads` remain unfiltered regardless of role
427
-
428
- ### Phase 2 Validation Gates
429
-
430
- | Gate | What to verify |
431
- |------|----------------|
432
- | **1 — Git hooks** | `git commit` in a `--hooks` repo → context commit auto-written with `gitCommitSha` populated |
433
- | **2 — Push/pull** | Commit in dir1, push, pull in dir2, `contextgit context` in dir2 shows dir1's commit |
434
- | **3 — Auth** | API with `CONTEXTGIT_AUTH=1`: no unauthenticated request succeeds |
435
- | **4 — CI** | GH Actions workflow writes `agentRole: ci` commit; `contextgit search "CI run"` finds it |
436
- | **5 — Multi-agent** | `context_get agent_role=dev` returns only dev-role `recentCommits` |
437
- | **6 — Claims** | `contextgit claim "task"` → `context_get` shows activeClaims → `contextgit commit` auto-releases claim |
438
-
439
- ---
440
-
441
- ## Phase 2 Delta — Coordination Primitives (added 2026-03-12)
442
-
443
- **Status: IN PROGRESS — Phase 2 is NOT complete until this ships.**
444
-
445
- Pre-launch dogfooding revealed task collision: two agents call `context_get`, both see the same next task, both start building it. Fix: `claims` table + claim/unclaim primitives.
446
-
447
- See `docs/ContextGit_DELTA.md` for full decision log.
448
-
449
- ### New: `claims` table (DB migration v4)
450
-
451
- ```sql
452
- CREATE TABLE claims (
453
- id TEXT PRIMARY KEY,
454
- project_id TEXT NOT NULL REFERENCES projects(id),
455
- branch_id TEXT NOT NULL REFERENCES branches(id),
456
- task TEXT NOT NULL,
457
- agent_id TEXT NOT NULL,
458
- role TEXT NOT NULL,
459
- claimed_at INTEGER NOT NULL,
460
- status TEXT NOT NULL DEFAULT 'proposed',
461
- ttl INTEGER NOT NULL,
462
- released_at INTEGER
463
- )
464
- ```
465
-
466
- ### New types in `packages/core/src/types.ts`
467
- - `ClaimStatus = 'proposed' | 'active' | 'released'`
468
- - `Claim` entity
469
- - `ClaimInput`
470
- - `SessionSnapshot.activeClaims: Claim[]`
471
-
472
- ### New store methods in `packages/store/src/interface.ts`
473
- - `claimTask(projectId, branchId, input): Promise<Claim>`
474
- - `unclaimTask(claimId): Promise<void>`
475
- - `listActiveClaims(projectId): Promise<Claim[]>`
476
-
477
- Auto-release on `createCommit()` — branch-scoped: only releases this agent's claims on this branch.
478
-
479
- TTL filter is in SQL (`claimed_at + ttl > now`) — not application code.
480
-
481
- ### New MCP tools
482
- - `context_claim` — input: `task`, `ttl_hours` (default 2). Returns claim ID.
483
- - `context_unclaim` — input: `claim_id`. Releases immediately.
484
-
485
- ### New CLI commands
486
- - `contextgit claim "<task>"` — creates proposed claim
487
- - `contextgit unclaim <claimId>` — releases claim manually
488
-
489
- ### Snapshot change
490
- `context_get` output gains `## Active Claims` section showing all non-released, non-TTL-expired claims.
491
-
492
- ---
493
-
494
- ## Architecture Notes
495
-
496
- ### Dependency graph is unchanged
497
-
498
- No new packages. The strict dep graph from Phase 1 is preserved:
499
- ```
500
- core → @anthropic-ai/sdk, @xenova/transformers, nanoid
501
- store → core (types only), better-sqlite3, sqlite-vec
502
- mcp → core, store, @modelcontextprotocol/sdk, simple-git
503
- cli → core, store, @oclif/core
504
- api → core, store, express
505
- ```
506
-
507
- `captureGitMetadata()` lives in `packages/mcp/src/git-sync.ts` (MCP already has `simple-git`). The CLI duplicates a minimal 5-line version in its bootstrap. Core stays pure business logic with no I/O deps.
508
-
509
- ### Config schema evolution
510
-
511
- All three bootstrap files (`cli/src/bootstrap.ts`, `mcp/src/server.ts`, `api/src/bootstrap.ts`) have their own copy of the config loader. This is intentional to preserve the dep graph. When `ContextGitConfig` gains `remote?` and the `apiKey` field is wired, update all three copies in parallel.
512
-
513
- ### Push/pull append-only guarantee
514
-
515
- Commits are immutable once written. "Conflicts" at the data level don't exist: if two agents wrote commits simultaneously, both are valid and both should exist in both stores after sync. The rolling summarizer naturally resolves semantic conflicts in subsequent summaries. No CRDT or OT needed.
516
-
517
- ### Auth is opt-in
518
-
519
- Local-only workflows (solo developer, single machine) stay zero-config. Auth is enabled only when the `CONTEXTGIT_AUTH=1` env var is set on the API server. This preserves the Phase 1 DX for solo use while adding security for team deployments.
520
-
521
- ### Remote Hosting
522
-
523
- Phase 2 validation uses localhost for the REST API server (`packages/api`). Deploying to a shared host (Railway, fly.io, etc.) is deferred to Phase 3 when the product goes public. For now, teams run the API server themselves on a machine they control.
524
-
525
- ---
526
-
527
- ## What to Defer to Phase 3
528
-
529
- | Feature | Why deferred |
530
- |---------|-------------|
531
- | **PostgreSQL + pgvector** | SQLite + WAL handles ~10 concurrent writers; build Postgres only when hitting real limits. Estimated 2–3 weeks of work. |
532
- | **Conflict resolution beyond last-write-wins** | Append-only ledger means no data conflicts; semantic conflicts resolved by summarizer |
533
- | **OpenAI embedding alternative** | `embeddingModel: 'openai'` is in the type but wiring it is a separate feature; Xenova local model works |
534
- | **Web UI dashboard** | REST API + formatted snapshot already expose the data |
535
- | **Multi-project API server mode** | Single-project-per-process is fine for Phase 2; multi-project routing is Phase 3 |