@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.
Files changed (60) hide show
  1. package/dist/core/audit/log-store.js +1 -1
  2. package/dist/core/orchestrator.d.ts +2 -2
  3. package/dist/core/orchestrator.js +3 -3
  4. package/dist/core/result.d.ts +1 -1
  5. package/dist/index.d.ts +3 -3
  6. package/dist/index.js +3 -3
  7. package/dist/opencode/plugin.d.ts +1 -1
  8. package/dist/opencode/plugin.js +8 -8
  9. package/package.json +6 -1
  10. package/.claude/settings.local.json +0 -25
  11. package/bun.lock +0 -368
  12. package/docs/superpowers/notes/2026-03-25-opencode-remote-tools-handoff.md +0 -81
  13. package/docs/superpowers/notes/2026-03-26-openshell-pre-release-review.md +0 -174
  14. package/docs/superpowers/plans/2026-03-25-opencode-remote-tools.md +0 -1656
  15. package/docs/superpowers/plans/2026-03-25-server-registry-cli.md +0 -54
  16. package/docs/superpowers/plans/2026-03-26-config-backed-credential-registry.md +0 -494
  17. package/docs/superpowers/plans/2026-03-26-openshell-release-prep.md +0 -639
  18. package/docs/superpowers/specs/2026-03-25-opencode-remote-tools-design.md +0 -378
  19. package/docs/superpowers/specs/2026-03-26-config-backed-credential-registry-design.md +0 -272
  20. package/docs/superpowers/specs/2026-03-26-openshell-release-prep-design.md +0 -197
  21. package/examples/opencode-local/opencode.json +0 -19
  22. package/scripts/openshell.ts +0 -3
  23. package/scripts/server-registry.ts +0 -3
  24. package/src/cli/openshell.ts +0 -65
  25. package/src/cli/server-registry.ts +0 -476
  26. package/src/core/audit/git-audit-repo.ts +0 -42
  27. package/src/core/audit/log-store.ts +0 -20
  28. package/src/core/audit/redact.ts +0 -4
  29. package/src/core/contracts.ts +0 -51
  30. package/src/core/orchestrator.ts +0 -1082
  31. package/src/core/patch.ts +0 -11
  32. package/src/core/paths.ts +0 -32
  33. package/src/core/policy.ts +0 -30
  34. package/src/core/registry/server-registry.ts +0 -505
  35. package/src/core/result.ts +0 -16
  36. package/src/core/ssh/ssh-runtime.ts +0 -355
  37. package/src/index.ts +0 -3
  38. package/src/opencode/plugin.ts +0 -242
  39. package/src/product/install.ts +0 -43
  40. package/src/product/opencode-config.ts +0 -118
  41. package/src/product/uninstall.ts +0 -47
  42. package/src/product/workspace-tracker.ts +0 -69
  43. package/tests/integration/fake-ssh-server.ts +0 -97
  44. package/tests/integration/install-lifecycle.test.ts +0 -85
  45. package/tests/integration/orchestrator.test.ts +0 -767
  46. package/tests/integration/ssh-runtime.test.ts +0 -122
  47. package/tests/unit/audit.test.ts +0 -221
  48. package/tests/unit/build-layout.test.ts +0 -28
  49. package/tests/unit/opencode-config.test.ts +0 -100
  50. package/tests/unit/opencode-plugin.test.ts +0 -358
  51. package/tests/unit/openshell-cli.test.ts +0 -60
  52. package/tests/unit/paths.test.ts +0 -64
  53. package/tests/unit/plugin-export.test.ts +0 -10
  54. package/tests/unit/policy.test.ts +0 -53
  55. package/tests/unit/release-docs.test.ts +0 -31
  56. package/tests/unit/result.test.ts +0 -28
  57. package/tests/unit/server-registry-cli.test.ts +0 -673
  58. package/tests/unit/server-registry.test.ts +0 -452
  59. package/tests/unit/workspace-tracker.test.ts +0 -57
  60. package/tsconfig.json +0 -14
