opencontext-mcp 1.2.1 → 1.3.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 +38 -12
- package/dist/cli/index.d.ts +25 -0
- package/dist/cli/index.js +97 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/{config.d.ts → config/index.d.ts} +1 -1
- package/dist/config/index.js +62 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.js +52 -9
- package/dist/index.js.map +1 -1
- package/dist/init/constants.d.ts +6 -0
- package/dist/init/constants.js +17 -0
- package/dist/init/constants.js.map +1 -0
- package/dist/init/display.d.ts +9 -0
- package/dist/init/display.js +28 -0
- package/dist/init/display.js.map +1 -0
- package/dist/init/files.d.ts +12 -0
- package/dist/init/files.js +39 -0
- package/dist/init/files.js.map +1 -0
- package/dist/init/index.d.ts +6 -0
- package/dist/init/index.js +157 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/inspect.d.ts +21 -0
- package/dist/init/inspect.js +57 -0
- package/dist/init/inspect.js.map +1 -0
- package/dist/init/integrations/claude.d.ts +17 -0
- package/dist/init/integrations/claude.js +94 -0
- package/dist/init/integrations/claude.js.map +1 -0
- package/dist/init/integrations/opencode.d.ts +20 -0
- package/dist/init/integrations/opencode.js +108 -0
- package/dist/init/integrations/opencode.js.map +1 -0
- package/dist/init/integrations/workflow-files.d.ts +23 -0
- package/dist/init/integrations/workflow-files.js +102 -0
- package/dist/init/integrations/workflow-files.js.map +1 -0
- package/dist/init/prompts.d.ts +9 -0
- package/dist/init/prompts.js +17 -0
- package/dist/init/prompts.js.map +1 -0
- package/dist/server/http.d.ts +21 -0
- package/dist/server/http.js +63 -0
- package/dist/server/http.js.map +1 -0
- package/dist/{server.d.ts → server/index.d.ts} +3 -1
- package/dist/{server.js → server/index.js} +7 -4
- package/dist/server/index.js.map +1 -0
- package/dist/shared/constants.d.ts +27 -0
- package/dist/shared/constants.js +26 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/errors.d.ts +17 -0
- package/dist/shared/errors.js +28 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/types.d.ts +29 -0
- package/dist/shared/types.js +17 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/{context-store.d.ts → store/context-store.d.ts} +2 -16
- package/dist/store/context-store.js +147 -0
- package/dist/store/context-store.js.map +1 -0
- package/dist/store/index-builder.d.ts +32 -0
- package/dist/store/index-builder.js +162 -0
- package/dist/store/index-builder.js.map +1 -0
- package/dist/validation/index.d.ts +16 -0
- package/dist/validation/index.js +39 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/{validation.d.ts → validation/write-guard.d.ts} +0 -16
- package/dist/{validation.js → validation/write-guard.js} +2 -38
- package/dist/validation/write-guard.js.map +1 -0
- package/package.json +2 -2
- package/dist/config.js +0 -145
- package/dist/config.js.map +0 -1
- package/dist/context-store.js +0 -296
- package/dist/context-store.js.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/types.d.ts +0 -56
- package/dist/types.js +0 -63
- package/dist/types.js.map +0 -1
- package/dist/validation.js.map +0 -1
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { INDEX_FILENAME, STATUS_BADGES } from "../shared/constants.js";
|
|
4
|
+
import { isNodeError } from "../shared/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Parses YAML frontmatter from markdown content.
|
|
7
|
+
* Returns extracted fields or an empty object when no frontmatter is present.
|
|
8
|
+
* Uses simple line-by-line parsing — no external YAML dependency.
|
|
9
|
+
*/
|
|
10
|
+
export function parseFrontmatter(content) {
|
|
11
|
+
const trimmed = content.trim();
|
|
12
|
+
if (!trimmed.startsWith("---")) {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
const endIdx = trimmed.indexOf("---", 3);
|
|
16
|
+
if (endIdx === -1) {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
const block = trimmed.slice(3, endIdx);
|
|
20
|
+
const result = {};
|
|
21
|
+
for (const line of block.split("\n")) {
|
|
22
|
+
const trimmedLine = line.trim();
|
|
23
|
+
if (!trimmedLine || trimmedLine.startsWith("#"))
|
|
24
|
+
continue;
|
|
25
|
+
const colonIdx = trimmedLine.indexOf(":");
|
|
26
|
+
if (colonIdx === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const key = trimmedLine.slice(0, colonIdx).trim();
|
|
29
|
+
let value = trimmedLine.slice(colonIdx + 1).trim();
|
|
30
|
+
// Strip surrounding quotes
|
|
31
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
32
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
33
|
+
value = value.slice(1, -1);
|
|
34
|
+
}
|
|
35
|
+
if (key === "description") {
|
|
36
|
+
result.description = value;
|
|
37
|
+
}
|
|
38
|
+
else if (key === "status" &&
|
|
39
|
+
(value === "active" || value === "deprecated" || value === "superseded")) {
|
|
40
|
+
result.status = value;
|
|
41
|
+
}
|
|
42
|
+
else if (key === "supersedes") {
|
|
43
|
+
result.supersedes = value;
|
|
44
|
+
}
|
|
45
|
+
else if (key === "superseded_by") {
|
|
46
|
+
result.superseded_by = value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Extracts a short description from markdown content.
|
|
53
|
+
* Strategy: frontmatter description → first heading → first paragraph → fallback.
|
|
54
|
+
* @param content - Raw markdown content
|
|
55
|
+
* @returns Truncated description (max 120 chars)
|
|
56
|
+
*/
|
|
57
|
+
export function extractDescription(content) {
|
|
58
|
+
const trimmed = content.trim();
|
|
59
|
+
if (!trimmed) {
|
|
60
|
+
return "No summary available.";
|
|
61
|
+
}
|
|
62
|
+
const fm = parseFrontmatter(content);
|
|
63
|
+
if (fm.description) {
|
|
64
|
+
return fm.description.slice(0, 120);
|
|
65
|
+
}
|
|
66
|
+
const lines = trimmed.split("\n");
|
|
67
|
+
// Fall back to the first heading, then the first paragraph line.
|
|
68
|
+
for (const line of lines) {
|
|
69
|
+
const headingMatch = line.match(/^#\s+(.+)$/);
|
|
70
|
+
if (headingMatch?.[1]) {
|
|
71
|
+
return headingMatch[1].slice(0, 120);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (const line of lines) {
|
|
75
|
+
const stripped = line.trim();
|
|
76
|
+
if (stripped && !stripped.startsWith("#")) {
|
|
77
|
+
return stripped.length > 120 ? stripped.slice(0, 120) + "..." : stripped;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return "No summary available.";
|
|
81
|
+
}
|
|
82
|
+
/** Formats a byte count as a compact human-readable size string. */
|
|
83
|
+
function formatSize(sizeBytes) {
|
|
84
|
+
return sizeBytes >= 1024
|
|
85
|
+
? `${(sizeBytes / 1024).toFixed(1)} KB`
|
|
86
|
+
: `${sizeBytes} B`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Rebuilds the auto-generated index.md file in the context directory.
|
|
90
|
+
* Scans all topic files, extracts metadata, and writes a compact index.
|
|
91
|
+
* @param contextDir - Absolute path to the .opencontext directory
|
|
92
|
+
* @returns The generated index markdown content ("" when no topics exist)
|
|
93
|
+
*/
|
|
94
|
+
export async function buildContextIndex(contextDir) {
|
|
95
|
+
let entries;
|
|
96
|
+
try {
|
|
97
|
+
entries = await readdir(contextDir, { withFileTypes: true });
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
101
|
+
return "";
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
const topicFiles = entries
|
|
106
|
+
.filter((entry) => entry.isFile() &&
|
|
107
|
+
entry.name.endsWith(".md") &&
|
|
108
|
+
entry.name !== INDEX_FILENAME &&
|
|
109
|
+
entry.name !== "README.md")
|
|
110
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
111
|
+
if (topicFiles.length === 0) {
|
|
112
|
+
return "";
|
|
113
|
+
}
|
|
114
|
+
const topicEntries = [];
|
|
115
|
+
for (const entry of topicFiles) {
|
|
116
|
+
const filePath = path.join(contextDir, entry.name);
|
|
117
|
+
const content = await readFile(filePath, "utf8");
|
|
118
|
+
const fileStat = await stat(filePath);
|
|
119
|
+
const topic = entry.name.slice(0, -".md".length);
|
|
120
|
+
const fm = parseFrontmatter(content);
|
|
121
|
+
topicEntries.push({
|
|
122
|
+
topic,
|
|
123
|
+
filename: entry.name,
|
|
124
|
+
description: extractDescription(content),
|
|
125
|
+
date: fileStat.mtime.toISOString().slice(0, 10),
|
|
126
|
+
sizeBytes: Buffer.byteLength(content, "utf8"),
|
|
127
|
+
status: fm.status,
|
|
128
|
+
supersedes: fm.supersedes,
|
|
129
|
+
superseded_by: fm.superseded_by,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const lines = [
|
|
133
|
+
"# Project Context Index",
|
|
134
|
+
"<!-- AUTO-GENERATED BY OPENCONTEXT - DO NOT EDIT MANUALLY -->",
|
|
135
|
+
"",
|
|
136
|
+
"Available context topics in this project:",
|
|
137
|
+
"",
|
|
138
|
+
];
|
|
139
|
+
for (const t of topicEntries) {
|
|
140
|
+
const badge = t.status && t.status !== "active"
|
|
141
|
+
? ` ${STATUS_BADGES.get(t.status) ?? `[${t.status.toUpperCase()}]`}`
|
|
142
|
+
: "";
|
|
143
|
+
const supersedesNote = t.supersedes
|
|
144
|
+
? ` (supersedes: \`${t.supersedes}\`)`
|
|
145
|
+
: "";
|
|
146
|
+
const supersededByNote = t.superseded_by
|
|
147
|
+
? ` (superseded by: \`${t.superseded_by}\`)`
|
|
148
|
+
: "";
|
|
149
|
+
lines.push(`- **${t.topic}**${badge} (\`${t.filename}\`) - Updated: ${t.date} (${formatSize(t.sizeBytes)})${supersedesNote}${supersededByNote}`);
|
|
150
|
+
lines.push(` > ${t.description}`);
|
|
151
|
+
}
|
|
152
|
+
lines.push("");
|
|
153
|
+
lines.push("---");
|
|
154
|
+
lines.push("*To read a specific context topic, call `read_context` with the topic name.*");
|
|
155
|
+
lines.push("");
|
|
156
|
+
lines.push("*OpenContext is open-source. Consider starring on [GitHub](https://github.com/slxca/opencontext).*");
|
|
157
|
+
const indexContent = lines.join("\n");
|
|
158
|
+
const indexPath = path.join(contextDir, INDEX_FILENAME);
|
|
159
|
+
await writeFile(indexPath, indexContent, "utf8");
|
|
160
|
+
return indexContent;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=index-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-builder.js","sourceRoot":"","sources":["../../src/store/index-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates a topic string for safe filesystem operations.
|
|
3
|
+
* @param topicInput - The topic string to validate
|
|
4
|
+
* @returns The trimmed, validated topic
|
|
5
|
+
* @throws UserInputError if the topic is invalid
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateTopic(topicInput: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Sanitizes a topic path to prevent path traversal attacks.
|
|
10
|
+
* Ensures the resolved path stays within the context directory.
|
|
11
|
+
* @param contextDir - The absolute path to the context directory
|
|
12
|
+
* @param topic - The topic name
|
|
13
|
+
* @returns The sanitized absolute path to the topic file
|
|
14
|
+
* @throws UserInputError if path traversal is detected
|
|
15
|
+
*/
|
|
16
|
+
export declare function sanitizeTopicPath(contextDir: string, topic: string): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { TOPIC_PATTERN } from "../shared/constants.js";
|
|
3
|
+
import { UserInputError } from "../shared/errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* Validates a topic string for safe filesystem operations.
|
|
6
|
+
* @param topicInput - The topic string to validate
|
|
7
|
+
* @returns The trimmed, validated topic
|
|
8
|
+
* @throws UserInputError if the topic is invalid
|
|
9
|
+
*/
|
|
10
|
+
export function validateTopic(topicInput) {
|
|
11
|
+
const topic = topicInput.trim();
|
|
12
|
+
if (!TOPIC_PATTERN.test(topic)) {
|
|
13
|
+
throw new UserInputError("Topic must be snake_case or kebab-case using lowercase letters, numbers, underscores, or hyphens.");
|
|
14
|
+
}
|
|
15
|
+
return topic;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Sanitizes a topic path to prevent path traversal attacks.
|
|
19
|
+
* Ensures the resolved path stays within the context directory.
|
|
20
|
+
* @param contextDir - The absolute path to the context directory
|
|
21
|
+
* @param topic - The topic name
|
|
22
|
+
* @returns The sanitized absolute path to the topic file
|
|
23
|
+
* @throws UserInputError if path traversal is detected
|
|
24
|
+
*/
|
|
25
|
+
export function sanitizeTopicPath(contextDir, topic) {
|
|
26
|
+
// Quick rejection of obvious path traversal attempts
|
|
27
|
+
if (topic.includes("..") || path.isAbsolute(topic) || topic.startsWith(".") || topic.includes("/")) {
|
|
28
|
+
throw new UserInputError("Path traversal detected: topic must not contain '..', '/', or absolute paths.");
|
|
29
|
+
}
|
|
30
|
+
const filePath = path.join(contextDir, `${topic}.md`);
|
|
31
|
+
const resolvedPath = path.resolve(filePath);
|
|
32
|
+
const resolvedContextDir = path.resolve(contextDir);
|
|
33
|
+
// Double-check resolved path is still within .opencontext directory
|
|
34
|
+
if (!resolvedPath.startsWith(resolvedContextDir + path.sep) && resolvedPath !== resolvedContextDir) {
|
|
35
|
+
throw new UserInputError("Path traversal detected: topic must not contain '..' or absolute paths.");
|
|
36
|
+
}
|
|
37
|
+
return resolvedPath;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validation/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;IAEhC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,cAAc,CACtB,mGAAmG,CACpG,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB,EAAE,KAAa;IACjE,qDAAqD;IACrD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnG,MAAM,IAAI,cAAc,CAAC,+EAA+E,CAAC,CAAC;IAC5G,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,KAAK,KAAK,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAEpD,oEAAoE;IACpE,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,KAAK,kBAAkB,EAAE,CAAC;QACnG,MAAM,IAAI,cAAc,CAAC,yEAAyE,CAAC,CAAC;IACtG,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -20,22 +20,6 @@ export interface GuardResult {
|
|
|
20
20
|
/** Error code for programmatic handling */
|
|
21
21
|
code?: "EMPTY_CONTENT" | "PAYLOAD_TOO_LARGE" | "INVALID_TOPIC" | "PATH_TRAVERSAL" | "FORBIDDEN_PATTERN" | "RESERVED_TOPIC";
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Validates a topic string for safe filesystem operations.
|
|
25
|
-
* @param topicInput - The topic string to validate
|
|
26
|
-
* @returns The trimmed, validated topic
|
|
27
|
-
* @throws UserInputError if the topic is invalid
|
|
28
|
-
*/
|
|
29
|
-
export declare function validateTopic(topicInput: string): string;
|
|
30
|
-
/**
|
|
31
|
-
* Sanitizes a topic path to prevent path traversal attacks.
|
|
32
|
-
* Ensures the resolved path stays within the context directory.
|
|
33
|
-
* @param contextDir - The absolute path to the context directory
|
|
34
|
-
* @param topic - The topic name
|
|
35
|
-
* @returns The sanitized absolute path to the topic file
|
|
36
|
-
* @throws UserInputError if path traversal is detected
|
|
37
|
-
*/
|
|
38
|
-
export declare function sanitizeTopicPath(contextDir: string, topic: string): string;
|
|
39
23
|
/**
|
|
40
24
|
* Validates a write payload for context storage.
|
|
41
25
|
* Checks topic validity, content safety, size limits, and forbidden patterns.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { RESERVED_TOPICS, TOPIC_PATTERN, UserInputError } from "./types.js";
|
|
1
|
+
import { RESERVED_TOPICS, TOPIC_PATTERN } from "../shared/constants.js";
|
|
3
2
|
/**
|
|
4
3
|
* Forbidden patterns that indicate prompt injection attempts.
|
|
5
4
|
* These are checked case-insensitively against the content.
|
|
@@ -9,41 +8,6 @@ const FORBIDDEN_PATTERNS = [
|
|
|
9
8
|
/system\s*:\s*override/i,
|
|
10
9
|
/bypass\s+(safety|guardrails?|system\s+prompt)/i,
|
|
11
10
|
];
|
|
12
|
-
/**
|
|
13
|
-
* Validates a topic string for safe filesystem operations.
|
|
14
|
-
* @param topicInput - The topic string to validate
|
|
15
|
-
* @returns The trimmed, validated topic
|
|
16
|
-
* @throws UserInputError if the topic is invalid
|
|
17
|
-
*/
|
|
18
|
-
export function validateTopic(topicInput) {
|
|
19
|
-
const topic = topicInput.trim();
|
|
20
|
-
if (!TOPIC_PATTERN.test(topic)) {
|
|
21
|
-
throw new UserInputError("Topic must be snake_case or kebab-case using lowercase letters, numbers, underscores, or hyphens.");
|
|
22
|
-
}
|
|
23
|
-
return topic;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Sanitizes a topic path to prevent path traversal attacks.
|
|
27
|
-
* Ensures the resolved path stays within the context directory.
|
|
28
|
-
* @param contextDir - The absolute path to the context directory
|
|
29
|
-
* @param topic - The topic name
|
|
30
|
-
* @returns The sanitized absolute path to the topic file
|
|
31
|
-
* @throws UserInputError if path traversal is detected
|
|
32
|
-
*/
|
|
33
|
-
export function sanitizeTopicPath(contextDir, topic) {
|
|
34
|
-
// Quick rejection of obvious path traversal attempts
|
|
35
|
-
if (topic.includes("..") || path.isAbsolute(topic) || topic.startsWith(".") || topic.includes("/")) {
|
|
36
|
-
throw new UserInputError("Path traversal detected: topic must not contain '..', '/', or absolute paths.");
|
|
37
|
-
}
|
|
38
|
-
const filePath = path.join(contextDir, `${topic}.md`);
|
|
39
|
-
const resolvedPath = path.resolve(filePath);
|
|
40
|
-
const resolvedContextDir = path.resolve(contextDir);
|
|
41
|
-
// Double-check resolved path is still within .opencontext directory
|
|
42
|
-
if (!resolvedPath.startsWith(resolvedContextDir + path.sep) && resolvedPath !== resolvedContextDir) {
|
|
43
|
-
throw new UserInputError("Path traversal detected: topic must not contain '..' or absolute paths.");
|
|
44
|
-
}
|
|
45
|
-
return resolvedPath;
|
|
46
|
-
}
|
|
47
11
|
/**
|
|
48
12
|
* Validates a write payload for context storage.
|
|
49
13
|
* Checks topic validity, content safety, size limits, and forbidden patterns.
|
|
@@ -103,4 +67,4 @@ export function validateWritePayload(topic, content, options) {
|
|
|
103
67
|
}
|
|
104
68
|
return { allowed: true };
|
|
105
69
|
}
|
|
106
|
-
//# sourceMappingURL=
|
|
70
|
+
//# sourceMappingURL=write-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-guard.js","sourceRoot":"","sources":["../../src/validation/write-guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA0BxE;;;GAGG;AACH,MAAM,kBAAkB,GAAa;IACnC,oDAAoD;IACpD,wBAAwB;IACxB,gDAAgD;CACjD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAa,EACb,OAAe,EACf,OAAsB;IAEtB,MAAM,IAAI,GAA2B;QACnC,aAAa,EAAE,OAAO,EAAE,aAAa,IAAI,EAAE;QAC3C,UAAU,EAAE,OAAO,EAAE,UAAU,IAAI,KAAK;QACxC,kBAAkB,EAAE,OAAO,EAAE,kBAAkB,IAAI,IAAI;KACxD,CAAC;IAEF,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAClC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QACtC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,mGAAmG;YAC3G,IAAI,EAAE,eAAe;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QACtC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI,YAAY,8DAA8D;YACtF,IAAI,EAAE,gBAAgB;SACvB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,4DAA4D;YACpE,IAAI,EAAE,eAAe;SACtB,CAAC;IACJ,CAAC;IAED,0CAA0C;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC3C,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACxD,IAAI,YAAY,GAAG,QAAQ,EAAE,CAAC;QAC5B,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,iBAAiB,YAAY,yCAAyC,QAAQ,UAAU;YAChG,IAAI,EAAE,mBAAmB;SAC1B,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;YACzC,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1B,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,uCAAuC,OAAO,CAAC,MAAM,EAAE;oBAC/D,IAAI,EAAE,mBAAmB;iBAC1B,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencontext-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A Model Context Protocol server for persistent project-specific AI agent context.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"examples"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"build": "tsc -p tsconfig.json && chmod +x dist/index.js",
|
|
16
16
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
17
17
|
"test": "vitest run",
|
|
18
18
|
"test:watch": "vitest",
|
package/dist/config.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
export const DEFAULT_CONFIG = {
|
|
4
|
-
path: ".opencontext",
|
|
5
|
-
readOnly: false,
|
|
6
|
-
disabled: false,
|
|
7
|
-
autoIndex: true,
|
|
8
|
-
history: {
|
|
9
|
-
enabled: false,
|
|
10
|
-
maxBackupsPerTopic: 5,
|
|
11
|
-
retentionDays: 7,
|
|
12
|
-
},
|
|
13
|
-
guard: {
|
|
14
|
-
enabled: true,
|
|
15
|
-
maxFileSizeKb: 50,
|
|
16
|
-
strictPatternCheck: true,
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
const CONFIG_CANDIDATES = [".opencontext.jsonc", ".opencontext.json"];
|
|
20
|
-
/**
|
|
21
|
-
* Strips JSONC content into parseable JSON by removing comments and trailing commas.
|
|
22
|
-
* Handles single-line (//), multi-line (/* * /), and trailing commas.
|
|
23
|
-
* Trailing comma removal is token-aware to avoid modifying string literals.
|
|
24
|
-
*/
|
|
25
|
-
function stripJsonComments(raw) {
|
|
26
|
-
let result = "";
|
|
27
|
-
let i = 0;
|
|
28
|
-
const len = raw.length;
|
|
29
|
-
while (i < len) {
|
|
30
|
-
const ch = raw[i];
|
|
31
|
-
// Strings: copy verbatim (including escaped characters)
|
|
32
|
-
if (ch === '"') {
|
|
33
|
-
result += ch;
|
|
34
|
-
i++;
|
|
35
|
-
while (i < len && raw[i] !== '"') {
|
|
36
|
-
if (raw[i] === "\\") {
|
|
37
|
-
result += raw[i];
|
|
38
|
-
i++;
|
|
39
|
-
}
|
|
40
|
-
if (i < len) {
|
|
41
|
-
result += raw[i];
|
|
42
|
-
i++;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (i < len) {
|
|
46
|
-
result += raw[i]; // closing quote
|
|
47
|
-
i++;
|
|
48
|
-
}
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
// Single-line comment: skip until newline
|
|
52
|
-
if (ch === "/" && i + 1 < len && raw[i + 1] === "/") {
|
|
53
|
-
while (i < len && raw[i] !== "\n") {
|
|
54
|
-
i++;
|
|
55
|
-
}
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
// Multi-line comment: skip until */
|
|
59
|
-
if (ch === "/" && i + 1 < len && raw[i + 1] === "*") {
|
|
60
|
-
i += 2;
|
|
61
|
-
while (i < len - 1 && !(raw[i] === "*" && raw[i + 1] === "/")) {
|
|
62
|
-
i++;
|
|
63
|
-
}
|
|
64
|
-
i += 2; // skip */
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
// Trailing comma: skip comma if followed by optional whitespace/comments then } or ]
|
|
68
|
-
if (ch === ",") {
|
|
69
|
-
let j = i + 1;
|
|
70
|
-
// Skip whitespace and comments to find the next meaningful token
|
|
71
|
-
while (j < len) {
|
|
72
|
-
if (raw[j] === " " || raw[j] === "\t" || raw[j] === "\n" || raw[j] === "\r") {
|
|
73
|
-
j++;
|
|
74
|
-
}
|
|
75
|
-
else if (raw[j] === "/" && j + 1 < len && raw[j + 1] === "/") {
|
|
76
|
-
while (j < len && raw[j] !== "\n")
|
|
77
|
-
j++;
|
|
78
|
-
}
|
|
79
|
-
else if (raw[j] === "/" && j + 1 < len && raw[j + 1] === "*") {
|
|
80
|
-
j += 2;
|
|
81
|
-
while (j < len - 1 && !(raw[j] === "*" && raw[j + 1] === "/"))
|
|
82
|
-
j++;
|
|
83
|
-
j += 2;
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (j < len && (raw[j] === "}" || raw[j] === "]")) {
|
|
90
|
-
i = j; // skip comma and whitespace/comments, continue from closing bracket
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
// Not a trailing comma — keep it
|
|
94
|
-
result += ch;
|
|
95
|
-
i++;
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
result += ch;
|
|
99
|
-
i++;
|
|
100
|
-
}
|
|
101
|
-
return result;
|
|
102
|
-
}
|
|
103
|
-
function deepMerge(target, source) {
|
|
104
|
-
const result = { ...target };
|
|
105
|
-
for (const key of Object.keys(source)) {
|
|
106
|
-
const sourceVal = source[key];
|
|
107
|
-
const targetVal = result[key];
|
|
108
|
-
if (sourceVal !== null &&
|
|
109
|
-
typeof sourceVal === "object" &&
|
|
110
|
-
!Array.isArray(sourceVal) &&
|
|
111
|
-
targetVal !== null &&
|
|
112
|
-
typeof targetVal === "object" &&
|
|
113
|
-
!Array.isArray(targetVal)) {
|
|
114
|
-
result[key] = deepMerge(targetVal, sourceVal);
|
|
115
|
-
}
|
|
116
|
-
else if (sourceVal !== undefined) {
|
|
117
|
-
result[key] = sourceVal;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Loads configuration from .opencontext.jsonc or .opencontext.json in the given directory.
|
|
124
|
-
* Falls back to DEFAULT_CONFIG if no file exists or parsing fails.
|
|
125
|
-
*/
|
|
126
|
-
export async function loadConfig(cwd = process.cwd()) {
|
|
127
|
-
for (const filename of CONFIG_CANDIDATES) {
|
|
128
|
-
const filePath = path.join(cwd, filename);
|
|
129
|
-
try {
|
|
130
|
-
const raw = await readFile(filePath, "utf8");
|
|
131
|
-
const cleaned = stripJsonComments(raw);
|
|
132
|
-
const parsed = JSON.parse(cleaned);
|
|
133
|
-
return deepMerge(DEFAULT_CONFIG, parsed);
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
if (error.code === "ENOENT") {
|
|
137
|
-
continue; // file doesn't exist, try next candidate
|
|
138
|
-
}
|
|
139
|
-
console.error(`OpenContext: failed to parse ${filename}: ${error.message}`);
|
|
140
|
-
return DEFAULT_CONFIG;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return DEFAULT_CONFIG;
|
|
144
|
-
}
|
|
145
|
-
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|