contextgit 0.0.9 → 0.0.11
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/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +36 -121
- package/dist/commands/init.js.map +1 -1
- package/dist/lib/client-config.d.ts +1 -18
- package/dist/lib/client-config.d.ts.map +1 -1
- package/dist/lib/client-config.js +1 -73
- package/dist/lib/client-config.js.map +1 -1
- package/dist/lib/client-config.test.js +1 -96
- package/dist/lib/client-config.test.js.map +1 -1
- package/dist/lib/init-helpers.d.ts +24 -0
- package/dist/lib/init-helpers.d.ts.map +1 -0
- package/dist/lib/init-helpers.js +155 -0
- package/dist/lib/init-helpers.js.map +1 -0
- package/dist/lib/init-helpers.test.d.ts +2 -0
- package/dist/lib/init-helpers.test.d.ts.map +1 -0
- package/dist/lib/init-helpers.test.js +73 -0
- package/dist/lib/init-helpers.test.js.map +1 -0
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAA;AAW5C,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAC,WAAW,SAA0C;IAE5D,MAAM,CAAC,KAAK;;;MAWX;IAEK,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAgI3B"}
|
package/dist/commands/init.js
CHANGED
|
@@ -7,51 +7,7 @@ import { nanoid } from 'nanoid';
|
|
|
7
7
|
import { simpleGit } from 'simple-git';
|
|
8
8
|
import { LocalStore } from '@contextgit/store';
|
|
9
9
|
import { installGitHooks } from '../git-hooks.js';
|
|
10
|
-
import {
|
|
11
|
-
const MCP_SYSTEM_PROMPT = `You have access to ContextGit memory tools.
|
|
12
|
-
|
|
13
|
-
At the start of every session, call context_get with scope=global immediately — before reading any files, before asking any questions, before doing any work. Do not skip this step.
|
|
14
|
-
|
|
15
|
-
After completing significant work (a feature, a decision, a resolved problem), call context_commit with a message describing what was done, what was decided, and any open questions. Include the current git branch and commit hash at the top of the message.
|
|
16
|
-
|
|
17
|
-
If you are about to explore a risky or experimental approach, call context_branch first to create an isolated context workspace.`;
|
|
18
|
-
const SYSTEM_PROMPT_FRAGMENT = `\
|
|
19
|
-
You have access to ContextGit memory tools.
|
|
20
|
-
|
|
21
|
-
## Session Start (do this every time)
|
|
22
|
-
Call context_get with scope=global immediately.
|
|
23
|
-
Do not ask questions first. Read the snapshot, then start working.
|
|
24
|
-
Start the highest priority item from the snapshot.
|
|
25
|
-
|
|
26
|
-
## What counts as one task (commit after each)
|
|
27
|
-
Match the grain of your plan:
|
|
28
|
-
- Numbered steps in a plan → each numbered step = one commit
|
|
29
|
-
- User stories → each accepted story = one commit
|
|
30
|
-
- No plan → each logical unit of change (one file, one feature, one fix) = one commit
|
|
31
|
-
|
|
32
|
-
Do NOT batch unrelated changes into one commit.
|
|
33
|
-
When in doubt, commit more often rather than less.
|
|
34
|
-
|
|
35
|
-
## After EVERY completed task
|
|
36
|
-
Immediately, without being asked:
|
|
37
|
-
\`\`\`
|
|
38
|
-
context_commit "what was built | key decisions | next task"
|
|
39
|
-
\`\`\`
|
|
40
|
-
Do not proceed to the next task until the current one is committed.
|
|
41
|
-
|
|
42
|
-
## When scope changes mid-session
|
|
43
|
-
1. Write a context_commit with replan: prefix BEFORE building new scope:
|
|
44
|
-
context_commit "replan: <what changed and why>"
|
|
45
|
-
2. Then build the new scope
|
|
46
|
-
3. Write a normal context_commit when done
|
|
47
|
-
|
|
48
|
-
## Session End (do this every time)
|
|
49
|
-
Call context_commit with:
|
|
50
|
-
- what was built
|
|
51
|
-
- key decisions and why
|
|
52
|
-
- open threads
|
|
53
|
-
- the first concrete task for the next session
|
|
54
|
-
`;
|
|
10
|
+
import { writeClaude, writeSkills } from '../lib/init-helpers.js';
|
|
55
11
|
export default class Init extends Command {
|
|
56
12
|
static description = 'Initialize ContextGit in this project';
|
|
57
13
|
static flags = {
|
|
@@ -71,7 +27,6 @@ export default class Init extends Command {
|
|
|
71
27
|
const cwd = process.cwd();
|
|
72
28
|
const configDir = join(cwd, '.contextgit');
|
|
73
29
|
const configPath = join(configDir, 'config.json');
|
|
74
|
-
const promptPath = join(configDir, 'system-prompt.md');
|
|
75
30
|
// True if the user explicitly passed --hooks or --no-hooks
|
|
76
31
|
const hooksExplicit = argv.some(a => String(a).startsWith('--hooks') || String(a) === '--no-hooks');
|
|
77
32
|
// ── Self-heal: config exists but DB may be empty ───────────────────────────
|
|
@@ -92,6 +47,15 @@ export default class Init extends Command {
|
|
|
92
47
|
installGitHooks(cwd);
|
|
93
48
|
this.log('Git hooks installed (.git/hooks/post-commit, post-checkout, post-merge)');
|
|
94
49
|
}
|
|
50
|
+
// Write CLAUDE.md + skills even on re-init (idempotent)
|
|
51
|
+
const claudeResult = writeClaude(cwd);
|
|
52
|
+
if (claudeResult.status === 'written') {
|
|
53
|
+
this.log(`✅ CLAUDE.md updated (contextgit memory section appended)`);
|
|
54
|
+
}
|
|
55
|
+
const skillsResult = writeSkills(cwd);
|
|
56
|
+
if (skillsResult.status === 'written') {
|
|
57
|
+
this.log(`✅ Skills installed (.claude/skills/context-commit, .claude/skills/context-branch)`);
|
|
58
|
+
}
|
|
95
59
|
this.log('ContextGit already initialized. Config found at .contextgit/config.json');
|
|
96
60
|
return;
|
|
97
61
|
}
|
|
@@ -103,9 +67,7 @@ export default class Init extends Command {
|
|
|
103
67
|
name: `Context: ${gitBranch}`,
|
|
104
68
|
gitBranch,
|
|
105
69
|
});
|
|
106
|
-
writeSystemPrompt(promptPath);
|
|
107
70
|
this.log(`Recreated project "${existing.project}" (${existing.projectId}) for branch: ${gitBranch}`);
|
|
108
|
-
this.log(`System prompt: .contextgit/system-prompt.md`);
|
|
109
71
|
if (flags.hooks) {
|
|
110
72
|
installGitHooks(cwd);
|
|
111
73
|
this.log('Git hooks installed (.git/hooks/post-commit, post-checkout, post-merge)');
|
|
@@ -135,12 +97,10 @@ export default class Init extends Command {
|
|
|
135
97
|
embeddingModel: 'local',
|
|
136
98
|
};
|
|
137
99
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
138
|
-
|
|
139
|
-
this.log(`
|
|
140
|
-
this.log(`
|
|
141
|
-
this.log(`Branch:
|
|
142
|
-
this.log(`Config: .contextgit/config.json`);
|
|
143
|
-
this.log(`DB: ~/.contextgit/projects/${projectId}.db`);
|
|
100
|
+
this.log(`✅ Project initialized (.contextgit.json)`);
|
|
101
|
+
this.log(` Project: ${projectName}`);
|
|
102
|
+
this.log(` ID: ${projectId}`);
|
|
103
|
+
this.log(` Branch: ${gitBranch}`);
|
|
144
104
|
this.log(``);
|
|
145
105
|
// BUG-3 fix: prompt for hooks unless user was explicit about it
|
|
146
106
|
let installHooks = flags.hooks;
|
|
@@ -149,66 +109,33 @@ export default class Init extends Command {
|
|
|
149
109
|
}
|
|
150
110
|
if (installHooks) {
|
|
151
111
|
installGitHooks(cwd);
|
|
152
|
-
this.log(
|
|
112
|
+
this.log(`✅ Git hooks installed (.git/hooks/post-commit, post-checkout, post-merge)`);
|
|
153
113
|
}
|
|
154
114
|
else {
|
|
155
|
-
this.log(
|
|
115
|
+
this.log(`⏭ Git hooks skipped (run "contextgit init --hooks" anytime to install)`);
|
|
156
116
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
const clients = detectClients();
|
|
163
|
-
if (clients.length === 0) {
|
|
164
|
-
this.log(`⚠️ No MCP clients detected.`);
|
|
165
|
-
this.log(``);
|
|
166
|
-
this.log(`Add the following to your MCP client config manually:`);
|
|
167
|
-
this.log(``);
|
|
168
|
-
this.log(` "contextgit": {`);
|
|
169
|
-
this.log(` "command": "npx",`);
|
|
170
|
-
this.log(` "args": ["contextgit", "mcp"],`);
|
|
171
|
-
this.log(` "systemPrompt": "${MCP_SYSTEM_PROMPT.replace(/\n/g, '\\n')}"`);
|
|
172
|
-
this.log(` }`);
|
|
173
|
-
this.log(``);
|
|
174
|
-
this.log(`Searched:`);
|
|
175
|
-
this.log(` ~/.claude.json`);
|
|
176
|
-
this.log(` ~/.cursor/mcp.json`);
|
|
177
|
-
this.log(` ~/Library/Application Support/Claude/claude_desktop_config.json`);
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
let anyInjected = false;
|
|
181
|
-
for (const client of clients) {
|
|
182
|
-
const result = injectMcpServer(client.path, client.type, MCP_SYSTEM_PROMPT);
|
|
183
|
-
const label = clientLabel(client.type).padEnd(14);
|
|
184
|
-
const shortPath = client.path.replace(process.env['HOME'] ?? '', '~');
|
|
185
|
-
if (result.status === 'injected') {
|
|
186
|
-
this.log(`✅ Configured ${label} (${shortPath})`);
|
|
187
|
-
anyInjected = true;
|
|
188
|
-
}
|
|
189
|
-
else if (result.status === 'already-present') {
|
|
190
|
-
this.log(`⏭ ${label} already configured (skipped)`);
|
|
191
|
-
}
|
|
192
|
-
else if (result.status === 'error') {
|
|
193
|
-
this.log(`❌ ${label} config error: ${result.reason}`);
|
|
194
|
-
this.log(` Path: ${shortPath}`);
|
|
195
|
-
this.log(` Fix manually or re-run after repairing the file.`);
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
this.log(`⏭ ${label} not found (skipped)`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
if (anyInjected) {
|
|
202
|
-
this.log(``);
|
|
203
|
-
this.log(`ContextGit is ready. Open Claude Code in this project and start a session.`);
|
|
204
|
-
this.log(`The agent will call context_get automatically on every session start.`);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
117
|
+
// ── Write CLAUDE.md fragment ───────────────────────────────────────────────
|
|
118
|
+
const claudeResult = writeClaude(cwd);
|
|
119
|
+
if (claudeResult.status === 'written') {
|
|
120
|
+
this.log(`✅ CLAUDE.md updated (contextgit memory section appended)`);
|
|
207
121
|
}
|
|
208
|
-
|
|
209
|
-
this.log(
|
|
210
|
-
this.log(`Add the MCP server entry manually — see .contextgit/system-prompt.md`);
|
|
122
|
+
else if (claudeResult.status === 'already-present') {
|
|
123
|
+
this.log(`⏭ CLAUDE.md already configured (skipped)`);
|
|
211
124
|
}
|
|
125
|
+
else {
|
|
126
|
+
this.log(`⚠️ CLAUDE.md not updated (${claudeResult.reason})`);
|
|
127
|
+
}
|
|
128
|
+
// ── Write project-level skills ─────────────────────────────────────────────
|
|
129
|
+
const skillsResult = writeSkills(cwd);
|
|
130
|
+
if (skillsResult.status === 'written') {
|
|
131
|
+
this.log(`✅ Skills installed (.claude/skills/context-commit, .claude/skills/context-branch)`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
this.log(`⚠️ Skills not installed (could not write to .claude/skills/ — create manually)`);
|
|
135
|
+
}
|
|
136
|
+
this.log(``);
|
|
137
|
+
this.log(`ContextGit is ready. Start a Claude Code session in this project.`);
|
|
138
|
+
this.log(`The agent will load project memory automatically via MCP tool discovery.`);
|
|
212
139
|
}
|
|
213
140
|
}
|
|
214
141
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
@@ -221,18 +148,6 @@ async function detectGitBranch(cwd) {
|
|
|
221
148
|
return 'main';
|
|
222
149
|
}
|
|
223
150
|
}
|
|
224
|
-
function writeSystemPrompt(promptPath) {
|
|
225
|
-
writeFileSync(promptPath, SYSTEM_PROMPT_FRAGMENT);
|
|
226
|
-
}
|
|
227
|
-
function clientLabel(type) {
|
|
228
|
-
if (type === 'claude-code')
|
|
229
|
-
return 'Claude Code';
|
|
230
|
-
if (type === 'cursor')
|
|
231
|
-
return 'Cursor';
|
|
232
|
-
if (type === 'claude-desktop')
|
|
233
|
-
return 'Claude Desktop';
|
|
234
|
-
return type;
|
|
235
|
-
}
|
|
236
151
|
/** Prompt the user with a yes/no question. Defaults to yes on empty input. */
|
|
237
152
|
function promptYesNo(question) {
|
|
238
153
|
return new Promise(resolve => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEjE,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAC,WAAW,GAAG,uCAAuC,CAAA;IAE5D,MAAM,CAAC,KAAK,GAAG;QACb,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;YACjB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,mDAAmD;YAChE,QAAQ,EAAE,KAAK;SAChB,CAAC;QACF,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;YACnB,WAAW,EAAE,+DAA+D;YAC5E,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,IAAI,EAAI,oDAAoD;SACtE,CAAC;KACH,CAAA;IAED,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;QACzB,MAAM,SAAS,GAAI,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;QAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;QACjD,2DAA2D;QAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,CAAA;QAEnG,8EAA8E;QAC9E,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,IAAI,QAA0B,CAAA;YAC9B,IAAI,CAAC;gBACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAqB,CAAA;YAC7E,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,KAAK,CAAC,kFAAkF,CAAC,CAAA;YAChG,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;YAChD,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,CAAA;YAC5C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;YAE5E,IAAI,MAAM,EAAE,CAAC;gBACX,oEAAoE;gBACpE,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAChB,eAAe,CAAC,GAAG,CAAC,CAAA;oBACpB,IAAI,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAA;gBACrF,CAAC;gBAED,wDAAwD;gBACxD,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;gBACrC,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBACtC,IAAI,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAA;gBACjF,CAAC;gBACD,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;gBACrC,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBACtC,IAAI,CAAC,GAAG,CAAC,+FAA+F,CAAC,CAAA;gBAC3G,CAAC;gBAED,IAAI,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAA;gBACnF,OAAM;YACR,CAAC;YAED,kDAAkD;YAClD,IAAI,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAA;YAC/E,MAAM,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;YAC7E,MAAM,KAAK,CAAC,YAAY,CAAC;gBACvB,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,IAAI,EAAE,YAAY,SAAS,EAAE;gBAC7B,SAAS;aACV,CAAC,CAAA;YACF,IAAI,CAAC,GAAG,CAAC,sBAAsB,QAAQ,CAAC,OAAO,MAAM,QAAQ,CAAC,SAAS,iBAAiB,SAAS,EAAE,CAAC,CAAA;YACpG,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAChB,eAAe,CAAC,GAAG,CAAC,CAAA;gBACpB,IAAI,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAA;YACrF,CAAC;YACD,OAAM;QACR,CAAC;QAED,8EAA8E;QAC9E,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAA;QAC/C,MAAM,SAAS,GAAG,MAAM,EAAE,CAAA;QAE1B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,SAAS,CAAC,CAAA;QACvC,MAAM,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAA;QAE/D,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,CAAA;QAC5C,MAAM,KAAK,CAAC,YAAY,CAAC;YACvB,SAAS;YACT,IAAI,EAAE,YAAY,SAAS,EAAE;YAC7B,SAAS;SACV,CAAC,CAAA;QAEF,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACzC,MAAM,MAAM,GAAqB;YAC/B,OAAO,EAAE,WAAW;YACpB,SAAS;YACT,KAAK,EAAE,OAAO;YACd,SAAS,EAAE,MAAM;YACjB,YAAY,EAAE,aAAa;YAC3B,YAAY,EAAE,KAAK;YACnB,gBAAgB,EAAE,EAAE;YACpB,cAAc,EAAE,OAAO;SACxB,CAAA;QACD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;QAEjE,IAAI,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAA;QAC7D,IAAI,CAAC,GAAG,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAA;QACvC,IAAI,CAAC,GAAG,CAAC,gBAAgB,SAAS,EAAE,CAAC,CAAA;QACrC,IAAI,CAAC,GAAG,CAAC,gBAAgB,SAAS,EAAE,CAAC,CAAA;QACrC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAEZ,gEAAgE;QAChE,IAAI,YAAY,GAAG,KAAK,CAAC,KAAK,CAAA;QAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,YAAY,GAAG,MAAM,WAAW,CAC9B,uEAAuE,CACxE,CAAA;QACH,CAAC;QAED,IAAI,YAAY,EAAE,CAAC;YACjB,eAAe,CAAC,GAAG,CAAC,CAAA;YACpB,IAAI,CAAC,GAAG,CAAC,oFAAoF,CAAC,CAAA;QAChG,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,mFAAmF,CAAC,CAAA;QAC/F,CAAC;QAED,8EAA8E;QAC9E,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;QACrC,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAA;QACjF,CAAC;aAAM,IAAI,YAAY,CAAC,MAAM,KAAK,iBAAiB,EAAE,CAAC;YACrD,IAAI,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;QACvD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,qCAAqC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAA;QACvE,CAAC;QAED,8EAA8E;QAC9E,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;QACrC,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,+FAA+F,CAAC,CAAA;QAC3G,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,wFAAwF,CAAC,CAAA;QACpG,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACZ,IAAI,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAA;QAC7E,IAAI,CAAC,GAAG,CAAC,0EAA0E,CAAC,CAAA;IACtF,CAAC;;AAGH,iFAAiF;AAEjF,KAAK,UAAU,eAAe,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;QAC1B,OAAO,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAA;IACf,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,SAAS,WAAW,CAAC,QAAgB;IACnC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QAC3B,iEAAiE;QACjE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,CAAA;YACb,OAAM;QACR,CAAC;QACD,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;QAC5E,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;YAC7B,EAAE,CAAC,KAAK,EAAE,CAAA;YACV,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -1,19 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export interface DetectedClient {
|
|
3
|
-
type: ClientType;
|
|
4
|
-
path: string;
|
|
5
|
-
}
|
|
6
|
-
export interface InjectionResult {
|
|
7
|
-
status: 'injected' | 'already-present' | 'skipped' | 'error';
|
|
8
|
-
reason?: string;
|
|
9
|
-
}
|
|
10
|
-
/** Return all MCP clients whose config file exists on disk. */
|
|
11
|
-
export declare function detectClients(home?: string): DetectedClient[];
|
|
12
|
-
/** Check whether a contextgit entry already exists under mcpServers. */
|
|
13
|
-
export declare function isAlreadyInjected(config: Record<string, unknown>): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Inject the contextgit MCP server entry into the given client config file.
|
|
16
|
-
* Uses an atomic write (temp file + rename) so the original is never corrupted.
|
|
17
|
-
*/
|
|
18
|
-
export declare function injectMcpServer(configPath: string, _clientType: ClientType, systemPrompt: string): InjectionResult;
|
|
1
|
+
export {};
|
|
19
2
|
//# sourceMappingURL=client-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-config.d.ts","sourceRoot":"","sources":["../../src/lib/client-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-config.d.ts","sourceRoot":"","sources":["../../src/lib/client-config.ts"],"names":[],"mappings":""}
|
|
@@ -1,74 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import { homedir } from 'os';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
const MCP_ENTRY = {
|
|
5
|
-
command: 'npx',
|
|
6
|
-
args: ['contextgit-mcp'],
|
|
7
|
-
};
|
|
8
|
-
/** Resolve known config paths for each client type. */
|
|
9
|
-
function clientPaths(home) {
|
|
10
|
-
const appData = process.env['APPDATA'] ?? '';
|
|
11
|
-
return {
|
|
12
|
-
'claude-code': join(home, '.claude.json'),
|
|
13
|
-
'cursor': join(home, '.cursor', 'mcp.json'),
|
|
14
|
-
'claude-desktop': process.platform === 'win32'
|
|
15
|
-
? join(appData, 'Claude', 'claude_desktop_config.json')
|
|
16
|
-
: join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
/** Return all MCP clients whose config file exists on disk. */
|
|
20
|
-
export function detectClients(home = homedir()) {
|
|
21
|
-
const paths = clientPaths(home);
|
|
22
|
-
return Object.keys(paths)
|
|
23
|
-
.filter(type => existsSync(paths[type]))
|
|
24
|
-
.map(type => ({ type, path: paths[type] }));
|
|
25
|
-
}
|
|
26
|
-
/** Check whether a contextgit entry already exists under mcpServers. */
|
|
27
|
-
export function isAlreadyInjected(config) {
|
|
28
|
-
const servers = config['mcpServers'] ?? config['globalShortcuts']?.['mcpServers'];
|
|
29
|
-
if (!servers || typeof servers !== 'object')
|
|
30
|
-
return false;
|
|
31
|
-
return 'contextgit' in servers;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Inject the contextgit MCP server entry into the given client config file.
|
|
35
|
-
* Uses an atomic write (temp file + rename) so the original is never corrupted.
|
|
36
|
-
*/
|
|
37
|
-
export function injectMcpServer(configPath, _clientType, systemPrompt) {
|
|
38
|
-
// Read existing content — create empty object if file doesn't exist
|
|
39
|
-
let raw = '{}';
|
|
40
|
-
if (existsSync(configPath)) {
|
|
41
|
-
raw = readFileSync(configPath, 'utf8');
|
|
42
|
-
}
|
|
43
|
-
let config;
|
|
44
|
-
try {
|
|
45
|
-
config = JSON.parse(raw);
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
return {
|
|
49
|
-
status: 'error',
|
|
50
|
-
reason: 'existing config is not valid JSON — skipped to avoid data loss',
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
if (isAlreadyInjected(config)) {
|
|
54
|
-
return { status: 'already-present' };
|
|
55
|
-
}
|
|
56
|
-
// Resolve the mcpServers object — handle Claude Desktop's globalShortcuts wrapper
|
|
57
|
-
let target;
|
|
58
|
-
if (config['globalShortcuts'] &&
|
|
59
|
-
typeof config['globalShortcuts'] === 'object' &&
|
|
60
|
-
'mcpServers' in config['globalShortcuts']) {
|
|
61
|
-
target = config['globalShortcuts']['mcpServers'];
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
if (!config['mcpServers'])
|
|
65
|
-
config['mcpServers'] = {};
|
|
66
|
-
target = config['mcpServers'];
|
|
67
|
-
}
|
|
68
|
-
target['contextgit'] = { ...MCP_ENTRY, systemPrompt };
|
|
69
|
-
const tmpPath = configPath + '.contextgit-tmp';
|
|
70
|
-
writeFileSync(tmpPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
71
|
-
renameSync(tmpPath, configPath);
|
|
72
|
-
return { status: 'injected' };
|
|
73
|
-
}
|
|
1
|
+
export {};
|
|
74
2
|
//# sourceMappingURL=client-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-config.js","sourceRoot":"","sources":["../../src/lib/client-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-config.js","sourceRoot":"","sources":["../../src/lib/client-config.ts"],"names":[],"mappings":""}
|
|
@@ -1,97 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import { mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from 'fs';
|
|
3
|
-
import { tmpdir } from 'os';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
import { detectClients, injectMcpServer, isAlreadyInjected } from './client-config.js';
|
|
6
|
-
const SYSTEM_PROMPT = 'test system prompt';
|
|
7
|
-
let tmpDir;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
tmpDir = mkdtempSync(join(tmpdir(), 'contextgit-test-'));
|
|
10
|
-
});
|
|
11
|
-
afterEach(() => {
|
|
12
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
13
|
-
});
|
|
14
|
-
// 1. detectClients returns empty array when no config files exist
|
|
15
|
-
it('detectClients returns empty array when no config files exist', () => {
|
|
16
|
-
const result = detectClients(tmpDir);
|
|
17
|
-
expect(result).toEqual([]);
|
|
18
|
-
});
|
|
19
|
-
// 2. detectClients returns Claude Code entry when ~/.claude.json exists
|
|
20
|
-
it('detectClients returns claude-code when .claude.json exists', () => {
|
|
21
|
-
writeFileSync(join(tmpDir, '.claude.json'), '{}');
|
|
22
|
-
const result = detectClients(tmpDir);
|
|
23
|
-
expect(result).toHaveLength(1);
|
|
24
|
-
expect(result[0].type).toBe('claude-code');
|
|
25
|
-
expect(result[0].path).toBe(join(tmpDir, '.claude.json'));
|
|
26
|
-
});
|
|
27
|
-
// 3. injectMcpServer writes correct JSON structure to a new empty config file
|
|
28
|
-
it('injectMcpServer writes correct JSON to a new empty config file', () => {
|
|
29
|
-
const configPath = join(tmpDir, '.claude.json');
|
|
30
|
-
// file does not exist yet
|
|
31
|
-
const result = injectMcpServer(configPath, 'claude-code', SYSTEM_PROMPT);
|
|
32
|
-
expect(result.status).toBe('injected');
|
|
33
|
-
const written = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
34
|
-
const servers = written['mcpServers'];
|
|
35
|
-
expect(servers).toBeDefined();
|
|
36
|
-
const entry = servers['contextgit'];
|
|
37
|
-
expect(entry['command']).toBe('npx');
|
|
38
|
-
expect(entry['args']).toEqual(['contextgit', 'mcp']);
|
|
39
|
-
expect(entry['systemPrompt']).toBe(SYSTEM_PROMPT);
|
|
40
|
-
});
|
|
41
|
-
// 4. injectMcpServer merges into existing config without touching other keys
|
|
42
|
-
it('injectMcpServer merges without touching other keys', () => {
|
|
43
|
-
const configPath = join(tmpDir, '.claude.json');
|
|
44
|
-
writeFileSync(configPath, JSON.stringify({
|
|
45
|
-
someOtherKey: 'keep-me',
|
|
46
|
-
mcpServers: { 'other-server': { command: 'npx', args: ['other'] } },
|
|
47
|
-
}));
|
|
48
|
-
const result = injectMcpServer(configPath, 'claude-code', SYSTEM_PROMPT);
|
|
49
|
-
expect(result.status).toBe('injected');
|
|
50
|
-
const written = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
51
|
-
expect(written['someOtherKey']).toBe('keep-me');
|
|
52
|
-
const servers = written['mcpServers'];
|
|
53
|
-
expect(servers['other-server']).toBeDefined();
|
|
54
|
-
expect(servers['contextgit']).toBeDefined();
|
|
55
|
-
});
|
|
56
|
-
// 5. injectMcpServer returns already-present if contextgit key exists
|
|
57
|
-
it('injectMcpServer returns already-present if contextgit exists', () => {
|
|
58
|
-
const configPath = join(tmpDir, '.claude.json');
|
|
59
|
-
writeFileSync(configPath, JSON.stringify({
|
|
60
|
-
mcpServers: { contextgit: { command: 'npx', args: ['contextgit', 'mcp'] } },
|
|
61
|
-
}));
|
|
62
|
-
const result = injectMcpServer(configPath, 'claude-code', SYSTEM_PROMPT);
|
|
63
|
-
expect(result.status).toBe('already-present');
|
|
64
|
-
});
|
|
65
|
-
// 6. injectMcpServer returns error and does not write if existing file is invalid JSON
|
|
66
|
-
it('injectMcpServer returns error and does not write if file is invalid JSON', () => {
|
|
67
|
-
const configPath = join(tmpDir, '.claude.json');
|
|
68
|
-
writeFileSync(configPath, 'NOT JSON {{{');
|
|
69
|
-
const originalContent = readFileSync(configPath, 'utf8');
|
|
70
|
-
const result = injectMcpServer(configPath, 'claude-code', SYSTEM_PROMPT);
|
|
71
|
-
expect(result.status).toBe('error');
|
|
72
|
-
expect(result.reason).toContain('not valid JSON');
|
|
73
|
-
// File must not have been overwritten
|
|
74
|
-
expect(readFileSync(configPath, 'utf8')).toBe(originalContent);
|
|
75
|
-
});
|
|
76
|
-
// 7. injectMcpServer uses atomic write (temp file + rename)
|
|
77
|
-
it('injectMcpServer cleans up temp file after write', () => {
|
|
78
|
-
const configPath = join(tmpDir, '.claude.json');
|
|
79
|
-
injectMcpServer(configPath, 'claude-code', SYSTEM_PROMPT);
|
|
80
|
-
// Temp file should not exist after successful rename
|
|
81
|
-
expect(existsSync(configPath + '.contextgit-tmp')).toBe(false);
|
|
82
|
-
// Final file should exist
|
|
83
|
-
expect(existsSync(configPath)).toBe(true);
|
|
84
|
-
});
|
|
85
|
-
// 8. isAlreadyInjected returns true when contextgit is present under mcpServers
|
|
86
|
-
describe('isAlreadyInjected', () => {
|
|
87
|
-
it('returns true when contextgit is under mcpServers', () => {
|
|
88
|
-
expect(isAlreadyInjected({ mcpServers: { contextgit: {} } })).toBe(true);
|
|
89
|
-
});
|
|
90
|
-
it('returns false when contextgit is absent', () => {
|
|
91
|
-
expect(isAlreadyInjected({ mcpServers: { other: {} } })).toBe(false);
|
|
92
|
-
});
|
|
93
|
-
it('returns false when mcpServers is missing', () => {
|
|
94
|
-
expect(isAlreadyInjected({})).toBe(false);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
1
|
+
export {};
|
|
97
2
|
//# sourceMappingURL=client-config.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-config.test.js","sourceRoot":"","sources":["../../src/lib/client-config.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-config.test.js","sourceRoot":"","sources":["../../src/lib/client-config.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const CLAUDE_MD_SENTINEL_START = "<!-- contextgit:start -->";
|
|
2
|
+
export declare const CLAUDE_MD_SENTINEL_END = "<!-- contextgit:end -->";
|
|
3
|
+
export declare const CLAUDE_MD_FRAGMENT = "\n<!-- contextgit:start -->\n## ContextGit Memory\n\nThis project uses ContextGit for persistent AI memory across sessions.\n\n**Session start:** Call `project_memory_load` (or `context_get`) immediately \u2014 before reading files, before asking questions, before doing any work. This loads the full project state: what was built, what was decided, active tasks, and open questions.\n\n**After significant work:** Call `project_memory_save` (or `context_commit`) with a structured message:\n- One-line summary of what was done\n- What was decided and why\n- What was built (files changed, approach taken)\n- Open questions\n- Git branch and commit hash\n\n**Before risky exploration:** Call `project_memory_branch` (or `context_branch`) to create an isolated context workspace.\n\n**Before starting a task:** Call `project_task_claim` (or `context_claim`) to prevent other agents from duplicating your work.\n\nDo not skip these steps. The next session starts blind without them.\n<!-- contextgit:end -->\n";
|
|
4
|
+
/**
|
|
5
|
+
* Write the ContextGit CLAUDE.md fragment into the given directory.
|
|
6
|
+
* Idempotent: skips if sentinel already present.
|
|
7
|
+
* @returns 'written' | 'already-present' | 'error'
|
|
8
|
+
*/
|
|
9
|
+
export declare function writeClaude(projectDir: string): {
|
|
10
|
+
status: 'written' | 'already-present' | 'error';
|
|
11
|
+
reason?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const CONTEXT_COMMIT_SKILL = "---\nname: context-commit\ndescription: \"Save project memory after completing work. Use this skill whenever you have just finished implementing a feature, resolved a bug or blocker, made an architectural decision, closed a thread, completed a code review, or are about to end the session. Also trigger when you see signals like 'that's working', 'task complete', 'let's move on', 'I'm done', or after completing a git commit. IMPORTANT: Always use this skill before ending a session or moving to the next task \u2014 skipping it means the next session starts blind.\"\n---\n\n# ContextGit \u2014 Context Commit Discipline\n\n## When to commit context\n\nCall `project_memory_save` (MCP tool) after:\n- Completing a feature or task (before moving to the next)\n- Making an architectural decision or choosing between options\n- Resolving a bug, blocker, or open question\n- Closing a thread\n- Before ending the session\n\n## What makes a good commit message\n\nA context commit message is a future-you briefing. Write it so the next agent session (or the next developer) can pick up exactly where this one left off.\n\nStructure:\n```\n<one-line summary of what was done>\n\nWhat was decided: <the decision and why>\nWhat was built: <files changed, approach taken>\nOpen questions: <anything unresolved>\nGit: <branch> | <commit hash if available>\n```\n\nExample:\n```\nImplemented optimistic locking via CAS on branches table\n\nWhat was decided: CAS with 3-attempt retry + jitter over queue-based serialization.\nQueue deferred until high-conflict multi-agent scale. COMMIT_CONFLICT error type added.\nWhat was built: store/src/local/queries.ts (version column), store/src/local/index.ts (retry logic), core/src/types.ts (COMMIT_CONFLICT)\nOpen questions: TTL behavior under high contention not yet load-tested.\nGit: feat/phase2-delta1 | a3f9c12\n```\n\n## How to call it\n\nUse the `project_memory_save` MCP tool (alias: `context_commit`). Pass the full message as the `message` argument.\n\nDo not skip this step when the work feels small. Small decisions compound. The next session starts blind without them.\n";
|
|
14
|
+
export declare const CONTEXT_BRANCH_SKILL = "---\nname: context-branch\ndescription: \"Create an isolated context branch before risky or experimental work. Use this skill when the agent is about to explore something uncertain, experimental, or potentially breaking \u2014 trying an approach that might not work, refactoring something risky, exploring an architectural alternative, or doing anything that should be isolatable and reversible. Triggers on: 'let me try', 'what if we', 'I want to explore', 'let's experiment', 'alternative approach', or any phrasing that signals exploration rather than execution.\"\n---\n\n# ContextGit \u2014 Context Branch Discipline\n\n## When to branch context\n\nCall `project_memory_branch` (MCP tool) before:\n- Trying an approach you're not sure will work\n- Refactoring something that touches many files\n- Exploring an architectural alternative to the current plan\n- Doing anything you'd want to be able to roll back semantically (not just via git)\n\n## Why this matters\n\nA context branch creates an isolated snapshot workspace. If the exploration fails, you can return to the main branch context without polluting the session history with dead-end decisions.\n\nIt's cheap. It takes one tool call. The cost of not doing it is re-explaining to the next session why you abandoned the approach you just spent an hour on.\n\n## How to call it\n\nUse the `project_memory_branch` MCP tool (alias: `context_branch`). Pass a short descriptive name:\n\n```\nproject_memory_branch name=\"explore-queue-based-concurrency\"\n```\n\nWhen the exploration concludes:\n- If it worked: `project_memory_save` your findings and merge back\n- If it failed: `project_memory_save` a brief note (\"explored X, abandoned because Y\") and switch back to main branch\n\nThe failure note is as valuable as the success note. The next session needs to know not to try the same dead end.\n";
|
|
15
|
+
/**
|
|
16
|
+
* Write the context-commit and context-branch skills into <projectDir>/.claude/skills/.
|
|
17
|
+
* Overwrites if already present (these files are managed by contextgit).
|
|
18
|
+
* @returns 'written' | 'error'
|
|
19
|
+
*/
|
|
20
|
+
export declare function writeSkills(projectDir: string): {
|
|
21
|
+
status: 'written' | 'error';
|
|
22
|
+
reason?: string;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=init-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/init-helpers.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,wBAAwB,8BAA8B,CAAA;AACnE,eAAO,MAAM,sBAAsB,4BAA4B,CAAA;AAE/D,eAAO,MAAM,kBAAkB,o/BAqB9B,CAAA;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,GACjB;IAAE,MAAM,EAAE,SAAS,GAAG,iBAAiB,GAAG,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAgBtE;AAID,eAAO,MAAM,oBAAoB,0kEA8ChC,CAAA;AAED,eAAO,MAAM,oBAAoB,y0DAkChC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,GACjB;IAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAYlD"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// init-helpers.ts — testable helpers for contextgit init
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
// ── CLAUDE.md ─────────────────────────────────────────────────────────────────
|
|
5
|
+
export const CLAUDE_MD_SENTINEL_START = '<!-- contextgit:start -->';
|
|
6
|
+
export const CLAUDE_MD_SENTINEL_END = '<!-- contextgit:end -->';
|
|
7
|
+
export const CLAUDE_MD_FRAGMENT = `
|
|
8
|
+
<!-- contextgit:start -->
|
|
9
|
+
## ContextGit Memory
|
|
10
|
+
|
|
11
|
+
This project uses ContextGit for persistent AI memory across sessions.
|
|
12
|
+
|
|
13
|
+
**Session start:** Call \`project_memory_load\` (or \`context_get\`) immediately — before reading files, before asking questions, before doing any work. This loads the full project state: what was built, what was decided, active tasks, and open questions.
|
|
14
|
+
|
|
15
|
+
**After significant work:** Call \`project_memory_save\` (or \`context_commit\`) with a structured message:
|
|
16
|
+
- One-line summary of what was done
|
|
17
|
+
- What was decided and why
|
|
18
|
+
- What was built (files changed, approach taken)
|
|
19
|
+
- Open questions
|
|
20
|
+
- Git branch and commit hash
|
|
21
|
+
|
|
22
|
+
**Before risky exploration:** Call \`project_memory_branch\` (or \`context_branch\`) to create an isolated context workspace.
|
|
23
|
+
|
|
24
|
+
**Before starting a task:** Call \`project_task_claim\` (or \`context_claim\`) to prevent other agents from duplicating your work.
|
|
25
|
+
|
|
26
|
+
Do not skip these steps. The next session starts blind without them.
|
|
27
|
+
<!-- contextgit:end -->
|
|
28
|
+
`;
|
|
29
|
+
/**
|
|
30
|
+
* Write the ContextGit CLAUDE.md fragment into the given directory.
|
|
31
|
+
* Idempotent: skips if sentinel already present.
|
|
32
|
+
* @returns 'written' | 'already-present' | 'error'
|
|
33
|
+
*/
|
|
34
|
+
export function writeClaude(projectDir) {
|
|
35
|
+
const claudePath = join(projectDir, 'CLAUDE.md');
|
|
36
|
+
try {
|
|
37
|
+
if (existsSync(claudePath)) {
|
|
38
|
+
const content = readFileSync(claudePath, 'utf8');
|
|
39
|
+
if (content.includes(CLAUDE_MD_SENTINEL_START)) {
|
|
40
|
+
return { status: 'already-present' };
|
|
41
|
+
}
|
|
42
|
+
writeFileSync(claudePath, content + CLAUDE_MD_FRAGMENT);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
writeFileSync(claudePath, CLAUDE_MD_FRAGMENT.trimStart());
|
|
46
|
+
}
|
|
47
|
+
return { status: 'written' };
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
return { status: 'error', reason: String(err) };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// ── Skills ────────────────────────────────────────────────────────────────────
|
|
54
|
+
export const CONTEXT_COMMIT_SKILL = `---
|
|
55
|
+
name: context-commit
|
|
56
|
+
description: "Save project memory after completing work. Use this skill whenever you have just finished implementing a feature, resolved a bug or blocker, made an architectural decision, closed a thread, completed a code review, or are about to end the session. Also trigger when you see signals like 'that's working', 'task complete', 'let's move on', 'I'm done', or after completing a git commit. IMPORTANT: Always use this skill before ending a session or moving to the next task — skipping it means the next session starts blind."
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
# ContextGit — Context Commit Discipline
|
|
60
|
+
|
|
61
|
+
## When to commit context
|
|
62
|
+
|
|
63
|
+
Call \`project_memory_save\` (MCP tool) after:
|
|
64
|
+
- Completing a feature or task (before moving to the next)
|
|
65
|
+
- Making an architectural decision or choosing between options
|
|
66
|
+
- Resolving a bug, blocker, or open question
|
|
67
|
+
- Closing a thread
|
|
68
|
+
- Before ending the session
|
|
69
|
+
|
|
70
|
+
## What makes a good commit message
|
|
71
|
+
|
|
72
|
+
A context commit message is a future-you briefing. Write it so the next agent session (or the next developer) can pick up exactly where this one left off.
|
|
73
|
+
|
|
74
|
+
Structure:
|
|
75
|
+
\`\`\`
|
|
76
|
+
<one-line summary of what was done>
|
|
77
|
+
|
|
78
|
+
What was decided: <the decision and why>
|
|
79
|
+
What was built: <files changed, approach taken>
|
|
80
|
+
Open questions: <anything unresolved>
|
|
81
|
+
Git: <branch> | <commit hash if available>
|
|
82
|
+
\`\`\`
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
\`\`\`
|
|
86
|
+
Implemented optimistic locking via CAS on branches table
|
|
87
|
+
|
|
88
|
+
What was decided: CAS with 3-attempt retry + jitter over queue-based serialization.
|
|
89
|
+
Queue deferred until high-conflict multi-agent scale. COMMIT_CONFLICT error type added.
|
|
90
|
+
What was built: store/src/local/queries.ts (version column), store/src/local/index.ts (retry logic), core/src/types.ts (COMMIT_CONFLICT)
|
|
91
|
+
Open questions: TTL behavior under high contention not yet load-tested.
|
|
92
|
+
Git: feat/phase2-delta1 | a3f9c12
|
|
93
|
+
\`\`\`
|
|
94
|
+
|
|
95
|
+
## How to call it
|
|
96
|
+
|
|
97
|
+
Use the \`project_memory_save\` MCP tool (alias: \`context_commit\`). Pass the full message as the \`message\` argument.
|
|
98
|
+
|
|
99
|
+
Do not skip this step when the work feels small. Small decisions compound. The next session starts blind without them.
|
|
100
|
+
`;
|
|
101
|
+
export const CONTEXT_BRANCH_SKILL = `---
|
|
102
|
+
name: context-branch
|
|
103
|
+
description: "Create an isolated context branch before risky or experimental work. Use this skill when the agent is about to explore something uncertain, experimental, or potentially breaking — trying an approach that might not work, refactoring something risky, exploring an architectural alternative, or doing anything that should be isolatable and reversible. Triggers on: 'let me try', 'what if we', 'I want to explore', 'let's experiment', 'alternative approach', or any phrasing that signals exploration rather than execution."
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
# ContextGit — Context Branch Discipline
|
|
107
|
+
|
|
108
|
+
## When to branch context
|
|
109
|
+
|
|
110
|
+
Call \`project_memory_branch\` (MCP tool) before:
|
|
111
|
+
- Trying an approach you're not sure will work
|
|
112
|
+
- Refactoring something that touches many files
|
|
113
|
+
- Exploring an architectural alternative to the current plan
|
|
114
|
+
- Doing anything you'd want to be able to roll back semantically (not just via git)
|
|
115
|
+
|
|
116
|
+
## Why this matters
|
|
117
|
+
|
|
118
|
+
A context branch creates an isolated snapshot workspace. If the exploration fails, you can return to the main branch context without polluting the session history with dead-end decisions.
|
|
119
|
+
|
|
120
|
+
It's cheap. It takes one tool call. The cost of not doing it is re-explaining to the next session why you abandoned the approach you just spent an hour on.
|
|
121
|
+
|
|
122
|
+
## How to call it
|
|
123
|
+
|
|
124
|
+
Use the \`project_memory_branch\` MCP tool (alias: \`context_branch\`). Pass a short descriptive name:
|
|
125
|
+
|
|
126
|
+
\`\`\`
|
|
127
|
+
project_memory_branch name="explore-queue-based-concurrency"
|
|
128
|
+
\`\`\`
|
|
129
|
+
|
|
130
|
+
When the exploration concludes:
|
|
131
|
+
- If it worked: \`project_memory_save\` your findings and merge back
|
|
132
|
+
- If it failed: \`project_memory_save\` a brief note ("explored X, abandoned because Y") and switch back to main branch
|
|
133
|
+
|
|
134
|
+
The failure note is as valuable as the success note. The next session needs to know not to try the same dead end.
|
|
135
|
+
`;
|
|
136
|
+
/**
|
|
137
|
+
* Write the context-commit and context-branch skills into <projectDir>/.claude/skills/.
|
|
138
|
+
* Overwrites if already present (these files are managed by contextgit).
|
|
139
|
+
* @returns 'written' | 'error'
|
|
140
|
+
*/
|
|
141
|
+
export function writeSkills(projectDir) {
|
|
142
|
+
try {
|
|
143
|
+
const commitDir = join(projectDir, '.claude', 'skills', 'context-commit');
|
|
144
|
+
const branchDir = join(projectDir, '.claude', 'skills', 'context-branch');
|
|
145
|
+
mkdirSync(commitDir, { recursive: true });
|
|
146
|
+
mkdirSync(branchDir, { recursive: true });
|
|
147
|
+
writeFileSync(join(commitDir, 'SKILL.md'), CONTEXT_COMMIT_SKILL);
|
|
148
|
+
writeFileSync(join(branchDir, 'SKILL.md'), CONTEXT_BRANCH_SKILL);
|
|
149
|
+
return { status: 'written' };
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
return { status: 'error', reason: String(err) };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=init-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-helpers.js","sourceRoot":"","sources":["../../src/lib/init-helpers.ts"],"names":[],"mappings":"AAAA,yDAAyD;AAEzD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AACvE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,iFAAiF;AAEjF,MAAM,CAAC,MAAM,wBAAwB,GAAG,2BAA2B,CAAA;AACnE,MAAM,CAAC,MAAM,sBAAsB,GAAG,yBAAyB,CAAA;AAE/D,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBjC,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,UAAkB;IAElB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;IAChD,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;YAChD,IAAI,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;gBAC/C,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAA;YACtC,CAAC;YACD,aAAa,CAAC,UAAU,EAAE,OAAO,GAAG,kBAAkB,CAAC,CAAA;QACzD,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,UAAU,EAAE,kBAAkB,CAAC,SAAS,EAAE,CAAC,CAAA;QAC3D,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAA;IACjD,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CnC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCnC,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,UAAkB;IAElB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAA;QACzE,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAA;QACzE,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACzC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACzC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,oBAAoB,CAAC,CAAA;QAChE,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,oBAAoB,CAAC,CAAA;QAChE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAA;IACjD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-helpers.test.d.ts","sourceRoot":"","sources":["../../src/lib/init-helpers.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { writeClaude, writeSkills, CLAUDE_MD_SENTINEL_START, CLAUDE_MD_SENTINEL_END, } from './init-helpers.js';
|
|
6
|
+
let tmpDir;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'contextgit-init-test-'));
|
|
9
|
+
});
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
12
|
+
});
|
|
13
|
+
// ── writeClaude ───────────────────────────────────────────────────────────────
|
|
14
|
+
describe('writeClaude', () => {
|
|
15
|
+
it('creates CLAUDE.md with sentinel when file does not exist', () => {
|
|
16
|
+
const result = writeClaude(tmpDir);
|
|
17
|
+
expect(result.status).toBe('written');
|
|
18
|
+
const content = readFileSync(join(tmpDir, 'CLAUDE.md'), 'utf8');
|
|
19
|
+
expect(content).toContain(CLAUDE_MD_SENTINEL_START);
|
|
20
|
+
expect(content).toContain(CLAUDE_MD_SENTINEL_END);
|
|
21
|
+
expect(content).toContain('project_memory_load');
|
|
22
|
+
});
|
|
23
|
+
it('appends sentinel to existing CLAUDE.md', () => {
|
|
24
|
+
const claudePath = join(tmpDir, 'CLAUDE.md');
|
|
25
|
+
writeFileSync(claudePath, '# My Project\n\nExisting content.\n');
|
|
26
|
+
const result = writeClaude(tmpDir);
|
|
27
|
+
expect(result.status).toBe('written');
|
|
28
|
+
const content = readFileSync(claudePath, 'utf8');
|
|
29
|
+
expect(content).toContain('# My Project');
|
|
30
|
+
expect(content).toContain('Existing content.');
|
|
31
|
+
expect(content).toContain(CLAUDE_MD_SENTINEL_START);
|
|
32
|
+
});
|
|
33
|
+
it('is idempotent — skips if sentinel already present', () => {
|
|
34
|
+
const claudePath = join(tmpDir, 'CLAUDE.md');
|
|
35
|
+
writeClaude(tmpDir); // first call
|
|
36
|
+
const afterFirst = readFileSync(claudePath, 'utf8');
|
|
37
|
+
writeClaude(tmpDir); // second call
|
|
38
|
+
const afterSecond = readFileSync(claudePath, 'utf8');
|
|
39
|
+
expect(afterSecond).toBe(afterFirst); // no change
|
|
40
|
+
// sentinel appears exactly once
|
|
41
|
+
const occurrences = afterSecond.split(CLAUDE_MD_SENTINEL_START).length - 1;
|
|
42
|
+
expect(occurrences).toBe(1);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
// ── writeSkills ───────────────────────────────────────────────────────────────
|
|
46
|
+
describe('writeSkills', () => {
|
|
47
|
+
it('creates both skill files under .claude/skills/', () => {
|
|
48
|
+
const result = writeSkills(tmpDir);
|
|
49
|
+
expect(result.status).toBe('written');
|
|
50
|
+
const commitSkill = join(tmpDir, '.claude', 'skills', 'context-commit', 'SKILL.md');
|
|
51
|
+
const branchSkill = join(tmpDir, '.claude', 'skills', 'context-branch', 'SKILL.md');
|
|
52
|
+
expect(existsSync(commitSkill)).toBe(true);
|
|
53
|
+
expect(existsSync(branchSkill)).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
it('context-commit skill contains correct name frontmatter', () => {
|
|
56
|
+
writeSkills(tmpDir);
|
|
57
|
+
const content = readFileSync(join(tmpDir, '.claude', 'skills', 'context-commit', 'SKILL.md'), 'utf8');
|
|
58
|
+
expect(content).toContain('name: context-commit');
|
|
59
|
+
expect(content).toContain('project_memory_save');
|
|
60
|
+
});
|
|
61
|
+
it('context-branch skill contains correct name frontmatter', () => {
|
|
62
|
+
writeSkills(tmpDir);
|
|
63
|
+
const content = readFileSync(join(tmpDir, '.claude', 'skills', 'context-branch', 'SKILL.md'), 'utf8');
|
|
64
|
+
expect(content).toContain('name: context-branch');
|
|
65
|
+
expect(content).toContain('project_memory_branch');
|
|
66
|
+
});
|
|
67
|
+
it('overwrites existing skill files on repeated calls', () => {
|
|
68
|
+
writeSkills(tmpDir); // first call
|
|
69
|
+
const result = writeSkills(tmpDir); // second call
|
|
70
|
+
expect(result.status).toBe('written');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=init-helpers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-helpers.test.js","sourceRoot":"","sources":["../../src/lib/init-helpers.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contextgit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"contextgit": "./bin/run.js"
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"typecheck": "tsc --noEmit"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@contextgit/core": "0.0.
|
|
23
|
-
"@contextgit/store": "0.0.
|
|
24
|
-
"@contextgit/api": "0.0.
|
|
22
|
+
"@contextgit/core": "0.0.11",
|
|
23
|
+
"@contextgit/store": "0.0.11",
|
|
24
|
+
"@contextgit/api": "0.0.11",
|
|
25
25
|
"@oclif/core": "^3.27.0",
|
|
26
26
|
"nanoid": "^5.0.0",
|
|
27
27
|
"simple-git": "^3.27.0"
|