@joe-broadhead/opencode-messaging 0.4.0 → 0.5.0

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/CHANGELOG.md CHANGED
@@ -6,6 +6,49 @@ All notable changes to `@joe-broadhead/opencode-messaging`. Versions follow
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.5.0] - 2026-11-07
10
+
11
+ Published on npm (public). The release that carries the `jelly` declaration (hey-jelly#36, A13) and runs
12
+ inside Jelly (A3, A4). Built against `@joe-broadhead/messaging` **0.5.0** (vendored, release commit `0462258`:
13
+ `37723bf`, which includes the Jelly mode lane `10438fe`, plus three fixes), and ships with the 0.5.0 daemon: the five
14
+ platform packages `@joe-broadhead/messaging-bin-{darwin-arm64,darwin-x64,linux-arm64-gnu,linux-x64-gnu,win32-x64}`
15
+ are pinned at exactly 0.5.0, each by the registry's integrity in the lockfile and by its executable's sha256 in
16
+ the launcher, both equal to the release's `SHA256SUMS` and provenance. A 0.4.x daemon is refused at the IPC
17
+ hello (`daemon_mismatch`). Messaging 0.5.0 brings the environment start contract, `cls` required with `view`
18
+ on reads, `notice.ack` as `chat`, previews taking their action's whole input, `request.answer.preview`,
19
+ `daemon.woke`, `person.attached`, `daemon.snapshot`, wake tickets, `ACTION_CLASSES`, and renewal of a
20
+ session ticket by key. Nothing is removed: outside Jelly the plugin behaves as in 0.4.0.
21
+
22
+ - **The `jelly` declaration** in `package.json`, as Jelly's master reads it: title, summary and icon
23
+ (`assets/icon.svg`); the eight tools (`messaging.read` or `messaging.send`, `allow`, read-only where
24
+ they only read); `asks: ["messaging.send"]`; `resources: ["messaging"]`; the `messaging` service
25
+ (`agent.sock`, `admin.sock`, `daemon.health` on the agent socket, wakes, `identity.json` and
26
+ `pairing.json` left out of backups); the section (`views/section.html`: People, Chats, Requests,
27
+ Devices, Your agents) with its eleven read-only methods; twelve service actions with Jelly's
28
+ classes and confirmations (`person.send` chat/session; `conv.markRead`, `notice.ack` chat/never;
29
+ `request.answer`, `grant.set`, `contact.request`, `channel.*`, `device.approve`, `device.remove`
30
+ local/always, with the daemon's previews); notices (Message, Request, Messaging alert); `turns`
31
+ labelled "Messages"; and `requires` `service`, `section`, `actions`, `turns`, `notices` and
32
+ `resources`, never `act`. It is built from the vendored daemon's IPC schemas
33
+ (`npm run jelly:update`), `check:package` validates it with Jelly's rules, and a test holds every
34
+ action's class, every section read (`view`, or agent tier with no grant) and every preview's class
35
+ equal to the daemon's `ACTION_CLASSES`.
36
+ - **Inside Jelly** (Jelly's services accessor is present): the plugin connects to the agent socket
37
+ Jelly names, never starts a daemon, never resolves a home or reads `~/.messaging`, and registers
38
+ exactly the session name Jelly's ticket names, with the ticket. Every OpenCode session of the agent
39
+ shares that one Messaging session. Renewal is messaging 0.5.0's: when the agent's ticket ends, the
40
+ daemon keeps the session and its mail and answers `ticket_invalid`; the plugin re-reads Jelly's
41
+ accessor, registers the same key with the fresh ticket on the same connection, and makes the call
42
+ again. If the accessor still holds the ended ticket, the tool says to restart the agent in Jelly.
43
+ - **Turns through Jelly:** inside Jelly a wake files a `turn` request with Jelly's core plugin (the
44
+ sender person as key, `own`, `trusted` or `guarded` from the daemon's record, a fixed prompt)
45
+ instead of prompting a session; every refusal falls back to notes. A guarded turn keeps the plugin's
46
+ Messaging send and read limit; Jelly's `jelly.peer` mark fences the rest.
47
+ - Inside Jelly there is no console (the `config` RPC refuses) and no setup note.
48
+ - Without the accessor nothing changes.
49
+ - **Not yet:** the plugin does not raise the declared notices itself (Jelly reads the service's
50
+ counts for its badge), and the section page has no search and no card refresh.
51
+
9
52
  ## [0.4.0] - 2026-11-07
10
53
 
11
54
  Published on npm (public). Built against `@joe-broadhead/messaging` **0.4.0** (vendored, release commit `da50b5d`:
package/README.md CHANGED
@@ -73,10 +73,10 @@ the executable (without it, the plugin uses the Node fallback):
73
73
 
74
74
  ```bash
75
75
  mkdir -p ~/.local/share/opencode-messaging
76
- tar -xzf joe-broadhead-opencode-messaging-0.4.0.tgz -C ~/.local/share/opencode-messaging --strip-components=1
77
- npm pack @joe-broadhead/messaging-bin-darwin-arm64@0.4.0 # your platform's package
76
+ tar -xzf joe-broadhead-opencode-messaging-0.5.0.tgz -C ~/.local/share/opencode-messaging --strip-components=1
77
+ npm pack @joe-broadhead/messaging-bin-darwin-arm64@0.5.0 # your platform's package
78
78
  mkdir -p ~/.local/share/opencode-messaging/node_modules/@joe-broadhead/messaging-bin-darwin-arm64
79
- tar -xzf joe-broadhead-messaging-bin-darwin-arm64-0.4.0.tgz \
79
+ tar -xzf joe-broadhead-messaging-bin-darwin-arm64-0.5.0.tgz \
80
80
  -C ~/.local/share/opencode-messaging/node_modules/@joe-broadhead/messaging-bin-darwin-arm64 --strip-components=1
81
81
  node ~/.local/share/opencode-messaging/dist/messaging.js --help # the messaging CLI of this version
82
82
  ```
@@ -85,7 +85,7 @@ node ~/.local/share/opencode-messaging/dist/messaging.js --help # the messagi
85
85
  { "plugins": [{ "package": "/Users/you/.local/share/opencode-messaging" }] }
86
86
  ```
87
87
 
88
- `npm install ./joe-broadhead-opencode-messaging-0.4.0.tgz` into a folder OpenCode loads works too: it
88
+ `npm install ./joe-broadhead-opencode-messaging-0.5.0.tgz` into a folder OpenCode loads works too: it
89
89
  adds the package and this machine's platform package, nothing else.
90
90
 
91
91
  ## Install from a local path
@@ -229,6 +229,66 @@ cannot. **Until Jelly ID offers browser sign-in** (Jelly's contract v1.2), the d
229
229
  `login_unsupported`, and the console says so in one sentence and points to Link this device; it never
230
230
  retries. Agent tools never sign in: `device.login` is on the daemon's admin socket only.
231
231
 
232
+ ## Running inside Jelly
233
+
234
+ Jelly installs this package as a curated plugin with a service: Jelly's host runs the pinned
235
+ `messagingd` itself, as the host owner's, and hands each agent's engine its place in it. The
236
+ package's `jelly` declaration (in `package.json`) says what Jelly runs and draws. It is built from the
237
+ vendored daemon's own method schemas by `npm run jelly:update`, and `npm run check:package` checks it
238
+ with Jelly's rules.
239
+
240
+ **How the plugin knows.** In a Jelly engine,
241
+ `globalThis[Symbol.for("jelly.services")]?.get("@joe-broadhead/opencode-messaging")` answers
242
+ `{ socket, name, ticket, expiresAt }`: the service's agent socket, the one session name this agent
243
+ may use, and a session ticket that proves it. When that accessor is present, the plugin:
244
+
245
+ - connects to that socket and **never starts a daemon** (`daemon.autostart`, `daemon.bin` and
246
+ `daemon.node` do nothing there), and never resolves a Messaging home, reads `~/.messaging` or looks
247
+ for `identity.json`; the host enrolled the service's device;
248
+ - registers **exactly the ticket's name, with the ticket**, and no wake host. Every OpenCode session
249
+ of the agent (its conversation, and each turn Jelly starts) speaks as that one session, so
250
+ teammates see one address per agent;
251
+ - renews with Jelly's fresh ticket. Jelly keeps the accessor's ticket current (a new one for the
252
+ same agent and name before `expiresAt`). Once the ticket the agent registered with ends, the service
253
+ keeps the session and its mail and answers its calls `ticket_invalid`; the plugin then reads the
254
+ accessor again, registers the same key with the fresh ticket on the same connection (which takes
255
+ the registration back for every connection of the agent), and makes the call again. A refused
256
+ `session.register` is retried the same way. If the accessor still holds the ticket that ended, the
257
+ tool says to restart the agent in Jelly, and the next call reads the accessor again;
258
+ - starts **turns through Jelly**, never by prompting a session: a wake becomes a `turn` request to
259
+ Jelly's core plugin, one per sender person, with that person as the conversation key, the profile
260
+ from the daemon's record (`own` for your own devices and agents, `trusted` only when the daemon
261
+ calls every item trusted, else `guarded`) and a fixed prompt that carries nothing a peer wrote. Jelly
262
+ decides: only while the agent's owner has turned "Messages can start work" on, within Jelly's
263
+ budget. Any refusal (`invalid`, `agent`, `not_declared`, `off`, `budget`, `engine`) gives the items
264
+ notes in the agent's conversation instead. The plugin's per-person wake budget still applies;
265
+ - in a guarded turn keeps its own Messaging limit (reads and sends reach the person the turn is for,
266
+ and nothing waits on a person), and leaves the rest of the fence (no shell, edits only in the
267
+ conversation's folder, no outward tools) to Jelly's own `jelly.peer` mark. It sets no session
268
+ permissions and removes no tools there. A turn Jelly marked that the plugin has no record of may
269
+ not read or send at all.
270
+
271
+ Without the accessor, nothing above applies, and the plugin behaves exactly as in stock OpenCode.
272
+
273
+ **What Jelly draws instead of `/messaging`.** Jelly runs no terminal UI: the person's console is the
274
+ plugin's **section**, a sealed page in Jelly's navigation (`views/section.html`) with People, Chats,
275
+ Requests, Devices and Your agents. It reads through the service's admin socket (each read is a
276
+ declared read-only method; Jelly signs it with class `view`) and changes things only through the
277
+ declared actions, each under the confirmation Jelly draws in its own words:
278
+
279
+ | Action | Class | Confirmation |
280
+ |---|---|---|
281
+ | `person.send` | `chat` | once per opening |
282
+ | `conv.markRead`, `notice.ack` | `chat` | none |
283
+ | `request.answer`, `grant.set`, `contact.request`, `device.approve`, `device.remove` | `local` (owner devices) | every time, with the daemon's preview |
284
+ | `channel.create`, `channel.invite`, `channel.remove`, `channel.leave` | `local` | every time |
285
+
286
+ Under Jelly the plugin's `config` RPC refuses, so a TUI part loaded there anyway connects to nothing
287
+ and starts nothing. The section's badge is Jelly's own count from the service (`notice.list`, unread and
288
+ waiting). The declaration names the notices a banner may show (Message, Request, Messaging alert);
289
+ this release does not raise them yet. The service's key files (`identity.json`, `pairing.json`) are
290
+ left out of Jelly's backups.
291
+
232
292
  ## Docs
233
293
 
234
294
  - [Configuration](docs/configuration.md): every option and its default.
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><title>Messaging</title><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v7a2.5 2.5 0 0 1-2.5 2.5H11l-4.5 4v-4h0A2.5 2.5 0 0 1 4 12.5z"/><path d="M8 8h8"/><path d="M8 11h5"/></svg>