opencode-codeops 1.4.0 → 1.5.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/CHANGELOG.md +7 -0
- package/README.md +25 -30
- package/bin/index.mjs +129 -47
- package/bin/install-agents.mjs +8 -11
- package/bin/install-skills.mjs +8 -11
- package/bin/lib/opencode-install.mjs +3 -2
- package/install.sh +9 -9
- package/package.json +1 -1
- package/plugin/index.ts +3 -3
- package/skills/setup-codeops/scaffold.md +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to CodeOps are recorded here.
|
|
4
4
|
|
|
5
|
+
## 1.5.0 — 2026-09-19
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- installer: unify install/update into one command
|
|
10
|
+
- installer: add npm-first install, agents installer, and release tooling
|
|
11
|
+
|
|
5
12
|
## 1.4.0 — 2026-09-19
|
|
6
13
|
|
|
7
14
|
### Features
|
package/README.md
CHANGED
|
@@ -45,41 +45,46 @@ Add to your `opencode.json`:
|
|
|
45
45
|
OpenCode installs the plugin automatically via Bun on next startup. A global config
|
|
46
46
|
(`~/.config/opencode/opencode.json`) is recommended so CodeOps is active in every project.
|
|
47
47
|
|
|
48
|
-
### 2. Install the skills
|
|
48
|
+
### 2. Install the skills and subagents
|
|
49
49
|
|
|
50
|
-
OpenCode discovers skills only from the filesystem
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
OpenCode discovers skills and subagents only from the filesystem; it never reads them from a plugin
|
|
51
|
+
package. One command installs both. The installer is a thin `npx` wrapper around this package, so
|
|
52
|
+
the installed files always match the published version:
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
55
|
# Global (recommended) — available in every OpenCode project
|
|
56
56
|
curl -fsSL https://cdn.jsdelivr.net/npm/opencode-codeops@latest/install.sh | bash
|
|
57
57
|
|
|
58
|
-
# Project-only —
|
|
58
|
+
# Project-only — files live in ./.opencode and are committed with the repo
|
|
59
59
|
curl -fsSL https://cdn.jsdelivr.net/npm/opencode-codeops@latest/install.sh | bash -s -- --project
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
The same installer runs directly through npm:
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
npx -y opencode-codeops@latest install
|
|
65
|
+
npx -y opencode-codeops@latest install
|
|
66
|
+
npx -y opencode-codeops@latest update # alias of install
|
|
66
67
|
```
|
|
67
68
|
|
|
69
|
+
The scope is auto-detected: inside a CodeOps project (a git repo with `.opencode/` or
|
|
70
|
+
`codeops/.codeops.yml`) it installs into `./.opencode/skills` and `./.opencode/agents`; anywhere
|
|
71
|
+
else it installs globally into `~/.config/opencode/`. Pass `--project` or `--global` to force one.
|
|
72
|
+
|
|
68
73
|
Pin a version with `CODEOPS_VERSION` (an npm dist-tag or exact version; defaults to `latest`):
|
|
69
74
|
|
|
70
75
|
```bash
|
|
71
|
-
CODEOPS_VERSION=1.
|
|
76
|
+
CODEOPS_VERSION=1.5.0 curl -fsSL https://cdn.jsdelivr.net/npm/opencode-codeops@latest/install.sh | bash
|
|
72
77
|
```
|
|
73
78
|
|
|
74
79
|
Pin the plugin to the same version so the two cannot drift apart:
|
|
75
80
|
|
|
76
81
|
```json
|
|
77
|
-
{ "plugin": ["opencode-codeops@1.
|
|
82
|
+
{ "plugin": ["opencode-codeops@1.5.0"] }
|
|
78
83
|
```
|
|
79
84
|
|
|
80
85
|
Re-running the installer upgrades an existing install in place. It replaces only the files this
|
|
81
|
-
package owns, recorded in
|
|
82
|
-
|
|
86
|
+
package owns, recorded in `.opencode-codeops.json`. Files you author yourself, or install with
|
|
87
|
+
another tool, are left untouched.
|
|
83
88
|
|
|
84
89
|
Check or remove an install:
|
|
85
90
|
|
|
@@ -88,47 +93,37 @@ npx -y opencode-codeops@latest status
|
|
|
88
93
|
npx -y opencode-codeops@latest uninstall
|
|
89
94
|
```
|
|
90
95
|
|
|
91
|
-
`status` reports the installed version next to the current package version, so a plugin/
|
|
92
|
-
mismatch is visible. Use `--dry-run` to preview an install; a same-named
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
### 3. Install the subagents
|
|
96
|
-
|
|
97
|
-
The 12 CodeOps subagents install into `.opencode/agents/` (project) or `~/.config/opencode/agents/`
|
|
98
|
-
(global). The `/setup-codeops` skill does this for a project; do it manually with:
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
npx -y opencode-codeops@latest install-agents --project
|
|
102
|
-
```
|
|
96
|
+
`status` reports the installed version next to the current package version, so a plugin/files
|
|
97
|
+
mismatch is visible. Use `--dry-run` to preview an install; a same-named file the package does not
|
|
98
|
+
own is skipped with a warning, and `--force` replaces it.
|
|
103
99
|
|
|
104
100
|
### Local development
|
|
105
101
|
|
|
106
|
-
Symlink the plugin into your OpenCode plugin directory and link the
|
|
107
|
-
are picked up without reinstalling:
|
|
102
|
+
Symlink the plugin into your OpenCode plugin directory and link the installed files to a checkout,
|
|
103
|
+
so edits are picked up without reinstalling:
|
|
108
104
|
|
|
109
105
|
```bash
|
|
110
106
|
# Plugin (project or global plugin directory)
|
|
111
107
|
ln -s /path/to/opencode-codeops/plugin/index.ts ~/.config/opencode/plugins/codeops.ts
|
|
112
108
|
|
|
113
109
|
# Skills and agents — link instead of copy
|
|
114
|
-
node /path/to/opencode-codeops/bin/index.mjs install
|
|
115
|
-
node /path/to/opencode-codeops/bin/index.mjs install-agents --link --global
|
|
110
|
+
node /path/to/opencode-codeops/bin/index.mjs install --link --global
|
|
116
111
|
```
|
|
117
112
|
|
|
118
113
|
## Setup
|
|
119
114
|
|
|
120
|
-
After installing the plugin and the
|
|
115
|
+
After installing the plugin and the files, initialize CodeOps in your project:
|
|
121
116
|
|
|
122
117
|
```
|
|
123
118
|
/setup-codeops
|
|
124
119
|
```
|
|
125
120
|
|
|
126
|
-
This creates the `codeops/` layout, scaffolds `codeops/codeops.json` and `codeops/.codeops.yml`, installs the 12 CodeOps subagent files into `.opencode
|
|
121
|
+
This creates the `codeops/` layout, scaffolds `codeops/codeops.json` and `codeops/.codeops.yml`, installs the skills and the 12 CodeOps subagent files into `.opencode/`, and adds a managed section to `AGENTS.md`.
|
|
127
122
|
|
|
128
123
|
Commit the result:
|
|
129
124
|
|
|
130
125
|
```bash
|
|
131
|
-
git add codeops/ .opencode/
|
|
126
|
+
git add codeops/ .opencode/ AGENTS.md
|
|
132
127
|
git commit -m "chore: initialize CodeOps"
|
|
133
128
|
```
|
|
134
129
|
|
|
@@ -140,7 +135,7 @@ On every OpenCode session start and after every compaction, the plugin injects:
|
|
|
140
135
|
|
|
141
136
|
These standards are active without any user action. They do not need to be copied into `AGENTS.md`.
|
|
142
137
|
|
|
143
|
-
The plugin also warns (non-blocking) if any tool attempts to edit `codeops/.codeops.yml` directly — that file is managed exclusively by the `setup-codeops` skill.
|
|
138
|
+
The plugin also warns (non-blocking) if any tool attempts to edit `codeops/.codeops.yml` directly — that file is managed exclusively by the `setup-codeops` skill — and if the installed skills version differs from the plugin version, so a stale install is visible.
|
|
144
139
|
|
|
145
140
|
## Agent model configuration
|
|
146
141
|
|
package/bin/index.mjs
CHANGED
|
@@ -2,92 +2,174 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* The `opencode-codeops` command-line entry point.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
5
|
+
* There is exactly one installation path: a command installs or updates the
|
|
6
|
+
* skills and the subagents together. The two filesystems installers
|
|
7
|
+
* (`install-skills.mjs` and `install-agents.mjs`) are implementation details
|
|
8
|
+
* this module orchestrates; they are never exposed as separate user commands.
|
|
9
|
+
*
|
|
10
|
+
* The scope is auto-detected. Inside a CodeOps project the files go to
|
|
11
|
+
* `.opencode/skills` and `.opencode/agents`; anywhere else they go to the
|
|
12
|
+
* global `~/.config/opencode/` directories. `--project` and `--global` override
|
|
13
|
+
* the detection.
|
|
9
14
|
*
|
|
10
15
|
* Usage:
|
|
11
|
-
* opencode-codeops install
|
|
12
|
-
* opencode-codeops
|
|
13
|
-
* opencode-codeops status [options]
|
|
14
|
-
* opencode-codeops uninstall [options]
|
|
15
|
-
* opencode-codeops help
|
|
16
|
+
* opencode-codeops install [options] Install or upgrade skills and agents
|
|
17
|
+
* opencode-codeops update [options] Alias of install
|
|
18
|
+
* opencode-codeops status [options] Show installed versions
|
|
19
|
+
* opencode-codeops uninstall [options] Remove managed files
|
|
20
|
+
* opencode-codeops help Show this help
|
|
16
21
|
*
|
|
17
22
|
* @module index
|
|
18
23
|
*/
|
|
19
24
|
|
|
20
|
-
import {
|
|
25
|
+
import { execFileSync } from "node:child_process"
|
|
26
|
+
import { existsSync, realpathSync } from "node:fs"
|
|
27
|
+
import { join } from "node:path"
|
|
21
28
|
import { fileURLToPath } from "node:url"
|
|
22
29
|
|
|
30
|
+
/** Commands this CLI understands. */
|
|
31
|
+
const COMMANDS = new Set(["install", "update", "status", "uninstall", "help"])
|
|
32
|
+
|
|
23
33
|
/** Prints command usage. */
|
|
24
34
|
function printUsage() {
|
|
25
35
|
console.log(`CodeOps installer for OpenCode.
|
|
26
36
|
|
|
27
37
|
Usage:
|
|
28
|
-
opencode-codeops install
|
|
29
|
-
opencode-codeops
|
|
30
|
-
opencode-codeops status [options]
|
|
31
|
-
opencode-codeops uninstall [options]
|
|
32
|
-
opencode-codeops help
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
opencode-codeops install [options] Install or upgrade skills and agents (default)
|
|
39
|
+
opencode-codeops update [options] Alias of install
|
|
40
|
+
opencode-codeops status [options] Show installed skills and agents
|
|
41
|
+
opencode-codeops uninstall [options] Remove managed skills and agents
|
|
42
|
+
opencode-codeops help Show this help
|
|
43
|
+
|
|
44
|
+
Options:
|
|
45
|
+
--project Force the project scope (./.opencode)
|
|
46
|
+
--global Force the global scope (~/.config/opencode)
|
|
47
|
+
--dry-run Show what would happen without writing files
|
|
48
|
+
--force Replace same-named files this package does not own
|
|
49
|
+
--link Symlink to the source instead of copying (development)
|
|
50
|
+
-h, --help Show this help
|
|
51
|
+
|
|
52
|
+
Scope is auto-detected: inside a CodeOps project (a git repo with .opencode/ or
|
|
53
|
+
codeops/.codeops.yml) the files go to .opencode/; otherwise to ~/.config/opencode/.`)
|
|
36
54
|
}
|
|
37
55
|
|
|
38
56
|
/**
|
|
39
|
-
*
|
|
57
|
+
* Finds the git top-level directory for a working directory.
|
|
40
58
|
*
|
|
41
|
-
* @param
|
|
42
|
-
* @returns `
|
|
59
|
+
* @param cwd - Directory to start from
|
|
60
|
+
* @returns The repository root, or `cwd` when it is not a git checkout
|
|
43
61
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
62
|
+
function findProjectRoot(cwd) {
|
|
63
|
+
try {
|
|
64
|
+
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
65
|
+
cwd,
|
|
66
|
+
encoding: "utf-8",
|
|
67
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
68
|
+
}).trim()
|
|
69
|
+
} catch {
|
|
70
|
+
return cwd
|
|
48
71
|
}
|
|
49
|
-
return "skills"
|
|
50
72
|
}
|
|
51
73
|
|
|
52
74
|
/**
|
|
53
|
-
*
|
|
75
|
+
* Resolves whether files install into the project or globally.
|
|
54
76
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
77
|
+
* Explicit flags win. Otherwise a git repository is a CodeOps project when it
|
|
78
|
+
* already contains `.opencode/` or `codeops/.codeops.yml`; anything else uses
|
|
79
|
+
* the global scope.
|
|
80
|
+
*
|
|
81
|
+
* @param options - Scope flags from the command line
|
|
82
|
+
* @param options.project - Force the project scope
|
|
83
|
+
* @param options.global - Force the global scope
|
|
84
|
+
* @param cwd - Directory the command ran from
|
|
85
|
+
* @returns `"project"` or `"global"`
|
|
57
86
|
*/
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
87
|
+
export function resolveScope(options, cwd) {
|
|
88
|
+
if (options.project) return "project"
|
|
89
|
+
if (options.global) return "global"
|
|
90
|
+
|
|
91
|
+
const root = findProjectRoot(cwd)
|
|
92
|
+
if (existsSync(join(root, ".opencode")) || existsSync(join(root, "codeops", ".codeops.yml"))) {
|
|
93
|
+
return "project"
|
|
94
|
+
}
|
|
95
|
+
return "global"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Runs one command against both installers.
|
|
100
|
+
*
|
|
101
|
+
* @param command - `install`, `status`, or `uninstall`
|
|
102
|
+
* @param rest - Options to forward, without the scope flags (re-added below)
|
|
103
|
+
* @param io - Injectable environment (`cwd`, `home`) for tests
|
|
104
|
+
* @returns The combined process exit code
|
|
105
|
+
*/
|
|
106
|
+
async function runCombined(command, rest, io) {
|
|
107
|
+
const skills = await import("./install-skills.mjs")
|
|
108
|
+
const agents = await import("./install-agents.mjs")
|
|
109
|
+
|
|
110
|
+
const cwd = io.cwd ?? process.cwd()
|
|
111
|
+
const scope = resolveScope(
|
|
112
|
+
{ project: rest.includes("--project"), global: rest.includes("--global") },
|
|
113
|
+
cwd
|
|
114
|
+
)
|
|
115
|
+
const passed = rest.filter((arg) => arg !== "--project" && arg !== "--global")
|
|
116
|
+
const scoped = [scope === "project" ? "--project" : "--global", ...passed]
|
|
117
|
+
|
|
118
|
+
const skillsCode = skills.main([command, ...scoped], io)
|
|
119
|
+
const agentsCode = agents.main([command, ...scoped], io)
|
|
120
|
+
return skillsCode || agentsCode
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Dispatches a command line.
|
|
125
|
+
*
|
|
126
|
+
* Bare options (for example `opencode-codeops --project`) mean `install`, so the
|
|
127
|
+
* common case needs no subcommand.
|
|
128
|
+
*
|
|
129
|
+
* @param argv - Arguments after the executable
|
|
130
|
+
* @param io - Injectable environment (`cwd`, `home`) for tests
|
|
131
|
+
* @returns The process exit code
|
|
132
|
+
*/
|
|
133
|
+
export async function dispatch(argv, io = {}) {
|
|
134
|
+
const first = argv[0]
|
|
135
|
+
const rest = argv.slice(1)
|
|
61
136
|
|
|
62
137
|
if (!first || first === "help" || first === "-h" || first === "--help") {
|
|
63
138
|
printUsage()
|
|
64
|
-
return
|
|
139
|
+
return 0
|
|
65
140
|
}
|
|
66
141
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
process.exitCode = skillsCode || agentsCode
|
|
73
|
-
return
|
|
142
|
+
// Keep the unified help; the internal installers still document the old
|
|
143
|
+
// component commands in their own usage text.
|
|
144
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
145
|
+
printUsage()
|
|
146
|
+
return 0
|
|
74
147
|
}
|
|
75
148
|
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
149
|
+
if (first.startsWith("-")) return runCombined("install", argv, io)
|
|
150
|
+
|
|
151
|
+
if (!COMMANDS.has(first)) {
|
|
152
|
+
console.error(`error: unknown command '${first}'`)
|
|
153
|
+
printUsage()
|
|
154
|
+
return 2
|
|
80
155
|
}
|
|
81
156
|
|
|
82
|
-
const
|
|
83
|
-
|
|
157
|
+
const command = first === "update" ? "install" : first
|
|
158
|
+
return runCombined(command, rest, io)
|
|
84
159
|
}
|
|
85
160
|
|
|
86
161
|
/**
|
|
87
|
-
*
|
|
162
|
+
* Runs the CLI when this module is the process entry point.
|
|
88
163
|
*
|
|
89
164
|
* The comparison resolves symlinks because npm installs the bin as a symlink in
|
|
90
165
|
* `node_modules/.bin`, so `process.argv[1]` is the link path, not the real path.
|
|
166
|
+
*/
|
|
167
|
+
async function run() {
|
|
168
|
+
process.exitCode = await dispatch(process.argv.slice(2))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* True when this module is the process entry point.
|
|
91
173
|
*
|
|
92
174
|
* @returns True when this file is the entry point
|
|
93
175
|
*/
|
package/bin/install-agents.mjs
CHANGED
|
@@ -81,20 +81,17 @@ export function readPackageVersion() {
|
|
|
81
81
|
/**
|
|
82
82
|
* Resolves the directory that holds the packaged agent definitions.
|
|
83
83
|
*
|
|
84
|
-
* The `
|
|
85
|
-
*
|
|
84
|
+
* The package's own `agents/` directory is always the source, so the installed
|
|
85
|
+
* agents match the package that was invoked. The `CODEOPS_PLUGIN_ROOT`
|
|
86
|
+
* environment variable is deliberately ignored: the plugin exports it into
|
|
87
|
+
* every shell, and honouring it would install a different checkout's agents.
|
|
88
|
+
* Pass `--source` to override for development.
|
|
86
89
|
*
|
|
87
90
|
* @param override - Optional explicit agents directory
|
|
88
91
|
* @returns Absolute path to the agents directory
|
|
89
92
|
*/
|
|
90
93
|
export function resolveSourceDir(override) {
|
|
91
94
|
if (override) return resolve(override)
|
|
92
|
-
|
|
93
|
-
const envRoot = process.env.CODEOPS_PLUGIN_ROOT
|
|
94
|
-
if (envRoot && existsSync(join(envRoot, "agents"))) {
|
|
95
|
-
return join(envRoot, "agents")
|
|
96
|
-
}
|
|
97
|
-
|
|
98
95
|
return join(PACKAGE_ROOT, "agents")
|
|
99
96
|
}
|
|
100
97
|
|
|
@@ -375,7 +372,7 @@ export function main(argv, io = {}) {
|
|
|
375
372
|
const cwd = io.cwd ?? process.cwd()
|
|
376
373
|
const version = io.version ?? readPackageVersion()
|
|
377
374
|
const sourceDir = io.source ?? resolveSourceDir(options.source)
|
|
378
|
-
const targetDir = resolveTarget(options, cwd, "agents")
|
|
375
|
+
const targetDir = resolveTarget(options, cwd, "agents", io.home)
|
|
379
376
|
|
|
380
377
|
if (!existsSync(sourceDir)) {
|
|
381
378
|
console.error(`error: agents directory not found: ${sourceDir}`)
|
|
@@ -404,8 +401,8 @@ export function main(argv, io = {}) {
|
|
|
404
401
|
if (command === "uninstall") {
|
|
405
402
|
const result = uninstallAgents({ targetDir, dryRun: options.dryRun })
|
|
406
403
|
if (result.error) {
|
|
407
|
-
console.
|
|
408
|
-
return
|
|
404
|
+
console.log(`nothing to remove at ${targetDir} (${result.error})`)
|
|
405
|
+
return 0
|
|
409
406
|
}
|
|
410
407
|
console.log(
|
|
411
408
|
`${options.dryRun ? "would remove" : "removed"} ${result.removed.length} agent(s); ` +
|
package/bin/install-skills.mjs
CHANGED
|
@@ -81,20 +81,17 @@ export function readPackageVersion() {
|
|
|
81
81
|
/**
|
|
82
82
|
* Resolves the directory that holds the shipped skills.
|
|
83
83
|
*
|
|
84
|
-
* The `
|
|
85
|
-
*
|
|
84
|
+
* The package's own `skills/` directory is always the source, so the installed
|
|
85
|
+
* skills match the package that was invoked. The `CODEOPS_PLUGIN_ROOT`
|
|
86
|
+
* environment variable is deliberately ignored: the plugin exports it into
|
|
87
|
+
* every shell, and honouring it would install a different checkout's skills.
|
|
88
|
+
* Pass `--source` to override for development.
|
|
86
89
|
*
|
|
87
90
|
* @param override - Optional explicit skills directory
|
|
88
91
|
* @returns Absolute path to the skills directory
|
|
89
92
|
*/
|
|
90
93
|
export function resolveSourceDir(override) {
|
|
91
94
|
if (override) return resolve(override)
|
|
92
|
-
|
|
93
|
-
const envRoot = process.env.CODEOPS_PLUGIN_ROOT
|
|
94
|
-
if (envRoot && existsSync(join(envRoot, "skills"))) {
|
|
95
|
-
return join(envRoot, "skills")
|
|
96
|
-
}
|
|
97
|
-
|
|
98
95
|
return join(PACKAGE_ROOT, "skills")
|
|
99
96
|
}
|
|
100
97
|
|
|
@@ -385,7 +382,7 @@ export function main(argv, io = {}) {
|
|
|
385
382
|
const cwd = io.cwd ?? process.cwd()
|
|
386
383
|
const version = io.version ?? readPackageVersion()
|
|
387
384
|
const sourceDir = io.source ?? resolveSourceDir(options.source)
|
|
388
|
-
const targetDir = resolveTarget(options, cwd, "skills")
|
|
385
|
+
const targetDir = resolveTarget(options, cwd, "skills", io.home)
|
|
389
386
|
|
|
390
387
|
if (!existsSync(sourceDir)) {
|
|
391
388
|
console.error(`error: skills directory not found: ${sourceDir}`)
|
|
@@ -414,8 +411,8 @@ export function main(argv, io = {}) {
|
|
|
414
411
|
if (command === "uninstall") {
|
|
415
412
|
const result = uninstallSkills({ targetDir, dryRun: options.dryRun })
|
|
416
413
|
if (result.error) {
|
|
417
|
-
console.
|
|
418
|
-
return
|
|
414
|
+
console.log(`nothing to remove at ${targetDir} (${result.error})`)
|
|
415
|
+
return 0
|
|
419
416
|
}
|
|
420
417
|
console.log(
|
|
421
418
|
`${options.dryRun ? "would remove" : "removed"} ${result.removed.length} skill(s); ` +
|
|
@@ -167,12 +167,13 @@ export function linkEntry({ from, dest, type = "dir" }) {
|
|
|
167
167
|
* @param options.project - Use a project-relative directory instead of global
|
|
168
168
|
* @param cwd - Project root used for `--project`
|
|
169
169
|
* @param kind - Subdirectory name under `.opencode` (for example `skills`)
|
|
170
|
+
* @param home - Home directory used for the global default (injectable for tests)
|
|
170
171
|
* @returns Absolute path to the target directory
|
|
171
172
|
*/
|
|
172
|
-
export function resolveTarget(options, cwd, kind) {
|
|
173
|
+
export function resolveTarget(options, cwd, kind, home = homedir()) {
|
|
173
174
|
if (options.target) return resolve(options.target)
|
|
174
175
|
if (options.project) return resolve(cwd, ".opencode", kind)
|
|
175
|
-
return join(
|
|
176
|
+
return join(home, ".config", "opencode", kind)
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
/**
|
package/install.sh
CHANGED
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
# defaults to "latest").
|
|
18
18
|
#
|
|
19
19
|
# Subcommands (see `npx opencode-codeops help` for the full option list):
|
|
20
|
-
# install
|
|
21
|
-
#
|
|
22
|
-
# status
|
|
23
|
-
# uninstall
|
|
24
|
-
# help
|
|
20
|
+
# install Install or upgrade skills and subagents (default)
|
|
21
|
+
# update Alias of install
|
|
22
|
+
# status Show the installed versions
|
|
23
|
+
# uninstall Remove the managed files
|
|
24
|
+
# help Show installer help
|
|
25
25
|
|
|
26
26
|
set -euo pipefail
|
|
27
27
|
|
|
@@ -40,12 +40,12 @@ if ! command -v npx >/dev/null 2>&1; then
|
|
|
40
40
|
exit 1
|
|
41
41
|
fi
|
|
42
42
|
|
|
43
|
-
# The subcommand is optional and defaults to install
|
|
44
|
-
#
|
|
45
|
-
subcommand="install
|
|
43
|
+
# The subcommand is optional and defaults to install. Any remaining arguments
|
|
44
|
+
# are passed through to the installer unchanged.
|
|
45
|
+
subcommand="install"
|
|
46
46
|
if (( $# > 0 )); then
|
|
47
47
|
case "$1" in
|
|
48
|
-
install |
|
|
48
|
+
install | update | status | uninstall | help)
|
|
49
49
|
subcommand="$1"
|
|
50
50
|
shift
|
|
51
51
|
;;
|
package/package.json
CHANGED
package/plugin/index.ts
CHANGED
|
@@ -79,9 +79,9 @@ function installedSkillsVersion(skillsDir: string): string | undefined {
|
|
|
79
79
|
|
|
80
80
|
// ---------------------------------------------------------------------------
|
|
81
81
|
// Helper — warn (non-blocking) when the installed skills were written by a
|
|
82
|
-
// different CodeOps version than this plugin. The plugin and the
|
|
82
|
+
// different CodeOps version than this plugin. The plugin and the files are
|
|
83
83
|
// installed by separate commands, so their versions can drift; a mismatch
|
|
84
|
-
// usually means the skills need `npx opencode-codeops
|
|
84
|
+
// usually means the skills need `npx opencode-codeops update` again.
|
|
85
85
|
// ---------------------------------------------------------------------------
|
|
86
86
|
async function warnOnVersionSkew(
|
|
87
87
|
client: Parameters<Plugin>[0]["client"],
|
|
@@ -103,7 +103,7 @@ async function warnOnVersionSkew(
|
|
|
103
103
|
message:
|
|
104
104
|
`CodeOps skills at ${skillsDir} are version ${installed}, ` +
|
|
105
105
|
`but the plugin is version ${packageVersion}. ` +
|
|
106
|
-
`Run \`npx opencode-codeops@${packageVersion}
|
|
106
|
+
`Run \`npx opencode-codeops@${packageVersion} update\` to match them.`,
|
|
107
107
|
},
|
|
108
108
|
})
|
|
109
109
|
}
|
|
@@ -76,24 +76,24 @@ default when it is absent — so this line is a convenience/pin, not a requireme
|
|
|
76
76
|
- Scaffolding is intentionally simple, so it lives in skill prose; only the *migration* path
|
|
77
77
|
needs the deterministic engine. For migration, see [migration.md](migration.md).
|
|
78
78
|
|
|
79
|
-
##
|
|
79
|
+
## Project file installation
|
|
80
80
|
|
|
81
|
-
After scaffolding, install the CodeOps
|
|
82
|
-
|
|
81
|
+
After scaffolding, install the CodeOps skills and subagents into the project. Prefer the installer
|
|
82
|
+
bundled with the running plugin, so the installed files always match the plugin version:
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
|
-
node "${CODEOPS_PLUGIN_ROOT}/bin/
|
|
85
|
+
node "${CODEOPS_PLUGIN_ROOT}/bin/index.mjs" install --project
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
When the plugin is not active, the published installer does the same thing:
|
|
89
89
|
|
|
90
90
|
```bash
|
|
91
|
-
npx -y opencode-codeops@latest install
|
|
91
|
+
npx -y opencode-codeops@latest install --project
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
This installs the 12
|
|
95
|
-
etc.) into `.opencode/agents
|
|
96
|
-
are safe to commit to git. Files the installer owns are
|
|
97
|
-
does not own are left untouched (pass `--force` to replace
|
|
98
|
-
agent models in `opencode.json` under the `agent` key.
|
|
94
|
+
This installs the skills into `.opencode/skills/` and the 12 subagent definitions (`executor`,
|
|
95
|
+
`explorer`, `correctness-reviewer`, etc.) into `.opencode/agents/`, where OpenCode discovers and
|
|
96
|
+
loads them automatically. These files are safe to commit to git. Files the installer owns are
|
|
97
|
+
replaced on upgrade; same-named files it does not own are left untouched (pass `--force` to replace
|
|
98
|
+
them). Users can override individual agent models in `opencode.json` under the `agent` key.
|
|
99
99
|
|