wm-opencode 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/dist/index.js +12460 -0
- package/package.json +23 -0
- package/src/index.ts +151 -0
- package/tsconfig.json +16 -0
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wm-opencode",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "wm working memory plugin for OpenCode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "bun build src/index.ts --outdir dist --target bun",
|
|
10
|
+
"dev": "bun run src/index.ts",
|
|
11
|
+
"test": "bun test",
|
|
12
|
+
"typecheck": "tsc --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@opencode-ai/plugin": "^1.0.61",
|
|
17
|
+
"@types/bun": "^1.2.4",
|
|
18
|
+
"typescript": "^5.7.0"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"bun": ">=1.0.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WM OpenCode Plugin
|
|
3
|
+
*
|
|
4
|
+
* Working memory for OpenCode. The LLM calls wm tools when it needs context.
|
|
5
|
+
* Similar to superego's "pull mode" - model-driven rather than automatic.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
9
|
+
import { tool } from "@opencode-ai/plugin";
|
|
10
|
+
import { existsSync, appendFileSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { spawnSync } from "child_process";
|
|
13
|
+
|
|
14
|
+
// Log to file since OpenCode is a TUI
|
|
15
|
+
function log(wmDir: string, message: string): void {
|
|
16
|
+
const timestamp = new Date().toISOString();
|
|
17
|
+
const logFile = join(wmDir, "hook.log");
|
|
18
|
+
try {
|
|
19
|
+
appendFileSync(logFile, `${timestamp} ${message}\n`);
|
|
20
|
+
} catch {
|
|
21
|
+
// Ignore log failures
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const WM_DIR = ".wm";
|
|
26
|
+
const WM_CONTRACT = `WM ACTIVE: This project uses wm (working memory) to accumulate tacit knowledge across sessions. When you need relevant context for your work, use the wm tool to retrieve it. If you don't know what/why something works or need background, encourage the user to prep a dive pack via wm. Key commands: wm show state (view knowledge), wm compile (get relevant context for current task).`;
|
|
27
|
+
|
|
28
|
+
// Check if wm binary is available
|
|
29
|
+
function checkWmBinary(): { available: boolean; version?: string } {
|
|
30
|
+
try {
|
|
31
|
+
const result = spawnSync("wm", ["--version"], { encoding: "utf-8" });
|
|
32
|
+
if (result.status === 0) {
|
|
33
|
+
return { available: true, version: result.stdout.trim() };
|
|
34
|
+
}
|
|
35
|
+
return { available: false };
|
|
36
|
+
} catch {
|
|
37
|
+
return { available: false };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Execute wm command
|
|
42
|
+
function executeWmCommand(
|
|
43
|
+
directory: string,
|
|
44
|
+
args: string[]
|
|
45
|
+
): { success: boolean; output: string; error?: string } {
|
|
46
|
+
try {
|
|
47
|
+
const result = spawnSync("wm", args, {
|
|
48
|
+
cwd: directory,
|
|
49
|
+
encoding: "utf-8",
|
|
50
|
+
timeout: 30000,
|
|
51
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (result.status === 0) {
|
|
55
|
+
return { success: true, output: result.stdout || "Command completed successfully" };
|
|
56
|
+
} else {
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
output: result.stdout || "",
|
|
60
|
+
error: result.stderr || `Command failed with exit code ${result.status}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
return { success: false, output: "", error: `Failed to execute command: ${e}` };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const WM: Plugin = async ({ directory }) => {
|
|
69
|
+
const wmDir = join(directory, WM_DIR);
|
|
70
|
+
const initialized = existsSync(wmDir);
|
|
71
|
+
const wmCheck = checkWmBinary();
|
|
72
|
+
|
|
73
|
+
if (initialized && wmCheck.available) {
|
|
74
|
+
log(wmDir, `Plugin loaded, binary: ${wmCheck.version}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
// Inject contract into system prompt (soft hint for model to use tool)
|
|
79
|
+
"experimental.chat.system.transform": async (_input, output) => {
|
|
80
|
+
if (initialized && wmCheck.available) {
|
|
81
|
+
output.system.push(WM_CONTRACT);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
tool: {
|
|
86
|
+
wm: tool({
|
|
87
|
+
description: "Manage working memory. Commands: init, status, show <state|working|sessions>, compile, distill, compress, pause, resume. Use 'compile' to get relevant context for current task.",
|
|
88
|
+
args: {
|
|
89
|
+
command: tool.schema
|
|
90
|
+
.enum(["init", "status", "show", "compile", "distill", "compress", "pause", "resume"])
|
|
91
|
+
.default("status"),
|
|
92
|
+
subcommand: tool.schema.string().optional(),
|
|
93
|
+
options: tool.schema.string().optional(),
|
|
94
|
+
},
|
|
95
|
+
async execute({ command, subcommand, options }) {
|
|
96
|
+
// Check if wm binary is available
|
|
97
|
+
if (!wmCheck.available) {
|
|
98
|
+
return `wm binary not found. Install with:\n\n` +
|
|
99
|
+
` brew tap cloud-atlas-ai/wm\n` +
|
|
100
|
+
` brew install wm\n\n` +
|
|
101
|
+
`Or:\n\n` +
|
|
102
|
+
` cargo install wm\n\n` +
|
|
103
|
+
`Then restart OpenCode.`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Build command arguments
|
|
107
|
+
const args: string[] = [command];
|
|
108
|
+
if (subcommand) args.push(subcommand);
|
|
109
|
+
if (options) args.push(...options.split(/\s+/));
|
|
110
|
+
|
|
111
|
+
// Special handling for init
|
|
112
|
+
if (command === "init") {
|
|
113
|
+
if (existsSync(wmDir)) {
|
|
114
|
+
return "wm already initialized in this project.";
|
|
115
|
+
}
|
|
116
|
+
const result = executeWmCommand(directory, args);
|
|
117
|
+
if (result.success) {
|
|
118
|
+
return `wm initialized. Created ${WM_DIR}/ directory.\n\n` +
|
|
119
|
+
`Working memory will accumulate knowledge from your sessions.\n\n` +
|
|
120
|
+
`Key commands:\n` +
|
|
121
|
+
` wm show state - View accumulated knowledge\n` +
|
|
122
|
+
` wm compile - Get relevant context for current task\n` +
|
|
123
|
+
` wm distill - Extract knowledge from recent work`;
|
|
124
|
+
}
|
|
125
|
+
return `Failed to initialize wm: ${result.error || result.output}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Check if initialized for other commands
|
|
129
|
+
if (!existsSync(wmDir)) {
|
|
130
|
+
return "wm not initialized. Use 'wm init' first.";
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Execute command
|
|
134
|
+
const result = executeWmCommand(directory, args);
|
|
135
|
+
|
|
136
|
+
if (result.success) {
|
|
137
|
+
// Special message for compile to explain output
|
|
138
|
+
if (command === "compile") {
|
|
139
|
+
return result.output + "\n\n(This is the relevant context from working memory for your current task)";
|
|
140
|
+
}
|
|
141
|
+
return result.output;
|
|
142
|
+
} else {
|
|
143
|
+
return `Error: ${result.error}\n\n${result.output}`;
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
}),
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export default WM;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"outDir": "dist",
|
|
11
|
+
"rootDir": "src",
|
|
12
|
+
"types": ["bun-types"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|