pathmark 0.1.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 +21 -0
- package/README.md +339 -0
- package/SECURITY.md +39 -0
- package/assets/pathmark-icon-v3-glyph.png +0 -0
- package/dist/chat.d.ts +6 -0
- package/dist/chat.js +169 -0
- package/dist/chat.js.map +1 -0
- package/dist/codex/capture.d.ts +12 -0
- package/dist/codex/capture.js +328 -0
- package/dist/codex/capture.js.map +1 -0
- package/dist/codex/cli.d.ts +1 -0
- package/dist/codex/cli.js +96 -0
- package/dist/codex/cli.js.map +1 -0
- package/dist/codex/config-file.d.ts +9 -0
- package/dist/codex/config-file.js +100 -0
- package/dist/codex/config-file.js.map +1 -0
- package/dist/codex/cursor.d.ts +11 -0
- package/dist/codex/cursor.js +35 -0
- package/dist/codex/cursor.js.map +1 -0
- package/dist/codex/hooks.d.ts +10 -0
- package/dist/codex/hooks.js +108 -0
- package/dist/codex/hooks.js.map +1 -0
- package/dist/codex/paths.d.ts +5 -0
- package/dist/codex/paths.js +29 -0
- package/dist/codex/paths.js.map +1 -0
- package/dist/codex/tool-summary.d.ts +5 -0
- package/dist/codex/tool-summary.js +223 -0
- package/dist/codex/tool-summary.js.map +1 -0
- package/dist/codex/transcript.d.ts +9 -0
- package/dist/codex/transcript.js +99 -0
- package/dist/codex/transcript.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +40 -0
- package/dist/config.js.map +1 -0
- package/dist/format.d.ts +10 -0
- package/dist/format.js +48 -0
- package/dist/format.js.map +1 -0
- package/dist/ids.d.ts +1 -0
- package/dist/ids.js +6 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.js +130 -0
- package/dist/mcp.js.map +1 -0
- package/dist/redact.d.ts +5 -0
- package/dist/redact.js +36 -0
- package/dist/redact.js.map +1 -0
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +208 -0
- package/dist/setup.js.map +1 -0
- package/dist/store.d.ts +27 -0
- package/dist/store.js +174 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/examples/claude_code.md +21 -0
- package/examples/claude_desktop_config.json +10 -0
- package/examples/codex.md +39 -0
- package/examples/cursor_mcp_config.json +10 -0
- package/examples/gemini_settings.json +12 -0
- package/examples/generic_mcp_config.json +12 -0
- package/examples/openai_compatible.env +8 -0
- package/examples/opencode.jsonc +13 -0
- package/package.json +66 -0
- package/scripts/import-honcho.mjs +243 -0
package/dist/ids.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,eAAe,CAAC,KAAe;IAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7E,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;AACtH,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runMcpServer } from "./mcp.js";
|
|
3
|
+
const [domain, ...rest] = process.argv.slice(2);
|
|
4
|
+
if (domain === "codex") {
|
|
5
|
+
const { runCodexCommand } = await import("./codex/cli.js");
|
|
6
|
+
await runCodexCommand(rest);
|
|
7
|
+
}
|
|
8
|
+
else if (domain === "setup") {
|
|
9
|
+
const { runSetupCommand } = await import("./setup.js");
|
|
10
|
+
await runSetupCommand(rest);
|
|
11
|
+
}
|
|
12
|
+
else if (domain === "help" || domain === "--help" || domain === "-h") {
|
|
13
|
+
console.log("Usage: pathmark [setup <client>|codex <command>]");
|
|
14
|
+
console.log("");
|
|
15
|
+
console.log("No arguments starts the Pathmark MCP stdio server.");
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
if (domain) {
|
|
19
|
+
console.error(`Unknown command: ${domain}`);
|
|
20
|
+
console.error("Usage: pathmark [setup <client>|codex <command>]");
|
|
21
|
+
process.exitCode = 2;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
await runMcpServer();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEhD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC3D,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;KAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;IAC9B,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IACvD,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;KAAM,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;IAChE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;AACpE,CAAC;KAAM,CAAC;IACN,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,oBAAoB,MAAM,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAClE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,MAAM,YAAY,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runMcpServer(): Promise<void>;
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { synthesizeWithCommand } from "./chat.js";
|
|
5
|
+
import { loadConfig } from "./config.js";
|
|
6
|
+
import { jsonText, publicConfig, summarizeRecords, summarizeSearch } from "./format.js";
|
|
7
|
+
import { PathmarkStore } from "./store.js";
|
|
8
|
+
export async function runMcpServer() {
|
|
9
|
+
const config = loadConfig();
|
|
10
|
+
const store = new PathmarkStore(config);
|
|
11
|
+
const server = new McpServer({
|
|
12
|
+
name: "pathmark",
|
|
13
|
+
version: "0.1.0",
|
|
14
|
+
});
|
|
15
|
+
server.registerTool("get_config", {
|
|
16
|
+
title: "Get Pathmark configuration",
|
|
17
|
+
description: "Show the local Pathmark Memory store location and enabled optional features.",
|
|
18
|
+
inputSchema: {},
|
|
19
|
+
}, async () => jsonText(publicConfig(config)));
|
|
20
|
+
server.registerTool("remember", {
|
|
21
|
+
title: "Remember",
|
|
22
|
+
description: "Save a durable local memory item.",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
text: z.string().min(1).describe("Memory text to save."),
|
|
25
|
+
tags: z.array(z.string()).optional().describe("Optional lowercase-ish tags for later filtering."),
|
|
26
|
+
source: z.string().optional().describe("Optional source label, such as repo, thread, or tool name."),
|
|
27
|
+
},
|
|
28
|
+
}, async ({ text, tags, source }) => {
|
|
29
|
+
const record = await store.add({ kind: "memory", text, tags, source });
|
|
30
|
+
return jsonText(record);
|
|
31
|
+
});
|
|
32
|
+
server.registerTool("create_conclusion", {
|
|
33
|
+
title: "Create conclusion",
|
|
34
|
+
description: "Save a durable conclusion or preference that should be treated as higher-signal than raw memory.",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
text: z.string().min(1).describe("Conclusion text to save."),
|
|
37
|
+
tags: z.array(z.string()).optional(),
|
|
38
|
+
source: z.string().optional(),
|
|
39
|
+
},
|
|
40
|
+
}, async ({ text, tags, source }) => {
|
|
41
|
+
const record = await store.add({ kind: "conclusion", text, tags, source });
|
|
42
|
+
return jsonText(record);
|
|
43
|
+
});
|
|
44
|
+
server.registerTool("search_memory", {
|
|
45
|
+
title: "Search memory",
|
|
46
|
+
description: "Search saved local memories and conclusions.",
|
|
47
|
+
inputSchema: {
|
|
48
|
+
query: z.string().default("").describe("Search query. Empty query returns recent records."),
|
|
49
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
50
|
+
tags: z.array(z.string()).optional(),
|
|
51
|
+
kind: z.enum(["memory", "conclusion"]).optional(),
|
|
52
|
+
},
|
|
53
|
+
}, async ({ query, limit, tags, kind }) => {
|
|
54
|
+
const results = await store.search({ query, limit, tags, kind });
|
|
55
|
+
return jsonText({
|
|
56
|
+
results: results.map((result) => ({
|
|
57
|
+
...result.record,
|
|
58
|
+
score: result.score,
|
|
59
|
+
matchedTerms: result.matchedTerms,
|
|
60
|
+
})),
|
|
61
|
+
summary: summarizeSearch(results),
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
server.registerTool("get_context", {
|
|
65
|
+
title: "Get context",
|
|
66
|
+
description: "Return compact local memory context for a task or question.",
|
|
67
|
+
inputSchema: {
|
|
68
|
+
query: z.string().default("").describe("Task or question to retrieve context for."),
|
|
69
|
+
limit: z.number().int().min(1).max(30).optional(),
|
|
70
|
+
},
|
|
71
|
+
}, async ({ query, limit }) => {
|
|
72
|
+
const results = await store.search({ query, limit });
|
|
73
|
+
return jsonText({
|
|
74
|
+
context: summarizeSearch(results),
|
|
75
|
+
records: results.map((result) => result.record),
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
server.registerTool("list_conclusions", {
|
|
79
|
+
title: "List conclusions",
|
|
80
|
+
description: "List saved durable conclusions.",
|
|
81
|
+
inputSchema: {
|
|
82
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
83
|
+
},
|
|
84
|
+
}, async ({ limit }) => {
|
|
85
|
+
const records = (await store.all({ kind: "conclusion" })).slice(0, limit ?? 50);
|
|
86
|
+
return jsonText({
|
|
87
|
+
records,
|
|
88
|
+
summary: summarizeRecords(records),
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
server.registerTool("delete_memory", {
|
|
92
|
+
title: "Delete memory",
|
|
93
|
+
description: "Soft-delete a saved memory or conclusion by id.",
|
|
94
|
+
inputSchema: {
|
|
95
|
+
id: z.string().min(1),
|
|
96
|
+
},
|
|
97
|
+
}, async ({ id }) => {
|
|
98
|
+
const deleted = await store.delete(id);
|
|
99
|
+
return jsonText({ deleted: deleted ?? null });
|
|
100
|
+
});
|
|
101
|
+
server.registerTool("ask_memory", {
|
|
102
|
+
title: "Ask memory",
|
|
103
|
+
description: "Retrieve relevant context and optionally synthesize an answer through PATHMARK_CHAT_COMMAND. Without a command, returns context for the MCP client to synthesize.",
|
|
104
|
+
inputSchema: {
|
|
105
|
+
question: z.string().min(1),
|
|
106
|
+
limit: z.number().int().min(1).max(30).optional(),
|
|
107
|
+
},
|
|
108
|
+
}, async ({ question, limit }) => answerFromMemory(question, limit));
|
|
109
|
+
server.registerTool("chat", {
|
|
110
|
+
title: "Chat",
|
|
111
|
+
description: "Ask Pathmark memory a question. Returns the exact retrieved context so the MCP client can show what memory was used.",
|
|
112
|
+
inputSchema: {
|
|
113
|
+
question: z.string().min(1),
|
|
114
|
+
limit: z.number().int().min(1).max(30).optional(),
|
|
115
|
+
},
|
|
116
|
+
}, async ({ question, limit }) => answerFromMemory(question, limit));
|
|
117
|
+
await store.ensureReady();
|
|
118
|
+
await server.connect(new StdioServerTransport());
|
|
119
|
+
async function answerFromMemory(question, limit) {
|
|
120
|
+
const results = await store.search({ query: question, limit });
|
|
121
|
+
const answer = await synthesizeWithCommand({ config, question, context: results });
|
|
122
|
+
return jsonText({
|
|
123
|
+
answer: answer ?? null,
|
|
124
|
+
synthesis: answer ? "server_command" : "client_should_synthesize",
|
|
125
|
+
context: summarizeSearch(results),
|
|
126
|
+
records: results.map((result) => result.record),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
package/dist/redact.d.ts
ADDED
package/dist/redact.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const ENV_SECRET_RE = /\b([A-Z0-9_]*(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PRIVATE[_-]?KEY)[A-Z0-9_]*\s*[:=]\s*)(?:"[\s\S]*?"|'[\s\S]*?'|[^\s'",;}]+)/gi;
|
|
2
|
+
const ENV_URL_OR_DSN_RE = /\b([A-Z0-9_]*(?:DATABASE_URL|REDIS_URL|MONGO_URL|DSN|[A-Z0-9_]+_URL)[A-Z0-9_]*)(\s*[:=]\s*)("[^"]*"|'[^']*'|[^\s'",;}]+)/gi;
|
|
3
|
+
const BEARER_RE = /\bBearer\s+[A-Za-z0-9._~+/=-]+/gi;
|
|
4
|
+
const STANDALONE_OPENAI_KEY_RE = /\bsk-(?:proj-)?[A-Za-z0-9_-]{16,}\b/g;
|
|
5
|
+
const CREDENTIAL_URL_RE = /^[a-z][a-z0-9+.-]*:\/\/[^/\s:@]+:[^@\s]+@/i;
|
|
6
|
+
export function redactSecrets(text) {
|
|
7
|
+
let redacted = false;
|
|
8
|
+
const safeText = text
|
|
9
|
+
.replace(ENV_SECRET_RE, (_match, prefix) => {
|
|
10
|
+
redacted = true;
|
|
11
|
+
return `${prefix}[REDACTED]`;
|
|
12
|
+
})
|
|
13
|
+
.replace(ENV_URL_OR_DSN_RE, (match, name, separator, value) => {
|
|
14
|
+
const normalizedName = name.toUpperCase();
|
|
15
|
+
const unquotedValue = value.replace(/^(['"])([\s\S]*)\1$/, "$2");
|
|
16
|
+
const isDsn = normalizedName.includes("DSN");
|
|
17
|
+
const isUrlName = normalizedName.includes("DATABASE_URL") ||
|
|
18
|
+
normalizedName.includes("REDIS_URL") ||
|
|
19
|
+
normalizedName.includes("MONGO_URL") ||
|
|
20
|
+
normalizedName.includes("_URL");
|
|
21
|
+
if (!isDsn && (!isUrlName || !CREDENTIAL_URL_RE.test(unquotedValue)))
|
|
22
|
+
return match;
|
|
23
|
+
redacted = true;
|
|
24
|
+
return `${name}${separator}[REDACTED]`;
|
|
25
|
+
})
|
|
26
|
+
.replace(BEARER_RE, () => {
|
|
27
|
+
redacted = true;
|
|
28
|
+
return "Bearer [REDACTED]";
|
|
29
|
+
})
|
|
30
|
+
.replace(STANDALONE_OPENAI_KEY_RE, () => {
|
|
31
|
+
redacted = true;
|
|
32
|
+
return "[REDACTED]";
|
|
33
|
+
});
|
|
34
|
+
return { text: safeText, redacted };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAKA,MAAM,aAAa,GACjB,gIAAgI,CAAC;AACnI,MAAM,iBAAiB,GACrB,4HAA4H,CAAC;AAC/H,MAAM,SAAS,GAAG,kCAAkC,CAAC;AACrD,MAAM,wBAAwB,GAAG,sCAAsC,CAAC;AACxE,MAAM,iBAAiB,GAAG,4CAA4C,CAAC;AAEvE,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,MAAM,QAAQ,GAAG,IAAI;SAClB,OAAO,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAc,EAAE,EAAE;QACjD,QAAQ,GAAG,IAAI,CAAC;QAChB,OAAO,GAAG,MAAM,YAAY,CAAC;IAC/B,CAAC,CAAC;SACD,OAAO,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,IAAY,EAAE,SAAiB,EAAE,KAAa,EAAE,EAAE;QACpF,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;QACjE,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,SAAS,GACb,cAAc,CAAC,QAAQ,CAAC,cAAc,CAAC;YACvC,cAAc,CAAC,QAAQ,CAAC,WAAW,CAAC;YACpC,cAAc,CAAC,QAAQ,CAAC,WAAW,CAAC;YACpC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAEnF,QAAQ,GAAG,IAAI,CAAC;QAChB,OAAO,GAAG,IAAI,GAAG,SAAS,YAAY,CAAC;IACzC,CAAC,CAAC;SACD,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,QAAQ,GAAG,IAAI,CAAC;QAChB,OAAO,mBAAmB,CAAC;IAC7B,CAAC,CAAC;SACD,OAAO,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACtC,QAAQ,GAAG,IAAI,CAAC;QAChB,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC,CAAC;IAEL,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACtC,CAAC"}
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runSetupCommand(args: string[]): Promise<void>;
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { loadConfig } from "./config.js";
|
|
2
|
+
const TARGET_ALIASES = {
|
|
3
|
+
codex: "codex",
|
|
4
|
+
"claude-code": "claude-code",
|
|
5
|
+
claude: "claude-code",
|
|
6
|
+
"claude-desktop": "claude-desktop",
|
|
7
|
+
"claude_desktop": "claude-desktop",
|
|
8
|
+
cursor: "cursor",
|
|
9
|
+
opencode: "opencode",
|
|
10
|
+
"open-code": "opencode",
|
|
11
|
+
gemini: "gemini-cli",
|
|
12
|
+
"gemini-cli": "gemini-cli",
|
|
13
|
+
generic: "generic",
|
|
14
|
+
mcp: "generic",
|
|
15
|
+
"openai-compatible": "openai-compatible",
|
|
16
|
+
openai: "openai-compatible",
|
|
17
|
+
kimi: "openai-compatible",
|
|
18
|
+
glm: "openai-compatible",
|
|
19
|
+
zai: "openai-compatible",
|
|
20
|
+
"z-ai": "openai-compatible",
|
|
21
|
+
command: "command",
|
|
22
|
+
cli: "command",
|
|
23
|
+
};
|
|
24
|
+
const TARGETS = [
|
|
25
|
+
"codex",
|
|
26
|
+
"claude-code",
|
|
27
|
+
"claude-desktop",
|
|
28
|
+
"cursor",
|
|
29
|
+
"opencode",
|
|
30
|
+
"gemini-cli",
|
|
31
|
+
"generic",
|
|
32
|
+
"openai-compatible",
|
|
33
|
+
"command",
|
|
34
|
+
];
|
|
35
|
+
export async function runSetupCommand(args) {
|
|
36
|
+
const json = args.includes("--json");
|
|
37
|
+
const targetArg = args.find((arg) => !arg.startsWith("-"));
|
|
38
|
+
if (!targetArg || targetArg === "list") {
|
|
39
|
+
if (json) {
|
|
40
|
+
console.log(JSON.stringify({ targets: TARGETS }, null, 2));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
console.log(`Usage: pathmark setup <${TARGETS.join("|")}> [--json]`);
|
|
44
|
+
console.log("");
|
|
45
|
+
console.log("Targets:");
|
|
46
|
+
for (const target of TARGETS)
|
|
47
|
+
console.log(` ${target}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const target = TARGET_ALIASES[targetArg.toLowerCase()];
|
|
51
|
+
if (!target) {
|
|
52
|
+
console.error(`Unknown setup target: ${targetArg}`);
|
|
53
|
+
console.error(`Usage: pathmark setup <${TARGETS.join("|")}> [--json]`);
|
|
54
|
+
process.exitCode = 2;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const guide = setupGuide(target);
|
|
58
|
+
if (json) {
|
|
59
|
+
console.log(JSON.stringify(guide, null, 2));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log(renderGuide(guide));
|
|
63
|
+
}
|
|
64
|
+
function setupGuide(target) {
|
|
65
|
+
const config = loadConfig();
|
|
66
|
+
const env = {
|
|
67
|
+
PATHMARK_STORE_DIR: config.storeDir,
|
|
68
|
+
PATHMARK_SYNTHESIS_PROVIDER: "client",
|
|
69
|
+
};
|
|
70
|
+
if (target === "codex") {
|
|
71
|
+
return {
|
|
72
|
+
target,
|
|
73
|
+
title: "Codex",
|
|
74
|
+
summary: "Register Pathmark as a Codex MCP server and optionally enable Codex auto-capture hooks.",
|
|
75
|
+
commands: ["codex mcp add pathmark -- pathmark", "pathmark codex install --replace-honcho"],
|
|
76
|
+
env,
|
|
77
|
+
notes: [
|
|
78
|
+
"Use the install command when you want automatic Codex prompt/tool/transcript capture.",
|
|
79
|
+
"The --replace-honcho flag removes old Honcho hook commands but does not delete ~/.honcho/codex/local.",
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (target === "claude-code") {
|
|
84
|
+
return {
|
|
85
|
+
target,
|
|
86
|
+
title: "Claude Code",
|
|
87
|
+
summary: "Register Pathmark as a local stdio MCP server in Claude Code.",
|
|
88
|
+
commands: ["claude mcp add pathmark -- pathmark"],
|
|
89
|
+
env,
|
|
90
|
+
notes: [
|
|
91
|
+
"Keep synthesis in client mode so Claude Code's own model answers from returned memory context.",
|
|
92
|
+
"Use the same PATHMARK_STORE_DIR as Codex to share memory across harnesses.",
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (target === "opencode") {
|
|
97
|
+
return {
|
|
98
|
+
target,
|
|
99
|
+
title: "opencode",
|
|
100
|
+
summary: "Add Pathmark as a local MCP server in opencode config.",
|
|
101
|
+
config: {
|
|
102
|
+
mcp: {
|
|
103
|
+
pathmark: {
|
|
104
|
+
type: "local",
|
|
105
|
+
command: ["pathmark"],
|
|
106
|
+
enabled: true,
|
|
107
|
+
environment: env,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
notes: ["Merge this into your opencode config and keep the same store directory across harnesses."],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (target === "gemini-cli") {
|
|
115
|
+
return {
|
|
116
|
+
target,
|
|
117
|
+
title: "Gemini CLI",
|
|
118
|
+
summary: "Add Pathmark to Gemini CLI's mcpServers settings.",
|
|
119
|
+
config: {
|
|
120
|
+
mcpServers: {
|
|
121
|
+
pathmark: {
|
|
122
|
+
command: "pathmark",
|
|
123
|
+
args: [],
|
|
124
|
+
env,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
notes: ["Place this in the Gemini CLI settings file that defines MCP servers."],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (target === "claude-desktop" || target === "cursor" || target === "generic") {
|
|
132
|
+
const title = target === "claude-desktop" ? "Claude Desktop" : target === "cursor" ? "Cursor" : "Generic MCP Client";
|
|
133
|
+
return {
|
|
134
|
+
target,
|
|
135
|
+
title,
|
|
136
|
+
summary: "Add Pathmark as a local stdio MCP server.",
|
|
137
|
+
config: {
|
|
138
|
+
mcpServers: {
|
|
139
|
+
pathmark: {
|
|
140
|
+
command: "pathmark",
|
|
141
|
+
env,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
notes: ["Use this shape for MCP clients that accept mcpServers JSON."],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (target === "openai-compatible") {
|
|
149
|
+
return {
|
|
150
|
+
target,
|
|
151
|
+
title: "Kimi, GLM/Z.ai, OpenRouter, LiteLLM, or local OpenAI-compatible gateway",
|
|
152
|
+
summary: "Use Pathmark with an MCP host, and optionally let ask_memory synthesize through a compatible API.",
|
|
153
|
+
env: {
|
|
154
|
+
PATHMARK_STORE_DIR: config.storeDir,
|
|
155
|
+
PATHMARK_SYNTHESIS_PROVIDER: "openai-compatible",
|
|
156
|
+
PATHMARK_OPENAI_BASE_URL: "https://api.provider.example/v1",
|
|
157
|
+
PATHMARK_OPENAI_API_KEY: "replace-me",
|
|
158
|
+
PATHMARK_OPENAI_MODEL: "replace-me",
|
|
159
|
+
},
|
|
160
|
+
notes: [
|
|
161
|
+
"Raw models still need an MCP-capable host to call Pathmark tools.",
|
|
162
|
+
"The OpenAI-compatible mode affects ask_memory synthesis only; save/search tools remain local.",
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
target,
|
|
168
|
+
title: "Command-backed synthesis",
|
|
169
|
+
summary: "Use any local subscription CLI or model command for ask_memory synthesis.",
|
|
170
|
+
env: {
|
|
171
|
+
PATHMARK_STORE_DIR: config.storeDir,
|
|
172
|
+
PATHMARK_SYNTHESIS_PROVIDER: "command",
|
|
173
|
+
PATHMARK_CHAT_COMMAND: "your-agent-cli chat --model your-model",
|
|
174
|
+
},
|
|
175
|
+
notes: ["PATHMARK_CHAT_COMMAND receives the memory prompt on stdin and must write an answer to stdout."],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function renderGuide(guide) {
|
|
179
|
+
const lines = [`# ${guide.title}`, "", guide.summary, ""];
|
|
180
|
+
if (guide.commands?.length) {
|
|
181
|
+
lines.push("Commands:", "");
|
|
182
|
+
lines.push(...guide.commands.map((command) => ` ${command}`));
|
|
183
|
+
lines.push("");
|
|
184
|
+
}
|
|
185
|
+
if (guide.config) {
|
|
186
|
+
lines.push("Config:", "");
|
|
187
|
+
lines.push(JSON.stringify(guide.config, null, 2));
|
|
188
|
+
lines.push("");
|
|
189
|
+
}
|
|
190
|
+
if (guide.env) {
|
|
191
|
+
lines.push("Environment:", "");
|
|
192
|
+
for (const [key, value] of Object.entries(guide.env))
|
|
193
|
+
lines.push(` ${key}=${shellQuote(value)}`);
|
|
194
|
+
lines.push("");
|
|
195
|
+
}
|
|
196
|
+
if (guide.notes.length) {
|
|
197
|
+
lines.push("Notes:");
|
|
198
|
+
for (const note of guide.notes)
|
|
199
|
+
lines.push(` - ${note}`);
|
|
200
|
+
}
|
|
201
|
+
return lines.join("\n");
|
|
202
|
+
}
|
|
203
|
+
function shellQuote(value) {
|
|
204
|
+
if (/^[A-Za-z0-9_./:@-]+$/.test(value))
|
|
205
|
+
return value;
|
|
206
|
+
return JSON.stringify(value);
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PathmarkConfig, PathmarkRecord, PathmarkRecordDraft, PathmarkRecordKind, SearchResult } from "./types.js";
|
|
2
|
+
export declare class PathmarkStore {
|
|
3
|
+
private readonly config;
|
|
4
|
+
constructor(config: PathmarkConfig);
|
|
5
|
+
ensureReady(): Promise<void>;
|
|
6
|
+
add(input: PathmarkRecordDraft): Promise<PathmarkRecord>;
|
|
7
|
+
addRecord(input: PathmarkRecordDraft): Promise<{
|
|
8
|
+
record: PathmarkRecord;
|
|
9
|
+
created: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
all(options?: {
|
|
12
|
+
includeDeleted?: boolean;
|
|
13
|
+
kind?: PathmarkRecordKind;
|
|
14
|
+
}): Promise<PathmarkRecord[]>;
|
|
15
|
+
count(): Promise<number>;
|
|
16
|
+
delete(id: string): Promise<PathmarkRecord | undefined>;
|
|
17
|
+
search(input: {
|
|
18
|
+
query: string;
|
|
19
|
+
limit?: number;
|
|
20
|
+
tags?: string[];
|
|
21
|
+
kind?: PathmarkRecordKind;
|
|
22
|
+
}): Promise<SearchResult[]>;
|
|
23
|
+
private readRecords;
|
|
24
|
+
private append;
|
|
25
|
+
private rewrite;
|
|
26
|
+
private withWriteLock;
|
|
27
|
+
}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { appendFile, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const WORD_RE = /[\p{L}\p{N}_'-]+/gu;
|
|
5
|
+
const LOCK_RETRY_MS = 10;
|
|
6
|
+
const LOCK_TIMEOUT_MS = 5000;
|
|
7
|
+
export class PathmarkStore {
|
|
8
|
+
config;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
}
|
|
12
|
+
async ensureReady() {
|
|
13
|
+
await mkdir(this.config.storeDir, { recursive: true });
|
|
14
|
+
await appendFile(this.config.memoryFile, "", "utf8");
|
|
15
|
+
}
|
|
16
|
+
async add(input) {
|
|
17
|
+
const { record } = await this.addRecord(input);
|
|
18
|
+
return record;
|
|
19
|
+
}
|
|
20
|
+
async addRecord(input) {
|
|
21
|
+
await this.ensureReady();
|
|
22
|
+
const now = new Date().toISOString();
|
|
23
|
+
const normalizedText = input.text.trim();
|
|
24
|
+
if (!normalizedText) {
|
|
25
|
+
throw new Error("text is required");
|
|
26
|
+
}
|
|
27
|
+
return this.withWriteLock(async () => {
|
|
28
|
+
const id = input.id?.trim() || randomUUID();
|
|
29
|
+
const existing = (await this.readRecords({ includeDeleted: true })).find((record) => record.id === id);
|
|
30
|
+
if (existing) {
|
|
31
|
+
return { record: existing, created: false };
|
|
32
|
+
}
|
|
33
|
+
const record = {
|
|
34
|
+
id,
|
|
35
|
+
kind: input.kind,
|
|
36
|
+
text: normalizedText,
|
|
37
|
+
tags: normalizeTags(input.tags ?? []),
|
|
38
|
+
source: input.source?.trim() || "mcp",
|
|
39
|
+
createdAt: input.createdAt ?? now,
|
|
40
|
+
updatedAt: input.updatedAt ?? input.createdAt ?? now,
|
|
41
|
+
};
|
|
42
|
+
await this.append(record);
|
|
43
|
+
return { record, created: true };
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async all(options = {}) {
|
|
47
|
+
await this.ensureReady();
|
|
48
|
+
const records = await this.readRecords(options);
|
|
49
|
+
return records.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
50
|
+
}
|
|
51
|
+
async count() {
|
|
52
|
+
return (await this.all({ includeDeleted: true })).length;
|
|
53
|
+
}
|
|
54
|
+
async delete(id) {
|
|
55
|
+
await this.ensureReady();
|
|
56
|
+
return this.withWriteLock(async () => {
|
|
57
|
+
const records = await this.readRecords({ includeDeleted: true });
|
|
58
|
+
const existing = records.find((record) => record.id === id && !record.deletedAt);
|
|
59
|
+
if (!existing)
|
|
60
|
+
return undefined;
|
|
61
|
+
const now = new Date().toISOString();
|
|
62
|
+
const updatedRecords = records.map((record) => record.id === id ? { ...record, deletedAt: now, updatedAt: now } : record);
|
|
63
|
+
await this.rewrite(updatedRecords);
|
|
64
|
+
return { ...existing, deletedAt: now, updatedAt: now };
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async search(input) {
|
|
68
|
+
const queryTerms = tokenize(input.query);
|
|
69
|
+
const tagFilter = normalizeTags(input.tags ?? []);
|
|
70
|
+
const records = await this.all({ kind: input.kind });
|
|
71
|
+
const limit = Math.max(1, Math.min(input.limit ?? this.config.maxSearchResults, 50));
|
|
72
|
+
if (queryTerms.length === 0 && tagFilter.length === 0) {
|
|
73
|
+
return records.slice(0, limit).map((record) => ({
|
|
74
|
+
record,
|
|
75
|
+
score: 1,
|
|
76
|
+
matchedTerms: [],
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
return records
|
|
80
|
+
.filter((record) => tagFilter.every((tag) => record.tags.includes(tag)))
|
|
81
|
+
.map((record) => scoreRecord(record, queryTerms))
|
|
82
|
+
.filter((result) => queryTerms.length === 0 || result.matchedTerms.length > 0)
|
|
83
|
+
.sort((a, b) => b.score - a.score || b.record.createdAt.localeCompare(a.record.createdAt))
|
|
84
|
+
.slice(0, limit);
|
|
85
|
+
}
|
|
86
|
+
async readRecords(options = {}) {
|
|
87
|
+
const raw = await readFile(this.config.memoryFile, "utf8");
|
|
88
|
+
return raw
|
|
89
|
+
.split("\n")
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.map((line) => JSON.parse(line))
|
|
92
|
+
.filter((record) => options.includeDeleted || !record.deletedAt)
|
|
93
|
+
.filter((record) => !options.kind || record.kind === options.kind);
|
|
94
|
+
}
|
|
95
|
+
async append(record) {
|
|
96
|
+
const line = `${JSON.stringify(record)}\n`;
|
|
97
|
+
await appendFile(this.config.memoryFile, line, "utf8");
|
|
98
|
+
}
|
|
99
|
+
async rewrite(records) {
|
|
100
|
+
await mkdir(this.config.storeDir, { recursive: true });
|
|
101
|
+
const tmp = path.join(this.config.storeDir, `.memory.${createHash("sha256").update(String(Date.now())).digest("hex").slice(0, 8)}.tmp`);
|
|
102
|
+
const body = records.map((record) => JSON.stringify(record)).join("\n");
|
|
103
|
+
await writeFile(tmp, body ? `${body}\n` : "", "utf8");
|
|
104
|
+
await rename(tmp, this.config.memoryFile);
|
|
105
|
+
}
|
|
106
|
+
async withWriteLock(operation) {
|
|
107
|
+
await mkdir(this.config.storeDir, { recursive: true });
|
|
108
|
+
const lockDir = path.join(this.config.storeDir, ".memory.lock");
|
|
109
|
+
const startedAt = Date.now();
|
|
110
|
+
while (true) {
|
|
111
|
+
try {
|
|
112
|
+
await mkdir(lockDir);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error.code !== "EEXIST")
|
|
117
|
+
throw error;
|
|
118
|
+
if (Date.now() - startedAt > LOCK_TIMEOUT_MS) {
|
|
119
|
+
throw new Error(`Timed out waiting for Pathmark store lock: ${lockDir}`);
|
|
120
|
+
}
|
|
121
|
+
await sleep(LOCK_RETRY_MS);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
return await operation();
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
await rm(lockDir, { force: true, recursive: true });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function normalizeTags(tags) {
|
|
133
|
+
return [...new Set(tags.map((tag) => tag.trim().toLowerCase()).filter(Boolean))].sort();
|
|
134
|
+
}
|
|
135
|
+
function tokenize(text) {
|
|
136
|
+
return [...new Set((text.toLowerCase().match(WORD_RE) ?? []).filter((term) => term.length > 1))];
|
|
137
|
+
}
|
|
138
|
+
function scoreRecord(record, queryTerms) {
|
|
139
|
+
const haystack = `${record.text} ${record.tags.join(" ")} ${record.source}`.toLowerCase();
|
|
140
|
+
const textTerms = tokenize(record.text);
|
|
141
|
+
const matchedTerms = queryTerms.filter((term) => haystack.includes(term));
|
|
142
|
+
const exactTextMatches = matchedTerms.filter((term) => textTerms.includes(term)).length;
|
|
143
|
+
const tagMatches = matchedTerms.filter((term) => record.tags.includes(term)).length;
|
|
144
|
+
const priority = scorePriority(record);
|
|
145
|
+
return {
|
|
146
|
+
record,
|
|
147
|
+
score: matchedTerms.length + exactTextMatches * 2 + tagMatches * 3 + priority,
|
|
148
|
+
matchedTerms,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function scorePriority(record) {
|
|
152
|
+
let priority = 0;
|
|
153
|
+
if (record.kind === "conclusion")
|
|
154
|
+
priority += 8;
|
|
155
|
+
if (record.tags.includes("codex-summary"))
|
|
156
|
+
priority += 6;
|
|
157
|
+
if (record.tags.includes("project-note"))
|
|
158
|
+
priority += 5;
|
|
159
|
+
if (record.tags.includes("decision"))
|
|
160
|
+
priority += 5;
|
|
161
|
+
if (record.tags.includes("role-user"))
|
|
162
|
+
priority += 3;
|
|
163
|
+
if (record.tags.includes("role-assistant"))
|
|
164
|
+
priority += 2;
|
|
165
|
+
if (record.tags.includes("role-tool"))
|
|
166
|
+
priority -= 4;
|
|
167
|
+
if (record.tags.includes("honcho-import"))
|
|
168
|
+
priority -= 1;
|
|
169
|
+
return priority;
|
|
170
|
+
}
|
|
171
|
+
function sleep(ms) {
|
|
172
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=store.js.map
|