contextgit 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -0
- package/bin/contextgit-mcp.js +7 -0
- package/package.json +24 -14
- package/node_modules/@contextgit/mcp/dist/auto-snapshot.d.ts +0 -30
- package/node_modules/@contextgit/mcp/dist/auto-snapshot.d.ts.map +0 -1
- package/node_modules/@contextgit/mcp/dist/auto-snapshot.js +0 -68
- package/node_modules/@contextgit/mcp/dist/auto-snapshot.js.map +0 -1
- package/node_modules/@contextgit/mcp/dist/config.d.ts +0 -17
- package/node_modules/@contextgit/mcp/dist/config.d.ts.map +0 -1
- package/node_modules/@contextgit/mcp/dist/config.js +0 -48
- package/node_modules/@contextgit/mcp/dist/config.js.map +0 -1
- package/node_modules/@contextgit/mcp/dist/git-sync.d.ts +0 -15
- package/node_modules/@contextgit/mcp/dist/git-sync.d.ts.map +0 -1
- package/node_modules/@contextgit/mcp/dist/git-sync.js +0 -87
- package/node_modules/@contextgit/mcp/dist/git-sync.js.map +0 -1
- package/node_modules/@contextgit/mcp/dist/index.d.ts +0 -3
- package/node_modules/@contextgit/mcp/dist/index.d.ts.map +0 -1
- package/node_modules/@contextgit/mcp/dist/index.js +0 -17
- package/node_modules/@contextgit/mcp/dist/index.js.map +0 -1
- package/node_modules/@contextgit/mcp/dist/server.d.ts +0 -3
- package/node_modules/@contextgit/mcp/dist/server.d.ts.map +0 -1
- package/node_modules/@contextgit/mcp/dist/server.js +0 -377
- package/node_modules/@contextgit/mcp/dist/server.js.map +0 -1
- package/node_modules/@contextgit/mcp/package.json +0 -31
- package/node_modules/@contextgit/mcp/src/auto-snapshot.ts +0 -83
- package/node_modules/@contextgit/mcp/src/config.ts +0 -53
- package/node_modules/@contextgit/mcp/src/git-sync.ts +0 -94
- package/node_modules/@contextgit/mcp/src/index.ts +0 -19
- package/node_modules/@contextgit/mcp/src/server.ts +0 -568
- package/node_modules/@contextgit/mcp/tsconfig.json +0 -9
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# ContextGit
|
|
2
|
+
|
|
3
|
+
Every time you start a new session with an AI coding agent, it starts from zero. It doesn't know what was built yesterday, what decisions were made, or what's left to do. You spend the first 10 minutes of every session re-explaining your project. ContextGit fixes this — it gives your agents a persistent memory layer that survives across sessions, branches, and machines.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g contextgit
|
|
9
|
+
cd your-project
|
|
10
|
+
contextgit init
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> **Restart Claude Code** (or any MCP client) after running `init` for the MCP server to take effect.
|
|
14
|
+
|
|
15
|
+
That's it. `init` registers the MCP server, updates CLAUDE.md with session instructions, and installs Claude Code hooks. Start a new session — the agent calls `project_memory_load` automatically and picks up exactly where the last session left off.
|
|
16
|
+
|
|
17
|
+
## How it works
|
|
18
|
+
|
|
19
|
+
ContextGit stores structured context commits alongside your git history. Each commit captures what was done, what was decided, and what questions remain open.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Session 1: Agent builds auth module → saves context commit
|
|
23
|
+
Session 2: Agent loads snapshot → knows auth is done → starts on the next task
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## What the agent sees
|
|
27
|
+
|
|
28
|
+
When an agent calls `project_memory_load`, it gets a snapshot like this:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
## Project State
|
|
32
|
+
Auth module complete. API routes tested. Database schema finalized.
|
|
33
|
+
|
|
34
|
+
## Current Branch: Context: main
|
|
35
|
+
Implementing payment integration. Stripe SDK configured.
|
|
36
|
+
|
|
37
|
+
## Recent Activity
|
|
38
|
+
- [2026-03-20T08:33:44Z] "Payment webhook handler done" by solo via claude-code
|
|
39
|
+
- [2026-03-20T07:15:22Z] "Stripe SDK integration" by solo via claude-code
|
|
40
|
+
- [2026-03-19T16:42:11Z] "Auth module complete" by solo via claude-code
|
|
41
|
+
|
|
42
|
+
## Open Threads
|
|
43
|
+
- [FREE] Need to add rate limiting to payment endpoints
|
|
44
|
+
- [CLAIMED by studio-mcp-agent] Build invoice PDF generation
|
|
45
|
+
- [FREE] Decide on webhook retry strategy
|
|
46
|
+
|
|
47
|
+
## Active Claims
|
|
48
|
+
- "Build invoice PDF generation" claimed by studio-mcp-agent (2h TTL)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The agent reads this and knows exactly where the project stands without you saying a word.
|
|
52
|
+
|
|
53
|
+
## MCP tools
|
|
54
|
+
|
|
55
|
+
These tools are exposed to the agent via MCP. The agent calls them as part of its normal workflow.
|
|
56
|
+
|
|
57
|
+
| Tool | What it does |
|
|
58
|
+
|------|-------------|
|
|
59
|
+
| `project_memory_load` | Load the full project snapshot — what was built, what's decided, open threads, active claims. Call at session start. |
|
|
60
|
+
| `project_memory_save` | Save a context commit — what you did, decisions made, open questions. Call before ending a session. |
|
|
61
|
+
| `context_search` | Semantic + full-text search over past context commits. |
|
|
62
|
+
| `project_task_claim` | Claim a task so other agents skip it. Claims auto-expire after 2 hours. |
|
|
63
|
+
| `project_task_unclaim` | Release a claimed task. |
|
|
64
|
+
| `project_memory_branch` | Create a context branch for experimental work. |
|
|
65
|
+
| `project_memory_merge` | Merge a context branch back into the parent. |
|
|
66
|
+
|
|
67
|
+
## CLI commands
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
contextgit init # Initialize contextgit in current project
|
|
71
|
+
contextgit init --hooks # Initialize with git hooks
|
|
72
|
+
contextgit commit "message" # Write a context commit
|
|
73
|
+
contextgit status # Show current project state
|
|
74
|
+
contextgit search "query" # Search past commits
|
|
75
|
+
contextgit claim "task" # Claim a task
|
|
76
|
+
contextgit unclaim <id> # Release a claim
|
|
77
|
+
contextgit branch <name> # Create a context branch
|
|
78
|
+
contextgit merge <id> # Merge a context branch
|
|
79
|
+
contextgit serve # Start the REST API server
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Architecture
|
|
83
|
+
|
|
84
|
+
Monorepo with strict dependency ordering:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
packages/
|
|
88
|
+
core/ → Types, snapshot formatter, embedding service, context engine
|
|
89
|
+
store/ → Storage interface, LocalStore (SQLite), RemoteStore, SupabaseStore
|
|
90
|
+
mcp/ → MCP server (stdio transport, launched by Claude Code)
|
|
91
|
+
cli/ → CLI commands (oclif)
|
|
92
|
+
api/ → REST API (Express)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Local storage:** SQLite via better-sqlite3. One DB per project at `~/.contextgit/projects/<id>.db`.
|
|
96
|
+
|
|
97
|
+
**Remote storage:** Optional Supabase (Postgres + pgvector) for cross-machine sync and team use.
|
|
98
|
+
|
|
99
|
+
**Embeddings:** Local all-MiniLM-L6-v2 (384 dimensions, no API key needed) for semantic search.
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
Project config lives at `.contextgit/config.json`:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"project": "my-project",
|
|
108
|
+
"projectId": "unique-id",
|
|
109
|
+
"store": "local",
|
|
110
|
+
"agentRole": "solo",
|
|
111
|
+
"workflowType": "interactive",
|
|
112
|
+
"autoSnapshot": false,
|
|
113
|
+
"snapshotInterval": 10,
|
|
114
|
+
"embeddingModel": "local"
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Current status
|
|
119
|
+
|
|
120
|
+
This is an early-stage tool. It works for solo developers using Claude Code across one or more machines. The core memory layer is solid — context commits, branches, threads, search, and snapshots all work.
|
|
121
|
+
|
|
122
|
+
## Known limitations
|
|
123
|
+
|
|
124
|
+
- No automatic context merge when git branches are merged (manual `project_memory_merge` required)
|
|
125
|
+
- No integration with external boards (Linear, Jira, GitHub Issues)
|
|
126
|
+
- Semantic search requires the embedding model to download on first use (~23MB)
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Starts the ContextGit MCP server (stdio transport).
|
|
3
|
+
// Uses Node module resolution — works whether @contextgit/mcp is nested or hoisted.
|
|
4
|
+
import('@contextgit/mcp').catch(err => {
|
|
5
|
+
console.error('[contextgit-mcp] Failed to start:', err.message)
|
|
6
|
+
process.exit(1)
|
|
7
|
+
})
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contextgit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"contextgit": "./bin/run.js",
|
|
7
|
-
"contextgit-mcp": "./
|
|
7
|
+
"contextgit-mcp": "./bin/contextgit-mcp.js"
|
|
8
8
|
},
|
|
9
9
|
"oclif": {
|
|
10
10
|
"bin": "contextgit",
|
|
@@ -15,24 +15,34 @@
|
|
|
15
15
|
"dist",
|
|
16
16
|
"bin"
|
|
17
17
|
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"ai",
|
|
20
|
+
"coding-agent",
|
|
21
|
+
"memory",
|
|
22
|
+
"context",
|
|
23
|
+
"git",
|
|
24
|
+
"mcp",
|
|
25
|
+
"claude-code",
|
|
26
|
+
"llm",
|
|
27
|
+
"persistent-memory"
|
|
28
|
+
],
|
|
29
|
+
"description": "Persistent memory layer for AI agent workflows",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc",
|
|
33
|
+
"typecheck": "tsc --noEmit"
|
|
34
|
+
},
|
|
18
35
|
"dependencies": {
|
|
19
|
-
"@contextgit/core": "0.1.
|
|
20
|
-
"@contextgit/store": "0.1.
|
|
21
|
-
"@contextgit/api": "0.1.
|
|
22
|
-
"@contextgit/mcp": "0.1.
|
|
36
|
+
"@contextgit/core": "0.1.6",
|
|
37
|
+
"@contextgit/store": "0.1.6",
|
|
38
|
+
"@contextgit/api": "0.1.6",
|
|
39
|
+
"@contextgit/mcp": "0.1.6",
|
|
23
40
|
"@oclif/core": "^3.27.0",
|
|
24
41
|
"nanoid": "^5.0.0",
|
|
25
42
|
"simple-git": "^3.27.0"
|
|
26
43
|
},
|
|
27
|
-
"bundleDependencies": [
|
|
28
|
-
"@contextgit/mcp"
|
|
29
|
-
],
|
|
30
44
|
"devDependencies": {
|
|
31
45
|
"@types/node": "^20.0.0",
|
|
32
46
|
"typescript": "^5.4.0"
|
|
33
|
-
},
|
|
34
|
-
"scripts": {
|
|
35
|
-
"build": "tsc",
|
|
36
|
-
"typecheck": "tsc --noEmit"
|
|
37
47
|
}
|
|
38
|
-
}
|
|
48
|
+
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { ContextEngine } from '@contextgit/core';
|
|
2
|
-
export interface AutoSnapshotOptions {
|
|
3
|
-
/** Number of non-commit tool calls before an auto-commit fires. Default: 10. */
|
|
4
|
-
interval?: number;
|
|
5
|
-
}
|
|
6
|
-
export declare class AutoSnapshotManager {
|
|
7
|
-
private count;
|
|
8
|
-
private readonly interval;
|
|
9
|
-
private readonly engine;
|
|
10
|
-
constructor(engine: ContextEngine, options?: AutoSnapshotOptions);
|
|
11
|
-
/**
|
|
12
|
-
* Record a tool call by name.
|
|
13
|
-
*
|
|
14
|
-
* - `context_commit` resets the counter (manual commit; no auto-commit fired).
|
|
15
|
-
* - All other tool names increment the counter.
|
|
16
|
-
* - When the counter reaches `interval`, an auto-commit is fired and the
|
|
17
|
-
* counter resets to 0.
|
|
18
|
-
*
|
|
19
|
-
* Auto-commit failures are swallowed — the tool call is never blocked.
|
|
20
|
-
*
|
|
21
|
-
* @returns The new commit ID if an auto-commit was fired, otherwise undefined.
|
|
22
|
-
*/
|
|
23
|
-
onToolCall(toolName: string): Promise<string | undefined>;
|
|
24
|
-
/** Current tool-call count since the last commit (manual or auto). */
|
|
25
|
-
get toolCallCount(): number;
|
|
26
|
-
/** Manually reset the counter (e.g. after an out-of-band commit). */
|
|
27
|
-
reset(): void;
|
|
28
|
-
private fireAutoCommit;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=auto-snapshot.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-snapshot.d.ts","sourceRoot":"","sources":["../src/auto-snapshot.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAE1B,MAAM,EAAE,aAAa,EAAE,OAAO,GAAE,mBAAwB;IAKpE;;;;;;;;;;;OAWG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAgB/D,sEAAsE;IACtE,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,qEAAqE;IACrE,KAAK,IAAI,IAAI;YAMC,cAAc;CAa7B"}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// auto-snapshot.ts — AutoSnapshotManager
|
|
2
|
-
//
|
|
3
|
-
// Tracks tool calls made to the MCP server and fires an automatic context_commit
|
|
4
|
-
// after every N=10 non-commit calls. This ensures context is preserved even when
|
|
5
|
-
// the agent forgets to call context_commit manually.
|
|
6
|
-
//
|
|
7
|
-
// Context tool semantics:
|
|
8
|
-
// context_commit → resets the counter (manual commit = checkpoint reached)
|
|
9
|
-
// context_get → counted (each session-start snapshot counts toward the interval)
|
|
10
|
-
// context_search → counted
|
|
11
|
-
// any other tool → counted (future tools)
|
|
12
|
-
export class AutoSnapshotManager {
|
|
13
|
-
count = 0;
|
|
14
|
-
interval;
|
|
15
|
-
engine;
|
|
16
|
-
constructor(engine, options = {}) {
|
|
17
|
-
this.engine = engine;
|
|
18
|
-
this.interval = options.interval ?? 10;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Record a tool call by name.
|
|
22
|
-
*
|
|
23
|
-
* - `context_commit` resets the counter (manual commit; no auto-commit fired).
|
|
24
|
-
* - All other tool names increment the counter.
|
|
25
|
-
* - When the counter reaches `interval`, an auto-commit is fired and the
|
|
26
|
-
* counter resets to 0.
|
|
27
|
-
*
|
|
28
|
-
* Auto-commit failures are swallowed — the tool call is never blocked.
|
|
29
|
-
*
|
|
30
|
-
* @returns The new commit ID if an auto-commit was fired, otherwise undefined.
|
|
31
|
-
*/
|
|
32
|
-
async onToolCall(toolName) {
|
|
33
|
-
if (toolName === 'context_commit') {
|
|
34
|
-
this.count = 0;
|
|
35
|
-
return undefined;
|
|
36
|
-
}
|
|
37
|
-
this.count++;
|
|
38
|
-
if (this.count >= this.interval) {
|
|
39
|
-
this.count = 0;
|
|
40
|
-
return this.fireAutoCommit();
|
|
41
|
-
}
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
/** Current tool-call count since the last commit (manual or auto). */
|
|
45
|
-
get toolCallCount() {
|
|
46
|
-
return this.count;
|
|
47
|
-
}
|
|
48
|
-
/** Manually reset the counter (e.g. after an out-of-band commit). */
|
|
49
|
-
reset() {
|
|
50
|
-
this.count = 0;
|
|
51
|
-
}
|
|
52
|
-
// ─── Private ──────────────────────────────────────────────────────────────
|
|
53
|
-
async fireAutoCommit() {
|
|
54
|
-
try {
|
|
55
|
-
const commit = await this.engine.commit({
|
|
56
|
-
message: `Auto-snapshot after ${this.interval} tool calls`,
|
|
57
|
-
content: `Automatic context checkpoint triggered after ${this.interval} tool calls without a manual context_commit.`,
|
|
58
|
-
commitType: 'auto',
|
|
59
|
-
});
|
|
60
|
-
return commit.id;
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
// Never block a tool call due to auto-snapshot failure.
|
|
64
|
-
return undefined;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
//# sourceMappingURL=auto-snapshot.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-snapshot.js","sourceRoot":"","sources":["../src/auto-snapshot.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,iFAAiF;AACjF,iFAAiF;AACjF,qDAAqD;AACrD,EAAE;AACF,0BAA0B;AAC1B,8EAA8E;AAC9E,uFAAuF;AACvF,8BAA8B;AAC9B,6CAA6C;AAS7C,MAAM,OAAO,mBAAmB;IACtB,KAAK,GAAG,CAAC,CAAA;IACA,QAAQ,CAAQ;IAChB,MAAM,CAAe;IAEtC,YAAY,MAAqB,EAAE,UAA+B,EAAE;QAClE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAA;IACxC,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,UAAU,CAAC,QAAgB;QAC/B,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;YACd,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,CAAA;QAEZ,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;YACd,OAAO,IAAI,CAAC,cAAc,EAAE,CAAA;QAC9B,CAAC;QAED,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,sEAAsE;IACtE,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED,qEAAqE;IACrE,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;IAChB,CAAC;IAED,6EAA6E;IAErE,KAAK,CAAC,cAAc;QAC1B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;gBACtC,OAAO,EAAE,uBAAuB,IAAI,CAAC,QAAQ,aAAa;gBAC1D,OAAO,EAAE,gDAAgD,IAAI,CAAC,QAAQ,8CAA8C;gBACpH,UAAU,EAAE,MAAM;aACnB,CAAC,CAAA;YACF,OAAO,MAAM,CAAC,EAAE,CAAA;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,wDAAwD;YACxD,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { ContextGitConfig } from '@contextgit/core';
|
|
2
|
-
export declare class ConfigNotFoundError extends Error {
|
|
3
|
-
constructor(startDir: string);
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Search upward from `startDir` for `.contextgit/config.json`.
|
|
7
|
-
* Returns the first match found, or throws ConfigNotFoundError.
|
|
8
|
-
*/
|
|
9
|
-
export declare function findConfigPath(startDir?: string): string;
|
|
10
|
-
/**
|
|
11
|
-
* Load and parse `.contextgit/config.json`.
|
|
12
|
-
* Throws ConfigNotFoundError if not found, or Error if JSON is invalid.
|
|
13
|
-
*/
|
|
14
|
-
export declare function loadConfig(startDir?: string): ContextGitConfig & {
|
|
15
|
-
configDir: string;
|
|
16
|
-
};
|
|
17
|
-
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAExD,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,QAAQ,EAAE,MAAM;CAI7B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAevE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAatF"}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// config.ts — load and validate .contextgit/config.json
|
|
2
|
-
// Searches from CWD upwards until it finds the config file.
|
|
3
|
-
import { readFileSync } from 'fs';
|
|
4
|
-
import { join, dirname } from 'path';
|
|
5
|
-
export class ConfigNotFoundError extends Error {
|
|
6
|
-
constructor(startDir) {
|
|
7
|
-
super(`No .contextgit/config.json found searching upward from: ${startDir}`);
|
|
8
|
-
this.name = 'ConfigNotFoundError';
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Search upward from `startDir` for `.contextgit/config.json`.
|
|
13
|
-
* Returns the first match found, or throws ConfigNotFoundError.
|
|
14
|
-
*/
|
|
15
|
-
export function findConfigPath(startDir = process.cwd()) {
|
|
16
|
-
let current = startDir;
|
|
17
|
-
while (true) {
|
|
18
|
-
const candidate = join(current, '.contextgit', 'config.json');
|
|
19
|
-
try {
|
|
20
|
-
readFileSync(candidate);
|
|
21
|
-
return candidate;
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
const parent = dirname(current);
|
|
25
|
-
if (parent === current) {
|
|
26
|
-
throw new ConfigNotFoundError(startDir);
|
|
27
|
-
}
|
|
28
|
-
current = parent;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Load and parse `.contextgit/config.json`.
|
|
34
|
-
* Throws ConfigNotFoundError if not found, or Error if JSON is invalid.
|
|
35
|
-
*/
|
|
36
|
-
export function loadConfig(startDir) {
|
|
37
|
-
const configPath = findConfigPath(startDir);
|
|
38
|
-
const raw = readFileSync(configPath, 'utf-8');
|
|
39
|
-
const config = JSON.parse(raw);
|
|
40
|
-
if (!config.projectId) {
|
|
41
|
-
throw new Error(`Invalid config at ${configPath}: missing required field 'projectId'`);
|
|
42
|
-
}
|
|
43
|
-
if (!config.project) {
|
|
44
|
-
throw new Error(`Invalid config at ${configPath}: missing required field 'project'`);
|
|
45
|
-
}
|
|
46
|
-
return { ...config, configDir: dirname(configPath) };
|
|
47
|
-
}
|
|
48
|
-
//# sourceMappingURL=config.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,4DAA4D;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAGpC,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,QAAgB;QAC1B,KAAK,CAAC,2DAA2D,QAAQ,EAAE,CAAC,CAAA;QAC5E,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAC7D,IAAI,OAAO,GAAG,QAAQ,CAAA;IACtB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,CAAA;QAC7D,IAAI,CAAC;YACH,YAAY,CAAC,SAAS,CAAC,CAAA;YACvB,OAAO,SAAS,CAAA;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;YAC/B,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;gBACvB,MAAM,IAAI,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YACzC,CAAC;YACD,OAAO,GAAG,MAAM,CAAA;QAClB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,QAAiB;IAC1C,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;IAC3C,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAqB,CAAA;IAElD,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,qBAAqB,UAAU,sCAAsC,CAAC,CAAA;IACxF,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,qBAAqB,UAAU,oCAAoC,CAAC,CAAA;IACtF,CAAC;IAED,OAAO,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,CAAA;AACtD,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Capture the current git commit SHA and branch name.
|
|
3
|
-
* Returns null on any error — must never block a context commit.
|
|
4
|
-
*/
|
|
5
|
-
export declare function captureGitMetadata(cwd: string): Promise<{
|
|
6
|
-
sha: string;
|
|
7
|
-
branch: string;
|
|
8
|
-
} | null>;
|
|
9
|
-
/**
|
|
10
|
-
* Install contextgit git hooks into <projectRoot>/.git/hooks/.
|
|
11
|
-
* Idempotent: checks for the sentinel comment before appending.
|
|
12
|
-
* Hook failures are logged to ~/.contextgit/hooks.log — never to stderr.
|
|
13
|
-
*/
|
|
14
|
-
export declare function installGitHooks(projectRoot: string): Promise<void>;
|
|
15
|
-
//# sourceMappingURL=git-sync.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"git-sync.d.ts","sourceRoot":"","sources":["../src/git-sync.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAWjD;AAmBD;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBxE"}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// git-sync.ts — git metadata capture and hook installation.
|
|
2
|
-
//
|
|
3
|
-
// captureGitMetadata: used by context_commit (MCP) and commit CLI command to
|
|
4
|
-
// auto-populate gitCommitSha on every context commit.
|
|
5
|
-
//
|
|
6
|
-
// installGitHooks: idempotent hook installer — writes post-commit,
|
|
7
|
-
// post-checkout, post-merge scripts into .git/hooks/.
|
|
8
|
-
import { writeFileSync, readFileSync, mkdirSync, existsSync, appendFileSync } from 'fs';
|
|
9
|
-
import { join, resolve } from 'path';
|
|
10
|
-
import { homedir } from 'os';
|
|
11
|
-
import { simpleGit } from 'simple-git';
|
|
12
|
-
const SENTINEL = '# contextgit';
|
|
13
|
-
const HOOKS_LOG = join(homedir(), '.contextgit', 'hooks.log');
|
|
14
|
-
// ─── captureGitMetadata ────────────────────────────────────────────────────────
|
|
15
|
-
/**
|
|
16
|
-
* Capture the current git commit SHA and branch name.
|
|
17
|
-
* Returns null on any error — must never block a context commit.
|
|
18
|
-
*/
|
|
19
|
-
export async function captureGitMetadata(cwd) {
|
|
20
|
-
try {
|
|
21
|
-
const git = simpleGit(cwd);
|
|
22
|
-
const [sha, branch] = await Promise.all([
|
|
23
|
-
git.revparse(['HEAD']),
|
|
24
|
-
git.revparse(['--abbrev-ref', 'HEAD']),
|
|
25
|
-
]);
|
|
26
|
-
return { sha: sha.trim(), branch: branch.trim() };
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// ─── installGitHooks ──────────────────────────────────────────────────────────
|
|
33
|
-
const HOOK_SCRIPTS = {
|
|
34
|
-
'post-commit': `#!/bin/sh
|
|
35
|
-
${SENTINEL}
|
|
36
|
-
contextgit commit -m "git: $(git log -1 --pretty=%s)" 2>>"${HOOKS_LOG}" || true
|
|
37
|
-
`,
|
|
38
|
-
'post-checkout': `#!/bin/sh
|
|
39
|
-
${SENTINEL}
|
|
40
|
-
contextgit context --quiet 2>>"${HOOKS_LOG}" || true
|
|
41
|
-
`,
|
|
42
|
-
'post-merge': `#!/bin/sh
|
|
43
|
-
${SENTINEL}
|
|
44
|
-
contextgit commit -m "Merged into $(git rev-parse --abbrev-ref HEAD)" 2>>"${HOOKS_LOG}" || true
|
|
45
|
-
`,
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Install contextgit git hooks into <projectRoot>/.git/hooks/.
|
|
49
|
-
* Idempotent: checks for the sentinel comment before appending.
|
|
50
|
-
* Hook failures are logged to ~/.contextgit/hooks.log — never to stderr.
|
|
51
|
-
*/
|
|
52
|
-
export async function installGitHooks(projectRoot) {
|
|
53
|
-
const hooksDir = join(resolve(projectRoot), '.git', 'hooks');
|
|
54
|
-
mkdirSync(hooksDir, { recursive: true });
|
|
55
|
-
for (const [hookName, script] of Object.entries(HOOK_SCRIPTS)) {
|
|
56
|
-
const hookPath = join(hooksDir, hookName);
|
|
57
|
-
if (existsSync(hookPath)) {
|
|
58
|
-
const existing = readFileSync(hookPath, 'utf-8');
|
|
59
|
-
if (existing.includes(SENTINEL))
|
|
60
|
-
continue; // already installed
|
|
61
|
-
// Append to existing hook
|
|
62
|
-
writeFileSync(hookPath, existing.trimEnd() + '\n\n' + script);
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
writeFileSync(hookPath, script);
|
|
66
|
-
}
|
|
67
|
-
// Make executable (chmod +x)
|
|
68
|
-
try {
|
|
69
|
-
const { chmodSync } = await import('fs');
|
|
70
|
-
chmodSync(hookPath, 0o755);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
logHookError(`chmod failed for ${hookPath}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function logHookError(msg) {
|
|
78
|
-
try {
|
|
79
|
-
const dir = join(homedir(), '.contextgit');
|
|
80
|
-
mkdirSync(dir, { recursive: true });
|
|
81
|
-
appendFileSync(HOOKS_LOG, `[${new Date().toISOString()}] ${msg}\n`);
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
// truly silent
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
//# sourceMappingURL=git-sync.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"git-sync.js","sourceRoot":"","sources":["../src/git-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// index.ts — entry point for the ContextGit MCP server process.
|
|
3
|
-
// Started by the MCP host (Claude Desktop / Claude Code) via stdio.
|
|
4
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
-
import { createServer } from './server.js';
|
|
6
|
-
async function main() {
|
|
7
|
-
const server = await createServer();
|
|
8
|
-
const transport = new StdioServerTransport();
|
|
9
|
-
await server.connect(transport);
|
|
10
|
-
// Server is now listening on stdin/stdout — process stays alive until the
|
|
11
|
-
// host closes the connection.
|
|
12
|
-
}
|
|
13
|
-
main().catch(err => {
|
|
14
|
-
console.error('[contextgit-mcp] Fatal error:', err);
|
|
15
|
-
process.exit(1);
|
|
16
|
-
});
|
|
17
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,gEAAgE;AAChE,oEAAoE;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE,CAAA;IACnC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC/B,0EAA0E;IAC1E,8BAA8B;AAChC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAA;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAsGnE,wBAAsB,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC,CA4bvD"}
|