@rvboris/opencode-mempalace 0.2.0 → 0.2.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.
@@ -8,17 +8,18 @@ from pathlib import Path
8
8
 
9
9
  from mempalace.config import MempalaceConfig
10
10
  from mempalace.convo_miner import mine_convos
11
- from mempalace.mcp_server import (
12
- tool_add_drawer,
13
- tool_diary_write,
14
- tool_kg_add,
15
- tool_search,
16
- )
11
+ import mempalace.mcp_server as mcp_server
12
+
13
+
14
+ restore_stdout = getattr(mcp_server, "_restore_stdout", None)
15
+ if callable(restore_stdout):
16
+ restore_stdout()
17
17
 
18
18
 
19
19
  def write_result(result: dict) -> None:
20
20
  output = json.dumps(result, ensure_ascii=False)
21
21
  sys.stdout.buffer.write(output.encode("utf-8", errors="replace"))
22
+ sys.stdout.buffer.flush()
22
23
 
23
24
 
24
25
  def main() -> int:
@@ -27,21 +28,21 @@ def main() -> int:
27
28
 
28
29
  mode = payload["mode"]
29
30
  if mode == "search":
30
- result = tool_search(
31
+ result = mcp_server.tool_search(
31
32
  query=payload["query"],
32
33
  limit=payload.get("limit", 5),
33
34
  wing=payload.get("wing"),
34
35
  room=payload.get("room"),
35
36
  )
36
37
  elif mode == "save":
37
- result = tool_add_drawer(
38
+ result = mcp_server.tool_add_drawer(
38
39
  wing=payload["wing"],
39
40
  room=payload["room"],
40
41
  content=payload["content"],
41
42
  added_by=payload.get("added_by", "opencode"),
42
43
  )
43
44
  elif mode == "kg_add":
44
- result = tool_kg_add(
45
+ result = mcp_server.tool_kg_add(
45
46
  subject=payload["subject"],
46
47
  predicate=payload["predicate"],
47
48
  object=payload["object"],
@@ -49,7 +50,7 @@ def main() -> int:
49
50
  source_closet=payload.get("source_closet", ""),
50
51
  )
51
52
  elif mode == "diary_write":
52
- result = tool_diary_write(
53
+ result = mcp_server.tool_diary_write(
53
54
  agent_name=payload["agent_name"],
54
55
  entry=payload["entry"],
55
56
  topic=payload.get("topic", "autosave"),
@@ -17,12 +17,18 @@ const getAdapterTimeoutMs = () => {
17
17
  const isAdapterResponse = (value) => {
18
18
  return typeof value === "object" && value !== null && !Array.isArray(value);
19
19
  };
20
+ const getStderrSnippet = (value) => {
21
+ const normalized = value.trim();
22
+ if (!normalized)
23
+ return "";
24
+ return normalized.length > 240 ? `${normalized.slice(0, 240)}...` : normalized;
25
+ };
20
26
  export const executeAdapter = async (_shell, payload, retries = 3) => {
21
27
  let lastError;
22
28
  const timeoutMs = getAdapterTimeoutMs();
23
29
  for (let attempt = 0; attempt <= retries; attempt += 1) {
24
30
  try {
25
- const text = await new Promise((resolve, reject) => {
31
+ const { stderrText, stdoutText } = await new Promise((resolve, reject) => {
26
32
  const child = spawn(getPythonCommand(), [getAdapterPath()], {
27
33
  stdio: ["pipe", "pipe", "pipe"],
28
34
  });
@@ -48,17 +54,25 @@ export const executeAdapter = async (_shell, payload, retries = 3) => {
48
54
  child.on("error", (error) => finish(() => reject(error)));
49
55
  child.on("close", (code) => {
50
56
  finish(() => {
57
+ const stderrText = Buffer.concat(stderr).toString("utf8");
58
+ const stdoutText = Buffer.concat(stdout).toString("utf8");
51
59
  if (code === 0) {
52
- resolve(Buffer.concat(stdout).toString("utf8"));
60
+ resolve({ stderrText, stdoutText });
53
61
  return;
54
62
  }
55
- reject(new Error(Buffer.concat(stderr).toString("utf8") || `Adapter exited with code ${code}`));
63
+ reject(new Error(stderrText || `Adapter exited with code ${code}`));
56
64
  });
57
65
  });
58
66
  child.stdin.write(JSON.stringify(payload), "utf8");
59
67
  child.stdin.end();
60
68
  });
61
- const parsed = JSON.parse(text);
69
+ if (!stdoutText.trim()) {
70
+ const stderrSnippet = getStderrSnippet(stderrText);
71
+ throw new Error(stderrSnippet
72
+ ? `${TOOL_ERROR_MESSAGES.emptyAdapterStdout}: ${stderrSnippet}`
73
+ : TOOL_ERROR_MESSAGES.emptyAdapterStdout);
74
+ }
75
+ const parsed = JSON.parse(stdoutText);
62
76
  if (!isAdapterResponse(parsed)) {
63
77
  throw new Error(TOOL_ERROR_MESSAGES.invalidAdapterPayload);
64
78
  }
@@ -37,6 +37,7 @@ export declare const TOOL_DESCRIPTIONS: {
37
37
  export declare const TOOL_ERROR_MESSAGES: {
38
38
  readonly directMutationBlocked: "Use mempalace_memory instead of direct MemPalace mutation tools";
39
39
  readonly invalidAdapterPayload: "Adapter returned an invalid JSON payload";
40
+ readonly emptyAdapterStdout: "Adapter returned empty stdout";
40
41
  readonly adapterTimedOut: "Adapter execution timed out";
41
42
  };
42
43
  export declare const LOG_MESSAGES: {
@@ -44,6 +44,7 @@ export const TOOL_DESCRIPTIONS = {
44
44
  export const TOOL_ERROR_MESSAGES = {
45
45
  directMutationBlocked: "Use mempalace_memory instead of direct MemPalace mutation tools",
46
46
  invalidAdapterPayload: "Adapter returned an invalid JSON payload",
47
+ emptyAdapterStdout: "Adapter returned empty stdout",
47
48
  adapterTimedOut: "Adapter execution timed out",
48
49
  };
49
50
  export const LOG_MESSAGES = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rvboris/opencode-mempalace",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "OpenCode plugin for hidden MemPalace retrieval and autosave via a local Python adapter.",
5
5
  "type": "module",
6
6
  "main": "dist/plugin/index.js",