clikit-plugin 0.2.19 → 0.2.21
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/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +151 -13
- package/dist/cli.test.d.ts +2 -0
- package/dist/cli.test.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/tools/memory.d.ts.map +1 -1
- package/memory/handoffs/2026-02-15-importmeta-fix.md +3 -1
- package/memory/plans/2026-02-16-plugin-install.md +195 -0
- package/memory/research/2026-02-16-opencode-plugin-alignment.md +128 -0
- package/package.json +2 -2
- package/dist/clikit.schema.json +0 -423
package/dist/cli.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
interface ScaffoldStats {
|
|
3
|
+
copied: number;
|
|
4
|
+
skipped: number;
|
|
5
|
+
missingSources: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveProjectDir(env?: NodeJS.ProcessEnv, cwd?: string): string;
|
|
8
|
+
export declare function upsertPluginEntry(existingPlugins: string[], pluginName: string, version: string): string[];
|
|
9
|
+
export declare function scaffoldProjectOpencode(projectDir: string, packageRoot?: string): ScaffoldStats;
|
|
2
10
|
export {};
|
|
3
11
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AASA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AA4BD,wBAAgB,iBAAiB,CAC/B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,GAAG,GAAE,MAAsB,GAC1B,MAAM,CAiBR;AAED,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAM1G;AA0CD,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,SAAmB,GAAG,aAAa,CAoDzG"}
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,126 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
+
for (let key of __getOwnPropNames(mod))
|
|
12
|
+
if (!__hasOwnProp.call(to, key))
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: () => mod[key],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
20
|
+
var __require = import.meta.require;
|
|
3
21
|
|
|
4
22
|
// src/cli.ts
|
|
5
23
|
import * as fs from "fs";
|
|
6
24
|
import * as path from "path";
|
|
7
25
|
import * as os from "os";
|
|
26
|
+
import { fileURLToPath } from "url";
|
|
8
27
|
var PLUGIN_NAME = "clikit-plugin";
|
|
9
|
-
var VERSION = "0.2.
|
|
28
|
+
var VERSION = "0.2.20";
|
|
29
|
+
function getPackageRoot() {
|
|
30
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
31
|
+
const currentDir = path.dirname(currentFile);
|
|
32
|
+
if (path.basename(currentDir) === "dist") {
|
|
33
|
+
return path.dirname(currentDir);
|
|
34
|
+
}
|
|
35
|
+
return path.dirname(currentDir);
|
|
36
|
+
}
|
|
37
|
+
function getPackageVersion() {
|
|
38
|
+
const packageJsonPath = path.join(getPackageRoot(), "package.json");
|
|
39
|
+
try {
|
|
40
|
+
const raw = fs.readFileSync(packageJsonPath, "utf-8");
|
|
41
|
+
const parsed = JSON.parse(raw);
|
|
42
|
+
return parsed.version || VERSION;
|
|
43
|
+
} catch {
|
|
44
|
+
return VERSION;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function getPluginEntry() {
|
|
48
|
+
return `${PLUGIN_NAME}@${getPackageVersion()}`;
|
|
49
|
+
}
|
|
50
|
+
function resolveProjectDir(env = process.env, cwd = process.cwd()) {
|
|
51
|
+
const candidates = [env.INIT_CWD, env.PWD, cwd].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
52
|
+
for (const candidate of candidates) {
|
|
53
|
+
const resolved = path.resolve(candidate);
|
|
54
|
+
try {
|
|
55
|
+
if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
|
|
56
|
+
return resolved;
|
|
57
|
+
}
|
|
58
|
+
} catch {}
|
|
59
|
+
}
|
|
60
|
+
return cwd;
|
|
61
|
+
}
|
|
62
|
+
function upsertPluginEntry(existingPlugins, pluginName, version) {
|
|
63
|
+
const filteredPlugins = existingPlugins.filter((p) => p !== pluginName && !p.startsWith(`${pluginName}@`));
|
|
64
|
+
filteredPlugins.push(`${pluginName}@${version}`);
|
|
65
|
+
return filteredPlugins;
|
|
66
|
+
}
|
|
67
|
+
function copyFileIfMissing(sourcePath, targetPath, stats) {
|
|
68
|
+
if (!fs.existsSync(sourcePath)) {
|
|
69
|
+
stats.missingSources.push(sourcePath);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (fs.existsSync(targetPath)) {
|
|
73
|
+
stats.skipped += 1;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
77
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
78
|
+
stats.copied += 1;
|
|
79
|
+
}
|
|
80
|
+
function copyDirectoryFilesIfMissing(sourceDir, targetDir, stats) {
|
|
81
|
+
if (!fs.existsSync(sourceDir)) {
|
|
82
|
+
stats.missingSources.push(sourceDir);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
86
|
+
const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
|
|
87
|
+
for (const entry of entries) {
|
|
88
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
89
|
+
const targetPath = path.join(targetDir, entry.name);
|
|
90
|
+
if (entry.isDirectory()) {
|
|
91
|
+
copyDirectoryFilesIfMissing(sourcePath, targetPath, stats);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (entry.isFile()) {
|
|
95
|
+
copyFileIfMissing(sourcePath, targetPath, stats);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function scaffoldProjectOpencode(projectDir, packageRoot = getPackageRoot()) {
|
|
100
|
+
const projectOpencodeDir = path.join(projectDir, ".opencode");
|
|
101
|
+
const stats = {
|
|
102
|
+
copied: 0,
|
|
103
|
+
skipped: 0,
|
|
104
|
+
missingSources: []
|
|
105
|
+
};
|
|
106
|
+
fs.mkdirSync(projectOpencodeDir, { recursive: true });
|
|
107
|
+
copyFileIfMissing(path.join(packageRoot, "AGENTS.md"), path.join(projectOpencodeDir, "AGENTS.md"), stats);
|
|
108
|
+
copyDirectoryFilesIfMissing(path.join(packageRoot, "command"), path.join(projectOpencodeDir, "command"), stats);
|
|
109
|
+
copyDirectoryFilesIfMissing(path.join(packageRoot, "skill"), path.join(projectOpencodeDir, "skill"), stats);
|
|
110
|
+
copyDirectoryFilesIfMissing(path.join(packageRoot, "memory", "_templates"), path.join(projectOpencodeDir, "memory", "_templates"), stats);
|
|
111
|
+
copyFileIfMissing(path.join(packageRoot, "README.md"), path.join(projectOpencodeDir, "README-clikit.md"), stats);
|
|
112
|
+
const indexPath = path.join(projectOpencodeDir, "index.ts");
|
|
113
|
+
if (!fs.existsSync(indexPath)) {
|
|
114
|
+
fs.writeFileSync(indexPath, `import CliKitPlugin from "${PLUGIN_NAME}";
|
|
115
|
+
|
|
116
|
+
export default CliKitPlugin;
|
|
117
|
+
`);
|
|
118
|
+
stats.copied += 1;
|
|
119
|
+
} else {
|
|
120
|
+
stats.skipped += 1;
|
|
121
|
+
}
|
|
122
|
+
return stats;
|
|
123
|
+
}
|
|
10
124
|
function getRealHome() {
|
|
11
125
|
if (process.env.SNAP_REAL_HOME) {
|
|
12
126
|
return process.env.SNAP_REAL_HOME;
|
|
@@ -74,7 +188,8 @@ async function install() {
|
|
|
74
188
|
CliKit Installer
|
|
75
189
|
================
|
|
76
190
|
`);
|
|
77
|
-
|
|
191
|
+
const pluginVersion = getPackageVersion();
|
|
192
|
+
console.log("[1/4] Adding CliKit plugin to OpenCode config...");
|
|
78
193
|
try {
|
|
79
194
|
ensureConfigDir();
|
|
80
195
|
} catch (err) {
|
|
@@ -91,22 +206,38 @@ async function install() {
|
|
|
91
206
|
return 1;
|
|
92
207
|
}
|
|
93
208
|
const config = result.config;
|
|
94
|
-
const existingPlugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
209
|
+
const existingPlugins = Array.isArray(config.plugin) ? config.plugin.filter((p) => typeof p === "string") : [];
|
|
95
210
|
const preservedKeys = Object.keys(config).filter((k) => k !== "plugin");
|
|
96
211
|
if (preservedKeys.length > 0) {
|
|
97
212
|
console.log(` Preserving existing config: ${preservedKeys.join(", ")}`);
|
|
98
213
|
}
|
|
99
|
-
const filteredPlugins = existingPlugins
|
|
100
|
-
filteredPlugins.push(PLUGIN_NAME);
|
|
214
|
+
const filteredPlugins = upsertPluginEntry(existingPlugins, PLUGIN_NAME, pluginVersion);
|
|
101
215
|
const newConfig = { ...config, plugin: filteredPlugins };
|
|
102
216
|
writeConfig(configPath, newConfig);
|
|
103
|
-
console.log(`\u2713 Plugin added to ${configPath}`);
|
|
217
|
+
console.log(`\u2713 Plugin added to ${configPath} as ${getPluginEntry()}`);
|
|
104
218
|
} catch (err) {
|
|
105
219
|
console.error(`\u2717 Failed to update OpenCode config: ${err}`);
|
|
106
220
|
return 1;
|
|
107
221
|
}
|
|
108
222
|
console.log(`
|
|
109
|
-
[2/
|
|
223
|
+
[2/4] Scaffolding project .opencode assets...`);
|
|
224
|
+
try {
|
|
225
|
+
const projectDir = resolveProjectDir();
|
|
226
|
+
const stats = scaffoldProjectOpencode(projectDir);
|
|
227
|
+
console.log(`\u2713 Project assets ready in ${path.join(projectDir, ".opencode")}`);
|
|
228
|
+
console.log(` Copied: ${stats.copied}, Skipped existing: ${stats.skipped}`);
|
|
229
|
+
if (stats.missingSources.length > 0) {
|
|
230
|
+
console.log(" Missing bundled sources (skipped):");
|
|
231
|
+
for (const missing of stats.missingSources) {
|
|
232
|
+
console.log(` - ${missing}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
} catch (err) {
|
|
236
|
+
console.error(`\u2717 Failed to scaffold project assets: ${err}`);
|
|
237
|
+
return 1;
|
|
238
|
+
}
|
|
239
|
+
console.log(`
|
|
240
|
+
[3/4] Creating memory directories...`);
|
|
110
241
|
const memoryDir = path.join(getConfigDir(), "memory");
|
|
111
242
|
const memorySubdirs = ["specs", "plans", "research", "reviews", "handoffs", "beads", "prds"];
|
|
112
243
|
for (const subdir of memorySubdirs) {
|
|
@@ -117,7 +248,7 @@ async function install() {
|
|
|
117
248
|
}
|
|
118
249
|
console.log(`\u2713 Memory directories created in ${memoryDir}`);
|
|
119
250
|
console.log(`
|
|
120
|
-
[
|
|
251
|
+
[4/4] Creating CliKit config...`);
|
|
121
252
|
const clikitConfigPath = path.join(getConfigDir(), "clikit.config.json");
|
|
122
253
|
if (!fs.existsSync(clikitConfigPath)) {
|
|
123
254
|
const defaultConfig = {
|
|
@@ -165,7 +296,7 @@ Examples:
|
|
|
165
296
|
`);
|
|
166
297
|
}
|
|
167
298
|
function version() {
|
|
168
|
-
console.log(`clikit-plugin v${
|
|
299
|
+
console.log(`clikit-plugin v${getPackageVersion()}`);
|
|
169
300
|
}
|
|
170
301
|
async function main() {
|
|
171
302
|
const args = process.argv.slice(2);
|
|
@@ -193,7 +324,14 @@ async function main() {
|
|
|
193
324
|
}
|
|
194
325
|
process.exit(exitCode);
|
|
195
326
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
327
|
+
if (import.meta.main) {
|
|
328
|
+
main().catch((err) => {
|
|
329
|
+
console.error(err);
|
|
330
|
+
process.exit(1);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
export {
|
|
334
|
+
upsertPluginEntry,
|
|
335
|
+
scaffoldProjectOpencode,
|
|
336
|
+
resolveProjectDir
|
|
337
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.test.d.ts","sourceRoot":"","sources":["../src/cli.test.ts"],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
|
@@ -5050,6 +5050,9 @@ function getDb() {
|
|
|
5050
5050
|
return db;
|
|
5051
5051
|
}
|
|
5052
5052
|
function memoryRead(relativePath) {
|
|
5053
|
+
if (typeof relativePath !== "string" || !relativePath.trim()) {
|
|
5054
|
+
return null;
|
|
5055
|
+
}
|
|
5053
5056
|
const fullPath = path10.join(MEMORY_DIR, relativePath);
|
|
5054
5057
|
if (!fs9.existsSync(fullPath)) {
|
|
5055
5058
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/tools/memory.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA8ED,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/tools/memory.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA8ED,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY9D;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,kBAAkB,EAAE,CAuClE;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,EAAE,CAwB3D;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,iBAAiB,EAAE,CAmCnE;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA2BnE;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,iBAAiB,CA8E9D"}
|
|
@@ -61,6 +61,8 @@ dist/index.js ← import.meta.dir points here
|
|
|
61
61
|
| 0.2.1-0.2.9 | Type guards for hooks/tools |
|
|
62
62
|
| 0.2.10 | `__dirname` → `import.meta.dir` (paths still wrong) |
|
|
63
63
|
| 0.2.11 | Correct relative paths from `dist/` directory |
|
|
64
|
+
| 0.2.19 | Retry `getObservationsByType` when SQLite reports datatype mismatch |
|
|
65
|
+
| 0.2.20 | Guard `memoryRead` against non-string paths |
|
|
64
66
|
|
|
65
67
|
---
|
|
66
68
|
|
|
@@ -116,4 +118,4 @@ Bun's bundler inlines `__dirname` to the build-time absolute path. However, `imp
|
|
|
116
118
|
|
|
117
119
|
1. All source files (`src/agents/index.ts`, `src/commands/index.ts`, `src/skills/index.ts`) are combined into a single `dist/index.js`
|
|
118
120
|
2. `import.meta.dir` in the bundled code refers to the location of `dist/index.js`, not the original source files
|
|
119
|
-
3. Resource files (`.md` files) are NOT bundled - they must be found via relative paths from `dist/`
|
|
121
|
+
3. Resource files (`.md` files) are NOT bundled - they must be found via relative paths from `dist/`
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Implementation Plan: Align CliKit Plugin Installation with OpenCode
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-02-16
|
|
4
|
+
**Author:** Plan Agent
|
|
5
|
+
**Status:** Draft
|
|
6
|
+
**bead_id:** clikit-plugin
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Define and implement an installation and configuration workflow for CliKit that mirrors Oh My OpenCode’s opinionated setup. This includes documenting the desired behavior, creating a CLI installer that automates plugin registration and config scaffolding, and updating guidance so users can reliably install via npm/local files following OpenCode’s documented plugin system.
|
|
13
|
+
|
|
14
|
+
## References
|
|
15
|
+
|
|
16
|
+
- **Spec:** *(not provided)*
|
|
17
|
+
- **PRD:** *(not provided)*
|
|
18
|
+
- **Research:** `.opencode/memory/research/2026-02-16-opencode-plugin-alignment.md` *(planned; current knowledge from repo/docs review)*
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Tasks
|
|
23
|
+
|
|
24
|
+
### Task 1: Capture Target Installation Workflow
|
|
25
|
+
|
|
26
|
+
| Field | Value |
|
|
27
|
+
|-------|-------|
|
|
28
|
+
| **task_id** | T-001 |
|
|
29
|
+
| **type** | task |
|
|
30
|
+
| **assignee** | build |
|
|
31
|
+
| **effort** | S |
|
|
32
|
+
| **priority** | P1 |
|
|
33
|
+
| **status** | not_started |
|
|
34
|
+
| **dependencies** | none |
|
|
35
|
+
|
|
36
|
+
**Description:**
|
|
37
|
+
Summarize Oh My OpenCode’s installation behavior (CLI prompts, subscription flags, config injection) and map each requirement to CliKit. Produce a short design note describing which steps we will replicate and which remain optional.
|
|
38
|
+
|
|
39
|
+
**Input:**
|
|
40
|
+
- README + docs from `code-yeongyu/oh-my-opencode`
|
|
41
|
+
- OpenCode plugin docs (`opencode.ai/docs/plugins`)
|
|
42
|
+
|
|
43
|
+
**Output:**
|
|
44
|
+
- Design note (e.g., `.opencode/memory/research/2026-02-16-opencode-plugin-alignment.md`)
|
|
45
|
+
- Checklist of actions installer must perform
|
|
46
|
+
|
|
47
|
+
**Acceptance Criteria:**
|
|
48
|
+
- [ ] AC-01: Clearly list each step Oh My OpenCode installer performs.
|
|
49
|
+
- [ ] AC-02: Define corresponding CliKit behavior (adopt/skip) with rationale.
|
|
50
|
+
|
|
51
|
+
**Boundaries:**
|
|
52
|
+
- Do not implement code changes here—documentation/research only.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### Task 2: Implement CliKit Installer CLI
|
|
57
|
+
|
|
58
|
+
| Field | Value |
|
|
59
|
+
|-------|-------|
|
|
60
|
+
| **task_id** | T-002 |
|
|
61
|
+
| **type** | feature |
|
|
62
|
+
| **assignee** | build |
|
|
63
|
+
| **effort** | M |
|
|
64
|
+
| **priority** | P0 |
|
|
65
|
+
| **status** | not_started |
|
|
66
|
+
| **dependencies** | [T-001] |
|
|
67
|
+
|
|
68
|
+
**Description:**
|
|
69
|
+
Create a `bunx clikit-plugin install` command paralleling Oh My OpenCode: accept provider flags, update `opencode.json` plugin array, scaffold `.opencode/clikit.config.json`, and emit post-install instructions. Include validation (prevent duplicates) and support non-interactive defaults.
|
|
70
|
+
|
|
71
|
+
**Input:**
|
|
72
|
+
- Output of Task 1 design note
|
|
73
|
+
- Existing `.opencode/plugin.ts`, `.opencode/src/config.ts`
|
|
74
|
+
|
|
75
|
+
**Output:**
|
|
76
|
+
- CLI script (likely under `.opencode/script/install.ts` or package bin entry)
|
|
77
|
+
- Updated package metadata so command is published
|
|
78
|
+
- Tests or manual verification steps documenting expected behavior
|
|
79
|
+
|
|
80
|
+
**Acceptance Criteria:**
|
|
81
|
+
- [ ] AC-01: Running installer registers CliKit in `plugin` array when absent and is idempotent.
|
|
82
|
+
- [ ] AC-02: Installer writes/merges config template without overwriting user overrides.
|
|
83
|
+
- [ ] AC-03: Help text documents supported flags modeled after Oh My OpenCode.
|
|
84
|
+
|
|
85
|
+
**Boundaries:**
|
|
86
|
+
- Do not modify runtime hook logic; focus on installer.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### Task 3: Update Documentation and Verification Guide
|
|
91
|
+
|
|
92
|
+
| Field | Value |
|
|
93
|
+
|-------|-------|
|
|
94
|
+
| **task_id** | T-003 |
|
|
95
|
+
| **type** | chore |
|
|
96
|
+
| **assignee** | build |
|
|
97
|
+
| **effort** | S |
|
|
98
|
+
| **priority** | P1 |
|
|
99
|
+
| **status** | not_started |
|
|
100
|
+
| **dependencies** | [T-002] |
|
|
101
|
+
|
|
102
|
+
**Description:**
|
|
103
|
+
Revise `.opencode/README.md` and root `README.md` to outline installation paths (npm + installer, manual config). Include verification steps (opencode version check, config inspection) and troubleshooting tips inspired by Oh My OpenCode docs.
|
|
104
|
+
|
|
105
|
+
**Input:**
|
|
106
|
+
- Completed installer features
|
|
107
|
+
- Task 1 research checklist
|
|
108
|
+
|
|
109
|
+
**Output:**
|
|
110
|
+
- Updated documentation referencing new CLI command, load order, and auth reminders
|
|
111
|
+
|
|
112
|
+
**Acceptance Criteria:**
|
|
113
|
+
- [ ] AC-01: README contains explicit step-by-step instructions mirroring OpenCode plugin docs.
|
|
114
|
+
- [ ] AC-02: Adds warning about not disabling core features unless required.
|
|
115
|
+
- [ ] AC-03: Describes verification commands post-install.
|
|
116
|
+
|
|
117
|
+
**Boundaries:**
|
|
118
|
+
- Do not duplicate entire Oh My OpenCode README—only relevant sections.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## File Impact
|
|
123
|
+
|
|
124
|
+
**Files to CREATE:**
|
|
125
|
+
- `.opencode/memory/research/2026-02-16-opencode-plugin-alignment.md` — research note from Task 1
|
|
126
|
+
- `script/install.ts` (or equivalent CLI entry) — new installer command logic
|
|
127
|
+
|
|
128
|
+
**Files to MODIFY:**
|
|
129
|
+
- `package.json` — add bin entry & dependencies for installer
|
|
130
|
+
- `.opencode/README.md` — refreshed installation instructions
|
|
131
|
+
- `README.md` — high-level install overview referencing CLI
|
|
132
|
+
- `.opencode/src/config.ts` — ensure config loader supports templates/merging if needed by installer
|
|
133
|
+
- `.opencode/script/` helpers (if reused) — support CLI utilities
|
|
134
|
+
|
|
135
|
+
**Files to DELETE:**
|
|
136
|
+
- (none)
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Dependencies
|
|
141
|
+
|
|
142
|
+
```mermaid
|
|
143
|
+
graph TD
|
|
144
|
+
T001[T-001: Capture Target Installation Workflow] --> T002[T-002: Implement CliKit Installer CLI]
|
|
145
|
+
T002 --> T003[T-003: Update Documentation and Verification Guide]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Effort Summary
|
|
151
|
+
|
|
152
|
+
| Task | Effort | Priority |
|
|
153
|
+
|------|--------|----------|
|
|
154
|
+
| T-001 | S | P1 |
|
|
155
|
+
| T-002 | M | P0 |
|
|
156
|
+
| T-003 | S | P1 |
|
|
157
|
+
|
|
158
|
+
**Total Estimated Effort:** ~3-4 days (including testing & docs)
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Risk Assessment
|
|
163
|
+
|
|
164
|
+
| Risk | Probability | Impact | Mitigation |
|
|
165
|
+
|------|-------------|--------|------------|
|
|
166
|
+
| Installer overwrites user config | M | M | Implement merge logic with backups + prompts |
|
|
167
|
+
| CLI divergence from OpenCode expectations | M | H | Validate against official plugin docs; add tests for load order |
|
|
168
|
+
| Users skip auth steps leading to failures | H | M | Add prominent warnings & post-install checklist |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Quick Mode Eligibility
|
|
173
|
+
|
|
174
|
+
Tasks eligible for Quick Mode (no full plan needed):
|
|
175
|
+
- [ ] T-001 (requires research + documentation > 3 files)
|
|
176
|
+
- [ ] T-002 (installer touches multiple files, so not eligible)
|
|
177
|
+
- [ ] T-003 (docs updates only but depends on T-002 completion)
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Rollout Plan
|
|
182
|
+
|
|
183
|
+
| Phase | Tasks | Milestone |
|
|
184
|
+
|-------|-------|-----------|
|
|
185
|
+
| Phase 1 | T-001 | Approved installation blueprint |
|
|
186
|
+
| Phase 2 | T-002 | Installer CLI ready & manually verified |
|
|
187
|
+
| Phase 3 | T-003 | Documentation updated & user walkthrough published |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Approval
|
|
192
|
+
|
|
193
|
+
- [ ] Plan reviewed
|
|
194
|
+
- [ ] User approved
|
|
195
|
+
- [ ] Ready for implementation
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
topic: "Oh My OpenCode Installer Behavior"
|
|
3
|
+
date: 2026-02-16
|
|
4
|
+
confidence: high
|
|
5
|
+
depth: deep
|
|
6
|
+
versions:
|
|
7
|
+
- library: "oh-my-opencode"
|
|
8
|
+
version: "3.5.5"
|
|
9
|
+
bead_id: clikit-plugin
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Research: Oh My OpenCode Installer
|
|
13
|
+
|
|
14
|
+
**Question:** How does oh-my-opencode's installer configure OpenCode and what pieces should CliKit replicate?
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Summary
|
|
19
|
+
|
|
20
|
+
Oh My OpenCode's CLI installer (`bunx oh-my-opencode install`) performs a six-step workflow: it validates CLI args, checks for the OpenCode binary/version, ensures the plugin entry exists in `opencode.json`, optionally installs auth/provider configs (Gemini et al.), writes/merges a dedicated `oh-my-opencode` config file, and prints guidance/warnings. Config files live under both the global config dir (`~/.config/opencode`) and per-project `.opencode`. CliKit's installer should mirror the config detection/merge logic and idempotent plugin registration.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Key Findings
|
|
25
|
+
|
|
26
|
+
### Finding 1: Installer Flow Mirrors Documented Steps
|
|
27
|
+
- `runCliInstaller` (dist/cli/index.js) orchestrates 6 numbered steps: detect OpenCode binary/version, add plugin entry, add auth plugins (conditional), add provider config (conditional), and write final `oh-my-opencode` config before printing summary boxes.
|
|
28
|
+
- Non-interactive mode requires explicit provider flags (`--claude`, `--gemini`, `--copilot`, etc.); otherwise TUI handles prompts.
|
|
29
|
+
- Failure at any sub-step aborts with contextual error text (`formatErrorWithSuggestion`).
|
|
30
|
+
|
|
31
|
+
### Finding 2: Plugin Registration Logic is Idempotent
|
|
32
|
+
- `addPluginToOpenCodeConfig(version)` ensures `~/.config/opencode/opencode.json[c]` exists, parses JSON/JSONC, removes prior `oh-my-opencode` entries, and writes the latest pinned version string (e.g., `oh-my-opencode@3.5.5`).
|
|
33
|
+
- JSONC files are updated by regex replacement to preserve comments/formatting; JSON files are re-serialized.
|
|
34
|
+
- This mirrors what CliKit's installer must do for `clikit-plugin`, including detection of config dir via `getOpenCodeConfigDir` semantics.
|
|
35
|
+
|
|
36
|
+
### Finding 3: Config Merge Targets Global + Project Paths
|
|
37
|
+
- `writeOmoConfig` writes `oh-my-opencode.json` (or `.jsonc`) inside `~/.config/opencode/oh-my-opencode.*`, using `deepMergeRecord` against existing JSONC.
|
|
38
|
+
- Loader functions (e.g., `loadPluginConfig`) look at both global config dir and per-project `.opencode/oh-my-opencode.*`, merging project overrides atop global defaults.
|
|
39
|
+
- Ensuring CliKit's installer writes `~/.config/opencode/clikit.config.json` (global) while respecting `.opencode/clikit.config.json` matches OpenCode expectations.
|
|
40
|
+
|
|
41
|
+
### Finding 4: Ancillary Setup (Auth, Providers, bun install)
|
|
42
|
+
- When Gemini support is requested, installer calls `addAuthPlugins` and `addProviderConfig` to inject additional packages/config references.
|
|
43
|
+
- After plugin or binary updates, oh-my-opencode optionally runs `bun install` inside the config dir to ensure dependencies exist (`runBunInstall`).
|
|
44
|
+
- CliKit may not need auth/provider hooks yet but should adopt the same structure for future flags, and consider invoking `bun install` when copying template files that introduce dependencies.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Comparison
|
|
49
|
+
|
|
50
|
+
| Aspect | Oh My OpenCode | Current CliKit | Gap |
|
|
51
|
+
|--------|----------------|----------------|-----|
|
|
52
|
+
| Plugin registration | Adds/updates versioned entry in `plugin` array with JSONC-safe merge | Adds bare `clikit-plugin` without version, no JSONC handling | Need versioned entry + JSONC-safe edits |
|
|
53
|
+
| Config scaffolding | Writes `oh-my-opencode.json` w/ deep merge fallback | Writes `clikit.config.json` only if missing, no merge | Implement deep merge + JSONC parse guard |
|
|
54
|
+
| Provider/auth flags | Supports `--claude`, `--gemini`, `--copilot`, `--opencode-zen`, etc. | No flags | Evaluate minimal flag set / defaults |
|
|
55
|
+
| Dependency setup | Runs `bun install` when necessary | None | Optional follow-up |
|
|
56
|
+
| Project overrides | Loader merges global + `.opencode/oh-my-opencode.*` | Loader already merges `~/.config` + project `.opencode` | Already aligned |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Code Examples
|
|
61
|
+
|
|
62
|
+
### Example 1: Adding Plugin Entry (pseudo-extracted)
|
|
63
|
+
```ts
|
|
64
|
+
const pluginEntry = await getPluginNameWithVersion(currentVersion);
|
|
65
|
+
const parseResult = parseOpenCodeConfigFileWithError(path);
|
|
66
|
+
const plugins = (parseResult.config.plugin ?? []).filter(
|
|
67
|
+
(p) => !p.startsWith("oh-my-opencode")
|
|
68
|
+
);
|
|
69
|
+
plugins.push(pluginEntry);
|
|
70
|
+
writeConfigPreservingFormat(path, plugins);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Example 2: Writing Config with Deep Merge
|
|
74
|
+
```ts
|
|
75
|
+
const omoConfigPath = getOmoConfigPath();
|
|
76
|
+
const newConfig = generateOmoConfig(installConfig);
|
|
77
|
+
if (existsSync(omoConfigPath)) {
|
|
78
|
+
const existing = parseJsonc(readFileSync(omoConfigPath, "utf8"));
|
|
79
|
+
const merged = deepMergeRecord(existing, newConfig);
|
|
80
|
+
writeFileSync(omoConfigPath, JSON.stringify(merged, null, 2));
|
|
81
|
+
} else {
|
|
82
|
+
writeFileSync(omoConfigPath, JSON.stringify(newConfig, null, 2));
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Recommendation
|
|
89
|
+
|
|
90
|
+
**Recommended approach:** Reimplement CliKit's installer to follow Oh My OpenCode's structure.
|
|
91
|
+
|
|
92
|
+
**Rationale:**
|
|
93
|
+
1. Users already expect the oh-my-opencode workflow; mirroring it reduces friction.
|
|
94
|
+
2. JSONC-safe merging and versioned plugin entries prevent config corruption and enable updates.
|
|
95
|
+
3. Aligning directories and merge logic ensures compatibility with OpenCode's plugin loader (global + project overrides).
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Verification Steps
|
|
100
|
+
|
|
101
|
+
- [ ] Validate installer on machines with `opencode.json` and `opencode.jsonc` variants.
|
|
102
|
+
- [ ] Confirm repeated `bun x clikit-plugin install` leaves config unchanged and updates version.
|
|
103
|
+
- [ ] Ensure `.opencode/clikit.config.json` overrides global values after install.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Open Questions
|
|
108
|
+
|
|
109
|
+
- [ ] Which provider flags should CliKit expose initially (Claude-only vs. multi-provider)?
|
|
110
|
+
- [ ] Do we need to run `bun install` inside `~/.config/opencode` after copying CliKit assets?
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Sources
|
|
115
|
+
|
|
116
|
+
| Source | Type | Reliability |
|
|
117
|
+
|--------|------|-------------|
|
|
118
|
+
| `oh-my-opencode@3.5.5` package (`dist/cli/index.js`, `postinstall.mjs`) | Source | High |
|
|
119
|
+
| OpenCode config conventions from oh-my-opencode loader | Source | High |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Version Notes
|
|
124
|
+
|
|
125
|
+
| Library/Tool | Version Researched | Current Latest | Notes |
|
|
126
|
+
|--------------|-------------------|----------------|-------|
|
|
127
|
+
| oh-my-opencode | 3.5.5 | 3.5.5 | Latest on npm during research |
|
|
128
|
+
| clikit-plugin | 0.2.20 | 0.2.20 | Installer work in progress |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clikit-plugin",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.21",
|
|
4
4
|
"description": "OpenCode plugin with 10 agents, 19 commands, 48 skills, 14 hooks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"scripts": {
|
|
28
|
-
"build": "bun build src/index.ts src/cli.ts --outdir dist --target bun --format esm && tsc --emitDeclarationOnly && cp src/clikit.schema.json dist/",
|
|
28
|
+
"build": "bun build src/index.ts src/cli.ts --outdir dist --target bun --format esm && tsc --emitDeclarationOnly && cp src/clikit.schema.json dist/ 2>/dev/null || true",
|
|
29
29
|
"clean": "rm -rf dist",
|
|
30
30
|
"prepublishOnly": "bun run clean && bun run build",
|
|
31
31
|
"typecheck": "tsc --noEmit",
|
package/dist/clikit.schema.json
DELETED
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"title": "CliKit Plugin Configuration",
|
|
4
|
-
"description": "Configuration for CliKit OpenCode plugin",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"properties": {
|
|
7
|
-
"disabled_agents": {
|
|
8
|
-
"type": "array",
|
|
9
|
-
"items": { "type": "string" },
|
|
10
|
-
"description": "List of agent names to disable",
|
|
11
|
-
"examples": [["scout"]]
|
|
12
|
-
},
|
|
13
|
-
"disabled_commands": {
|
|
14
|
-
"type": "array",
|
|
15
|
-
"items": { "type": "string" },
|
|
16
|
-
"description": "List of command names to disable",
|
|
17
|
-
"examples": [["debug", "import-plan"]]
|
|
18
|
-
},
|
|
19
|
-
"agents": {
|
|
20
|
-
"type": "object",
|
|
21
|
-
"description": "Override settings for specific agents",
|
|
22
|
-
"additionalProperties": {
|
|
23
|
-
"type": "object",
|
|
24
|
-
"properties": {
|
|
25
|
-
"model": { "type": "string", "description": "Override model for this agent" },
|
|
26
|
-
"temperature": { "type": "number", "minimum": 0, "maximum": 2 },
|
|
27
|
-
"top_p": { "type": "number", "minimum": 0, "maximum": 1 },
|
|
28
|
-
"mode": { "enum": ["subagent", "primary", "all"] },
|
|
29
|
-
"disabled": { "type": "boolean", "description": "Disable this agent" },
|
|
30
|
-
"color": { "type": "string", "description": "Agent color in UI" },
|
|
31
|
-
"maxSteps": { "type": "integer", "minimum": 1, "description": "Maximum steps for agent" },
|
|
32
|
-
"tools": {
|
|
33
|
-
"type": "object",
|
|
34
|
-
"additionalProperties": { "type": "boolean" }
|
|
35
|
-
},
|
|
36
|
-
"permission": {
|
|
37
|
-
"type": "object",
|
|
38
|
-
"description": "Permission overrides for this agent",
|
|
39
|
-
"properties": {
|
|
40
|
-
"edit": { "enum": ["ask", "allow", "deny"] },
|
|
41
|
-
"bash": {
|
|
42
|
-
"oneOf": [
|
|
43
|
-
{ "enum": ["ask", "allow", "deny"] },
|
|
44
|
-
{ "type": "object", "additionalProperties": { "enum": ["ask", "allow", "deny"] } }
|
|
45
|
-
]
|
|
46
|
-
},
|
|
47
|
-
"webfetch": { "enum": ["ask", "allow", "deny"] },
|
|
48
|
-
"doom_loop": { "enum": ["ask", "allow", "deny"] },
|
|
49
|
-
"external_directory": { "enum": ["ask", "allow", "deny"] }
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
"commands": {
|
|
56
|
-
"type": "object",
|
|
57
|
-
"description": "Override settings for specific commands",
|
|
58
|
-
"additionalProperties": {
|
|
59
|
-
"type": "object",
|
|
60
|
-
"properties": {
|
|
61
|
-
"agent": { "type": "string", "description": "Agent to use for this command" },
|
|
62
|
-
"model": { "type": "string", "description": "Model to use for this command" },
|
|
63
|
-
"subtask": { "type": "boolean", "description": "Run as subtask" },
|
|
64
|
-
"description": { "type": "string", "description": "Command description" },
|
|
65
|
-
"template": { "type": "string", "description": "Command template/prompt" }
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
"lsp": {
|
|
70
|
-
"type": "object",
|
|
71
|
-
"description": "LSP server configurations to inject into OpenCode",
|
|
72
|
-
"additionalProperties": {
|
|
73
|
-
"type": "object",
|
|
74
|
-
"required": ["command"],
|
|
75
|
-
"properties": {
|
|
76
|
-
"command": {
|
|
77
|
-
"type": "array",
|
|
78
|
-
"items": { "type": "string" },
|
|
79
|
-
"description": "Command and arguments to start the LSP server"
|
|
80
|
-
},
|
|
81
|
-
"extensions": {
|
|
82
|
-
"type": "array",
|
|
83
|
-
"items": { "type": "string" },
|
|
84
|
-
"description": "File extensions this LSP handles (e.g., ['.ts', '.tsx'])"
|
|
85
|
-
},
|
|
86
|
-
"priority": { "type": "integer", "description": "Priority when multiple LSPs match (higher = preferred)" },
|
|
87
|
-
"disabled": { "type": "boolean", "description": "Disable this LSP server" },
|
|
88
|
-
"env": {
|
|
89
|
-
"type": "object",
|
|
90
|
-
"additionalProperties": { "type": "string" },
|
|
91
|
-
"description": "Environment variables for the LSP process"
|
|
92
|
-
},
|
|
93
|
-
"initialization": {
|
|
94
|
-
"type": "object",
|
|
95
|
-
"description": "LSP initialization options"
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
"examples": [{
|
|
100
|
-
"typescript": {
|
|
101
|
-
"command": ["typescript-language-server", "--stdio"],
|
|
102
|
-
"extensions": [".ts", ".tsx", ".js", ".jsx"]
|
|
103
|
-
}
|
|
104
|
-
}]
|
|
105
|
-
},
|
|
106
|
-
"hooks": {
|
|
107
|
-
"type": "object",
|
|
108
|
-
"properties": {
|
|
109
|
-
"session_logging": {
|
|
110
|
-
"type": "boolean",
|
|
111
|
-
"default": true,
|
|
112
|
-
"description": "Enable session lifecycle logging"
|
|
113
|
-
},
|
|
114
|
-
"tool_logging": {
|
|
115
|
-
"type": "boolean",
|
|
116
|
-
"default": false,
|
|
117
|
-
"description": "Enable tool execution logging"
|
|
118
|
-
},
|
|
119
|
-
"todo_enforcer": {
|
|
120
|
-
"type": "object",
|
|
121
|
-
"description": "Todo continuation enforcer - warns when todos are incomplete",
|
|
122
|
-
"properties": {
|
|
123
|
-
"enabled": {
|
|
124
|
-
"type": "boolean",
|
|
125
|
-
"default": true,
|
|
126
|
-
"description": "Enable todo completion checking"
|
|
127
|
-
},
|
|
128
|
-
"warn_on_incomplete": {
|
|
129
|
-
"type": "boolean",
|
|
130
|
-
"default": true,
|
|
131
|
-
"description": "Log warning when todos are incomplete"
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
"empty_message_sanitizer": {
|
|
136
|
-
"type": "object",
|
|
137
|
-
"description": "Empty message sanitizer - prevents API errors from empty outputs",
|
|
138
|
-
"properties": {
|
|
139
|
-
"enabled": {
|
|
140
|
-
"type": "boolean",
|
|
141
|
-
"default": true,
|
|
142
|
-
"description": "Enable empty message sanitization"
|
|
143
|
-
},
|
|
144
|
-
"log_empty": {
|
|
145
|
-
"type": "boolean",
|
|
146
|
-
"default": true,
|
|
147
|
-
"description": "Log when empty messages are detected"
|
|
148
|
-
},
|
|
149
|
-
"placeholder": {
|
|
150
|
-
"type": "string",
|
|
151
|
-
"default": "(No output)",
|
|
152
|
-
"description": "Placeholder text for empty outputs"
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
"git_guard": {
|
|
157
|
-
"type": "object",
|
|
158
|
-
"description": "Blocks dangerous git commands (force push, hard reset, rm -rf)",
|
|
159
|
-
"properties": {
|
|
160
|
-
"enabled": {
|
|
161
|
-
"type": "boolean",
|
|
162
|
-
"default": true,
|
|
163
|
-
"description": "Enable git command guard"
|
|
164
|
-
},
|
|
165
|
-
"allow_force_with_lease": {
|
|
166
|
-
"type": "boolean",
|
|
167
|
-
"default": true,
|
|
168
|
-
"description": "Allow --force-with-lease as a safer alternative"
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
"security_check": {
|
|
173
|
-
"type": "object",
|
|
174
|
-
"description": "Scans for secrets and credentials before git commits",
|
|
175
|
-
"properties": {
|
|
176
|
-
"enabled": {
|
|
177
|
-
"type": "boolean",
|
|
178
|
-
"default": true,
|
|
179
|
-
"description": "Enable secret scanning"
|
|
180
|
-
},
|
|
181
|
-
"block_commits": {
|
|
182
|
-
"type": "boolean",
|
|
183
|
-
"default": false,
|
|
184
|
-
"description": "Block commits when secrets are detected (vs. warn only)"
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
"subagent_question_blocker": {
|
|
189
|
-
"type": "object",
|
|
190
|
-
"description": "Prevents subagents from asking clarifying questions",
|
|
191
|
-
"properties": {
|
|
192
|
-
"enabled": {
|
|
193
|
-
"type": "boolean",
|
|
194
|
-
"default": true,
|
|
195
|
-
"description": "Enable subagent question blocking"
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
"comment_checker": {
|
|
200
|
-
"type": "object",
|
|
201
|
-
"description": "Detects excessive AI-generated comments in code",
|
|
202
|
-
"properties": {
|
|
203
|
-
"enabled": {
|
|
204
|
-
"type": "boolean",
|
|
205
|
-
"default": true,
|
|
206
|
-
"description": "Enable comment density checking"
|
|
207
|
-
},
|
|
208
|
-
"threshold": {
|
|
209
|
-
"type": "number",
|
|
210
|
-
"default": 0.3,
|
|
211
|
-
"minimum": 0,
|
|
212
|
-
"maximum": 1,
|
|
213
|
-
"description": "Comment-to-code ratio threshold (0.3 = 30%)"
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
"env_context": {
|
|
218
|
-
"type": "object",
|
|
219
|
-
"description": "Injects project structure, git branch, and build system info",
|
|
220
|
-
"properties": {
|
|
221
|
-
"enabled": {
|
|
222
|
-
"type": "boolean",
|
|
223
|
-
"default": true,
|
|
224
|
-
"description": "Enable environment context injection"
|
|
225
|
-
},
|
|
226
|
-
"include_git": {
|
|
227
|
-
"type": "boolean",
|
|
228
|
-
"default": true,
|
|
229
|
-
"description": "Include git branch and status"
|
|
230
|
-
},
|
|
231
|
-
"include_package": {
|
|
232
|
-
"type": "boolean",
|
|
233
|
-
"default": true,
|
|
234
|
-
"description": "Include package.json info"
|
|
235
|
-
},
|
|
236
|
-
"include_structure": {
|
|
237
|
-
"type": "boolean",
|
|
238
|
-
"default": true,
|
|
239
|
-
"description": "Include project directory structure"
|
|
240
|
-
},
|
|
241
|
-
"max_depth": {
|
|
242
|
-
"type": "integer",
|
|
243
|
-
"default": 2,
|
|
244
|
-
"minimum": 1,
|
|
245
|
-
"maximum": 5,
|
|
246
|
-
"description": "Max depth for directory structure scan"
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
"auto_format": {
|
|
251
|
-
"type": "object",
|
|
252
|
-
"description": "Runs project formatter after file edits (prettier, biome, dprint)",
|
|
253
|
-
"properties": {
|
|
254
|
-
"enabled": {
|
|
255
|
-
"type": "boolean",
|
|
256
|
-
"default": false,
|
|
257
|
-
"description": "Enable auto-formatting (off by default)"
|
|
258
|
-
},
|
|
259
|
-
"formatter": {
|
|
260
|
-
"type": "string",
|
|
261
|
-
"enum": ["prettier", "biome", "dprint"],
|
|
262
|
-
"description": "Override formatter (auto-detected if not set)"
|
|
263
|
-
},
|
|
264
|
-
"extensions": {
|
|
265
|
-
"type": "array",
|
|
266
|
-
"items": { "type": "string" },
|
|
267
|
-
"description": "File extensions to format (e.g., ['.ts', '.tsx'])"
|
|
268
|
-
},
|
|
269
|
-
"log": {
|
|
270
|
-
"type": "boolean",
|
|
271
|
-
"default": true,
|
|
272
|
-
"description": "Log format operations"
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
},
|
|
276
|
-
"typecheck_gate": {
|
|
277
|
-
"type": "object",
|
|
278
|
-
"description": "Runs TypeScript type checking after .ts/.tsx file edits",
|
|
279
|
-
"properties": {
|
|
280
|
-
"enabled": {
|
|
281
|
-
"type": "boolean",
|
|
282
|
-
"default": false,
|
|
283
|
-
"description": "Enable typecheck gate (off by default)"
|
|
284
|
-
},
|
|
285
|
-
"tsconfig": {
|
|
286
|
-
"type": "string",
|
|
287
|
-
"description": "Path to tsconfig.json (auto-detected if not set)"
|
|
288
|
-
},
|
|
289
|
-
"log": {
|
|
290
|
-
"type": "boolean",
|
|
291
|
-
"default": true,
|
|
292
|
-
"description": "Log typecheck results"
|
|
293
|
-
},
|
|
294
|
-
"block_on_error": {
|
|
295
|
-
"type": "boolean",
|
|
296
|
-
"default": false,
|
|
297
|
-
"description": "Block file writes when type errors are found"
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
"session_notification": {
|
|
302
|
-
"type": "object",
|
|
303
|
-
"description": "Desktop notifications when sessions complete or error",
|
|
304
|
-
"properties": {
|
|
305
|
-
"enabled": {
|
|
306
|
-
"type": "boolean",
|
|
307
|
-
"default": true,
|
|
308
|
-
"description": "Enable desktop notifications"
|
|
309
|
-
},
|
|
310
|
-
"on_idle": {
|
|
311
|
-
"type": "boolean",
|
|
312
|
-
"default": true,
|
|
313
|
-
"description": "Notify when session goes idle"
|
|
314
|
-
},
|
|
315
|
-
"on_error": {
|
|
316
|
-
"type": "boolean",
|
|
317
|
-
"default": true,
|
|
318
|
-
"description": "Notify on session errors"
|
|
319
|
-
},
|
|
320
|
-
"title_prefix": {
|
|
321
|
-
"type": "string",
|
|
322
|
-
"default": "OpenCode",
|
|
323
|
-
"description": "Prefix for notification titles"
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
"truncator": {
|
|
328
|
-
"type": "object",
|
|
329
|
-
"description": "Dynamic output truncation to prevent context overflow",
|
|
330
|
-
"properties": {
|
|
331
|
-
"enabled": {
|
|
332
|
-
"type": "boolean",
|
|
333
|
-
"default": true,
|
|
334
|
-
"description": "Enable output truncation"
|
|
335
|
-
},
|
|
336
|
-
"max_output_chars": {
|
|
337
|
-
"type": "integer",
|
|
338
|
-
"default": 30000,
|
|
339
|
-
"description": "Maximum output characters before truncation"
|
|
340
|
-
},
|
|
341
|
-
"max_output_lines": {
|
|
342
|
-
"type": "integer",
|
|
343
|
-
"default": 500,
|
|
344
|
-
"description": "Maximum output lines before truncation"
|
|
345
|
-
},
|
|
346
|
-
"preserve_head_lines": {
|
|
347
|
-
"type": "integer",
|
|
348
|
-
"default": 50,
|
|
349
|
-
"description": "Lines to preserve from the start"
|
|
350
|
-
},
|
|
351
|
-
"preserve_tail_lines": {
|
|
352
|
-
"type": "integer",
|
|
353
|
-
"default": 50,
|
|
354
|
-
"description": "Lines to preserve from the end"
|
|
355
|
-
},
|
|
356
|
-
"log": {
|
|
357
|
-
"type": "boolean",
|
|
358
|
-
"default": true,
|
|
359
|
-
"description": "Log truncation events"
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
},
|
|
363
|
-
"compaction": {
|
|
364
|
-
"type": "object",
|
|
365
|
-
"description": "Preserves beads state and memory during context compaction",
|
|
366
|
-
"properties": {
|
|
367
|
-
"enabled": {
|
|
368
|
-
"type": "boolean",
|
|
369
|
-
"default": true,
|
|
370
|
-
"description": "Enable compaction state preservation"
|
|
371
|
-
},
|
|
372
|
-
"include_beads_state": {
|
|
373
|
-
"type": "boolean",
|
|
374
|
-
"default": true,
|
|
375
|
-
"description": "Include beads-village task state"
|
|
376
|
-
},
|
|
377
|
-
"include_memory_refs": {
|
|
378
|
-
"type": "boolean",
|
|
379
|
-
"default": true,
|
|
380
|
-
"description": "Include recent memory references"
|
|
381
|
-
},
|
|
382
|
-
"include_todo_state": {
|
|
383
|
-
"type": "boolean",
|
|
384
|
-
"default": true,
|
|
385
|
-
"description": "Include current todo list state"
|
|
386
|
-
},
|
|
387
|
-
"max_state_chars": {
|
|
388
|
-
"type": "integer",
|
|
389
|
-
"default": 5000,
|
|
390
|
-
"description": "Maximum characters for compaction context"
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
},
|
|
394
|
-
"swarm_enforcer": {
|
|
395
|
-
"type": "object",
|
|
396
|
-
"description": "Enforces task isolation for multi-agent swarms",
|
|
397
|
-
"properties": {
|
|
398
|
-
"enabled": {
|
|
399
|
-
"type": "boolean",
|
|
400
|
-
"default": false,
|
|
401
|
-
"description": "Enable swarm enforcement (off by default)"
|
|
402
|
-
},
|
|
403
|
-
"strict_file_locking": {
|
|
404
|
-
"type": "boolean",
|
|
405
|
-
"default": true,
|
|
406
|
-
"description": "Only allow edits to reserved files"
|
|
407
|
-
},
|
|
408
|
-
"block_unreserved_edits": {
|
|
409
|
-
"type": "boolean",
|
|
410
|
-
"default": false,
|
|
411
|
-
"description": "Block edits to unreserved files (vs. warn)"
|
|
412
|
-
},
|
|
413
|
-
"log": {
|
|
414
|
-
"type": "boolean",
|
|
415
|
-
"default": true,
|
|
416
|
-
"description": "Log enforcement decisions"
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|