agentic-comments 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -2
- package/SKILL.md +5 -0
- package/dist/account.d.ts +62 -0
- package/dist/account.js +114 -0
- package/dist/{chunk-VAVKBAHM.js → chunk-4G5BDTBA.js} +574 -574
- package/dist/{chunk-H6JK62SP.js → chunk-6UQ6CDLJ.js} +1 -1
- package/dist/{chunk-UNJL3N2L.js → chunk-J6JGWDUP.js} +3 -3
- package/dist/{chunk-6N53KQVU.js → chunk-LFYTCHXS.js} +1 -1
- package/dist/{chunk-T77DPNIV.js → chunk-TTNT27PG.js} +1 -1
- package/dist/chunk-UEQL27KF.js +148 -0
- package/dist/cli.js +7 -7
- package/dist/client.d.ts +3 -3
- package/dist/client.js +4 -143
- package/dist/{errors-C-xvp24-.d.ts → errors-Cin-719h.d.ts} +3 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/local.d.ts +2 -2
- package/dist/local.js +3 -3
- package/dist/mcp-IFQQHOA2.js +11 -0
- package/dist/mcp-bin.js +9 -9
- package/dist/{service-BvIE6t5n.d.ts → service-ZdZPWrwI.d.ts} +1 -1
- package/dist/{suggestions-CnkEcTuY.d.ts → suggestions-G1seGf5d.d.ts} +5 -2
- package/dist/ui.css +54 -0
- package/dist/ui.d.ts +46 -0
- package/dist/ui.js +332 -0
- package/dist/worker.d.ts +26 -2
- package/dist/worker.js +91 -3
- package/llms.txt +2 -0
- package/package.json +39 -7
- package/dist/mcp-WBAHKMF4.js +0 -11
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6UQ6CDLJ.js";
|
|
4
4
|
import {
|
|
5
5
|
CommentsService
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-TTNT27PG.js";
|
|
7
7
|
import {
|
|
8
8
|
CommentsError
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-4G5BDTBA.js";
|
|
10
10
|
|
|
11
11
|
// src/mcp.ts
|
|
12
12
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
var CODES = {
|
|
3
|
+
INVALID_AUTHOR: true,
|
|
4
|
+
INVALID_INPUT: true,
|
|
5
|
+
INVALID_ANCHOR: true,
|
|
6
|
+
NO_THREAD: true,
|
|
7
|
+
NO_MESSAGE: true,
|
|
8
|
+
THREAD_RESOLVED: true,
|
|
9
|
+
CORRUPT: true,
|
|
10
|
+
NO_SUGGESTION: true,
|
|
11
|
+
FORBIDDEN: true,
|
|
12
|
+
ALREADY_DECIDED: true,
|
|
13
|
+
APPLY_FAILED: true,
|
|
14
|
+
RELOCATE_FAILED: true,
|
|
15
|
+
STORE_MISSING: true,
|
|
16
|
+
STORE_EXISTS: true,
|
|
17
|
+
STORE_CORRUPT: true,
|
|
18
|
+
STORE_LOCKED: true,
|
|
19
|
+
STORE_FULL: true,
|
|
20
|
+
NO_DOCUMENT: true,
|
|
21
|
+
DOCUMENT_EXISTS: true,
|
|
22
|
+
CONFLICT: true,
|
|
23
|
+
MISCONFIGURED: true,
|
|
24
|
+
USAGE: true,
|
|
25
|
+
UNAUTHENTICATED: true,
|
|
26
|
+
NOT_FOUND: true,
|
|
27
|
+
INTERNAL: true,
|
|
28
|
+
UNKNOWN: true
|
|
29
|
+
};
|
|
30
|
+
var isKnownCode = (v) => typeof v === "string" && Object.hasOwn(CODES, v);
|
|
31
|
+
var CommentsApiError = class extends Error {
|
|
32
|
+
code;
|
|
33
|
+
status;
|
|
34
|
+
constructor(code, status, message) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = "CommentsApiError";
|
|
37
|
+
this.code = code;
|
|
38
|
+
this.status = status;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var KINDS = { human: true, agent_of_human: true, agent_of_agent: true, agent: true, user_token: true };
|
|
42
|
+
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
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));
|
|
46
|
+
var SHAPES = {
|
|
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),
|
|
48
|
+
created: (v) => isObject(v) && isString(v.id),
|
|
49
|
+
document: (v) => isObject(v) && isString(v.id) && isString(v.text),
|
|
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",
|
|
51
|
+
threads: (v) => Array.isArray(v) && v.every(SHAPES.thread),
|
|
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")
|
|
59
|
+
};
|
|
60
|
+
function createClient(options) {
|
|
61
|
+
if (typeof options.baseUrl !== "string" || options.baseUrl === "") throw new TypeError("createClient needs a baseUrl");
|
|
62
|
+
if (typeof options.token !== "string" || options.token === "") throw new TypeError("createClient needs a token");
|
|
63
|
+
let origin;
|
|
64
|
+
try {
|
|
65
|
+
origin = new URL(options.baseUrl);
|
|
66
|
+
} catch {
|
|
67
|
+
throw new TypeError("baseUrl must be an absolute URL");
|
|
68
|
+
}
|
|
69
|
+
if (origin.protocol !== "https:" && origin.protocol !== "http:") throw new TypeError("baseUrl must be an http or https URL");
|
|
70
|
+
if (origin.search !== "" || origin.hash !== "" || origin.username !== "" || origin.password !== "") {
|
|
71
|
+
throw new TypeError("baseUrl must have no query, hash, or credentials");
|
|
72
|
+
}
|
|
73
|
+
const root = `${origin.origin}${origin.pathname.replace(/\/+$/, "")}/api/v1`;
|
|
74
|
+
const token = options.token;
|
|
75
|
+
const send = (input, init) => {
|
|
76
|
+
const run = options.fetch ?? globalThis.fetch;
|
|
77
|
+
return run(input, init);
|
|
78
|
+
};
|
|
79
|
+
const seg = (value) => {
|
|
80
|
+
if (typeof value !== "string" || /^(?:\.|%2e){0,2}$/i.test(value)) throw new TypeError("an id must be a non-empty string that is not . or ..");
|
|
81
|
+
return encodeURIComponent(value);
|
|
82
|
+
};
|
|
83
|
+
const query = (filter) => {
|
|
84
|
+
const params = new URLSearchParams();
|
|
85
|
+
for (const [key, value] of Object.entries(filter ?? {})) if (value !== void 0) params.set(key, String(value));
|
|
86
|
+
const text = params.toString();
|
|
87
|
+
return text === "" ? "" : `?${text}`;
|
|
88
|
+
};
|
|
89
|
+
async function call(method, path, body, callOptions, shape) {
|
|
90
|
+
const headers = { authorization: `Bearer ${token}` };
|
|
91
|
+
if (body !== void 0) headers["content-type"] = "application/json";
|
|
92
|
+
const response = await send(`${root}${path}`, {
|
|
93
|
+
method,
|
|
94
|
+
headers,
|
|
95
|
+
body: body === void 0 ? void 0 : JSON.stringify(body),
|
|
96
|
+
signal: callOptions?.signal,
|
|
97
|
+
// Never follow a redirect: it would send a write to another host.
|
|
98
|
+
redirect: "manual"
|
|
99
|
+
});
|
|
100
|
+
const text = await response.text();
|
|
101
|
+
let parsed;
|
|
102
|
+
try {
|
|
103
|
+
parsed = text === "" ? void 0 : JSON.parse(text);
|
|
104
|
+
} catch {
|
|
105
|
+
parsed = void 0;
|
|
106
|
+
}
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
const error = parsed?.error;
|
|
109
|
+
const code = isKnownCode(error?.code) ? error.code : "UNKNOWN";
|
|
110
|
+
const message = typeof error?.message === "string" ? error.message : `HTTP ${response.status}`;
|
|
111
|
+
throw new CommentsApiError(code, response.status, message);
|
|
112
|
+
}
|
|
113
|
+
if (!SHAPES[shape](parsed)) throw new CommentsApiError("UNKNOWN", response.status, `the reply is not a ${shape}`);
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
const doc = (id) => `/docs/${seg(id)}`;
|
|
117
|
+
const thread = (id, threadId) => `${doc(id)}/threads/${seg(threadId)}`;
|
|
118
|
+
const suggestion = (id, suggestionId) => `${doc(id)}/suggestions/${seg(suggestionId)}`;
|
|
119
|
+
const methods = {
|
|
120
|
+
me: (o) => call("GET", "/me", void 0, o, "me"),
|
|
121
|
+
createDocument: (input, o) => call("POST", "/docs", input, o, "created"),
|
|
122
|
+
getDocument: (id, o) => call("GET", doc(id), void 0, o, "document"),
|
|
123
|
+
listThreads: (id, filter, o) => call("GET", `${doc(id)}/threads${query(filter)}`, void 0, o, "threads"),
|
|
124
|
+
getThread: (id, threadId, o) => call("GET", thread(id, threadId), void 0, o, "thread"),
|
|
125
|
+
addThread: (id, input, o) => call("POST", `${doc(id)}/threads`, input, o, "thread"),
|
|
126
|
+
reply: (id, threadId, input, o) => call("POST", `${thread(id, threadId)}/replies`, input, o, "message"),
|
|
127
|
+
resolve: (id, threadId, o) => call("POST", `${thread(id, threadId)}/resolve`, void 0, o, "thread"),
|
|
128
|
+
reopen: (id, threadId, o) => call("POST", `${thread(id, threadId)}/reopen`, void 0, o, "thread"),
|
|
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"),
|
|
135
|
+
listSuggestions: (id, filter, o) => call("GET", `${doc(id)}/suggestions${query(filter)}`, void 0, o, "suggestions"),
|
|
136
|
+
suggest: (id, input, o) => call("POST", `${doc(id)}/suggestions`, input, o, "suggestion"),
|
|
137
|
+
accept: (id, suggestionId, o) => call("POST", `${suggestion(id, suggestionId)}/accept`, void 0, o, "suggestion"),
|
|
138
|
+
reject: (id, suggestionId, o) => call("POST", `${suggestion(id, suggestionId)}/reject`, void 0, o, "suggestion")
|
|
139
|
+
};
|
|
140
|
+
return Object.fromEntries(
|
|
141
|
+
Object.entries(methods).map(([name, method]) => [name, async (...args) => method(...args)])
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export {
|
|
146
|
+
CommentsApiError,
|
|
147
|
+
createClient
|
|
148
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
VERSION
|
|
4
|
+
} from "./chunk-6UQ6CDLJ.js";
|
|
2
5
|
import {
|
|
3
6
|
FileStore,
|
|
4
7
|
lockTimeoutFrom,
|
|
5
8
|
operatorActor
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
VERSION
|
|
9
|
-
} from "./chunk-H6JK62SP.js";
|
|
9
|
+
} from "./chunk-LFYTCHXS.js";
|
|
10
10
|
import {
|
|
11
11
|
CommentsService,
|
|
12
12
|
TEXT_ROOT
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-TTNT27PG.js";
|
|
14
14
|
import {
|
|
15
15
|
CommentsError
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-4G5BDTBA.js";
|
|
17
17
|
|
|
18
18
|
// src/cli.ts
|
|
19
19
|
import { readFileSync, realpathSync } from "fs";
|
|
@@ -178,7 +178,7 @@ async function runCli(argv, io) {
|
|
|
178
178
|
return 0;
|
|
179
179
|
}
|
|
180
180
|
if (p.command === "mcp") {
|
|
181
|
-
const { startMcp } = await import("./mcp-
|
|
181
|
+
const { startMcp } = await import("./mcp-IFQQHOA2.js");
|
|
182
182
|
await startMcp(store, operatorActor(p.flags["--as"] ?? io.env.AGENTIC_COMMENTS_AS, io.env.AGENTIC_COMMENTS_SCOPES));
|
|
183
183
|
return 0;
|
|
184
184
|
}
|
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-ZdZPWrwI.js';
|
|
2
|
+
import { C as CommentsErrorCode } from './errors-Cin-719h.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, P as PersonExport, a as PersonSuggestions, 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-G1seGf5d.js';
|
|
6
6
|
import 'yjs';
|
|
7
7
|
|
|
8
8
|
/** Codes the comment rules return, plus the ones the Worker and its auth return. */
|
package/dist/client.js
CHANGED
|
@@ -1,146 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
INVALID_ANCHOR: true,
|
|
6
|
-
NO_THREAD: true,
|
|
7
|
-
NO_MESSAGE: true,
|
|
8
|
-
THREAD_RESOLVED: true,
|
|
9
|
-
CORRUPT: true,
|
|
10
|
-
NO_SUGGESTION: true,
|
|
11
|
-
FORBIDDEN: true,
|
|
12
|
-
ALREADY_DECIDED: true,
|
|
13
|
-
APPLY_FAILED: true,
|
|
14
|
-
RELOCATE_FAILED: true,
|
|
15
|
-
STORE_MISSING: true,
|
|
16
|
-
STORE_EXISTS: true,
|
|
17
|
-
STORE_CORRUPT: true,
|
|
18
|
-
STORE_LOCKED: true,
|
|
19
|
-
STORE_FULL: true,
|
|
20
|
-
NO_DOCUMENT: true,
|
|
21
|
-
DOCUMENT_EXISTS: true,
|
|
22
|
-
CONFLICT: true,
|
|
23
|
-
MISCONFIGURED: true,
|
|
24
|
-
USAGE: true,
|
|
25
|
-
UNAUTHENTICATED: true,
|
|
26
|
-
NOT_FOUND: true,
|
|
27
|
-
INTERNAL: true,
|
|
28
|
-
UNKNOWN: true
|
|
29
|
-
};
|
|
30
|
-
var isKnownCode = (v) => typeof v === "string" && Object.hasOwn(CODES, v);
|
|
31
|
-
var CommentsApiError = class extends Error {
|
|
32
|
-
code;
|
|
33
|
-
status;
|
|
34
|
-
constructor(code, status, message) {
|
|
35
|
-
super(message);
|
|
36
|
-
this.name = "CommentsApiError";
|
|
37
|
-
this.code = code;
|
|
38
|
-
this.status = status;
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
var KINDS = { human: true, agent_of_human: true, agent_of_agent: true, agent: true, user_token: true };
|
|
42
|
-
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
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));
|
|
46
|
-
var SHAPES = {
|
|
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),
|
|
48
|
-
created: (v) => isObject(v) && isString(v.id),
|
|
49
|
-
document: (v) => isObject(v) && isString(v.id) && isString(v.text),
|
|
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",
|
|
51
|
-
threads: (v) => Array.isArray(v) && v.every(SHAPES.thread),
|
|
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")
|
|
59
|
-
};
|
|
60
|
-
function createClient(options) {
|
|
61
|
-
if (typeof options.baseUrl !== "string" || options.baseUrl === "") throw new TypeError("createClient needs a baseUrl");
|
|
62
|
-
if (typeof options.token !== "string" || options.token === "") throw new TypeError("createClient needs a token");
|
|
63
|
-
let origin;
|
|
64
|
-
try {
|
|
65
|
-
origin = new URL(options.baseUrl);
|
|
66
|
-
} catch {
|
|
67
|
-
throw new TypeError("baseUrl must be an absolute URL");
|
|
68
|
-
}
|
|
69
|
-
if (origin.protocol !== "https:" && origin.protocol !== "http:") throw new TypeError("baseUrl must be an http or https URL");
|
|
70
|
-
if (origin.search !== "" || origin.hash !== "" || origin.username !== "" || origin.password !== "") {
|
|
71
|
-
throw new TypeError("baseUrl must have no query, hash, or credentials");
|
|
72
|
-
}
|
|
73
|
-
const root = `${origin.origin}${origin.pathname.replace(/\/+$/, "")}/api/v1`;
|
|
74
|
-
const token = options.token;
|
|
75
|
-
const send = (input, init) => {
|
|
76
|
-
const run = options.fetch ?? globalThis.fetch;
|
|
77
|
-
return run(input, init);
|
|
78
|
-
};
|
|
79
|
-
const seg = (value) => {
|
|
80
|
-
if (typeof value !== "string" || /^(?:\.|%2e){0,2}$/i.test(value)) throw new TypeError("an id must be a non-empty string that is not . or ..");
|
|
81
|
-
return encodeURIComponent(value);
|
|
82
|
-
};
|
|
83
|
-
const query = (filter) => {
|
|
84
|
-
const params = new URLSearchParams();
|
|
85
|
-
for (const [key, value] of Object.entries(filter ?? {})) if (value !== void 0) params.set(key, String(value));
|
|
86
|
-
const text = params.toString();
|
|
87
|
-
return text === "" ? "" : `?${text}`;
|
|
88
|
-
};
|
|
89
|
-
async function call(method, path, body, callOptions, shape) {
|
|
90
|
-
const headers = { authorization: `Bearer ${token}` };
|
|
91
|
-
if (body !== void 0) headers["content-type"] = "application/json";
|
|
92
|
-
const response = await send(`${root}${path}`, {
|
|
93
|
-
method,
|
|
94
|
-
headers,
|
|
95
|
-
body: body === void 0 ? void 0 : JSON.stringify(body),
|
|
96
|
-
signal: callOptions?.signal,
|
|
97
|
-
// Never follow a redirect: it would send a write to another host.
|
|
98
|
-
redirect: "manual"
|
|
99
|
-
});
|
|
100
|
-
const text = await response.text();
|
|
101
|
-
let parsed;
|
|
102
|
-
try {
|
|
103
|
-
parsed = text === "" ? void 0 : JSON.parse(text);
|
|
104
|
-
} catch {
|
|
105
|
-
parsed = void 0;
|
|
106
|
-
}
|
|
107
|
-
if (!response.ok) {
|
|
108
|
-
const error = parsed?.error;
|
|
109
|
-
const code = isKnownCode(error?.code) ? error.code : "UNKNOWN";
|
|
110
|
-
const message = typeof error?.message === "string" ? error.message : `HTTP ${response.status}`;
|
|
111
|
-
throw new CommentsApiError(code, response.status, message);
|
|
112
|
-
}
|
|
113
|
-
if (!SHAPES[shape](parsed)) throw new CommentsApiError("UNKNOWN", response.status, `the reply is not a ${shape}`);
|
|
114
|
-
return parsed;
|
|
115
|
-
}
|
|
116
|
-
const doc = (id) => `/docs/${seg(id)}`;
|
|
117
|
-
const thread = (id, threadId) => `${doc(id)}/threads/${seg(threadId)}`;
|
|
118
|
-
const suggestion = (id, suggestionId) => `${doc(id)}/suggestions/${seg(suggestionId)}`;
|
|
119
|
-
const methods = {
|
|
120
|
-
me: (o) => call("GET", "/me", void 0, o, "me"),
|
|
121
|
-
createDocument: (input, o) => call("POST", "/docs", input, o, "created"),
|
|
122
|
-
getDocument: (id, o) => call("GET", doc(id), void 0, o, "document"),
|
|
123
|
-
listThreads: (id, filter, o) => call("GET", `${doc(id)}/threads${query(filter)}`, void 0, o, "threads"),
|
|
124
|
-
getThread: (id, threadId, o) => call("GET", thread(id, threadId), void 0, o, "thread"),
|
|
125
|
-
addThread: (id, input, o) => call("POST", `${doc(id)}/threads`, input, o, "thread"),
|
|
126
|
-
reply: (id, threadId, input, o) => call("POST", `${thread(id, threadId)}/replies`, input, o, "message"),
|
|
127
|
-
resolve: (id, threadId, o) => call("POST", `${thread(id, threadId)}/resolve`, void 0, o, "thread"),
|
|
128
|
-
reopen: (id, threadId, o) => call("POST", `${thread(id, threadId)}/reopen`, void 0, o, "thread"),
|
|
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"),
|
|
135
|
-
listSuggestions: (id, filter, o) => call("GET", `${doc(id)}/suggestions${query(filter)}`, void 0, o, "suggestions"),
|
|
136
|
-
suggest: (id, input, o) => call("POST", `${doc(id)}/suggestions`, input, o, "suggestion"),
|
|
137
|
-
accept: (id, suggestionId, o) => call("POST", `${suggestion(id, suggestionId)}/accept`, void 0, o, "suggestion"),
|
|
138
|
-
reject: (id, suggestionId, o) => call("POST", `${suggestion(id, suggestionId)}/reject`, void 0, o, "suggestion")
|
|
139
|
-
};
|
|
140
|
-
return Object.fromEntries(
|
|
141
|
-
Object.entries(methods).map(([name, method]) => [name, async (...args) => method(...args)])
|
|
142
|
-
);
|
|
143
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
CommentsApiError,
|
|
3
|
+
createClient
|
|
4
|
+
} from "./chunk-UEQL27KF.js";
|
|
144
5
|
export {
|
|
145
6
|
CommentsApiError,
|
|
146
7
|
createClient
|
|
@@ -1,7 +1,9 @@
|
|
|
1
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
2
|
declare class CommentsError extends Error {
|
|
3
3
|
readonly code: CommentsErrorCode;
|
|
4
|
-
constructor(code: CommentsErrorCode, message: string
|
|
4
|
+
constructor(code: CommentsErrorCode, message: string, options?: {
|
|
5
|
+
cause?: unknown;
|
|
6
|
+
});
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
export { type CommentsErrorCode as C, CommentsError as a };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { b as Author, C as Comments, c as Suggestions } from './suggestions-
|
|
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-
|
|
3
|
-
export { a as CommentsError, C as CommentsErrorCode } from './errors-
|
|
1
|
+
import { b as Author, C as Comments, c as Suggestions } from './suggestions-G1seGf5d.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-G1seGf5d.js';
|
|
3
|
+
export { a as CommentsError, C as CommentsErrorCode } from './errors-Cin-719h.js';
|
|
4
4
|
export { PRINCIPAL_KINDS, PrincipalKind } from 'agentic-identity';
|
|
5
5
|
import 'yjs';
|
|
6
6
|
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6UQ6CDLJ.js";
|
|
4
4
|
import {
|
|
5
5
|
ACCEPT_SCOPE,
|
|
6
6
|
Actor,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
textAnchor,
|
|
18
18
|
textOf,
|
|
19
19
|
validDate
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-4G5BDTBA.js";
|
|
21
21
|
|
|
22
22
|
// src/notifications.ts
|
|
23
23
|
import * as Y from "yjs";
|
package/dist/local.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
|
-
export { A as AnchorSpec, C as CommentsService, L as ListFilter } from './service-
|
|
3
|
-
import { u as SuggestionHost, A as Actor } from './suggestions-
|
|
2
|
+
export { A as AnchorSpec, C as CommentsService, L as ListFilter } from './service-ZdZPWrwI.js';
|
|
3
|
+
import { u as SuggestionHost, A as Actor } from './suggestions-G1seGf5d.js';
|
|
4
4
|
import 'agentic-identity';
|
|
5
5
|
|
|
6
6
|
/** The most bytes a saved document holds. A save over this is refused, so a file never grows past what a load accepts. */
|
package/dist/local.js
CHANGED
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
MAX_FILE,
|
|
4
4
|
lockTimeoutFrom,
|
|
5
5
|
operatorActor
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LFYTCHXS.js";
|
|
7
7
|
import {
|
|
8
8
|
CommentsService,
|
|
9
9
|
TEXT_ROOT,
|
|
10
10
|
VALUES_ROOT,
|
|
11
11
|
localHost
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-TTNT27PG.js";
|
|
13
|
+
import "./chunk-4G5BDTBA.js";
|
|
14
14
|
export {
|
|
15
15
|
CommentsService,
|
|
16
16
|
FileStore,
|
package/dist/mcp-bin.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
FileStore,
|
|
4
|
-
lockTimeoutFrom,
|
|
5
|
-
operatorActor
|
|
6
|
-
} from "./chunk-6N53KQVU.js";
|
|
7
2
|
import {
|
|
8
3
|
startMcp
|
|
9
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-J6JGWDUP.js";
|
|
10
5
|
import {
|
|
11
6
|
VERSION
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import
|
|
14
|
-
|
|
7
|
+
} from "./chunk-6UQ6CDLJ.js";
|
|
8
|
+
import {
|
|
9
|
+
FileStore,
|
|
10
|
+
lockTimeoutFrom,
|
|
11
|
+
operatorActor
|
|
12
|
+
} from "./chunk-LFYTCHXS.js";
|
|
13
|
+
import "./chunk-TTNT27PG.js";
|
|
14
|
+
import "./chunk-4G5BDTBA.js";
|
|
15
15
|
|
|
16
16
|
// src/mcp-bin.ts
|
|
17
17
|
var MCP_HELP = `agentic-comments-mcp ${VERSION}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
|
-
import { A as Actor, T as Thread, M as Message, P as PersonExport, a as PersonSuggestions, S as Suggestion } from './suggestions-
|
|
2
|
+
import { A as Actor, T as Thread, M as Message, P as PersonExport, a as PersonSuggestions, S as Suggestion } from './suggestions-G1seGf5d.js';
|
|
3
3
|
|
|
4
4
|
/** Where a comment or suggestion points, in terms a person or agent can write down. */
|
|
5
5
|
type AnchorSpec = {
|
|
@@ -383,11 +383,14 @@ interface SuggestionFilter {
|
|
|
383
383
|
* with the accept scope that did not write it, accepts. Accept and reject are safe across replicas.
|
|
384
384
|
*/
|
|
385
385
|
declare class Suggestions {
|
|
386
|
-
|
|
386
|
+
/** The threads these suggestions anchor to. */
|
|
387
|
+
readonly comments: Comments;
|
|
387
388
|
private readonly host;
|
|
388
389
|
private readonly onTransaction;
|
|
389
390
|
private failures;
|
|
390
|
-
constructor(
|
|
391
|
+
constructor(
|
|
392
|
+
/** The threads these suggestions anchor to. */
|
|
393
|
+
comments: Comments, host: SuggestionHost);
|
|
391
394
|
/** Stop listening to the document. */
|
|
392
395
|
close(): void;
|
|
393
396
|
private get ydoc();
|
package/dist/ui.css
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/* The comments panel. It uses the agentic-design tokens and its own agd-comments classes. */
|
|
2
|
+
.agd-comments {
|
|
3
|
+
display: grid;
|
|
4
|
+
grid-template-columns: minmax(0, 1fr);
|
|
5
|
+
gap: var(--agd-space-16);
|
|
6
|
+
max-width: 44rem;
|
|
7
|
+
margin-inline: auto;
|
|
8
|
+
padding: var(--agd-space-16);
|
|
9
|
+
color: var(--agd-color-text);
|
|
10
|
+
font-family: var(--agd-font-family-sans);
|
|
11
|
+
font-size: var(--agd-font-size-md);
|
|
12
|
+
line-height: var(--agd-line-height-normal);
|
|
13
|
+
}
|
|
14
|
+
.agd-comments__top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--agd-space-8); }
|
|
15
|
+
.agd-comments__title { margin: 0; font-size: var(--agd-font-size-xl); font-weight: var(--agd-font-weight-semibold); line-height: var(--agd-line-height-tight); }
|
|
16
|
+
.agd-comments__me { display: flex; align-items: center; gap: var(--agd-space-8); margin: 0; color: var(--agd-color-text-muted); font-size: var(--agd-font-size-sm); }
|
|
17
|
+
.agd-comments__section { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--agd-space-12, 12px); }
|
|
18
|
+
.agd-comments__heading { display: flex; align-items: center; gap: var(--agd-space-8); margin: 0; font-size: var(--agd-font-size-lg); font-weight: var(--agd-font-weight-semibold); }
|
|
19
|
+
.agd-comments__count { min-width: 1.5rem; padding: 0 var(--agd-space-6); border-radius: var(--agd-radius-full); background: var(--agd-color-surface-sunken); color: var(--agd-color-text-muted); font-size: var(--agd-font-size-sm); font-weight: var(--agd-font-weight-medium); text-align: center; }
|
|
20
|
+
.agd-comments__views { display: flex; flex-wrap: wrap; gap: var(--agd-space-8); }
|
|
21
|
+
.agd-comments__list, .agd-comments__messages { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--agd-space-12, 12px); margin: 0; padding: 0; list-style: none; }
|
|
22
|
+
.agd-comments__thread { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--agd-space-8); padding: var(--agd-space-16); border: 1px solid var(--agd-color-border); border-radius: var(--agd-radius-lg); background: var(--agd-color-surface); }
|
|
23
|
+
.agd-comments__thread > article { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--agd-space-8); }
|
|
24
|
+
.agd-comments__item-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--agd-space-8); }
|
|
25
|
+
.agd-comments__item-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--agd-space-8); margin: 0; font-size: var(--agd-font-size-md); font-weight: var(--agd-font-weight-semibold); overflow-wrap: anywhere; }
|
|
26
|
+
.agd-comments__status { font-size: var(--agd-font-size-xs); }
|
|
27
|
+
.agd-comments__status--resolved, .agd-comments__status--accepted { background: var(--agd-color-success-subtle); color: var(--agd-color-success-text); }
|
|
28
|
+
.agd-comments__status--rejected { background: var(--agd-color-danger-subtle); color: var(--agd-color-danger-text); }
|
|
29
|
+
.agd-comments__status--pending, .agd-comments__status--open { background: var(--agd-color-accent-subtle); color: var(--agd-color-accent-text); }
|
|
30
|
+
.agd-comments__anchor { margin: 0; }
|
|
31
|
+
.agd-comments__label { color: var(--agd-color-text-muted); font-size: var(--agd-font-size-xs); font-weight: var(--agd-font-weight-medium); letter-spacing: 0.04em; text-transform: uppercase; }
|
|
32
|
+
.agd-comments__quote { margin: var(--agd-space-4) 0 0; padding: var(--agd-space-4) var(--agd-space-12, 12px); border-inline-start: 3px solid var(--agd-color-border-strong); background: var(--agd-color-surface-sunken); border-radius: var(--agd-radius-sm); overflow-wrap: anywhere; }
|
|
33
|
+
.agd-comments__state { margin: 0; padding: var(--agd-space-8) var(--agd-space-12, 12px); border-radius: var(--agd-radius-md); background: var(--agd-color-warning-subtle); color: var(--agd-color-warning-text); font-size: var(--agd-font-size-sm); overflow-wrap: anywhere; }
|
|
34
|
+
.agd-comments__message { display: grid; gap: var(--agd-space-4); padding-top: var(--agd-space-8); border-top: 1px solid var(--agd-color-border); }
|
|
35
|
+
.agd-comments__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--agd-space-8); }
|
|
36
|
+
.agd-comments__who { display: inline-flex; align-items: center; gap: var(--agd-space-8); }
|
|
37
|
+
.agd-comments__name { font-weight: var(--agd-font-weight-semibold); overflow-wrap: anywhere; }
|
|
38
|
+
.agd-comments__time { color: var(--agd-color-text-muted); font-size: var(--agd-font-size-sm); }
|
|
39
|
+
.agd-comments__body { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
40
|
+
.agd-comments__change { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--agd-space-4); margin: 0; }
|
|
41
|
+
.agd-comments__code { padding: var(--agd-space-4) var(--agd-space-8); border-radius: var(--agd-radius-sm); background: var(--agd-color-surface-sunken); font-family: var(--agd-font-family-mono); font-size: var(--agd-font-size-sm); white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
42
|
+
.agd-comments__note, .agd-comments__empty { margin: 0; color: var(--agd-color-text-muted); font-size: var(--agd-font-size-sm); }
|
|
43
|
+
.agd-comments__reply, .agd-comments__new { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--agd-space-8); }
|
|
44
|
+
.agd-comments__new { padding: var(--agd-space-16); border: 1px solid var(--agd-color-border); border-radius: var(--agd-radius-lg); background: var(--agd-color-surface-raised); }
|
|
45
|
+
.agd-comments__reply .agd-button, .agd-comments__new .agd-button { justify-self: start; }
|
|
46
|
+
.agd-comments__actions { display: flex; flex-wrap: wrap; gap: var(--agd-space-8); }
|
|
47
|
+
.agd-comments__error { margin: 0; padding: var(--agd-space-8) var(--agd-space-12, 12px); border: 1px solid var(--agd-color-danger); border-radius: var(--agd-radius-md); background: var(--agd-color-danger-subtle); color: var(--agd-color-danger-text); overflow-wrap: anywhere; }
|
|
48
|
+
@media (max-width: 480px) {
|
|
49
|
+
.agd-comments { padding: var(--agd-space-12, 12px); }
|
|
50
|
+
.agd-comments__thread { padding: var(--agd-space-12, 12px); }
|
|
51
|
+
}
|
|
52
|
+
/* On a narrow screen the badge wraps, so its words are never cut off. */
|
|
53
|
+
.agd-comments .agd-agent-badge { flex-wrap: wrap; row-gap: 0; }
|
|
54
|
+
.agd-comments .agd-agent-badge__label, .agd-comments .agd-agent-badge__meta { white-space: normal; overflow: visible; overflow-wrap: anywhere; }
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { CommentsClient, Me } from './client.js';
|
|
3
|
+
export { createClient } from './client.js';
|
|
4
|
+
import { b as Author, S as Suggestion } from './suggestions-G1seGf5d.js';
|
|
5
|
+
import './service-ZdZPWrwI.js';
|
|
6
|
+
import 'yjs';
|
|
7
|
+
import './errors-Cin-719h.js';
|
|
8
|
+
import 'agentic-identity';
|
|
9
|
+
|
|
10
|
+
/** The calls the panel makes. A `CommentsClient` fits, and so does any object with these methods. */
|
|
11
|
+
type PanelClient = Pick<CommentsClient, "me" | "listThreads" | "addThread" | "reply" | "resolve" | "reopen" | "listSuggestions" | "accept" | "reject">;
|
|
12
|
+
interface CommentsPanelProps {
|
|
13
|
+
client: PanelClient;
|
|
14
|
+
/** The document whose threads the panel shows. */
|
|
15
|
+
docId: string;
|
|
16
|
+
/** The heading. Defaults to "Comments". */
|
|
17
|
+
title?: string;
|
|
18
|
+
/** Show the form that starts a thread on a quote. On by default. A page that makes its own anchors turns it off. */
|
|
19
|
+
newThread?: boolean;
|
|
20
|
+
/** Name the person an agent acts for, when the host knows. The badge says "for unknown" without it. */
|
|
21
|
+
actingFor?: (author: Author) => string | undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A threaded comments panel: thread list, reply box, resolve and reopen, the quote each thread points at, an agent or
|
|
25
|
+
* person mark on every message, and accept and reject buttons for suggestions. The buttons follow the product rule: an
|
|
26
|
+
* agent never decides its own suggestion. The server still checks every call, so a hidden button is a help and not a lock.
|
|
27
|
+
* It needs the `agentic-design/styles.css` and `agentic-comments/ui.css` styles on the page.
|
|
28
|
+
*/
|
|
29
|
+
declare function CommentsPanel({ client, docId, title, newThread, actingFor }: CommentsPanelProps): react.JSX.Element;
|
|
30
|
+
|
|
31
|
+
type Need = "read" | "comment" | "write";
|
|
32
|
+
/** Whether the principal holds a scope at least as strong as `need`. */
|
|
33
|
+
declare function holds(me: Pick<Me, "scopes"> | undefined, need: Need): boolean;
|
|
34
|
+
interface Decision {
|
|
35
|
+
allowed: boolean;
|
|
36
|
+
/** Plain words that say why not. Set when `allowed` is false. */
|
|
37
|
+
reason?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Whether the signed-in principal may accept a suggestion, and whether it may reject one. The Worker checks the
|
|
41
|
+
* same rule, so this only decides what the page offers. A person may decide any suggestion. An agent needs the
|
|
42
|
+
* `comments:admin` scope or the `comments:accept` right, and never decides its own suggestion.
|
|
43
|
+
*/
|
|
44
|
+
declare function mayDecide(me: Me | undefined, suggestion: Pick<Suggestion, "author" | "status">): Decision;
|
|
45
|
+
|
|
46
|
+
export { CommentsClient, CommentsPanel, type CommentsPanelProps, type Decision, Me, type Need, type PanelClient, holds, mayDecide };
|