@devtheops/opencode-plugin-mempalace 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 +86 -0
- package/package.json +50 -0
- package/skills/mempalace/SKILL.md +55 -0
- package/src/config.ts +75 -0
- package/src/index.ts +100 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DEVtheOPS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# opencode-plugin-mempalace
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@devtheops/opencode-plugin-mempalace)
|
|
4
|
+
[](https://www.npmjs.com/package/@devtheops/opencode-plugin-mempalace)
|
|
5
|
+
[](https://github.com/DEVtheOPS/opencode-mempalace/stargazers)
|
|
6
|
+
[](https://github.com/DEVtheOPS/opencode-mempalace/actions/workflows/release-please.yml)
|
|
7
|
+
[](https://github.com/DEVtheOPS/opencode-mempalace/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
An [OpenCode](https://opencode.ai) server plugin that integrates [MemPalace](https://github.com/MemPalace/mempalace) without vendoring the MemPalace application code.
|
|
10
|
+
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Requirements](#requirements)
|
|
13
|
+
- [What It Adds](#what-it-adds)
|
|
14
|
+
- [Runtime Behavior](#runtime-behavior)
|
|
15
|
+
- [Development](#development)
|
|
16
|
+
|
|
17
|
+
The plugin:
|
|
18
|
+
|
|
19
|
+
- installs the `mempalace` Python package if it is missing
|
|
20
|
+
- registers a local `mempalace` MCP server
|
|
21
|
+
- injects MemPalace slash commands into OpenCode
|
|
22
|
+
- injects a bundled `mempalace` skill into OpenCode
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
Add the plugin to your OpenCode config:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"$schema": "https://opencode.ai/config.json",
|
|
31
|
+
"plugin": ["@devtheops/opencode-plugin-mempalace"]
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For local development you can point OpenCode directly at this checkout:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"$schema": "https://opencode.ai/config.json",
|
|
40
|
+
"plugin": ["/path/to/opencode-mempalace/src/index.ts"]
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- OpenCode
|
|
47
|
+
- Python 3.9+
|
|
48
|
+
- `pip`
|
|
49
|
+
|
|
50
|
+
## What It Adds
|
|
51
|
+
|
|
52
|
+
The plugin injects these commands:
|
|
53
|
+
|
|
54
|
+
- `/mempalace-help`
|
|
55
|
+
- `/mempalace-init`
|
|
56
|
+
- `/mempalace-mine`
|
|
57
|
+
- `/mempalace-search`
|
|
58
|
+
- `/mempalace-status`
|
|
59
|
+
|
|
60
|
+
It also injects:
|
|
61
|
+
|
|
62
|
+
- a `mempalace` skill
|
|
63
|
+
- a local `mempalace` MCP server that runs `python3 -m mempalace.mcp_server` or falls back to `python -m mempalace.mcp_server`
|
|
64
|
+
|
|
65
|
+
If a `mempalace` MCP server is already configured, the plugin leaves it alone.
|
|
66
|
+
|
|
67
|
+
## Runtime Behavior
|
|
68
|
+
|
|
69
|
+
When OpenCode loads the plugin, it checks for `python3` or `python` and then verifies whether the `mempalace` package is importable.
|
|
70
|
+
If not, it runs:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
python3 -m pip install --upgrade mempalace
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If installation fails, the plugin logs a warning and OpenCode continues running.
|
|
77
|
+
|
|
78
|
+
## Development
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
bun install
|
|
82
|
+
bun run typecheck
|
|
83
|
+
bun test
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for development and release workflow details.
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@devtheops/opencode-plugin-mempalace",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MemPalace plugin for OpenCode. Installs the Python package, registers the MCP server, and injects commands and a bundled skill.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "DEVtheOPS",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/DEVtheOPS/opencode-mempalace#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/DEVtheOPS/opencode-mempalace.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/DEVtheOPS/opencode-mempalace/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"opencode",
|
|
18
|
+
"plugin",
|
|
19
|
+
"mempalace",
|
|
20
|
+
"memory",
|
|
21
|
+
"mcp",
|
|
22
|
+
"python"
|
|
23
|
+
],
|
|
24
|
+
"main": "./src/index.ts",
|
|
25
|
+
"module": "./src/index.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": "./src/index.ts",
|
|
28
|
+
"./server": "./src/index.ts"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"src/",
|
|
32
|
+
"skills/"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@opencode-ai/plugin": "^1.2.23",
|
|
39
|
+
"@opencode-ai/sdk": "^1.2.23",
|
|
40
|
+
"typescript": "^5.9.3"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/bun": "latest",
|
|
44
|
+
"@types/node": "^25.6.0"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"test": "bun test",
|
|
48
|
+
"typecheck": "tsc --noEmit"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mempalace
|
|
3
|
+
description: MemPalace memory workflows for setup, mining, search, and palace status. Use when asked about MemPalace, memory palace setup, mining memories, or semantic memory search.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: opencode
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# MemPalace
|
|
9
|
+
|
|
10
|
+
MemPalace is a searchable memory system for mined projects and conversations.
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
This plugin tries to install `mempalace` automatically through `pip` when OpenCode loads the plugin.
|
|
15
|
+
|
|
16
|
+
Verify the CLI is available:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
mempalace --version
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If it is still missing, install it manually:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
python3 -m pip install --upgrade mempalace
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
or:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
python -m pip install --upgrade mempalace
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Dynamic Instructions
|
|
35
|
+
|
|
36
|
+
MemPalace ships operation-specific instructions. Fetch the guide for the workflow you need first:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
mempalace instructions <command>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Supported commands:
|
|
43
|
+
|
|
44
|
+
- `help`
|
|
45
|
+
- `init`
|
|
46
|
+
- `mine`
|
|
47
|
+
- `search`
|
|
48
|
+
- `status`
|
|
49
|
+
|
|
50
|
+
After retrieving the instructions, follow them step by step.
|
|
51
|
+
|
|
52
|
+
## MCP Server
|
|
53
|
+
|
|
54
|
+
This plugin injects a local `mempalace` MCP server into OpenCode config at runtime.
|
|
55
|
+
If the tools are missing, confirm the Python package installed successfully.
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Config } from "@opencode-ai/plugin";
|
|
2
|
+
|
|
3
|
+
export type ConfigWithExtensions = Config & {
|
|
4
|
+
mcp?: Record<string, unknown>;
|
|
5
|
+
command?: Record<string, unknown>;
|
|
6
|
+
skills?: {
|
|
7
|
+
paths?: string[];
|
|
8
|
+
urls?: string[];
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function ensureStringArray(value: unknown): string[] {
|
|
13
|
+
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function injectCommands(cfg: ConfigWithExtensions) {
|
|
17
|
+
cfg.command ??= {};
|
|
18
|
+
|
|
19
|
+
const commands = cfg.command as Record<string, unknown>;
|
|
20
|
+
const template = (workflow: string, description: string, extra = "") => ({
|
|
21
|
+
description,
|
|
22
|
+
template: [
|
|
23
|
+
"Use the `skill` tool to load the `mempalace` skill.",
|
|
24
|
+
`Then run \`mempalace instructions ${workflow}\` with the bash tool.`,
|
|
25
|
+
"Follow the returned instructions exactly and complete the workflow end to end.",
|
|
26
|
+
extra,
|
|
27
|
+
]
|
|
28
|
+
.filter(Boolean)
|
|
29
|
+
.join("\n\n"),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
commands["mempalace-help"] = template("help", "Show MemPalace usage, tools, and workflow guidance.");
|
|
33
|
+
commands["mempalace-init"] = template("init", "Install and initialize MemPalace for the current project.");
|
|
34
|
+
commands["mempalace-mine"] = template(
|
|
35
|
+
"mine",
|
|
36
|
+
"Mine a project or conversation export into MemPalace.",
|
|
37
|
+
"If command arguments are present, treat them as the target path or export to mine. Otherwise, use the current project root.",
|
|
38
|
+
);
|
|
39
|
+
commands["mempalace-search"] = template(
|
|
40
|
+
"search",
|
|
41
|
+
"Search memories stored in MemPalace.",
|
|
42
|
+
"If command arguments are present, treat them as the search query.",
|
|
43
|
+
);
|
|
44
|
+
commands["mempalace-status"] = template("status", "Show MemPalace status, room counts, and health.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function injectMcp(cfg: ConfigWithExtensions) {
|
|
48
|
+
cfg.mcp ??= {};
|
|
49
|
+
const mcp = cfg.mcp as Record<string, unknown>;
|
|
50
|
+
if (mcp["mempalace"]) return;
|
|
51
|
+
|
|
52
|
+
mcp["mempalace"] = {
|
|
53
|
+
type: "local",
|
|
54
|
+
command: [
|
|
55
|
+
"sh",
|
|
56
|
+
"-lc",
|
|
57
|
+
"if command -v python3 >/dev/null 2>&1; then exec python3 -m mempalace.mcp_server; else exec python -m mempalace.mcp_server; fi",
|
|
58
|
+
],
|
|
59
|
+
enabled: true,
|
|
60
|
+
timeout: 10000,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function injectSkill(cfg: ConfigWithExtensions, skillsDir: string) {
|
|
65
|
+
cfg.skills ??= {};
|
|
66
|
+
const paths = ensureStringArray(cfg.skills.paths);
|
|
67
|
+
if (!paths.includes(skillsDir)) paths.push(skillsDir);
|
|
68
|
+
cfg.skills.paths = paths;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function applyMemPalaceConfig(cfg: ConfigWithExtensions, skillsDir: string) {
|
|
72
|
+
injectMcp(cfg);
|
|
73
|
+
injectCommands(cfg);
|
|
74
|
+
injectSkill(cfg, skillsDir);
|
|
75
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
3
|
+
import type { ConfigWithExtensions } from "./config.ts";
|
|
4
|
+
import { applyMemPalaceConfig } from "./config.ts";
|
|
5
|
+
|
|
6
|
+
const PACKAGE_NAME = "mempalace";
|
|
7
|
+
const SKILLS_DIR = fileURLToPath(new URL("../skills", import.meta.url));
|
|
8
|
+
const IMPORT_CHECK = "import importlib.util, sys; sys.exit(0 if importlib.util.find_spec('mempalace') else 1)";
|
|
9
|
+
|
|
10
|
+
type Logger = {
|
|
11
|
+
app?: {
|
|
12
|
+
log?: (input: {
|
|
13
|
+
body: {
|
|
14
|
+
service: string;
|
|
15
|
+
level: "debug" | "info" | "warn" | "error";
|
|
16
|
+
message: string;
|
|
17
|
+
extra?: Record<string, string>;
|
|
18
|
+
};
|
|
19
|
+
}) => Promise<unknown>;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
async function log(
|
|
24
|
+
client: Logger,
|
|
25
|
+
level: "debug" | "info" | "warn" | "error",
|
|
26
|
+
message: string,
|
|
27
|
+
extra?: Record<string, string>,
|
|
28
|
+
) {
|
|
29
|
+
if (!client.app?.log) return;
|
|
30
|
+
await client.app.log({
|
|
31
|
+
body: {
|
|
32
|
+
service: "opencode-plugin-mempalace",
|
|
33
|
+
level,
|
|
34
|
+
message,
|
|
35
|
+
extra,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function run(cmd: string[]) {
|
|
41
|
+
const proc = Bun.spawn({
|
|
42
|
+
cmd,
|
|
43
|
+
stdout: "pipe",
|
|
44
|
+
stderr: "pipe",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
48
|
+
new Response(proc.stdout).text(),
|
|
49
|
+
new Response(proc.stderr).text(),
|
|
50
|
+
proc.exited,
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
return { stdout, stderr, exitCode };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function ensureMemPalaceInstalled(client: Logger) {
|
|
57
|
+
const python = Bun.which("python3") ?? Bun.which("python");
|
|
58
|
+
if (!python) {
|
|
59
|
+
await log(
|
|
60
|
+
client,
|
|
61
|
+
"warn",
|
|
62
|
+
"Could not find python3 or python. MemPalace MCP setup will remain unavailable until Python is installed.",
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const check = await run([python, "-c", IMPORT_CHECK]);
|
|
68
|
+
if (check.exitCode === 0) {
|
|
69
|
+
await log(client, "debug", "MemPalace Python package already installed.", { python });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
await log(client, "info", "Installing MemPalace Python package.", { python, package: PACKAGE_NAME });
|
|
74
|
+
const install = await run([python, "-m", "pip", "install", "--upgrade", PACKAGE_NAME]);
|
|
75
|
+
|
|
76
|
+
if (install.exitCode === 0) {
|
|
77
|
+
await log(client, "info", "Installed MemPalace Python package.", { python, package: PACKAGE_NAME });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await log(client, "warn", "MemPalace Python package install failed.", {
|
|
82
|
+
python,
|
|
83
|
+
stderr: install.stderr.trim() || "unknown error",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const server: Plugin = async ({ client }) => {
|
|
88
|
+
await ensureMemPalaceInstalled(client);
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
config: async (cfg) => {
|
|
92
|
+
applyMemPalaceConfig(cfg as ConfigWithExtensions, SKILLS_DIR);
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export default {
|
|
98
|
+
id: "devtheops.mempalace",
|
|
99
|
+
server,
|
|
100
|
+
};
|