@dotdotgod/hermes 0.6.0 → 0.6.2
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/mcp/cli.mjs +1313 -254
- package/mcp/parsers/IGNORE_LICENSE +21 -0
- package/mcp/parsers/LICENSE +21 -0
- package/mcp/parsers/tree-sitter-bash.wasm +0 -0
- package/mcp/parsers/tree-sitter-c-sharp.wasm +0 -0
- package/mcp/parsers/tree-sitter-cpp.wasm +0 -0
- package/mcp/parsers/tree-sitter-css.wasm +0 -0
- package/mcp/parsers/tree-sitter-go.wasm +0 -0
- package/mcp/parsers/tree-sitter-ini.wasm +0 -0
- package/mcp/parsers/tree-sitter-java.wasm +0 -0
- package/mcp/parsers/tree-sitter-javascript.wasm +0 -0
- package/mcp/parsers/tree-sitter-php.wasm +0 -0
- package/mcp/parsers/tree-sitter-powershell.wasm +0 -0
- package/mcp/parsers/tree-sitter-python.wasm +0 -0
- package/mcp/parsers/tree-sitter-regex.wasm +0 -0
- package/mcp/parsers/tree-sitter-ruby.wasm +0 -0
- package/mcp/parsers/tree-sitter-rust.wasm +0 -0
- package/mcp/parsers/tree-sitter-tsx.wasm +0 -0
- package/mcp/parsers/tree-sitter-typescript.wasm +0 -0
- package/mcp/parsers/tree-sitter.cjs +4075 -0
- package/mcp/parsers/tree-sitter.wasm +0 -0
- package/mcp/server.mjs +11 -6
- package/package.json +2 -2
- package/plugin.yaml +1 -1
- package/runtime.py +33 -4
- package/skills/project-load/SKILL.md +2 -2
|
Binary file
|
package/mcp/server.mjs
CHANGED
|
@@ -23240,28 +23240,33 @@ async function cliJson(args, cwd) {
|
|
|
23240
23240
|
throw new Error(`Expected JSON from dotdotgod: ${out.slice(0, 500)}`);
|
|
23241
23241
|
}
|
|
23242
23242
|
}
|
|
23243
|
+
function embeddingRuntimeRecovery() {
|
|
23244
|
+
return {
|
|
23245
|
+
code: "EMBEDDING_RUNTIME_MISSING",
|
|
23246
|
+
message: "Semantic vectors need an optional runtime; continue with keyword/map retrieval or ask before installation.",
|
|
23247
|
+
recovery: { kind: "embedding-runtime-install", requiresConfirmation: true, statusTool: "dotdotgod_embedding_status", installTool: "dotdotgod_embedding_install", cliCommand: "dotdotgod embedding install --confirm" }
|
|
23248
|
+
};
|
|
23249
|
+
}
|
|
23243
23250
|
async function projectLoad(input) {
|
|
23244
23251
|
const root2 = resolve5(input.root || process.cwd());
|
|
23245
23252
|
const focus = input.focus?.trim() ?? "";
|
|
23246
23253
|
const tree = markdownTree(root2, input.maxDepth ?? (focus ? 3 : 5));
|
|
23247
23254
|
let query = null;
|
|
23248
23255
|
let queryUnavailable;
|
|
23256
|
+
let vectorUnavailable;
|
|
23249
23257
|
if (focus) {
|
|
23250
23258
|
try {
|
|
23251
23259
|
query = await cliJson(["query", root2, focus, "--limit", String(Math.min(input.limit ?? 30, 30)), "--json"], root2);
|
|
23260
|
+
if (query.warnings?.some((warning) => warning.includes("Optional local embedding runtime is not installed"))) vectorUnavailable = embeddingRuntimeRecovery();
|
|
23252
23261
|
} catch (error2) {
|
|
23253
23262
|
const missingRuntime = String(error2?.message ?? error2).includes("Optional local embedding runtime is not installed");
|
|
23254
|
-
queryUnavailable = missingRuntime ? {
|
|
23255
|
-
code: "EMBEDDING_RUNTIME_MISSING",
|
|
23256
|
-
message: "Local semantic search requires an optional embedding runtime; continue with the documentation map or ask the user before installation.",
|
|
23257
|
-
recovery: { kind: "embedding-runtime-install", requiresConfirmation: true, statusTool: "dotdotgod_embedding_status", installTool: "dotdotgod_embedding_install", cliCommand: "dotdotgod embedding install --confirm" }
|
|
23258
|
-
} : {
|
|
23263
|
+
queryUnavailable = missingRuntime ? embeddingRuntimeRecovery() : {
|
|
23259
23264
|
code: "QUERY_UNAVAILABLE",
|
|
23260
23265
|
message: "Semantic project query is unavailable; continue with the documentation map and targeted reads."
|
|
23261
23266
|
};
|
|
23262
23267
|
}
|
|
23263
23268
|
}
|
|
23264
|
-
return { ok: true, root: root2, focus, documentationTree: tree, query, ...queryUnavailable ? { queryUnavailable } : {} };
|
|
23269
|
+
return { ok: true, root: root2, focus, documentationTree: tree, query, ...queryUnavailable ? { queryUnavailable } : {}, ...vectorUnavailable ? { vectorUnavailable } : {} };
|
|
23265
23270
|
}
|
|
23266
23271
|
async function projectEmbeddingStatus(input = {}) {
|
|
23267
23272
|
const root2 = resolve5(input.root || process.cwd());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotdotgod/hermes",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Hermes CLI and messaging-gateway adapter without Plan Mode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
15
15
|
"esbuild": "0.27.3",
|
|
16
|
-
"@dotdotgod/context": "0.6.
|
|
16
|
+
"@dotdotgod/context": "0.6.2"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"plugin.yaml",
|
package/plugin.yaml
CHANGED
package/runtime.py
CHANGED
|
@@ -52,10 +52,13 @@ class Runtime:
|
|
|
52
52
|
labels = access.get(session.principal, []) if isinstance(access, dict) else []
|
|
53
53
|
return {label: roots[label] for label in labels if label in roots} if isinstance(labels, list) else {}
|
|
54
54
|
|
|
55
|
-
def
|
|
55
|
+
def trusted_session(self, session_id):
|
|
56
56
|
if not session_id or session_id not in self.sessions:
|
|
57
57
|
raise ValueError("No trusted host session; start a turn before using dotdotgod")
|
|
58
|
-
|
|
58
|
+
return self.sessions[session_id]
|
|
59
|
+
|
|
60
|
+
def session(self, session_id):
|
|
61
|
+
session = self.trusted_session(session_id)
|
|
59
62
|
if session.root is None:
|
|
60
63
|
raise ValueError("Select an authorized repository with dotdotgod_select_root first")
|
|
61
64
|
if session.parent_id:
|
|
@@ -122,8 +125,23 @@ class Runtime:
|
|
|
122
125
|
|
|
123
126
|
def call(self, name, args, session_id):
|
|
124
127
|
with self.lock:
|
|
128
|
+
session = self.trusted_session(session_id)
|
|
125
129
|
if name == "dotdotgod_select_root":
|
|
126
|
-
|
|
130
|
+
if not self.allowed(session):
|
|
131
|
+
raise PermissionError("No authorized repository labels; only dotdotgod_project_initialize is available")
|
|
132
|
+
return self.select(session, args.get("label"))
|
|
133
|
+
if session.root is None and not session.parent_id and name == "dotdotgod_project_initialize":
|
|
134
|
+
target = args.get("root")
|
|
135
|
+
if not isinstance(target, str) or not Path(target).is_absolute():
|
|
136
|
+
raise ValueError("Initialization without selection requires an explicit absolute root directory")
|
|
137
|
+
root = Path(target).resolve(strict=True)
|
|
138
|
+
if not root.is_dir():
|
|
139
|
+
raise ValueError("Initialization root must be a directory")
|
|
140
|
+
proxy = Proxy(root, digest(session.principal + "\0" + session.id + "\0initialize"))
|
|
141
|
+
try:
|
|
142
|
+
return proxy.call(name, {**args, "root": str(root)})
|
|
143
|
+
finally:
|
|
144
|
+
proxy.close()
|
|
127
145
|
session = self.session(session_id)
|
|
128
146
|
if name == "dotdotgod_impact_status":
|
|
129
147
|
return envelope({"ok": True, "pending": list(self.pending(session))})
|
|
@@ -160,6 +178,13 @@ class Runtime:
|
|
|
160
178
|
|
|
161
179
|
def before_tool(self, tool_name, args, session_id="", **kwargs):
|
|
162
180
|
try:
|
|
181
|
+
session = self.trusted_session(session_id)
|
|
182
|
+
if session.root is None and not session.parent_id:
|
|
183
|
+
if not tool_name.startswith("dotdotgod_") or tool_name == "dotdotgod_project_initialize":
|
|
184
|
+
return None
|
|
185
|
+
if tool_name == "dotdotgod_select_root" and self.allowed(session):
|
|
186
|
+
return None
|
|
187
|
+
return {"action": "block", "message": "dotdotgod is inactive without a selected repository; only initialization is available (selection requires authorized labels)"}
|
|
163
188
|
if tool_name == "dotdotgod_select_root":
|
|
164
189
|
return None
|
|
165
190
|
session = self.session(session_id)
|
|
@@ -194,7 +219,11 @@ class Runtime:
|
|
|
194
219
|
elif platform in {"", "cli"}:
|
|
195
220
|
session.root = Path(self.ctx.get_config("cli_root", "") or self.launch_root).resolve(strict=True)
|
|
196
221
|
if session.root is None:
|
|
197
|
-
|
|
222
|
+
labels = list(self.allowed(session))
|
|
223
|
+
context = "dotdotgod is inactive; ordinary host tools remain available. Only dotdotgod_project_initialize may run without selection, with an explicit absolute root and existing write confirmation. Initialization does not select or authorize a repository."
|
|
224
|
+
if labels:
|
|
225
|
+
context += " Optionally select a repository using dotdotgod_select_root. Authorized labels: " + json.dumps(labels)
|
|
226
|
+
return {"context": context}
|
|
198
227
|
try:
|
|
199
228
|
self.session(session_id)
|
|
200
229
|
parts = []
|
|
@@ -22,9 +22,9 @@ Load the repository's dotdotgod project memory without modifying maintained file
|
|
|
22
22
|
1. Identify the repository root. Expose `Help: dotdotgod --help` as optional CLI discovery guidance without checking or reporting installation status, and do not require Help execution for Load to continue.
|
|
23
23
|
2. When baseline context is missing, read `AGENTS.md`, the adapter entrypoint, `README.md`, and `docs/README.md` when present.
|
|
24
24
|
3. Without arguments, run `dotdotgod map <root> --depth 5 --json` and use its configured prefix-compressed documentation tree. The command owns `documentation.root`, `load.documentationSummary.exclude`, deterministic Markdown discovery, and boundary summaries.
|
|
25
|
-
4. With arguments, run `dotdotgod query <root> "<focus>" --limit 30 --json` for at most 30
|
|
25
|
+
4. With arguments, run `dotdotgod query <root> "<focus>" --limit 30 --json` for at most 30 documentation-file or code-symbol results and `dotdotgod map <root> --depth 3 --json` for the configured navigation tree.
|
|
26
26
|
5. If the CLI or shell execution is unavailable, preserve Load behavior by building the same tree from the configured documentation root when known, excluding local memory, and using README routing. At the depth boundary, list every direct Markdown file and immediate child directory, then summarize hidden descendants separately under each named child with exact recursive directory and Markdown-file counts.
|
|
27
|
-
6. Read bodies selectively from query results, explicit paths, and README indexes. Read relevant active plans only when needed, use `docs/archive/README.md` (or the configured archive `README.md` under an alternate documentation root) as the history map, and avoid broad generated, dependency, cache, or secret reads.
|
|
27
|
+
6. Query searches full documentation content and code outlines/comments, not implementation bodies. Preserve result kind, source ranges and retrieval warnings; verify source freshness before reading a symbol's implementation. Read bodies selectively from query results, explicit paths, and README indexes. Read relevant active plans only when needed, use `docs/archive/README.md` (or the configured archive `README.md` under an alternate documentation root) as the history map, and avoid broad generated, dependency, cache, or secret reads.
|
|
28
28
|
|
|
29
29
|
## Output
|
|
30
30
|
|