@towry/mcp 0.2.0 → 0.4.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/README.md +13 -126
- package/dist/checkpoints.d.ts +67 -0
- package/dist/checkpoints.d.ts.map +1 -0
- package/dist/checkpoints.js +330 -0
- package/dist/checkpoints.js.map +1 -0
- package/dist/checkpoints.test.d.ts +2 -0
- package/dist/checkpoints.test.d.ts.map +1 -0
- package/dist/checkpoints.test.js +277 -0
- package/dist/checkpoints.test.js.map +1 -0
- package/dist/checkpoints.validation.test.d.ts +2 -0
- package/dist/checkpoints.validation.test.d.ts.map +1 -0
- package/dist/checkpoints.validation.test.js +28 -0
- package/dist/checkpoints.validation.test.js.map +1 -0
- package/dist/index.d.ts +3 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -172
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +7 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +7 -0
- package/dist/lib.js.map +1 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @towry/mcp
|
|
2
2
|
|
|
3
|
-
MCP (Model Context Protocol) server for
|
|
3
|
+
MCP (Model Context Protocol) server for fast semantic codebase search.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -10,20 +10,12 @@ pnpm add @towry/mcp
|
|
|
10
10
|
npm install @towry/mcp
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
## Environment Variables
|
|
14
|
-
|
|
15
|
-
| Variable | Description | Default |
|
|
16
|
-
|----------|-------------|---------|
|
|
17
|
-
| `KG_API_URL` | Knowledge Graph API base URL | `http://localhost:8361` |
|
|
18
|
-
| `KG_API_KEY` | API authentication key | `kg-dev-api-key` |
|
|
19
|
-
| `KG_API_TOKEN` | Alternative to KG_API_KEY | - |
|
|
20
|
-
|
|
21
13
|
## Usage
|
|
22
14
|
|
|
23
15
|
### As a CLI
|
|
24
16
|
|
|
25
17
|
```bash
|
|
26
|
-
|
|
18
|
+
pnpm dlx @towry/mcp
|
|
27
19
|
```
|
|
28
20
|
|
|
29
21
|
### With Claude Desktop
|
|
@@ -33,13 +25,9 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_
|
|
|
33
25
|
```json
|
|
34
26
|
{
|
|
35
27
|
"mcpServers": {
|
|
36
|
-
"towry-mcp
|
|
28
|
+
"towry-mcp": {
|
|
37
29
|
"command": "npx",
|
|
38
|
-
"args": ["@towry/mcp"]
|
|
39
|
-
"env": {
|
|
40
|
-
"KG_API_URL": "http://localhost:8361",
|
|
41
|
-
"KG_API_KEY": "your-api-key"
|
|
42
|
-
}
|
|
30
|
+
"args": ["@towry/mcp"]
|
|
43
31
|
}
|
|
44
32
|
}
|
|
45
33
|
}
|
|
@@ -47,116 +35,15 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_
|
|
|
47
35
|
|
|
48
36
|
## Available Tools
|
|
49
37
|
|
|
50
|
-
### `
|
|
51
|
-
|
|
52
|
-
Create or update a document in the knowledge graph.
|
|
53
|
-
|
|
54
|
-
**Parameters:**
|
|
55
|
-
- `title` (string, required): Document title
|
|
56
|
-
- `body` (string, required): Document content
|
|
57
|
-
- `doc_type` (enum, required): `note` | `doc` | `task` | `plan` | `agent_session`
|
|
58
|
-
- `id` (string, optional): UUID to update existing doc
|
|
59
|
-
- `project_repo` (string, optional): Project repo (owner/repo)
|
|
60
|
-
- `tags` (string[], optional): Tags for categorization
|
|
61
|
-
- `status` (enum, optional): `pending` | `in_progress` | `done` | `blocked` (for tasks)
|
|
62
|
-
- `parent_id` (string, optional): Parent document ID for hierarchy
|
|
63
|
-
|
|
64
|
-
### `kg_get_doc`
|
|
65
|
-
|
|
66
|
-
Get full document by ID.
|
|
67
|
-
|
|
68
|
-
**Parameters:**
|
|
69
|
-
- `id` (string, required): Document UUID
|
|
70
|
-
|
|
71
|
-
### `kg_delete_doc`
|
|
72
|
-
|
|
73
|
-
Delete a document from the knowledge graph.
|
|
74
|
-
|
|
75
|
-
**Parameters:**
|
|
76
|
-
- `id` (string, required): Document UUID to delete
|
|
77
|
-
|
|
78
|
-
### `kg_search`
|
|
79
|
-
|
|
80
|
-
Search documents with filters.
|
|
81
|
-
|
|
82
|
-
**Parameters:**
|
|
83
|
-
- `q` (string, optional): Search query
|
|
84
|
-
- `doc_type` (enum, optional): Filter by document type
|
|
85
|
-
- `project_repo` (string, optional): Filter by project repo
|
|
86
|
-
- `status` (enum, optional): Filter by task status
|
|
87
|
-
- `tag` (string, optional): Filter by tag
|
|
88
|
-
- `limit` (number, optional): Max results (1-100, default: 20)
|
|
89
|
-
- `offset` (number, optional): Pagination offset (default: 0)
|
|
90
|
-
|
|
91
|
-
### `kg_semantic_search`
|
|
92
|
-
|
|
93
|
-
Semantic search using embeddings.
|
|
94
|
-
|
|
95
|
-
**Parameters:**
|
|
96
|
-
- `q` (string, required): Search query
|
|
97
|
-
- `embedding_keywords` (string[], optional): Keywords for embedding search
|
|
98
|
-
- `doc_type` (enum, optional): Filter by document type
|
|
99
|
-
- `project_repo` (string, optional): Filter by project repo
|
|
100
|
-
- `tag` (string, optional): Filter by tag
|
|
101
|
-
- `limit` (number, optional): Max results (1-20, default: 5)
|
|
102
|
-
|
|
103
|
-
### `kg_status`
|
|
104
|
-
|
|
105
|
-
Get document statistics: total count, breakdown by type and repo.
|
|
106
|
-
|
|
107
|
-
**Parameters:** None
|
|
108
|
-
|
|
109
|
-
## Document Types
|
|
110
|
-
|
|
111
|
-
| Type | Use Case |
|
|
112
|
-
|------|----------|
|
|
113
|
-
| `note` | Session-specific learnings, debugging discoveries (ephemeral) |
|
|
114
|
-
| `doc` | Curated reference docs meant to be maintained (stable) |
|
|
115
|
-
| `task` | Actionable items with status tracking |
|
|
116
|
-
| `plan` | Multi-step roadmaps with phases |
|
|
117
|
-
| `agent_session` | Chat session logs |
|
|
118
|
-
|
|
119
|
-
## Tmux Tools
|
|
120
|
-
|
|
121
|
-
### `tmux_list_panes`
|
|
122
|
-
|
|
123
|
-
List all tmux panes.
|
|
124
|
-
|
|
125
|
-
**Parameters:** None
|
|
126
|
-
|
|
127
|
-
### `tmux_send`
|
|
128
|
-
|
|
129
|
-
Send keys to a tmux pane.
|
|
130
|
-
|
|
131
|
-
**Parameters:**
|
|
132
|
-
- `pane` (string, optional): Target pane ID. Defaults to `PI_MASTER_PANE` env if set
|
|
133
|
-
- `keys` (string, required): Keys to send
|
|
134
|
-
- `enter` (boolean, optional): Send Enter after (default: true)
|
|
135
|
-
|
|
136
|
-
### `tmux_kill_pane`
|
|
137
|
-
|
|
138
|
-
Kill a tmux pane by ID.
|
|
139
|
-
|
|
140
|
-
**Parameters:**
|
|
141
|
-
- `pane` (string, required): Pane ID in `%N` format (e.g., `%886`)
|
|
142
|
-
|
|
143
|
-
### `tmux_capture`
|
|
144
|
-
|
|
145
|
-
Capture the content of a tmux pane.
|
|
146
|
-
|
|
147
|
-
**Parameters:**
|
|
148
|
-
- `pane` (string, required): Target pane ID to capture
|
|
149
|
-
- `lines` (number, optional): Number of lines to capture from end (default: 10)
|
|
150
|
-
- `filter` (string, optional): Grep pattern (case-insensitive, extended regex)
|
|
151
|
-
|
|
152
|
-
### `tmux_run`
|
|
38
|
+
### `grep_fast`
|
|
153
39
|
|
|
154
|
-
|
|
40
|
+
Fast semantic codebase search. It first narrows files by `keywords` and `filePatterns`, then runs `sgrep` on the filtered set.
|
|
155
41
|
|
|
156
42
|
**Parameters:**
|
|
157
|
-
- `
|
|
158
|
-
- `
|
|
159
|
-
- `
|
|
43
|
+
- `cwd` (string, required): Working directory to search in
|
|
44
|
+
- `keywords` (string[], required): Specific grep patterns such as `"login|signin"`
|
|
45
|
+
- `filePatterns` (string[], required): Specific filename globs such as `"*auth*"`
|
|
46
|
+
- `semanticQuery` (string, required): Natural-language query for semantic search
|
|
160
47
|
|
|
161
48
|
## Development
|
|
162
49
|
|
|
@@ -187,8 +74,8 @@ The [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) is a b
|
|
|
187
74
|
# Using the package script (recommended)
|
|
188
75
|
pnpm inspect
|
|
189
76
|
|
|
190
|
-
# Or manually
|
|
191
|
-
pnpm dlx @modelcontextprotocol/inspector
|
|
77
|
+
# Or manually
|
|
78
|
+
pnpm dlx @modelcontextprotocol/inspector node dist/index.js
|
|
192
79
|
|
|
193
80
|
# Debug in watch mode (rebuild first, then run inspector)
|
|
194
81
|
pnpm build && npx @modelcontextprotocol/inspector node dist/index.js
|
|
@@ -226,7 +113,7 @@ pnpm dlx @modelcontextprotocol/inspector --cli node dist/index.js
|
|
|
226
113
|
- **Check tool schemas**: Use the Tools tab to verify parameter types and descriptions
|
|
227
114
|
- **Test edge cases**: Try empty inputs, invalid types, missing required fields
|
|
228
115
|
- **Monitor errors**: Watch the Notifications pane for server-side errors
|
|
229
|
-
- **Verify
|
|
116
|
+
- **Verify search flow**: Test `grep_fast` with a small repository and focused keywords first
|
|
230
117
|
|
|
231
118
|
## License
|
|
232
119
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoints - Branch-scoped task recording for agent context continuity
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for recording and retrieving task checkpoints:
|
|
5
|
+
* - record_checkpoint: Append a task summary to branch-scoped JSONL
|
|
6
|
+
* - list_checkpoints: Query checkpoints by time, branch, or keywords
|
|
7
|
+
*
|
|
8
|
+
* Storage: `<repo-root>/.agents/checkpoints/<sanitized-branch>.jsonl`
|
|
9
|
+
*
|
|
10
|
+
* Keywords: checkpoint, task-history, agent-memory, context-continuity
|
|
11
|
+
*/
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
|
+
export declare function countSentences(text: string): number;
|
|
15
|
+
export declare const SummarySchema: z.ZodString;
|
|
16
|
+
export declare const ReferenceSchema: z.ZodObject<{
|
|
17
|
+
kind: z.ZodEnum<{
|
|
18
|
+
file: "file";
|
|
19
|
+
url: "url";
|
|
20
|
+
doc: "doc";
|
|
21
|
+
issue: "issue";
|
|
22
|
+
pr: "pr";
|
|
23
|
+
}>;
|
|
24
|
+
title: z.ZodString;
|
|
25
|
+
ref: z.ZodString;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export declare const CheckpointSchema: z.ZodObject<{
|
|
28
|
+
timestamp: z.ZodString;
|
|
29
|
+
branch: z.ZodString;
|
|
30
|
+
task: z.ZodString;
|
|
31
|
+
summary: z.ZodString;
|
|
32
|
+
files: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
33
|
+
references: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
34
|
+
kind: z.ZodEnum<{
|
|
35
|
+
file: "file";
|
|
36
|
+
url: "url";
|
|
37
|
+
doc: "doc";
|
|
38
|
+
issue: "issue";
|
|
39
|
+
pr: "pr";
|
|
40
|
+
}>;
|
|
41
|
+
title: z.ZodString;
|
|
42
|
+
ref: z.ZodString;
|
|
43
|
+
}, z.core.$strip>>>;
|
|
44
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
45
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
46
|
+
note: z.ZodOptional<z.ZodString>;
|
|
47
|
+
commit: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
hash: z.ZodString;
|
|
49
|
+
message: z.ZodString;
|
|
50
|
+
}, z.core.$strip>>;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
export type Checkpoint = z.infer<typeof CheckpointSchema>;
|
|
53
|
+
export type Reference = z.infer<typeof ReferenceSchema>;
|
|
54
|
+
export declare const RELATIVE_TIME_ALIASES: Record<string, () => Date>;
|
|
55
|
+
export declare function parseRelativeTime(alias: string): Date | null;
|
|
56
|
+
export declare function getCurrentBranch(cwd: string): string;
|
|
57
|
+
export declare function getGitRoot(cwd: string): string;
|
|
58
|
+
export declare function sanitizeBranchName(branch: string): string;
|
|
59
|
+
export declare function getCheckpointsDir(repoRoot: string): string;
|
|
60
|
+
export declare function getCheckpointFilePath(repoRoot: string, branch: string): string;
|
|
61
|
+
export declare function appendCheckpoint(repoRoot: string, branch: string, checkpoint: Checkpoint): string;
|
|
62
|
+
export declare function readCheckpoints(filePath: string): Checkpoint[];
|
|
63
|
+
export declare function filterByTime(checkpoints: Checkpoint[], since?: Date, until?: Date): Checkpoint[];
|
|
64
|
+
export declare function filterByQuery(checkpoints: Checkpoint[], query: string): Checkpoint[];
|
|
65
|
+
export declare function formatCheckpoints(checkpoints: Checkpoint[], branch: string): string;
|
|
66
|
+
export declare function registerCheckpointTools(server: McpServer): void;
|
|
67
|
+
//# sourceMappingURL=checkpoints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoints.d.ts","sourceRoot":"","sources":["../src/checkpoints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnD;AAMD,eAAO,MAAM,aAAa,aAM0B,CAAC;AAErD,eAAO,MAAM,eAAe;;;;;;;;;;iBAM1B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;iBAoB3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAMxD,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,CAgB5D,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAG5D;AAMD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAU9C;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD;AAMD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI9E;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,MAAM,CAKR;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAO9D;AAMD,wBAAgB,YAAY,CAC1B,WAAW,EAAE,UAAU,EAAE,EACzB,KAAK,CAAC,EAAE,IAAI,EACZ,KAAK,CAAC,EAAE,IAAI,GACX,UAAU,EAAE,CAOd;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAgBpF;AAMD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA6BnF;AAMD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwI/D"}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoints - Branch-scoped task recording for agent context continuity
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for recording and retrieving task checkpoints:
|
|
5
|
+
* - record_checkpoint: Append a task summary to branch-scoped JSONL
|
|
6
|
+
* - list_checkpoints: Query checkpoints by time, branch, or keywords
|
|
7
|
+
*
|
|
8
|
+
* Storage: `<repo-root>/.agents/checkpoints/<sanitized-branch>.jsonl`
|
|
9
|
+
*
|
|
10
|
+
* Keywords: checkpoint, task-history, agent-memory, context-continuity
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
import * as path from "node:path";
|
|
14
|
+
import { execSync } from "node:child_process";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Internal Utilities
|
|
18
|
+
// ============================================================================
|
|
19
|
+
export function countSentences(text) {
|
|
20
|
+
const trimmed = text.trim();
|
|
21
|
+
if (!trimmed)
|
|
22
|
+
return 0;
|
|
23
|
+
const matches = trimmed.match(/[^.!?]+[.!?]+/g);
|
|
24
|
+
if (!matches)
|
|
25
|
+
return 1;
|
|
26
|
+
return matches.length;
|
|
27
|
+
}
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// Types & Schemas (exported for pi extension)
|
|
30
|
+
// ============================================================================
|
|
31
|
+
export const SummarySchema = z
|
|
32
|
+
.string()
|
|
33
|
+
.refine((value) => {
|
|
34
|
+
const sentenceCount = countSentences(value);
|
|
35
|
+
return sentenceCount >= 2 && sentenceCount <= 4;
|
|
36
|
+
}, "Summary must contain 2-4 sentences.")
|
|
37
|
+
.describe("What was accomplished (2-4 sentences)");
|
|
38
|
+
export const ReferenceSchema = z.object({
|
|
39
|
+
kind: z
|
|
40
|
+
.enum(["file", "doc", "url", "issue", "pr"])
|
|
41
|
+
.describe("Reference type"),
|
|
42
|
+
title: z.string().describe("Human-readable title"),
|
|
43
|
+
ref: z.string().describe("Path, URL, or identifier"),
|
|
44
|
+
});
|
|
45
|
+
export const CheckpointSchema = z.object({
|
|
46
|
+
timestamp: z.string().describe("ISO 8601 timestamp"),
|
|
47
|
+
branch: z.string().describe("Git branch name or 'default'"),
|
|
48
|
+
task: z.string().describe("Short task description"),
|
|
49
|
+
summary: SummarySchema,
|
|
50
|
+
files: z.array(z.string()).optional().describe("Modified files"),
|
|
51
|
+
references: z
|
|
52
|
+
.array(ReferenceSchema)
|
|
53
|
+
.optional()
|
|
54
|
+
.describe("Referenced docs/files/URLs"),
|
|
55
|
+
tags: z.array(z.string()).optional().describe("Categorization tags"),
|
|
56
|
+
sessionId: z.string().optional().describe("Optional session identifier"),
|
|
57
|
+
note: z.string().optional().describe("Optional follow-up note"),
|
|
58
|
+
commit: z
|
|
59
|
+
.object({
|
|
60
|
+
hash: z.string(),
|
|
61
|
+
message: z.string(),
|
|
62
|
+
})
|
|
63
|
+
.optional()
|
|
64
|
+
.describe("Git commit info (populated by hooks)"),
|
|
65
|
+
});
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// Time Utilities (exported for pi extension)
|
|
68
|
+
// ============================================================================
|
|
69
|
+
export const RELATIVE_TIME_ALIASES = {
|
|
70
|
+
today: () => {
|
|
71
|
+
const d = new Date();
|
|
72
|
+
d.setHours(0, 0, 0, 0);
|
|
73
|
+
return d;
|
|
74
|
+
},
|
|
75
|
+
yesterday: () => {
|
|
76
|
+
const d = new Date();
|
|
77
|
+
d.setDate(d.getDate() - 1);
|
|
78
|
+
d.setHours(0, 0, 0, 0);
|
|
79
|
+
return d;
|
|
80
|
+
},
|
|
81
|
+
last_1h: () => new Date(Date.now() - 60 * 60 * 1000),
|
|
82
|
+
last_24h: () => new Date(Date.now() - 24 * 60 * 60 * 1000),
|
|
83
|
+
last_7d: () => new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
|
|
84
|
+
last_30d: () => new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
|
|
85
|
+
};
|
|
86
|
+
export function parseRelativeTime(alias) {
|
|
87
|
+
const fn = RELATIVE_TIME_ALIASES[alias.toLowerCase()];
|
|
88
|
+
return fn ? fn() : null;
|
|
89
|
+
}
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Git Utilities (exported for pi extension)
|
|
92
|
+
// ============================================================================
|
|
93
|
+
export function getCurrentBranch(cwd) {
|
|
94
|
+
try {
|
|
95
|
+
const branch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
96
|
+
cwd,
|
|
97
|
+
encoding: "utf-8",
|
|
98
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
99
|
+
}).trim();
|
|
100
|
+
return branch || "default";
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return "default";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function getGitRoot(cwd) {
|
|
107
|
+
try {
|
|
108
|
+
return execSync("git rev-parse --show-toplevel", {
|
|
109
|
+
cwd,
|
|
110
|
+
encoding: "utf-8",
|
|
111
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
112
|
+
}).trim();
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return cwd;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export function sanitizeBranchName(branch) {
|
|
119
|
+
return branch.replace(/[/\\:*?"<>|]/g, "_").replace(/_+/g, "_");
|
|
120
|
+
}
|
|
121
|
+
// ============================================================================
|
|
122
|
+
// Storage (exported for pi extension)
|
|
123
|
+
// ============================================================================
|
|
124
|
+
export function getCheckpointsDir(repoRoot) {
|
|
125
|
+
const dir = path.join(repoRoot, ".agents", "checkpoints");
|
|
126
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
127
|
+
return dir;
|
|
128
|
+
}
|
|
129
|
+
export function getCheckpointFilePath(repoRoot, branch) {
|
|
130
|
+
const dir = getCheckpointsDir(repoRoot);
|
|
131
|
+
const safeName = sanitizeBranchName(branch);
|
|
132
|
+
return path.join(dir, `${safeName}.jsonl`);
|
|
133
|
+
}
|
|
134
|
+
export function appendCheckpoint(repoRoot, branch, checkpoint) {
|
|
135
|
+
const filePath = getCheckpointFilePath(repoRoot, branch);
|
|
136
|
+
const line = JSON.stringify(checkpoint);
|
|
137
|
+
fs.appendFileSync(filePath, line + "\n", "utf-8");
|
|
138
|
+
return filePath;
|
|
139
|
+
}
|
|
140
|
+
export function readCheckpoints(filePath) {
|
|
141
|
+
if (!fs.existsSync(filePath)) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
145
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
146
|
+
return lines.map((line) => JSON.parse(line));
|
|
147
|
+
}
|
|
148
|
+
// ============================================================================
|
|
149
|
+
// Filtering (exported for pi extension)
|
|
150
|
+
// ============================================================================
|
|
151
|
+
export function filterByTime(checkpoints, since, until) {
|
|
152
|
+
return checkpoints.filter((cp) => {
|
|
153
|
+
const ts = new Date(cp.timestamp);
|
|
154
|
+
if (since && ts < since)
|
|
155
|
+
return false;
|
|
156
|
+
if (until && ts > until)
|
|
157
|
+
return false;
|
|
158
|
+
return true;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
export function filterByQuery(checkpoints, query) {
|
|
162
|
+
const q = query.toLowerCase();
|
|
163
|
+
return checkpoints.filter((cp) => {
|
|
164
|
+
if (cp.task.toLowerCase().includes(q))
|
|
165
|
+
return true;
|
|
166
|
+
if (cp.summary.toLowerCase().includes(q))
|
|
167
|
+
return true;
|
|
168
|
+
if (cp.tags?.some((t) => t.toLowerCase().includes(q)))
|
|
169
|
+
return true;
|
|
170
|
+
if (cp.references?.some((r) => r.title.toLowerCase().includes(q) || r.ref.toLowerCase().includes(q))) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// ============================================================================
|
|
177
|
+
// Output Formatting (exported for pi extension)
|
|
178
|
+
// ============================================================================
|
|
179
|
+
export function formatCheckpoints(checkpoints, branch) {
|
|
180
|
+
if (checkpoints.length === 0) {
|
|
181
|
+
return `No checkpoints found for branch "${branch}".`;
|
|
182
|
+
}
|
|
183
|
+
const lines = [`## Checkpoints (${branch})\n`];
|
|
184
|
+
for (const cp of checkpoints) {
|
|
185
|
+
lines.push(`### ${cp.timestamp}`);
|
|
186
|
+
lines.push(`**Task**: ${cp.task}`);
|
|
187
|
+
lines.push(`**Summary**: ${cp.summary}`);
|
|
188
|
+
if (cp.files?.length) {
|
|
189
|
+
lines.push(`**Files**: ${cp.files.join(", ")}`);
|
|
190
|
+
}
|
|
191
|
+
if (cp.references?.length) {
|
|
192
|
+
lines.push(`**References**:`);
|
|
193
|
+
for (const ref of cp.references) {
|
|
194
|
+
lines.push(` - [${ref.kind}] ${ref.title}: ${ref.ref}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (cp.tags?.length) {
|
|
198
|
+
lines.push(`**Tags**: ${cp.tags.join(", ")}`);
|
|
199
|
+
}
|
|
200
|
+
if (cp.note) {
|
|
201
|
+
lines.push(`**Note**: ${cp.note}`);
|
|
202
|
+
}
|
|
203
|
+
lines.push("");
|
|
204
|
+
}
|
|
205
|
+
return lines.join("\n");
|
|
206
|
+
}
|
|
207
|
+
// ============================================================================
|
|
208
|
+
// MCP Tool Registration
|
|
209
|
+
// ============================================================================
|
|
210
|
+
export function registerCheckpointTools(server) {
|
|
211
|
+
server.registerTool("record_checkpoint", {
|
|
212
|
+
description: `Record a task checkpoint to a branch-scoped JSONL file.
|
|
213
|
+
|
|
214
|
+
Call this at the end of a task session to leave context for future sessions.
|
|
215
|
+
|
|
216
|
+
Parameters:
|
|
217
|
+
- task: Short task description (e.g., "implement login form")
|
|
218
|
+
- summary: What was accomplished (2-4 sentences)
|
|
219
|
+
- references: Optional array of {kind, title, ref} for docs/files/URLs consulted
|
|
220
|
+
- files: Optional array of modified file paths
|
|
221
|
+
- tags: Optional array of categorization tags
|
|
222
|
+
- note: Optional follow-up note`,
|
|
223
|
+
inputSchema: {
|
|
224
|
+
task: z.string().describe("Short task description"),
|
|
225
|
+
summary: SummarySchema,
|
|
226
|
+
references: z
|
|
227
|
+
.array(ReferenceSchema)
|
|
228
|
+
.optional()
|
|
229
|
+
.describe("Referenced docs/files/URLs"),
|
|
230
|
+
files: z.array(z.string()).optional().describe("Modified files"),
|
|
231
|
+
tags: z.array(z.string()).optional().describe("Categorization tags"),
|
|
232
|
+
sessionId: z.string().optional().describe("Session identifier"),
|
|
233
|
+
note: z.string().optional().describe("Follow-up note"),
|
|
234
|
+
timestamp: z.string().optional().describe("Override timestamp (ISO 8601)"),
|
|
235
|
+
},
|
|
236
|
+
}, async (params) => {
|
|
237
|
+
const cwd = process.cwd();
|
|
238
|
+
const branch = getCurrentBranch(cwd);
|
|
239
|
+
const timestamp = params.timestamp ?? new Date().toISOString();
|
|
240
|
+
const checkpoint = {
|
|
241
|
+
timestamp,
|
|
242
|
+
branch,
|
|
243
|
+
task: params.task,
|
|
244
|
+
summary: params.summary,
|
|
245
|
+
files: params.files,
|
|
246
|
+
references: params.references,
|
|
247
|
+
tags: params.tags,
|
|
248
|
+
sessionId: params.sessionId,
|
|
249
|
+
note: params.note,
|
|
250
|
+
};
|
|
251
|
+
try {
|
|
252
|
+
const filePath = appendCheckpoint(cwd, branch, checkpoint);
|
|
253
|
+
return {
|
|
254
|
+
content: [
|
|
255
|
+
{
|
|
256
|
+
type: "text",
|
|
257
|
+
text: `Checkpoint recorded.\n- Branch: ${branch}\n- File: ${filePath}\n- Timestamp: ${timestamp}`,
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
264
|
+
return {
|
|
265
|
+
content: [{ type: "text", text: `Failed to record checkpoint: ${msg}` }],
|
|
266
|
+
isError: true,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
server.registerTool("list_checkpoints", {
|
|
271
|
+
description: `List checkpoints from branch-scoped JSONL files.
|
|
272
|
+
|
|
273
|
+
Supports time filtering via ISO dates or natural aliases:
|
|
274
|
+
- relativeTime: "today", "yesterday", "last_1h", "last_24h", "last_7d", "last_30d"
|
|
275
|
+
- since/until: ISO 8601 dates for precise range
|
|
276
|
+
|
|
277
|
+
Query searches in task, summary, tags, and reference titles/refs.
|
|
278
|
+
|
|
279
|
+
Parameters:
|
|
280
|
+
- cwd: Repository root directory (optional; defaults to current git root)
|
|
281
|
+
- branch: Target branch (defaults to current branch)
|
|
282
|
+
- query: Optional keyword filter
|
|
283
|
+
- since/until: ISO 8601 time range, recommend to use relativeTime.
|
|
284
|
+
- relativeTime: Natural time alias
|
|
285
|
+
- limit: Max results (default 5)`,
|
|
286
|
+
inputSchema: {
|
|
287
|
+
cwd: z
|
|
288
|
+
.string()
|
|
289
|
+
.optional()
|
|
290
|
+
.describe("Repository root directory (default: current git root)"),
|
|
291
|
+
branch: z.string().optional().describe("Target branch (default: current)"),
|
|
292
|
+
query: z.string().optional().describe("Keyword filter"),
|
|
293
|
+
since: z.string().optional().describe("Start time (ISO 8601)"),
|
|
294
|
+
until: z.string().optional().describe("End time (ISO 8601)"),
|
|
295
|
+
relativeTime: z
|
|
296
|
+
.enum(["today", "yesterday", "last_1h", "last_24h", "last_7d", "last_30d"])
|
|
297
|
+
.optional()
|
|
298
|
+
.describe("Recommend: Natural time alias"),
|
|
299
|
+
limit: z.number().min(1).max(100).optional().describe("Max results (default 5)"),
|
|
300
|
+
},
|
|
301
|
+
}, async (params) => {
|
|
302
|
+
const cwd = params.cwd ?? getGitRoot(process.cwd());
|
|
303
|
+
const branch = params.branch ?? getCurrentBranch(cwd);
|
|
304
|
+
const filePath = getCheckpointFilePath(cwd, branch);
|
|
305
|
+
let checkpoints = readCheckpoints(filePath);
|
|
306
|
+
let since;
|
|
307
|
+
let until;
|
|
308
|
+
if (params.relativeTime) {
|
|
309
|
+
since = parseRelativeTime(params.relativeTime) ?? undefined;
|
|
310
|
+
}
|
|
311
|
+
if (params.since) {
|
|
312
|
+
since = new Date(params.since);
|
|
313
|
+
}
|
|
314
|
+
if (params.until) {
|
|
315
|
+
until = new Date(params.until);
|
|
316
|
+
}
|
|
317
|
+
if (since || until) {
|
|
318
|
+
checkpoints = filterByTime(checkpoints, since, until);
|
|
319
|
+
}
|
|
320
|
+
if (params.query) {
|
|
321
|
+
checkpoints = filterByQuery(checkpoints, params.query);
|
|
322
|
+
}
|
|
323
|
+
const limit = params.limit ?? 10;
|
|
324
|
+
checkpoints = checkpoints.reverse().slice(0, limit);
|
|
325
|
+
return {
|
|
326
|
+
content: [{ type: "text", text: formatCheckpoints(checkpoints, branch) }],
|
|
327
|
+
};
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=checkpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoints.js","sourceRoot":"","sources":["../src/checkpoints.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoints.test.d.ts","sourceRoot":"","sources":["../src/checkpoints.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import * as os from "node:os";
|
|
5
|
+
// Import internal functions for testing
|
|
6
|
+
// We need to export them or test via the public API
|
|
7
|
+
// For now, test the core logic via file operations
|
|
8
|
+
const TEST_DIR = path.join(os.tmpdir(), "mcp-checkpoints-test");
|
|
9
|
+
// Helper to create test checkpoint file
|
|
10
|
+
function createTestCheckpointFile(branch, checkpoints) {
|
|
11
|
+
const dir = path.join(TEST_DIR, ".agents", "checkpoints");
|
|
12
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
13
|
+
const safeBranch = branch.replace(/\//g, "_");
|
|
14
|
+
const filePath = path.join(dir, `${safeBranch}.jsonl`);
|
|
15
|
+
const lines = checkpoints.map((cp) => JSON.stringify(cp)).join("\n");
|
|
16
|
+
fs.writeFileSync(filePath, lines + "\n", "utf-8");
|
|
17
|
+
return filePath;
|
|
18
|
+
}
|
|
19
|
+
function readTestCheckpoints(branch) {
|
|
20
|
+
const dir = path.join(TEST_DIR, ".agents", "checkpoints");
|
|
21
|
+
const safeBranch = branch.replace(/\//g, "_");
|
|
22
|
+
const filePath = path.join(dir, `${safeBranch}.jsonl`);
|
|
23
|
+
if (!fs.existsSync(filePath))
|
|
24
|
+
return [];
|
|
25
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
26
|
+
return content
|
|
27
|
+
.trim()
|
|
28
|
+
.split("\n")
|
|
29
|
+
.filter(Boolean)
|
|
30
|
+
.map((line) => JSON.parse(line));
|
|
31
|
+
}
|
|
32
|
+
// Recreate time filtering logic for testing
|
|
33
|
+
function filterByTime(checkpoints, since, until) {
|
|
34
|
+
return checkpoints.filter((cp) => {
|
|
35
|
+
const ts = new Date(cp.timestamp);
|
|
36
|
+
if (since && ts < since)
|
|
37
|
+
return false;
|
|
38
|
+
if (until && ts > until)
|
|
39
|
+
return false;
|
|
40
|
+
return true;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function parseRelativeTime(alias) {
|
|
44
|
+
const aliases = {
|
|
45
|
+
today: () => {
|
|
46
|
+
const d = new Date();
|
|
47
|
+
d.setHours(0, 0, 0, 0);
|
|
48
|
+
return d;
|
|
49
|
+
},
|
|
50
|
+
yesterday: () => {
|
|
51
|
+
const d = new Date();
|
|
52
|
+
d.setDate(d.getDate() - 1);
|
|
53
|
+
d.setHours(0, 0, 0, 0);
|
|
54
|
+
return d;
|
|
55
|
+
},
|
|
56
|
+
last_1h: () => new Date(Date.now() - 60 * 60 * 1000),
|
|
57
|
+
last_24h: () => new Date(Date.now() - 24 * 60 * 60 * 1000),
|
|
58
|
+
last_7d: () => new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
|
|
59
|
+
last_30d: () => new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
|
|
60
|
+
};
|
|
61
|
+
const fn = aliases[alias.toLowerCase()];
|
|
62
|
+
return fn ? fn() : null;
|
|
63
|
+
}
|
|
64
|
+
function filterByQuery(checkpoints, query) {
|
|
65
|
+
const q = query.toLowerCase();
|
|
66
|
+
return checkpoints.filter((cp) => {
|
|
67
|
+
if (cp.task.toLowerCase().includes(q))
|
|
68
|
+
return true;
|
|
69
|
+
if (cp.summary.toLowerCase().includes(q))
|
|
70
|
+
return true;
|
|
71
|
+
if (cp.tags?.some((t) => t.toLowerCase().includes(q)))
|
|
72
|
+
return true;
|
|
73
|
+
if (cp.references?.some((r) => r.title.toLowerCase().includes(q) || r.ref.toLowerCase().includes(q))) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
describe("checkpoints", () => {
|
|
80
|
+
beforeEach(() => {
|
|
81
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
82
|
+
fs.mkdirSync(TEST_DIR, { recursive: true });
|
|
83
|
+
});
|
|
84
|
+
afterEach(() => {
|
|
85
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
86
|
+
});
|
|
87
|
+
describe("record checkpoint", () => {
|
|
88
|
+
it("writes checkpoint to branch-scoped JSONL file", () => {
|
|
89
|
+
const checkpoint = {
|
|
90
|
+
timestamp: new Date().toISOString(),
|
|
91
|
+
branch: "feature/test",
|
|
92
|
+
task: "implement feature",
|
|
93
|
+
summary: "Added new checkpoint tools",
|
|
94
|
+
};
|
|
95
|
+
createTestCheckpointFile("feature/test", [checkpoint]);
|
|
96
|
+
const records = readTestCheckpoints("feature/test");
|
|
97
|
+
expect(records).toHaveLength(1);
|
|
98
|
+
expect(records[0]).toMatchObject({
|
|
99
|
+
branch: "feature/test",
|
|
100
|
+
task: "implement feature",
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
it("appends multiple checkpoints to same file", () => {
|
|
104
|
+
const cp1 = { timestamp: "2026-03-12T10:00:00Z", branch: "main", task: "task 1", summary: "s1" };
|
|
105
|
+
const cp2 = { timestamp: "2026-03-12T11:00:00Z", branch: "main", task: "task 2", summary: "s2" };
|
|
106
|
+
createTestCheckpointFile("main", [cp1, cp2]);
|
|
107
|
+
const records = readTestCheckpoints("main");
|
|
108
|
+
expect(records).toHaveLength(2);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe("branch file isolation", () => {
|
|
112
|
+
it("stores checkpoints in separate files per branch", () => {
|
|
113
|
+
const mainCp = { timestamp: "2026-03-12T10:00:00Z", branch: "main", task: "main task", summary: "s" };
|
|
114
|
+
const featureCp = {
|
|
115
|
+
timestamp: "2026-03-12T11:00:00Z",
|
|
116
|
+
branch: "feature/x",
|
|
117
|
+
task: "feature task",
|
|
118
|
+
summary: "s",
|
|
119
|
+
};
|
|
120
|
+
createTestCheckpointFile("main", [mainCp]);
|
|
121
|
+
createTestCheckpointFile("feature/x", [featureCp]);
|
|
122
|
+
expect(readTestCheckpoints("main")).toHaveLength(1);
|
|
123
|
+
expect(readTestCheckpoints("feature/x")).toHaveLength(1);
|
|
124
|
+
});
|
|
125
|
+
it("sanitizes branch names with slashes", () => {
|
|
126
|
+
const dir = path.join(TEST_DIR, ".agents", "checkpoints");
|
|
127
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
128
|
+
const branch = "feature/awesome-thing";
|
|
129
|
+
const safeName = branch.replace(/\//g, "_");
|
|
130
|
+
const filePath = path.join(dir, `${safeName}.jsonl`);
|
|
131
|
+
fs.writeFileSync(filePath, '{"test": true}\n', "utf-8");
|
|
132
|
+
expect(fs.existsSync(filePath)).toBe(true);
|
|
133
|
+
expect(safeName).toBe("feature_awesome-thing");
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe("ISO time filtering", () => {
|
|
137
|
+
it("filters by since date", () => {
|
|
138
|
+
const checkpoints = [
|
|
139
|
+
{ timestamp: "2026-03-10T10:00:00Z" },
|
|
140
|
+
{ timestamp: "2026-03-12T10:00:00Z" },
|
|
141
|
+
{ timestamp: "2026-03-14T10:00:00Z" },
|
|
142
|
+
];
|
|
143
|
+
const since = new Date("2026-03-11T00:00:00Z");
|
|
144
|
+
const filtered = filterByTime(checkpoints, since, undefined);
|
|
145
|
+
expect(filtered).toHaveLength(2);
|
|
146
|
+
});
|
|
147
|
+
it("filters by until date", () => {
|
|
148
|
+
const checkpoints = [
|
|
149
|
+
{ timestamp: "2026-03-10T10:00:00Z" },
|
|
150
|
+
{ timestamp: "2026-03-12T10:00:00Z" },
|
|
151
|
+
{ timestamp: "2026-03-14T10:00:00Z" },
|
|
152
|
+
];
|
|
153
|
+
const until = new Date("2026-03-13T00:00:00Z");
|
|
154
|
+
const filtered = filterByTime(checkpoints, undefined, until);
|
|
155
|
+
expect(filtered).toHaveLength(2);
|
|
156
|
+
});
|
|
157
|
+
it("filters by date range", () => {
|
|
158
|
+
const checkpoints = [
|
|
159
|
+
{ timestamp: "2026-03-10T10:00:00Z" },
|
|
160
|
+
{ timestamp: "2026-03-12T10:00:00Z" },
|
|
161
|
+
{ timestamp: "2026-03-14T10:00:00Z" },
|
|
162
|
+
];
|
|
163
|
+
const since = new Date("2026-03-11T00:00:00Z");
|
|
164
|
+
const until = new Date("2026-03-13T00:00:00Z");
|
|
165
|
+
const filtered = filterByTime(checkpoints, since, until);
|
|
166
|
+
expect(filtered).toHaveLength(1);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe("relativeTime alias filtering", () => {
|
|
170
|
+
it("parses 'today' as start of current day", () => {
|
|
171
|
+
const today = parseRelativeTime("today");
|
|
172
|
+
expect(today).not.toBeNull();
|
|
173
|
+
expect(today.getHours()).toBe(0);
|
|
174
|
+
expect(today.getMinutes()).toBe(0);
|
|
175
|
+
expect(today.getSeconds()).toBe(0);
|
|
176
|
+
});
|
|
177
|
+
it("parses 'yesterday' as start of previous day", () => {
|
|
178
|
+
const yesterday = parseRelativeTime("yesterday");
|
|
179
|
+
const today = parseRelativeTime("today");
|
|
180
|
+
expect(yesterday).not.toBeNull();
|
|
181
|
+
const diffMs = today.getTime() - yesterday.getTime();
|
|
182
|
+
expect(diffMs).toBe(24 * 60 * 60 * 1000);
|
|
183
|
+
});
|
|
184
|
+
it("parses 'last_1h' as 1 hour ago", () => {
|
|
185
|
+
const last1h = parseRelativeTime("last_1h");
|
|
186
|
+
expect(last1h).not.toBeNull();
|
|
187
|
+
const diffMs = Date.now() - last1h.getTime();
|
|
188
|
+
expect(diffMs).toBeGreaterThanOrEqual(60 * 60 * 1000 - 1000);
|
|
189
|
+
expect(diffMs).toBeLessThanOrEqual(60 * 60 * 1000 + 1000);
|
|
190
|
+
});
|
|
191
|
+
it("parses 'last_7d' as 7 days ago", () => {
|
|
192
|
+
const last7d = parseRelativeTime("last_7d");
|
|
193
|
+
expect(last7d).not.toBeNull();
|
|
194
|
+
const diffMs = Date.now() - last7d.getTime();
|
|
195
|
+
expect(diffMs).toBeGreaterThanOrEqual(7 * 24 * 60 * 60 * 1000 - 1000);
|
|
196
|
+
});
|
|
197
|
+
it("filters checkpoints using relative time", () => {
|
|
198
|
+
const now = new Date();
|
|
199
|
+
const oneHourAgo = new Date(now.getTime() - 30 * 60 * 1000); // 30 min ago
|
|
200
|
+
const twoHoursAgo = new Date(now.getTime() - 2 * 60 * 60 * 1000);
|
|
201
|
+
const checkpoints = [
|
|
202
|
+
{ timestamp: twoHoursAgo.toISOString() },
|
|
203
|
+
{ timestamp: oneHourAgo.toISOString() },
|
|
204
|
+
];
|
|
205
|
+
const since = parseRelativeTime("last_1h");
|
|
206
|
+
const filtered = filterByTime(checkpoints, since, undefined);
|
|
207
|
+
expect(filtered).toHaveLength(1);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
describe("keyword matching", () => {
|
|
211
|
+
it("matches query in task", () => {
|
|
212
|
+
const checkpoints = [
|
|
213
|
+
{ task: "implement login", summary: "s1", tags: [] },
|
|
214
|
+
{ task: "fix logout", summary: "s2", tags: [] },
|
|
215
|
+
];
|
|
216
|
+
const filtered = filterByQuery(checkpoints, "login");
|
|
217
|
+
expect(filtered).toHaveLength(1);
|
|
218
|
+
});
|
|
219
|
+
it("matches query in summary", () => {
|
|
220
|
+
const checkpoints = [
|
|
221
|
+
{ task: "t1", summary: "added authentication flow", tags: [] },
|
|
222
|
+
{ task: "t2", summary: "fixed styling", tags: [] },
|
|
223
|
+
];
|
|
224
|
+
const filtered = filterByQuery(checkpoints, "authentication");
|
|
225
|
+
expect(filtered).toHaveLength(1);
|
|
226
|
+
});
|
|
227
|
+
it("matches query in tags", () => {
|
|
228
|
+
const checkpoints = [
|
|
229
|
+
{ task: "t1", summary: "s1", tags: ["mcp", "checkpoint"] },
|
|
230
|
+
{ task: "t2", summary: "s2", tags: ["test"] },
|
|
231
|
+
];
|
|
232
|
+
const filtered = filterByQuery(checkpoints, "mcp");
|
|
233
|
+
expect(filtered).toHaveLength(1);
|
|
234
|
+
});
|
|
235
|
+
it("matches query in references title", () => {
|
|
236
|
+
const checkpoints = [
|
|
237
|
+
{
|
|
238
|
+
task: "t1",
|
|
239
|
+
summary: "s1",
|
|
240
|
+
references: [{ kind: "file", title: "MCP Server Docs", ref: "docs/mcp.md" }],
|
|
241
|
+
},
|
|
242
|
+
{ task: "t2", summary: "s2" },
|
|
243
|
+
];
|
|
244
|
+
const filtered = filterByQuery(checkpoints, "server");
|
|
245
|
+
expect(filtered).toHaveLength(1);
|
|
246
|
+
});
|
|
247
|
+
it("matches query in references ref", () => {
|
|
248
|
+
const checkpoints = [
|
|
249
|
+
{
|
|
250
|
+
task: "t1",
|
|
251
|
+
summary: "s1",
|
|
252
|
+
references: [{ kind: "url", title: "API", ref: "https://example.com/api/auth" }],
|
|
253
|
+
},
|
|
254
|
+
{ task: "t2", summary: "s2" },
|
|
255
|
+
];
|
|
256
|
+
const filtered = filterByQuery(checkpoints, "auth");
|
|
257
|
+
expect(filtered).toHaveLength(1);
|
|
258
|
+
});
|
|
259
|
+
it("is case-insensitive", () => {
|
|
260
|
+
const checkpoints = [{ task: "Implement LOGIN", summary: "S", tags: [] }];
|
|
261
|
+
const filtered = filterByQuery(checkpoints, "login");
|
|
262
|
+
expect(filtered).toHaveLength(1);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
describe("non-git directory fallback", () => {
|
|
266
|
+
it("uses 'default' branch name when not in git repo", () => {
|
|
267
|
+
// Non-git directory would return 'default' from getCurrentBranch
|
|
268
|
+
// We test that the file path is correctly generated
|
|
269
|
+
const branch = "default";
|
|
270
|
+
const filePath = path.join(TEST_DIR, ".agents", "checkpoints", `${branch}.jsonl`);
|
|
271
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
272
|
+
fs.writeFileSync(filePath, '{"test": true}\n', "utf-8");
|
|
273
|
+
expect(fs.existsSync(filePath)).toBe(true);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
//# sourceMappingURL=checkpoints.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoints.test.js","sourceRoot":"","sources":["../src/checkpoints.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoints.validation.test.d.ts","sourceRoot":"","sources":["../src/checkpoints.validation.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { countSentences, SummarySchema } from "./checkpoints.js";
|
|
3
|
+
describe("checkpoints summary validation", () => {
|
|
4
|
+
describe("countSentences", () => {
|
|
5
|
+
it("counts punctuation-delimited sentences", () => {
|
|
6
|
+
expect(countSentences("First sentence. Second sentence!")).toBe(2);
|
|
7
|
+
expect(countSentences("One. Two? Three! Four.")).toBe(4);
|
|
8
|
+
});
|
|
9
|
+
it("treats text without terminal punctuation as one sentence", () => {
|
|
10
|
+
expect(countSentences("Single sentence without punctuation")).toBe(1);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
describe("SummarySchema", () => {
|
|
14
|
+
it("accepts 2-4 sentences", () => {
|
|
15
|
+
expect(SummarySchema.safeParse("Did setup. Added tests.").success).toBe(true);
|
|
16
|
+
expect(SummarySchema.safeParse("A. B. C. D.").success).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it("rejects fewer than 2 sentences", () => {
|
|
19
|
+
const result = SummarySchema.safeParse("Only one sentence.");
|
|
20
|
+
expect(result.success).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it("rejects more than 4 sentences", () => {
|
|
23
|
+
const result = SummarySchema.safeParse("A. B. C. D. E.");
|
|
24
|
+
expect(result.success).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=checkpoints.validation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoints.validation.test.js","sourceRoot":"","sources":["../src/checkpoints.validation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjE,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,CAAC,cAAc,CAAC,kCAAkC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnE,MAAM,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,CAAC,cAAc,CAAC,qCAAqC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9E,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;YACzD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @towry/mcp -
|
|
3
|
+
* @towry/mcp - Grep MCP Server
|
|
4
4
|
*
|
|
5
5
|
* Provides tools for:
|
|
6
|
-
* - Document management in a knowledge graph
|
|
7
6
|
* - Fast grep-based code search
|
|
7
|
+
* - Checkpoint recording and retrieval
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* - KG_API_URL: API base URL (default: http://localhost:8361)
|
|
11
|
-
* - KG_API_KEY or KG_API_TOKEN: API authentication key
|
|
12
|
-
*
|
|
13
|
-
* Keywords: mcp, knowledge-graph, document-management, grep, ai-tools, llm-server
|
|
9
|
+
* Keywords: mcp, grep, ai-tools, llm-server, checkpoints
|
|
14
10
|
*/
|
|
15
11
|
export {};
|
|
16
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG"}
|
package/dist/index.js
CHANGED
|
@@ -1,194 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @towry/mcp -
|
|
3
|
+
* @towry/mcp - Grep MCP Server
|
|
4
4
|
*
|
|
5
5
|
* Provides tools for:
|
|
6
|
-
* - Document management in a knowledge graph
|
|
7
6
|
* - Fast grep-based code search
|
|
7
|
+
* - Checkpoint recording and retrieval
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* - KG_API_URL: API base URL (default: http://localhost:8361)
|
|
11
|
-
* - KG_API_KEY or KG_API_TOKEN: API authentication key
|
|
12
|
-
*
|
|
13
|
-
* Keywords: mcp, knowledge-graph, document-management, grep, ai-tools, llm-server
|
|
9
|
+
* Keywords: mcp, grep, ai-tools, llm-server, checkpoints
|
|
14
10
|
*/
|
|
15
|
-
import { z } from "zod";
|
|
16
11
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
17
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
13
|
import { registerGrepFastTools } from "./grep-fast.js";
|
|
19
|
-
|
|
20
|
-
// Knowledge Graph Types
|
|
21
|
-
// ============================================================================
|
|
22
|
-
const DocTypeEnum = z.enum(["note", "doc", "task", "plan", "agent_session"]);
|
|
23
|
-
const TaskStatusEnum = z.enum(["pending", "in_progress", "done", "blocked"]);
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// Knowledge Graph API Client
|
|
26
|
-
// ============================================================================
|
|
27
|
-
function getKgBaseUrl() {
|
|
28
|
-
return process.env.KG_API_URL ?? "http://localhost:8361";
|
|
29
|
-
}
|
|
30
|
-
function getKgApiKey() {
|
|
31
|
-
return process.env.KG_API_KEY ?? process.env.KG_API_TOKEN ?? "kg-dev-api-key";
|
|
32
|
-
}
|
|
33
|
-
async function kgApiRequest(method, path, body) {
|
|
34
|
-
const url = `${getKgBaseUrl()}${path}`;
|
|
35
|
-
const headers = {
|
|
36
|
-
"X-API-Key": getKgApiKey(),
|
|
37
|
-
"Content-Type": "application/json",
|
|
38
|
-
};
|
|
39
|
-
const res = await fetch(url, {
|
|
40
|
-
method,
|
|
41
|
-
headers,
|
|
42
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
43
|
-
});
|
|
44
|
-
if (!res.ok) {
|
|
45
|
-
const text = await res.text();
|
|
46
|
-
throw new Error(`API error ${res.status}: ${text}`);
|
|
47
|
-
}
|
|
48
|
-
return res.json();
|
|
49
|
-
}
|
|
14
|
+
import { registerCheckpointTools } from "./checkpoints.js";
|
|
50
15
|
// ============================================================================
|
|
51
16
|
// MCP Server
|
|
52
17
|
// ============================================================================
|
|
53
18
|
const server = new McpServer({
|
|
54
19
|
name: "towry-mcp",
|
|
55
|
-
version: "0.
|
|
56
|
-
});
|
|
57
|
-
// ============================================================================
|
|
58
|
-
// Knowledge Graph Tools
|
|
59
|
-
// ============================================================================
|
|
60
|
-
// kg_create_doc - Create or update a document
|
|
61
|
-
server.registerTool("kg_create_doc", {
|
|
62
|
-
description: "Create or update a document. Use 'note' for session learnings (ephemeral), 'doc' for stable reference docs, 'plan' for roadmaps, 'task' for actionable items. For insights from current chat, prefer kg_insight_save.",
|
|
63
|
-
inputSchema: {
|
|
64
|
-
title: z.string().describe("Document title"),
|
|
65
|
-
body: z.string().describe("Document content"),
|
|
66
|
-
doc_type: DocTypeEnum.describe("note: session learnings (ephemeral), doc: stable reference, task: actionable items, plan: roadmaps, agent_session: chat logs"),
|
|
67
|
-
id: z.string().optional().describe("UUID to update existing doc"),
|
|
68
|
-
project_repo: z.string().optional().describe("Project repo (owner/repo)"),
|
|
69
|
-
tags: z.array(z.string()).optional().describe("Tags for categorization"),
|
|
70
|
-
status: TaskStatusEnum.optional().describe("Task status (only for task type)"),
|
|
71
|
-
parent_id: z
|
|
72
|
-
.string()
|
|
73
|
-
.optional()
|
|
74
|
-
.describe("Parent document ID for hierarchy"),
|
|
75
|
-
},
|
|
76
|
-
}, async (params) => {
|
|
77
|
-
const result = await kgApiRequest("POST", "/api/docs", {
|
|
78
|
-
...params,
|
|
79
|
-
doc_type: params.doc_type ?? "note",
|
|
80
|
-
});
|
|
81
|
-
return {
|
|
82
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
83
|
-
};
|
|
84
|
-
});
|
|
85
|
-
// kg_get_doc - Get full document by ID
|
|
86
|
-
server.registerTool("kg_get_doc", {
|
|
87
|
-
description: "Get full document by ID. Use AFTER kg_search when you need the complete body (snippets are truncated).",
|
|
88
|
-
inputSchema: {
|
|
89
|
-
id: z.string().describe("Document UUID"),
|
|
90
|
-
},
|
|
91
|
-
}, async (params) => {
|
|
92
|
-
const result = await kgApiRequest("GET", `/api/docs/${params.id}`);
|
|
93
|
-
return {
|
|
94
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
95
|
-
};
|
|
96
|
-
});
|
|
97
|
-
// kg_delete_doc - Delete a document
|
|
98
|
-
server.registerTool("kg_delete_doc", {
|
|
99
|
-
description: "Delete a document from the knowledge graph.",
|
|
100
|
-
inputSchema: {
|
|
101
|
-
id: z.string().describe("Document UUID to delete"),
|
|
102
|
-
},
|
|
103
|
-
}, async (params) => {
|
|
104
|
-
const result = await kgApiRequest("DELETE", `/api/docs/${params.id}`);
|
|
105
|
-
return {
|
|
106
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
107
|
-
};
|
|
108
|
-
});
|
|
109
|
-
// kg_search - Search documents
|
|
110
|
-
server.registerTool("kg_search", {
|
|
111
|
-
description: "Find plans, tasks, or docs. Use doc_type='plan' for plans, tag='insight' for insights. Returns snippets - use kg_get_doc for full content.",
|
|
112
|
-
inputSchema: {
|
|
113
|
-
q: z
|
|
114
|
-
.string()
|
|
115
|
-
.optional()
|
|
116
|
-
.describe("Search query (optional - omit to list all of doc_type)"),
|
|
117
|
-
doc_type: DocTypeEnum.optional().describe("Filter by type: 'plan' for plans, 'note' for insights/learnings"),
|
|
118
|
-
project_repo: z.string().optional().describe("Filter by project repo"),
|
|
119
|
-
status: TaskStatusEnum.optional().describe("Filter by task status"),
|
|
120
|
-
tag: z.string().optional().describe("Filter by tag"),
|
|
121
|
-
limit: z.number().int().min(1).max(100).default(20).optional(),
|
|
122
|
-
offset: z.number().int().min(0).default(0).optional(),
|
|
123
|
-
},
|
|
124
|
-
}, async (params) => {
|
|
125
|
-
const searchParams = new URLSearchParams();
|
|
126
|
-
if (params.q)
|
|
127
|
-
searchParams.set("q", params.q);
|
|
128
|
-
if (params.doc_type)
|
|
129
|
-
searchParams.set("doc_type", params.doc_type);
|
|
130
|
-
if (params.project_repo)
|
|
131
|
-
searchParams.set("project_repo", params.project_repo);
|
|
132
|
-
if (params.status)
|
|
133
|
-
searchParams.set("status", params.status);
|
|
134
|
-
if (params.tag)
|
|
135
|
-
searchParams.set("tag", params.tag);
|
|
136
|
-
if (params.limit)
|
|
137
|
-
searchParams.set("limit", String(params.limit));
|
|
138
|
-
if (params.offset)
|
|
139
|
-
searchParams.set("offset", String(params.offset));
|
|
140
|
-
const result = await kgApiRequest("GET", `/api/docs/search?${searchParams.toString()}`);
|
|
141
|
-
return {
|
|
142
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
143
|
-
};
|
|
144
|
-
});
|
|
145
|
-
// kg_semantic_search - Semantic search using embeddings
|
|
146
|
-
server.registerTool("kg_semantic_search", {
|
|
147
|
-
description: "Semantic search using embeddings in the knowledge graph.",
|
|
148
|
-
inputSchema: {
|
|
149
|
-
q: z.string().describe("Search query (required)"),
|
|
150
|
-
embedding_keywords: z
|
|
151
|
-
.array(z.string())
|
|
152
|
-
.optional()
|
|
153
|
-
.describe("Keywords for embedding search. If provided, searches with these keywords. If not, fetches latest 2 docs."),
|
|
154
|
-
doc_type: DocTypeEnum.optional().describe("Filter by document type"),
|
|
155
|
-
project_repo: z.string().optional().describe("Filter by project repo"),
|
|
156
|
-
tag: z.string().optional().describe("Filter by tag"),
|
|
157
|
-
limit: z.number().int().min(1).max(20).default(5).optional(),
|
|
158
|
-
},
|
|
159
|
-
}, async (params) => {
|
|
160
|
-
const searchParams = new URLSearchParams();
|
|
161
|
-
const searchQuery = params.embedding_keywords && params.embedding_keywords.length > 0
|
|
162
|
-
? params.embedding_keywords.join(" ")
|
|
163
|
-
: params.q;
|
|
164
|
-
searchParams.set("q", searchQuery);
|
|
165
|
-
if (params.doc_type)
|
|
166
|
-
searchParams.set("doc_type", params.doc_type);
|
|
167
|
-
if (params.project_repo)
|
|
168
|
-
searchParams.set("project_repo", params.project_repo);
|
|
169
|
-
if (params.tag)
|
|
170
|
-
searchParams.set("tag", params.tag);
|
|
171
|
-
if (params.limit)
|
|
172
|
-
searchParams.set("limit", String(params.limit));
|
|
173
|
-
const result = await kgApiRequest("GET", `/api/docs/semantic?${searchParams.toString()}`);
|
|
174
|
-
return {
|
|
175
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
176
|
-
};
|
|
177
|
-
});
|
|
178
|
-
// kg_status - Get document statistics
|
|
179
|
-
server.registerTool("kg_status", {
|
|
180
|
-
description: "Get document statistics: total count, breakdown by type (plan/task/doc/note) and by repo. Use to check what's stored before searching.",
|
|
181
|
-
inputSchema: {},
|
|
182
|
-
}, async () => {
|
|
183
|
-
const result = await kgApiRequest("GET", "/api/docs/status");
|
|
184
|
-
return {
|
|
185
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
186
|
-
};
|
|
20
|
+
version: "0.4.0",
|
|
187
21
|
});
|
|
188
22
|
// ============================================================================
|
|
189
|
-
//
|
|
23
|
+
// Tools Registration
|
|
190
24
|
// ============================================================================
|
|
191
25
|
registerGrepFastTools(server);
|
|
26
|
+
registerCheckpointTools(server);
|
|
192
27
|
// ============================================================================
|
|
193
28
|
// Start Server
|
|
194
29
|
// ============================================================================
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAEhC,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoints library - Core functions for pi extension
|
|
3
|
+
*
|
|
4
|
+
* Re-exports checkpoint utilities without MCP server side effects.
|
|
5
|
+
*/
|
|
6
|
+
export { type Checkpoint, type Reference, CheckpointSchema, ReferenceSchema, SummarySchema, RELATIVE_TIME_ALIASES, parseRelativeTime, getCurrentBranch, getGitRoot, sanitizeBranchName, getCheckpointsDir, getCheckpointFilePath, appendCheckpoint, readCheckpoints, filterByTime, filterByQuery, formatCheckpoints, } from "./checkpoints.js";
|
|
7
|
+
//# sourceMappingURL=lib.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,KAAK,SAAS,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,kBAAkB,CAAC"}
|
package/dist/lib.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoints library - Core functions for pi extension
|
|
3
|
+
*
|
|
4
|
+
* Re-exports checkpoint utilities without MCP server side effects.
|
|
5
|
+
*/
|
|
6
|
+
export { CheckpointSchema, ReferenceSchema, SummarySchema, RELATIVE_TIME_ALIASES, parseRelativeTime, getCurrentBranch, getGitRoot, sanitizeBranchName, getCheckpointsDir, getCheckpointFilePath, appendCheckpoint, readCheckpoints, filterByTime, filterByQuery, formatCheckpoints, } from "./checkpoints.js";
|
|
7
|
+
//# sourceMappingURL=lib.js.map
|
package/dist/lib.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAGL,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@towry/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "MCP server implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
".": {
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./lib": {
|
|
17
|
+
"types": "./dist/lib.d.ts",
|
|
18
|
+
"import": "./dist/lib.js"
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
21
|
"files": [
|