@mirrowel/opencode-openshare 0.2.1 → 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
@@ -14,8 +14,9 @@ Every plugin config key, its file chain, and the cross-package config surface ar
14
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 |
15
15
 
16
16
  All three are behavior-identical where they overlap — `npm run
17
- test:regression` proves the single file and the package match the frozen
18
- 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.
19
20
 
20
21
  ## Install
21
22
 
@@ -61,12 +62,26 @@ spec `"file:///…/openshare/share-plugin"` in both config files (run
61
62
  no build at all: [`ci/openshare.js`](ci/README.md), committed ready to
62
63
  use.
63
64
 
64
- **With no token the plugin enrolls itself** on first contact: public
65
- servers (hoster set `AUTH_MODE=public`) take anyone; private ones need
66
- a `code` from the hoster (activation-budgeted invite). The enrolled
67
- token persists to `~/.config/opencode/openshare.config.json` — enroll
68
- once per server, then it just works. A revoked token re-enrolls the
69
- 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
70
85
  plugin says so on stderr and stops — no retry storms.
71
86
 
72
87
  ## Share modes
@@ -80,7 +95,7 @@ No selfwiring: which parts you install IS the switch.
80
95
 
81
96
  Manual mode stores the opt-in in session metadata:
82
97
  `metadata.openshare = { v: 2, enabled: true, opts? }` with per-session
83
- overrides (`ttlDays`, `authLogin`, `authPassword`, `modelLabel`). The
98
+ overrides (`ttlHours`, `authLogin`, `authPassword`, `modelLabel`). The
84
99
  per-server binding map (`servers: {url: {id, secret, rev, url}}`) is
85
100
  written next to it — legacy flat bindings migrate at read. The key is
86
101
  stripped from everything synced and never reaches viewers.
@@ -89,6 +104,19 @@ On OpenCode v2: the package declaring its `tui` entrypoint is the presence
89
104
  signal (the v2 host auto-loads it); the single file declares none and
90
105
  stays all-mode.
91
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
+
92
120
  ## TUI
93
121
 
94
122
  - `/share` — share the session (explicit consent on EVERY creation —
@@ -96,12 +124,13 @@ stays all-mode.
96
124
  session, shares the whole family. Already shared → the session menu,
97
125
  identical to `/openshare → This session`: copy links (per server, or
98
126
  all), stop sharing — delete or leave a snapshot, per-server stop on
99
- multi-server shares —, share to another server, session TTL and read
127
+ multi-server shares —, share to another server, session TTL, read
100
128
  auth. A credential conflict opens the collision dialog (copy debug
101
129
  info / share on a new share / don't share).
102
130
  - `/openshare` — grouped settings (compact root with live summaries →
103
131
  focused submenus): This session (share/stop — delete or leave a
104
- snapshot —, TTL override, session read auth), **Servers** (connection
132
+ snapshot —, TTL override, session read auth),
133
+ **Servers** (connection
105
134
  AND membership: legacy pair, connect, enroll, rotate, get-a-user-token
106
135
  for root holders, disconnect, per-server **admin panel** — users,
107
136
  tokens, codes, shares, purge —, test, remove), Sharing (share mode +
@@ -126,7 +155,7 @@ stays all-mode.
126
155
  npm install
127
156
  npm run build # tsc -> dist/ + bun bundle -> ci/openshare.js (Bun on PATH)
128
157
  npm run typecheck
129
- 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)
130
159
  npm run test:quick # everyday gate (~90s): parity + manual core + TUI + v2 + auth
131
160
  ```
132
161
 
@@ -135,20 +164,11 @@ watchdogged, port-swept, and drives real `opencode serve` instances with
135
164
  a mock OpenAI-compatible provider — except where noted). The canonical
136
165
  suite table — what each covers, including the big/backends scale suites —
137
166
  lives in [`../DEVELOPMENT.md`](../DEVELOPMENT.md#test-suites); the
138
- commands:
139
-
140
- - `test:regression` — parity of legacy / single-file / package across the
141
- full lifecycle.
142
- - `test:manual` — the engine scenarios (dormancy, backfill, tombstones,
143
- timers, turn sockets, all-mode gating).
144
- - `test:tui-flow` — share/manager flows, config write targets, enrollment,
145
- admin console, gone detection.
146
- - `test:v2` — the v2 adapter against a scripted mock v2 host.
147
- - `test:auth` / `test:server-auth` — the identity contract (52 checks)
148
- against the Cloudflare worker and the Bun backend.
149
- - `test:enroll` / `test:server-enroll`, `test:fanout`, `test:big` /
150
- `test:server-big` — enrollment lifecycle, multi-server fan-out,
151
- 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.
152
172
  - `test:cli`, `node scripts/npm-e2e.mjs` — real `opencode run` / the
153
173
  published npm package — on demand only.
154
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,22 +56,26 @@ 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).
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).
53
68
 
54
69
  **Ephemeral runners** (GitHub-hosted, containers): do NOT enroll through
55
70
  a code - each fresh machine would burn one activation. Ask the hoster
56
- for a pre-minted registered token (`osk_…`) and pass it via
57
- `OPENSHARE_CREATE_TOKEN` (or the config's token field) - registered
58
- tokens skip enrollment entirely and never expire on their own. Point
59
- `OPENSHARE_CONFIG_DIR` (or mount) the settings home at a cached path
60
- only if you want the token persisted; env alone is enough. Note:
61
- revoking that token (when it is the user's last) freezes control of all
62
- its shares server-side, even ones holding the share secret.
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.
63
79
 
64
80
  The bundle also supports **fan-out**: multiple `active` servers in the
65
81
  `servers` group each get the session (one urlFile line per server).