agentic-documents 0.0.0-stage → 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/CHANGELOG.md +36 -0
- package/LICENSE +21 -0
- package/README.md +237 -2
- package/SECURITY.md +23 -0
- package/SKILL.md +35 -0
- package/dist/chunk-5Y66UCTE.js +7 -0
- package/dist/chunk-FZA5LQV3.js +150 -0
- package/dist/chunk-GYQFTF2E.js +389 -0
- package/dist/chunk-IU3YIQ4Y.js +232 -0
- package/dist/chunk-R5XUTBC3.js +177 -0
- package/dist/chunk-TFCRPEEM.js +224 -0
- package/dist/chunk-YBBQNCMC.js +744 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +165 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.js +44 -0
- package/dist/live-worker.d.ts +20 -0
- package/dist/live-worker.js +27 -0
- package/dist/live.d.ts +73 -0
- package/dist/live.js +12 -0
- package/dist/mcp-P2C75IIG.js +40 -0
- package/dist/service-BKkxEnaJ.d.ts +181 -0
- package/dist/worker.d.ts +50 -0
- package/dist/worker.js +15 -0
- package/llms.txt +15 -0
- package/package.json +104 -4
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import * as Y from 'yjs';
|
|
2
|
+
import { Blobs, Store } from 'agentic-identity';
|
|
3
|
+
|
|
4
|
+
/** A ProseMirror node in JSON form, the shape y-prosemirror reads and writes. */
|
|
5
|
+
interface PmNode {
|
|
6
|
+
type: string;
|
|
7
|
+
attrs?: Record<string, unknown>;
|
|
8
|
+
content?: PmNode[];
|
|
9
|
+
text?: string;
|
|
10
|
+
marks?: {
|
|
11
|
+
type: string;
|
|
12
|
+
attrs?: Record<string, unknown>;
|
|
13
|
+
}[];
|
|
14
|
+
}
|
|
15
|
+
/** Parse GitHub-flavored Markdown into top-level ProseMirror blocks. */
|
|
16
|
+
declare function markdownToBlocks(markdown: string): PmNode[];
|
|
17
|
+
/** Serialize top-level ProseMirror blocks to GitHub-flavored Markdown. */
|
|
18
|
+
declare function blocksToMarkdown(nodes: PmNode[]): string;
|
|
19
|
+
|
|
20
|
+
declare const PRINCIPAL_KINDS: readonly ["human", "agent_of_human", "agent_of_agent", "agent", "user_token"];
|
|
21
|
+
type PrincipalKind = (typeof PRINCIPAL_KINDS)[number];
|
|
22
|
+
/** Who made a change. Every mutation needs one, so machine-made work stays labeled. */
|
|
23
|
+
interface Principal {
|
|
24
|
+
kind: PrincipalKind;
|
|
25
|
+
name: string;
|
|
26
|
+
/** Rights this principal was granted, such as `docs:accept`. Used to decide, never stored in the doc. */
|
|
27
|
+
scopes?: string[];
|
|
28
|
+
}
|
|
29
|
+
/** A text range that follows its text through concurrent edits. */
|
|
30
|
+
interface Anchor {
|
|
31
|
+
text: string;
|
|
32
|
+
start: Record<string, unknown>;
|
|
33
|
+
end: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
type TextTarget = {
|
|
36
|
+
text: string;
|
|
37
|
+
occurrence?: number;
|
|
38
|
+
at?: "before" | "after";
|
|
39
|
+
};
|
|
40
|
+
type AnchorTarget = {
|
|
41
|
+
anchor: Anchor;
|
|
42
|
+
at?: "before" | "after";
|
|
43
|
+
};
|
|
44
|
+
type SectionTarget = {
|
|
45
|
+
section: string;
|
|
46
|
+
at?: "start" | "end";
|
|
47
|
+
};
|
|
48
|
+
type Target = TextTarget | AnchorTarget | SectionTarget;
|
|
49
|
+
interface Section {
|
|
50
|
+
id: string;
|
|
51
|
+
level: number;
|
|
52
|
+
title: string;
|
|
53
|
+
}
|
|
54
|
+
interface EditEntry {
|
|
55
|
+
op: "create" | "append" | "insert" | "replace" | "delete";
|
|
56
|
+
at: string;
|
|
57
|
+
author: Principal;
|
|
58
|
+
/** Counts of characters (text targets) or blocks (section targets). Never content. */
|
|
59
|
+
inserted: number;
|
|
60
|
+
deleted: number;
|
|
61
|
+
section?: string;
|
|
62
|
+
/** Set when an accepted suggestion caused the edit. `author` is who suggested it. */
|
|
63
|
+
suggestion?: {
|
|
64
|
+
id: string;
|
|
65
|
+
author: Principal;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** When the edit was logged, and where it put new text (relative positions that follow the text). */
|
|
69
|
+
interface EditResult {
|
|
70
|
+
at: string;
|
|
71
|
+
inserted?: {
|
|
72
|
+
start: Record<string, unknown>;
|
|
73
|
+
end: Record<string, unknown>;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
interface DocOptions {
|
|
77
|
+
now?: () => Date;
|
|
78
|
+
}
|
|
79
|
+
type Range = {
|
|
80
|
+
unit: Y.XmlText;
|
|
81
|
+
start: number;
|
|
82
|
+
end: number;
|
|
83
|
+
};
|
|
84
|
+
/** `kind:name`, for example `agent_of_human:scribe`. Validation happens when a change needs it. */
|
|
85
|
+
declare function parseAuthor(value: string | undefined): Principal | undefined;
|
|
86
|
+
declare class AgenticDoc {
|
|
87
|
+
readonly ydoc: Y.Doc;
|
|
88
|
+
readonly now: () => Date;
|
|
89
|
+
constructor(ydoc?: Y.Doc, options?: DocOptions);
|
|
90
|
+
static fromMarkdown(markdown: string, author: Principal, options?: DocOptions): AgenticDoc;
|
|
91
|
+
static fromUpdate(update: Uint8Array, options?: DocOptions): AgenticDoc;
|
|
92
|
+
encode(): Uint8Array;
|
|
93
|
+
applyUpdate(update: Uint8Array): void;
|
|
94
|
+
/** A new replica with its own client id, holding the same state. */
|
|
95
|
+
fork(): AgenticDoc;
|
|
96
|
+
private get fragment();
|
|
97
|
+
private get log();
|
|
98
|
+
edits(): EditEntry[];
|
|
99
|
+
private change;
|
|
100
|
+
toJSON(): PmNode;
|
|
101
|
+
toMarkdown(): string;
|
|
102
|
+
/** Sections in order. Blocks before the first heading come first, as the `preamble` section at level 0. */
|
|
103
|
+
outline(): Section[];
|
|
104
|
+
readSection(id: string): string;
|
|
105
|
+
private headings;
|
|
106
|
+
/**
|
|
107
|
+
* A section runs from its heading to the next heading of the same or a higher level. The preamble
|
|
108
|
+
* has no heading and runs to the first heading. It is always a valid target, even when empty.
|
|
109
|
+
*/
|
|
110
|
+
private range;
|
|
111
|
+
private find;
|
|
112
|
+
private pick;
|
|
113
|
+
/** Pin a text range so later edits by other replicas do not move it. */
|
|
114
|
+
anchor(text: string, occurrence?: number): Anchor;
|
|
115
|
+
resolve(target: TextTarget | AnchorTarget): Range;
|
|
116
|
+
edit(op: "insert" | "replace" | "delete", target: TextTarget | AnchorTarget, content: string, author: Principal, extra?: Pick<EditEntry, "suggestion">): EditResult;
|
|
117
|
+
private editSection;
|
|
118
|
+
/** Insert Markdown into a section, or plain text next to matched text. */
|
|
119
|
+
insert(target: Target, content: string, author: Principal): void;
|
|
120
|
+
/** Replace a section body (the heading stays), or the matched text. */
|
|
121
|
+
replace(target: Target, content: string, author: Principal): void;
|
|
122
|
+
/** Delete a whole section with its subsections, or the matched text. */
|
|
123
|
+
delete(target: Target, author: Principal): void;
|
|
124
|
+
append(markdown: string, author: Principal): void;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** What the catalog keeps for each document. The author kind stays, so machine-made work stays labeled. */
|
|
128
|
+
interface DocInfo {
|
|
129
|
+
createdBy: {
|
|
130
|
+
kind: PrincipalKind;
|
|
131
|
+
name: string;
|
|
132
|
+
};
|
|
133
|
+
createdAt: number;
|
|
134
|
+
}
|
|
135
|
+
interface DocsPorts {
|
|
136
|
+
/** Holds each document as a Yjs update. Saves are conditional on the version that was read. */
|
|
137
|
+
blobs: Blobs;
|
|
138
|
+
/** Holds the catalog: who created each document, and when. */
|
|
139
|
+
store: Store;
|
|
140
|
+
}
|
|
141
|
+
/** What every command needs: make a document, read it, and change it. A live room can stand behind it as well as the ports. */
|
|
142
|
+
interface DocAccess {
|
|
143
|
+
create(id: string, markdown: string, author: Principal): Promise<void>;
|
|
144
|
+
read<T>(id: string, run: (doc: AgenticDoc) => T): Promise<T>;
|
|
145
|
+
write<T>(id: string, run: (doc: AgenticDoc) => T): Promise<T>;
|
|
146
|
+
}
|
|
147
|
+
/** Loads and saves documents as Yjs updates in a Blobs port. The CLI, MCP server, and API share it. */
|
|
148
|
+
declare class DocsService implements DocAccess {
|
|
149
|
+
private readonly options;
|
|
150
|
+
private readonly blobs;
|
|
151
|
+
private readonly store;
|
|
152
|
+
constructor(ports: DocsPorts, options?: DocOptions);
|
|
153
|
+
private key;
|
|
154
|
+
create(id: string, markdown: string, author: Principal): Promise<void>;
|
|
155
|
+
/** The stored document as a Yjs update. A live client seeds its room from it. */
|
|
156
|
+
state(id: string): Promise<Uint8Array>;
|
|
157
|
+
/**
|
|
158
|
+
* Merge a Yjs update from a live room into the stored document, and create the document when it
|
|
159
|
+
* has none. A merge is safe to repeat and to run in any order. The save is conditional, so two
|
|
160
|
+
* checkpoints at once both land.
|
|
161
|
+
*/
|
|
162
|
+
checkpoint(id: string, update: Uint8Array, author: Principal): Promise<void>;
|
|
163
|
+
/**
|
|
164
|
+
* The encoded document, once it reads back and every stored entry has the shape the commands rely on. Yjs does not
|
|
165
|
+
* check types, so an update can put text where the editor expects blocks, or a thread with no messages, and then a
|
|
166
|
+
* command fails on every later call.
|
|
167
|
+
*/
|
|
168
|
+
private checked;
|
|
169
|
+
private fits;
|
|
170
|
+
private catalog;
|
|
171
|
+
/** Who created the document and when, or null when it has no catalog entry (made before the catalog, or a failed catalog write). */
|
|
172
|
+
info(id: string): Promise<DocInfo | null>;
|
|
173
|
+
read<T>(id: string, run: (doc: AgenticDoc) => T): Promise<T>;
|
|
174
|
+
/**
|
|
175
|
+
* Load, run the change, and save only if nobody saved in between. When someone did, load again and
|
|
176
|
+
* run the change again, so a check such as "is it still pending" sees the new state.
|
|
177
|
+
*/
|
|
178
|
+
write<T>(id: string, run: (doc: AgenticDoc) => T): Promise<T>;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { type Anchor as A, type DocAccess as D, type EditEntry as E, type Principal as P, type Section as S, type TextTarget as T, AgenticDoc as a, type AnchorTarget as b, type PmNode as c, type DocInfo as d, type DocOptions as e, type DocsPorts as f, DocsService as g, PRINCIPAL_KINDS as h, type PrincipalKind as i, type SectionTarget as j, type Target as k, blocksToMarkdown as l, markdownToBlocks as m, parseAuthor as p };
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { Region } from 'agentic-identity';
|
|
3
|
+
import { D1Like, R2Like } from 'agentic-identity/cloudflare';
|
|
4
|
+
import { Realtime, Role } from 'agentic-realtime';
|
|
5
|
+
import { g as DocsService, P as Principal } from './service-BKkxEnaJ.js';
|
|
6
|
+
import 'yjs';
|
|
7
|
+
|
|
8
|
+
interface WorkerEnv {
|
|
9
|
+
/**
|
|
10
|
+
* Where the data lives: "eu" or "us". It is a claim you make at deploy time, with no default.
|
|
11
|
+
* "unknown" skips the region check. Local D1 reports no region, so "unknown" needs `AGENTIC_DOCS_UNSAFE_REGION=1` too.
|
|
12
|
+
*/
|
|
13
|
+
AGENTIC_DOCS_REGION?: string;
|
|
14
|
+
/** Set to "1" to accept the region "unknown" under `wrangler dev`. Never set it in production. */
|
|
15
|
+
AGENTIC_DOCS_UNSAFE_REGION?: string;
|
|
16
|
+
/** D1 database: the catalog of documents. Create it with `wrangler d1 create agentic-documents --location weur`. */
|
|
17
|
+
DB?: D1Like;
|
|
18
|
+
/** R2 bucket: each document as a Yjs update. Create it with `--jurisdiction eu`. */
|
|
19
|
+
DOCS?: R2Like;
|
|
20
|
+
/**
|
|
21
|
+
* JSON object: bearer token (32 bytes or more) to `kind:name`, or to `{ "as": "kind:name", "scopes": ["docs:accept"], "role": "viewer" }`.
|
|
22
|
+
* A role is `editor` (the default) or `viewer`. A viewer reads and cannot write, over HTTP or in a live room.
|
|
23
|
+
* Set it as a secret. A short token or a bad entry refuses the whole config.
|
|
24
|
+
*/
|
|
25
|
+
AGENTIC_DOCS_TOKENS?: string;
|
|
26
|
+
}
|
|
27
|
+
type DocRole = Extract<Role, "editor" | "viewer">;
|
|
28
|
+
/** A service, or a function that makes one from the Worker bindings. */
|
|
29
|
+
type ServiceSource = DocsService | ((env: WorkerEnv) => Promise<DocsService>);
|
|
30
|
+
type AppEnv = {
|
|
31
|
+
Bindings: WorkerEnv;
|
|
32
|
+
Variables: {
|
|
33
|
+
author: Principal;
|
|
34
|
+
role: DocRole;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
interface AppOptions {
|
|
38
|
+
/** Makes the live-room server from the Worker bindings. Without it, the ws route answers 404. */
|
|
39
|
+
live?: (env: WorkerEnv) => Realtime;
|
|
40
|
+
}
|
|
41
|
+
declare function createApp(source: ServiceSource, options?: AppOptions): Hono<AppEnv>;
|
|
42
|
+
/** The region claim, or a MISCONFIGURED error. The HTTP API and the live rooms both use it, so neither runs without it. */
|
|
43
|
+
declare function regionOf(env: WorkerEnv): Region;
|
|
44
|
+
/** The service over D1 and R2. One region claim covers D1 and R2. The bucket is declared with the "eu" jurisdiction in wrangler.jsonc: keep the two in step. */
|
|
45
|
+
declare function serviceFor(env: WorkerEnv): Promise<DocsService>;
|
|
46
|
+
declare const _default: {
|
|
47
|
+
fetch: (request: Request, env: WorkerEnv, ctx: unknown) => Response | Promise<Response>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export { type AppOptions, type DocRole, type ServiceSource, type WorkerEnv, createApp, _default as default, regionOf, serviceFor };
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createApp,
|
|
3
|
+
regionOf,
|
|
4
|
+
serviceFor,
|
|
5
|
+
worker_default
|
|
6
|
+
} from "./chunk-IU3YIQ4Y.js";
|
|
7
|
+
import "./chunk-FZA5LQV3.js";
|
|
8
|
+
import "./chunk-GYQFTF2E.js";
|
|
9
|
+
import "./chunk-YBBQNCMC.js";
|
|
10
|
+
export {
|
|
11
|
+
createApp,
|
|
12
|
+
worker_default as default,
|
|
13
|
+
regionOf,
|
|
14
|
+
serviceFor
|
|
15
|
+
};
|
package/llms.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# agentic-documents
|
|
2
|
+
|
|
3
|
+
Write documents with people and agents in real time.
|
|
4
|
+
|
|
5
|
+
Keywords: documents, editor, rich-text, tiptap, yjs, collaboration, agents.
|
|
6
|
+
|
|
7
|
+
- SDK: import { AgenticDoc } from "agentic-documents".
|
|
8
|
+
- Read as Markdown, read an outline, edit by section id or exact text.
|
|
9
|
+
- CLI: npx agentic-documents <command> <id>. MCP: npx agentic-documents mcp --as <kind>:<name>.
|
|
10
|
+
- Every edit carries an author kind and name.
|
|
11
|
+
|
|
12
|
+
## Docs
|
|
13
|
+
|
|
14
|
+
- README: https://github.com/pooriaarab/agentic-documents
|
|
15
|
+
- License: MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,106 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-documents",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Write documents with people and agents in real time.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"documents",
|
|
7
|
+
"editor",
|
|
8
|
+
"rich-text",
|
|
9
|
+
"tiptap",
|
|
10
|
+
"collaboration",
|
|
11
|
+
"agents",
|
|
12
|
+
"mcp",
|
|
13
|
+
"cli",
|
|
14
|
+
"cloudflare"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "Pooria Arab",
|
|
18
|
+
"homepage": "https://github.com/pooriaarab/agentic-documents#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/pooriaarab/agentic-documents/issues"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/pooriaarab/agentic-documents.git"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"private": false,
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"SECURITY.md",
|
|
34
|
+
"SKILL.md",
|
|
35
|
+
"CHANGELOG.md",
|
|
36
|
+
"llms.txt"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"mcpName": "io.github.pooriaarab/agentic-documents",
|
|
42
|
+
"main": "./dist/index.js",
|
|
43
|
+
"types": "./dist/index.d.ts",
|
|
44
|
+
"exports": {
|
|
45
|
+
".": {
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
47
|
+
"import": "./dist/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./worker": {
|
|
50
|
+
"types": "./dist/worker.d.ts",
|
|
51
|
+
"import": "./dist/worker.js"
|
|
52
|
+
},
|
|
53
|
+
"./live": {
|
|
54
|
+
"types": "./dist/live.d.ts",
|
|
55
|
+
"import": "./dist/live.js"
|
|
56
|
+
},
|
|
57
|
+
"./live-worker": {
|
|
58
|
+
"types": "./dist/live-worker.d.ts",
|
|
59
|
+
"import": "./dist/live-worker.js"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "tsup",
|
|
64
|
+
"prepack": "npm run build",
|
|
65
|
+
"typecheck": "tsc --noEmit",
|
|
66
|
+
"test": "vitest run",
|
|
67
|
+
"clean": "rm -rf dist",
|
|
68
|
+
"ci:local": "npm run build && npm run typecheck && npm test"
|
|
69
|
+
},
|
|
70
|
+
"dependencies": {
|
|
71
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
72
|
+
"agentic-identity": "^0.3.0",
|
|
73
|
+
"agentic-realtime": "^0.1.0",
|
|
74
|
+
"fflate": "^0.8.3",
|
|
75
|
+
"hono": "^4.13.14",
|
|
76
|
+
"lib0": "^0.2.119",
|
|
77
|
+
"mdast-util-from-markdown": "^2.1.0",
|
|
78
|
+
"mdast-util-gfm": "^3.1.0",
|
|
79
|
+
"mdast-util-to-markdown": "^2.2.1",
|
|
80
|
+
"micromark-extension-gfm": "^3.0.0",
|
|
81
|
+
"prosemirror-model": "^1.25.12",
|
|
82
|
+
"prosemirror-state": "^1.4.4",
|
|
83
|
+
"prosemirror-view": "^1.42.8",
|
|
84
|
+
"y-prosemirror": "^1.3.7",
|
|
85
|
+
"y-protocols": "^1.0.7",
|
|
86
|
+
"yjs": "^13.6.33",
|
|
87
|
+
"zod": "^3.25.0"
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@tiptap/core": "^3.32.1",
|
|
91
|
+
"@tiptap/extension-image": "^3.32.1",
|
|
92
|
+
"@tiptap/extension-list": "^3.32.1",
|
|
93
|
+
"@tiptap/extension-table": "^3.32.1",
|
|
94
|
+
"@tiptap/pm": "^3.32.1",
|
|
95
|
+
"@tiptap/starter-kit": "^3.32.1",
|
|
96
|
+
"@types/mdast": "^4.0.4",
|
|
97
|
+
"@types/node": "^22.0.0",
|
|
98
|
+
"tsup": "^8.0.0",
|
|
99
|
+
"typescript": "^5.6.0",
|
|
100
|
+
"vitest": "^3.0.0",
|
|
101
|
+
"wrangler": "^4.155.0"
|
|
102
|
+
},
|
|
103
|
+
"bin": {
|
|
104
|
+
"agentic-documents": "./dist/cli.js"
|
|
105
|
+
}
|
|
106
|
+
}
|