agentic-comments 0.1.0 → 0.2.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 +99 -4
- package/SKILL.md +2 -1
- package/dist/chunk-C3P5TAC3.js +770 -0
- package/dist/chunk-C43HLFQE.js +262 -0
- package/dist/chunk-RWMBGIAS.js +7 -0
- package/dist/chunk-UE5ULEXU.js +86 -0
- package/dist/chunk-ZCM2UDLN.js +172 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +205 -0
- package/dist/index.d.ts +83 -310
- package/dist/index.js +181 -719
- package/dist/local.d.ts +112 -0
- package/dist/local.js +23 -0
- package/dist/mcp-BOJM5NE6.js +11 -0
- package/dist/mcp-bin.d.ts +1 -0
- package/dist/mcp-bin.js +21 -0
- package/dist/suggestions-U8tXRLZ5.d.ts +334 -0
- package/llms.txt +2 -1
- package/package.json +19 -3
package/README.md
CHANGED
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
Comment threads and suggestions anchored to any content, from people and agents.
|
|
8
8
|
|
|
9
|
-
> Status:
|
|
10
|
-
>
|
|
9
|
+
> Status: see [npm](https://www.npmjs.com/package/agentic-comments) for the latest released version. The
|
|
10
|
+
> `main` branch can have changes that npm does not have yet.
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
14
|
-
Requires Node.js 20 or later.
|
|
14
|
+
Requires Node.js 20 or later. `yjs` is a peer dependency. Your app and this package must use the same
|
|
15
|
+
copy of `yjs`, because the package checks the Yjs types of your document. Install both:
|
|
15
16
|
|
|
16
17
|
```sh
|
|
17
18
|
npm install agentic-comments yjs
|
|
@@ -126,6 +127,92 @@ suggestions.accept(s.id, ada);
|
|
|
126
127
|
record is, and it can win settle, so every replica undoes the real edit. The sync layer must decide who
|
|
127
128
|
may write.
|
|
128
129
|
|
|
130
|
+
## CLI and MCP server
|
|
131
|
+
|
|
132
|
+
Both run on a local store: one file that holds a Yjs document. The text is in the `text` root, and
|
|
133
|
+
non-text values are in the `values` map. A file starts with a magic mark and a hash, so a damaged or zero-filled file is refused and not read as empty. A write
|
|
134
|
+
takes a lock file, saves with a rename, and runs again if the file changed meanwhile, so parallel processes
|
|
135
|
+
on one machine lose nothing. A full disk or a file size limit fails the write and leaves the old file. A lock left by a dead process, or by this process under another mark, is cleared. So is an empty lock older
|
|
136
|
+
than two seconds and any lock older than a minute. The store is for one
|
|
137
|
+
machine. It cannot check a lock held in another container or on another machine. Two containers that
|
|
138
|
+
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
|
|
139
|
+
would pass 50 MB is refused.
|
|
140
|
+
|
|
141
|
+
If the version you install has no `agentic-comments` command, build from source (see [Develop](#develop)).
|
|
142
|
+
In the cloned repo, run `npm run build` and use `node dist/cli.js` where these examples say
|
|
143
|
+
`npx agentic-comments`.
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
export AGENTIC_COMMENTS_FILE=./comments.ydoc
|
|
147
|
+
export AGENTIC_COMMENTS_AS=human:ada # kind:name. The operator sets this.
|
|
148
|
+
npx agentic-comments init --text "Hello brave world"
|
|
149
|
+
npx agentic-comments comment --text-quote brave --body "Word choice? @scribe"
|
|
150
|
+
npx agentic-comments list --status open
|
|
151
|
+
AGENTIC_COMMENTS_AS=agent_of_human:scribe npx agentic-comments suggest --text-quote brave --replace bold
|
|
152
|
+
npx agentic-comments accept <id>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
- Commands: `init`, `list`, `show`, `comment`, `reply`, `resolve`, `reopen`, `relocate`, `suggestions`,
|
|
156
|
+
`suggest`, `accept`, `reject`, `mcp`. Run `agentic-comments --help` for flags.
|
|
157
|
+
- Every result is JSON. An error is JSON on stderr with a `code`, and the exit code is 1. A usage error
|
|
158
|
+
exits 2.
|
|
159
|
+
- The principal comes from `--as` or `AGENTIC_COMMENTS_AS`. Scopes come only from
|
|
160
|
+
`AGENTIC_COMMENTS_SCOPES`, a comma list such as `comments:accept`. No flag takes a scope or an author,
|
|
161
|
+
and a flag that does not apply to a command is refused. `AGENTIC_COMMENTS_LOCK_TIMEOUT_MS` sets the wait
|
|
162
|
+
for a lock, in whole milliseconds.
|
|
163
|
+
- `npx agentic-comments mcp` (or the `agentic-comments-mcp` binary, which reads the same environment) starts
|
|
164
|
+
the MCP server on stdio. The operator fixes the principal and the
|
|
165
|
+
scopes when the server starts. No tool takes an author or a scope. A call with any key a tool does not list is refused, so an agent
|
|
166
|
+
cannot pick its own kind or rights. Tools: `list_threads`, `get_thread`, `add_comment`, `reply_to_thread`, `resolve_thread`,
|
|
167
|
+
`reopen_thread`, `relocate_thread`, `list_suggestions`, `suggest_change`, `accept_suggestion`,
|
|
168
|
+
`reject_suggestion`.
|
|
169
|
+
- A text change is `{"replace": "new text"}`. A change for a cell, slide, or canvas anchor is
|
|
170
|
+
`{"value": <JSON>}`.
|
|
171
|
+
- From code: `import { FileStore, CommentsService, operatorActor } from "agentic-comments/local"`.
|
|
172
|
+
|
|
173
|
+
## Notifications
|
|
174
|
+
|
|
175
|
+
`Notifications` turns changes into events that your app can send to a notifier. It watches the data, so it
|
|
176
|
+
sees changes from other replicas too. It replays nothing from before you created it. A first load into an
|
|
177
|
+
empty document looks like new changes, so create the stream with `muted: true` and call `unmute()` after
|
|
178
|
+
that load.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { Notifications } from "agentic-comments";
|
|
182
|
+
|
|
183
|
+
const notifications = new Notifications(comments, suggestions, { muted: true, onError: (error, source) => report(error, source) });
|
|
184
|
+
// ...load the document or connect the provider, then:
|
|
185
|
+
notifications.unmute();
|
|
186
|
+
const stop = notifications.subscribe(async (event) => {
|
|
187
|
+
if (event.type === "mention") await notify(event.mention, event.threadId); // fetch the text with the ids
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- Events: `thread.created`, `message.added`, `mention` (one per handle), `thread.resolved`,
|
|
192
|
+
`thread.reopened`, `suggestion.created`, `suggestion.accepted`, `suggestion.rejected`.
|
|
193
|
+
- An event holds ids, the actor, `machineMade`, the anchor type, `source` (`local` or `remote`), and a time.
|
|
194
|
+
It never holds the text of a comment, a suggestion, or a change. Fetch that with the ids.
|
|
195
|
+
- The same change has the same `id` on every replica. So a notifier that must
|
|
196
|
+
send once keeps the ids it has sent. Within one replica, an id is delivered at most once, and a listener
|
|
197
|
+
that throws is not retried. A replica remembers its last 10,000 ids (`seenLimit`) and drops a
|
|
198
|
+
repeat within that window. Two accepts at once give one id, and the actor can differ between replicas. A `suggestion.rejected` event
|
|
199
|
+
can be overturned: if another replica accepted at the same time, the merge ends as accepted, and a
|
|
200
|
+
`suggestion.accepted` event follows.
|
|
201
|
+
An id for a status change includes the clock time, so a clock coarser than the changes can merge two.
|
|
202
|
+
- Use `source` to decide where to send. If every replica runs a notifier, filter on `local`, or each
|
|
203
|
+
replica sends its own copy of every remote change.
|
|
204
|
+
- Events are delivered after the Yjs transaction that caused them has finished, so a listener can write to
|
|
205
|
+
the document. A listener that throws, or returns a rejected promise, cannot break a write or another
|
|
206
|
+
listener. The
|
|
207
|
+
error goes to `onError`, or to `errors()`.
|
|
208
|
+
- Write a thread in one Yjs transaction, as `add` does. A thread whose map arrives empty and gets its fields
|
|
209
|
+
and messages in one later transaction is treated as created then. A thread built in more steps than that
|
|
210
|
+
can make no event.
|
|
211
|
+
- A peer that deletes a thread or a suggestion and adds it back under the same id makes a `created` event
|
|
212
|
+
again once the id has left the `seenLimit` window.
|
|
213
|
+
- A change that arrives as a whole thread, with its replies and status inside, makes an event for each
|
|
214
|
+
message and for a resolved status. A reopen inside such a thread makes none. A message past the thread's read limit makes no event.
|
|
215
|
+
|
|
129
216
|
## Author kinds
|
|
130
217
|
|
|
131
218
|
| Kind | Meaning | Label |
|
|
@@ -138,7 +225,7 @@ suggestions.accept(s.id, ada);
|
|
|
138
225
|
|
|
139
226
|
## Limits
|
|
140
227
|
|
|
141
|
-
- No file store
|
|
228
|
+
- No HTTP API yet. The file store is for one machine. It is not a sync server.
|
|
142
229
|
- `add` checks that a text anchor points into this document and matches its quote.
|
|
143
230
|
- The library trusts the host to call `stamp()` only for a principal it authenticated.
|
|
144
231
|
- A reply to a resolved thread is refused on the replica that sees the resolve. A reply and a
|
|
@@ -149,6 +236,14 @@ suggestions.accept(s.id, ada);
|
|
|
149
236
|
on every read, so keep it fast.
|
|
150
237
|
- A local reply stops at 1,000 messages. Replicas that reply at once can pass that. A read shows the first
|
|
151
238
|
2,000 valid messages. `skipped` and `problems()` report the rest.
|
|
239
|
+
- If several processes clear one stale lock at the same moment, two writes can very rarely overlap. The
|
|
240
|
+
save check catches almost every such case. A symlink as the store path is followed. A filesystem with no
|
|
241
|
+
hard links makes `init` use a check and a rename, which can race.
|
|
242
|
+
- The CLI trusts its caller: a process that can set `AGENTIC_COMMENTS_AS` and `AGENTIC_COMMENTS_SCOPES` can
|
|
243
|
+
act as anyone. Give an agent the MCP server, where the operator fixes both. Do not give it a shell with
|
|
244
|
+
the store file and the CLI.
|
|
245
|
+
- Events come from the data and not from the calls, so a status change that two replicas make at once gives
|
|
246
|
+
each replica its own event, and a thread that arrives whole gives events for its current state only.
|
|
152
247
|
- Every replica of a document must register the same custom anchor kinds.
|
|
153
248
|
- A repeated message id hides every copy. A peer that appends a copy of a thread's only message makes
|
|
154
249
|
the thread unreadable.
|
package/SKILL.md
CHANGED
|
@@ -25,7 +25,8 @@ Check `thread.anchorState`. An `orphaned` thread has lost its content. Read it,
|
|
|
25
25
|
Suggest a change with `suggestions.add({ anchor, change, summary }, actor)`. Accept needs a person or
|
|
26
26
|
the `comments:accept` scope. You never accept or reject your own suggestion.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Over MCP, call `list_threads`, `add_comment`, `reply_to_thread`, `resolve_thread`, `suggest_change`,
|
|
29
|
+
`accept_suggestion`, and `reject_suggestion`. You never pass an author or a scope.
|
|
29
30
|
|
|
30
31
|
## Rules
|
|
31
32
|
|