@junwu168/openshell 0.1.2 → 0.1.4
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/openshell.js +4 -0
- package/dist/core/audit/log-store.js +1 -1
- package/dist/core/orchestrator.d.ts +2 -2
- package/dist/core/orchestrator.js +3 -3
- package/dist/core/result.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/opencode/plugin.d.ts +1 -1
- package/dist/opencode/plugin.js +8 -8
- package/package.json +6 -1
- package/.claude/settings.local.json +0 -15
- package/bun.lock +0 -368
- package/docs/superpowers/notes/2026-03-25-opencode-remote-tools-handoff.md +0 -81
- package/docs/superpowers/notes/2026-03-26-openshell-pre-release-review.md +0 -174
- package/docs/superpowers/plans/2026-03-25-opencode-remote-tools.md +0 -1656
- package/docs/superpowers/plans/2026-03-25-server-registry-cli.md +0 -54
- package/docs/superpowers/plans/2026-03-26-config-backed-credential-registry.md +0 -494
- package/docs/superpowers/plans/2026-03-26-openshell-release-prep.md +0 -639
- package/docs/superpowers/specs/2026-03-25-opencode-remote-tools-design.md +0 -378
- package/docs/superpowers/specs/2026-03-26-config-backed-credential-registry-design.md +0 -272
- package/docs/superpowers/specs/2026-03-26-openshell-release-prep-design.md +0 -197
- package/examples/opencode-local/opencode.json +0 -19
- package/scripts/openshell.ts +0 -3
- package/scripts/server-registry.ts +0 -3
- package/src/cli/openshell.ts +0 -60
- package/src/cli/server-registry.ts +0 -476
- package/src/core/audit/git-audit-repo.ts +0 -42
- package/src/core/audit/log-store.ts +0 -20
- package/src/core/audit/redact.ts +0 -4
- package/src/core/contracts.ts +0 -51
- package/src/core/orchestrator.ts +0 -1082
- package/src/core/patch.ts +0 -11
- package/src/core/paths.ts +0 -32
- package/src/core/policy.ts +0 -30
- package/src/core/registry/server-registry.ts +0 -505
- package/src/core/result.ts +0 -16
- package/src/core/ssh/ssh-runtime.ts +0 -355
- package/src/index.ts +0 -3
- package/src/opencode/plugin.ts +0 -242
- package/src/product/install.ts +0 -43
- package/src/product/opencode-config.ts +0 -118
- package/src/product/uninstall.ts +0 -47
- package/src/product/workspace-tracker.ts +0 -69
- package/tests/integration/fake-ssh-server.ts +0 -97
- package/tests/integration/install-lifecycle.test.ts +0 -85
- package/tests/integration/orchestrator.test.ts +0 -767
- package/tests/integration/ssh-runtime.test.ts +0 -122
- package/tests/unit/audit.test.ts +0 -221
- package/tests/unit/build-layout.test.ts +0 -28
- package/tests/unit/opencode-config.test.ts +0 -100
- package/tests/unit/opencode-plugin.test.ts +0 -358
- package/tests/unit/openshell-cli.test.ts +0 -60
- package/tests/unit/paths.test.ts +0 -64
- package/tests/unit/plugin-export.test.ts +0 -10
- package/tests/unit/policy.test.ts +0 -53
- package/tests/unit/release-docs.test.ts +0 -31
- package/tests/unit/result.test.ts +0 -28
- package/tests/unit/server-registry-cli.test.ts +0 -673
- package/tests/unit/server-registry.test.ts +0 -452
- package/tests/unit/workspace-tracker.test.ts +0 -57
- package/tsconfig.json +0 -14
|
@@ -1,639 +0,0 @@
|
|
|
1
|
-
# OpenShell Release Prep Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
-
|
|
5
|
-
**Goal:** Productize the current branch as the npm package `@junwu168/openshell` with CLI binary `openshell`, global OpenCode install/uninstall flows, and a reviewer-friendly pre-release repo surface.
|
|
6
|
-
|
|
7
|
-
**Architecture:** Keep the existing remote-tool runtime and OpenCode plugin behavior, but rebrand the package, add a first-class CLI, and implement install/uninstall lifecycle code around standard OpenShell config and data directories. Register the plugin in OpenCode through the global `plugin` config array and merged permission config, because current OpenCode npm-plugin support loads packages from `opencode.json` directly.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript, Bun, OpenCode plugin SDK, `ssh2`, `env-paths`, Bun test
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## File Map
|
|
14
|
-
|
|
15
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/package.json`
|
|
16
|
-
Published package metadata, CLI bin wiring, npm-facing scripts, package identity.
|
|
17
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/index.ts`
|
|
18
|
-
Public package exports for the OpenCode plugin under the `openshell` product surface.
|
|
19
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/paths.ts`
|
|
20
|
-
OpenShell config/data path helpers, OpenCode global config path helpers, workspace `.open-code` helpers.
|
|
21
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/cli/openshell.ts`
|
|
22
|
-
Top-level `openshell` CLI command dispatcher and shared user-facing help text.
|
|
23
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/scripts/openshell.ts`
|
|
24
|
-
Bun entrypoint for local CLI execution during development.
|
|
25
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/cli/server-registry.ts`
|
|
26
|
-
Existing interactive registry subcommands, updated to sit under the top-level CLI and workspace tracker.
|
|
27
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/product/workspace-tracker.ts`
|
|
28
|
-
Persistent tracker for workspace `.open-code` directories created or managed by OpenShell.
|
|
29
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/product/opencode-config.ts`
|
|
30
|
-
Read/merge/remove helpers for `~/.config/opencode/opencode.json`.
|
|
31
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/product/install.ts`
|
|
32
|
-
`openshell install` orchestration: ensure directories, merge OpenCode config, initialize tracker.
|
|
33
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/product/uninstall.ts`
|
|
34
|
-
`openshell uninstall` orchestration: remove OpenCode registration, remove tracked workspaces, delete OpenShell state.
|
|
35
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/README.md`
|
|
36
|
-
Pre-release install/uninstall and first-run documentation.
|
|
37
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/opencode.json`
|
|
38
|
-
Example permission file aligned with the released OpenCode integration story.
|
|
39
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/.opencode/package.json`
|
|
40
|
-
Legacy local-plugin smoke artifact to delete if no longer aligned with the npm install path.
|
|
41
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/.opencode/plugins/open-code.ts`
|
|
42
|
-
Legacy local-plugin shim to delete or replace if still needed for reviewer docs.
|
|
43
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/build-layout.test.ts`
|
|
44
|
-
Package metadata and emitted layout assertions.
|
|
45
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/release-docs.test.ts`
|
|
46
|
-
README and example assertions that keep the public install story coherent.
|
|
47
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/paths.test.ts`
|
|
48
|
-
Runtime path and app-directory assertions for the renamed product.
|
|
49
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/plugin-export.test.ts`
|
|
50
|
-
Public package export assertions after the rename.
|
|
51
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/server-registry-cli.test.ts`
|
|
52
|
-
Existing registry CLI tests, expanded for nested CLI integration and workspace tracking.
|
|
53
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/opencode-plugin.test.ts`
|
|
54
|
-
OpenCode plugin export and runtime dependency tests after the package rename.
|
|
55
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/openshell-cli.test.ts`
|
|
56
|
-
New top-level CLI dispatch and help-text tests.
|
|
57
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/workspace-tracker.test.ts`
|
|
58
|
-
New workspace-tracker tests.
|
|
59
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/opencode-config.test.ts`
|
|
60
|
-
New OpenCode config merge/remove tests.
|
|
61
|
-
- `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/integration/install-lifecycle.test.ts`
|
|
62
|
-
New end-to-end install/uninstall filesystem lifecycle test using temporary config/data roots.
|
|
63
|
-
|
|
64
|
-
### Task 1: Rebrand The Package Surface And Runtime Paths
|
|
65
|
-
|
|
66
|
-
**Files:**
|
|
67
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/package.json`
|
|
68
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/index.ts`
|
|
69
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/paths.ts`
|
|
70
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/build-layout.test.ts`
|
|
71
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/paths.test.ts`
|
|
72
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/plugin-export.test.ts`
|
|
73
|
-
|
|
74
|
-
- [ ] **Step 1: Write the failing package and path tests**
|
|
75
|
-
|
|
76
|
-
Add or update tests to lock the renamed product contract:
|
|
77
|
-
|
|
78
|
-
```ts
|
|
79
|
-
test("package metadata publishes openshell with a bin entry", async () => {
|
|
80
|
-
expect(packageJson.name).toBe("@junwu168/openshell")
|
|
81
|
-
expect(packageJson.bin.openshell).toBe("./dist/cli/openshell.js")
|
|
82
|
-
expect(packageJson.private).not.toBe(true)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
test("runtime paths use openshell app directories", () => {
|
|
86
|
-
const runtime = createRuntimePaths("/repo")
|
|
87
|
-
expect(runtime.configDir).toContain("openshell")
|
|
88
|
-
expect(runtime.dataDir).toContain("openshell")
|
|
89
|
-
expect(runtime.workspaceRegistryFile).toBe("/repo/.open-code/servers.json")
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test("package entry exports the OpenShell plugin", async () => {
|
|
93
|
-
expect(typeof OpenShellPlugin).toBe("function")
|
|
94
|
-
})
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Keep the current `dist/index.js` package entry expectation, but update it to assert the new package identity and CLI bin layout.
|
|
98
|
-
|
|
99
|
-
- [ ] **Step 2: Run targeted tests to verify they fail**
|
|
100
|
-
|
|
101
|
-
Run:
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
~/.bun/bin/bun test \
|
|
105
|
-
tests/unit/build-layout.test.ts \
|
|
106
|
-
tests/unit/paths.test.ts \
|
|
107
|
-
tests/unit/plugin-export.test.ts
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Expected:
|
|
111
|
-
|
|
112
|
-
- FAIL because `package.json` still says `open-code`
|
|
113
|
-
- FAIL because there is no `openshell` bin entry yet
|
|
114
|
-
- FAIL because `env-paths` still resolves `open-code`
|
|
115
|
-
- FAIL because the package entry still exports only `OpenCodePlugin`
|
|
116
|
-
|
|
117
|
-
- [ ] **Step 3: Implement the renamed package and path contract**
|
|
118
|
-
|
|
119
|
-
In `package.json`:
|
|
120
|
-
|
|
121
|
-
- set `"name": "@junwu168/openshell"`
|
|
122
|
-
- remove `"private": true`
|
|
123
|
-
- add:
|
|
124
|
-
|
|
125
|
-
```json
|
|
126
|
-
"bin": {
|
|
127
|
-
"openshell": "./dist/cli/openshell.js"
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
- keep the package root export pointed at `./dist/index.js`
|
|
132
|
-
- add a development script for the top-level CLI, for example:
|
|
133
|
-
|
|
134
|
-
```json
|
|
135
|
-
"scripts": {
|
|
136
|
-
"openshell": "$npm_execpath scripts/openshell.ts"
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
In `src/core/paths.ts`:
|
|
141
|
-
|
|
142
|
-
- switch `envPaths("open-code", ...)` to `envPaths("openshell", ...)`
|
|
143
|
-
- expose OpenCode global config helpers alongside the existing registry/audit helpers, for example:
|
|
144
|
-
|
|
145
|
-
```ts
|
|
146
|
-
const openShellPaths = envPaths("openshell", { suffix: "" })
|
|
147
|
-
const openCodePaths = envPaths("opencode", { suffix: "" })
|
|
148
|
-
|
|
149
|
-
opencodeConfigDir: openCodePaths.config,
|
|
150
|
-
opencodeConfigFile: `${openCodePaths.config}/opencode.json`,
|
|
151
|
-
workspaceRegistryDir: `${workspaceRoot}/.open-code`,
|
|
152
|
-
workspaceRegistryFile: `${workspaceRoot}/.open-code/servers.json`,
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Do not rename the workspace `.open-code` directory in this pass.
|
|
156
|
-
|
|
157
|
-
In `src/index.ts`:
|
|
158
|
-
|
|
159
|
-
- export a product-facing plugin symbol:
|
|
160
|
-
|
|
161
|
-
```ts
|
|
162
|
-
export { OpenCodePlugin as OpenShellPlugin, OpenCodePlugin } from "./opencode/plugin"
|
|
163
|
-
export { OpenCodePlugin as default } from "./opencode/plugin"
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Keep current compatibility exports unless a test proves they are unnecessary.
|
|
167
|
-
|
|
168
|
-
- [ ] **Step 4: Run targeted tests to verify they pass**
|
|
169
|
-
|
|
170
|
-
Run:
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
~/.bun/bin/bun test \
|
|
174
|
-
tests/unit/build-layout.test.ts \
|
|
175
|
-
tests/unit/paths.test.ts \
|
|
176
|
-
tests/unit/plugin-export.test.ts
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
Expected:
|
|
180
|
-
|
|
181
|
-
- PASS with the renamed package, CLI bin, and runtime path assertions green
|
|
182
|
-
|
|
183
|
-
- [ ] **Step 5: Commit**
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add \
|
|
187
|
-
package.json \
|
|
188
|
-
src/index.ts \
|
|
189
|
-
src/core/paths.ts \
|
|
190
|
-
tests/unit/build-layout.test.ts \
|
|
191
|
-
tests/unit/paths.test.ts \
|
|
192
|
-
tests/unit/plugin-export.test.ts
|
|
193
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "refactor: rename package surface to openshell"
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Task 2: Add The First-Class OpenShell CLI And Workspace Tracker
|
|
197
|
-
|
|
198
|
-
**Files:**
|
|
199
|
-
- Create: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/cli/openshell.ts`
|
|
200
|
-
- Create: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/scripts/openshell.ts`
|
|
201
|
-
- Create: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/product/workspace-tracker.ts`
|
|
202
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/cli/server-registry.ts`
|
|
203
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/openshell-cli.test.ts`
|
|
204
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/workspace-tracker.test.ts`
|
|
205
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/server-registry-cli.test.ts`
|
|
206
|
-
|
|
207
|
-
- [ ] **Step 1: Write the failing CLI and tracker tests**
|
|
208
|
-
|
|
209
|
-
Add tests for the product CLI contract:
|
|
210
|
-
|
|
211
|
-
```ts
|
|
212
|
-
test("openshell routes server-registry subcommands", async () => {
|
|
213
|
-
const exitCode = await runOpenShellCli(["server-registry", "list"], deps)
|
|
214
|
-
expect(exitCode).toBe(0)
|
|
215
|
-
expect(serverRegistryCalls).toEqual([["list"]])
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
test("workspace tracker records and deduplicates managed workspaces", async () => {
|
|
219
|
-
await tracker.record({ workspaceRoot: "/repo", managedPath: "/repo/.open-code" })
|
|
220
|
-
await tracker.record({ workspaceRoot: "/repo", managedPath: "/repo/.open-code" })
|
|
221
|
-
expect(await tracker.list()).toEqual([
|
|
222
|
-
expect.objectContaining({ workspaceRoot: "/repo", managedPath: "/repo/.open-code" }),
|
|
223
|
-
])
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
test("adding a workspace-scoped server records the managed workspace path", async () => {
|
|
227
|
-
await runServerRegistryCli(["add"], deps)
|
|
228
|
-
expect(trackerCalls).toContainEqual({
|
|
229
|
-
workspaceRoot,
|
|
230
|
-
managedPath: `${workspaceRoot}/.open-code`,
|
|
231
|
-
})
|
|
232
|
-
})
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Also add help-text coverage:
|
|
236
|
-
|
|
237
|
-
- `openshell` with no args prints top-level usage
|
|
238
|
-
- unknown subcommands return a non-zero exit code
|
|
239
|
-
|
|
240
|
-
- [ ] **Step 2: Run targeted tests to verify they fail**
|
|
241
|
-
|
|
242
|
-
Run:
|
|
243
|
-
|
|
244
|
-
```bash
|
|
245
|
-
~/.bun/bin/bun test \
|
|
246
|
-
tests/unit/openshell-cli.test.ts \
|
|
247
|
-
tests/unit/workspace-tracker.test.ts \
|
|
248
|
-
tests/unit/server-registry-cli.test.ts
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Expected:
|
|
252
|
-
|
|
253
|
-
- FAIL because there is no top-level `openshell` CLI yet
|
|
254
|
-
- FAIL because no workspace tracker exists
|
|
255
|
-
- FAIL because `server-registry` is not wired to any tracker
|
|
256
|
-
|
|
257
|
-
- [ ] **Step 3: Implement the top-level CLI and tracker**
|
|
258
|
-
|
|
259
|
-
Create `src/cli/openshell.ts` with a dispatcher shaped like:
|
|
260
|
-
|
|
261
|
-
```ts
|
|
262
|
-
switch (argv[0]) {
|
|
263
|
-
case "install":
|
|
264
|
-
return runInstallCli(argv.slice(1), deps)
|
|
265
|
-
case "uninstall":
|
|
266
|
-
return runUninstallCli(argv.slice(1), deps)
|
|
267
|
-
case "server-registry":
|
|
268
|
-
return runServerRegistryCli(argv.slice(1), deps)
|
|
269
|
-
default:
|
|
270
|
-
stdout.write(usage)
|
|
271
|
-
return argv.length === 0 ? 0 : 1
|
|
272
|
-
}
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
Create `src/product/workspace-tracker.ts` as a small JSON-backed store under the OpenShell data directory with methods like:
|
|
276
|
-
|
|
277
|
-
- `list()`
|
|
278
|
-
- `record({ workspaceRoot, managedPath })`
|
|
279
|
-
- `remove(workspaceRoot)`
|
|
280
|
-
- `clear()`
|
|
281
|
-
|
|
282
|
-
Update `src/cli/server-registry.ts` so that:
|
|
283
|
-
|
|
284
|
-
- workspace-scoped writes record `${workspaceRoot}/.open-code`
|
|
285
|
-
- workspace-scoped removals can remove tracker entries when the registry file no longer exists
|
|
286
|
-
- existing prompt/test seams stay injectable
|
|
287
|
-
|
|
288
|
-
Create `scripts/openshell.ts` as the Bun dev entrypoint:
|
|
289
|
-
|
|
290
|
-
```ts
|
|
291
|
-
import { main } from "../src/cli/openshell"
|
|
292
|
-
process.exitCode = await main(process.argv.slice(2))
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
- [ ] **Step 4: Run targeted tests to verify they pass**
|
|
296
|
-
|
|
297
|
-
Run:
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
~/.bun/bin/bun test \
|
|
301
|
-
tests/unit/openshell-cli.test.ts \
|
|
302
|
-
tests/unit/workspace-tracker.test.ts \
|
|
303
|
-
tests/unit/server-registry-cli.test.ts
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
Expected:
|
|
307
|
-
|
|
308
|
-
- PASS with CLI dispatch, help text, and workspace tracking green
|
|
309
|
-
|
|
310
|
-
- [ ] **Step 5: Commit**
|
|
311
|
-
|
|
312
|
-
```bash
|
|
313
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add \
|
|
314
|
-
src/cli/openshell.ts \
|
|
315
|
-
scripts/openshell.ts \
|
|
316
|
-
src/product/workspace-tracker.ts \
|
|
317
|
-
src/cli/server-registry.ts \
|
|
318
|
-
tests/unit/openshell-cli.test.ts \
|
|
319
|
-
tests/unit/workspace-tracker.test.ts \
|
|
320
|
-
tests/unit/server-registry-cli.test.ts
|
|
321
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "feat: add openshell cli and workspace tracking"
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Task 3: Implement OpenCode Install And Uninstall Lifecycle
|
|
325
|
-
|
|
326
|
-
**Files:**
|
|
327
|
-
- Create: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/product/opencode-config.ts`
|
|
328
|
-
- Create: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/product/install.ts`
|
|
329
|
-
- Create: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/product/uninstall.ts`
|
|
330
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/cli/openshell.ts`
|
|
331
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/paths.ts`
|
|
332
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/opencode-config.test.ts`
|
|
333
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/openshell-cli.test.ts`
|
|
334
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/integration/install-lifecycle.test.ts`
|
|
335
|
-
|
|
336
|
-
- [ ] **Step 1: Write the failing install/uninstall tests**
|
|
337
|
-
|
|
338
|
-
Add merge/remove tests around the actual OpenCode integration contract:
|
|
339
|
-
|
|
340
|
-
```ts
|
|
341
|
-
test("install merges openshell into the global OpenCode plugin list", async () => {
|
|
342
|
-
await writeFile(opencodeConfigFile, JSON.stringify({
|
|
343
|
-
plugin: ["existing-plugin"],
|
|
344
|
-
permission: { edit: "ask" },
|
|
345
|
-
}))
|
|
346
|
-
|
|
347
|
-
await installOpenShell({ runtimePaths, cwd: "/repo" })
|
|
348
|
-
|
|
349
|
-
expect(readMergedConfig()).toMatchObject({
|
|
350
|
-
plugin: ["existing-plugin", "@junwu168/openshell"],
|
|
351
|
-
permission: expect.objectContaining({
|
|
352
|
-
edit: "ask",
|
|
353
|
-
bash: expect.objectContaining({ "cat *": "allow" }),
|
|
354
|
-
}),
|
|
355
|
-
})
|
|
356
|
-
})
|
|
357
|
-
|
|
358
|
-
test("uninstall removes openshell registration and tracked workspaces", async () => {
|
|
359
|
-
await tracker.record({ workspaceRoot: "/repo", managedPath: "/repo/.open-code" })
|
|
360
|
-
await uninstallOpenShell({ runtimePaths })
|
|
361
|
-
expect(await exists("/repo/.open-code")).toBe(false)
|
|
362
|
-
expect(await exists(runtimePaths.configDir)).toBe(false)
|
|
363
|
-
expect(await exists(runtimePaths.dataDir)).toBe(false)
|
|
364
|
-
})
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
Also cover:
|
|
368
|
-
|
|
369
|
-
- install creates a minimal `opencode.json` when it does not exist
|
|
370
|
-
- install does not duplicate `@junwu168/openshell` in `plugin`
|
|
371
|
-
- uninstall preserves unrelated OpenCode plugins and permissions
|
|
372
|
-
- uninstall removes stale dev-only plugin shims under `~/.config/opencode/plugins/openshell.*` or `open-code.*` if present
|
|
373
|
-
|
|
374
|
-
- [ ] **Step 2: Run targeted tests to verify they fail**
|
|
375
|
-
|
|
376
|
-
Run:
|
|
377
|
-
|
|
378
|
-
```bash
|
|
379
|
-
~/.bun/bin/bun test \
|
|
380
|
-
tests/unit/opencode-config.test.ts \
|
|
381
|
-
tests/unit/openshell-cli.test.ts \
|
|
382
|
-
tests/integration/install-lifecycle.test.ts
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
Expected:
|
|
386
|
-
|
|
387
|
-
- FAIL because no install/uninstall modules exist
|
|
388
|
-
- FAIL because `openshell install` and `openshell uninstall` are not wired
|
|
389
|
-
- FAIL because OpenCode config merge/remove logic does not exist
|
|
390
|
-
|
|
391
|
-
- [ ] **Step 3: Implement the lifecycle modules**
|
|
392
|
-
|
|
393
|
-
Create `src/product/opencode-config.ts` to own:
|
|
394
|
-
|
|
395
|
-
- loading `opencode.json` if present
|
|
396
|
-
- creating a minimal config if absent
|
|
397
|
-
- merging:
|
|
398
|
-
|
|
399
|
-
```json
|
|
400
|
-
{
|
|
401
|
-
"plugin": ["@junwu168/openshell"],
|
|
402
|
-
"permission": {
|
|
403
|
-
"edit": "ask",
|
|
404
|
-
"bash": {
|
|
405
|
-
"*": "ask",
|
|
406
|
-
"cat *": "allow",
|
|
407
|
-
"grep *": "allow",
|
|
408
|
-
"find *": "allow",
|
|
409
|
-
"ls *": "allow",
|
|
410
|
-
"pwd": "allow",
|
|
411
|
-
"uname *": "allow",
|
|
412
|
-
"df *": "allow",
|
|
413
|
-
"free *": "allow",
|
|
414
|
-
"ps *": "allow",
|
|
415
|
-
"systemctl status *": "allow"
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
- removing only the `@junwu168/openshell` plugin entry and OpenShell-managed permission defaults during uninstall
|
|
422
|
-
|
|
423
|
-
Create `src/product/install.ts` to:
|
|
424
|
-
|
|
425
|
-
- ensure OpenShell config/data directories
|
|
426
|
-
- ensure the OpenCode config directory exists
|
|
427
|
-
- merge and write `opencode.json`
|
|
428
|
-
- initialize the workspace tracker
|
|
429
|
-
- print a concise summary
|
|
430
|
-
|
|
431
|
-
Create `src/product/uninstall.ts` to:
|
|
432
|
-
|
|
433
|
-
- remove OpenShell-managed OpenCode registration
|
|
434
|
-
- remove any tracked workspace `.open-code` directories
|
|
435
|
-
- delete OpenShell config and data directories
|
|
436
|
-
- print removal failures without hiding them
|
|
437
|
-
|
|
438
|
-
Wire these through `src/cli/openshell.ts`.
|
|
439
|
-
|
|
440
|
-
- [ ] **Step 4: Run targeted tests to verify they pass**
|
|
441
|
-
|
|
442
|
-
Run:
|
|
443
|
-
|
|
444
|
-
```bash
|
|
445
|
-
~/.bun/bin/bun test \
|
|
446
|
-
tests/unit/opencode-config.test.ts \
|
|
447
|
-
tests/unit/openshell-cli.test.ts \
|
|
448
|
-
tests/integration/install-lifecycle.test.ts
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
Expected:
|
|
452
|
-
|
|
453
|
-
- PASS with config merge/remove and lifecycle cleanup assertions green
|
|
454
|
-
|
|
455
|
-
- [ ] **Step 5: Commit**
|
|
456
|
-
|
|
457
|
-
```bash
|
|
458
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add \
|
|
459
|
-
src/product/opencode-config.ts \
|
|
460
|
-
src/product/install.ts \
|
|
461
|
-
src/product/uninstall.ts \
|
|
462
|
-
src/cli/openshell.ts \
|
|
463
|
-
src/core/paths.ts \
|
|
464
|
-
tests/unit/opencode-config.test.ts \
|
|
465
|
-
tests/unit/openshell-cli.test.ts \
|
|
466
|
-
tests/integration/install-lifecycle.test.ts
|
|
467
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "feat: add openshell install and uninstall lifecycle"
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
### Task 4: Clean Docs, Examples, And User-Facing Review Artifacts
|
|
471
|
-
|
|
472
|
-
**Files:**
|
|
473
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/README.md`
|
|
474
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/opencode.json`
|
|
475
|
-
- Delete: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/.opencode/package.json`
|
|
476
|
-
- Delete: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/.opencode/plugins/open-code.ts`
|
|
477
|
-
- Delete: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/.opencode/.gitignore`
|
|
478
|
-
- Create: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/release-docs.test.ts`
|
|
479
|
-
|
|
480
|
-
- [ ] **Step 1: Write the failing docs/example assertions**
|
|
481
|
-
|
|
482
|
-
Add lightweight checks that prevent the old developer-only install story from lingering:
|
|
483
|
-
|
|
484
|
-
```ts
|
|
485
|
-
test("README documents openshell install and uninstall", async () => {
|
|
486
|
-
expect(readme).toContain("npm install -g @junwu168/openshell")
|
|
487
|
-
expect(readme).toContain("openshell install")
|
|
488
|
-
expect(readme).toContain("openshell uninstall")
|
|
489
|
-
})
|
|
490
|
-
|
|
491
|
-
test("legacy local plugin shim is no longer part of the release example", async () => {
|
|
492
|
-
expect(await exists(exampleShimFile)).toBe(false)
|
|
493
|
-
})
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
Also update the current build-layout expectations if they still mention `open-code`.
|
|
497
|
-
|
|
498
|
-
- [ ] **Step 2: Run targeted tests to verify they fail**
|
|
499
|
-
|
|
500
|
-
Run:
|
|
501
|
-
|
|
502
|
-
```bash
|
|
503
|
-
~/.bun/bin/bun test tests/unit/release-docs.test.ts
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
Expected:
|
|
507
|
-
|
|
508
|
-
- FAIL because README and example files still describe the Bun-script/local-shim flow
|
|
509
|
-
|
|
510
|
-
- [ ] **Step 3: Rewrite the review-facing docs and examples**
|
|
511
|
-
|
|
512
|
-
Update `README.md` so the first screen a reviewer sees is:
|
|
513
|
-
|
|
514
|
-
1. install globally with npm
|
|
515
|
-
2. run `openshell install`
|
|
516
|
-
3. add a server with `openshell server-registry add`
|
|
517
|
-
4. start OpenCode and use the explicit remote tools
|
|
518
|
-
5. run `openshell uninstall` for full cleanup
|
|
519
|
-
|
|
520
|
-
Remove or rewrite stale wording:
|
|
521
|
-
|
|
522
|
-
- `open-code`
|
|
523
|
-
- encrypted registry / keychain references
|
|
524
|
-
- local `.opencode/plugins/open-code.ts` smoke setup as the primary story
|
|
525
|
-
|
|
526
|
-
Delete the example `.opencode` shim files if they are no longer part of the supported install path. Keep `examples/opencode-local/opencode.json` only if it still adds reviewer value as a permission example.
|
|
527
|
-
|
|
528
|
-
- [ ] **Step 4: Run targeted tests to verify they pass**
|
|
529
|
-
|
|
530
|
-
Run:
|
|
531
|
-
|
|
532
|
-
```bash
|
|
533
|
-
~/.bun/bin/bun test tests/unit/release-docs.test.ts
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
Expected:
|
|
537
|
-
|
|
538
|
-
- PASS with README and example assertions green
|
|
539
|
-
|
|
540
|
-
- [ ] **Step 5: Commit**
|
|
541
|
-
|
|
542
|
-
```bash
|
|
543
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add \
|
|
544
|
-
README.md \
|
|
545
|
-
examples/opencode-local/opencode.json \
|
|
546
|
-
tests/unit/release-docs.test.ts
|
|
547
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli rm \
|
|
548
|
-
examples/opencode-local/.opencode/package.json \
|
|
549
|
-
examples/opencode-local/.opencode/plugins/open-code.ts \
|
|
550
|
-
examples/opencode-local/.opencode/.gitignore
|
|
551
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "docs: align examples and install story with openshell"
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
### Task 5: Final Verification And Pre-Release Smoke Evidence
|
|
555
|
-
|
|
556
|
-
**Files:**
|
|
557
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/README.md`
|
|
558
|
-
- Create: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/docs/superpowers/notes/2026-03-26-openshell-pre-release-review.md`
|
|
559
|
-
|
|
560
|
-
- [ ] **Step 1: Run the full automated verification suite**
|
|
561
|
-
|
|
562
|
-
Run:
|
|
563
|
-
|
|
564
|
-
```bash
|
|
565
|
-
~/.bun/bin/bun test
|
|
566
|
-
~/.bun/bin/bun run typecheck
|
|
567
|
-
~/.bun/bin/bun run build
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
Expected:
|
|
571
|
-
|
|
572
|
-
- all unit and integration tests pass
|
|
573
|
-
- no type errors
|
|
574
|
-
- `dist/cli/openshell.js` is emitted for the published bin
|
|
575
|
-
|
|
576
|
-
- [ ] **Step 2: Run a fresh-install filesystem smoke in isolated config roots**
|
|
577
|
-
|
|
578
|
-
Run from the worktree root:
|
|
579
|
-
|
|
580
|
-
```bash
|
|
581
|
-
TMP_ROOT="$(mktemp -d)"
|
|
582
|
-
XDG_CONFIG_HOME="$TMP_ROOT/config" \
|
|
583
|
-
XDG_DATA_HOME="$TMP_ROOT/data" \
|
|
584
|
-
HOME="$TMP_ROOT/home" \
|
|
585
|
-
~/.bun/bin/bun run openshell install
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
Then verify:
|
|
589
|
-
|
|
590
|
-
```bash
|
|
591
|
-
test -f "$TMP_ROOT/config/opencode/opencode.json"
|
|
592
|
-
test -d "$TMP_ROOT/config/openshell"
|
|
593
|
-
test -d "$TMP_ROOT/data/openshell"
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
Expected:
|
|
597
|
-
|
|
598
|
-
- OpenCode global config exists and contains `@junwu168/openshell`
|
|
599
|
-
- OpenShell config/data roots exist
|
|
600
|
-
|
|
601
|
-
- [ ] **Step 3: Run a cleanup smoke in the same isolated roots**
|
|
602
|
-
|
|
603
|
-
Run:
|
|
604
|
-
|
|
605
|
-
```bash
|
|
606
|
-
XDG_CONFIG_HOME="$TMP_ROOT/config" \
|
|
607
|
-
XDG_DATA_HOME="$TMP_ROOT/data" \
|
|
608
|
-
HOME="$TMP_ROOT/home" \
|
|
609
|
-
~/.bun/bin/bun run openshell uninstall
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
Then verify:
|
|
613
|
-
|
|
614
|
-
```bash
|
|
615
|
-
test ! -e "$TMP_ROOT/config/openshell"
|
|
616
|
-
test ! -e "$TMP_ROOT/data/openshell"
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
Expected:
|
|
620
|
-
|
|
621
|
-
- OpenShell config/data are gone
|
|
622
|
-
- `@junwu168/openshell` has been removed from the OpenCode config
|
|
623
|
-
|
|
624
|
-
- [ ] **Step 4: Update the reviewer-facing checklist if any verification command changed**
|
|
625
|
-
|
|
626
|
-
If the README or review note still references stale commands or paths, update it so a reviewer can reproduce:
|
|
627
|
-
|
|
628
|
-
- global npm install
|
|
629
|
-
- `openshell install`
|
|
630
|
-
- `openshell server-registry add`
|
|
631
|
-
- OpenCode smoke prompts
|
|
632
|
-
- `openshell uninstall`
|
|
633
|
-
|
|
634
|
-
- [ ] **Step 5: Commit**
|
|
635
|
-
|
|
636
|
-
```bash
|
|
637
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add README.md docs/superpowers/notes/2026-03-26-openshell-pre-release-review.md
|
|
638
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "docs: finalize prerelease verification checklist"
|
|
639
|
-
```
|