@mirrowel/opencode-openshare 0.2.0 → 0.3.0-dev.1

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/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
  The opencode side of [Open(code)Share](../README.md) — session sharing for
4
4
  OpenCode v1 and v2, self-hosted on your own worker.
5
5
 
6
+ Every plugin config key, its file chain, and the cross-package config surface are inventoried in [../CONFIGURATION.md](../CONFIGURATION.md).
7
+
6
8
  ## Artifacts
7
9
 
8
10
  | Artifact | What it is | Share mode |
@@ -12,8 +14,9 @@ OpenCode v1 and v2, self-hosted on your own worker.
12
14
  | `ci/openshare.js` | single-file, zero-dependency bundle of the same engine (committed; rebuilt by `npm run build`) | all-mode **by default** — it declares no TUI entry, but an explicit `shareMode` in config/env still wins |
13
15
 
14
16
  All three are behavior-identical where they overlap — `npm run
15
- test:regression` proves the single file and the package match the frozen
16
- original (`reference/openshare.legacy.js`) on the full share lifecycle.
17
+ test:regression` drives the single file and the package entry through
18
+ the same real lifecycle (a local worker, a mock provider, a real
19
+ `opencode serve`) and diffs the resulting share data.
17
20
 
18
21
  ## Install
19
22
 
@@ -59,12 +62,26 @@ spec `"file:///…/openshare/share-plugin"` in both config files (run
59
62
  no build at all: [`ci/openshare.js`](ci/README.md), committed ready to
60
63
  use.
61
64
 
62
- **With no token the plugin enrolls itself** on first contact: public
63
- servers (hoster set `AUTH_MODE=public`) take anyone; private ones need
64
- a `code` from the hoster (activation-budgeted invite). The enrolled
65
- token persists to `~/.config/opencode/openshare.config.json` — enroll
66
- once per server, then it just works. A revoked token re-enrolls the
67
- same way (public/code available); if enrollment is impossible the
65
+ **Server-held config sets**: set `configSet` (or
66
+ `OPENSHARE_CONFIG_SET`) to pick a named set provisioned on your server
67
+ token - the server applies its auth/TTL at create (nothing sensitive in
68
+ the repo), and suggests modelLabel/shareMode which the plugin adopts once
69
+ per boot when you haven't set them locally.
70
+
71
+ **Identity is never assumed**: with no token configured the plugin does
72
+ NOT silently enroll. A configured `code` IS expressed
73
+ intent — the engine enrolls with it headlessly (the CI shape). Without
74
+ one: public servers share **anonymously** (ownerless shares under the
75
+ server's global anonymous caps), private servers refuse with guidance.
76
+ Onboarding happens through the ask-once TUI flow — `/share` first run
77
+ or `/openshare` → Servers → Connect to a server offers "Onboard (get an
78
+ account)" vs "Stay anonymous" (with the differences explained), detects
79
+ whether a code is needed, and only then prompts for one; the outcome is
80
+ remembered per server (token = onboarded, `anonymous` flag = declined,
81
+ onboard later via the server menu's Enroll now). The enrolled token
82
+ persists to `~/.config/opencode/openshare.config.json` — enroll once per
83
+ server, then it just works. A revoked token re-enrolls the same way
84
+ (code configured / codeless server); if enrollment is impossible the
68
85
  plugin says so on stderr and stops — no retry storms.
69
86
 
70
87
  ## Share modes
@@ -78,7 +95,7 @@ No selfwiring: which parts you install IS the switch.
78
95
 
79
96
  Manual mode stores the opt-in in session metadata:
80
97
  `metadata.openshare = { v: 2, enabled: true, opts? }` with per-session
81
- overrides (`ttlDays`, `authLogin`, `authPassword`, `modelLabel`). The
98
+ overrides (`ttlHours`, `authLogin`, `authPassword`, `modelLabel`). The
82
99
  per-server binding map (`servers: {url: {id, secret, rev, url}}`) is
83
100
  written next to it — legacy flat bindings migrate at read. The key is
84
101
  stripped from everything synced and never reaches viewers.
@@ -87,6 +104,19 @@ On OpenCode v2: the package declaring its `tui` entrypoint is the presence
87
104
  signal (the v2 host auto-loads it); the single file declares none and
88
105
  stays all-mode.
89
106
 
107
+ ## Trust controls (config)
108
+
109
+ Client-side redaction runs at the engine's single enqueue choke point
110
+ (backfill and live events both), so stripped secrets never reach a
111
+ queue, spool or wire:
112
+
113
+ - `redact.patterns` — extra regexes (strings) redacted beside the built-in
114
+ detectors on UNGATED shares only (a gated share is already
115
+ login-private): GitHub/AWS/Slack/Google key shapes, `sk-` keys, Bearer
116
+ tokens, PEM private-key blocks, `.env`-shaped assignments and
117
+ connection-string passwords, replaced with `[redacted:<kind>]`. The
118
+ consent dialog previews counts and the first hits.
119
+
90
120
  ## TUI
91
121
 
92
122
  - `/share` — share the session (explicit consent on EVERY creation —
@@ -94,12 +124,13 @@ stays all-mode.
94
124
  session, shares the whole family. Already shared → the session menu,
95
125
  identical to `/openshare → This session`: copy links (per server, or
96
126
  all), stop sharing — delete or leave a snapshot, per-server stop on
97
- multi-server shares —, share to another server, session TTL and read
127
+ multi-server shares —, share to another server, session TTL, read
98
128
  auth. A credential conflict opens the collision dialog (copy debug
99
129
  info / share on a new share / don't share).
100
130
  - `/openshare` — grouped settings (compact root with live summaries →
101
131
  focused submenus): This session (share/stop — delete or leave a
102
- snapshot —, TTL override, session read auth), **Servers** (connection
132
+ snapshot —, TTL override, session read auth),
133
+ **Servers** (connection
103
134
  AND membership: legacy pair, connect, enroll, rotate, get-a-user-token
104
135
  for root holders, disconnect, per-server **admin panel** — users,
105
136
  tokens, codes, shares, purge —, test, remove), Sharing (share mode +
@@ -124,7 +155,7 @@ stays all-mode.
124
155
  npm install
125
156
  npm run build # tsc -> dist/ + bun bundle -> ci/openshare.js (Bun on PATH)
126
157
  npm run typecheck
127
- npm run test # full matrix via the parallel driver (~4.5 min)
158
+ npm run test # full matrix via the parallel driver (~2.5 min)
128
159
  npm run test:quick # everyday gate (~90s): parity + manual core + TUI + v2 + auth
129
160
  ```
