agentic-comments 0.5.0 → 0.5.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 +9 -11
- package/dist/{chunk-HXXJNFEO.js → chunk-QJXI3P5D.js} +8 -1
- package/dist/{chunk-WQHJNHAR.js → chunk-REFQNIEP.js} +1 -1
- package/dist/{chunk-ABXAPWXD.js → chunk-TFRLOBJW.js} +1 -1
- package/dist/cli.js +3 -3
- package/dist/index.js +1 -1
- package/dist/local.js +1 -1
- package/dist/{mcp-JMEXA2RI.js → mcp-XUV3RPOO.js} +2 -2
- package/dist/mcp-bin.js +3 -3
- package/dist/worker.d.ts +4 -1
- package/dist/worker.js +17 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -18,8 +18,6 @@ copy of `yjs`, because the package checks the Yjs types of your document. Instal
|
|
|
18
18
|
npm install agentic-comments yjs
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
To build from source, see Develop.
|
|
22
|
-
|
|
23
21
|
## Quick start
|
|
24
22
|
|
|
25
23
|
```ts
|
|
@@ -165,10 +163,6 @@ machine. It cannot check a lock held in another container or on another machine.
|
|
|
165
163
|
share a volume can have the same process id, and each then clears the other's lock, so they can lose writes. A save that
|
|
166
164
|
would pass 50 MB is refused.
|
|
167
165
|
|
|
168
|
-
If the version you install has no `agentic-comments` command, build from source (see [Develop](#develop)).
|
|
169
|
-
In the cloned repo, run `npm run build` and use `node dist/cli.js` where these examples say
|
|
170
|
-
`npx agentic-comments`.
|
|
171
|
-
|
|
172
166
|
```sh
|
|
173
167
|
export AGENTIC_COMMENTS_FILE=./comments.ydoc
|
|
174
168
|
export AGENTIC_COMMENTS_AS=human:ada # kind:name. The operator sets this.
|
|
@@ -180,10 +174,10 @@ npx agentic-comments accept <id>
|
|
|
180
174
|
```
|
|
181
175
|
|
|
182
176
|
- Commands: `init`, `list`, `show`, `comment`, `reply`, `resolve`, `reopen`, `relocate`, `suggestions`,
|
|
183
|
-
`suggest`, `accept`, `reject`, `mcp`. Run `agentic-comments --help` for flags.
|
|
177
|
+
`suggest`, `accept`, `reject`, `mcp`. Run `npx agentic-comments --help` for flags.
|
|
184
178
|
- Every result is JSON. An error is JSON on stderr with a `code`, and the exit code is 1. A usage error
|
|
185
179
|
exits 2.
|
|
186
|
-
- The principal comes from `--as` or `AGENTIC_COMMENTS_AS`. Scopes come only from
|
|
180
|
+
- The principal comes from `--as` or `AGENTIC_COMMENTS_AS`, as `kind:name`. The name starts with A-Z a-z 0-9 `_` `-`, then uses A-Z a-z 0-9 `.` `_` `-`, and is at most 128 characters. Scopes come only from
|
|
187
181
|
`AGENTIC_COMMENTS_SCOPES`, a comma list such as `comments:accept`. No flag takes a scope or an author,
|
|
188
182
|
and a flag that does not apply to a command is refused. `AGENTIC_COMMENTS_LOCK_TIMEOUT_MS` sets the wait
|
|
189
183
|
for a lock, in whole milliseconds.
|
|
@@ -203,9 +197,13 @@ npx agentic-comments accept <id>
|
|
|
203
197
|
document in a D1 database through the `Store` port of `agentic-identity`. It checks every request with the
|
|
204
198
|
`Auth` port, so the host picks who the caller is and no request carries an author.
|
|
205
199
|
|
|
206
|
-
Set the principals as a secret. It is JSON from a bearer token
|
|
207
|
-
`{ "as": "kind:name", "scopes": [...] }`.
|
|
208
|
-
|
|
200
|
+
Set the principals as a secret. It is JSON from a bearer token to `kind:name`, or to
|
|
201
|
+
`{ "as": "kind:name", "scopes": [...] }`. A token is 32 to 512 bytes, from A-Z a-z 0-9 `_` `-`, so a base64 token with `+` or `/` is refused.
|
|
202
|
+
A name starts with A-Z a-z 0-9 `_` `-`, then uses A-Z a-z 0-9 `.` `_` `-`, and is at most 128 characters.
|
|
203
|
+
One bad entry refuses the whole table. A request with no valid token gets `401`.
|
|
204
|
+
A request whose `Authorization` header is not `Bearer` followed by 1 to 512 bytes of A-Z a-z 0-9 `_` `-` gets `401`, before any custom `Auth` runs.
|
|
205
|
+
A write with no `Authorization` header (a session cookie, for example) gets `403` unless its `Origin` is in the `origins`
|
|
206
|
+
option of `createApp`. The default lists none.
|
|
209
207
|
|
|
210
208
|
```sh
|
|
211
209
|
wrangler secret put AGENTIC_COMMENTS_TOKENS
|
|
@@ -244,6 +244,7 @@ var FileStore = class {
|
|
|
244
244
|
};
|
|
245
245
|
|
|
246
246
|
// src/operator.ts
|
|
247
|
+
import { PrincipalParseError, parsePrincipal } from "agentic-identity";
|
|
247
248
|
function operatorActor(as, scopes) {
|
|
248
249
|
const value = as?.trim();
|
|
249
250
|
const cut = value === void 0 ? -1 : value.indexOf(":");
|
|
@@ -251,7 +252,13 @@ function operatorActor(as, scopes) {
|
|
|
251
252
|
throw new CommentsError("INVALID_AUTHOR", `set the principal as kind:name, for example human:ada. Kinds: ${PRINCIPAL_KINDS.join(", ")}`);
|
|
252
253
|
}
|
|
253
254
|
const list = scopes === void 0 || scopes.trim() === "" ? [] : scopes.split(",").map((s) => s.trim());
|
|
254
|
-
|
|
255
|
+
try {
|
|
256
|
+
const { kind, id } = parsePrincipal({ kind: value.slice(0, cut), id: value.slice(cut + 1) });
|
|
257
|
+
return stamp({ kind, name: id, scopes: list });
|
|
258
|
+
} catch (error) {
|
|
259
|
+
if (!(error instanceof PrincipalParseError)) throw error;
|
|
260
|
+
throw new CommentsError("INVALID_AUTHOR", `the principal needs a known kind (${PRINCIPAL_KINDS.join(", ")}) and a name of A-Z a-z 0-9 . _ -`);
|
|
261
|
+
}
|
|
255
262
|
}
|
|
256
263
|
|
|
257
264
|
export {
|
package/dist/cli.js
CHANGED
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
FileStore,
|
|
4
4
|
lockTimeoutFrom,
|
|
5
5
|
operatorActor
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QJXI3P5D.js";
|
|
7
7
|
import {
|
|
8
8
|
VERSION
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-REFQNIEP.js";
|
|
10
10
|
import {
|
|
11
11
|
CommentsService,
|
|
12
12
|
TEXT_ROOT
|
|
@@ -155,7 +155,7 @@ async function runCli(argv, io) {
|
|
|
155
155
|
return 0;
|
|
156
156
|
}
|
|
157
157
|
if (p.command === "mcp") {
|
|
158
|
-
const { startMcp } = await import("./mcp-
|
|
158
|
+
const { startMcp } = await import("./mcp-XUV3RPOO.js");
|
|
159
159
|
await startMcp(store, operatorActor(p.flags["--as"] ?? io.env.AGENTIC_COMMENTS_AS, io.env.AGENTIC_COMMENTS_SCOPES));
|
|
160
160
|
return 0;
|
|
161
161
|
}
|
package/dist/index.js
CHANGED
package/dist/local.js
CHANGED
package/dist/mcp-bin.js
CHANGED
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
FileStore,
|
|
4
4
|
lockTimeoutFrom,
|
|
5
5
|
operatorActor
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QJXI3P5D.js";
|
|
7
7
|
import {
|
|
8
8
|
startMcp
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-TFRLOBJW.js";
|
|
10
10
|
import {
|
|
11
11
|
VERSION
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-REFQNIEP.js";
|
|
13
13
|
import "./chunk-NQWRFKJ6.js";
|
|
14
14
|
import "./chunk-BSNBDKR2.js";
|
|
15
15
|
|
package/dist/worker.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { Auth, Store, PrincipalContext, Region } from 'agentic-identity';
|
|
3
|
+
import { RequirePrincipalOptions } from 'agentic-identity/http';
|
|
3
4
|
import { D1Like } from 'agentic-identity/cloudflare';
|
|
4
5
|
import { A as Actor } from './suggestions-CvJwo6r4.js';
|
|
5
6
|
import { C as CommentsService } from './service-hpWbnSmc.js';
|
|
@@ -13,7 +14,7 @@ interface WorkerEnv {
|
|
|
13
14
|
/** D1 database: each document, with its threads, as a Yjs update. */
|
|
14
15
|
DB?: D1Like;
|
|
15
16
|
/**
|
|
16
|
-
* JSON object: bearer token (32 bytes
|
|
17
|
+
* JSON object: bearer token (32 to 512 bytes of A-Z a-z 0-9 _ -) to `kind:name` (the name uses A-Z a-z 0-9 . _ -), or to `{ "as": "kind:name", "scopes": ["comments:write"] }`.
|
|
17
18
|
* Set it as a secret. A short token or a bad entry refuses the whole config.
|
|
18
19
|
*/
|
|
19
20
|
AGENTIC_COMMENTS_TOKENS?: string;
|
|
@@ -39,6 +40,8 @@ type DocsSource = CommentsDocs | ((env: WorkerEnv) => Promise<CommentsDocs>);
|
|
|
39
40
|
interface AppOptions {
|
|
40
41
|
/** The credential check. The default reads `AGENTIC_COMMENTS_TOKENS`. Pass any `Auth` from agentic-identity to replace it. */
|
|
41
42
|
auth?: Auth | ((env: WorkerEnv) => Auth);
|
|
43
|
+
/** Origins that may send a write with a session cookie. A bearer token needs none. Passed to `requirePrincipal`. */
|
|
44
|
+
origins?: RequirePrincipalOptions["origins"];
|
|
42
45
|
}
|
|
43
46
|
type AppEnv = {
|
|
44
47
|
Bindings: WorkerEnv;
|
package/dist/worker.js
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
ACCEPT_SCOPE,
|
|
7
7
|
CommentsError,
|
|
8
|
-
PRINCIPAL_KINDS,
|
|
9
8
|
exact,
|
|
10
9
|
invalid,
|
|
11
10
|
stamp
|
|
@@ -13,7 +12,8 @@ import {
|
|
|
13
12
|
|
|
14
13
|
// src/worker.ts
|
|
15
14
|
import { Hono } from "hono";
|
|
16
|
-
import { StoreConflictError, assertRegion, isScope, parseRegion, hasScope } from "agentic-identity";
|
|
15
|
+
import { StoreConflictError, assertRegion, isScope, parseRegion, hasScope, parsePrincipal } from "agentic-identity";
|
|
16
|
+
import { requirePrincipal } from "agentic-identity/http";
|
|
17
17
|
import { D1_SCHEMA, createD1Store } from "agentic-identity/cloudflare";
|
|
18
18
|
import * as Y from "yjs";
|
|
19
19
|
var READ = "comments:read";
|
|
@@ -22,6 +22,7 @@ var WRITE = "comments:write";
|
|
|
22
22
|
var ADMIN = "comments:admin";
|
|
23
23
|
var DEFAULT_SCOPES = [COMMENT];
|
|
24
24
|
var MIN_TOKEN_BYTES = 32;
|
|
25
|
+
var TOKEN_SHAPE = /^[A-Za-z0-9_-]{1,512}$/;
|
|
25
26
|
var warned = /* @__PURE__ */ new Set();
|
|
26
27
|
function refuse(reason) {
|
|
27
28
|
if (!warned.has(reason)) {
|
|
@@ -40,9 +41,13 @@ function contextOf(entry) {
|
|
|
40
41
|
const who = typeof entry === "string" ? entry : object?.as;
|
|
41
42
|
const cut = typeof who === "string" ? who.indexOf(":") : -1;
|
|
42
43
|
if (typeof who !== "string" || cut < 1 || cut === who.length - 1) return void 0;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
let kind;
|
|
45
|
+
let name;
|
|
46
|
+
try {
|
|
47
|
+
({ kind, id: name } = parsePrincipal({ kind: who.slice(0, cut), id: who.slice(cut + 1) }));
|
|
48
|
+
} catch {
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
46
51
|
const given = object?.scopes;
|
|
47
52
|
if (given !== void 0 && !(Array.isArray(given) && given.every(isScope))) return void 0;
|
|
48
53
|
try {
|
|
@@ -61,6 +66,7 @@ function createTokenAuth(raw) {
|
|
|
61
66
|
for (const [token, entry] of Object.entries(parsed)) {
|
|
62
67
|
const context = contextOf(entry);
|
|
63
68
|
if (new TextEncoder().encode(token).length < MIN_TOKEN_BYTES) throw new Error(`a token is shorter than ${MIN_TOKEN_BYTES} bytes`);
|
|
69
|
+
if (!TOKEN_SHAPE.test(token)) throw new Error("a token holds a character outside A-Z a-z 0-9 _ - or is over 512 bytes");
|
|
64
70
|
if (!context) throw new Error("an entry is not a valid kind:name or { as, scopes }");
|
|
65
71
|
table.set(token, context);
|
|
66
72
|
}
|
|
@@ -186,8 +192,12 @@ function createApp(source, options = {}) {
|
|
|
186
192
|
app2.get("/health", (c) => c.json({ ok: true, pack: "agentic-comments" }));
|
|
187
193
|
app2.use("/api/v1/*", async (c, next) => {
|
|
188
194
|
const auth = typeof options.auth === "function" ? options.auth(c.env ?? {}) : options.auth ?? createTokenAuth(c.env?.AGENTIC_COMMENTS_TOKENS);
|
|
189
|
-
const context = await
|
|
190
|
-
if (
|
|
195
|
+
const context = await requirePrincipal(c.req.raw, auth, { origins: options.origins });
|
|
196
|
+
if (context instanceof Response) {
|
|
197
|
+
if (context.status === 401) return Response.json({ error: { code: "UNAUTHENTICATED", message: "send a valid bearer token" } }, { status: 401, headers: { "www-authenticate": "Bearer" } });
|
|
198
|
+
if (context.status === 403) return fail("FORBIDDEN", "this credential may not do this", 403);
|
|
199
|
+
return fail("INTERNAL", "the credential check is unavailable", context.status);
|
|
200
|
+
}
|
|
191
201
|
c.set("context", context);
|
|
192
202
|
await next();
|
|
193
203
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-comments",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Comment threads and suggestions anchored to any content, from people and agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"comments",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
79
|
-
"agentic-identity": "^0.
|
|
79
|
+
"agentic-identity": "^0.6.0",
|
|
80
80
|
"hono": "^4.13.14",
|
|
81
81
|
"zod": "^3.25.76"
|
|
82
82
|
},
|