relic-mcp 0.12.0 → 0.13.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 (40) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +52 -18
  4. package/dist/cover/cover.js +815 -817
  5. package/dist/cover/frame.html +929 -826
  6. package/dist/cover/styles.css +210 -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 +5237 -989
  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 +39 -12
  32. package/src/comments.ts +205 -3
  33. package/src/cover/inputs.ts +20 -0
  34. package/src/files.ts +38 -1
  35. package/src/index.ts +11 -2
  36. package/src/native-secure-open.ts +300 -0
  37. package/src/otio-bundle.ts +679 -0
  38. package/src/publish.ts +109 -2
  39. package/src/resolve-anchor.ts +665 -74
  40. package/src/server.ts +225 -71
@@ -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.0",
13
+ "version": "0.13.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.0"
24
+ "version": "0.13.0"
25
25
  }
26
26
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relic",
3
- "version": "0.12.0",
3
+ "version": "0.13.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,
@@ -147,15 +154,28 @@ Encryption has to happen where the plaintext is, so a hosted version of this
147
154
  would have to receive your file, which defeats the point. Nothing here is
148
155
  fetched from the network and executed.
149
156
 
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
157
+ The client ships its JavaScript as readable source: `dist/relic-mcp.js` is a
158
+ single unminified file and the TypeScript it was built from is in the same
159
+ package. There is one narrow exception for automatic `.otiod` directory
160
+ packaging. It uses a source-included Node-API secure-open helper, prebuilt in
161
+ the npm tarball for macOS arm64 and x64 with a 15.0 binary deployment floor,
162
+ plus glibc 2.28 or newer Linux on arm64 and x64. On either platform, before it
163
+ reads a bundle, the helper verifies on the running kernel that beneath-root
164
+ resolution refuses parent and absolute escapes from a held directory and that
165
+ the no-symlink flag is accepted. Symlink refusal, held-descriptor behavior, and
166
+ replacement behavior are verified by the CI probe on the listed versions. It
167
+ never downloads a helper, invokes Python, or compiles at install or publish
168
+ time. A missing packaged target or failed capability check refuses `.otiod`
169
+ packaging rather than using a pathname fallback. Ordinary file publishing
170
+ remains plain Node 18 or newer. The cover
171
+ rendering page assets in `dist/cover/` contain the
154
172
  unminified cover bundle built from `@relic/viewer`, with vendored React, pdfjs,
155
173
  and sucrase for offline document rendering in local Chrome. Releases carry npm
156
174
  provenance, a cryptographic attestation binding the tarball to a specific commit
157
175
  and workflow.
158
176
 
177
+ 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.
178
+
159
179
  ### Cover rendering and local Chrome requirement
160
180
 
161
181
  By default, publishing or republishing renders a 1200x630 cover image in an
@@ -180,10 +200,10 @@ relic plaintext leaves the machine during rendering.
180
200
  | `relic_lookup_source` | `path` | Reads local state to find whether this machine already published that file, and returns the exact `relic_republish` call. Calls no server. |
181
201
  | `relic_list` | optional `limit`, `include_expired`, `verify`, `refresh` | Every relic this machine published, newest first. The only tool that enumerates: lookup answers only from the file a relic came from. A name this machine never recorded is recovered by decrypting the relic's own envelope in one 64 KB range request, or comes back `null` with the reason. A relic the service will not serve is listed with which of removed, expired, exhausted, or unreachable it is. Each row carries the share URL, fragment included, so each row is a credential. Reaching the service spends one of a relic's finite opens; recovered names are cached, so a repeat listing spends none. |
182
202
  | `relic_show` | `relic_id`, optional `include_content` | One relic in detail, including how many versions the service holds against how many this machine recorded, and with `include_content` the current decrypted content. Read it before republishing anything you did not just write: republish replaces what the link serves, so without the read-back the edit is blind. Content that is not valid UTF-8 is reported as size and type rather than mangled text. |
183
- | `relic_republish` | `relic_id`, `path`, optional `filename`, `title`, `cover`, `ttl_days`, `addresses`, `notify` | Publishes a new version under the same key, so the share URL is unchanged. Replaces the plaintext title (defaults to the new filename; pass `""` to remove it). Replaces the cover image with a newly rendered cover, or clears it if `cover: false` is passed. Sends a change notice email to everyone following the relic unless `notify: false` is passed. Works only on the machine holding that relic's key and publish token; a taken-down relic can never be revived. |
184
- | `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 notices on future versions, 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. 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. |
203
+ | `relic_republish` | `relic_id`, `path`, optional `filename`, `title`, `cover`, `ttl_days`, `addresses`, `notify` | Publishes a new version under the same key, so the share URL is unchanged. Replaces the plaintext title (defaults to the new filename; pass `""` to remove it). Replaces the cover image with a newly rendered cover, or clears it if `cover: false` is passed. Sends a change notice email to everyone following the relic unless `notify: false` is passed. At most one email per person per relic per 10 minutes is sent, and one stop link stops every email about that relic. Works only on the machine holding that relic's key and publish token; a taken-down relic can never be revived. |
204
+ | `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
205
  | `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
- | `relic_comment` | `relic_id`, `body`, optional `display_name` | Leaves a comment, encrypted on this machine, authorized by the publish token and attributed as `publisher`. Body caps at 4096 bytes of UTF-8. |
206
+ | `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. |
187
207
  | `relic_describe_client` | none | Explains the encryption path. Reads nothing, sends nothing. |
188
208
 
189
209
  ## Environment
@@ -209,6 +229,20 @@ that does outlive a call is the per-machine publish state file described
209
229
  above. The handshake-based revisions (`2025-11-25` and earlier) are still
210
230
  answered.
211
231
 
212
- Requires Node 18 or newer.
232
+ Requires Node 18 or newer. Automatic `.otiod` packaging additionally requires
233
+ one of four packaged targets: macOS arm64 or x64 with a 15.0 binary deployment
234
+ floor, or Linux glibc 2.28+ arm64 or x64. On either platform, before it reads
235
+ a bundle, the helper verifies on the running kernel that beneath-root
236
+ resolution refuses parent and absolute escapes from a held directory and that
237
+ the no-symlink flag is accepted. Symlink refusal, held-descriptor behavior, and
238
+ replacement behavior are verified by the CI probe on the listed versions. A
239
+ target or kernel that cannot satisfy that requirement refuses directory
240
+ conversion without reducing ordinary file publishing.
241
+
242
+ Tested on macOS: CI native probes in dry run `39652819003` on macOS 15.7.9
243
+ (`24G830`), Darwin 24.6.0 (`xnu-11417.140.69.711.44~1`) on arm64 and x64, with
244
+ Xcode 26.0.1 and SDK 26.0 plus Xcode 16.4 and SDK 15.5; local macOS 27.0.1
245
+ (`26A434`), Darwin 27.0.0 arm64, Homebrew clang 22.1.8, and SDK 27. An earlier
246
+ historical local probe used Xcode clang 21.0.0 and SDK 27.
213
247
 
214
248
  MIT licensed. Source: https://github.com/TheBushidoCollective/relic