agentic-comments 0.5.1 → 0.6.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/README.md +75 -14
- package/SKILL.md +5 -1
- package/dist/{chunk-QJXI3P5D.js → chunk-6N53KQVU.js} +5 -2
- package/dist/{chunk-REFQNIEP.js → chunk-H6JK62SP.js} +1 -1
- package/dist/{chunk-NQWRFKJ6.js → chunk-T77DPNIV.js} +21 -1
- package/dist/{chunk-TFRLOBJW.js → chunk-UNJL3N2L.js} +12 -5
- package/dist/{chunk-BSNBDKR2.js → chunk-VAVKBAHM.js} +278 -6
- package/dist/cli.js +31 -8
- package/dist/client.d.ts +29 -4
- package/dist/client.js +17 -5
- package/dist/errors-C-xvp24-.d.ts +7 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +18 -3
- package/dist/local.d.ts +2 -2
- package/dist/local.js +3 -3
- package/dist/mcp-WBAHKMF4.js +11 -0
- package/dist/mcp-bin.js +6 -6
- package/dist/{service-hpWbnSmc.d.ts → service-BvIE6t5n.d.ts} +24 -1
- package/dist/{suggestions-CvJwo6r4.d.ts → suggestions-CnkEcTuY.d.ts} +128 -1
- package/dist/worker.d.ts +10 -5
- package/dist/worker.js +36 -6
- package/llms.txt +1 -0
- package/package.json +3 -3
- package/dist/errors-CNgWMVQT.d.ts +0 -7
- package/dist/mcp-XUV3RPOO.js +0 -11
|
@@ -115,6 +115,7 @@ function onlyOccurrence(type, quote) {
|
|
|
115
115
|
|
|
116
116
|
// src/principal.ts
|
|
117
117
|
import { PRINCIPAL_KINDS } from "agentic-identity";
|
|
118
|
+
var ERASED_NAME = "erased";
|
|
118
119
|
var MAX_NAME = 128;
|
|
119
120
|
var issued = /* @__PURE__ */ new WeakSet();
|
|
120
121
|
var Actor = class _Actor {
|
|
@@ -131,6 +132,7 @@ var Actor = class _Actor {
|
|
|
131
132
|
const author = readAuthor(input);
|
|
132
133
|
const given = author ? input.scopes : void 0;
|
|
133
134
|
const scopes = given === void 0 ? [] : Array.isArray(given) ? Array.from(given) : void 0;
|
|
135
|
+
if (author?.name === ERASED_NAME) throw new CommentsError("INVALID_AUTHOR", `the name "${ERASED_NAME}" is kept for erased authors`);
|
|
134
136
|
if (!author || !scopes || !scopes.every((s) => typeof s === "string" && s !== "")) {
|
|
135
137
|
throw new CommentsError("INVALID_AUTHOR", `an author needs a kind (${PRINCIPAL_KINDS.join(", ")}), a name, and scopes that are a list of text`);
|
|
136
138
|
}
|
|
@@ -187,7 +189,7 @@ var MAX_SUMMARY = 1e3;
|
|
|
187
189
|
var SUGGESTIONS = "comments.suggestions";
|
|
188
190
|
var APPLIED = "comments.suggestion-applied";
|
|
189
191
|
var REJECTED = "comments.suggestion-rejected";
|
|
190
|
-
var decidesOwn = (author, decider) => author.kind !== "human" && decider.kind !== "human" && author.name === decider.name;
|
|
192
|
+
var decidesOwn = (author, decider) => author.name !== ERASED_NAME && author.kind !== "human" && decider.kind !== "human" && author.name === decider.name;
|
|
191
193
|
var clientOf = (text) => /^(0|[1-9]\d{0,9})$/.test(text) && Number(text) <= 4294967295 ? Number(text) : void 0;
|
|
192
194
|
var thenable = (value) => typeof value?.then === "function";
|
|
193
195
|
var Suggestions = class {
|
|
@@ -308,6 +310,66 @@ var Suggestions = class {
|
|
|
308
310
|
if (typeof id2 !== "string" || !ID.test(id2) || !this.map.has(id2)) throw new CommentsError("NO_SUGGESTION", `no suggestion with id ${shown(id2)}`);
|
|
309
311
|
return { id: id2, fields: this.map.get(id2) };
|
|
310
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* The suggestions a person wrote, and the decisions they made, in this document. `unread` counts stored
|
|
315
|
+
* suggestions and decision records with their name that this export cannot show: a suggestion that cannot
|
|
316
|
+
* be read, a decision that lost a merge, a refused decision, or a decision with no suggestion. When it is not
|
|
317
|
+
* 0 the export is not complete. A person may export their own data.
|
|
318
|
+
*/
|
|
319
|
+
exportPerson(person, actor) {
|
|
320
|
+
const { match } = this.comments.checkPerson(person, actor);
|
|
321
|
+
const all = this.list();
|
|
322
|
+
const authored = all.filter((s) => match(s.author));
|
|
323
|
+
const decided = all.flatMap((s) => s.decidedBy && s.decidedAt && s.status !== "pending" && match(s.decidedBy) ? [{ id: s.id, status: s.status, at: s.decidedAt }] : []);
|
|
324
|
+
let found = 0;
|
|
325
|
+
for (const fields of this.map.values()) if (fields instanceof Y2.Map && this.named(fields.get("author"), match)) found++;
|
|
326
|
+
for (const map of [this.applied, this.rejected]) for (const raw of map.values()) if (this.named(raw?.by, match)) found++;
|
|
327
|
+
return { authored, decided, unread: Math.max(0, found - authored.length - decided.length) };
|
|
328
|
+
}
|
|
329
|
+
named(value, match) {
|
|
330
|
+
const author = readAuthor(value);
|
|
331
|
+
return author !== void 0 && match(author);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Give every suggestion a person wrote a tombstone author and drop its summary. An accepted one keeps its
|
|
335
|
+
* change, because that change is already part of the content. A pending or rejected one loses its change, and
|
|
336
|
+
* can no longer be accepted. A decision they made gets a tombstone decider. A decision that a read refuses (a
|
|
337
|
+
* principal that decided its own work) is deleted, so erase never turns it into a valid one. Returns how many
|
|
338
|
+
* suggestions and decisions it changed.
|
|
339
|
+
*/
|
|
340
|
+
erasePerson(person, actor) {
|
|
341
|
+
const { match } = this.comments.checkPerson(person, actor);
|
|
342
|
+
const out = { suggestions: 0, decisions: 0 };
|
|
343
|
+
const authors = /* @__PURE__ */ new Map();
|
|
344
|
+
for (const [id2, fields] of this.map.entries()) {
|
|
345
|
+
const author = fields instanceof Y2.Map ? readAuthor(fields.get("author")) : void 0;
|
|
346
|
+
if (author) authors.set(id2, author);
|
|
347
|
+
}
|
|
348
|
+
const status = new Map(this.list().map((s) => [s.id, s.status]));
|
|
349
|
+
this.ydoc.transact(() => {
|
|
350
|
+
for (const map of [this.applied, this.rejected]) {
|
|
351
|
+
for (const [key2, raw] of [...map.entries()]) {
|
|
352
|
+
const by = readAuthor(raw?.by);
|
|
353
|
+
const author = authors.get(key2.slice(0, key2.lastIndexOf(":")));
|
|
354
|
+
if (!by || !(match(by) || author && match(author))) continue;
|
|
355
|
+
if (author && decidesOwn(author, by)) map.delete(key2);
|
|
356
|
+
else if (match(by)) {
|
|
357
|
+
map.set(key2, { ...raw, by: { kind: by.kind, name: ERASED_NAME } });
|
|
358
|
+
out.decisions++;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (const [id2, author] of authors) {
|
|
363
|
+
if (!match(author)) continue;
|
|
364
|
+
const fields = this.map.get(id2);
|
|
365
|
+
fields.set("author", { kind: author.kind, name: ERASED_NAME });
|
|
366
|
+
fields.delete("summary");
|
|
367
|
+
if (status.get(id2) !== "accepted") fields.set("change", null);
|
|
368
|
+
out.suggestions++;
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
return out;
|
|
372
|
+
}
|
|
311
373
|
/** Propose a change. Anyone can suggest. The host stamps the author. */
|
|
312
374
|
add(input, actor) {
|
|
313
375
|
const who = assertActor(actor);
|
|
@@ -335,6 +397,7 @@ var Suggestions = class {
|
|
|
335
397
|
mayDecide(who, s, verb) {
|
|
336
398
|
const ok = !decidesOwn(s.author, who) && (who.kind === "human" || who.scopes.includes(ACCEPT_SCOPE));
|
|
337
399
|
if (!ok) throw new CommentsError("FORBIDDEN", `${who.kind}:${shown(who.name)} cannot ${verb} this suggestion: a signed-in person, or a principal with the ${ACCEPT_SCOPE} scope that did not write it, can`);
|
|
400
|
+
if (verb === "accept" && s.author.name === ERASED_NAME && s.status !== "accepted") throw new CommentsError("FORBIDDEN", "an erased suggestion has no change left and cannot be accepted");
|
|
338
401
|
}
|
|
339
402
|
/**
|
|
340
403
|
* Apply the change as the accepting author and record the decision, in one step. Accepting an
|
|
@@ -461,6 +524,8 @@ var Suggestions = class {
|
|
|
461
524
|
|
|
462
525
|
// src/threads.ts
|
|
463
526
|
import * as Y3 from "yjs";
|
|
527
|
+
var MODERATE_SCOPE = "comments:moderate";
|
|
528
|
+
var ERASED_BODY = "[erased]";
|
|
464
529
|
var THREADS = "comments.threads";
|
|
465
530
|
var MAX_BODY = 1e4;
|
|
466
531
|
var MAX_MENTIONS = 50;
|
|
@@ -605,7 +670,20 @@ var Comments = class {
|
|
|
605
670
|
throw new Error("a message has no id, ISO time, valid author, or body");
|
|
606
671
|
}
|
|
607
672
|
if (!Array.isArray(m.mentions) || m.mentions.length > MAX_MENTIONS || !m.mentions.every(validHandle)) throw new Error("a message has bad mentions");
|
|
608
|
-
|
|
673
|
+
const editor = m.editedBy === void 0 ? void 0 : readAuthor(m.editedBy);
|
|
674
|
+
if (m.editedAt === void 0 !== (m.editedBy === void 0) || m.editedAt !== void 0 && !validDate(m.editedAt) || m.editedBy !== void 0 && !editor) {
|
|
675
|
+
throw new Error("a message has a bad edit stamp");
|
|
676
|
+
}
|
|
677
|
+
if (m.erased !== void 0 && (m.erased !== true || m.body !== ERASED_BODY || author.name !== ERASED_NAME || m.mentions.length > 0)) throw new Error("a message has a bad erased flag");
|
|
678
|
+
return {
|
|
679
|
+
id: m.id,
|
|
680
|
+
at: m.at,
|
|
681
|
+
author,
|
|
682
|
+
body: m.body,
|
|
683
|
+
mentions: [...m.mentions],
|
|
684
|
+
...editor ? { editedAt: m.editedAt, editedBy: editor } : {},
|
|
685
|
+
...m.erased ? { erased: true } : {}
|
|
686
|
+
};
|
|
609
687
|
}
|
|
610
688
|
/** A thread with a bad anchor or status is malformed. A bad message is skipped and named in `issues`. */
|
|
611
689
|
read(id2, fields) {
|
|
@@ -622,11 +700,32 @@ var Comments = class {
|
|
|
622
700
|
const raw = list.toArray();
|
|
623
701
|
const counts = /* @__PURE__ */ new Map();
|
|
624
702
|
for (const m of raw) counts.set(m?.id, (counts.get(m?.id) ?? 0) + 1);
|
|
703
|
+
const parsed = raw.map((entry) => {
|
|
704
|
+
try {
|
|
705
|
+
return { message: this.readMessage(entry) };
|
|
706
|
+
} catch (error) {
|
|
707
|
+
return { error };
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
const copies = (id3) => parsed.flatMap((p) => p.message?.id === id3 ? [p.message] : []);
|
|
625
711
|
let past = 0;
|
|
626
|
-
|
|
712
|
+
let superseded = 0;
|
|
713
|
+
parsed.forEach((entry, index) => {
|
|
627
714
|
try {
|
|
628
|
-
|
|
629
|
-
|
|
715
|
+
if (entry.error) throw entry.error;
|
|
716
|
+
const message = entry.message;
|
|
717
|
+
if (counts.get(message.id) > 1) {
|
|
718
|
+
const same = copies(message.id);
|
|
719
|
+
const names = new Set(same.filter((c) => !c.erased).map((c) => c.author.name));
|
|
720
|
+
const agree = same.every((c) => c.editedAt !== void 0 && c.at === message.at && c.author.kind === message.author.kind) && names.size <= 1;
|
|
721
|
+
if (same.length !== counts.get(message.id) || !agree) throw new Error("a message id repeats");
|
|
722
|
+
const rank = (c) => `${c.erased ? 1 : 0}${c.editedAt}${JSON.stringify(c)}`;
|
|
723
|
+
const best = same.reduce((a, b) => rank(b) > rank(a) ? b : a);
|
|
724
|
+
if (best !== message) {
|
|
725
|
+
superseded++;
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
630
729
|
if (messages.length >= READ_LIMIT) past++;
|
|
631
730
|
else messages.push(message);
|
|
632
731
|
} catch (error) {
|
|
@@ -636,7 +735,7 @@ var Comments = class {
|
|
|
636
735
|
if (past > 0) issues.push(`${past} valid messages past the read limit are not shown`);
|
|
637
736
|
if (messages.length === 0) throw new Error("the thread has no valid message");
|
|
638
737
|
const anchor = this.parseAnchor(fields.get("anchor"));
|
|
639
|
-
const thread = { id: id2, anchor, anchorState: this.anchorState(anchor), status: state.status, statusBy: by, statusAt: state.at, messages, skipped: raw.length - messages.length };
|
|
738
|
+
const thread = { id: id2, anchor, anchorState: this.anchorState(anchor), status: state.status, statusBy: by, statusAt: state.at, messages, skipped: raw.length - messages.length - superseded };
|
|
640
739
|
return { thread, issues };
|
|
641
740
|
} catch (error) {
|
|
642
741
|
throw new CommentsError("CORRUPT", `thread ${shown(id2)} is malformed: ${safeText(error instanceof Error ? error.message : error)}`);
|
|
@@ -715,6 +814,176 @@ var Comments = class {
|
|
|
715
814
|
reopen(threadId, actor) {
|
|
716
815
|
return this.setStatus(threadId, "open", actor);
|
|
717
816
|
}
|
|
817
|
+
/** A principal may change what it wrote. A principal with the moderate scope may change what anyone wrote. A tombstone is nobody's. */
|
|
818
|
+
mayChange(who, message) {
|
|
819
|
+
return who.scopes.includes(MODERATE_SCOPE) || !message.erased && who.kind === message.author.kind && who.name === message.author.name;
|
|
820
|
+
}
|
|
821
|
+
forbid(who, what) {
|
|
822
|
+
throw new CommentsError("FORBIDDEN", `${who.kind}:${shown(who.name)} cannot ${what}: only its author, or a principal with the ${MODERATE_SCOPE} scope, can`);
|
|
823
|
+
}
|
|
824
|
+
/** Replace every stored copy of a message with `next`, or remove it when `next` is undefined. */
|
|
825
|
+
rewrite(fields, messageId, next) {
|
|
826
|
+
const list = fields.get("messages");
|
|
827
|
+
const at = list.toArray().flatMap((m, i) => m?.id === messageId ? [i] : []);
|
|
828
|
+
this.ydoc.transact(() => {
|
|
829
|
+
for (const i of [...at].reverse()) list.delete(i, 1);
|
|
830
|
+
if (next) list.insert(at[0], [copy(next)]);
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
find(threadId, messageId) {
|
|
834
|
+
const { id: id2, fields } = this.fields(threadId);
|
|
835
|
+
const { thread } = this.read(id2, fields);
|
|
836
|
+
const message = thread.messages.find((m) => m.id === messageId);
|
|
837
|
+
if (!message) throw new CommentsError("NO_MESSAGE", `thread ${shown(id2)} has no message with id ${shown(messageId)}`);
|
|
838
|
+
return { id: id2, fields, thread, message };
|
|
839
|
+
}
|
|
840
|
+
/** Change the body of a message. Its author and time stay, and it records who edited it and when. */
|
|
841
|
+
editMessage(threadId, messageId, input, actor) {
|
|
842
|
+
const who = assertActor(actor);
|
|
843
|
+
const given = exact(input, ["body", "mentions"], "an edit");
|
|
844
|
+
const text = body(given.body);
|
|
845
|
+
const { id: id2, fields, thread, message } = this.find(threadId, messageId);
|
|
846
|
+
if (message.erased) throw new CommentsError("FORBIDDEN", "an erased message cannot be edited");
|
|
847
|
+
if (!this.mayChange(who, message)) this.forbid(who, "edit this message");
|
|
848
|
+
if (thread.status === "resolved") throw new CommentsError("THREAD_RESOLVED", `thread ${shown(id2)} is resolved; reopen it to edit`);
|
|
849
|
+
const next = this.readEdited(message, text, given.mentions, who);
|
|
850
|
+
this.rewrite(fields, message.id, next);
|
|
851
|
+
return this.find(id2, message.id).message;
|
|
852
|
+
}
|
|
853
|
+
readEdited(message, text, explicit, who) {
|
|
854
|
+
const edited = { ...message, body: text, mentions: mentionsOf(text, explicit), editedAt: this.time(), editedBy: { kind: who.kind, name: who.name } };
|
|
855
|
+
try {
|
|
856
|
+
return this.readMessage(copy(edited));
|
|
857
|
+
} catch (error) {
|
|
858
|
+
return invalid(`the message cannot be stored: ${error.message}`);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Remove one message, also from a resolved thread. The last message of a thread stays: delete the thread instead. Replicas that delete
|
|
863
|
+
* two messages at once can leave a thread with none. A moderator can still delete that thread.
|
|
864
|
+
*/
|
|
865
|
+
deleteMessage(threadId, messageId, actor) {
|
|
866
|
+
const who = assertActor(actor);
|
|
867
|
+
const { id: id2, fields, thread, message } = this.find(threadId, messageId);
|
|
868
|
+
if (!this.mayChange(who, message)) this.forbid(who, "delete this message");
|
|
869
|
+
if (thread.messages.length === 1) invalid(`thread ${shown(id2)} has only this message; delete the thread instead`);
|
|
870
|
+
this.rewrite(fields, message.id, void 0);
|
|
871
|
+
return { threadId: id2, messageId: message.id };
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Remove a thread and all its messages. Its author may do it when every message is theirs. Once someone
|
|
875
|
+
* else replied, a message is erased, or a stored message cannot be read, it needs the moderate scope. A
|
|
876
|
+
* moderator can also remove a thread that cannot be read at all.
|
|
877
|
+
*/
|
|
878
|
+
deleteThread(threadId, actor) {
|
|
879
|
+
const who = assertActor(actor);
|
|
880
|
+
const { id: id2, fields } = this.fields(threadId);
|
|
881
|
+
if (!who.scopes.includes(MODERATE_SCOPE)) {
|
|
882
|
+
const { thread } = this.read(id2, fields);
|
|
883
|
+
if (thread.skipped > 0 || !thread.messages.every((m) => this.mayChange(who, m))) this.forbid(who, "delete this thread");
|
|
884
|
+
}
|
|
885
|
+
this.map.delete(id2);
|
|
886
|
+
return { threadId: id2 };
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Check who an export or erase is for, and that the actor may. A person may act on their own data: the same
|
|
890
|
+
* kind and name. A principal with the moderate scope may act on anyone's, and then every kind with that name is
|
|
891
|
+
* included. Returns the name and a test for an author. Used by `Suggestions`.
|
|
892
|
+
*/
|
|
893
|
+
checkPerson(person, actor) {
|
|
894
|
+
const who = assertActor(actor);
|
|
895
|
+
if (typeof person !== "string" || person === "" || person !== person.trim() || person.length > 128) invalid("a person is a name of 1 to 128 characters");
|
|
896
|
+
if (person === ERASED_NAME) invalid("a tombstone is not a person");
|
|
897
|
+
const moderator = who.scopes.includes(MODERATE_SCOPE);
|
|
898
|
+
if (who.name !== person && !moderator) {
|
|
899
|
+
throw new CommentsError("FORBIDDEN", `${who.kind}:${shown(who.name)} cannot read or erase the data of another person without the ${MODERATE_SCOPE} scope`);
|
|
900
|
+
}
|
|
901
|
+
return { name: person, match: (a) => a.name === person && (moderator || a.kind === who.kind) };
|
|
902
|
+
}
|
|
903
|
+
/** The raw stored threads, for the code that must see data a read hides. `list` is missing when the message field is bad. */
|
|
904
|
+
stored() {
|
|
905
|
+
return [...this.map.entries()].flatMap(([id2, fields]) => fields instanceof Y3.Map ? [{ id: id2, fields, list: fields.get("messages") instanceof Y3.Array ? fields.get("messages") : void 0 }] : []);
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* What a person wrote in this document: their messages, the status change of theirs that stands, and the
|
|
909
|
+
* edits they made to other people's messages. `unread` counts stored entries with their name that this read
|
|
910
|
+
* cannot show: a bad message, a thread that cannot be read, a message past the read limit, or a copy that
|
|
911
|
+
* lost a merge. When it is not 0 the export is not complete. A person may export their own data.
|
|
912
|
+
*/
|
|
913
|
+
exportPerson(person, actor) {
|
|
914
|
+
const { name, match } = this.checkPerson(person, actor);
|
|
915
|
+
const threads = [];
|
|
916
|
+
const edits = [];
|
|
917
|
+
let shownCount = 0;
|
|
918
|
+
for (const thread of this.list()) {
|
|
919
|
+
const messages = thread.messages.filter((m) => match(m.author));
|
|
920
|
+
shownCount += messages.length;
|
|
921
|
+
const status = match(thread.statusBy);
|
|
922
|
+
if (status) shownCount++;
|
|
923
|
+
for (const m of thread.messages) if (m.editedBy && match(m.editedBy) && !match(m.author)) edits.push({ threadId: thread.id, messageId: m.id, at: m.editedAt });
|
|
924
|
+
if (messages.length === 0 && !status) continue;
|
|
925
|
+
threads.push({
|
|
926
|
+
threadId: thread.id,
|
|
927
|
+
anchor: copy(thread.anchor),
|
|
928
|
+
messages: copy(messages),
|
|
929
|
+
...status ? { statusChange: { status: thread.status, at: thread.statusAt, by: copy(thread.statusBy) } } : {}
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
let found = 0;
|
|
933
|
+
const named = (value) => {
|
|
934
|
+
const author = readAuthor(value);
|
|
935
|
+
return author !== void 0 && match(author);
|
|
936
|
+
};
|
|
937
|
+
for (const { fields, list } of this.stored()) {
|
|
938
|
+
for (const raw of list?.toArray() ?? []) if (named(raw?.author) || named(raw?.editedBy)) found++;
|
|
939
|
+
if (named(fields.get("state")?.by)) found++;
|
|
940
|
+
}
|
|
941
|
+
return { person: name, exportedAt: this.time(), threads, edits, unread: Math.max(0, found - shownCount - edits.length) };
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Replace every message a person wrote with a tombstone: the body becomes "[erased]", the author name
|
|
945
|
+
* becomes "erased", and the mentions go. The author kind stays, so machine-made work stays marked. Thread
|
|
946
|
+
* shape, order, and times stay. A status change of theirs, and their name as the editor of another person's
|
|
947
|
+
* message, get the tombstone name. It works on the stored entries, so it reaches a bad message, a message past
|
|
948
|
+
* the read limit, a thread that cannot be read, and every copy that a merge hid. Names inside other people's
|
|
949
|
+
* messages are not touched. Returns how many messages, status changes, and edit stamps it erased.
|
|
950
|
+
*/
|
|
951
|
+
erasePerson(person, actor) {
|
|
952
|
+
const { match } = this.checkPerson(person, actor);
|
|
953
|
+
const tomb = (a) => ({ kind: a.kind, name: ERASED_NAME });
|
|
954
|
+
const out = { messages: 0, statuses: 0, edits: 0 };
|
|
955
|
+
this.ydoc.transact(() => {
|
|
956
|
+
for (const { fields, list } of this.stored()) {
|
|
957
|
+
const entries = list?.toArray() ?? [];
|
|
958
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
959
|
+
const raw = entries[i];
|
|
960
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
961
|
+
const author = readAuthor(raw.author);
|
|
962
|
+
const editor = readAuthor(raw.editedBy);
|
|
963
|
+
let next;
|
|
964
|
+
if (author && match(author)) {
|
|
965
|
+
const id2 = typeof raw.id === "string" && ID.test(raw.id) ? raw.id : globalThis.crypto.randomUUID();
|
|
966
|
+
const at = validDate(raw.at) ? raw.at : this.time();
|
|
967
|
+
next = { id: id2, at, author: tomb(author), body: ERASED_BODY, mentions: [], editedAt: this.time(), editedBy: tomb(author), erased: true };
|
|
968
|
+
out.messages++;
|
|
969
|
+
} else if (editor && match(editor)) {
|
|
970
|
+
next = { ...raw, editedBy: tomb(editor) };
|
|
971
|
+
out.edits++;
|
|
972
|
+
}
|
|
973
|
+
if (!next) continue;
|
|
974
|
+
list.delete(i, 1);
|
|
975
|
+
list.insert(i, [next]);
|
|
976
|
+
}
|
|
977
|
+
const state = fields.get("state");
|
|
978
|
+
const by = readAuthor(state?.by);
|
|
979
|
+
if (state && by && match(by)) {
|
|
980
|
+
fields.set("state", { ...state, by: tomb(by) });
|
|
981
|
+
out.statuses++;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
return out;
|
|
986
|
+
}
|
|
718
987
|
get(threadId) {
|
|
719
988
|
const { id: id2, fields } = this.fields(threadId);
|
|
720
989
|
return this.read(id2, fields).thread;
|
|
@@ -755,6 +1024,7 @@ export {
|
|
|
755
1024
|
textAnchor,
|
|
756
1025
|
textRange,
|
|
757
1026
|
PRINCIPAL_KINDS,
|
|
1027
|
+
ERASED_NAME,
|
|
758
1028
|
Actor,
|
|
759
1029
|
stamp,
|
|
760
1030
|
readAuthor,
|
|
@@ -764,5 +1034,7 @@ export {
|
|
|
764
1034
|
validDate,
|
|
765
1035
|
ACCEPT_SCOPE,
|
|
766
1036
|
Suggestions,
|
|
1037
|
+
MODERATE_SCOPE,
|
|
1038
|
+
ERASED_BODY,
|
|
767
1039
|
Comments
|
|
768
1040
|
};
|
package/dist/cli.js
CHANGED
|
@@ -3,17 +3,17 @@ import {
|
|
|
3
3
|
FileStore,
|
|
4
4
|
lockTimeoutFrom,
|
|
5
5
|
operatorActor
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-6N53KQVU.js";
|
|
7
7
|
import {
|
|
8
8
|
VERSION
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-H6JK62SP.js";
|
|
10
10
|
import {
|
|
11
11
|
CommentsService,
|
|
12
12
|
TEXT_ROOT
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-T77DPNIV.js";
|
|
14
14
|
import {
|
|
15
15
|
CommentsError
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-VAVKBAHM.js";
|
|
17
17
|
|
|
18
18
|
// src/cli.ts
|
|
19
19
|
import { readFileSync, realpathSync } from "fs";
|
|
@@ -24,6 +24,7 @@ var FLAGS = {
|
|
|
24
24
|
"--file": "value",
|
|
25
25
|
"--as": "value",
|
|
26
26
|
"--body": "value",
|
|
27
|
+
"--message": "value",
|
|
27
28
|
"--mention": "many",
|
|
28
29
|
"--text-quote": "value",
|
|
29
30
|
"--occurrence": "value",
|
|
@@ -50,19 +51,26 @@ var ALLOWED = {
|
|
|
50
51
|
resolve: SHARED,
|
|
51
52
|
reopen: SHARED,
|
|
52
53
|
relocate: SHARED,
|
|
54
|
+
"edit-message": [...SHARED, "--message", "--body", "--mention"],
|
|
55
|
+
"delete-message": [...SHARED, "--message"],
|
|
56
|
+
"delete-thread": SHARED,
|
|
57
|
+
"export-person": SHARED,
|
|
58
|
+
"erase-person": SHARED,
|
|
53
59
|
suggestions: [...SHARED, "--status", "--anchor-state"],
|
|
54
60
|
suggest: [...SHARED, ...ANCHOR, "--replace", "--value", "--summary"],
|
|
55
61
|
accept: SHARED,
|
|
56
62
|
reject: SHARED,
|
|
57
63
|
mcp: SHARED
|
|
58
64
|
};
|
|
59
|
-
var TAKES_ID = ["show", "reply", "resolve", "reopen", "relocate", "accept", "reject"];
|
|
60
|
-
var COMMANDS = ["init", "list", "show", "comment", "reply", "resolve", "reopen", "relocate", "suggestions", "suggest", "accept", "reject", "mcp"];
|
|
65
|
+
var TAKES_ID = ["show", "reply", "resolve", "reopen", "relocate", "accept", "reject", "edit-message", "delete-message", "delete-thread", "export-person", "erase-person"];
|
|
66
|
+
var COMMANDS = ["init", "list", "show", "comment", "reply", "resolve", "reopen", "relocate", "edit-message", "delete-message", "delete-thread", "export-person", "erase-person", "suggestions", "suggest", "accept", "reject", "mcp"];
|
|
61
67
|
function parseArgs(argv) {
|
|
62
68
|
const [command, ...rest] = argv;
|
|
63
69
|
if (command === void 0 || command === "--help" || command === "-h") return { command: "help", flags: {}, many: {} };
|
|
64
70
|
if (command === "--version" || command === "-V") return { command: "version", flags: {}, many: {} };
|
|
65
71
|
if (!COMMANDS.includes(command)) throw new UsageError(`unknown command "${command}"`);
|
|
72
|
+
if (command === "mcp" && rest.some((a) => a === "--help" || a === "-h")) return { command: "help", flags: {}, many: {} };
|
|
73
|
+
if (command === "mcp" && rest.some((a) => a === "--version" || a === "-V" || a === "-v")) return { command: "version", flags: {}, many: {} };
|
|
66
74
|
const parsed = { command, flags: {}, many: {} };
|
|
67
75
|
for (let i = 0; i < rest.length; i++) {
|
|
68
76
|
const arg = rest[i];
|
|
@@ -112,6 +120,15 @@ function need(p) {
|
|
|
112
120
|
if (p.id === void 0) throw new UsageError(`${p.command} needs an id`);
|
|
113
121
|
return p.id;
|
|
114
122
|
}
|
|
123
|
+
function needName(p) {
|
|
124
|
+
if (p.id === void 0) throw new UsageError(`${p.command} needs the name of a person`);
|
|
125
|
+
return p.id;
|
|
126
|
+
}
|
|
127
|
+
function flag(p, name) {
|
|
128
|
+
const value = p.flags[name];
|
|
129
|
+
if (value === void 0) throw new UsageError(`${p.command} needs ${name}`);
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
115
132
|
var HELP = `agentic-comments ${VERSION}
|
|
116
133
|
Comment threads and suggestions anchored to any content, from people and agents.
|
|
117
134
|
|
|
@@ -121,6 +138,7 @@ Setup:
|
|
|
121
138
|
--file <path> The store file. Or AGENTIC_COMMENTS_FILE. Default ./comments.ydoc.
|
|
122
139
|
--as <kind:name> Who acts. Or AGENTIC_COMMENTS_AS. Kinds: human, agent_of_human, agent_of_agent, agent, user_token.
|
|
123
140
|
Scopes come only from AGENTIC_COMMENTS_SCOPES, a comma list such as comments:accept.
|
|
141
|
+
Another person's message, thread, or data needs comments:moderate.
|
|
124
142
|
|
|
125
143
|
Commands:
|
|
126
144
|
init [--text <t> | --text-file <p>] Create the store.
|
|
@@ -129,6 +147,11 @@ Commands:
|
|
|
129
147
|
comment <anchor> --body <t> [--mention h] Start a thread.
|
|
130
148
|
reply <id> --body <t> [--mention h] Reply.
|
|
131
149
|
resolve <id> | reopen <id> | relocate <id>
|
|
150
|
+
edit-message <id> --message <mid> --body <t> [--mention h] Change a message you wrote.
|
|
151
|
+
delete-message <id> --message <mid> Delete a message you wrote.
|
|
152
|
+
delete-thread <id> Delete a thread. Needs every message to be yours.
|
|
153
|
+
export-person <name> Export what a person wrote.
|
|
154
|
+
erase-person <name> Replace what a person wrote with a tombstone.
|
|
132
155
|
suggestions [--status s] [--anchor-state s] List suggestions.
|
|
133
156
|
suggest <anchor> (--replace <t> | --value <json>) [--summary <t>]
|
|
134
157
|
accept <id> | reject <id>
|
|
@@ -155,7 +178,7 @@ async function runCli(argv, io) {
|
|
|
155
178
|
return 0;
|
|
156
179
|
}
|
|
157
180
|
if (p.command === "mcp") {
|
|
158
|
-
const { startMcp } = await import("./mcp-
|
|
181
|
+
const { startMcp } = await import("./mcp-WBAHKMF4.js");
|
|
159
182
|
await startMcp(store, operatorActor(p.flags["--as"] ?? io.env.AGENTIC_COMMENTS_AS, io.env.AGENTIC_COMMENTS_SCOPES));
|
|
160
183
|
return 0;
|
|
161
184
|
}
|
|
@@ -163,7 +186,7 @@ async function runCli(argv, io) {
|
|
|
163
186
|
const mentions = p.many["--mention"];
|
|
164
187
|
const filter = { status: p.flags["--status"], anchorState: p.flags["--anchor-state"], mentioning: p.flags["--mentioning"] };
|
|
165
188
|
const clean = Object.fromEntries(Object.entries(filter).filter(([, v]) => v !== void 0));
|
|
166
|
-
const result = p.command === "list" ? service.threads(clean) : p.command === "show" ? service.thread(need(p)) : p.command === "comment" ? service.comment({ anchor: anchorOf(p), body: p.flags["--body"], ...mentions ? { mentions } : {} }) : p.command === "reply" ? service.reply(need(p), { body: p.flags["--body"], ...mentions ? { mentions } : {} }) : p.command === "resolve" ? service.resolve(need(p)) : p.command === "reopen" ? service.reopen(need(p)) : p.command === "relocate" ? service.relocate(need(p)) : p.command === "suggestions" ? service.suggestions(Object.fromEntries(Object.entries(clean).filter(([k]) => k !== "mentioning"))) : p.command === "suggest" ? service.suggest({ anchor: anchorOf(p), change: changeOf(p), ...p.flags["--summary"] === void 0 ? {} : { summary: p.flags["--summary"] } }) : p.command === "accept" ? service.accept(need(p)) : service.reject(need(p));
|
|
189
|
+
const result = p.command === "list" ? service.threads(clean) : p.command === "show" ? service.thread(need(p)) : p.command === "comment" ? service.comment({ anchor: anchorOf(p), body: p.flags["--body"], ...mentions ? { mentions } : {} }) : p.command === "reply" ? service.reply(need(p), { body: p.flags["--body"], ...mentions ? { mentions } : {} }) : p.command === "edit-message" ? service.editMessage(need(p), flag(p, "--message"), { body: p.flags["--body"], ...mentions ? { mentions } : {} }) : p.command === "delete-message" ? service.deleteMessage(need(p), flag(p, "--message")) : p.command === "delete-thread" ? service.deleteThread(need(p)) : p.command === "export-person" ? service.exportPerson(needName(p)) : p.command === "erase-person" ? service.erasePerson(needName(p)) : p.command === "resolve" ? service.resolve(need(p)) : p.command === "reopen" ? service.reopen(need(p)) : p.command === "relocate" ? service.relocate(need(p)) : p.command === "suggestions" ? service.suggestions(Object.fromEntries(Object.entries(clean).filter(([k]) => k !== "mentioning"))) : p.command === "suggest" ? service.suggest({ anchor: anchorOf(p), change: changeOf(p), ...p.flags["--summary"] === void 0 ? {} : { summary: p.flags["--summary"] } }) : p.command === "accept" ? service.accept(need(p)) : service.reject(need(p));
|
|
167
190
|
io.out(JSON.stringify(result));
|
|
168
191
|
return 0;
|
|
169
192
|
} catch (error) {
|
package/dist/client.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { L as ListFilter, A as AnchorSpec } from './service-
|
|
2
|
-
import { C as CommentsErrorCode } from './errors-
|
|
1
|
+
import { L as ListFilter, A as AnchorSpec } from './service-BvIE6t5n.js';
|
|
2
|
+
import { C as CommentsErrorCode } from './errors-C-xvp24-.js';
|
|
3
3
|
import { PrincipalKind } from 'agentic-identity';
|
|
4
4
|
export { PrincipalKind } from 'agentic-identity';
|
|
5
|
-
import { T as Thread, N as NewReply, M as Message, S as Suggestion } from './suggestions-
|
|
5
|
+
import { T as Thread, N as NewReply, M as Message, P as PersonExport, a as PersonSuggestions, S as Suggestion } from './suggestions-CnkEcTuY.js';
|
|
6
6
|
import 'yjs';
|
|
7
7
|
|
|
8
8
|
/** Codes the comment rules return, plus the ones the Worker and its auth return. */
|
|
@@ -35,6 +35,18 @@ interface Me {
|
|
|
35
35
|
}
|
|
36
36
|
type ThreadFilter = ListFilter;
|
|
37
37
|
type SuggestionListFilter = Pick<ListFilter, "status" | "anchorState">;
|
|
38
|
+
/** What `exportPerson` returns: the messages and status changes of one person, and their suggestions. */
|
|
39
|
+
type PersonData = PersonExport & {
|
|
40
|
+
suggestions: PersonSuggestions;
|
|
41
|
+
};
|
|
42
|
+
/** What `erasePerson` changed in one document. */
|
|
43
|
+
interface Erased {
|
|
44
|
+
messages: number;
|
|
45
|
+
statuses: number;
|
|
46
|
+
edits: number;
|
|
47
|
+
suggestions: number;
|
|
48
|
+
decisions: number;
|
|
49
|
+
}
|
|
38
50
|
interface CommentsClient {
|
|
39
51
|
me(options?: CallOptions): Promise<Me>;
|
|
40
52
|
createDocument(input: {
|
|
@@ -58,6 +70,19 @@ interface CommentsClient {
|
|
|
58
70
|
resolve(docId: string, threadId: string, options?: CallOptions): Promise<Thread>;
|
|
59
71
|
reopen(docId: string, threadId: string, options?: CallOptions): Promise<Thread>;
|
|
60
72
|
relocate(docId: string, threadId: string, options?: CallOptions): Promise<Thread>;
|
|
73
|
+
editMessage(docId: string, threadId: string, messageId: string, input: {
|
|
74
|
+
body: string;
|
|
75
|
+
mentions?: string[];
|
|
76
|
+
}, options?: CallOptions): Promise<Message>;
|
|
77
|
+
deleteMessage(docId: string, threadId: string, messageId: string, options?: CallOptions): Promise<{
|
|
78
|
+
threadId: string;
|
|
79
|
+
messageId: string;
|
|
80
|
+
}>;
|
|
81
|
+
deleteThread(docId: string, threadId: string, options?: CallOptions): Promise<{
|
|
82
|
+
threadId: string;
|
|
83
|
+
}>;
|
|
84
|
+
exportPerson(docId: string, person: string, options?: CallOptions): Promise<PersonData>;
|
|
85
|
+
erasePerson(docId: string, person: string, options?: CallOptions): Promise<Erased>;
|
|
61
86
|
listSuggestions(docId: string, filter?: SuggestionListFilter, options?: CallOptions): Promise<Suggestion[]>;
|
|
62
87
|
suggest(docId: string, input: {
|
|
63
88
|
anchor: AnchorSpec;
|
|
@@ -69,4 +94,4 @@ interface CommentsClient {
|
|
|
69
94
|
}
|
|
70
95
|
declare function createClient(options: ClientOptions): CommentsClient;
|
|
71
96
|
|
|
72
|
-
export { AnchorSpec, type ApiErrorCode, type CallOptions, type ClientOptions, CommentsApiError, type CommentsClient, CommentsErrorCode, ListFilter, type Me, Message, NewReply, Suggestion, type SuggestionListFilter, Thread, type ThreadFilter, createClient };
|
|
97
|
+
export { AnchorSpec, type ApiErrorCode, type CallOptions, type ClientOptions, CommentsApiError, type CommentsClient, CommentsErrorCode, type Erased, ListFilter, type Me, Message, NewReply, type PersonData, PersonExport, PersonSuggestions, Suggestion, type SuggestionListFilter, Thread, type ThreadFilter, createClient };
|
package/dist/client.js
CHANGED
|
@@ -4,6 +4,7 @@ var CODES = {
|
|
|
4
4
|
INVALID_INPUT: true,
|
|
5
5
|
INVALID_ANCHOR: true,
|
|
6
6
|
NO_THREAD: true,
|
|
7
|
+
NO_MESSAGE: true,
|
|
7
8
|
THREAD_RESOLVED: true,
|
|
8
9
|
CORRUPT: true,
|
|
9
10
|
NO_SUGGESTION: true,
|
|
@@ -40,15 +41,21 @@ var CommentsApiError = class extends Error {
|
|
|
40
41
|
var KINDS = { human: true, agent_of_human: true, agent_of_agent: true, agent: true, user_token: true };
|
|
41
42
|
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
42
43
|
var isString = (v) => typeof v === "string";
|
|
44
|
+
var isAuthor = (v) => isObject(v) && typeof v.kind === "string" && Object.hasOwn(KINDS, v.kind) && isString(v.name);
|
|
45
|
+
var personThread = (v) => isObject(v) && isString(v.threadId) && isObject(v.anchor) && Array.isArray(v.messages) && v.messages.every(SHAPES.message) && (v.statusChange === void 0 || isObject(v.statusChange) && (v.statusChange.status === "open" || v.statusChange.status === "resolved") && isString(v.statusChange.at) && isAuthor(v.statusChange.by));
|
|
43
46
|
var SHAPES = {
|
|
44
|
-
me: (v) => isObject(v) && (typeof v.kind === "string" && Object.hasOwn(KINDS, v.kind)) && isString(v.name) && Array.isArray(v.scopes),
|
|
47
|
+
me: (v) => isObject(v) && (typeof v.kind === "string" && Object.hasOwn(KINDS, v.kind)) && isString(v.name) && Array.isArray(v.scopes) && v.scopes.every(isString),
|
|
45
48
|
created: (v) => isObject(v) && isString(v.id),
|
|
46
49
|
document: (v) => isObject(v) && isString(v.id) && isString(v.text),
|
|
47
|
-
thread: (v) => isObject(v) && isString(v.id) && isObject(v.anchor) && (v.status === "open" || v.status === "resolved") && Array.isArray(v.messages),
|
|
50
|
+
thread: (v) => isObject(v) && isString(v.id) && isObject(v.anchor) && isObject(v.anchorState) && isString(v.anchorState.state) && (v.status === "open" || v.status === "resolved") && isAuthor(v.statusBy) && isString(v.statusAt) && Array.isArray(v.messages) && v.messages.every(SHAPES.message) && typeof v.skipped === "number",
|
|
48
51
|
threads: (v) => Array.isArray(v) && v.every(SHAPES.thread),
|
|
49
|
-
message: (v) => isObject(v) && isString(v.id) && isString(v.body) &&
|
|
50
|
-
suggestion: (v) => isObject(v) && isString(v.id) && isObject(v.anchor) && isString(v.status) &&
|
|
51
|
-
suggestions: (v) => Array.isArray(v) && v.every(SHAPES.suggestion)
|
|
52
|
+
message: (v) => isObject(v) && isString(v.id) && isString(v.at) && isString(v.body) && Array.isArray(v.mentions) && v.mentions.every(isString) && isAuthor(v.author) && (v.editedAt === void 0 || isString(v.editedAt)) && (v.editedBy === void 0 || isAuthor(v.editedBy)),
|
|
53
|
+
suggestion: (v) => isObject(v) && isString(v.id) && isObject(v.anchor) && isObject(v.anchorState) && isString(v.anchorState.state) && (v.status === "pending" || v.status === "accepted" || v.status === "rejected") && isAuthor(v.author) && isString(v.createdAt) && "change" in v && (v.summary === void 0 || isString(v.summary)) && (v.decidedBy === void 0 || isAuthor(v.decidedBy)) && (v.decidedAt === void 0 || isString(v.decidedAt)),
|
|
54
|
+
suggestions: (v) => Array.isArray(v) && v.every(SHAPES.suggestion),
|
|
55
|
+
deletedMessage: (v) => isObject(v) && isString(v.threadId) && isString(v.messageId),
|
|
56
|
+
deletedThread: (v) => isObject(v) && isString(v.threadId),
|
|
57
|
+
person: (v) => isObject(v) && isString(v.person) && isString(v.exportedAt) && Array.isArray(v.threads) && v.threads.every(personThread) && Array.isArray(v.edits) && v.edits.every((e) => isObject(e) && isString(e.threadId) && isString(e.messageId) && isString(e.at)) && typeof v.unread === "number" && isObject(v.suggestions) && Array.isArray(v.suggestions.authored) && v.suggestions.authored.every(SHAPES.suggestion) && Array.isArray(v.suggestions.decided) && v.suggestions.decided.every((d) => isObject(d) && isString(d.id) && (d.status === "accepted" || d.status === "rejected") && isString(d.at)) && typeof v.suggestions.unread === "number",
|
|
58
|
+
erased: (v) => isObject(v) && ["messages", "statuses", "edits", "suggestions", "decisions"].every((k) => typeof v[k] === "number")
|
|
52
59
|
};
|
|
53
60
|
function createClient(options) {
|
|
54
61
|
if (typeof options.baseUrl !== "string" || options.baseUrl === "") throw new TypeError("createClient needs a baseUrl");
|
|
@@ -120,6 +127,11 @@ function createClient(options) {
|
|
|
120
127
|
resolve: (id, threadId, o) => call("POST", `${thread(id, threadId)}/resolve`, void 0, o, "thread"),
|
|
121
128
|
reopen: (id, threadId, o) => call("POST", `${thread(id, threadId)}/reopen`, void 0, o, "thread"),
|
|
122
129
|
relocate: (id, threadId, o) => call("POST", `${thread(id, threadId)}/relocate`, void 0, o, "thread"),
|
|
130
|
+
editMessage: (id, threadId, messageId, input, o) => call("PATCH", `${thread(id, threadId)}/messages/${seg(messageId)}`, input, o, "message"),
|
|
131
|
+
deleteMessage: (id, threadId, messageId, o) => call("DELETE", `${thread(id, threadId)}/messages/${seg(messageId)}`, void 0, o, "deletedMessage"),
|
|
132
|
+
deleteThread: (id, threadId, o) => call("DELETE", thread(id, threadId), void 0, o, "deletedThread"),
|
|
133
|
+
exportPerson: (id, person, o) => call("GET", `${doc(id)}/people/${seg(person)}/export`, void 0, o, "person"),
|
|
134
|
+
erasePerson: (id, person, o) => call("DELETE", `${doc(id)}/people/${seg(person)}`, void 0, o, "erased"),
|
|
123
135
|
listSuggestions: (id, filter, o) => call("GET", `${doc(id)}/suggestions${query(filter)}`, void 0, o, "suggestions"),
|
|
124
136
|
suggest: (id, input, o) => call("POST", `${doc(id)}/suggestions`, input, o, "suggestion"),
|
|
125
137
|
accept: (id, suggestionId, o) => call("POST", `${suggestion(id, suggestionId)}/accept`, void 0, o, "suggestion"),
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type CommentsErrorCode = "INVALID_AUTHOR" | "INVALID_INPUT" | "INVALID_ANCHOR" | "NO_THREAD" | "NO_MESSAGE" | "THREAD_RESOLVED" | "CORRUPT" | "NO_SUGGESTION" | "FORBIDDEN" | "ALREADY_DECIDED" | "APPLY_FAILED" | "RELOCATE_FAILED" | "STORE_MISSING" | "STORE_EXISTS" | "STORE_CORRUPT" | "STORE_LOCKED" | "STORE_FULL" | "NO_DOCUMENT" | "DOCUMENT_EXISTS" | "CONFLICT" | "MISCONFIGURED" | "USAGE";
|
|
2
|
+
declare class CommentsError extends Error {
|
|
3
|
+
readonly code: CommentsErrorCode;
|
|
4
|
+
constructor(code: CommentsErrorCode, message: string);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export { type CommentsErrorCode as C, CommentsError as a };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
export { a as CommentsError, C as CommentsErrorCode } from './errors-
|
|
1
|
+
import { b as Author, C as Comments, c as Suggestions } from './suggestions-CnkEcTuY.js';
|
|
2
|
+
export { d as ACCEPT_SCOPE, A as Actor, e as Anchor, f as AnchorKind, g as AnchorState, h as ApplyContext, i as CanvasAnchor, j as CellAnchor, k as CommentsOptions, E as ERASED_BODY, l as ERASED_NAME, m as EditMessage, n as MODERATE_SCOPE, M as Message, N as NewReply, o as NewSuggestion, p as NewThread, P as PersonExport, R as RelativePositionJson, q as RevertContext, r as SlideAnchor, s as StampInput, S as Suggestion, t as SuggestionFilter, u as SuggestionHost, v as TextAnchor, T as Thread, w as ThreadFilter, x as authorLabel, y as stamp, z as textAnchor, B as textOf } from './suggestions-CnkEcTuY.js';
|
|
3
|
+
export { a as CommentsError, C as CommentsErrorCode } from './errors-C-xvp24-.js';
|
|
4
4
|
export { PRINCIPAL_KINDS, PrincipalKind } from 'agentic-identity';
|
|
5
5
|
import 'yjs';
|
|
6
6
|
|