@dotdotgod/hermes 0.6.0 → 0.6.1
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/package.json +2 -2
- package/plugin.yaml +1 -1
- package/runtime.py +33 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotdotgod/hermes",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
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.1"
|
|
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 = []
|