@@ -1,378 +0,0 @@
1
- # Open Code v1 Design: OpenCode Remote Tools
2
-
3
- ## Overview
4
-
5
- Open Code is a terminal-only plugin for AI coding CLIs. In v1, the first host integration is `opencode`.
6
-
7
- The product goal is to let an AI model operate on one or more remote Linux servers over SSH while keeping credentials isolated from the model, enforcing strict user approvals for risky actions, and preserving an audit trail on the client machine.
8
-
9
- This document defines the design boundary for v1 so implementation planning can proceed without revisiting scope or architecture.
10
-
11
- ## Problem Statement
12
-
13
- AI coding CLIs are useful for local development, but infrastructure and operations work often happens across multiple remote machines. Existing CLI tools do not provide a safe, structured way for a model to:
14
-
15
- - work against multiple remote servers in one session,
16
- - use isolated SSH credentials that the model cannot read,
17
- - require explicit approval before risky remote actions,
18
- - preserve a local audit trail of commands and file changes, and
19
- - evolve cleanly to support additional host CLIs later.
20
-
21
- ## Goals
22
-
23
- - Integrate with `opencode` as the first supported host CLI.
24
- - Expose explicit remote tools rather than pretending the remote machine is the local filesystem.
25
- - Support multiple registered servers from the start.
26
- - Store server credentials in a local encrypted registry controlled by Open Code, not by model-visible config files.
27
- - Allow clearly safe Linux inspection commands to run without approval.
28
- - Require per-action approval for every write operation.
29
- - Require approval for middleware-oriented commands even when they appear read-only.
30
- - Keep a structured local audit log for every action.
31
- - Keep a local git-backed audit repository for file changes made through dedicated remote file write tools.
32
- - Preserve a host-agnostic core so future adapters for `codex`, `claude code`, or similar CLIs can reuse the same runtime and policy logic.
33
-
34
- ## Non-Goals
35
-
36
- - Supporting GUI editors or IDE plugins in v1.
37
- - Hiding remote execution behind local-looking file or shell tools.
38
- - Auto-approving writes for a whole session or server.
39
- - Using git on the remote server for audit or rollback.
40
- - Guaranteeing full file-level reconstruction for arbitrary shell commands that mutate remote state indirectly.
41
- - Supporting every possible remote protocol beyond SSH in v1.
42
-
43
- ## Scope Summary
44
-
45
- V1 is a terminal plugin for `opencode` backed by a host-agnostic local core library that runs in-process with the plugin. The plugin defines explicit remote tools. The core handles encrypted credentials, SSH execution, policy enforcement, audit logging, and local git snapshots for dedicated file-write operations.
46
-
47
- ## Architecture
48
-
49
- ### High-Level Shape
50
-
51
- The system is split into two layers:
52
-
53
- 1. `opencode` host adapter
54
- 2. host-agnostic local core
55
-
56
- In v1, the local core is an in-process library rather than a separate background daemon or long-lived local service. This keeps packaging, lifecycle, and approval flow simple for the first release while preserving clear boundaries that can later be extracted behind an IPC layer if needed.
57
-
58
- The `opencode` adapter is responsible for:
59
-
60
- - registering tool definitions with `opencode`,
61
- - receiving tool calls,
62
- - surfacing approval prompts to the user,
63
- - returning structured tool results in the shape expected by `opencode`.
64
-
65
- The local core is responsible for:
66
-
67
- - encrypted server registry,
68
- - SSH connection and session reuse,
69
- - command classification and policy enforcement,
70
- - remote file and command execution,
71
- - audit log persistence,
72
- - local git-backed file snapshotting.
73
-
74
- ### Core Module Boundaries
75
-
76
- The local core should be split into the following modules:
77
-
78
- - `host-adapter/opencode`
79
- - The `opencode`-specific plugin layer.
80
- - `tool-orchestrator`
81
- - Entry point for all tool calls.
82
- - Applies common sequencing: validate, resolve server, classify, request approval when needed, execute, audit, return result.
83
- - `server-registry`
84
- - Stores encrypted server definitions and authentication material.
85
- - `ssh-runtime`
86
- - Owns connection lifecycle, command execution, file transfer, and remote patch/write operations.
87
- - `policy-engine`
88
- - Classifies tool actions into auto-allow, approval-required, or reject.
89
- - `audit-engine`
90
- - Writes structured action logs and manages local git-backed snapshots for file changes.
91
-
92
- ### Design Rule
93
-
94
- All host tools must call the `tool-orchestrator`. No tool may bypass policy or audit directly. This keeps behavior consistent across commands and file tools and prevents policy drift as more adapters are added later.
95
-
96
- ## Tool Surface
97
-
98
- The v1 tool set is explicit and server-targeted:
99
-
100
- - `list_servers()`
101
- - `remote_exec(server, command, cwd?, timeout?)`
102
- - `remote_read_file(server, path, offset?, length?)`
103
- - `remote_write_file(server, path, content, mode?)`
104
- - `remote_patch_file(server, path, diff_or_patch)`
105
- - `remote_list_dir(server, path, recursive?, limit?)`
106
- - `remote_stat(server, path)`
107
- - `remote_find(server, path, pattern, glob?, limit?)`
108
-
109
- ### Tool Surface Principles
110
-
111
- - Every operation names a `server` explicitly.
112
- - The default behavior must favor clarity over convenience.
113
- - Session-local implicit "current server" behavior is out of scope for v1.
114
- - Dedicated file tools are preferred for file inspection and file mutation.
115
- - `remote_exec` remains available for shell-oriented work that does not map cleanly to a dedicated file tool.
116
-
117
- ## Data Flow
118
-
119
- For every tool invocation, the runtime sequence is:
120
-
121
- 1. The `opencode` adapter receives the tool call.
122
- 2. `tool-orchestrator` validates arguments and resolves the target server via `server-registry`.
123
- 3. `policy-engine` classifies the action.
124
- 4. If the action requires approval, the adapter presents the exact server, path, and command or write intent to the user.
125
- 5. `ssh-runtime` executes the command or file action.
126
- 6. `audit-engine` records the action and, when relevant, creates local snapshots.
127
- 7. A structured result is returned to the adapter and then back to `opencode`.
128
-
129
- ## Security And Permissions
130
-
131
- ### Permission Classes
132
-
133
- V1 uses three policy outcomes:
134
-
135
- - `auto-allow`
136
- - `approval-required`
137
- - `reject`
138
-
139
- ### Auto-Allow
140
-
141
- The following operations may run directly:
142
-
143
- - dedicated read-focused file tools such as `remote_read_file`, `remote_list_dir`, `remote_stat`, and `remote_find`,
144
- - clearly safe Linux inspection commands executed through `remote_exec`.
145
-
146
- Examples of Linux inspection commands include:
147
-
148
- - `cat`
149
- - `grep`
150
- - `find`
151
- - `ls`
152
- - `pwd`
153
- - `uname`
154
- - `df`
155
- - `free`
156
- - `ps`
157
- - `systemctl status`
158
-
159
- The exact allowlist belongs in implementation, but the design intent is a conservative rule-based allowlist.
160
-
161
- ### Approval-Required
162
-
163
- The following actions must require explicit user approval for each execution:
164
-
165
- - every file mutation,
166
- - every shell command that may mutate remote state,
167
- - every middleware-oriented command family even when the specific invocation appears read-only.
168
-
169
- Examples of middleware-oriented command families include:
170
-
171
- - `psql`
172
- - `mysql`
173
- - `redis-cli`
174
- - `kubectl`
175
- - `docker`
176
- - `helm`
177
- - cloud provider CLIs
178
-
179
- Unknown commands must default to `approval-required`.
180
-
181
- ### Reject
182
-
183
- The runtime may reject requests that are malformed or unsupported, such as:
184
-
185
- - unknown server ids,
186
- - invalid file paths or missing required arguments,
187
- - unsupported patch formats,
188
- - actions that violate hard safety rules defined by the implementation.
189
-
190
- ### Classification Strategy
191
-
192
- Policy classification must be deterministic and rule-based. V1 must not rely on a model to decide whether a command is safe. The model may propose commands, but the core decides whether they run directly, require approval, or are rejected.
193
-
194
- For `remote_exec`, the auto-allow path is intentionally narrow. Only simple invocations of allowlisted Linux inspection commands may bypass approval. Commands that include shell composition or higher-risk syntax must default to `approval-required`, including:
195
-
196
- - pipes,
197
- - redirection,
198
- - command chaining,
199
- - subshells,
200
- - compound shell expressions,
201
- - other command forms that require shell parsing beyond a single straightforward invocation.
202
-
203
- ## Credential Model
204
-
205
- ### Storage
206
-
207
- Open Code manages its own encrypted local server registry.
208
-
209
- Each server record stores:
210
-
211
- - server id,
212
- - host,
213
- - port,
214
- - username,
215
- - labels or grouping metadata,
216
- - authentication method,
217
- - authentication material,
218
- - optional non-secret metadata.
219
-
220
- Supported v1 authentication methods:
221
-
222
- - username plus password,
223
- - imported private key or certificate material.
224
-
225
- The registry encryption key should be protected by a client-controlled unlock mechanism such as an OS keychain entry or an equivalent local secret source selected during implementation. The design requirement is that registry decryption stays on the client machine and is independent of the model runtime.
226
-
227
- ### Isolation Requirements
228
-
229
- - Credentials must not be stored in model-visible prompt files.
230
- - Raw credentials must never be returned by tools.
231
- - Tool calls reference servers by logical id, not by raw secret material.
232
- - Decryption and secret handling stay inside the core.
233
-
234
- ## Multi-Server Model
235
-
236
- Multi-server support is a first-class requirement.
237
-
238
- Design implications:
239
-
240
- - every tool call requires an explicit server target,
241
- - the registry supports many named servers,
242
- - the SSH runtime may reuse connections per server during a session,
243
- - audit artifacts must be partitioned by server so changes remain attributable.
244
-
245
- Grouping, tags, or labels may be stored in the registry for future filtering, but group-based orchestration is not required in v1.
246
-
247
- ## Audit Model
248
-
249
- Audit artifacts are stored on the client machine where `opencode` runs, not on the remote server.
250
-
251
- ### Structured Action Log
252
-
253
- Every tool action writes a structured local log entry that includes:
254
-
255
- - timestamp,
256
- - server id,
257
- - tool name,
258
- - sanitized arguments,
259
- - approval status,
260
- - execution result metadata,
261
- - changed path metadata when available.
262
-
263
- Sensitive values must be redacted before persistence.
264
-
265
- Action logging is a hard requirement, not a best-effort feature. Before any remote operation runs, the runtime must verify that the action log sink is writable. If structured logging cannot be persisted, the tool call must fail closed and the remote action must not execute.
266
-
267
- ### Git-Backed File Snapshot Audit
268
-
269
- Dedicated file mutation tools participate in local git-backed snapshotting.
270
-
271
- For `remote_write_file` and `remote_patch_file`, the audit flow is:
272
-
273
- 1. capture the pre-change remote file content if the file exists,
274
- 2. perform the write or patch,
275
- 3. capture the post-change remote file content,
276
- 4. store snapshots locally under an audit directory organized by server and remote path,
277
- 5. commit the snapshot change into a local git repository.
278
-
279
- This repository exists only on the client machine and is used for inspection, history, and rollback support.
280
-
281
- For dedicated file mutation tools, snapshotting is also a hard requirement. Before a mutating file action executes, the runtime must verify that the snapshot workspace and local git repository are writable. If pre-change snapshot preparation cannot succeed, the write must not run.
282
-
283
- If the remote write succeeds but post-change snapshot persistence or git commit creation fails, the tool result must be returned as a partial failure rather than a clean success. The result must make clear that the remote state changed but audit completion failed, so the user can treat the operation as security-relevant follow-up work.
284
-
285
- ### Limit Of Audit Guarantees
286
-
287
- `remote_exec` always creates structured command audit logs, but v1 does not promise file-level snapshots for arbitrary shell side effects. If a user wants file-level diffs and recovery guarantees, they should prefer dedicated file mutation tools.
288
-
289
- ## Error Handling
290
-
291
- The system must return structured failures rather than flattening all problems into a generic error string.
292
-
293
- Important error classes:
294
-
295
- - server resolution failure,
296
- - credential decrypt or load failure,
297
- - SSH connection failure,
298
- - authentication failure,
299
- - timeout,
300
- - policy rejection,
301
- - approval denial,
302
- - remote file-not-found,
303
- - remote permission denied,
304
- - non-zero command exit,
305
- - patch apply failure,
306
- - local audit persistence failure,
307
- - local git snapshot failure.
308
-
309
- Tool results should distinguish:
310
-
311
- - whether the action was attempted,
312
- - whether it completed,
313
- - command exit status when applicable,
314
- - stdout and stderr payloads or truncation metadata,
315
- - audit/logging status when relevant.
316
-
317
- ## Testing Strategy
318
-
319
- ### Unit Tests
320
-
321
- - `policy-engine` command classification
322
- - argument validation and path validation
323
- - secret redaction
324
- - snapshot path mapping
325
- - `tool-orchestrator` sequencing logic
326
-
327
- ### Integration Tests
328
-
329
- - encrypted registry load and server resolution
330
- - SSH connection against disposable local test targets
331
- - read-only command execution
332
- - approval-required command flow
333
- - dedicated file read and write flows
334
- - multi-server session isolation
335
-
336
- ### Audit Tests
337
-
338
- - structured log persistence
339
- - pre-change and post-change snapshot capture
340
- - git commit creation for dedicated file writes
341
- - server-specific audit partitioning
342
-
343
- ### Adapter Contract Tests
344
-
345
- - tool registration shape for `opencode`
346
- - argument-to-core mapping
347
- - structured result mapping back to the host runtime
348
-
349
- ## Out Of Scope For V1
350
-
351
- - session-wide approval grants
352
- - group fan-out execution across multiple servers in one tool call
353
- - background daemon deployment model
354
- - remote git integration
355
- - full TUI management experience for registry and audit browsing
356
- - automatic command correction or command suggestion
357
- - support for non-SSH transports
358
-
359
- ## Implementation Constraints For Planning
360
-
361
- - The architecture must preserve a strict boundary between the `opencode` adapter and the host-agnostic core.
362
- - The initial implementation should optimize for clear module ownership and extension over completeness of the tool catalog.
363
- - Policy logic must be centralized and deterministic.
364
- - File-change audit guarantees should attach only to dedicated file mutation tools in v1.
365
- - The plan should assume future host adapters are likely, even though only `opencode` is in scope now.
366
-
367
- ## Success Criteria
368
-
369
- The design is successful for v1 when all of the following are true:
370
-
371
- - A user can register multiple remote servers locally with encrypted credentials.
372
- - `opencode` can invoke explicit remote tools against any registered server.
373
- - Clearly safe Linux inspection commands can run without approval.
374
- - Every write requires explicit approval.
375
- - Middleware-oriented commands require explicit approval even when nominally read-only.
376
- - Dedicated remote file writes create local git-backed before/after audit history.
377
- - Every tool action creates a structured local audit log.
378
- - The implementation plan can be written without reopening architecture or scope decisions.
@@ -1,272 +0,0 @@
1
- # Config-Backed Credential Registry Design
2
-
3
- Date: 2026-03-26
4
- Branch: `registry-cli`
5
- Status: Approved for planning
6
-
7
- ## Summary
8
-
9
- Replace the current encrypted registry plus OS keychain dependency with a simpler layered config model:
10
-
11
- - Read server definitions from two config files: user-global first, then workspace override.
12
- - Let workspace entries override global entries with the same `id`.
13
- - Store password auth in plain text, documented as unsafe.
14
- - Store certificate and private-key auth as filesystem paths only.
15
- - Remove reliance on macOS Keychain, `keytar`, or any other OS credential store.
16
-
17
- This change optimizes for operational simplicity and predictable cross-platform behavior over secret-at-rest protection.
18
-
19
- ## Goals
20
-
21
- - Eliminate the current OS keychain dependency.
22
- - Keep the credential model easy to inspect and edit manually.
23
- - Support repo-local and user-global server definitions.
24
- - Never store PEM or private-key contents in plugin-managed config.
25
- - Preserve the current explicit remote-tool model and SSH runtime shape.
26
-
27
- ## Non-Goals
28
-
29
- - Secret management or secure password storage.
30
- - Automatic migration from the current encrypted registry.
31
- - Environment-variable interpolation in v1 of this config-backed model.
32
- - Support for more than two config scopes.
33
-
34
- ## Current Problem
35
-
36
- The current branch stores the registry payload encrypted at rest and uses a `SecretProvider` backed by `keytar` to read or create a master key in the OS credential store. That behavior is acceptable on macOS but creates avoidable complexity, prompts, and portability concerns.
37
-
38
- The user preference is to simplify:
39
-
40
- - Plain-text passwords are acceptable if clearly documented as unsafe.
41
- - Key and certificate auth should reference files already managed by the user.
42
- - The plugin should not attempt to manage or protect key material itself.
43
-
44
- ## Proposed Design
45
-
46
- ### Config Scopes
47
-
48
- Two config scopes will be supported:
49
-
50
- 1. Workspace config
51
- 2. User-global config
52
-
53
- Read order:
54
-
55
- 1. Read the user-global config if present.
56
- 2. Read the workspace config if present.
57
- 3. Merge entries by `id`.
58
- 4. When both scopes define the same `id`, the workspace entry wins.
59
-
60
- When a workspace entry overrides a global entry, CLI output should make that explicit so users understand which effective server is active.
61
-
62
- ### File Locations
63
-
64
- Global config should live under the existing user config directory resolved by `env-paths`, for example:
65
-
66
- - macOS: `~/Library/Preferences/open-code/servers.json`
67
- - Linux: `~/.config/open-code/servers.json`
68
- - Windows: `%AppData%/open-code/servers.json`
69
-
70
- Workspace config should live in the repo/workspace root:
71
-
72
- - `<workspace>/.open-code/servers.json`
73
-
74
- The runtime should treat the presence of a workspace file as opt-in local override behavior.
75
-
76
- ### Data Model
77
-
78
- The config file should remain intentionally small and explicit. Each file is a top-level JSON array of server records:
79
-
80
- ```json
81
- [
82
- {
83
- "id": "prod-a",
84
- "host": "10.0.0.5",
85
- "port": 22,
86
- "username": "ubuntu",
87
- "labels": ["prod"],
88
- "groups": ["cluster-a"],
89
- "auth": {
90
- "kind": "privateKey",
91
- "privateKeyPath": "./keys/prod-a.pem"
92
- }
93
- }
94
- ]
95
- ```
96
-
97
- Supported auth shapes:
98
-
99
- - `password`
100
- - fields: `kind`, `secret`
101
- - `privateKey`
102
- - fields: `kind`, `privateKeyPath`, optional `passphrase`
103
- - `certificate`
104
- - fields: `kind`, `certificatePath`, `privateKeyPath`, optional `passphrase`
105
-
106
- Notes:
107
-
108
- - `password.secret` is stored in plain text.
109
- - `privateKey` and `certificate` entries store paths only.
110
- - No PEM, private key, or certificate contents are copied into config.
111
-
112
- ### Path Rules
113
-
114
- Workspace config:
115
-
116
- - may use relative key/cert paths
117
- - relative paths resolve from workspace root
118
-
119
- Global config:
120
-
121
- - key/cert paths must be absolute
122
- - relative paths in global config should be rejected as invalid
123
-
124
- At runtime, the effective server record should be normalized before SSH use:
125
-
126
- 1. determine effective scope for the selected record
127
- 2. resolve relative workspace paths
128
- 3. validate that referenced files exist and are readable
129
- 4. pass normalized auth inputs to the SSH runtime
130
-
131
- ### Registry Backend Changes
132
-
133
- The current encrypted registry backend should be replaced with a config-backed registry implementation.
134
-
135
- That means:
136
-
137
- - remove the `SecretProvider` dependency from the active registry path
138
- - stop encrypting the server registry payload
139
- - stop calling `keytar`
140
-
141
- The registry abstraction can remain, but it should now operate on layered config files rather than an encrypted blob.
142
-
143
- Recommended interfaces:
144
-
145
- - `list()`: return effective records with scope metadata
146
- - `resolve(id)`: return effective record with scope metadata
147
- - `upsert(scope, record)`: write to the chosen scope
148
- - `remove(scope, id)`: remove from the chosen scope
149
- - `listRaw(scope)`: read one scope without merge logic when the CLI needs direct scope inspection
150
-
151
- ## CLI Design
152
-
153
- The existing CLI entrypoint should remain:
154
-
155
- - `bun run server-registry add`
156
- - `bun run server-registry list`
157
- - `bun run server-registry remove`
158
-
159
- ### Add
160
-
161
- Prompt sequence:
162
-
163
- 1. choose target scope
164
- 2. enter server identity fields
165
- 3. choose auth kind
166
- 4. prompt for auth-specific fields
167
- 5. warn if storing a plain-text password
168
-
169
- Default scope behavior:
170
-
171
- - if workspace config exists, default to workspace
172
- - otherwise default to global
173
-
174
- If adding a workspace entry whose `id` already exists in global config:
175
-
176
- - print that the workspace entry will override the global entry
177
-
178
- ### List
179
-
180
- Listing should show effective records and source scope, for example:
181
-
182
- - `workspace`
183
- - `global`
184
-
185
- If an entry is overridden, the effective list should show the workspace record and should indicate that it shadows a global record when relevant.
186
-
187
- ### Remove
188
-
189
- Removal must be scope-aware.
190
-
191
- If the same `id` exists in both scopes:
192
-
193
- - prompt which scope to remove from
194
- - never remove both implicitly
195
-
196
- This keeps layered config behavior explicit and avoids destructive surprises.
197
-
198
- ## Runtime Flow
199
-
200
- For remote tool execution:
201
-
202
- 1. resolve the requested server `id` from the layered config registry
203
- 2. determine whether the effective record came from workspace or global scope
204
- 3. normalize auth paths if needed
205
- 4. validate file existence and readability for path-based auth
206
- 5. construct SSH auth options
207
- 6. continue through the existing orchestrator, policy, SSH, and audit flow
208
-
209
- This keeps policy, SSH execution, and auditing unchanged while simplifying only the credential-storage layer.
210
-
211
- ## Errors And Diagnostics
212
-
213
- The new registry path should return structured errors for:
214
-
215
- - missing config file when a write target is expected
216
- - malformed JSON
217
- - invalid schema
218
- - duplicate or conflicting records within one file if validation disallows them
219
- - relative key/cert path in global config
220
- - missing key/cert file
221
- - unreadable key/cert file
222
- - missing required auth fields
223
-
224
- Helpful CLI messaging matters here because users are now directly editing config.
225
-
226
- ## Migration
227
-
228
- No automatic migration in this pass.
229
-
230
- If the old encrypted registry exists, the new config-backed flow should ignore it. Documentation should state that the credential backend changed and that users need to define servers in config files going forward.
231
-
232
- This avoids partial migration logic and keeps the new behavior obvious.
233
-
234
- ## Testing
235
-
236
- Required test coverage:
237
-
238
- - parse and load a global-only config
239
- - parse and load a workspace-only config
240
- - workspace overrides global by `id`
241
- - workspace relative path resolution works
242
- - global relative path rejection works
243
- - path validation failures are surfaced cleanly
244
- - password auth records round-trip correctly through the config registry
245
- - `add` chooses the expected default scope
246
- - `add` warns when workspace overrides global
247
- - `list` reports source scope
248
- - `remove` prompts for scope when both scopes contain the same `id`
249
-
250
- Integration smoke coverage should continue to validate:
251
-
252
- - `list_servers`
253
- - safe `remote_exec`
254
- - `remote_write_file` approval behavior
255
-
256
- with at least one real SSH target, including the disposable Docker SSH path already used for manual smoke testing.
257
-
258
- ## Risks
259
-
260
- - Plain-text passwords are intentionally weaker than the current encrypted model.
261
- - Users may accidentally commit workspace config files if ignore rules are not clear.
262
- - File path auth depends on the target machine having stable path layout and permissions.
263
-
264
- These are acceptable tradeoffs for the requested simplicity, but they must be documented directly.
265
-
266
- ## Implementation Note
267
-
268
- Task 4 removed `keytar` from package metadata and synchronized the README with the config-backed registry model. The runtime design above remains unchanged.
269
-
270
- ## Recommendation
271
-
272
- Implement this as a clean replacement of the current encrypted/keychain-backed registry path. Do not keep both systems active in parallel. The simpler model is easier to understand, easier to operate, and more likely to behave consistently across macOS, Linux, and Windows.