@junwu168/openshell 0.1.3 → 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/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 -25
- 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 -65
- 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,54 +0,0 @@
|
|
|
1
|
-
# Server Registry CLI 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:** Add an interactive password-based server registry CLI for real OpenCode smoke testing, with `add`, `list`, and `remove` commands backed by the existing encrypted registry.
|
|
6
|
-
|
|
7
|
-
**Architecture:** Extend the existing encrypted registry with delete support, add a small CLI module that owns prompt flow and output formatting, and expose it through a thin script entrypoint plus a package script alias. Keep the OpenCode plugin and SSH runtime unchanged.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript, Bun, Node readline/TTY APIs, existing encrypted registry + Keychain secret provider
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
### Task 1: Add Registry Delete Coverage
|
|
14
|
-
|
|
15
|
-
**Files:**
|
|
16
|
-
- Modify: `tests/unit/server-registry.test.ts`
|
|
17
|
-
- Modify: `src/core/registry/server-registry.ts`
|
|
18
|
-
|
|
19
|
-
- [ ] **Step 1: Write failing tests for deleting an existing record and removing a missing id safely**
|
|
20
|
-
- [ ] **Step 2: Run `~/.bun/bin/bun test tests/unit/server-registry.test.ts` and confirm the new cases fail**
|
|
21
|
-
- [ ] **Step 3: Add `remove(id)` to the registry interface and implementation with the existing write queue + lock discipline**
|
|
22
|
-
- [ ] **Step 4: Re-run `~/.bun/bin/bun test tests/unit/server-registry.test.ts` and confirm it passes**
|
|
23
|
-
|
|
24
|
-
### Task 2: Add CLI Behavior Tests
|
|
25
|
-
|
|
26
|
-
**Files:**
|
|
27
|
-
- Create: `tests/unit/server-registry-cli.test.ts`
|
|
28
|
-
- Create: `src/cli/server-registry.ts`
|
|
29
|
-
|
|
30
|
-
- [ ] **Step 1: Write failing tests for `list`, interactive `add`, and interactive `remove` using a fake prompt/output adapter**
|
|
31
|
-
- [ ] **Step 2: Run `~/.bun/bin/bun test tests/unit/server-registry-cli.test.ts` and confirm the new cases fail**
|
|
32
|
-
- [ ] **Step 3: Implement a CLI module with command dispatch, interactive prompts, confirmation flow, and safe non-secret listing output**
|
|
33
|
-
- [ ] **Step 4: Re-run `~/.bun/bin/bun test tests/unit/server-registry-cli.test.ts` and confirm it passes**
|
|
34
|
-
|
|
35
|
-
### Task 3: Wire The Script Entry Point
|
|
36
|
-
|
|
37
|
-
**Files:**
|
|
38
|
-
- Create: `scripts/server-registry.ts`
|
|
39
|
-
- Modify: `package.json`
|
|
40
|
-
|
|
41
|
-
- [ ] **Step 1: Add a thin script entry point that calls the CLI module**
|
|
42
|
-
- [ ] **Step 2: Add a package script alias such as `server-registry`**
|
|
43
|
-
- [ ] **Step 3: Run `~/.bun/bin/bun run server-registry list` against an empty registry and confirm it exits cleanly**
|
|
44
|
-
|
|
45
|
-
### Task 4: Verify End To End
|
|
46
|
-
|
|
47
|
-
**Files:**
|
|
48
|
-
- Modify: `README.md`
|
|
49
|
-
|
|
50
|
-
- [ ] **Step 1: Document the real-server smoke workflow using the new CLI**
|
|
51
|
-
- [ ] **Step 2: Run `~/.bun/bin/bun test tests/unit/server-registry.test.ts tests/unit/server-registry-cli.test.ts`**
|
|
52
|
-
- [ ] **Step 3: Run `~/.bun/bin/bun run typecheck`**
|
|
53
|
-
- [ ] **Step 4: Run `~/.bun/bin/bun run build`**
|
|
54
|
-
- [ ] **Step 5: Run `~/.bun/bin/bun test` with elevated container-runtime access if needed, or note the environment limitation explicitly**
|
|
@@ -1,494 +0,0 @@
|
|
|
1
|
-
# Config-Backed Credential Registry 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:** Replace the current encrypted and keychain-backed credential registry with a layered workspace/global config model that stores plain-text passwords and path-only key or certificate references.
|
|
6
|
-
|
|
7
|
-
**Architecture:** Keep the existing orchestrator, policy, audit, and OpenCode tool surface intact while swapping only the credential-storage layer. The new backend reads and writes JSON config files from workspace and global scopes, resolves an effective server view with workspace override semantics, and normalizes path-based auth before building SSH connection options.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript, Bun, OpenCode plugin SDK, `ssh2`, `env-paths`, Bun test
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
### Task 1: Replace Runtime Path And Registry Types
|
|
14
|
-
|
|
15
|
-
**Files:**
|
|
16
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/paths.ts`
|
|
17
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/registry/server-registry.ts`
|
|
18
|
-
- Delete: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/registry/crypto.ts`
|
|
19
|
-
- Delete: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/registry/keychain-provider.ts`
|
|
20
|
-
- Delete: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/registry/secret-provider.ts`
|
|
21
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/paths.test.ts`
|
|
22
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/server-registry.test.ts`
|
|
23
|
-
|
|
24
|
-
- [ ] **Step 1: Write the failing path and registry tests**
|
|
25
|
-
|
|
26
|
-
Add tests that define the new backend contract:
|
|
27
|
-
|
|
28
|
-
```ts
|
|
29
|
-
test("runtime paths expose global and workspace server config locations", () => {
|
|
30
|
-
const runtime = createRuntimePaths("/repo")
|
|
31
|
-
expect(runtime.globalRegistryFile.endsWith("servers.json")).toBe(true)
|
|
32
|
-
expect(runtime.workspaceRegistryFile).toBe("/repo/.open-code/servers.json")
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test("workspace records override global records by id", async () => {
|
|
36
|
-
const registry = createServerRegistry({
|
|
37
|
-
globalRegistryFile,
|
|
38
|
-
workspaceRegistryFile,
|
|
39
|
-
workspaceRoot,
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
expect(await registry.resolve("prod-a")).toMatchObject({
|
|
43
|
-
id: "prod-a",
|
|
44
|
-
scope: "workspace",
|
|
45
|
-
shadowingGlobal: true,
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Also replace the old encryption-oriented tests with config-oriented expectations:
|
|
51
|
-
|
|
52
|
-
- plain-text password is written as plain JSON
|
|
53
|
-
- workspace and global scopes are loaded separately
|
|
54
|
-
- `list()` returns effective merged records with scope metadata
|
|
55
|
-
- `listRaw("workspace")` and `listRaw("global")` return unmerged records
|
|
56
|
-
|
|
57
|
-
- [ ] **Step 2: Run targeted tests to verify they fail**
|
|
58
|
-
|
|
59
|
-
Run:
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
~/.bun/bin/bun test tests/unit/paths.test.ts tests/unit/server-registry.test.ts
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Expected:
|
|
66
|
-
|
|
67
|
-
- FAIL because `runtimePaths` still exposes `servers.enc.json`
|
|
68
|
-
- FAIL because `createServerRegistry()` still expects `secretProvider`
|
|
69
|
-
- FAIL because scope metadata and layered reads do not exist yet
|
|
70
|
-
|
|
71
|
-
- [ ] **Step 3: Implement the new path model and registry types**
|
|
72
|
-
|
|
73
|
-
Update `src/core/paths.ts` to expose:
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
export const runtimePaths = {
|
|
77
|
-
configDir: paths.config,
|
|
78
|
-
dataDir: paths.data,
|
|
79
|
-
globalRegistryFile: `${paths.config}/servers.json`,
|
|
80
|
-
auditLogFile: `${paths.data}/audit/actions.jsonl`,
|
|
81
|
-
auditRepoDir: `${paths.data}/audit/repo`,
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export const workspaceRegistryFile = (workspaceRoot: string) =>
|
|
85
|
-
`${workspaceRoot}/.open-code/servers.json`
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
Replace the registry backend in `src/core/registry/server-registry.ts` with a JSON-file implementation:
|
|
89
|
-
|
|
90
|
-
- remove encryption and `SecretProvider`
|
|
91
|
-
- add scoped file loading for `global` and `workspace`
|
|
92
|
-
- add config schema types:
|
|
93
|
-
- `PasswordAuthRecord` with `secret`
|
|
94
|
-
- `PrivateKeyAuthRecord` with `privateKeyPath`
|
|
95
|
-
- `CertificateAuthRecord` with `certificatePath` and `privateKeyPath`
|
|
96
|
-
- add scope-aware result types, for example:
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
export type RegistryScope = "global" | "workspace"
|
|
100
|
-
|
|
101
|
-
export type ResolvedServerRecord = ServerRecord & {
|
|
102
|
-
scope: RegistryScope
|
|
103
|
-
shadowingGlobal?: boolean
|
|
104
|
-
workspaceRoot?: string
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Add methods needed by the spec:
|
|
109
|
-
|
|
110
|
-
- `list()`
|
|
111
|
-
- `resolve(id)`
|
|
112
|
-
- `upsert(scope, record)`
|
|
113
|
-
- `remove(scope, id)`
|
|
114
|
-
- `listRaw(scope)`
|
|
115
|
-
|
|
116
|
-
Keep atomic write behavior with temp-file + rename. Keep per-file lock behavior only if still needed for concurrent writes; if retained, scope the lock to the target config file rather than an encrypted-registry assumption.
|
|
117
|
-
|
|
118
|
-
- [ ] **Step 4: Run targeted tests to verify they pass**
|
|
119
|
-
|
|
120
|
-
Run:
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
~/.bun/bin/bun test tests/unit/paths.test.ts tests/unit/server-registry.test.ts
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Expected:
|
|
127
|
-
|
|
128
|
-
- PASS with config-path and scope-aware registry assertions green
|
|
129
|
-
|
|
130
|
-
- [ ] **Step 5: Commit**
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add \
|
|
134
|
-
src/core/paths.ts \
|
|
135
|
-
src/core/registry/server-registry.ts \
|
|
136
|
-
tests/unit/paths.test.ts \
|
|
137
|
-
tests/unit/server-registry.test.ts
|
|
138
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli rm \
|
|
139
|
-
src/core/registry/crypto.ts \
|
|
140
|
-
src/core/registry/keychain-provider.ts \
|
|
141
|
-
src/core/registry/secret-provider.ts
|
|
142
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "refactor: replace encrypted registry with layered config backend"
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Task 2: Update Orchestrator And Plugin Runtime For Path-Based Auth
|
|
146
|
-
|
|
147
|
-
**Files:**
|
|
148
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/orchestrator.ts`
|
|
149
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/opencode/plugin.ts`
|
|
150
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/core/contracts.ts`
|
|
151
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/integration/orchestrator.test.ts`
|
|
152
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/opencode-plugin.test.ts`
|
|
153
|
-
|
|
154
|
-
- [ ] **Step 1: Write the failing orchestrator and plugin tests**
|
|
155
|
-
|
|
156
|
-
Add tests that cover:
|
|
157
|
-
|
|
158
|
-
- path-based auth records are converted into `ssh2` connect config by reading file contents at runtime
|
|
159
|
-
- missing key or certificate files return structured validation errors before SSH execution
|
|
160
|
-
- plugin runtime dependencies no longer construct a Keychain-backed registry
|
|
161
|
-
|
|
162
|
-
Example test shape:
|
|
163
|
-
|
|
164
|
-
```ts
|
|
165
|
-
test("remote_exec reads privateKeyPath from workspace-scoped server records", async () => {
|
|
166
|
-
await writeFile(join(workspaceRoot, "keys/id_rsa"), "PRIVATE KEY")
|
|
167
|
-
|
|
168
|
-
const result = await orchestrator.remoteExec({
|
|
169
|
-
server: "prod-a",
|
|
170
|
-
command: "cat /etc/hosts",
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
expect(fakeSsh.execCalls[0]?.connection.privateKey).toContain("PRIVATE KEY")
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
test("missing private key path returns KEY_PATH_NOT_FOUND", async () => {
|
|
177
|
-
expect(result).toMatchObject({
|
|
178
|
-
status: "error",
|
|
179
|
-
code: "KEY_PATH_NOT_FOUND",
|
|
180
|
-
execution: { attempted: false, completed: false },
|
|
181
|
-
})
|
|
182
|
-
})
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
- [ ] **Step 2: Run targeted tests to verify they fail**
|
|
186
|
-
|
|
187
|
-
Run:
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
~/.bun/bin/bun test tests/integration/orchestrator.test.ts tests/unit/opencode-plugin.test.ts
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
Expected:
|
|
194
|
-
|
|
195
|
-
- FAIL because `toConnectConfig()` still expects in-memory key material
|
|
196
|
-
- FAIL because plugin still imports `createKeychainSecretProvider()`
|
|
197
|
-
|
|
198
|
-
- [ ] **Step 3: Implement scope-aware auth normalization in the orchestrator and plugin**
|
|
199
|
-
|
|
200
|
-
In `src/core/orchestrator.ts`:
|
|
201
|
-
|
|
202
|
-
- add a helper that turns a resolved server record into `ConnectConfig`
|
|
203
|
-
- for `password`, pass the plain `secret`
|
|
204
|
-
- for `privateKey`, read `privateKeyPath` from disk
|
|
205
|
-
- for `certificate`, read `privateKeyPath` and validate `certificatePath` exists even if `ssh2` does not need separate certificate material for the current flow
|
|
206
|
-
- resolve relative paths only for workspace-scoped records
|
|
207
|
-
- reject relative paths in global records
|
|
208
|
-
- return structured errors such as:
|
|
209
|
-
- `AUTH_PATH_INVALID`
|
|
210
|
-
- `KEY_PATH_NOT_FOUND`
|
|
211
|
-
- `CERTIFICATE_PATH_NOT_FOUND`
|
|
212
|
-
- `AUTH_PATH_UNREADABLE`
|
|
213
|
-
|
|
214
|
-
In `src/opencode/plugin.ts`:
|
|
215
|
-
|
|
216
|
-
- remove `createKeychainSecretProvider`
|
|
217
|
-
- construct the registry with global and workspace config paths derived from the current working directory
|
|
218
|
-
- keep the tool surface and approval behavior unchanged
|
|
219
|
-
|
|
220
|
-
Update any contracts if result payload types need new error codes.
|
|
221
|
-
|
|
222
|
-
- [ ] **Step 4: Run targeted tests to verify they pass**
|
|
223
|
-
|
|
224
|
-
Run:
|
|
225
|
-
|
|
226
|
-
```bash
|
|
227
|
-
~/.bun/bin/bun test tests/integration/orchestrator.test.ts tests/unit/opencode-plugin.test.ts
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
Expected:
|
|
231
|
-
|
|
232
|
-
- PASS with path-based auth and plugin wiring assertions green
|
|
233
|
-
|
|
234
|
-
- [ ] **Step 5: Commit**
|
|
235
|
-
|
|
236
|
-
```bash
|
|
237
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add \
|
|
238
|
-
src/core/orchestrator.ts \
|
|
239
|
-
src/opencode/plugin.ts \
|
|
240
|
-
src/core/contracts.ts \
|
|
241
|
-
tests/integration/orchestrator.test.ts \
|
|
242
|
-
tests/unit/opencode-plugin.test.ts
|
|
243
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "feat: resolve ssh auth from layered config files"
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Task 3: Rework The Registry CLI For Scope Selection And Auth Modes
|
|
247
|
-
|
|
248
|
-
**Files:**
|
|
249
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/src/cli/server-registry.ts`
|
|
250
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/scripts/server-registry.ts`
|
|
251
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/server-registry-cli.test.ts`
|
|
252
|
-
|
|
253
|
-
- [ ] **Step 1: Write the failing CLI tests**
|
|
254
|
-
|
|
255
|
-
Add tests for:
|
|
256
|
-
|
|
257
|
-
- defaulting to workspace scope when a workspace config already exists
|
|
258
|
-
- defaulting to global when no workspace config exists
|
|
259
|
-
- prompting for auth kind: `password`, `privateKey`, `certificate`
|
|
260
|
-
- warning before storing a plain-text password
|
|
261
|
-
- warning when a workspace `id` overrides a global `id`
|
|
262
|
-
- prompting which scope to remove from when both contain the same `id`
|
|
263
|
-
- listing source scope and shadowing status
|
|
264
|
-
|
|
265
|
-
Example:
|
|
266
|
-
|
|
267
|
-
```ts
|
|
268
|
-
test("add warns when a workspace record overrides a global record", async () => {
|
|
269
|
-
expect(stdout.toString()).toContain("will override global entry")
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
test("remove prompts for scope when the same id exists in both configs", async () => {
|
|
273
|
-
expect(promptCalls).toContainEqual(
|
|
274
|
-
expect.objectContaining({ message: expect.stringContaining("Remove from which scope") }),
|
|
275
|
-
)
|
|
276
|
-
})
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
- [ ] **Step 2: Run targeted tests to verify they fail**
|
|
280
|
-
|
|
281
|
-
Run:
|
|
282
|
-
|
|
283
|
-
```bash
|
|
284
|
-
~/.bun/bin/bun test tests/unit/server-registry-cli.test.ts
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
Expected:
|
|
288
|
-
|
|
289
|
-
- FAIL because CLI currently assumes one registry file
|
|
290
|
-
- FAIL because only password auth is supported
|
|
291
|
-
- FAIL because scope-aware list/remove flows do not exist
|
|
292
|
-
|
|
293
|
-
- [ ] **Step 3: Implement the CLI changes**
|
|
294
|
-
|
|
295
|
-
In `src/cli/server-registry.ts`:
|
|
296
|
-
|
|
297
|
-
- inject workspace root and scoped registry methods into CLI deps
|
|
298
|
-
- add scope selection prompt with defaults:
|
|
299
|
-
- workspace if workspace config exists
|
|
300
|
-
- otherwise global
|
|
301
|
-
- add auth-kind selection prompt
|
|
302
|
-
- support these persisted shapes:
|
|
303
|
-
|
|
304
|
-
```ts
|
|
305
|
-
auth: { kind: "password", secret: "plain-text" }
|
|
306
|
-
auth: { kind: "privateKey", privateKeyPath: "./keys/id_rsa", passphrase?: "..." }
|
|
307
|
-
auth: {
|
|
308
|
-
kind: "certificate",
|
|
309
|
-
certificatePath: "./keys/client.pem",
|
|
310
|
-
privateKeyPath: "./keys/client-key.pem",
|
|
311
|
-
passphrase?: "...",
|
|
312
|
-
}
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
- warn before plain-text password storage
|
|
316
|
-
- for `list`, print scope and shadowing markers
|
|
317
|
-
- for `remove`, resolve scope explicitly before deleting
|
|
318
|
-
|
|
319
|
-
Keep the script entrypoint unchanged so `bun run server-registry` still works.
|
|
320
|
-
|
|
321
|
-
- [ ] **Step 4: Run targeted tests to verify they pass**
|
|
322
|
-
|
|
323
|
-
Run:
|
|
324
|
-
|
|
325
|
-
```bash
|
|
326
|
-
~/.bun/bin/bun test tests/unit/server-registry-cli.test.ts
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
Expected:
|
|
330
|
-
|
|
331
|
-
- PASS with new scope and auth prompt behavior covered
|
|
332
|
-
|
|
333
|
-
- [ ] **Step 5: Commit**
|
|
334
|
-
|
|
335
|
-
```bash
|
|
336
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add \
|
|
337
|
-
src/cli/server-registry.ts \
|
|
338
|
-
scripts/server-registry.ts \
|
|
339
|
-
tests/unit/server-registry-cli.test.ts
|
|
340
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "feat: add layered config flows to server registry cli"
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### Task 4: Remove Keychain Dependency From Build And Docs
|
|
344
|
-
|
|
345
|
-
**Files:**
|
|
346
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/package.json`
|
|
347
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/README.md`
|
|
348
|
-
- Modify: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/docs/superpowers/specs/2026-03-26-config-backed-credential-registry-design.md`
|
|
349
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/build-layout.test.ts`
|
|
350
|
-
|
|
351
|
-
- [ ] **Step 1: Write the failing dependency and docs assertions**
|
|
352
|
-
|
|
353
|
-
Add or update a lightweight test to assert the published build no longer depends on `keytar` or deleted registry modules where practical.
|
|
354
|
-
|
|
355
|
-
Example:
|
|
356
|
-
|
|
357
|
-
```ts
|
|
358
|
-
test("package metadata no longer declares keytar", async () => {
|
|
359
|
-
const pkg = JSON.parse(await readFile("package.json", "utf8"))
|
|
360
|
-
expect(pkg.dependencies.keytar).toBeUndefined()
|
|
361
|
-
})
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
- [ ] **Step 2: Run targeted tests to verify they fail**
|
|
365
|
-
|
|
366
|
-
Run:
|
|
367
|
-
|
|
368
|
-
```bash
|
|
369
|
-
~/.bun/bin/bun test tests/unit/build-layout.test.ts
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
Expected:
|
|
373
|
-
|
|
374
|
-
- FAIL because `package.json` still includes `keytar`
|
|
375
|
-
|
|
376
|
-
- [ ] **Step 3: Remove obsolete dependencies and update docs**
|
|
377
|
-
|
|
378
|
-
In `package.json`:
|
|
379
|
-
|
|
380
|
-
- remove `keytar`
|
|
381
|
-
|
|
382
|
-
In `README.md`:
|
|
383
|
-
|
|
384
|
-
- document the new config file locations
|
|
385
|
-
- document that plain-text password storage is unsafe but supported
|
|
386
|
-
- document that key/cert auth stores file paths only
|
|
387
|
-
- include a short example for both workspace and global configs
|
|
388
|
-
|
|
389
|
-
If the spec doc needs a brief implementation note after planning, keep it synchronized.
|
|
390
|
-
|
|
391
|
-
- [ ] **Step 4: Run targeted tests to verify they pass**
|
|
392
|
-
|
|
393
|
-
Run:
|
|
394
|
-
|
|
395
|
-
```bash
|
|
396
|
-
~/.bun/bin/bun test tests/unit/build-layout.test.ts
|
|
397
|
-
~/.bun/bin/bun run typecheck
|
|
398
|
-
~/.bun/bin/bun run build
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
Expected:
|
|
402
|
-
|
|
403
|
-
- PASS
|
|
404
|
-
- build succeeds without `keytar`
|
|
405
|
-
|
|
406
|
-
- [ ] **Step 5: Commit**
|
|
407
|
-
|
|
408
|
-
```bash
|
|
409
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli add \
|
|
410
|
-
package.json \
|
|
411
|
-
README.md \
|
|
412
|
-
tests/unit/build-layout.test.ts
|
|
413
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli commit -m "chore: remove keychain dependency from credential registry"
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
### Task 5: Run Full Verification And Realistic Smoke Coverage
|
|
417
|
-
|
|
418
|
-
**Files:**
|
|
419
|
-
- Modify if needed: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/opencode.json`
|
|
420
|
-
- Modify if needed: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/examples/opencode-local/.opencode/package.json`
|
|
421
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/integration/orchestrator.test.ts`
|
|
422
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/integration/ssh-runtime.test.ts`
|
|
423
|
-
- Test: `/Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli/tests/unit/*.test.ts`
|
|
424
|
-
|
|
425
|
-
- [ ] **Step 1: Run the full automated test suite**
|
|
426
|
-
|
|
427
|
-
Run:
|
|
428
|
-
|
|
429
|
-
```bash
|
|
430
|
-
~/.bun/bin/bun test
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
Expected:
|
|
434
|
-
|
|
435
|
-
- PASS across unit and integration coverage
|
|
436
|
-
|
|
437
|
-
- [ ] **Step 2: Run typecheck and build**
|
|
438
|
-
|
|
439
|
-
Run:
|
|
440
|
-
|
|
441
|
-
```bash
|
|
442
|
-
~/.bun/bin/bun run typecheck
|
|
443
|
-
~/.bun/bin/bun run build
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
Expected:
|
|
447
|
-
|
|
448
|
-
- PASS
|
|
449
|
-
|
|
450
|
-
- [ ] **Step 3: Run manual Docker smoke test against the new config model**
|
|
451
|
-
|
|
452
|
-
Use the disposable SSH container flow:
|
|
453
|
-
|
|
454
|
-
```bash
|
|
455
|
-
docker run -d --name open-code-smoke-ssh \
|
|
456
|
-
-e USER_NAME=open \
|
|
457
|
-
-e USER_PASSWORD=openpass \
|
|
458
|
-
-e PASSWORD_ACCESS=true \
|
|
459
|
-
-e SUDO_ACCESS=false \
|
|
460
|
-
-p 22222:2222 \
|
|
461
|
-
linuxserver/openssh-server:10.2_p1-r0-ls219
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
Create a workspace or global `servers.json` matching the new schema, then validate:
|
|
465
|
-
|
|
466
|
-
- `bun run server-registry list`
|
|
467
|
-
- `opencode` -> `list_servers`
|
|
468
|
-
- `remote_exec` with `cat /tmp/open-code/hosts`
|
|
469
|
-
- `remote_write_file` still prompts for approval
|
|
470
|
-
|
|
471
|
-
Expected:
|
|
472
|
-
|
|
473
|
-
- config-backed server appears in `list_servers`
|
|
474
|
-
- safe `remote_exec` succeeds without approval prompt
|
|
475
|
-
- write tool still requires approval
|
|
476
|
-
|
|
477
|
-
- [ ] **Step 4: Clean up smoke artifacts**
|
|
478
|
-
|
|
479
|
-
Run:
|
|
480
|
-
|
|
481
|
-
```bash
|
|
482
|
-
docker rm -f open-code-smoke-ssh
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
Delete any temporary test configs created during the smoke run.
|
|
486
|
-
|
|
487
|
-
- [ ] **Step 5: Commit follow-up fixes if verification required any**
|
|
488
|
-
|
|
489
|
-
```bash
|
|
490
|
-
git -C /Users/wujunming/Documents/experimental/openshell/.worktrees/registry-cli status -sb
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
If no code changes were needed, do not create an empty commit.
|
|
494
|
-
|