context-stash 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mark Taylor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,442 @@
1
+ # context-stash
2
+
3
+ A workspace-scoped MCP server that provides a durable, Git-native memory layer for AI coding agents.
4
+
5
+ > **The missing piece in AI-assisted software development**: Give AI agents persistent memory of *why* changes were made.
6
+
7
+ ## Overview
8
+
9
+ **context-stash** stores atomic context entries as Markdown files inside a `.context/` directory at the root of your project. AI agents reference these entries in code comments (e.g., `// refer to context 00012`) to preserve reasoning and avoid reintroducing historical bugs.
10
+
11
+ ## Why context-stash?
12
+
13
+ ### The Problem: AI Forgets
14
+
15
+ Every AI coding assistant today suffers from the same flaw: **no persistent memory of past decisions**. This leads to:
16
+
17
+ - šŸ”„ Reintroduced bugs the AI fixed yesterday
18
+ - šŸ¤” Repeated questions about architectural decisions
19
+ - šŸ’„ Breaking changes that ignore historical constraints
20
+ - šŸ“ Lost context between sessions, models, and tools
21
+
22
+ ### The Solution: A Reasoning Ledger
23
+
24
+ context-stash creates a **distributed, code-embedded reference system** that works like:
25
+
26
+ - Git commit messages (explains *what* changed)
27
+ - Architectural Decision Records (explains *why* it changed)
28
+ - Inline documentation (stays with the code)
29
+ - AI reasoning logs (durable across sessions)
30
+
31
+ **All unified into a single, simple mechanism.**
32
+
33
+ ### Why It Works
34
+
35
+ 🧠 **Persistent Memory** - Context survives sessions, models, and tools
36
+ šŸ”— **Cross-File References** - One decision can explain changes in multiple files
37
+ šŸ“– **Human-Readable** - Markdown files anyone can read and audit
38
+ šŸ”’ **Immutable by Design** - Historical reasoning stays accurate
39
+ šŸŒ **Universal** - Works with any MCP-compatible AI agent
40
+ šŸš€ **Git-Native** - Version control for both code *and* reasoning
41
+
42
+ ## What Makes It Different
43
+
44
+ ### A Shared Language Between Humans and AI
45
+
46
+ Most AI tooling is either:
47
+ - **AI-only** (humans can't read it), or
48
+ - **Human-only** (AI ignores it)
49
+
50
+ context-stash is both:
51
+ - āœļø **AI-generated** - Agents create context automatically
52
+ - šŸ¤– **AI-consumable** - Agents retrieve it on demand
53
+ - šŸ‘ļø **Human-readable** - Plain Markdown anyone can understand
54
+ - āœļø **Human-editable** - Edit manually when needed
55
+ - šŸ“š **Git-tracked** - Full history of reasoning over time
56
+
57
+ ### Simple, Standard-Ready Design
58
+
59
+ Like `.gitignore`, `.editorconfig`, and `README.md`, context-stash is:
60
+ - Small, obvious, and useful
61
+ - Editor-agnostic and model-agnostic
62
+ - Easy to adopt, easy to ignore
63
+ - Non-intrusive to existing workflows
64
+
65
+ **This is how standards emerge.**
66
+
67
+ ## Links
68
+
69
+ - 🌐 **Website**: [https://nzmarktaylor.github.io/context-stash/](https://nzmarktaylor.github.io/context-stash/)
70
+ - šŸ“¦ **npm**: [https://www.npmjs.com/package/context-stash](https://www.npmjs.com/package/context-stash)
71
+ - šŸ’» **GitHub**: [https://github.com/nzmarktaylor/context-stash](https://github.com/nzmarktaylor/context-stash)
72
+ - šŸ“– **Examples**: [EXAMPLES.md](EXAMPLES.md)
73
+ - šŸ”§ **Development**: [DEVELOPMENT.md](DEVELOPMENT.md)
74
+
75
+ ## Features
76
+
77
+ - 🧠 **Persistent Memory** - Store reasoning, decisions, and context across AI coding sessions
78
+ - šŸ”’ **Immutable Entries** - Context entries are write-once, preventing accidental modifications
79
+ - šŸ“¦ **Git-Native** - Plain Markdown files that work seamlessly with version control
80
+ - šŸ” **Search & Discovery** - Find relevant context through keyword search
81
+ - šŸ› ļø **MCP Compatible** - Works with any MCP-compatible AI coding agent
82
+ - ⚔ **Zero Config** - Sensible defaults with optional customization
83
+
84
+ ## Installation
85
+
86
+ ### Global Installation (Recommended)
87
+
88
+ ```bash
89
+ npm install -g context-stash
90
+ ```
91
+
92
+ ### Project-Specific Installation
93
+
94
+ ```bash
95
+ npm install --save-dev context-stash
96
+ ```
97
+
98
+ ## Quick Start
99
+
100
+ ### 1. Initialize Your Workspace
101
+
102
+ Navigate to your project root and run:
103
+
104
+ ```bash
105
+ context-stash --init
106
+ ```
107
+
108
+ This creates:
109
+ - `.context/` directory for storing context entries
110
+ - `.context/config.json` with default configuration
111
+ - `agents.md` with usage instructions for AI agents
112
+
113
+ ### 2. Configure Your AI Agent
114
+
115
+ Add context-stash to your AI agent's MCP server configuration. For example, in Claude Desktop's config:
116
+
117
+ ```json
118
+ {
119
+ "mcpServers": {
120
+ "context-stash": {
121
+ "command": "context-stash",
122
+ "args": ["--serve"],
123
+ "cwd": "/path/to/your/project"
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### 3. Start Using Context
130
+
131
+ Your AI agent can now:
132
+ - **Create context entries**: `context.create` with Markdown content
133
+ - **Retrieve entries**: `context.get` with a reference number
134
+ - **List all entries**: `context.list`
135
+ - **Search entries**: `context.search` with a keyword
136
+
137
+ ## Usage Pattern
138
+
139
+ ### Creating Context Entries
140
+
141
+ When making a meaningful code change, create a context entry:
142
+
143
+ ```
144
+ Agent calls: context.create
145
+ Input: { "markdown": "# Fix: Null Pointer in User Service\n\nAdded null check before accessing user.profile..." }
146
+ Output: { "file": "00012.md" }
147
+ ```
148
+
149
+ ### Referencing Context in Code
150
+
151
+ Add comments to reference context:
152
+
153
+ ```javascript
154
+ // refer to context 00012
155
+ function getUserProfile(user) {
156
+ if (!user || !user.profile) return null;
157
+ return user.profile;
158
+ }
159
+ ```
160
+
161
+ ### Multiple References
162
+
163
+ A single context entry can be referenced in multiple files, and code can reference multiple entries:
164
+
165
+ ```python
166
+ # refer to context 00012, 00019, 00101
167
+ def process_user_data(user):
168
+ # ...
169
+ ```
170
+
171
+ ## MCP Tools
172
+
173
+ ### `context.create`
174
+
175
+ Create a new immutable context entry.
176
+
177
+ **Input:**
178
+ ```json
179
+ {
180
+ "markdown": "string (max 50 lines by default)"
181
+ }
182
+ ```
183
+
184
+ **Output:**
185
+ ```json
186
+ {
187
+ "file": "00012.md"
188
+ }
189
+ ```
190
+
191
+ ### `context.get`
192
+
193
+ Retrieve a context entry by reference.
194
+
195
+ **Input:**
196
+ ```json
197
+ {
198
+ "ref": "00012"
199
+ }
200
+ ```
201
+
202
+ **Output:**
203
+ ```json
204
+ {
205
+ "markdown": "# Fix: Null Pointer in User Service\n..."
206
+ }
207
+ ```
208
+
209
+ ### `context.list`
210
+
211
+ List all context entries.
212
+
213
+ **Output:**
214
+ ```json
215
+ {
216
+ "entries": [
217
+ { "ref": "00001", "file": "00001.md" },
218
+ { "ref": "00002", "file": "00002.md" }
219
+ ]
220
+ }
221
+ ```
222
+
223
+ ### `context.search`
224
+
225
+ Search context entries by keyword.
226
+
227
+ **Input:**
228
+ ```json
229
+ {
230
+ "query": "null pointer"
231
+ }
232
+ ```
233
+
234
+ **Output:**
235
+ ```json
236
+ {
237
+ "results": [
238
+ {
239
+ "ref": "00012",
240
+ "file": "00012.md",
241
+ "snippet": "Added null check before accessing user.profile..."
242
+ }
243
+ ]
244
+ }
245
+ ```
246
+
247
+ ## Configuration
248
+
249
+ The `.context/config.json` file controls behavior:
250
+
251
+ ```json
252
+ {
253
+ "maxLines": 50,
254
+ "startIndex": 1,
255
+ "leadingZeros": 5,
256
+ "filePrefix": "",
257
+ "fileSuffix": ".md"
258
+ }
259
+ ```
260
+
261
+ ### Configuration Options
262
+
263
+ | Option | Description | Default |
264
+ |--------|-------------|---------|
265
+ | `maxLines` | Maximum lines allowed per context entry | `50` |
266
+ | `startIndex` | First index number to use | `1` |
267
+ | `leadingZeros` | Number of digits in filenames | `5` |
268
+ | `filePrefix` | Optional filename prefix | `""` |
269
+ | `fileSuffix` | File extension | `".md"` |
270
+
271
+ ### Custom Filename Format
272
+
273
+ Adjust the config to use custom naming:
274
+
275
+ ```json
276
+ {
277
+ "filePrefix": "ctx-",
278
+ "fileSuffix": ".markdown",
279
+ "leadingZeros": 4
280
+ }
281
+ ```
282
+
283
+ This produces filenames like: `ctx-0123.markdown`
284
+
285
+ ## CLI Commands
286
+
287
+ ### `--init`
288
+
289
+ Initialize a workspace with context-stash:
290
+
291
+ ```bash
292
+ context-stash --init
293
+ ```
294
+
295
+ ### `--serve`
296
+
297
+ Start the MCP server (typically called by your AI agent):
298
+
299
+ ```bash
300
+ context-stash --serve
301
+ ```
302
+
303
+ ### `--help`
304
+
305
+ Show help information:
306
+
307
+ ```bash
308
+ context-stash --help
309
+ ```
310
+
311
+ ## Best Practices
312
+
313
+ ### Keep Entries Atomic
314
+
315
+ Each context entry should explain one conceptual change or decision:
316
+
317
+ āœ… **Good:**
318
+ ```markdown
319
+ # Fix: Race Condition in Payment Processing
320
+
321
+ Added mutex lock around balance update to prevent concurrent modifications
322
+ that could result in incorrect balance calculations.
323
+ ```
324
+
325
+ āŒ **Bad:**
326
+ ```markdown
327
+ # Various Changes
328
+
329
+ Fixed payment bug, updated user service, refactored database layer...
330
+ ```
331
+
332
+ ### Entries Are Immutable
333
+
334
+ Never modify existing context entries. If you need to add more information, create a new entry:
335
+
336
+ ```javascript
337
+ // refer to context 00012, 00045
338
+ // Context 00012: Original fix
339
+ // Context 00045: Additional edge case handling
340
+ ```
341
+
342
+ ### Use Descriptive Titles
343
+
344
+ Start each entry with a clear title:
345
+
346
+ ```markdown
347
+ # Decision: Use PostgreSQL Instead of MongoDB
348
+
349
+ After evaluating both databases, chose PostgreSQL because...
350
+ ```
351
+
352
+ ### When to Create Context
353
+
354
+ Create context entries to capture:
355
+
356
+ - šŸ› **Bug Fixes**: What broke, why it broke, how you fixed it
357
+ - šŸŽÆ **Design Decisions**: Why you chose approach A over B
358
+ - āš ļø **Workarounds**: Why the "proper" solution wasn't feasible
359
+ - šŸ”„ **Refactoring**: What assumptions changed
360
+ - 🚫 **Deprecated Code**: What future AI should avoid
361
+ - 🧱 **Constraints**: What limitations influenced the design
362
+ - šŸ’” **Intent**: What the code is *trying* to accomplish
363
+
364
+ **Think of it as a reasoning ledger, not just a change log.**
365
+
366
+ ## Version Control
367
+
368
+ The `.context/` directory is designed to work with Git:
369
+
370
+ ### Recommended `.gitignore`
371
+
372
+ Most teams should commit context entries:
373
+
374
+ ```gitignore
375
+ # Don't ignore .context/ - it's valuable project documentation!
376
+ ```
377
+
378
+ ### When to Ignore
379
+
380
+ Only ignore if your context contains sensitive information:
381
+
382
+ ```gitignore
383
+ .context/
384
+ ```
385
+
386
+ ## Requirements
387
+
388
+ - **Node.js**: >= 18.0.0
389
+ - **Operating System**: Windows, macOS, Linux
390
+
391
+ ## Development
392
+
393
+ ### Building from Source
394
+
395
+ ```bash
396
+ git clone https://github.com/nzmarktaylor/context-stash.git
397
+ cd context-stash
398
+ npm install
399
+ npm run build
400
+ ```
401
+
402
+ ### Testing Locally
403
+
404
+ ```bash
405
+ npm link
406
+ cd /path/to/test/project
407
+ context-stash --init
408
+ ```
409
+
410
+ ## Troubleshooting
411
+
412
+ ### "Failed to load config" Error
413
+
414
+ Make sure you've initialized the workspace:
415
+
416
+ ```bash
417
+ context-stash --init
418
+ ```
419
+
420
+ ### MCP Server Not Responding
421
+
422
+ Ensure the server is launched with the correct working directory (your project root).
423
+
424
+ ### Context Entry Too Long
425
+
426
+ Reduce the markdown content or increase `maxLines` in `.context/config.json`.
427
+
428
+ ## License
429
+
430
+ MIT
431
+
432
+ ## Contributing
433
+
434
+ Contributions are welcome! Please open an issue or submit a pull request.
435
+
436
+ ## Credits
437
+
438
+ Built with the [Model Context Protocol SDK](https://github.com/modelcontextprotocol/sdk).
439
+
440
+ ---
441
+
442
+ **Note**: This is a workspace-scoped MCP server. It must be launched per workspace, not globally, and is sandboxed to the workspace root for security.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { initializeWorkspace } from './utils.js';
3
+ import { startServer } from './server.js';
4
+ const args = process.argv.slice(2);
5
+ // refer to context 00001
6
+ async function main() {
7
+ if (args.includes('--init')) {
8
+ // Initialize workspace
9
+ const workspaceRoot = process.cwd();
10
+ await initializeWorkspace(workspaceRoot);
11
+ }
12
+ else if (args.includes('--serve')) {
13
+ // Start MCP server
14
+ await startServer();
15
+ }
16
+ else if (args.includes('--help') || args.includes('-h')) {
17
+ // Show help
18
+ console.log(`
19
+ context-stash - A workspace-scoped MCP server for AI coding agents
20
+
21
+ USAGE:
22
+ context-stash --init Initialize workspace with .context/ directory
23
+ context-stash --serve Start the MCP server (stdio transport)
24
+ context-stash --help Show this help message
25
+
26
+ DESCRIPTION:
27
+ context-stash provides a durable, Git-native memory layer for AI coding
28
+ agents. It stores atomic context entries as Markdown files inside a
29
+ .context/ directory at the root of your project.
30
+
31
+ INITIALIZATION:
32
+ Run 'context-stash --init' in your project root to create:
33
+ - .context/ Directory for context entries
34
+ - .context/config.json Configuration file
35
+ - agents.md Usage instructions for AI agents
36
+
37
+ MCP SERVER:
38
+ The MCP server provides four tools:
39
+ - context.create Create a new context entry
40
+ - context.get Retrieve a context entry by reference
41
+ - context.list List all context entries
42
+ - context.search Search context entries by keyword
43
+
44
+ The server must be launched with the workspace root as the working directory.
45
+
46
+ EXAMPLES:
47
+ # Initialize a new workspace
48
+ cd /path/to/your/project
49
+ context-stash --init
50
+
51
+ # Start the MCP server (typically configured in your AI agent)
52
+ context-stash --serve
53
+
54
+ MORE INFO:
55
+ https://github.com/yourusername/context-stash
56
+ `);
57
+ }
58
+ else {
59
+ console.error('Unknown command. Use --help for usage information.');
60
+ process.exit(1);
61
+ }
62
+ }
63
+ main().catch((error) => {
64
+ console.error('Error:', error.message);
65
+ process.exit(1);
66
+ });
67
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,yBAAyB;AACzB,KAAK,UAAU,IAAI;IACjB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,uBAAuB;QACvB,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAC3C,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,mBAAmB;QACnB,MAAM,WAAW,EAAE,CAAC;IACtB,CAAC;SAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1D,YAAY;QACZ,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCf,CAAC,CAAC;IACD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { createServer, startServer } from './server.js';
2
+ export { initializeWorkspace, loadConfig, saveConfig } from './utils.js';
3
+ export * from './types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzE,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { createServer, startServer } from './server.js';
2
+ export { initializeWorkspace, loadConfig, saveConfig } from './utils.js';
3
+ export * from './types.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzE,cAAc,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ /**
3
+ * Create and configure the MCP server
4
+ */
5
+ export declare function createServer(): Server;
6
+ /**
7
+ * Start the MCP server
8
+ */
9
+ export declare function startServer(): Promise<void>;
10
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAqBnE;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAyGrC;AAoLD;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAOjD"}
package/dist/server.js ADDED
@@ -0,0 +1,268 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
4
+ import { promises as fs } from 'fs';
5
+ import * as path from 'path';
6
+ import { loadConfig, formatFilename, extractRef, getNextIndex, countLines, validatePath, } from './utils.js';
7
+ const CONTEXT_DIR = '.context';
8
+ const workspaceRoot = process.cwd();
9
+ /**
10
+ * Create and configure the MCP server
11
+ */
12
+ export function createServer() {
13
+ const server = new Server({
14
+ name: 'context-stash',
15
+ version: '1.0.0',
16
+ }, {
17
+ capabilities: {
18
+ tools: {},
19
+ },
20
+ });
21
+ // List available tools
22
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
23
+ return {
24
+ tools: [
25
+ {
26
+ name: 'context.create',
27
+ description: 'Create a new immutable context entry',
28
+ inputSchema: {
29
+ type: 'object',
30
+ properties: {
31
+ markdown: {
32
+ type: 'string',
33
+ description: 'Markdown content for the context entry',
34
+ },
35
+ },
36
+ required: ['markdown'],
37
+ },
38
+ },
39
+ {
40
+ name: 'context.get',
41
+ description: 'Retrieve the contents of a context entry',
42
+ inputSchema: {
43
+ type: 'object',
44
+ properties: {
45
+ ref: {
46
+ type: 'string',
47
+ description: 'Reference number (e.g., "00012")',
48
+ },
49
+ },
50
+ required: ['ref'],
51
+ },
52
+ },
53
+ {
54
+ name: 'context.list',
55
+ description: 'List all context entries',
56
+ inputSchema: {
57
+ type: 'object',
58
+ properties: {},
59
+ },
60
+ },
61
+ {
62
+ name: 'context.search',
63
+ description: 'Search context entries by keyword',
64
+ inputSchema: {
65
+ type: 'object',
66
+ properties: {
67
+ query: {
68
+ type: 'string',
69
+ description: 'Search query string',
70
+ },
71
+ },
72
+ required: ['query'],
73
+ },
74
+ },
75
+ ],
76
+ };
77
+ });
78
+ // Handle tool calls
79
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
80
+ try {
81
+ switch (request.params.name) {
82
+ case 'context.create':
83
+ return await handleCreate(request.params.arguments);
84
+ case 'context.get':
85
+ return await handleGet(request.params.arguments);
86
+ case 'context.list':
87
+ return await handleList();
88
+ case 'context.search':
89
+ return await handleSearch(request.params.arguments);
90
+ default:
91
+ throw new Error(`Unknown tool: ${request.params.name}`);
92
+ }
93
+ }
94
+ catch (error) {
95
+ const message = error instanceof Error ? error.message : String(error);
96
+ return {
97
+ content: [
98
+ {
99
+ type: 'text',
100
+ text: `Error: ${message}`,
101
+ },
102
+ ],
103
+ isError: true,
104
+ };
105
+ }
106
+ });
107
+ return server;
108
+ }
109
+ /**
110
+ * Handle context.create tool
111
+ */
112
+ async function handleCreate(args) {
113
+ const { markdown } = args;
114
+ if (typeof markdown !== 'string') {
115
+ throw new Error('markdown must be a string');
116
+ }
117
+ // Load config
118
+ const config = await loadConfig(workspaceRoot);
119
+ // Validate line count
120
+ const lineCount = countLines(markdown);
121
+ if (lineCount > config.maxLines) {
122
+ throw new Error(`Markdown exceeds maximum of ${config.maxLines} lines (got ${lineCount} lines)`);
123
+ }
124
+ // Get next index and format filename
125
+ const index = await getNextIndex(workspaceRoot, config);
126
+ const filename = formatFilename(index, config);
127
+ const filePath = path.join(workspaceRoot, CONTEXT_DIR, filename);
128
+ // Validate path
129
+ validatePath(filePath, workspaceRoot);
130
+ // Write file
131
+ await fs.writeFile(filePath, markdown, 'utf-8');
132
+ return {
133
+ content: [
134
+ {
135
+ type: 'text',
136
+ text: JSON.stringify({ file: filename }, null, 2),
137
+ },
138
+ ],
139
+ };
140
+ }
141
+ /**
142
+ * Handle context.get tool
143
+ */
144
+ async function handleGet(args) {
145
+ const { ref } = args;
146
+ if (typeof ref !== 'string') {
147
+ throw new Error('ref must be a string');
148
+ }
149
+ // Load config
150
+ const config = await loadConfig(workspaceRoot);
151
+ // Determine filename
152
+ const filename = `${config.filePrefix}${ref}${config.fileSuffix}`;
153
+ const filePath = path.join(workspaceRoot, CONTEXT_DIR, filename);
154
+ // Validate path
155
+ validatePath(filePath, workspaceRoot);
156
+ // Read file
157
+ try {
158
+ const markdown = await fs.readFile(filePath, 'utf-8');
159
+ return {
160
+ content: [
161
+ {
162
+ type: 'text',
163
+ text: JSON.stringify({ markdown }, null, 2),
164
+ },
165
+ ],
166
+ };
167
+ }
168
+ catch (error) {
169
+ throw new Error(`Context entry '${ref}' not found`);
170
+ }
171
+ }
172
+ /**
173
+ * Handle context.list tool
174
+ */
175
+ async function handleList() {
176
+ // Load config
177
+ const config = await loadConfig(workspaceRoot);
178
+ const contextDir = path.join(workspaceRoot, CONTEXT_DIR);
179
+ try {
180
+ const files = await fs.readdir(contextDir);
181
+ const entries = [];
182
+ for (const file of files) {
183
+ if (file === 'config.json')
184
+ continue;
185
+ const ref = extractRef(file, config);
186
+ if (ref) {
187
+ entries.push({ ref, file });
188
+ }
189
+ }
190
+ // Sort by index
191
+ entries.sort((a, b) => {
192
+ const indexA = parseInt(a.ref, 10);
193
+ const indexB = parseInt(b.ref, 10);
194
+ return indexA - indexB;
195
+ });
196
+ return {
197
+ content: [
198
+ {
199
+ type: 'text',
200
+ text: JSON.stringify({ entries }, null, 2),
201
+ },
202
+ ],
203
+ };
204
+ }
205
+ catch (error) {
206
+ throw new Error('Failed to list context entries');
207
+ }
208
+ }
209
+ /**
210
+ * Handle context.search tool
211
+ */
212
+ async function handleSearch(args) {
213
+ const { query } = args;
214
+ if (typeof query !== 'string') {
215
+ throw new Error('query must be a string');
216
+ }
217
+ // Load config
218
+ const config = await loadConfig(workspaceRoot);
219
+ const contextDir = path.join(workspaceRoot, CONTEXT_DIR);
220
+ const results = [];
221
+ try {
222
+ const files = await fs.readdir(contextDir);
223
+ for (const file of files) {
224
+ if (file === 'config.json')
225
+ continue;
226
+ const ref = extractRef(file, config);
227
+ if (!ref)
228
+ continue;
229
+ const filePath = path.join(contextDir, file);
230
+ const content = await fs.readFile(filePath, 'utf-8');
231
+ // Simple case-insensitive search
232
+ const lines = content.split('\n');
233
+ const lowerQuery = query.toLowerCase();
234
+ for (const line of lines) {
235
+ if (line.toLowerCase().includes(lowerQuery)) {
236
+ results.push({
237
+ ref,
238
+ file,
239
+ snippet: line.trim(),
240
+ });
241
+ break; // Only include first match per file
242
+ }
243
+ }
244
+ }
245
+ return {
246
+ content: [
247
+ {
248
+ type: 'text',
249
+ text: JSON.stringify({ results }, null, 2),
250
+ },
251
+ ],
252
+ };
253
+ }
254
+ catch (error) {
255
+ throw new Error('Failed to search context entries');
256
+ }
257
+ }
258
+ /**
259
+ * Start the MCP server
260
+ */
261
+ export async function startServer() {
262
+ const server = createServer();
263
+ const transport = new StdioServerTransport();
264
+ await server.connect(transport);
265
+ // Keep process running
266
+ process.stdin.resume();
267
+ }
268
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Configuration for context-stash
3
+ */
4
+ export interface Config {
5
+ maxLines: number;
6
+ startIndex: number;
7
+ leadingZeros: number;
8
+ filePrefix: string;
9
+ fileSuffix: string;
10
+ }
11
+ /**
12
+ * Represents a context entry reference
13
+ */
14
+ export interface ContextEntry {
15
+ ref: string;
16
+ file: string;
17
+ }
18
+ /**
19
+ * Result of a context search
20
+ */
21
+ export interface SearchResult {
22
+ ref: string;
23
+ file: string;
24
+ snippet: string;
25
+ }
26
+ /**
27
+ * Default configuration values
28
+ */
29
+ export declare const DEFAULT_CONFIG: Config;
30
+ /**
31
+ * Default agents.md content
32
+ */
33
+ export declare const AGENTS_MD_CONTENT = "# Context Stash (MCP Tool)\n\nThis project uses **context\u2011stash**, a workspace\u2011local MCP server that stores durable reasoning context for AI coding agents.\n\n## Purpose\n\nContext entries explain *why* code changes were made. They help prevent reintroducing historical bugs and allow AI agents to understand the intent behind modifications.\n\n## Usage Pattern\n\n- When making a meaningful code change, call the MCP tool `context.create` with a short Markdown explanation.\n- The tool returns a reference number (e.g., `00012`).\n- Insert comments in relevant files such as:\n\n```\n// refer to context 00012\n```\n\n- Context entries are **immutable**. If new reasoning is needed, create a new entry rather than modifying an old one.\n- A single context entry may be referenced in many files.\n- Code may reference multiple entries:\n\n```\n// refer to context 00012, 00019, 00101\n```\n\n## When to Create Context\n\nCreate context entries for:\n\n- **Bug Fixes**: What broke, why it broke, and how you fixed it\n- **Design Decisions**: Why you chose approach A over B\n- **Workarounds**: Why the \"proper\" solution wasn't feasible\n- **Refactoring**: What assumptions changed and why\n- **Constraints**: What limitations influenced the design\n- **Deprecated Code**: What future AI should avoid and why\n- **Intent Clarification**: What the code is trying to accomplish beyond what's obvious\n\n**Do NOT create context for:**\n- Trivial changes (formatting, typos)\n- Self-explanatory code changes\n- Temporary experiments\n- Changes that are fully explained by existing documentation\n\n## Writing Good Context\n\n### Use Clear Structure\n\n```markdown\n# Brief Title (Bug Fix / Decision / Workaround)\n\n## Problem / Context\nWhat situation led to this change?\n\n## Solution / Decision\nWhat did you do and why?\n\n## Alternatives Considered (optional)\nWhat other approaches were rejected and why?\n\n## Impact (optional)\nWhat files/systems does this affect?\n```\n\n### Be Concise But Complete\n\n- Max 50 lines by default (configurable)\n- Focus on **WHY**, not just WHAT\n- Include enough detail that future AI can understand the reasoning\n- Avoid unnecessary verbosity\n\n### Think Cross-Session\n\nRemember: You might not be the AI agent that reads this later. Write for:\n- Different AI models\n- Future versions of yourself\n- Human developers reviewing code\n- Team members unfamiliar with the change\n\n## Best Practices for AI Agents\n\n### Before Making Changes\n\n1. **Search existing context**: Use `context.search` to check if similar issues were addressed\n2. **List recent context**: Use `context.list` to see what decisions were made recently\n3. **Read referenced context**: If you see `// refer to context XXXXX`, call `context.get` to understand WHY the code exists\n\n### When Making Changes\n\n1. **Create context FIRST** if the change needs explanation\n2. **Add references IMMEDIATELY** after creating context\n3. **Be consistent** with comment format: `// refer to context 00012`\n\n### Important Reminders\n\n- **NEVER edit existing context files** in `.context/` - they are immutable\n- **ALWAYS reference context** when the reasoning isn't obvious from the code alone\n- **CHECK for existing context** before assuming you know the full story\n- **CREATE new context** if you discover additional information about an old decision\n\n## Project-Specific Guidelines\n\n### TypeScript Project\n\nThis is a TypeScript project targeting Node.js 18+. When working with this codebase:\n\n- Use explicit types for function parameters and return values\n- Prefer `async/await` over raw promises\n- Use ES modules (`import/export`) not CommonJS\n- Follow existing code style and conventions\n- Add JSDoc comments for public APIs\n\n### MCP Server Implementation\n\nKey architectural decisions for this project:\n\n- **Stdio transport**: The server uses stdio for communication (not TCP/HTTP)\n- **Workspace-scoped**: All operations must be sandboxed to `process.cwd()`\n- **Path validation**: Always validate paths to prevent directory traversal\n- **Immutability**: Context entries are write-once by design\n- **Simplicity**: The server should stay \"dumb\" - no AI interpretation, just storage\n\n### Security Considerations\n\n- Never allow path traversal outside workspace root\n- No network operations (stdio only)\n- Validate all user inputs\n- Keep dependencies minimal\n\n## MCP Server\n\nTo enable this tool, configure your agent to launch:\n\n```\ncontext-stash --serve\n```\n\nThe server must be launched with the workspace root as the working directory.\n\n## Questions?\n\nIf you're unsure whether to create context, err on the side of **creating it**. It's better to have too much reasoning documented than too little.\n";
34
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,MAM5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,0qJA8I7B,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Default configuration values
3
+ */
4
+ export const DEFAULT_CONFIG = {
5
+ maxLines: 50,
6
+ startIndex: 1,
7
+ leadingZeros: 5,
8
+ filePrefix: "",
9
+ fileSuffix: ".md"
10
+ };
11
+ /**
12
+ * Default agents.md content
13
+ */
14
+ export const AGENTS_MD_CONTENT = `# Context Stash (MCP Tool)
15
+
16
+ This project uses **context‑stash**, a workspace‑local MCP server that stores durable reasoning context for AI coding agents.
17
+
18
+ ## Purpose
19
+
20
+ Context entries explain *why* code changes were made. They help prevent reintroducing historical bugs and allow AI agents to understand the intent behind modifications.
21
+
22
+ ## Usage Pattern
23
+
24
+ - When making a meaningful code change, call the MCP tool \`context.create\` with a short Markdown explanation.
25
+ - The tool returns a reference number (e.g., \`00012\`).
26
+ - Insert comments in relevant files such as:
27
+
28
+ \`\`\`
29
+ // refer to context 00012
30
+ \`\`\`
31
+
32
+ - Context entries are **immutable**. If new reasoning is needed, create a new entry rather than modifying an old one.
33
+ - A single context entry may be referenced in many files.
34
+ - Code may reference multiple entries:
35
+
36
+ \`\`\`
37
+ // refer to context 00012, 00019, 00101
38
+ \`\`\`
39
+
40
+ ## When to Create Context
41
+
42
+ Create context entries for:
43
+
44
+ - **Bug Fixes**: What broke, why it broke, and how you fixed it
45
+ - **Design Decisions**: Why you chose approach A over B
46
+ - **Workarounds**: Why the "proper" solution wasn't feasible
47
+ - **Refactoring**: What assumptions changed and why
48
+ - **Constraints**: What limitations influenced the design
49
+ - **Deprecated Code**: What future AI should avoid and why
50
+ - **Intent Clarification**: What the code is trying to accomplish beyond what's obvious
51
+
52
+ **Do NOT create context for:**
53
+ - Trivial changes (formatting, typos)
54
+ - Self-explanatory code changes
55
+ - Temporary experiments
56
+ - Changes that are fully explained by existing documentation
57
+
58
+ ## Writing Good Context
59
+
60
+ ### Use Clear Structure
61
+
62
+ \`\`\`markdown
63
+ # Brief Title (Bug Fix / Decision / Workaround)
64
+
65
+ ## Problem / Context
66
+ What situation led to this change?
67
+
68
+ ## Solution / Decision
69
+ What did you do and why?
70
+
71
+ ## Alternatives Considered (optional)
72
+ What other approaches were rejected and why?
73
+
74
+ ## Impact (optional)
75
+ What files/systems does this affect?
76
+ \`\`\`
77
+
78
+ ### Be Concise But Complete
79
+
80
+ - Max 50 lines by default (configurable)
81
+ - Focus on **WHY**, not just WHAT
82
+ - Include enough detail that future AI can understand the reasoning
83
+ - Avoid unnecessary verbosity
84
+
85
+ ### Think Cross-Session
86
+
87
+ Remember: You might not be the AI agent that reads this later. Write for:
88
+ - Different AI models
89
+ - Future versions of yourself
90
+ - Human developers reviewing code
91
+ - Team members unfamiliar with the change
92
+
93
+ ## Best Practices for AI Agents
94
+
95
+ ### Before Making Changes
96
+
97
+ 1. **Search existing context**: Use \`context.search\` to check if similar issues were addressed
98
+ 2. **List recent context**: Use \`context.list\` to see what decisions were made recently
99
+ 3. **Read referenced context**: If you see \`// refer to context XXXXX\`, call \`context.get\` to understand WHY the code exists
100
+
101
+ ### When Making Changes
102
+
103
+ 1. **Create context FIRST** if the change needs explanation
104
+ 2. **Add references IMMEDIATELY** after creating context
105
+ 3. **Be consistent** with comment format: \`// refer to context 00012\`
106
+
107
+ ### Important Reminders
108
+
109
+ - **NEVER edit existing context files** in \`.context/\` - they are immutable
110
+ - **ALWAYS reference context** when the reasoning isn't obvious from the code alone
111
+ - **CHECK for existing context** before assuming you know the full story
112
+ - **CREATE new context** if you discover additional information about an old decision
113
+
114
+ ## Project-Specific Guidelines
115
+
116
+ ### TypeScript Project
117
+
118
+ This is a TypeScript project targeting Node.js 18+. When working with this codebase:
119
+
120
+ - Use explicit types for function parameters and return values
121
+ - Prefer \`async/await\` over raw promises
122
+ - Use ES modules (\`import/export\`) not CommonJS
123
+ - Follow existing code style and conventions
124
+ - Add JSDoc comments for public APIs
125
+
126
+ ### MCP Server Implementation
127
+
128
+ Key architectural decisions for this project:
129
+
130
+ - **Stdio transport**: The server uses stdio for communication (not TCP/HTTP)
131
+ - **Workspace-scoped**: All operations must be sandboxed to \`process.cwd()\`
132
+ - **Path validation**: Always validate paths to prevent directory traversal
133
+ - **Immutability**: Context entries are write-once by design
134
+ - **Simplicity**: The server should stay "dumb" - no AI interpretation, just storage
135
+
136
+ ### Security Considerations
137
+
138
+ - Never allow path traversal outside workspace root
139
+ - No network operations (stdio only)
140
+ - Validate all user inputs
141
+ - Keep dependencies minimal
142
+
143
+ ## MCP Server
144
+
145
+ To enable this tool, configure your agent to launch:
146
+
147
+ \`\`\`
148
+ context-stash --serve
149
+ \`\`\`
150
+
151
+ The server must be launched with the workspace root as the working directory.
152
+
153
+ ## Questions?
154
+
155
+ If you're unsure whether to create context, err on the side of **creating it**. It's better to have too much reasoning documented than too little.
156
+ `;
157
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA4BA;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,QAAQ,EAAE,EAAE;IACZ,UAAU,EAAE,CAAC;IACb,YAAY,EAAE,CAAC;IACf,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,KAAK;CAClB,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8IhC,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { Config } from './types.js';
2
+ /**
3
+ * Load configuration from .context/config.json
4
+ */
5
+ export declare function loadConfig(workspaceRoot: string): Promise<Config>;
6
+ /**
7
+ * Save configuration to .context/config.json
8
+ */
9
+ export declare function saveConfig(workspaceRoot: string, config: Config): Promise<void>;
10
+ /**
11
+ * Initialize the context-stash workspace
12
+ */
13
+ export declare function initializeWorkspace(workspaceRoot: string): Promise<void>;
14
+ /**
15
+ * Format index as filename according to config
16
+ */
17
+ export declare function formatFilename(index: number, config: Config): string;
18
+ /**
19
+ * Extract reference number from filename
20
+ */
21
+ export declare function extractRef(filename: string, config: Config): string | null;
22
+ /**
23
+ * Get the next available index
24
+ */
25
+ export declare function getNextIndex(workspaceRoot: string, config: Config): Promise<number>;
26
+ /**
27
+ * Count lines in markdown content
28
+ */
29
+ export declare function countLines(markdown: string): number;
30
+ /**
31
+ * Validate path to prevent directory traversal
32
+ */
33
+ export declare function validatePath(requestedPath: string, workspaceRoot: string): void;
34
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAqC,MAAM,YAAY,CAAC;AAMvE;;GAEG;AACH,wBAAsB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUvE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC9E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU1E;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BzF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,CAO/E"}
package/dist/utils.js ADDED
@@ -0,0 +1,128 @@
1
+ import { promises as fs } from 'fs';
2
+ import * as path from 'path';
3
+ import { DEFAULT_CONFIG, AGENTS_MD_CONTENT } from './types.js';
4
+ const CONTEXT_DIR = '.context';
5
+ const CONFIG_FILE = 'config.json';
6
+ const AGENTS_FILE = 'agents.md';
7
+ /**
8
+ * Load configuration from .context/config.json
9
+ */
10
+ export async function loadConfig(workspaceRoot) {
11
+ const configPath = path.join(workspaceRoot, CONTEXT_DIR, CONFIG_FILE);
12
+ try {
13
+ const content = await fs.readFile(configPath, 'utf-8');
14
+ const config = JSON.parse(content);
15
+ return { ...DEFAULT_CONFIG, ...config };
16
+ }
17
+ catch (error) {
18
+ throw new Error(`Failed to load config. Run 'context-stash --init' first.`);
19
+ }
20
+ }
21
+ /**
22
+ * Save configuration to .context/config.json
23
+ */
24
+ export async function saveConfig(workspaceRoot, config) {
25
+ const configPath = path.join(workspaceRoot, CONTEXT_DIR, CONFIG_FILE);
26
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
27
+ }
28
+ /**
29
+ * Initialize the context-stash workspace
30
+ */
31
+ export async function initializeWorkspace(workspaceRoot) {
32
+ const contextDir = path.join(workspaceRoot, CONTEXT_DIR);
33
+ // Create .context directory
34
+ try {
35
+ await fs.mkdir(contextDir, { recursive: true });
36
+ console.log(`āœ“ Created ${CONTEXT_DIR}/ directory`);
37
+ }
38
+ catch (error) {
39
+ console.log(`āœ“ ${CONTEXT_DIR}/ directory already exists`);
40
+ }
41
+ // Create or update config.json
42
+ const configPath = path.join(contextDir, CONFIG_FILE);
43
+ try {
44
+ await fs.access(configPath);
45
+ console.log(`āœ“ ${CONTEXT_DIR}/${CONFIG_FILE} already exists`);
46
+ }
47
+ catch {
48
+ await saveConfig(workspaceRoot, DEFAULT_CONFIG);
49
+ console.log(`āœ“ Created ${CONTEXT_DIR}/${CONFIG_FILE}`);
50
+ }
51
+ // Create or update agents.md
52
+ const agentsPath = path.join(workspaceRoot, AGENTS_FILE);
53
+ try {
54
+ await fs.access(agentsPath);
55
+ console.log(`āœ“ ${AGENTS_FILE} already exists`);
56
+ }
57
+ catch {
58
+ await fs.writeFile(agentsPath, AGENTS_MD_CONTENT, 'utf-8');
59
+ console.log(`āœ“ Created ${AGENTS_FILE}`);
60
+ }
61
+ console.log('\nāœ“ Initialization complete!');
62
+ console.log(`\nTo use the MCP server, run:`);
63
+ console.log(` context-stash --serve`);
64
+ }
65
+ /**
66
+ * Format index as filename according to config
67
+ */
68
+ export function formatFilename(index, config) {
69
+ const paddedIndex = String(index).padStart(config.leadingZeros, '0');
70
+ return `${config.filePrefix}${paddedIndex}${config.fileSuffix}`;
71
+ }
72
+ /**
73
+ * Extract reference number from filename
74
+ */
75
+ export function extractRef(filename, config) {
76
+ const { filePrefix, fileSuffix } = config;
77
+ if (!filename.startsWith(filePrefix) || !filename.endsWith(fileSuffix)) {
78
+ return null;
79
+ }
80
+ const start = filePrefix.length;
81
+ const end = filename.length - fileSuffix.length;
82
+ return filename.substring(start, end);
83
+ }
84
+ /**
85
+ * Get the next available index
86
+ */
87
+ export async function getNextIndex(workspaceRoot, config) {
88
+ const contextDir = path.join(workspaceRoot, CONTEXT_DIR);
89
+ try {
90
+ const files = await fs.readdir(contextDir);
91
+ const indices = [];
92
+ for (const file of files) {
93
+ if (file === CONFIG_FILE)
94
+ continue;
95
+ const ref = extractRef(file, config);
96
+ if (ref) {
97
+ const index = parseInt(ref, 10);
98
+ if (!isNaN(index)) {
99
+ indices.push(index);
100
+ }
101
+ }
102
+ }
103
+ if (indices.length === 0) {
104
+ return config.startIndex;
105
+ }
106
+ return Math.max(...indices) + 1;
107
+ }
108
+ catch (error) {
109
+ return config.startIndex;
110
+ }
111
+ }
112
+ /**
113
+ * Count lines in markdown content
114
+ */
115
+ export function countLines(markdown) {
116
+ return markdown.split('\n').length;
117
+ }
118
+ /**
119
+ * Validate path to prevent directory traversal
120
+ */
121
+ export function validatePath(requestedPath, workspaceRoot) {
122
+ const normalized = path.normalize(requestedPath);
123
+ const resolved = path.resolve(workspaceRoot, normalized);
124
+ if (!resolved.startsWith(workspaceRoot)) {
125
+ throw new Error('Path traversal detected');
126
+ }
127
+ }
128
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "context-stash",
3
+ "version": "1.0.0",
4
+ "description": "A workspace-scoped MCP server that provides a durable, Git-native memory layer for AI coding agents",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "context-stash": "dist/cli.js"
8
+ },
9
+ "type": "module",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "watch": "tsc --watch",
13
+ "prepublishOnly": "npm run build",
14
+ "dev": "tsc && node dist/cli.js",
15
+ "preview:site": "echo Open docs/index.html in your browser to preview the website"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "model-context-protocol",
20
+ "ai",
21
+ "coding-agent",
22
+ "context",
23
+ "memory",
24
+ "documentation",
25
+ "git",
26
+ "claude",
27
+ "copilot",
28
+ "agent"
29
+ ],
30
+ "author": "Mark Taylor",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/nzmarktaylor/context-stash.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/nzmarktaylor/context-stash/issues"
38
+ },
39
+ "homepage": "https://github.com/nzmarktaylor/context-stash#readme",
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.0.4"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^20.11.0",
48
+ "typescript": "^5.3.3"
49
+ },
50
+ "files": [
51
+ "dist",
52
+ "README.md",
53
+ "LICENSE"
54
+ ]
55
+ }