@mirrowel/opencode-openshare 0.2.1 → 0.3.0-dev.10
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 +74 -28
- package/ci/README.md +30 -14
- package/ci/openshare.js +475 -61
- package/dist/binding-queue.js +2 -2
- package/dist/commands.js +8 -8
- package/dist/config.d.ts +37 -14
- package/dist/config.js +119 -33
- package/dist/contract.d.ts +5 -5
- package/dist/contract.js +5 -5
- package/dist/core.d.ts +12 -1
- package/dist/core.js +409 -138
- package/dist/dialogs.d.ts +9 -10
- package/dist/dialogs.js +25 -28
- package/dist/redact.d.ts +46 -0
- package/dist/redact.js +130 -0
- package/dist/settings.d.ts +10 -7
- package/dist/settings.js +138 -56
- package/dist/share-flow.d.ts +30 -6
- package/dist/share-flow.js +73 -18
- package/dist/tui.js +260 -60
- package/dist/ui-prefs.js +6 -6
- package/dist/v2-server.js +5 -6
- package/package.json +2 -4
- package/src/binding-queue.ts +2 -2
- package/src/commands.ts +8 -8
- package/src/config.ts +124 -31
- package/src/contract.ts +5 -5
- package/src/core.ts +384 -137
- package/src/dialogs.tsx +29 -32
- package/src/redact.ts +134 -0
- package/src/settings.ts +134 -54
- package/src/share-flow.ts +76 -20
- package/src/sidebar.tsx +7 -7
- package/src/tui.tsx +22 -24
- package/src/ui-prefs.ts +6 -6
- package/src/v2-server.ts +5 -6
package/README.md
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
# Open(code)Share plugin (`@mirrowel/opencode-openshare`)
|
|
2
2
|
|
|
3
|
-
The opencode side of [Open(code)Share](../README.md)
|
|
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
|
+
**This package is only the plugin.** It captures and uploads sessions, but a
|
|
7
|
+
share needs a backend to upload to. OpenShare ships as four parts that
|
|
8
|
+
version and release together:
|
|
9
|
+
|
|
10
|
+
| Part | What it does | Where to get it |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| **This plugin** | hooks into opencode, syncs sessions | this npm package |
|
|
13
|
+
| **Worker** | the Cloudflare backend - stores shares, serves the viewer | deploy from the repo: `share-worker/` (3-command setup, see the repo README) |
|
|
14
|
+
| **Server** | self-hosted alternative to the worker - one Bun process, SQLite, Docker image | repo `share-server/` |
|
|
15
|
+
| **Viewer** | the share page - ships inside the worker/server assets; nothing to install separately | repo `share-viewer/` (embedded automatically) |
|
|
16
|
+
|
|
17
|
+
The repo also builds **offline snapshots** - a single self-contained HTML
|
|
18
|
+
file of any share, generated by the viewer's download button or the
|
|
19
|
+
`osh-snapshot` CLI - so a shared link keeps working even with no backend at
|
|
20
|
+
all.
|
|
21
|
+
|
|
22
|
+
Everything lives in one repository: **https://github.com/Mirrowel/openshare**
|
|
23
|
+
(clone it, or browse the [README](https://github.com/Mirrowel/openshare#readme)
|
|
24
|
+
for the full picture - deployment, configuration, and the viewer tour).
|
|
25
|
+
|
|
6
26
|
Every plugin config key, its file chain, and the cross-package config surface are inventoried in [../CONFIGURATION.md](../CONFIGURATION.md).
|
|
7
27
|
|
|
8
28
|
## Artifacts
|
|
@@ -14,8 +34,9 @@ Every plugin config key, its file chain, and the cross-package config surface ar
|
|
|
14
34
|
| `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
35
|
|
|
16
36
|
All three are behavior-identical where they overlap — `npm run
|
|
17
|
-
test:regression`
|
|
18
|
-
|
|
37
|
+
test:regression` drives the single file and the package entry through
|
|
38
|
+
the same real lifecycle (a local worker, a mock provider, a real
|
|
39
|
+
`opencode serve`) and diffs the resulting share data.
|
|
19
40
|
|
|
20
41
|
## Install
|
|
21
42
|
|
|
@@ -36,7 +57,9 @@ itself):
|
|
|
36
57
|
opencode plugin add @mirrowel/opencode-openshare
|
|
37
58
|
```
|
|
38
59
|
|
|
39
|
-
Restart opencode; `/share` and `/openshare` appear in the TUI.
|
|
60
|
+
Restart opencode; `/share` and `/openshare` appear in the TUI. The
|
|
61
|
+
settings dialog's title carries the running plugin's version (read from
|
|
62
|
+
its own package manifest at runtime).
|
|
40
63
|
|
|
41
64
|
Then configure. For an npm install the durable config file is the
|
|
42
65
|
**settings home** (`~/.config/opencode/openshare.config.json` — also
|
|
@@ -61,12 +84,26 @@ spec `"file:///…/openshare/share-plugin"` in both config files (run
|
|
|
61
84
|
no build at all: [`ci/openshare.js`](ci/README.md), committed ready to
|
|
62
85
|
use.
|
|
63
86
|
|
|
64
|
-
**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
87
|
+
**Server-held config sets**: set `configSet` (or
|
|
88
|
+
`OPENSHARE_CONFIG_SET`) to pick a named set provisioned on your server
|
|
89
|
+
token - the server applies its auth/TTL at create (nothing sensitive in
|
|
90
|
+
the repo), and suggests modelLabel/shareMode which the plugin adopts once
|
|
91
|
+
per boot when you haven't set them locally.
|
|
92
|
+
|
|
93
|
+
**Identity is never assumed**: with no token configured the plugin does
|
|
94
|
+
NOT silently enroll. A configured `code` IS expressed
|
|
95
|
+
intent — the engine enrolls with it headlessly (the CI shape). Without
|
|
96
|
+
one: public servers share **anonymously** (ownerless shares under the
|
|
97
|
+
server's global anonymous caps), private servers refuse with guidance.
|
|
98
|
+
Onboarding happens through the ask-once TUI flow — `/share` first run
|
|
99
|
+
or `/openshare` → Servers → Connect to a server offers "Onboard (get an
|
|
100
|
+
account)" vs "Stay anonymous" (with the differences explained), detects
|
|
101
|
+
whether a code is needed, and only then prompts for one; the outcome is
|
|
102
|
+
remembered per server (token = onboarded, `anonymous` flag = declined,
|
|
103
|
+
onboard later via the server menu's Enroll now). The enrolled token
|
|
104
|
+
persists to `~/.config/opencode/openshare.config.json` — enroll once per
|
|
105
|
+
server, then it just works. A revoked token re-enrolls the same way
|
|
106
|
+
(code configured / codeless server); if enrollment is impossible the
|
|
70
107
|
plugin says so on stderr and stops — no retry storms.
|
|
71
108
|
|
|
72
109
|
## Share modes
|
|
@@ -80,7 +117,7 @@ No selfwiring: which parts you install IS the switch.
|
|
|
80
117
|
|
|
81
118
|
Manual mode stores the opt-in in session metadata:
|
|
82
119
|
`metadata.openshare = { v: 2, enabled: true, opts? }` with per-session
|
|
83
|
-
overrides (`
|
|
120
|
+
overrides (`ttlHours`, `authLogin`, `authPassword`, `modelLabel`). The
|
|
84
121
|
per-server binding map (`servers: {url: {id, secret, rev, url}}`) is
|
|
85
122
|
written next to it — legacy flat bindings migrate at read. The key is
|
|
86
123
|
stripped from everything synced and never reaches viewers.
|
|
@@ -89,6 +126,19 @@ On OpenCode v2: the package declaring its `tui` entrypoint is the presence
|
|
|
89
126
|
signal (the v2 host auto-loads it); the single file declares none and
|
|
90
127
|
stays all-mode.
|
|
91
128
|
|
|
129
|
+
## Trust controls (config)
|
|
130
|
+
|
|
131
|
+
Client-side redaction runs at the engine's single enqueue choke point
|
|
132
|
+
(backfill and live events both), so stripped secrets never reach a
|
|
133
|
+
queue, spool or wire:
|
|
134
|
+
|
|
135
|
+
- `redact.patterns` — extra regexes (strings) redacted beside the built-in
|
|
136
|
+
detectors on UNGATED shares only (a gated share is already
|
|
137
|
+
login-private): GitHub/AWS/Slack/Google key shapes, `sk-` keys, Bearer
|
|
138
|
+
tokens, PEM private-key blocks, `.env`-shaped assignments and
|
|
139
|
+
connection-string passwords, replaced with `[redacted:<kind>]`. The
|
|
140
|
+
consent dialog previews counts and the first hits.
|
|
141
|
+
|
|
92
142
|
## TUI
|
|
93
143
|
|
|
94
144
|
- `/share` — share the session (explicit consent on EVERY creation —
|
|
@@ -96,12 +146,13 @@ stays all-mode.
|
|
|
96
146
|
session, shares the whole family. Already shared → the session menu,
|
|
97
147
|
identical to `/openshare → This session`: copy links (per server, or
|
|
98
148
|
all), stop sharing — delete or leave a snapshot, per-server stop on
|
|
99
|
-
multi-server shares —, share to another server, session TTL
|
|
149
|
+
multi-server shares —, share to another server, session TTL, read
|
|
100
150
|
auth. A credential conflict opens the collision dialog (copy debug
|
|
101
151
|
info / share on a new share / don't share).
|
|
102
152
|
- `/openshare` — grouped settings (compact root with live summaries →
|
|
103
153
|
focused submenus): This session (share/stop — delete or leave a
|
|
104
|
-
snapshot —, TTL override, session read auth),
|
|
154
|
+
snapshot —, TTL override, session read auth),
|
|
155
|
+
**Servers** (connection
|
|
105
156
|
AND membership: legacy pair, connect, enroll, rotate, get-a-user-token
|
|
106
157
|
for root holders, disconnect, per-server **admin panel** — users,
|
|
107
158
|
tokens, codes, shares, purge —, test, remove), Sharing (share mode +
|
|
@@ -120,13 +171,17 @@ stays all-mode.
|
|
|
120
171
|
value + source, full URLs/ids); Interface rows set menu width/height
|
|
121
172
|
(host preference store).
|
|
122
173
|
|
|
174
|
+
## Versioning
|
|
175
|
+
|
|
176
|
+
Releases are automatic (conventional commits). The plugin reports its version in the `/openshare` title; the system version ships in every part and the worker's `/health` carries it in full (`version · date · commit`). Designating a version by hand: `bash .github/scripts/release-kit.sh next <1.2.3|major|minor|patch>` in the repo (see DEVELOPMENT.md).
|
|
177
|
+
|
|
123
178
|
## Development
|
|
124
179
|
|
|
125
180
|
```bash
|
|
126
181
|
npm install
|
|
127
182
|
npm run build # tsc -> dist/ + bun bundle -> ci/openshare.js (Bun on PATH)
|
|
128
183
|
npm run typecheck
|
|
129
|
-
npm run test # full matrix via the parallel driver (~
|
|
184
|
+
npm run test # full matrix via the parallel driver (~2.5 min)
|
|
130
185
|
npm run test:quick # everyday gate (~90s): parity + manual core + TUI + v2 + auth
|
|
131
186
|
```
|
|
132
187
|
|
|
@@ -135,20 +190,11 @@ watchdogged, port-swept, and drives real `opencode serve` instances with
|
|
|
135
190
|
a mock OpenAI-compatible provider — except where noted). The canonical
|
|
136
191
|
suite table — what each covers, including the big/backends scale suites —
|
|
137
192
|
lives in [`../DEVELOPMENT.md`](../DEVELOPMENT.md#test-suites); the
|
|
138
|
-
commands:
|
|
139
|
-
|
|
140
|
-
- `test:
|
|
141
|
-
|
|
142
|
-
|
|
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).
|
|
193
|
+
everyday commands:
|
|
194
|
+
|
|
195
|
+
- `test:quick` — the everyday gate: parity + manual core + TUI + v2 + auth.
|
|
196
|
+
- `test:auth` / `test:server-auth` — the identity contract against the
|
|
197
|
+
Cloudflare worker and the Bun backend.
|
|
152
198
|
- `test:cli`, `node scripts/npm-e2e.mjs` — real `opencode run` / the
|
|
153
199
|
published npm package — on demand only.
|
|
154
200
|
|
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
|
|
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
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
`
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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).
|