relic-mcp 0.12.1 → 0.14.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.
Files changed (42) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +67 -15
  4. package/dist/cover/cover.js +815 -817
  5. package/dist/cover/frame.html +929 -826
  6. package/dist/cover/styles.css +1015 -13
  7. package/dist/native-secure-open.d.ts +14 -0
  8. package/dist/native-secure-open.js +154 -0
  9. package/dist/relic-mcp.js +5431 -980
  10. package/mcp-servers.json +5 -2
  11. package/native/build.mjs +1003 -0
  12. package/native/confinement-probe.c +475 -0
  13. package/native/darwin-release-toolchain.json +6 -0
  14. package/native/linux-toolchain.json +14 -0
  15. package/native/local-build.mjs +50 -0
  16. package/native/platform-darwin.c +258 -0
  17. package/native/platform-linux.c +242 -0
  18. package/native/platform.h +31 -0
  19. package/native/secure-open.c +911 -0
  20. package/native/secure-open.d.ts +14 -0
  21. package/package.json +29 -3
  22. package/prebuilds/darwin-arm64/build-info.json +31 -0
  23. package/prebuilds/darwin-arm64/secure_open.node +0 -0
  24. package/prebuilds/darwin-x64/build-info.json +31 -0
  25. package/prebuilds/darwin-x64/secure_open.node +0 -0
  26. package/prebuilds/linux-arm64-gnu/build-info.json +32 -0
  27. package/prebuilds/linux-arm64-gnu/secure_open.node +0 -0
  28. package/prebuilds/linux-x64-gnu/build-info.json +32 -0
  29. package/prebuilds/linux-x64-gnu/secure_open.node +0 -0
  30. package/scripts/prove-packed-native.mjs +1032 -0
  31. package/skills/relic/SKILL.md +49 -9
  32. package/src/comments.ts +206 -4
  33. package/src/cover/inputs.ts +20 -0
  34. package/src/decisions.ts +125 -0
  35. package/src/files.ts +38 -1
  36. package/src/index.ts +11 -2
  37. package/src/native-secure-open.ts +300 -0
  38. package/src/otio-bundle.ts +679 -0
  39. package/src/publish.ts +142 -5
  40. package/src/republish.ts +29 -5
  41. package/src/resolve-anchor.ts +665 -74
  42. package/src/server.ts +361 -47
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "name": "relic",
12
12
  "description": "Publish a file from your machine as an encrypted, shareable link. The agent encrypts locally, uploads only ciphertext, and hands back a URL whose fragment holds the key, so the service stores something it cannot read.",
13
- "version": "0.12.1",
13
+ "version": "0.14.0",
14
14
  "source": "./",
15
15
  "author": {
16
16
  "name": "The Bushido Collective",
@@ -21,6 +21,6 @@
21
21
  }
22
22
  ],
23
23
  "metadata": {
24
- "version": "0.12.1"
24
+ "version": "0.14.0"
25
25
  }
26
26
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relic",
3
- "version": "0.12.1",
3
+ "version": "0.14.0",
4
4
  "description": "Publish a file from your machine as an encrypted, shareable link. The agent encrypts locally, uploads only ciphertext, and hands back a URL whose fragment holds the key, so the service stores something it cannot read.",
5
5
  "mcpServers": "./mcp-servers.json",
