@bjorntech/key-ferry 0.0.0-stage → 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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +209 -2
  3. package/SECURITY.md +87 -0
  4. package/dist/contracts.d.ts +133 -0
  5. package/dist/contracts.d.ts.map +1 -0
  6. package/dist/contracts.js +29 -0
  7. package/dist/contracts.js.map +1 -0
  8. package/dist/index.d.ts +7 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +12 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/options.d.ts +44 -0
  13. package/dist/options.d.ts.map +1 -0
  14. package/dist/options.js +260 -0
  15. package/dist/options.js.map +1 -0
  16. package/dist/plugin.d.ts +24 -0
  17. package/dist/plugin.d.ts.map +1 -0
  18. package/dist/plugin.js +215 -0
  19. package/dist/plugin.js.map +1 -0
  20. package/dist/relay/index.d.ts +37 -0
  21. package/dist/relay/index.d.ts.map +1 -0
  22. package/dist/relay/index.js +480 -0
  23. package/dist/relay/index.js.map +1 -0
  24. package/dist/remote.d.ts +62 -0
  25. package/dist/remote.d.ts.map +1 -0
  26. package/dist/remote.js +227 -0
  27. package/dist/remote.js.map +1 -0
  28. package/dist/rpc.d.ts +112 -0
  29. package/dist/rpc.d.ts.map +1 -0
  30. package/dist/rpc.js +117 -0
  31. package/dist/rpc.js.map +1 -0
  32. package/dist/services/process.d.ts +56 -0
  33. package/dist/services/process.d.ts.map +1 -0
  34. package/dist/services/process.js +208 -0
  35. package/dist/services/process.js.map +1 -0
  36. package/dist/tui.d.ts +59 -0
  37. package/dist/tui.d.ts.map +1 -0
  38. package/dist/tui.js +93 -0
  39. package/dist/tui.js.map +1 -0
  40. package/dist/varlock/manager.d.ts +6 -0
  41. package/dist/varlock/manager.d.ts.map +1 -0
  42. package/dist/varlock/manager.js +425 -0
  43. package/dist/varlock/manager.js.map +1 -0
  44. package/dist/varlock/protocol.d.ts +67 -0
  45. package/dist/varlock/protocol.d.ts.map +1 -0
  46. package/dist/varlock/protocol.js +248 -0
  47. package/dist/varlock/protocol.js.map +1 -0
  48. package/docs/architecture.md +179 -0
  49. package/docs/quality.md +102 -0
  50. package/docs/releasing.md +149 -0
  51. package/docs/troubleshooting.md +214 -0
  52. package/examples/.env.schema +17 -0
  53. package/examples/opencode.jsonc +44 -0
  54. package/package.json +96 -4
