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
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createFileBlobs,
|
|
4
|
+
createFileStore
|
|
5
|
+
} from "./chunk-TFCRPEEM.js";
|
|
6
|
+
import {
|
|
7
|
+
LiveService,
|
|
8
|
+
whoAmI
|
|
9
|
+
} from "./chunk-R5XUTBC3.js";
|
|
10
|
+
import {
|
|
11
|
+
DocsService
|
|
12
|
+
} from "./chunk-FZA5LQV3.js";
|
|
13
|
+
import {
|
|
14
|
+
VERSION
|
|
15
|
+
} from "./chunk-5Y66UCTE.js";
|
|
16
|
+
import {
|
|
17
|
+
commands
|
|
18
|
+
} from "./chunk-GYQFTF2E.js";
|
|
19
|
+
import {
|
|
20
|
+
DocError,
|
|
21
|
+
parseAuthor
|
|
22
|
+
} from "./chunk-YBBQNCMC.js";
|
|
23
|
+
|
|
24
|
+
// src/cli.ts
|
|
25
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
26
|
+
import { join } from "path";
|
|
27
|
+
import { parseArgs } from "util";
|
|
28
|
+
var NAME = "agentic-documents";
|
|
29
|
+
var flagNames = [...new Set(commands.flatMap((c) => Object.keys(c.shape)))].filter((k) => k !== "id");
|
|
30
|
+
var options = {
|
|
31
|
+
...Object.fromEntries(flagNames.map((k) => [k, { type: "string" }])),
|
|
32
|
+
as: { type: "string" },
|
|
33
|
+
scopes: { type: "string" },
|
|
34
|
+
dir: { type: "string" },
|
|
35
|
+
live: { type: "string" },
|
|
36
|
+
file: { type: "string" },
|
|
37
|
+
out: { type: "string" },
|
|
38
|
+
help: { type: "boolean", short: "h" },
|
|
39
|
+
version: { type: "boolean", short: "V" }
|
|
40
|
+
};
|
|
41
|
+
function help() {
|
|
42
|
+
const lines = commands.map((c) => ` ${c.name.padEnd(12)}${c.description}`);
|
|
43
|
+
return [
|
|
44
|
+
`${NAME} ${VERSION}`,
|
|
45
|
+
"",
|
|
46
|
+
`Usage: ${NAME} <command> <id> [flags]`,
|
|
47
|
+
"",
|
|
48
|
+
"Commands:",
|
|
49
|
+
...lines,
|
|
50
|
+
" mcp Start the MCP server on stdio.",
|
|
51
|
+
"",
|
|
52
|
+
"Flags:",
|
|
53
|
+
" --as <kind:name> Who makes the change. Or set AGENTIC_DOCS_AS. Kinds: human, agent_of_human,",
|
|
54
|
+
" agent_of_agent, agent, user_token.",
|
|
55
|
+
" --scopes <a,b> Rights for the author, such as docs:accept. Or set AGENTIC_DOCS_SCOPES. An agent",
|
|
56
|
+
" needs docs:accept to accept a suggestion.",
|
|
57
|
+
" --live <url> Join live rooms on this server, as the author of AGENTIC_DOCS_TOKEN. Or set",
|
|
58
|
+
" AGENTIC_DOCS_LIVE_URL. The server sets your author kind, so --as, --scopes, and --dir are refused.",
|
|
59
|
+
" --dir <path> Where documents live. Or set AGENTIC_DOCS_DIR. Default: .agentic-documents",
|
|
60
|
+
" --file <path> Read content (or markdown for new) from a file.",
|
|
61
|
+
" --out <path> Write the export to a file.",
|
|
62
|
+
" --<field> <value> Any field of the command, such as --text, --section, --occurrence."
|
|
63
|
+
].join("\n");
|
|
64
|
+
}
|
|
65
|
+
function bindValues(argv) {
|
|
66
|
+
const out = [];
|
|
67
|
+
for (let i = 0; i < argv.length; i++) {
|
|
68
|
+
const name = argv[i].startsWith("--") && !argv[i].includes("=") ? argv[i].slice(2) : void 0;
|
|
69
|
+
const takesValue = name !== void 0 && options[name]?.type === "string";
|
|
70
|
+
out.push(takesValue && i + 1 < argv.length ? `${argv[i]}=${argv[++i]}` : argv[i]);
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
async function main(argv, env = process.env) {
|
|
75
|
+
let parsed;
|
|
76
|
+
try {
|
|
77
|
+
parsed = parseArgs({ args: bindValues(argv), options, allowPositionals: true });
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
80
|
+
return 2;
|
|
81
|
+
}
|
|
82
|
+
const { values, positionals } = parsed;
|
|
83
|
+
const [name, id] = positionals;
|
|
84
|
+
if (values.version || values.help || name === void 0) {
|
|
85
|
+
console.log(values.version ? VERSION : help());
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
const liveUrl = values.live ?? (env.AGENTIC_DOCS_LIVE_URL || void 0);
|
|
89
|
+
let service;
|
|
90
|
+
let author;
|
|
91
|
+
if (liveUrl !== void 0) {
|
|
92
|
+
if (!/^https?:\/\/[^/\s]+/.test(liveUrl)) {
|
|
93
|
+
console.error(`--live needs an http:// or https:// address, not "${liveUrl}"`);
|
|
94
|
+
return 2;
|
|
95
|
+
}
|
|
96
|
+
if (values.as !== void 0 || values.scopes !== void 0 || values.dir !== void 0) {
|
|
97
|
+
console.error("--as, --scopes, and --dir do not apply with --live: the server sets the author kind and the scopes from the token, and keeps the documents.");
|
|
98
|
+
return 2;
|
|
99
|
+
}
|
|
100
|
+
const token = env.AGENTIC_DOCS_TOKEN;
|
|
101
|
+
if (!token) {
|
|
102
|
+
console.error("set AGENTIC_DOCS_TOKEN to a bearer token to join a live room");
|
|
103
|
+
return 2;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
author = (await whoAmI(liveUrl, token)).author;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (!(error instanceof DocError)) throw error;
|
|
109
|
+
console.error(`${error.code}: ${error.message}`);
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
service = new LiveService({ server: liveUrl, token });
|
|
113
|
+
} else {
|
|
114
|
+
const dir = values.dir ?? env.AGENTIC_DOCS_DIR ?? ".agentic-documents";
|
|
115
|
+
service = new DocsService({ blobs: createFileBlobs(join(dir, "blobs")), store: createFileStore(join(dir, "store")) });
|
|
116
|
+
const scopes = (values.scopes ?? env.AGENTIC_DOCS_SCOPES)?.split(",").map((s) => s.trim()).filter(Boolean);
|
|
117
|
+
const named = parseAuthor(values.as ?? env.AGENTIC_DOCS_AS);
|
|
118
|
+
author = named && scopes?.length ? { ...named, scopes } : named;
|
|
119
|
+
}
|
|
120
|
+
if (name === "mcp") {
|
|
121
|
+
const { startMcp } = await import("./mcp-P2C75IIG.js");
|
|
122
|
+
await startMcp(service, author);
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
const command = commands.find((c) => c.name === name);
|
|
126
|
+
if (!command) {
|
|
127
|
+
console.error(`unknown command "${name}". Run "${NAME} --help".`);
|
|
128
|
+
return 2;
|
|
129
|
+
}
|
|
130
|
+
const { as: _as, scopes: _scopes, dir: _dir, live: _live, file, out, help: _help, version: _version, ...fields } = values;
|
|
131
|
+
const input = { ...command.shape.id ? { id } : {}, ...fields };
|
|
132
|
+
try {
|
|
133
|
+
if (file !== void 0) {
|
|
134
|
+
const key = "content" in command.shape ? "content" : "markdown" in command.shape ? "markdown" : void 0;
|
|
135
|
+
if (!key) throw new DocError("INVALID_INPUT", `"${name}" takes no --file`);
|
|
136
|
+
if (key in input) throw new DocError("INVALID_INPUT", `pass --file or --${key}, not both`);
|
|
137
|
+
input[key] = readFileSync(file, "utf8");
|
|
138
|
+
}
|
|
139
|
+
const result = await command.run(service, input, author);
|
|
140
|
+
if (name === "export") {
|
|
141
|
+
const { data, encoding } = result;
|
|
142
|
+
const bytes = encoding === "base64" ? Buffer.from(data, "base64") : data;
|
|
143
|
+
if (out === void 0) process.stdout.write(bytes);
|
|
144
|
+
else writeFileSync(out, bytes);
|
|
145
|
+
} else console.log(typeof result === "string" ? result.replace(/\n$/, "") : JSON.stringify(result, null, 2));
|
|
146
|
+
return 0;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (!(error instanceof DocError)) throw error;
|
|
149
|
+
console.error(`${error.code}: ${error.message}`);
|
|
150
|
+
for (const m of error.matches) console.error(` ${m.occurrence}: ...${m.context}...`);
|
|
151
|
+
return error.code === "INVALID_INPUT" ? 2 : 1;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
main(process.argv.slice(2)).then(
|
|
155
|
+
(code) => {
|
|
156
|
+
if (code !== 0) process.exit(code);
|
|
157
|
+
},
|
|
158
|
+
(error) => {
|
|
159
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
export {
|
|
164
|
+
main
|
|
165
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { P as Principal, A as Anchor, a as AgenticDoc, T as TextTarget, b as AnchorTarget, D as DocAccess, c as PmNode } from './service-BKkxEnaJ.js';
|
|
2
|
+
export { d as DocInfo, e as DocOptions, f as DocsPorts, g as DocsService, E as EditEntry, h as PRINCIPAL_KINDS, i as PrincipalKind, S as Section, j as SectionTarget, k as Target, l as blocksToMarkdown, m as markdownToBlocks, p as parseAuthor } from './service-BKkxEnaJ.js';
|
|
3
|
+
import { Schema } from 'prosemirror-model';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { AdapterOptions, Blobs, Store } from 'agentic-identity';
|
|
6
|
+
import 'yjs';
|
|
7
|
+
|
|
8
|
+
type DocErrorCode = "NO_MATCH" | "AMBIGUOUS_MATCH" | "STALE_ANCHOR" | "NO_SECTION" | "INVALID_AUTHOR" | "INVALID_INPUT" | "NO_THREAD" | "NO_SUGGESTION" | "ALREADY_DECIDED" | "FORBIDDEN" | "NO_DOCUMENT" | "DOCUMENT_EXISTS" | "LOCKED" | "CONFLICT" | "MISCONFIGURED";
|
|
9
|
+
declare class DocError extends Error {
|
|
10
|
+
readonly code: DocErrorCode;
|
|
11
|
+
readonly matches: {
|
|
12
|
+
occurrence: number;
|
|
13
|
+
context: string;
|
|
14
|
+
}[];
|
|
15
|
+
constructor(code: DocErrorCode, message: string, matches?: {
|
|
16
|
+
occurrence: number;
|
|
17
|
+
context: string;
|
|
18
|
+
}[]);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare const schema: Schema<string, string>;
|
|
22
|
+
|
|
23
|
+
interface Message {
|
|
24
|
+
id: string;
|
|
25
|
+
at: string;
|
|
26
|
+
author: Principal;
|
|
27
|
+
body: string;
|
|
28
|
+
}
|
|
29
|
+
interface Thread {
|
|
30
|
+
id: string;
|
|
31
|
+
anchor: Anchor;
|
|
32
|
+
status: "open" | "resolved";
|
|
33
|
+
resolvedBy?: Principal;
|
|
34
|
+
resolvedAt?: string;
|
|
35
|
+
messages: Message[];
|
|
36
|
+
/** The anchored text no longer matches what the comment was made on. */
|
|
37
|
+
stale: boolean;
|
|
38
|
+
/** The text now under the anchor, or null when it is gone. */
|
|
39
|
+
currentText: string | null;
|
|
40
|
+
}
|
|
41
|
+
interface Suggestion {
|
|
42
|
+
id: string;
|
|
43
|
+
kind: "insert" | "replace" | "delete";
|
|
44
|
+
at?: "before" | "after";
|
|
45
|
+
anchor: Anchor;
|
|
46
|
+
replacement: string;
|
|
47
|
+
author: Principal;
|
|
48
|
+
createdAt: string;
|
|
49
|
+
status: "pending" | "accepted" | "rejected";
|
|
50
|
+
decidedBy?: Principal;
|
|
51
|
+
decidedAt?: string;
|
|
52
|
+
stale: boolean;
|
|
53
|
+
}
|
|
54
|
+
/** Comment threads anchored to text. Replies and status merge across replicas. */
|
|
55
|
+
declare class Threads {
|
|
56
|
+
private readonly doc;
|
|
57
|
+
constructor(doc: AgenticDoc);
|
|
58
|
+
private get map();
|
|
59
|
+
private get;
|
|
60
|
+
private message;
|
|
61
|
+
add(target: TextTarget | AnchorTarget, body: string, author: Principal): string;
|
|
62
|
+
reply(id: string, body: string, author: Principal): void;
|
|
63
|
+
private setStatus;
|
|
64
|
+
resolve(id: string, author: Principal): void;
|
|
65
|
+
reopen(id: string, author: Principal): void;
|
|
66
|
+
list(filter?: {
|
|
67
|
+
status?: Thread["status"];
|
|
68
|
+
}): Thread[];
|
|
69
|
+
}
|
|
70
|
+
/** Suggested edits. Nothing changes in the text until a person, or an agent with the accept scope, accepts one. */
|
|
71
|
+
declare class Suggestions {
|
|
72
|
+
private readonly doc;
|
|
73
|
+
constructor(doc: AgenticDoc);
|
|
74
|
+
private get map();
|
|
75
|
+
private get;
|
|
76
|
+
private read;
|
|
77
|
+
/** An `at` on the target means insert. An empty replacement means delete. */
|
|
78
|
+
add(target: TextTarget | AnchorTarget, replacement: string, author: Principal): string;
|
|
79
|
+
private decide;
|
|
80
|
+
/**
|
|
81
|
+
* Apply the edit as the accepting author. The check and the edit share one transaction. Accepting
|
|
82
|
+
* an accepted suggestion changes nothing. A stale anchor throws and the suggestion stays pending.
|
|
83
|
+
*/
|
|
84
|
+
accept(id: string, author: Principal): void;
|
|
85
|
+
/** Same right as accept. A person can withdraw their own suggestion. An agent can never decide its own. */
|
|
86
|
+
reject(id: string, author: Principal): void;
|
|
87
|
+
list(filter?: {
|
|
88
|
+
status?: Suggestion["status"];
|
|
89
|
+
}): Suggestion[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** One table drives the CLI, the MCP server, and the HTTP API, so they stay the same. */
|
|
93
|
+
interface Command {
|
|
94
|
+
name: string;
|
|
95
|
+
description: string;
|
|
96
|
+
shape: z.ZodRawShape;
|
|
97
|
+
readOnly: boolean;
|
|
98
|
+
run(service: DocAccess, input: Record<string, unknown>, author: Principal | undefined): Promise<unknown>;
|
|
99
|
+
}
|
|
100
|
+
declare const commands: Command[];
|
|
101
|
+
|
|
102
|
+
declare const EXPORT_FORMATS: readonly ["md", "html", "odt"];
|
|
103
|
+
type ExportFormat = (typeof EXPORT_FORMATS)[number];
|
|
104
|
+
interface ExportOptions {
|
|
105
|
+
/** Keep `<img>` for web and relative sources. Opening the page then asks those hosts for the image. Off by default. */
|
|
106
|
+
remoteImages?: boolean;
|
|
107
|
+
}
|
|
108
|
+
interface ExportResult {
|
|
109
|
+
format: ExportFormat;
|
|
110
|
+
contentType: string;
|
|
111
|
+
encoding: "utf8" | "base64";
|
|
112
|
+
data: string;
|
|
113
|
+
}
|
|
114
|
+
declare function exportDoc(doc: AgenticDoc, format: ExportFormat, options?: ExportOptions): ExportResult;
|
|
115
|
+
|
|
116
|
+
interface FileBlobsOptions extends AdapterOptions {
|
|
117
|
+
/** A lock older than this is taken over. Default 10 seconds. A save takes milliseconds. */
|
|
118
|
+
lockStaleMs?: number;
|
|
119
|
+
/** How long a writer waits for a lock before it fails with LOCKED. Default 5 seconds. */
|
|
120
|
+
lockTimeoutMs?: number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Blobs kept as files under one directory. File names are key hashes, so no key leaves the folder.
|
|
124
|
+
* A write takes a lock file, checks the condition again, then writes a temp file and renames it into
|
|
125
|
+
* place. A reader never sees a torn file, and two processes cannot both pass the version check.
|
|
126
|
+
*/
|
|
127
|
+
declare function createFileBlobs(dir: string, options?: FileBlobsOptions): Blobs;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* A Store kept in one file. The file holds every doc as one snapshot, saved through the file Blobs
|
|
131
|
+
* adapter with a conditional write. Each call loads the newest snapshot, so several processes (CLI
|
|
132
|
+
* runs, MCP servers) share one dataset. A transaction holds a lock file from its first read to its
|
|
133
|
+
* commit, so a rival write waits and lands after it. The conditional write is a second guard: if the
|
|
134
|
+
* lock was lost and the snapshot changed, the transaction runs again on the new snapshot.
|
|
135
|
+
* The store re-reads and re-writes the whole snapshot on each call: it suits a small local catalog.
|
|
136
|
+
*/
|
|
137
|
+
declare function createFileStore(dir: string, options?: AdapterOptions & Pick<FileBlobsOptions, "lockStaleMs" | "lockTimeoutMs"> & {
|
|
138
|
+
shared?: string;
|
|
139
|
+
}): Store;
|
|
140
|
+
|
|
141
|
+
declare const ODT_MIME = "application/vnd.oasis.opendocument.text";
|
|
142
|
+
/** Write blocks as an OpenDocument text file (.odt): content, styles, and images as embedded files. */
|
|
143
|
+
declare function exportOdt(blocks: PmNode[]): Uint8Array;
|
|
144
|
+
|
|
145
|
+
export { AgenticDoc, Anchor, AnchorTarget, type Command, DocError, type DocErrorCode, EXPORT_FORMATS, type ExportFormat, type ExportOptions, type ExportResult, type FileBlobsOptions, type Message, ODT_MIME, PmNode, Principal, type Suggestion, Suggestions, TextTarget, type Thread, Threads, commands, createFileBlobs, createFileStore, exportDoc, exportOdt, schema };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createFileBlobs,
|
|
3
|
+
createFileStore
|
|
4
|
+
} from "./chunk-TFCRPEEM.js";
|
|
5
|
+
import {
|
|
6
|
+
DocsService
|
|
7
|
+
} from "./chunk-FZA5LQV3.js";
|
|
8
|
+
import {
|
|
9
|
+
EXPORT_FORMATS,
|
|
10
|
+
ODT_MIME,
|
|
11
|
+
commands,
|
|
12
|
+
exportDoc,
|
|
13
|
+
exportOdt
|
|
14
|
+
} from "./chunk-GYQFTF2E.js";
|
|
15
|
+
import {
|
|
16
|
+
AgenticDoc,
|
|
17
|
+
DocError,
|
|
18
|
+
PRINCIPAL_KINDS,
|
|
19
|
+
Suggestions,
|
|
20
|
+
Threads,
|
|
21
|
+
blocksToMarkdown,
|
|
22
|
+
markdownToBlocks,
|
|
23
|
+
parseAuthor,
|
|
24
|
+
schema
|
|
25
|
+
} from "./chunk-YBBQNCMC.js";
|
|
26
|
+
export {
|
|
27
|
+
AgenticDoc,
|
|
28
|
+
DocError,
|
|
29
|
+
DocsService,
|
|
30
|
+
EXPORT_FORMATS,
|
|
31
|
+
ODT_MIME,
|
|
32
|
+
PRINCIPAL_KINDS,
|
|
33
|
+
Suggestions,
|
|
34
|
+
Threads,
|
|
35
|
+
blocksToMarkdown,
|
|
36
|
+
commands,
|
|
37
|
+
createFileBlobs,
|
|
38
|
+
createFileStore,
|
|
39
|
+
exportDoc,
|
|
40
|
+
exportOdt,
|
|
41
|
+
markdownToBlocks,
|
|
42
|
+
parseAuthor,
|
|
43
|
+
schema
|
|
44
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createDurableObjectRealtime } from 'agentic-realtime/worker';
|
|
2
|
+
export { SyncRoom } from 'agentic-realtime/worker';
|
|
3
|
+
import { WorkerEnv } from './worker.js';
|
|
4
|
+
import 'hono';
|
|
5
|
+
import 'agentic-identity';
|
|
6
|
+
import 'agentic-identity/cloudflare';
|
|
7
|
+
import 'agentic-realtime';
|
|
8
|
+
import './service-BKkxEnaJ.js';
|
|
9
|
+
import 'yjs';
|
|
10
|
+
|
|
11
|
+
type Namespace = Parameters<typeof createDurableObjectRealtime>[0];
|
|
12
|
+
interface LiveEnv extends WorkerEnv {
|
|
13
|
+
/** Durable Object namespace of the live rooms. Bind `SyncRoom` to it. */
|
|
14
|
+
SYNC_ROOM?: Namespace;
|
|
15
|
+
}
|
|
16
|
+
declare const _default: {
|
|
17
|
+
fetch: (request: Request, env: LiveEnv, ctx: unknown) => Response | Promise<Response>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { type LiveEnv, _default as default };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createApp,
|
|
3
|
+
regionOf,
|
|
4
|
+
serviceFor
|
|
5
|
+
} from "./chunk-IU3YIQ4Y.js";
|
|
6
|
+
import "./chunk-FZA5LQV3.js";
|
|
7
|
+
import "./chunk-GYQFTF2E.js";
|
|
8
|
+
import {
|
|
9
|
+
DocError
|
|
10
|
+
} from "./chunk-YBBQNCMC.js";
|
|
11
|
+
|
|
12
|
+
// src/live-worker.ts
|
|
13
|
+
import { createDurableObjectRealtime } from "agentic-realtime/worker";
|
|
14
|
+
import { SyncRoom } from "agentic-realtime/worker";
|
|
15
|
+
var app = createApp(serviceFor, {
|
|
16
|
+
live: (env) => {
|
|
17
|
+
const region = regionOf(env);
|
|
18
|
+
const rooms = env.SYNC_ROOM;
|
|
19
|
+
if (!rooms) throw new DocError("MISCONFIGURED", "bind a Durable Object namespace as SYNC_ROOM");
|
|
20
|
+
return createDurableObjectRealtime(rooms, region === "eu" ? "eu" : void 0);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
var live_worker_default = { fetch: (request, env, ctx) => app.fetch(request, env, ctx) };
|
|
24
|
+
export {
|
|
25
|
+
SyncRoom,
|
|
26
|
+
live_worker_default as default
|
|
27
|
+
};
|
package/dist/live.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Peer } from 'agentic-realtime/client';
|
|
2
|
+
import { a as AgenticDoc, P as Principal, e as DocOptions, D as DocAccess } from './service-BKkxEnaJ.js';
|
|
3
|
+
import 'yjs';
|
|
4
|
+
import 'agentic-identity';
|
|
5
|
+
|
|
6
|
+
interface LiveOptions {
|
|
7
|
+
/** The Worker address, such as `https://docs.example.com`. */
|
|
8
|
+
server: string;
|
|
9
|
+
/** Document id. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** A bearer token. The server maps it to the author kind and the role. */
|
|
12
|
+
token: string;
|
|
13
|
+
/** The name other people see in presence. Defaults to the author name. */
|
|
14
|
+
name?: string;
|
|
15
|
+
/** Reconnect after a drop. Edits made offline merge when the socket returns. */
|
|
16
|
+
reconnect?: {
|
|
17
|
+
initialMs?: number;
|
|
18
|
+
maxMs?: number;
|
|
19
|
+
};
|
|
20
|
+
doc?: DocOptions;
|
|
21
|
+
/** Start an empty room from the stored document. Default true. A merge is safe when the room already holds it. */
|
|
22
|
+
seed?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Who the server says the token is. */
|
|
25
|
+
interface Me {
|
|
26
|
+
author: Principal;
|
|
27
|
+
role: "editor" | "viewer";
|
|
28
|
+
}
|
|
29
|
+
declare function whoAmI(server: string, token: string): Promise<Me>;
|
|
30
|
+
/**
|
|
31
|
+
* One document, open in a live room. The author of every edit is the one the server reads from the
|
|
32
|
+
* token, so an agent token always writes agent edits. The room keeps the edits, the stored author
|
|
33
|
+
* label of each update, and the state for the next join.
|
|
34
|
+
*/
|
|
35
|
+
declare class LiveDoc {
|
|
36
|
+
readonly doc: AgenticDoc;
|
|
37
|
+
readonly me: Me;
|
|
38
|
+
private readonly client;
|
|
39
|
+
private readonly api;
|
|
40
|
+
private readonly refusedAtStart;
|
|
41
|
+
private constructor();
|
|
42
|
+
static join(options: LiveOptions): Promise<LiveDoc>;
|
|
43
|
+
/** Saves the room's state to the stored document, through the Blobs port. A viewer cannot save. */
|
|
44
|
+
save(): Promise<void>;
|
|
45
|
+
/** The other people and agents in the room. `machine` is true for an agent. */
|
|
46
|
+
get peers(): Peer[];
|
|
47
|
+
/** Why the room dropped an update, in order. */
|
|
48
|
+
get denied(): string[];
|
|
49
|
+
/**
|
|
50
|
+
* Runs one change as the token's author and waits until the room has it. A viewer fails before the change.
|
|
51
|
+
* After a refusal from the room the local copy still holds the change. Leave and join again.
|
|
52
|
+
*/
|
|
53
|
+
edit<T>(run: (doc: AgenticDoc, author: Principal) => T): Promise<T>;
|
|
54
|
+
/** Waits until the room has every change made so far. */
|
|
55
|
+
flush(): Promise<void>;
|
|
56
|
+
leave(): Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The commands of the CLI and the MCP server, run in a live room. Each call joins the room, runs one
|
|
60
|
+
* change as the token's author, saves to the stored document, and leaves. A read joins and leaves.
|
|
61
|
+
*/
|
|
62
|
+
declare class LiveService implements DocAccess {
|
|
63
|
+
private readonly options;
|
|
64
|
+
constructor(options: Pick<LiveOptions, "server" | "token" | "name" | "doc">);
|
|
65
|
+
private join;
|
|
66
|
+
/** The room is only a copy, so a new document is made in the store. A room seeds from it on the next join. */
|
|
67
|
+
create(id: string, markdown: string): Promise<void>;
|
|
68
|
+
read<T>(id: string, run: (doc: AgenticDoc) => T): Promise<T>;
|
|
69
|
+
write<T>(id: string, run: (doc: AgenticDoc) => T): Promise<T>;
|
|
70
|
+
private exists;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { LiveDoc, type LiveOptions, LiveService, type Me, whoAmI };
|
package/dist/live.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VERSION
|
|
3
|
+
} from "./chunk-5Y66UCTE.js";
|
|
4
|
+
import {
|
|
5
|
+
commands
|
|
6
|
+
} from "./chunk-GYQFTF2E.js";
|
|
7
|
+
import {
|
|
8
|
+
DocError
|
|
9
|
+
} from "./chunk-YBBQNCMC.js";
|
|
10
|
+
|
|
11
|
+
// src/mcp.ts
|
|
12
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
13
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
14
|
+
function createMcpServer(service, author) {
|
|
15
|
+
const server = new McpServer({ name: "agentic-documents", version: VERSION });
|
|
16
|
+
for (const command of commands) {
|
|
17
|
+
server.registerTool(
|
|
18
|
+
`doc_${command.name}`,
|
|
19
|
+
{ description: command.description, inputSchema: command.shape, annotations: { readOnlyHint: command.readOnly } },
|
|
20
|
+
async (input) => {
|
|
21
|
+
try {
|
|
22
|
+
const result = await command.run(service, input, author);
|
|
23
|
+
return { content: [{ type: "text", text: typeof result === "string" ? result : JSON.stringify(result) }] };
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (!(error instanceof DocError)) throw error;
|
|
26
|
+
const body = { error: { code: error.code, message: error.message, matches: error.matches } };
|
|
27
|
+
return { content: [{ type: "text", text: JSON.stringify(body) }], isError: true };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return server;
|
|
33
|
+
}
|
|
34
|
+
async function startMcp(service, author) {
|
|
35
|
+
await createMcpServer(service, author).connect(new StdioServerTransport());
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
createMcpServer,
|
|
39
|
+
startMcp
|
|
40
|
+
};
|