6
6
  "author": {
package/README.md CHANGED
@@ -25,23 +25,30 @@ For any client that takes a JSON config:
25
25
  ## What it does with your file
26
26
 
27
27
  1. Reads it from disk, in this process. It is never sent anywhere in plaintext.
28
+ A standard OpenTimelineIO directory (`.otiod`) is automatically packaged into
29
+ a deterministic standard `.otioz` archive; arbitrary directories are refused.
28
30
  2. Draws a 128-bit key and a 26-character relic id independently from your
29
31
  machine's CSPRNG. Neither derives from the other.
30
32
  3. Encrypts locally with AES-128-GCM under RFC 8188 `aes128gcm` framing.
31
33
  4. Uploads **only ciphertext**, straight to object storage under a signed URL.
32
34
  It does not pass through the Relic service.
33
- 5. Tells the service four things: a coarse renderer class from an eight-value
34
- list, this client's name, the ciphertext's byte length, and the title, which
35
- defaults to the filename and is stored in the clear. By default, it also
36
- renders a 1200x630 cover image of the file's first screen in local headless
37
- Chrome and uploads it unencrypted via `POST /api/relics/{id}/cover` for link
38
- preview cards (pass `cover: false` to decline). Not the mimetype, not the
39
- contents.
35
+ 5. Tells the service four things: a coarse renderer class from a ten-value
36
+ list (`markdown`, `code`, `html`, `jsx`, `image`, `pdf`, `media`, `archive`,
37
+ `binary`, `otio`), this client's name, the ciphertext's byte length, and the
38
+ title, which defaults to the filename and is stored in the clear. By default,
39
+ it also renders a 1200x630 cover image of the file's first screen in local
40
+ headless Chrome and uploads it unencrypted via `POST /api/relics/{id}/cover`
41
+ for link preview cards (pass `cover: false` to decline). OpenTimelineIO
42
+ timeline relics (`otio`) skip unencrypted first-screen media rendering by
43
+ default, using a generic card carrying the title and format label to protect
44
+ private timeline cuts and media from leaking into unencrypted link previews.
45
+ Not the mimetype, not the contents.
40
46
  6. Records the relic's id, key, and publish token locally, in a 0600 file
41
47
  under your user config directory, so the relic can be republished from
42
- this machine later. See [Republishing](#republishing). The service never
43
- receives the key or the token plaintext; it keeps only a SHA-256 of the
44
- token.
48
+ this machine later. See [Republishing](#republishing). Preserves logical
49
+ source identity for `.otiod` directories as the original directory path so
50
+ republishing detects the source across sessions. The service never receives
51
+ the key or the token plaintext; it keeps only a SHA-256 of the token.
45
52
  7. Returns a shareable URL whose fragment holds the decryption key. Fragments
46
53
  are never sent to a server by a browser.
47
54
  Call the `relic_describe_client` tool and it will tell you all of this itself,
@@ -141,21 +148,51 @@ What the service holds is comment ciphertext it cannot read. What it learns is
141
148
  who commented on which relic and when, which for a human commenter is a
142
149
  verified email address. The content stays private; the participation does not.
143
150
 
151
+ ## Decisions
152
+
153
+ Readers can record approval or rejection decisions in the viewer, confirmed with a passkey. Decisions are separate from comments: comment text never creates a decision, and no tool records one.
154
+
155
+ `relic_read_decisions` reads them back:
156
+
157
+ ```json
158
+ {
159
+ "name": "relic_read_decisions",
160
+ "arguments": { "relic_id": "0a2c..." }
161
+ }
162
+ ```
163
+
164
+ Optional `version` takes a version number (`1`, `2`, ...) to read decisions for that specific version, or `"*"` to read decisions across all versions. When omitted, it defaults to the relic's current version.
165
+
166
+ Decisions are made by a person in the viewer with a passkey; no tool records them, and comment text never creates one. A person's latest record on a version is their current decision.
167
+
144
168
  ## Why it runs locally
145
169
 
146
170
  Encryption has to happen where the plaintext is, so a hosted version of this
147
171
  would have to receive your file, which defeats the point. Nothing here is
148
172
  fetched from the network and executed.
149
173
 
150
- Because a local client is otherwise opaque, it ships as **readable source
151
- rather than a compiled binary**. `dist/relic-mcp.js` is a single unminified
152
- file and it is exactly what runs; the TypeScript it was built from is in the
153
- same package. The cover rendering page assets in `dist/cover/` contain the
174
+ The client ships its JavaScript as readable source: `dist/relic-mcp.js` is a
175
+ single unminified file and the TypeScript it was built from is in the same
176
+ package. There is one narrow exception for automatic `.otiod` directory
177
+ packaging. It uses a source-included Node-API secure-open helper, prebuilt in
178
+ the npm tarball for macOS arm64 and x64 with a 15.0 binary deployment floor,
179
+ plus glibc 2.28 or newer Linux on arm64 and x64. On either platform, before it
180
+ reads a bundle, the helper verifies on the running kernel that beneath-root
181
+ resolution refuses parent and absolute escapes from a held directory and that
182
+ the no-symlink flag is accepted. Symlink refusal, held-descriptor behavior, and
183
+ replacement behavior are verified by the CI probe on the listed versions. It
184
+ never downloads a helper, invokes Python, or compiles at install or publish
185
+ time. A missing packaged target or failed capability check refuses `.otiod`
186
+ packaging rather than using a pathname fallback. Ordinary file publishing
187
+ remains plain Node 18 or newer. The cover
188
+ rendering page assets in `dist/cover/` contain the
154
189
  unminified cover bundle built from `@relic/viewer`, with vendored React, pdfjs,
155
190
  and sucrase for offline document rendering in local Chrome. Releases carry npm
156
191
  provenance, a cryptographic attestation binding the tarball to a specific commit
157
192
  and workflow.
158
193
 
194
+ The manual release workflow requires an exact SemVer 2.0.0 version, accepts prerelease and build metadata, validates it before release metadata changes, and passes it as environment data rather than executable shell source.
195
+
159
196
  ### Cover rendering and local Chrome requirement
160
197
 
161
198
  By default, publishing or republishing renders a 1200x630 cover image in an
@@ -184,6 +221,7 @@ relic plaintext leaves the machine during rendering.
184
221
  | `relic_share` | `relic_id`, `emails` | Send a relic this machine published to named people. Registers up to 20 email addresses with the service for change and comment notices, and returns a composed share email and mailto link to draft in the sharer's own mailbox. Addresses are stored in the clear by the service, linked to the relic id. A new comment emails everyone on the list except the author, naming the commenter's address (or 'The publisher'). At most one email per person per relic per 10 minutes, and one stop link stops every email about that relic. Relic never sends the share email. Readers holding the link can also share from the viewer once this client version has published or republished the relic. |
185
222
  | `relic_read_comments` | `relic_id` | Returns the relic's comments oldest first, decrypted locally, with the author and a count of any that would not decrypt. Works only on the machine that published. |
186
223
  | `relic_comment` | `relic_id`, `body`, optional `display_name` | Leaves a comment, encrypted on this machine, authorized by the publish token and attributed as `publisher`. Warning: posting emails everyone following the relic, naming 'The publisher'. At most one email per person per relic per 10 minutes, and one stop link stops every email about that relic. Body caps at 4096 bytes of UTF-8. |
224
+ | `relic_read_decisions` | `relic_id`, optional `version` | Read the approval and rejection decisions recorded for a relic. Decisions are made by a person in the viewer confirmed with a passkey; no tool records them, and comment text never creates one. Returns each decision with its verdict, author address, timestamp, and version digest. Pass an integer version (1 or greater) to read decisions for that version, or `"*"` to read across all versions. Defaults to the current version. Works only on the machine that published the relic. |
187
225
  | `relic_describe_client` | none | Explains the encryption path. Reads nothing, sends nothing. |
188
226
 
189
227
  ## Environment
@@ -209,6 +247,20 @@ that does outlive a call is the per-machine publish state file described
209
247
  above. The handshake-based revisions (`2025-11-25` and earlier) are still
210
248
  answered.
211
249
 
212
- Requires Node 18 or newer.
250
+ Requires Node 18 or newer. Automatic `.otiod` packaging additionally requires
251
+ one of four packaged targets: macOS arm64 or x64 with a 15.0 binary deployment
252
+ floor, or Linux glibc 2.28+ arm64 or x64. On either platform, before it reads
253
+ a bundle, the helper verifies on the running kernel that beneath-root
254
+ resolution refuses parent and absolute escapes from a held directory and that
255
+ the no-symlink flag is accepted. Symlink refusal, held-descriptor behavior, and
256
+ replacement behavior are verified by the CI probe on the listed versions. A
257
+ target or kernel that cannot satisfy that requirement refuses directory
258
+ conversion without reducing ordinary file publishing.
259
+
260
+ Tested on macOS: CI native probes in dry run `39652819003` on macOS 15.7.9
261
+ (`24G830`), Darwin 24.6.0 (`xnu-11417.140.69.711.44~1`) on arm64 and x64, with
262
+ Xcode 26.0.1 and SDK 26.0 plus Xcode 16.4 and SDK 15.5; local macOS 27.0.1
263
+ (`26A434`), Darwin 27.0.0 arm64, Homebrew clang 22.1.8, and SDK 27. An earlier
264
+ historical local probe used Xcode clang 21.0.0 and SDK 27.
213
265
 
214
266
  MIT licensed. Source: https://github.com/TheBushidoCollective/relic