@@ -0,0 +1,149 @@
1
+ # Release checklist
2
+
3
+ This is a maintainer runbook. Nothing in this document performs a release,
4
+ changes repository settings, creates a tag, pushes code, or publishes to npm.
5
+ Do not put npm credentials or long-lived publish tokens in the repository or in
6
+ chat.
7
+
8
+ ## One-time account and repository setup
9
+
10
+ Complete these steps interactively, using an account that owns the
11
+ `@bjorntech` scope and has publish permission. Verify the scope ownership,
12
+ account/org access, and 2FA before continuing.
13
+
14
+ 1. Decide whether the repository should be public. npm provenance for this
15
+ package requires the public repository/package policy used by this project;
16
+ in GitHub, use **Settings → General → Danger Zone → Change visibility** and
17
+ make the repository public if that is the approved decision. This is a
18
+ manual decision, not an automated release step.
19
+ 2. Create the GitHub environment named exactly `production`. Configure its
20
+ required reviewers (do not enable self-review if that would defeat the
21
+ approval policy), and restrict deployments to the approved stable version
22
+ tag pattern (`v*`). Protect tag creation and `main` with the repository's
23
+ normal branch/ruleset policy.
24
+ 3. Push the release workflow and its supporting release scripts to `main`
25
+ before configuring npm Trusted Publishing. The fixed workflow filename is
26
+ `.github/workflows/publish.yml`.
27
+ 4. Bootstrap the package if it does not yet exist on npm. For the initial
28
+ `0.1.0` release, run the normal quality/build gates below, then use one
29
+ interactive browser/2FA login and publish from the repository:
30
+
31
+ ```sh
32
+ npm login
33
+ npm publish --access public
34
+ ```
35
+
36
+ Do not add `--provenance` to this local bootstrap publish. This initial
37
+ publication does not validate OIDC, and `0.1.0` must not be tagged and
38
+ published again after it already exists.
39
+ 5. Shortly before the next genuine release, configure npm Trusted Publishing
40
+ for the package at **Package settings → Trusted Publisher** with:
41
+ - provider: **GitHub Actions**
42
+ - organization/owner: `bjorntech`
43
+ - repository: `key-ferry`
44
+ - workflow filename: `publish.yml`
45
+ - environment: `production`
46
+
47
+ Use npm's current UI field names if they differ. A newly created,
48
+ unvalidated configuration expires after 48 hours without a successful
49
+ publish, so do not create a fake release merely to test it. Configure it
50
+ for the next real version (for example, `0.1.4`) after the bootstrap
51
+ package exists. See [npm Trusted Publishers](https://docs.npmjs.com/trusted-publishers/)
52
+ and the [npm trust command reference](https://docs.npmjs.com/cli/v12/commands/npm-trust).
53
+ 6. After the first successful OIDC release, consider enabling npm's **Require
54
+ two-factor authentication** and **Disallow tokens** package controls, and
55
+ lock down classic publishing as allowed by the account policy. Trusted
56
+ publishing uses the GitHub OIDC exchange; it does not require an
57
+ `NPM_TOKEN`, `NODE_AUTH_TOKEN`, or another repository secret.
58
+
59
+ ## Quality gates
60
+
61
+ From the repository root, run the normal gates before committing a release:
62
+
63
+ ```sh
64
+ bun install --frozen-lockfile
65
+ bun run format:check
66
+ bun typecheck
67
+ bun test
68
+ bun run test:coverage
69
+ bun run test:crap
70
+ bun run build
71
+ bun pm pack --dry-run
72
+ ```
73
+
74
+ The coverage gate requires aggregate runtime-source coverage of at least 90%
75
+ for lines and 75% for functions. The CRAP gate requires new or changed
76
+ functions to score at most 6; unchanged legacy violations warn, while
77
+ regressions against the committed baseline fail. Review the reports rather
78
+ than hard-coding their current counts.
79
+
80
+ Run the two opt-in Varlock fixtures separately with a configured CLI path and
81
+ synthetic isolated fixtures:
82
+
83
+ ```sh
84
+ VARLOCK_LIVE_BINARY=/absolute/path/to/varlock bun test tests/varlock-live.test.ts
85
+ VARLOCK_LIVE_BINARY=/absolute/path/to/varlock bun test tests/remote-varlock-live.test.ts
86
+ ```
87
+
88
+ These fixtures do not substitute for production deployment or compatibility
89
+ testing with every external MCP service.
90
+
91
+ ## Release and tag flow
92
+
93
+ 1. Review the package version, changelog, exports, generated package contents,
94
+ public-scope permissions, repository visibility, and the complete release
95
+ diff. Set a new, genuine semver version; never retry a version that npm has
96
+ already accepted. Update the lockfile consistently and rerun all gates.
97
+ 2. Commit the reviewed source and workflow changes, push the selected branch,
98
+ and wait for the commit to be available on `main`.
99
+ 3. Create and push the matching stable tag only after explicit approval:
100
+
101
+ ```sh
102
+ git tag vX.Y.Z
103
+ git push origin vX.Y.Z
104
+ ```
105
+
106
+ The tag must point at the reviewed release commit and its version must
107
+ match `package.json` exactly. Stable tags are the only automatic publish
108
+ trigger; the workflow does not publish from `main`.
109
+ 4. `.github/workflows/publish.yml` runs on GitHub-hosted Ubuntu with the
110
+ pinned Node 24.22/npm 12.2/Bun 1.4.2 toolchain and verified action SHA
111
+ pins. Its unprivileged `verify` job has contents-read permission, runs the
112
+ quality/build checks, and creates the tarball artifact. The privileged
113
+ `publish` job has contents-read and `id-token: write`, waits for the
114
+ `production` environment approval, and publishes **exactly the verified
115
+ tarball** with `--access public --provenance --ignore-scripts`.
116
+
117
+ The quality/build job is the gate: the publish job must not re-execute
118
+ source or dependency installation in a privileged context. The
119
+ `--ignore-scripts` flag is intentional for the final artifact publication,
120
+ not a way to bypass the quality gates.
121
+ 5. For a manually started run, select an existing stable tag as the workflow
122
+ ref. For example:
123
+
124
+ ```sh
125
+ gh workflow run publish.yml --ref vX.Y.Z
126
+ ```
127
+
128
+ Do not dispatch from `main` or use an arbitrary branch. At the environment
129
+ approval, inspect the tag, commit, tarball, and checksum before approving.
130
+ After publication, verify the exact registry version, provenance, public
131
+ access, clean installation, and the documented OpenCode V2 plugin/TUI
132
+ discovery path.
133
+
134
+ ## Troubleshooting
135
+
136
+ - **Package not found (404):** complete the one-time interactive bootstrap;
137
+ Trusted Publishing cannot create the first package.
138
+ - **OIDC token missing:** check that the publish job has exactly the runtime
139
+ `id-token: write` permission and that the environment name is exactly
140
+ `production`.
141
+ - **Provenance or repository failure:** verify the package is public, the
142
+ Trusted Publisher fields match `bjorntech/key-ferry` and `publish.yml`, and
143
+ the run is from a stable tag.
144
+ - **Configuration expired:** recreate it shortly before the next genuine
145
+ release; do not manufacture an empty or fake release.
146
+ - **Version already exists:** check the registry first, then increment to a
147
+ new genuine version. Do not blindly retry or attempt to overwrite it.
148
+ - **Quality failure:** fix the source and rerun the gates. Do not use
149
+ `--ignore-scripts` indiscriminately or bypass the verification job.
@@ -0,0 +1,214 @@
1
+ # Troubleshooting
2
+
3
+ This integration is a native OpenCode V2 Effect plugin. It manages an owned,
4
+ project-scoped Varlock CLI proxy process. Start OpenCode normally from the
5
+ project directory. Do not wrap OpenCode with `varlock proxy`.
6
+
7
+ ## Before starting
8
+
9
+ Install Varlock CLI **1.23.0** separately and make sure `varlock` is on `PATH`:
10
+
11
+ ```sh
12
+ varlock --version
13
+ varlock proxy --help
14
+ ```
15
+
16
+ The plugin does not install Varlock, unlock secret stores, or read credentials
17
+ for diagnostics. It expects a valid `.env.schema` in the configured project.
18
+ Configure the Varlock environment, secret source, authentication, and proxy
19
+ rules before starting OpenCode, following the [Varlock documentation](https://varlock.dev/).
20
+
21
+ The integration protects explicitly mapped local MCP servers and selected
22
+ remote API-key MCP servers. Direct provider transports are not isolated.
23
+ Remote servers not selected by this plugin, including OAuth-only servers, keep
24
+ native OpenCode OAuth and transport behavior.
25
+
26
+ ## Plugin does not load
27
+
28
+ Add `@bjorntech/key-ferry@0.1.4` to the OpenCode V2 `plugins` list and preserve
29
+ unrelated configuration. OpenCode installs configured npm plugins
30
+ automatically. Install Varlock separately, preferably with
31
+ `brew install dmno-dev/tap/varlock`.
32
+
33
+ Configure the server plugin from `opencode.json(c)`. OpenCode V2 discovers the
34
+ package's sibling `./tui` export automatically, so a duplicate global
35
+ `cli.json` entry is not needed. A global `cli.json` entry is optional only when
36
+ the CLI connects to a remote OpenCode server that already loaded the server
37
+ plugin, or for a genuinely CLI-only deployment. There is no project-local
38
+ `cli.json` setup.
39
+
40
+ The plugin requires OpenCode V2's native Effect entrypoint, compatible with
41
+ `@opencode/plugin` 2.0.30 and Effect 4.0.1. Do not load it through the Promise
42
+ entrypoint. The package declares Node >=22; Bun 1.4.2 is used by this project
43
+ for development and CI.
44
+
45
+ If OpenCode reports a plugin import or entrypoint error, check the built
46
+ package exports and restart the OpenCode service after rebuilding.
47
+
48
+ Relative `projectDirectory` values are resolved against OpenCode's project
49
+ directory and canonicalized before the sidecar starts. The resulting canonical
50
+ directory is used for Varlock ownership matching and safe status output.
51
+
52
+ ## MCP server is disabled
53
+
54
+ The plugin changes only names listed in `options.servers`. Each mapping is
55
+ output environment name to an exact Varlock placeholder name. An array is a
56
+ same-name mapping:
57
+
58
+ ```jsonc
59
+ "servers": {
60
+ "example-local-mcp": {
61
+ "env": ["FAKE_API_KEY"]
62
+ }
63
+ }
64
+ ```
65
+
66
+ An object supports an explicit mapping:
67
+
68
+ ```jsonc
69
+ "servers": {
70
+ "example-local-mcp": {
71
+ "env": { "UPSTREAM_KEY": "FAKE_API_KEY" }
72
+ }
73
+ }
74
+ ```
75
+
76
+ The MCP server must already exist in `mcp.servers` and must be `type: "local"`.
77
+ Remote or missing servers are not silently routed. Replace the illustrative
78
+ command in `examples/opencode.jsonc` with a real local MCP command before
79
+ launching it; the example command is not an installed fixture.
80
+
81
+ The server remains disabled when the sidecar is not ready, startup or refresh
82
+ fails, a mapped placeholder is absent, or the project explicitly disabled the
83
+ server. This is fail-closed behavior. A later successful refresh can restore a
84
+ server that the plugin disabled, but never one explicitly disabled in project
85
+ configuration.
86
+
87
+ ## Remote MCP server is disabled
88
+
89
+ Select a remote server with a `remote.headers` mapping only when the native
90
+ MCP configuration explicitly uses `oauth: false`:
91
+
92
+ ```jsonc
93
+ {
94
+ "type": "remote",
95
+ "url": "https://mcp.example.test/mcp",
96
+ "oauth": false
97
+ }
98
+ ```
99
+
100
+ The plugin then creates an authenticated loopback relay. Header mappings refer
101
+ to exact Varlock environment names, not raw values:
102
+
103
+ ```jsonc
104
+ "remote-tools": {
105
+ "remote": {
106
+ "headers": {
107
+ "Authorization": { "env": "REMOTE_API_KEY", "prefix": "Bearer " },
108
+ "X-Tenant": "REMOTE_TENANT"
109
+ }
110
+ }
111
+ }
112
+ ```
113
+
114
+ If `oauth` is omitted or is an OAuth object, the selected server is disabled
115
+ with a safe diagnostic. Remove the mapping to preserve native OAuth, or
116
+ explicitly choose API-key mode with `oauth: false`. The plugin never silently
117
+ disables OAuth or falls back to the direct remote URL.
118
+
119
+ The remote URL must be HTTPS without URL credentials or a fragment. Literal
120
+ loopback, private, link-local, and metadata IP targets are rejected unless
121
+ `allowPrivateNetwork: true` is explicitly configured. Corporate DNS names are
122
+ allowed. The relay target is fixed from the configured server and cannot be
123
+ chosen by a downstream MCP request.
124
+
125
+ The relay supports Streamable HTTP and legacy SSE, including streaming,
126
+ session headers, DELETE termination, cancellation, and same-origin legacy SSE
127
+ endpoint rewriting. It caps registered session routes at 256, rejects new
128
+ routes after the cap, and does not count duplicate registrations. A Varlock
129
+ refresh or relay replacement resets native MCP sessions. Existing sessions
130
+ must reconnect.
131
+
132
+ Verification status: the synthetic HTTPS remote Varlock test passes. This
133
+ does not claim compatibility with every external MCP provider or a live
134
+ OpenCode TUI session.
135
+
136
+ ## Strict egress or schema errors
137
+
138
+ With `requireStrictEgress: true`, the manager requires the Varlock schema to
139
+ use strict egress. The schema header syntax is:
140
+
141
+ ```env-spec
142
+ # @proxyConfig={egress="strict"}
143
+ # ---
144
+ ```
145
+
146
+ Route a protected item with an item decorator, for example:
147
+
148
+ ```env-spec
149
+ # @proxy(domain="api.example.test")
150
+ FAKE_API_KEY=sk-test-000000000000000000000000
151
+ ```
152
+
153
+ `@proxy(domain=...)` on an item creates the injection rule. A header-level
154
+ proxy rule alone does not inject an item. Do not use a real key in examples or
155
+ diagnostics.
156
+
157
+ The plugin's protocol accepts only exact placeholder matches. `@proxy=passthrough`
158
+ values are allowed by Varlock for child environments, but they are not a
159
+ wildcard source for this integration and cannot satisfy an unrelated mapping.
160
+
161
+ ## Proxy-aware SDK behavior
162
+
163
+ An explicitly mapped local MCP process receives proxy-related environment
164
+ wiring only when the proxy is ready. A local client that ignores or overwrites
165
+ those variables can bypass the intended route.
166
+
167
+ An explicitly mapped remote MCP server uses the authenticated relay instead of
168
+ native direct transport. The relay sends placeholder-bearing headers through
169
+ Varlock's HTTP CONNECT proxy to the fixed HTTPS target, so remote routing does
170
+ not depend on the MCP client honoring environment proxy variables. CA MITM
171
+ support and response scrubbing still have limitations. This integration is not
172
+ a sandbox and cannot isolate a same-user process from stores, files, or daemons.
173
+
174
+ ## Refresh, status, and doctor
175
+
176
+ The server plugin exposes the `key-ferry` RPC with `status`, `refresh`,
177
+ and `doctor` methods. These return sanitized phase, project, generation, PID,
178
+ endpoint metadata, safe configuration diagnostics, and safe error codes. They
179
+ do not return environment maps, relay capabilities or tokens, CA material, or
180
+ secret values.
181
+
182
+ If refresh fails, protected servers are disabled and the failure is reported
183
+ as a sanitized `unavailable` RPC error. Doctor first ensures Varlock state and
184
+ then reconciles or recreates unhealthy selected `oauth:false` remote relays;
185
+ it does not silently authenticate or replace native OAuth. Check the Varlock
186
+ schema and configured authentication context, then use `/key-ferry-refresh` or
187
+ `/key-ferry-doctor`, or the matching Varlock palette commands, when the TUI is
188
+ available. Do not manually stop unrelated Varlock processes: only the process
189
+ owned by this project manager is eligible for cleanup.
190
+
191
+ ## Verify the installation
192
+
193
+ These commands do not contact a real service or require credentials:
194
+
195
+ ```sh
196
+ bun typecheck
197
+ bun test
198
+ bun run build
199
+ ```
200
+
201
+ An opt-in live test is available with `VARLOCK_LIVE_BINARY` set to an absolute
202
+ Varlock CLI path. It uses a synthetic fixture and isolated XDG configuration.
203
+ Do not enable real secret-manager, OAuth, or network tests in CI.
204
+
205
+ The remote live fixture is gated and skipped by default:
206
+
207
+ ```sh
208
+ VARLOCK_LIVE_BINARY=/absolute/path/to/varlock bun test tests/remote-varlock-live.test.ts
209
+ ```
210
+
211
+ That command is a gated synthetic compatibility check. The normal suite and
212
+ live fixtures are separate verification layers; these commands do not certify
213
+ production deployments, every external MCP provider, or a fully live OpenCode
214
+ host/TUI session.
@@ -0,0 +1,17 @@
1
+ # Synthetic example only. Do not put a real credential in this file.
2
+ # Strict egress blocks requests that do not match an explicit proxy rule.
3
+ # @proxyConfig={egress="strict"}
4
+ # ---
5
+ # @proxy(domain="api.example.test")
6
+ # @placeholder=sk-test-000000000000000000000000
7
+ FAKE_API_KEY=sk-test-000000000000000000000000
8
+
9
+ # Synthetic remote MCP API-key example. The value is deliberately fake.
10
+ # @proxy(domain="mcp.example.test")
11
+ # @placeholder=sk-remote-test-000000000000000000000
12
+ REMOTE_API_KEY=sk-remote-test-000000000000000000000
13
+
14
+ # This is also synthetic and is mapped as a header placeholder in the example.
15
+ # @proxy(domain="mcp.example.test")
16
+ # @placeholder=tenant-test-placeholder
17
+ REMOTE_TENANT=tenant-test-placeholder
@@ -0,0 +1,44 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "plugins": [
4
+ {
5
+ // Merge this entry into your existing config; preserve unrelated
6
+ // plugins and MCP servers.
7
+ "package": "@bjorntech/key-ferry@0.1.4",
8
+ "options": {
9
+ "enabled": true,
10
+ "projectDirectory": ".",
11
+ "command": ["varlock"],
12
+ "startupTimeoutMs": 30000,
13
+ "reloadTimeoutMs": 30000,
14
+ "requireStrictEgress": true,
15
+ "servers": {
16
+ "example-local-mcp": {
17
+ "env": ["FAKE_API_KEY"],
18
+ },
19
+ "example-remote-mcp": {
20
+ "remote": {
21
+ "headers": {
22
+ "Authorization": { "env": "REMOTE_API_KEY", "prefix": "Bearer " },
23
+ "X-Tenant": "REMOTE_TENANT",
24
+ },
25
+ },
26
+ },
27
+ },
28
+ },
29
+ },
30
+ ],
31
+ "mcp": {
32
+ "servers": {
33
+ "example-local-mcp": {
34
+ "type": "local",
35
+ "command": ["node", "./path/to/your-mcp-server.mjs"],
36
+ },
37
+ "example-remote-mcp": {
38
+ "type": "remote",
39
+ "url": "https://mcp.example.test/mcp",
40
+ "oauth": false,
41
+ },
42
+ },
43
+ },
44
+ }
package/package.json CHANGED
@@ -1,6 +1,98 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/package.json",
2
3
  "name": "@bjorntech/key-ferry",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
4
+ "version": "0.1.4",
5
+ "description": "Project-scoped Key Ferry integration for OpenCode V2",
6
+ "keywords": [],
7
+ "homepage": "https://github.com/bjorntech/key-ferry#readme",
8
+ "bugs": {
9
+ "url": "https://github.com/bjorntech/key-ferry/issues"
10
+ },
11
+ "license": "MIT",
12
+ "author": "",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/bjorntech/key-ferry.git"
16
+ },
17
+ "directories": {
18
+ "doc": "docs",
19
+ "example": "examples",
20
+ "test": "tests"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md",
25
+ "LICENSE",
26
+ "SECURITY.md",
27
+ "docs",
28
+ "examples"
29
+ ],
30
+ "type": "module",
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js"
37
+ },
38
+ "./contracts": {
39
+ "types": "./dist/contracts.d.ts",
40
+ "import": "./dist/contracts.js"
41
+ },
42
+ "./plugin": {
43
+ "types": "./dist/plugin.d.ts",
44
+ "import": "./dist/plugin.js"
45
+ },
46
+ "./options": {
47
+ "types": "./dist/options.d.ts",
48
+ "import": "./dist/options.js"
49
+ },
50
+ "./rpc": {
51
+ "types": "./dist/rpc.d.ts",
52
+ "import": "./dist/rpc.js"
53
+ },
54
+ "./tui": {
55
+ "types": "./dist/tui.d.ts",
56
+ "import": "./dist/tui.js"
57
+ },
58
+ "./relay": {
59
+ "types": "./dist/relay/index.d.ts",
60
+ "import": "./dist/relay/index.js"
61
+ }
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "scripts": {
67
+ "build": "tsc -p tsconfig.build.json",
68
+ "typecheck": "tsc --noEmit",
69
+ "test": "bun test",
70
+ "test:coverage": "bun test --coverage && bun scripts/check-coverage.ts",
71
+ "test:crap": "bun scripts/crap/run.ts",
72
+ "format": "oxfmt",
73
+ "format:check": "oxfmt --check",
74
+ "quality": "npm run format:check && npm run typecheck && npm run test:coverage && npm run test:crap",
75
+ "prepack": "npm run build",
76
+ "prepublishOnly": "npm run quality && npm run build"
77
+ },
78
+ "devDependencies": {
79
+ "@opencode/plugin": "2.0.30",
80
+ "@types/istanbul-lib-coverage": "2.0.6",
81
+ "@types/istanbul-lib-instrument": "1.7.8",
82
+ "@types/node": "^24.0.0",
83
+ "effect": "4.0.1",
84
+ "istanbul-lib-coverage": "3.2.2",
85
+ "istanbul-lib-instrument": "6.0.3",
86
+ "oxfmt": "0.72.0",
87
+ "solid-js": "1.9.17",
88
+ "typescript": "^5.8.2"
89
+ },
90
+ "peerDependencies": {
91
+ "@opencode/plugin": "2.0.30",
92
+ "effect": "4.0.1",
93
+ "solid-js": ">=1.9.0"
94
+ },
95
+ "engines": {
96
+ "node": ">=22"
97
+ }
98
+ }