130
161
 
@@ -133,20 +164,11 @@ watchdogged, port-swept, and drives real `opencode serve` instances with
133
164
  a mock OpenAI-compatible provider — except where noted). The canonical
134
165
  suite table — what each covers, including the big/backends scale suites —
135
166
  lives in [`../DEVELOPMENT.md`](../DEVELOPMENT.md#test-suites); the
136
- commands:
137
-
138
- - `test:regression` — parity of legacy / single-file / package across the
139
- full lifecycle.
140
- - `test:manual` — the engine scenarios (dormancy, backfill, tombstones,
141
- timers, turn sockets, all-mode gating).
142
- - `test:tui-flow` — share/manager flows, config write targets, enrollment,
143
- admin console, gone detection.
144
- - `test:v2` — the v2 adapter against a scripted mock v2 host.
145
- - `test:auth` / `test:server-auth` — the identity contract (52 checks)
146
- against the Cloudflare worker and the Bun backend.
147
- - `test:enroll` / `test:server-enroll`, `test:fanout`, `test:big` /
148
- `test:server-big` — enrollment lifecycle, multi-server fan-out,
149
- big-session scale (both backends).
167
+ everyday commands:
168
+
169
+ - `test:quick` — the everyday gate: parity + manual core + TUI + v2 + auth.
170
+ - `test:auth` / `test:server-auth` — the identity contract against the
171
+ Cloudflare worker and the Bun backend.
150
172
  - `test:cli`, `node scripts/npm-e2e.mjs` — real `opencode run` / the
151
173
  published npm package — on demand only.
152
174
 
package/ci/README.md CHANGED
@@ -31,10 +31,22 @@ README's [Configuration](../../README.md#configuration)):
31
31
 
32
32
  ```
33
33
  OPENSHARE_WORKER_URL=https://your-host
34
- OPENSHARE_CREATE_TOKEN=… # legacy: root token
34
+ OPENSHARE_CREATE_TOKEN=: # legacy: root token
35
35
  OPENSHARE_URL_FILE=share-urls.txt # each share URL appended + stderr line
36
36
  ```
37
37
 
38
+ CI conveniences:
39
+
40
+ - `OPENSHARE_CONFIG_JSON` - the whole config as one env var (same keys as
41
+ the config file), when mounting a file is awkward. A specific
42
+ `OPENSHARE_*` var still wins over it.
43
+ - `OPENSHARE_URL_FILE_FORMAT=json` - urlFile lines become
44
+ `{"id":"…","url":"…","status":"…","gated":false}` objects, one per
45
+ line, so workflow steps read fields instead of parsing URLs.
46
+ - `meta` in the config stamps free-form labels (env-interpolated, e.g.
47
+ `"branch": "${GITHUB_REF_NAME}"`) onto every share - visible in the
48
+ server's admin shares listing.
49
+
38
50
  ```jsonc
39
51
  // openshare.config.json — enrollment shape (no root token needed)
40
52
  {
@@ -44,14 +56,29 @@ OPENSHARE_URL_FILE=share-urls.txt # each share URL appended + stderr line
44
56
  }
45
57
  ```
46
58
 
47
- With no token held, the bundle **enrolls itself** on first contact
48
- (public servers take anyone; private ones consume the one-time code) and
49
- persists the token to `~/.config/opencode/openshare.config.json` —
50
- enroll once, then every run just shares. A revoked token re-enrolls the
51
- same way; if enrollment is impossible the error lands on stderr and
52
- sharing stops (no retry storms). The bundle also supports **fan-out**:
53
- multiple `active` servers in the `servers` group each get the session
54
- (one urlFile line per server).
59
+ With no token held the bundle never silently enrolls: a configured
60
+ `code` enrolls with it headlessly (the CI shape — each code use is one
61
+ enrollment); without one, public servers share anonymously (ownerless
62
+ shares under the server's global anonymous caps) and private servers
63
+ refuse with guidance. When enrollment does run, the token persists to
64
+ `~/.config/opencode/openshare.config.json` — enroll once, then every
65
+ run just shares. A revoked token re-enrolls the same way (code
66
+ configured / codeless server); if enrollment is impossible the error
67
+ lands on stderr and sharing stops (no retry storms).
68
+
69
+ **Ephemeral runners** (GitHub-hosted, containers): do NOT enroll through
70
+ a code - each fresh machine would burn one activation. Ask the hoster
71
+ for a pre-registered token and pass it via `OPENSHARE_CREATE_TOKEN`
72
+ (or the config's token field); registered tokens skip enrollment
73
+ entirely and never expire on their own. A **scoped** token
74
+ (`POST /api/token {"kind":"scoped"}`, minted by any full token) is the
75
+ right credential here: it creates within its limits, reaches only the
76
+ shares it created, and revoking it never freezes the owner's account.
77
+ Point `OPENCODE_CONFIG_DIR` (or mount) the settings home at a cached
78
+ path only if you want the token persisted; env alone is enough.
79
+
80
+ The bundle also supports **fan-out**: multiple `active` servers in the
81
+ `servers` group each get the session (one urlFile line per server).
55
82
 
56
83
  On OpenCode v2, plugin targets should be directories/packages — wrap this
57
84
  file in a folder with a `package.json` exporting it (`{"exports": {".": "./openshare.js"}}`)