relic-mcp 0.12.0 → 0.12.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -3
- package/dist/relic-mcp.js +30 -24
- package/package.json +1 -1
- package/skills/relic/SKILL.md +13 -4
- package/src/server.ts +56 -33
|
@@ -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.
|
|
13
|
+
"version": "0.12.1",
|
|
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.
|
|
24
|
+
"version": "0.12.1"
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "relic",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
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
|
@@ -180,10 +180,10 @@ relic plaintext leaves the machine during rendering.
|
|
|
180
180
|
| `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
181
|
| `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
182
|
| `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
|
|
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. 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. |
|
|
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 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
185
|
| `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. |
|
|
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`. 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
187
|
| `relic_describe_client` | none | Explains the encryption path. Reads nothing, sends nothing. |
|
|
188
188
|
|
|
189
189
|
## Environment
|
package/dist/relic-mcp.js
CHANGED
|
@@ -26295,7 +26295,7 @@ async function shareVerifierFor(proof) {
|
|
|
26295
26295
|
function composeShareEmail(p) {
|
|
26296
26296
|
const thing = p.title === null ? "a file" : `"${p.title}"`;
|
|
26297
26297
|
const subject = p.title === null ? "A file shared with you on Relic" : `Shared with you: ${p.title}`;
|
|
26298
|
-
const next = p.sender === "publisher" ? "When I publish a new version" : "When a new version is published";
|
|
26298
|
+
const next = p.sender === "publisher" ? "When someone comments or I publish a new version" : "When someone comments or a new version is published";
|
|
26299
26299
|
const text = [
|
|
26300
26300
|
`I've shared ${thing} with you on Relic. Open it here:`,
|
|
26301
26301
|
"",
|
|
@@ -26303,7 +26303,7 @@ function composeShareEmail(p) {
|
|
|
26303
26303
|
"",
|
|
26304
26304
|
"Anyone with this whole link can read it, including the part after the #, which is the key that decrypts it. Relic never receives that part.",
|
|
26305
26305
|
"",
|
|
26306
|
-
`${next}, Relic will email you
|
|
26306
|
+
`${next}, Relic will email you. That email never contains the key, and it has a link to stop those emails. Relic keeps your address for that.`
|
|
26307
26307
|
].join(`
|
|
26308
26308
|
`);
|
|
26309
26309
|
return { to: [...p.to], subject, text };
|
|
@@ -31389,7 +31389,7 @@ var TOOL_DEFINITION = {
|
|
|
31389
31389
|
var REPUBLISH_TOOL_DEFINITION = {
|
|
31390
31390
|
name: REPUBLISH_TOOL_NAME,
|
|
31391
31391
|
title: "Republish a relic",
|
|
31392
|
-
description: "Publish a new version of a relic this machine originally published, " + "encrypting under the same key so the existing share URL keeps working. " + VERSION_HISTORY_DISCLOSURE + " Only possible from the machine that holds the relic's key and publish " + "token; a relic that was taken down can never be revived. " + "By default a picture of the first screen is rendered locally and " + "uploaded unencrypted for link previews; pass cover: false to withhold " + "it." + REPUBLISH_DISCIPLINE_DISCLOSURE + " Each new version emails a change notice, naming the title and version and never the key, to
|
|
31392
|
+
description: "Publish a new version of a relic this machine originally published, " + "encrypting under the same key so the existing share URL keeps working. " + VERSION_HISTORY_DISCLOSURE + " Only possible from the machine that holds the relic's key and publish " + "token; a relic that was taken down can never be revived. " + "By default a picture of the first screen is rendered locally and " + "uploaded unencrypted for link previews; pass cover: false to withhold " + "it." + REPUBLISH_DISCIPLINE_DISCLOSURE + " Each new version emails a change notice, naming the title and version and never the key, to each verified commenter and each address added with relic_share, minus any that stopped emails; pass notify: false to skip it. At most one email per person per relic per 10 minutes, and one stop link stops every email about that relic.",
|
|
31393
31393
|
inputSchema: {
|
|
31394
31394
|
type: "object",
|
|
31395
31395
|
properties: {
|
|
@@ -31442,7 +31442,7 @@ var REPUBLISH_TOOL_DEFINITION = {
|
|
|
31442
31442
|
notify: {
|
|
31443
31443
|
type: "boolean",
|
|
31444
31444
|
default: true,
|
|
31445
|
-
description: "Optional. Email a change notice for this version to
|
|
31445
|
+
description: "Optional. Email a change notice for this version to each verified address that commented on the relic and each address added with relic_share, except any that stopped those emails. Defaults to true. The notice names the title and version and never carries the key. At most one email per person per relic per 10 minutes, and one stop link stops every email about that relic. Pass false for a change not worth an email, such as a typo fix."
|
|
31446
31446
|
}
|
|
31447
31447
|
},
|
|
31448
31448
|
required: ["relic_id", "path"],
|
|
@@ -31505,7 +31505,7 @@ var REPUBLISH_TOOL_DEFINITION = {
|
|
|
31505
31505
|
var SHARE_TOOL_DEFINITION = {
|
|
31506
31506
|
name: SHARE_TOOL_NAME,
|
|
31507
31507
|
title: "Share a relic with people",
|
|
31508
|
-
description:
|
|
31508
|
+
description: 'Send a relic this machine published to named people. Registers their email addresses with the service so each gets an email notice when someone comments and when you republish, and returns a ready share email carrying the full link, plus a mailto link that opens it as a draft. Relic never sends the share email, because it carries the key: draft it in the sharer’s own mailbox, from their own address, and let them send it. The service stores the addresses in the clear, linked to the relic. A change notice names the title and version, never the key. 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. Only works on the machine that published the relic: the link needs its key and registering needs its publish token. Takes the relic id, never the share URL. Up to 20 addresses per call and 50 per relic.',
|
|
31509
31509
|
inputSchema: {
|
|
31510
31510
|
type: "object",
|
|
31511
31511
|
properties: {
|
|
@@ -31518,7 +31518,7 @@ var SHARE_TOOL_DEFINITION = {
|
|
|
31518
31518
|
items: { type: "string" },
|
|
31519
31519
|
minItems: 1,
|
|
31520
31520
|
maxItems: 20,
|
|
31521
|
-
description: "Up to 20 email addresses to register for change notices."
|
|
31521
|
+
description: "Up to 20 email addresses to register for comment and change notices."
|
|
31522
31522
|
}
|
|
31523
31523
|
},
|
|
31524
31524
|
required: ["relic_id", "emails"],
|
|
@@ -32055,7 +32055,7 @@ var READ_COMMENTS_TOOL_DEFINITION = {
|
|
|
32055
32055
|
var COMMENT_TOOL_DEFINITION = {
|
|
32056
32056
|
name: COMMENT_TOOL_NAME,
|
|
32057
32057
|
title: "Comment on a relic",
|
|
32058
|
-
description: "Leave a comment on a relic this machine published, encrypted here so " + "the service stores ciphertext it cannot read. Everyone holding the " + "link sees it. Attribution is the publish token, so the comment is " + '
|
|
32058
|
+
description: "Leave a comment on a relic this machine published, encrypted here so " + "the service stores ciphertext it cannot read. Everyone holding the " + "link sees it. Warning: posting emails everyone following the relic " + "(each verified commenter, each address added with relic_share, and " + "the owner address, minus any that used the stop link). " + "Attribution is the publish token, so the comment is attributed to " + '"publisher" rather than to an email address: an agent has no mailbox ' + 'and cannot verify one, and the email names "The publisher". At most ' + "one email per person per relic per 10 minutes, and one stop link stops " + "every email about that relic. That is attribution and not " + "authorization. " + "Comments can be anchored to an exact location: a text quote, a stage " + "pin, an artifact region, a moment or span in audio or video, or a page " + "in a document. Passing an anchor attaches your reply at that location, " + "so the reader sees what you are answering; omitting it leaves a remark " + "about the whole relic. " + COMMENT_MACHINE_BOUNDARY + " Takes the relic id, never the share URL.",
|
|
32059
32059
|
inputSchema: {
|
|
32060
32060
|
type: "object",
|
|
32061
32061
|
properties: {
|
|
@@ -32265,7 +32265,7 @@ var DESCRIBE_TOOL_DEFINITION = {
|
|
|
32265
32265
|
additionalProperties: false
|
|
32266
32266
|
}
|
|
32267
32267
|
};
|
|
32268
|
-
var SERVER_VERSION = "0.12.
|
|
32268
|
+
var SERVER_VERSION = "0.12.1";
|
|
32269
32269
|
var SERVER_INFO = {
|
|
32270
32270
|
name: "relic",
|
|
32271
32271
|
title: "Relic",
|
|
@@ -32281,9 +32281,9 @@ Nine things that change how you should act:
|
|
|
32281
32281
|
4. Check sources with relic_lookup_source; relic_republish keeps the URL where relic_publish costs a second URL. ${VERSION_HISTORY_DISCLOSURE}
|
|
32282
32282
|
5. A relic can be republished only from the machine that published it: the key and publish token live nowhere else.
|
|
32283
32283
|
6. HTML and JSX render in an isolated frame with no network access, so inline styles, scripts, fonts, and images: a CDN reference renders as nothing.
|
|
32284
|
-
7. People can comment on a relic. Read with relic_read_comments before changing reviewed content, answer with relic_comment. relic_edit_comment rewrites one, relic_resolve_comment settles one, and settled counts as handled. All take the relic id and attribute you as publisher.
|
|
32284
|
+
7. People can comment on a relic. Read with relic_read_comments before changing reviewed content, answer with relic_comment. relic_edit_comment rewrites one, relic_resolve_comment settles one, and settled counts as handled. All take the relic id and attribute you as publisher. A new comment emails everyone on the relic's list except the author (naming the address, or "The publisher" for relic_comment; at most once per 10 minutes). One stop link stops every email about that relic.
|
|
32285
32285
|
8. By default relic_publish and relic_republish upload a picture of the file's first screen, unencrypted, for link previews: the service and anyone holding the link without the key can see it. Pass cover: false for anything you would not show in a chat preview.
|
|
32286
|
-
9. relic_republish emails a change notice, naming the title and version but never the key, to everyone
|
|
32286
|
+
9. relic_republish emails a change notice, naming the title and version but never the key, to everyone following the relic; pass notify: false to skip it. relic_share hands back a share email with the full link for you to draft in the sharer's own mailbox: Relic never sends it, so the key never reaches the service. Readers holding the link can also share from the viewer once this client version has published or republished the relic.`;
|
|
32287
32287
|
async function handleMessage(message, deps) {
|
|
32288
32288
|
if (message.id === undefined)
|
|
32289
32289
|
return;
|
|
@@ -32369,9 +32369,10 @@ async function callTool(id2, params, deps) {
|
|
|
32369
32369
|
ciphertext_destination: "object storage, via a signed URL",
|
|
32370
32370
|
local_publish_state: "relic id, source identity, key, and publish token per relic, " + "written 0600 under the user config directory; key and token " + "are never printed or sent",
|
|
32371
32371
|
comment_encryption: "AES-128-GCM under a key derived from the relic key with a " + "distinct HKDF label, so comment bodies reach the service as " + "ciphertext and the URL fragment is unchanged",
|
|
32372
|
-
comment_attribution: 'the publish token, reported by the service as "publisher"; the ' + "operator learns which identity commented on which relic and when",
|
|
32373
|
-
|
|
32374
|
-
|
|
32372
|
+
comment_attribution: 'the publish token, reported by the service as "publisher"; the ' + "operator learns which identity commented on which relic and when; " + 'posting with relic_comment emails everyone following the relic, naming "The publisher"',
|
|
32373
|
+
comment_notices: "a new comment on a relic emails everyone on its list (commenters, " + "shared addresses, the owner address) 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",
|
|
32374
|
+
change_notices: "on every republish unless notify: false, the service emails every " + "verified address that commented on the relic and every address " + "added with relic_share, minus any that used " + "the stop link; the email names the title and version and never carries the key; " + "at most one email per person per relic per 10 minutes, and one stop link stops every email about that relic",
|
|
32375
|
+
sharing: "relic_share sends the service email addresses and nothing else; " + "it stores them in the clear, linked to the relic id so they receive " + "comment and change notices; the share email carrying the full link " + "is composed here for you to send from your own mailbox, so the key " + "never reaches the service; readers holding the link can also share " + "from the viewer once a relic was published or republished by this client version",
|
|
32375
32376
|
service_origin: deps.serviceOrigin
|
|
32376
32377
|
},
|
|
32377
32378
|
isError: false
|
|
@@ -32692,7 +32693,7 @@ async function callRepublish(id2, params, deps) {
|
|
|
32692
32693
|
|
|
32693
32694
|
` + "The share URL is unchanged: everyone holding the existing " + "link, including its fragment, now sees this content. There " + `is no new link to hand out.
|
|
32694
32695
|
|
|
32695
|
-
` + `${result.notify ? `Relic sends a change notice for version ${result.version} to
|
|
32696
|
+
` + `${result.notify ? `Relic sends a change notice for version ${result.version} to each address that commented on this relic or was added with relic_share, except any that stopped those emails. It names the title and version and never carries the key (at most one email per recipient per relic per 10 minutes; one stop link stops every email about that relic).` : "No change notice goes out for this version, as asked."}
|
|
32696
32697
|
|
|
32697
32698
|
` + `Key phrase: ${result.key_phrase}
|
|
32698
32699
|
` + `${KEY_PHRASE_DISCLOSURE}
|
|
@@ -32734,7 +32735,7 @@ async function callShare(id2, params, deps) {
|
|
|
32734
32735
|
relic_id: relicId,
|
|
32735
32736
|
emails: rawEmails
|
|
32736
32737
|
}, deps);
|
|
32737
|
-
const text = `Registered ${result.registered.length} address(es) on relic ${result.relic_id} ` + `for change notices (${result.added} new; ${result.shared_count} of ${result.share_limit} on its list). ` + `Relic has emailed nobody.
|
|
32738
|
+
const text = `Registered ${result.registered.length} address(es) on relic ${result.relic_id} ` + `for comment and change notices (${result.added} new; ${result.shared_count} of ${result.share_limit} on its list). ` + `Relic has emailed nobody.
|
|
32738
32739
|
|
|
32739
32740
|
` + "Draft the email below in the sharer's own mailbox, from their own address, " + "and let them send it. Do not send it through Relic or any other service, and " + `do not paste the link anywhere else: it carries the key, which is now in this transcript.
|
|
32740
32741
|
|
|
@@ -32837,7 +32838,7 @@ async function callComment(id2, params, deps) {
|
|
|
32837
32838
|
{
|
|
32838
32839
|
type: "text",
|
|
32839
32840
|
text: `Commented on relic ${result.relic_id} as ${result.author}.
|
|
32840
|
-
` + "Everyone holding the link sees it. The service stored " + "ciphertext it cannot read, and it knows that this address " + "commented on this relic at this time."
|
|
32841
|
+
` + "Everyone holding the link sees it. The service stored " + "ciphertext it cannot read, and it knows that this address " + "commented on this relic at this time. Relic emails everyone " + 'following this relic, naming "The publisher" (at most one ' + "email per recipient per relic per 10 minutes; one stop link " + "stops every email about that relic)."
|
|
32841
32842
|
}
|
|
32842
32843
|
],
|
|
32843
32844
|
structuredContent: result,
|
|
@@ -33101,18 +33102,23 @@ writes is attributed to the publisher rather than an email address, because
|
|
|
33101
33102
|
an agent has no mailbox to verify. What the operator does learn is who
|
|
33102
33103
|
commented on which relic and when: for a person that is a verified email
|
|
33103
33104
|
address, and that association is a real cost the content's encryption does
|
|
33104
|
-
not cover.
|
|
33105
|
+
not cover. A new comment emails everyone on the relic's list (commenters,
|
|
33106
|
+
shared addresses, and the owner address) except the author, naming the
|
|
33107
|
+
commenter's address or "The publisher" for comments this client posts.
|
|
33108
|
+
At most one email per person per relic per 10 minutes, and one stop link
|
|
33109
|
+
stops every email about that relic.
|
|
33105
33110
|
|
|
33106
33111
|
What happens with change notices and sharing: on every republish unless
|
|
33107
33112
|
notify: false, the service emails every verified address that commented on
|
|
33108
33113
|
the relic and every address added with relic_share, minus any that used the
|
|
33109
|
-
stop link. The email names the title and version and
|
|
33110
|
-
|
|
33111
|
-
|
|
33112
|
-
|
|
33113
|
-
|
|
33114
|
-
|
|
33115
|
-
|
|
33114
|
+
stop link. The email names the title and version and
|
|
33115
|
+
never carries the key. At most one email per person per relic per 10 minutes,
|
|
33116
|
+
and one stop link stops every email about that relic. relic_share sends the
|
|
33117
|
+
service email addresses and nothing else: it stores them in the clear, linked
|
|
33118
|
+
to the relic id. The share email carrying the full link is composed here on
|
|
33119
|
+
this machine for you to send from your own mailbox, so the key never reaches
|
|
33120
|
+
the service. Readers holding the link can also share from the viewer once the
|
|
33121
|
+
relic was published or republished by this client version.
|
|
33116
33122
|
|
|
33117
33123
|
What this does NOT protect against: the key is returned to your agent in the
|
|
33118
33124
|
URL, so it enters the model's context and your session transcript. That is
|
package/package.json
CHANGED
package/skills/relic/SKILL.md
CHANGED
|
@@ -153,18 +153,23 @@ Call `relic_share` with the relic id and up to 20 email addresses:
|
|
|
153
153
|
relic_share(relic_id: "0a2c...", emails: ["ada@example.com", "grace@example.com"])
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
`relic_share` registers the addresses with the service so each recipient receives an email notice whenever a new version is republished. It composes a ready-to-send share email containing the full URL and key, and returns both the email text and a `mailto:` link.
|
|
156
|
+
`relic_share` registers the addresses with the service so each recipient receives an email notice whenever someone comments or a new version is republished. It composes a ready-to-send share email containing the full URL and key, and returns both the email text and a `mailto:` link.
|
|
157
157
|
|
|
158
158
|
Draft the email in the user's own mailbox (or hand over the `mailto:` link if there is no mail tool available) and let them send it. Relic never sends the share email, because the share link carries the key in its fragment, and the service must never receive the key.
|
|
159
159
|
|
|
160
|
-
Addresses are stored by the service in the clear, linked to the relic id. When you republish, the service automatically sends a change notice to
|
|
160
|
+
Addresses are stored by the service in the clear, linked to the relic id. When you republish, the service automatically sends a change notice to each commenter and shared address, unless you pass `notify: false`. When a new comment is posted, the service emails everyone on the relic's list (commenters, shared addresses, and the owner address) except the comment's author, naming the commenter's address (or "The publisher"). Relic sends at most one email per person per relic per 10 minutes, and one stop link stops every email about that relic.
|
|
161
161
|
|
|
162
162
|
Readers holding the link can also share from the viewer once a relic was published or republished by this client version.
|
|
163
163
|
|
|
164
164
|
## Comments
|
|
165
165
|
|
|
166
166
|
People can comment on a relic, and that is the only way a reader can answer
|
|
167
|
-
back.
|
|
167
|
+
back. A new comment on a relic emails everyone on its list (verified commenters,
|
|
168
|
+
shared addresses, and the owner address) except the author, naming the
|
|
169
|
+
commenter's address (or "The publisher"). At most one email per person per
|
|
170
|
+
relic per 10 minutes is sent, and one stop link stops every email about that
|
|
171
|
+
relic. You have no mailbox, so none of those emails reach you: read them.
|
|
172
|
+
|
|
168
173
|
```
|
|
169
174
|
relic_read_comments(relic_id: "0a2c...")
|
|
170
175
|
```
|
|
@@ -180,6 +185,9 @@ Answer with:
|
|
|
180
185
|
relic_comment(relic_id: "0a2c...", body: "Fixed the chart, republished as version 3.")
|
|
181
186
|
```
|
|
182
187
|
|
|
188
|
+
Posting a comment with `relic_comment` emails everyone following the relic,
|
|
189
|
+
naming "The publisher".
|
|
190
|
+
|
|
183
191
|
Four things to know:
|
|
184
192
|
|
|
185
193
|
- **Both work only on the machine that published the relic.** The comment key
|
|
@@ -192,7 +200,8 @@ Four things to know:
|
|
|
192
200
|
- **Your comment is attributed to the publisher, not to a person.** A human
|
|
193
201
|
commenter verifies an email address through a magic link and that address is
|
|
194
202
|
their identity. You have no mailbox, so the publish token stands in and the
|
|
195
|
-
comment reads as `publisher`.
|
|
203
|
+
comment reads as `publisher`. Posting emails everyone following the relic,
|
|
204
|
+
naming "The publisher". Optional `display_name` puts a label beside it;
|
|
196
205
|
it decorates the attribution and never replaces it.
|
|
197
206
|
- **A comment that will not decrypt comes back marked unreadable**, with a
|
|
198
207
|
count. That is not noise to filter out: it means part of the conversation is
|
package/src/server.ts
CHANGED
|
@@ -383,7 +383,7 @@ export const REPUBLISH_TOOL_DEFINITION = {
|
|
|
383
383
|
'uploaded unencrypted for link previews; pass cover: false to withhold ' +
|
|
384
384
|
'it.' +
|
|
385
385
|
REPUBLISH_DISCIPLINE_DISCLOSURE +
|
|
386
|
-
' Each new version emails a change notice, naming the title and version and never the key, to
|
|
386
|
+
' Each new version emails a change notice, naming the title and version and never the key, to each verified commenter and each address added with relic_share, minus any that stopped emails; pass notify: false to skip it. At most one email per person per relic per 10 minutes, and one stop link stops every email about that relic.',
|
|
387
387
|
inputSchema: {
|
|
388
388
|
type: 'object',
|
|
389
389
|
properties: {
|
|
@@ -451,7 +451,7 @@ export const REPUBLISH_TOOL_DEFINITION = {
|
|
|
451
451
|
type: 'boolean',
|
|
452
452
|
default: true,
|
|
453
453
|
description:
|
|
454
|
-
'Optional. Email a change notice for this version to
|
|
454
|
+
'Optional. Email a change notice for this version to each verified address that commented on the relic and each address added with relic_share, except any that stopped those emails. Defaults to true. The notice names the title and version and never carries the key. At most one email per person per relic per 10 minutes, and one stop link stops every email about that relic. Pass false for a change not worth an email, such as a typo fix.',
|
|
455
455
|
},
|
|
456
456
|
},
|
|
457
457
|
required: ['relic_id', 'path'],
|
|
@@ -516,7 +516,7 @@ export const SHARE_TOOL_DEFINITION = {
|
|
|
516
516
|
name: SHARE_TOOL_NAME,
|
|
517
517
|
title: 'Share a relic with people',
|
|
518
518
|
description:
|
|
519
|
-
'Send a relic this machine published to named people. Registers their email addresses with the service so each gets
|
|
519
|
+
'Send a relic this machine published to named people. Registers their email addresses with the service so each gets an email notice when someone comments and when you republish, and returns a ready share email carrying the full link, plus a mailto link that opens it as a draft. Relic never sends the share email, because it carries the key: draft it in the sharer\u2019s own mailbox, from their own address, and let them send it. The service stores the addresses in the clear, linked to the relic. A change notice names the title and version, never the key. A new comment emails everyone on the list except the author, naming the commenter\u2019s 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. Only works on the machine that published the relic: the link needs its key and registering needs its publish token. Takes the relic id, never the share URL. Up to 20 addresses per call and 50 per relic.',
|
|
520
520
|
inputSchema: {
|
|
521
521
|
type: 'object',
|
|
522
522
|
properties: {
|
|
@@ -529,7 +529,8 @@ export const SHARE_TOOL_DEFINITION = {
|
|
|
529
529
|
items: { type: 'string' },
|
|
530
530
|
minItems: 1,
|
|
531
531
|
maxItems: 20,
|
|
532
|
-
description:
|
|
532
|
+
description:
|
|
533
|
+
'Up to 20 email addresses to register for comment and change notices.',
|
|
533
534
|
},
|
|
534
535
|
},
|
|
535
536
|
required: ['relic_id', 'emails'],
|
|
@@ -1210,9 +1211,14 @@ export const COMMENT_TOOL_DEFINITION = {
|
|
|
1210
1211
|
description:
|
|
1211
1212
|
'Leave a comment on a relic this machine published, encrypted here so ' +
|
|
1212
1213
|
'the service stores ciphertext it cannot read. Everyone holding the ' +
|
|
1213
|
-
'link sees it.
|
|
1214
|
-
'
|
|
1215
|
-
'
|
|
1214
|
+
'link sees it. Warning: posting emails everyone following the relic ' +
|
|
1215
|
+
'(each verified commenter, each address added with relic_share, and ' +
|
|
1216
|
+
'the owner address, minus any that used the stop link). ' +
|
|
1217
|
+
'Attribution is the publish token, so the comment is attributed to ' +
|
|
1218
|
+
'"publisher" rather than to an email address: an agent has no mailbox ' +
|
|
1219
|
+
'and cannot verify one, and the email names "The publisher". At most ' +
|
|
1220
|
+
'one email per person per relic per 10 minutes, and one stop link stops ' +
|
|
1221
|
+
'every email about that relic. That is attribution and not ' +
|
|
1216
1222
|
'authorization. ' +
|
|
1217
1223
|
'Comments can be anchored to an exact location: a text quote, a stage ' +
|
|
1218
1224
|
'pin, an artifact region, a moment or span in audio or video, or a page ' +
|
|
@@ -1558,18 +1564,20 @@ styles, scripts, fonts, and images: a CDN reference renders as nothing.
|
|
|
1558
1564
|
7. People can comment on a relic. Read with relic_read_comments before \
|
|
1559
1565
|
changing reviewed content, answer with relic_comment. relic_edit_comment \
|
|
1560
1566
|
rewrites one, relic_resolve_comment settles one, and settled counts as \
|
|
1561
|
-
handled. All take the relic id and attribute you as publisher.
|
|
1567
|
+
handled. All take the relic id and attribute you as publisher. A new \
|
|
1568
|
+
comment emails everyone on the relic's list except the author (naming \
|
|
1569
|
+
the address, or "The publisher" for relic_comment; at most once per 10 \
|
|
1570
|
+
minutes). One stop link stops every email about that relic.
|
|
1562
1571
|
8. By default relic_publish and relic_republish upload a picture of the file's \
|
|
1563
1572
|
first screen, unencrypted, for link previews: the service and anyone holding \
|
|
1564
1573
|
the link without the key can see it. Pass cover: false for anything you would \
|
|
1565
1574
|
not show in a chat preview.
|
|
1566
1575
|
9. relic_republish emails a change notice, naming the title and version but \
|
|
1567
|
-
never the key, to everyone
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
or republished the relic.`;
|
|
1576
|
+
never the key, to everyone following the relic; pass notify: false to skip \
|
|
1577
|
+
it. relic_share hands back a share email with the full link for you to draft \
|
|
1578
|
+
in the sharer's own mailbox: Relic never sends it, so the key never reaches \
|
|
1579
|
+
the service. Readers holding the link can also share from the viewer once this \
|
|
1580
|
+
client version has published or republished the relic.`;
|
|
1573
1581
|
|
|
1574
1582
|
/**
|
|
1575
1583
|
* Handle one JSON-RPC message.
|
|
@@ -1715,19 +1723,26 @@ async function callTool(
|
|
|
1715
1723
|
'ciphertext and the URL fragment is unchanged',
|
|
1716
1724
|
comment_attribution:
|
|
1717
1725
|
'the publish token, reported by the service as "publisher"; the ' +
|
|
1718
|
-
'operator learns which identity commented on which relic and when'
|
|
1726
|
+
'operator learns which identity commented on which relic and when; ' +
|
|
1727
|
+
'posting with relic_comment emails everyone following the relic, naming "The publisher"',
|
|
1728
|
+
comment_notices:
|
|
1729
|
+
'a new comment on a relic emails everyone on its list (commenters, ' +
|
|
1730
|
+
'shared addresses, the owner address) except the author, naming the ' +
|
|
1731
|
+
'commenter\u2019s address or "The publisher"; at most one email per person ' +
|
|
1732
|
+
'per relic per 10 minutes, and one stop link stops every email about that relic',
|
|
1719
1733
|
change_notices:
|
|
1720
1734
|
'on every republish unless notify: false, the service emails every ' +
|
|
1721
1735
|
'verified address that commented on the relic and every address ' +
|
|
1722
|
-
'added with relic_share, minus any that used
|
|
1723
|
-
'email names the title and version and never carries the key'
|
|
1736
|
+
'added with relic_share, minus any that used ' +
|
|
1737
|
+
'the stop link; the email names the title and version and never carries the key; ' +
|
|
1738
|
+
'at most one email per person per relic per 10 minutes, and one stop link stops every email about that relic',
|
|
1724
1739
|
sharing:
|
|
1725
1740
|
'relic_share sends the service email addresses and nothing else; ' +
|
|
1726
|
-
'it stores them in the clear, linked to the relic id
|
|
1727
|
-
'
|
|
1728
|
-
'from your own mailbox, so the key
|
|
1729
|
-
'readers holding the link can also share
|
|
1730
|
-
'relic was published or republished by this client version',
|
|
1741
|
+
'it stores them in the clear, linked to the relic id so they receive ' +
|
|
1742
|
+
'comment and change notices; the share email carrying the full link ' +
|
|
1743
|
+
'is composed here for you to send from your own mailbox, so the key ' +
|
|
1744
|
+
'never reaches the service; readers holding the link can also share ' +
|
|
1745
|
+
'from the viewer once a relic was published or republished by this client version',
|
|
1731
1746
|
service_origin: deps.serviceOrigin,
|
|
1732
1747
|
},
|
|
1733
1748
|
isError: false,
|
|
@@ -2303,7 +2318,7 @@ async function callRepublish(
|
|
|
2303
2318
|
'is no new link to hand out.\n\n' +
|
|
2304
2319
|
`${
|
|
2305
2320
|
result.notify
|
|
2306
|
-
? `Relic sends a change notice for version ${result.version} to
|
|
2321
|
+
? `Relic sends a change notice for version ${result.version} to each address that commented on this relic or was added with relic_share, except any that stopped those emails. It names the title and version and never carries the key (at most one email per recipient per relic per 10 minutes; one stop link stops every email about that relic).`
|
|
2307
2322
|
: 'No change notice goes out for this version, as asked.'
|
|
2308
2323
|
}\n\n` +
|
|
2309
2324
|
`Key phrase: ${result.key_phrase}\n` +
|
|
@@ -2375,7 +2390,7 @@ async function callShare(
|
|
|
2375
2390
|
|
|
2376
2391
|
const text =
|
|
2377
2392
|
`Registered ${result.registered.length} address(es) on relic ${result.relic_id} ` +
|
|
2378
|
-
`for change notices (${result.added} new; ${result.shared_count} of ${result.share_limit} on its list). ` +
|
|
2393
|
+
`for comment and change notices (${result.added} new; ${result.shared_count} of ${result.share_limit} on its list). ` +
|
|
2379
2394
|
'Relic has emailed nobody.\n\n' +
|
|
2380
2395
|
"Draft the email below in the sharer's own mailbox, from their own address, " +
|
|
2381
2396
|
'and let them send it. Do not send it through Relic or any other service, and ' +
|
|
@@ -2546,7 +2561,10 @@ async function callComment(
|
|
|
2546
2561
|
`Commented on relic ${result.relic_id} as ${result.author}.\n` +
|
|
2547
2562
|
'Everyone holding the link sees it. The service stored ' +
|
|
2548
2563
|
'ciphertext it cannot read, and it knows that this address ' +
|
|
2549
|
-
'commented on this relic at this time.'
|
|
2564
|
+
'commented on this relic at this time. Relic emails everyone ' +
|
|
2565
|
+
'following this relic, naming "The publisher" (at most one ' +
|
|
2566
|
+
'email per recipient per relic per 10 minutes; one stop link ' +
|
|
2567
|
+
'stops every email about that relic).',
|
|
2550
2568
|
},
|
|
2551
2569
|
],
|
|
2552
2570
|
structuredContent: result,
|
|
@@ -2984,18 +3002,23 @@ writes is attributed to the publisher rather than an email address, because
|
|
|
2984
3002
|
an agent has no mailbox to verify. What the operator does learn is who
|
|
2985
3003
|
commented on which relic and when: for a person that is a verified email
|
|
2986
3004
|
address, and that association is a real cost the content's encryption does
|
|
2987
|
-
not cover.
|
|
3005
|
+
not cover. A new comment emails everyone on the relic's list (commenters,
|
|
3006
|
+
shared addresses, and the owner address) except the author, naming the
|
|
3007
|
+
commenter's address or "The publisher" for comments this client posts.
|
|
3008
|
+
At most one email per person per relic per 10 minutes, and one stop link
|
|
3009
|
+
stops every email about that relic.
|
|
2988
3010
|
|
|
2989
3011
|
What happens with change notices and sharing: on every republish unless
|
|
2990
3012
|
notify: false, the service emails every verified address that commented on
|
|
2991
3013
|
the relic and every address added with relic_share, minus any that used the
|
|
2992
|
-
stop link. The email names the title and version and
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
3014
|
+
stop link. The email names the title and version and
|
|
3015
|
+
never carries the key. At most one email per person per relic per 10 minutes,
|
|
3016
|
+
and one stop link stops every email about that relic. relic_share sends the
|
|
3017
|
+
service email addresses and nothing else: it stores them in the clear, linked
|
|
3018
|
+
to the relic id. The share email carrying the full link is composed here on
|
|
3019
|
+
this machine for you to send from your own mailbox, so the key never reaches
|
|
3020
|
+
the service. Readers holding the link can also share from the viewer once the
|
|
3021
|
+
relic was published or republished by this client version.
|
|
2999
3022
|
|
|
3000
3023
|
What this does NOT protect against: the key is returned to your agent in the
|
|
3001
3024
|
URL, so it enters the model's context and your session transcript. That is
|