opencode-resolve 0.1.0 → 0.1.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/README.md +9 -1
- package/package.json +2 -1
- package/scripts/postinstall.mjs +105 -0
package/README.md
CHANGED
|
@@ -24,7 +24,15 @@ Install this where OpenCode resolves plugins from. For most users, a global inst
|
|
|
24
24
|
npm install -g opencode-resolve
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
The package automatically registers itself in `~/.config/opencode/opencode.json` during `postinstall` and creates `~/.config/opencode/resolve.json` when missing.
|
|
28
|
+
|
|
29
|
+
To skip automatic registration:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
OPENCODE_RESOLVE_SKIP_POSTINSTALL=1 npm install -g opencode-resolve
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Manual config fallback:
|
|
28
36
|
|
|
29
37
|
```json
|
|
30
38
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-resolve",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "OpenCode plugin that adds a small coder/reviewer agent set while preserving native plan/build behavior.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/jshsakura/opencode-resolve#readme",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "tsc -p tsconfig.json",
|
|
31
31
|
"install:local": "npm run build && node scripts/install-local.mjs",
|
|
32
|
+
"postinstall": "node scripts/postinstall.mjs",
|
|
32
33
|
"prepack": "npm test",
|
|
33
34
|
"test": "npm run build && node --test test/*.mjs",
|
|
34
35
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { constants } from "node:fs"
|
|
2
|
+
import { access, copyFile, mkdir, readFile, writeFile } from "node:fs/promises"
|
|
3
|
+
import { homedir } from "node:os"
|
|
4
|
+
import { dirname, join, resolve } from "node:path"
|
|
5
|
+
import { fileURLToPath } from "node:url"
|
|
6
|
+
|
|
7
|
+
const packageName = "opencode-resolve"
|
|
8
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..")
|
|
9
|
+
const configDir = process.env.OPENCODE_CONFIG_HOME || join(homedir(), ".config", "opencode")
|
|
10
|
+
const opencodeConfigPath = join(configDir, "opencode.json")
|
|
11
|
+
const resolveConfigPath = join(configDir, "resolve.json")
|
|
12
|
+
const exampleConfigPath = join(root, "opencode-resolve.example.json")
|
|
13
|
+
|
|
14
|
+
if (process.env.OPENCODE_RESOLVE_SKIP_POSTINSTALL === "1") {
|
|
15
|
+
process.exit(0)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
await registerPlugin()
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.warn(`[${packageName}] automatic OpenCode registration skipped: ${formatError(error)}`)
|
|
22
|
+
console.warn(`[${packageName}] add "${packageName}" to your OpenCode plugin list manually if needed.`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function registerPlugin() {
|
|
26
|
+
await mkdir(configDir, { recursive: true })
|
|
27
|
+
|
|
28
|
+
const config = await readOpenCodeConfig()
|
|
29
|
+
const changed = addPlugin(config)
|
|
30
|
+
|
|
31
|
+
if (changed) {
|
|
32
|
+
await writeFile(opencodeConfigPath, `${JSON.stringify(config, null, 2)}\n`)
|
|
33
|
+
console.log(`[${packageName}] registered in ${opencodeConfigPath}`)
|
|
34
|
+
} else {
|
|
35
|
+
console.log(`[${packageName}] already registered in ${opencodeConfigPath}`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!(await exists(resolveConfigPath))) {
|
|
39
|
+
await assertReadable(exampleConfigPath)
|
|
40
|
+
await copyFile(exampleConfigPath, resolveConfigPath)
|
|
41
|
+
console.log(`[${packageName}] created ${resolveConfigPath}`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function readOpenCodeConfig() {
|
|
46
|
+
if (!(await exists(opencodeConfigPath))) {
|
|
47
|
+
return {
|
|
48
|
+
$schema: "https://opencode.ai/config.json",
|
|
49
|
+
plugin: [],
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const raw = await readFile(opencodeConfigPath, "utf8")
|
|
54
|
+
const parsed = JSON.parse(raw)
|
|
55
|
+
if (!isObject(parsed)) throw new Error(`${opencodeConfigPath} must contain a JSON object`)
|
|
56
|
+
return parsed
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function addPlugin(config) {
|
|
60
|
+
config.plugin ??= []
|
|
61
|
+
if (!Array.isArray(config.plugin)) {
|
|
62
|
+
throw new Error(`${opencodeConfigPath}.plugin must be an array`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (config.plugin.some(isRegisteredPluginEntry)) return false
|
|
66
|
+
config.plugin.push(packageName)
|
|
67
|
+
return true
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isRegisteredPluginEntry(entry) {
|
|
71
|
+
if (typeof entry === "string") return isResolvePluginName(entry)
|
|
72
|
+
if (Array.isArray(entry) && typeof entry[0] === "string") return isResolvePluginName(entry[0])
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isResolvePluginName(value) {
|
|
77
|
+
const name = value.split("/").pop() || value
|
|
78
|
+
return name === packageName || name.startsWith(`${packageName}@`)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function assertReadable(path) {
|
|
82
|
+
await access(path, constants.R_OK)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function exists(path) {
|
|
86
|
+
try {
|
|
87
|
+
await access(path)
|
|
88
|
+
return true
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (isMissingFileError(error)) return false
|
|
91
|
+
throw error
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function isMissingFileError(error) {
|
|
96
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT"
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function isObject(value) {
|
|
100
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function formatError(error) {
|
|
104
|
+
return error instanceof Error ? error.message : String(error)
|
|
105
|
+
}
|