@wordinweb/agent 0.1.0 → 0.2.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 +59 -16
- package/dist/{chunk-E7AFDS2O.js → chunk-EMDLXVNY.js} +20243 -8902
- package/dist/chunk-EMDLXVNY.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +330 -36
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1578 -100
- package/dist/index.js +43 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-E7AFDS2O.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,18 +2,22 @@ import {
|
|
|
2
2
|
AGENT_COMPOSE_SCHEMA,
|
|
3
3
|
AGENT_EDIT_CAPABILITIES,
|
|
4
4
|
AgentDocument,
|
|
5
|
+
DOCMD_ATOMS,
|
|
5
6
|
DocxDocument,
|
|
6
7
|
agentCapabilities,
|
|
7
8
|
agentOperationSchema,
|
|
8
9
|
applyIntentScoped,
|
|
9
10
|
collaborativeAgentTarget,
|
|
11
|
+
hoistRepeatedSubschemas,
|
|
12
|
+
isSuggestable,
|
|
13
|
+
isSuggestableTableOp,
|
|
10
14
|
resyncScope,
|
|
11
15
|
sha256Hex,
|
|
12
16
|
unionScopes,
|
|
13
17
|
validateAgentComposeRequest,
|
|
14
18
|
validateAgentOperationShape,
|
|
15
19
|
validateIntent
|
|
16
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-EMDLXVNY.js";
|
|
17
21
|
|
|
18
22
|
// src/session.ts
|
|
19
23
|
var LocalDocumentSession = class {
|
|
@@ -30,10 +34,21 @@ var LocalDocumentSession = class {
|
|
|
30
34
|
this.dirtyScope = null;
|
|
31
35
|
return scope;
|
|
32
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Called immediately before an intent mutates the document.
|
|
39
|
+
*
|
|
40
|
+
* A host that also renders this document — the desktop app, whose editor owns
|
|
41
|
+
* an undo stack — sets this to take a checkpoint, so an edit made by an agent
|
|
42
|
+
* is reachable with Cmd+Z like any other. Without it the agent's changes are
|
|
43
|
+
* applied behind the editor's back: undo cannot reverse them, and structural
|
|
44
|
+
* ones have no tracked form to reject either, leaving no way back.
|
|
45
|
+
*/
|
|
46
|
+
this.onBeforeApply = null;
|
|
33
47
|
this.submit = (operation) => {
|
|
34
48
|
const intent = this.fullIntent(operation);
|
|
35
49
|
const error = validateIntent(intent);
|
|
36
50
|
if (error) throw new Error(error);
|
|
51
|
+
this.onBeforeApply?.();
|
|
37
52
|
const ids = this.doc.enableStableIds();
|
|
38
53
|
const result = applyIntentScoped(this.doc, ids, intent);
|
|
39
54
|
if (!result.applied) throw new Error(`${operation.kind} could not apply to the referenced document state`);
|
|
@@ -45,6 +60,13 @@ var LocalDocumentSession = class {
|
|
|
45
60
|
for (const listener of this.listeners) listener();
|
|
46
61
|
};
|
|
47
62
|
this.submitOp = (operation) => this.submit(operation);
|
|
63
|
+
/** Record a local history undo/redo that mutated the shared doc outside the
|
|
64
|
+
* intent path (the editor already re-rendered itself). Matches the
|
|
65
|
+
* pre-applied contract: bump the revision so agent-side caches keyed on it
|
|
66
|
+
* (projections, inspection fingerprints) never serve the pre-undo tree. */
|
|
67
|
+
this.noteHistory = () => {
|
|
68
|
+
this.revision++;
|
|
69
|
+
};
|
|
48
70
|
/** Record an operation that DocxView already applied to this same object. */
|
|
49
71
|
this.submitPreApplied = (operation) => {
|
|
50
72
|
const error = validateIntent(this.fullIntent(operation));
|
|
@@ -71,6 +93,7 @@ var LocalDocumentSession = class {
|
|
|
71
93
|
}
|
|
72
94
|
allocateIds(count) {
|
|
73
95
|
if (!Number.isInteger(count) || count < 0) throw new Error("ID count must be a non-negative integer");
|
|
96
|
+
this.nextId = Math.max(this.nextId, this.doc.enableStableIds().nextId());
|
|
74
97
|
return Array.from({ length: count }, () => this.nextId++);
|
|
75
98
|
}
|
|
76
99
|
subscribe(listener) {
|
|
@@ -85,14 +108,24 @@ var LocalDocumentSession = class {
|
|
|
85
108
|
fullIntent(operation) {
|
|
86
109
|
return { ...operation, clientId: "local-document-session", clientSeq: ++this.clientSequence, base: this.revision };
|
|
87
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Fill the part an operation just reserved with the bytes this session is
|
|
113
|
+
* already holding.
|
|
114
|
+
*
|
|
115
|
+
* Keyed on the blobSha the operation carries, not on its kind: the sha IS
|
|
116
|
+
* the media reservation, and every operation that reserves media carries
|
|
117
|
+
* one (insertImage, insertPictureWatermark). Naming one kind here left
|
|
118
|
+
* every later one's picture pending forever.
|
|
119
|
+
*/
|
|
88
120
|
installUploadedImage(operation) {
|
|
89
|
-
|
|
90
|
-
|
|
121
|
+
const blobSha = operation.blobSha;
|
|
122
|
+
if (typeof blobSha !== "string") return;
|
|
123
|
+
const bytes = this.uploadedMedia.get(blobSha);
|
|
91
124
|
if (!bytes) return;
|
|
92
125
|
for (const [part, metadata] of this.doc.pendingMedia) {
|
|
93
|
-
if (metadata.sha !==
|
|
126
|
+
if (metadata.sha !== blobSha) continue;
|
|
94
127
|
this.doc.installMedia(part, bytes);
|
|
95
|
-
this.uploadedMedia.delete(
|
|
128
|
+
this.uploadedMedia.delete(blobSha);
|
|
96
129
|
return;
|
|
97
130
|
}
|
|
98
131
|
}
|
|
@@ -106,6 +139,7 @@ function localDocumentViewBinding(session) {
|
|
|
106
139
|
submitOp: session.submitOp,
|
|
107
140
|
allocIds: session.allocIds,
|
|
108
141
|
uploadMedia: (bytes) => session.uploadMedia(bytes),
|
|
142
|
+
noteHistory: session.noteHistory,
|
|
109
143
|
takeRenderScope: session.takeRenderScope
|
|
110
144
|
};
|
|
111
145
|
}
|
|
@@ -113,10 +147,14 @@ export {
|
|
|
113
147
|
AGENT_COMPOSE_SCHEMA,
|
|
114
148
|
AGENT_EDIT_CAPABILITIES,
|
|
115
149
|
AgentDocument,
|
|
150
|
+
DOCMD_ATOMS,
|
|
116
151
|
LocalDocumentSession,
|
|
117
152
|
agentCapabilities,
|
|
118
153
|
agentOperationSchema,
|
|
119
154
|
collaborativeAgentTarget,
|
|
155
|
+
hoistRepeatedSubschemas,
|
|
156
|
+
isSuggestable,
|
|
157
|
+
isSuggestableTableOp,
|
|
120
158
|
localDocumentViewBinding,
|
|
121
159
|
validateAgentComposeRequest,
|
|
122
160
|
validateAgentOperationShape
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/session.ts"],"sourcesContent":["import { DocxDocument, type XmlElement } from \"@wordinweb/core\";\nimport { applyIntentScoped, resyncScope, sha256Hex, unionScopes, type Intent, type IntentBody, type Scope } from \"@wordinweb/collab/client\";\nimport { validateIntent } from \"@wordinweb/collab/server\";\nimport type { AgentCollaborativeTarget } from \"./types.js\";\n\n/**\n * A canonical document session for one process. It lets a browser editor and\n * an AgentDocument share one DocxDocument without a server or a DOM dependency.\n */\nexport class LocalDocumentSession implements AgentCollaborativeTarget {\n readonly doc: DocxDocument;\n private revision = 0;\n private renderRevision = 0;\n private clientSequence = 0;\n private nextId: number;\n private dirtyScope: Scope | null = null;\n private readonly listeners = new Set<() => void>();\n private readonly uploadedMedia = new Map<string, Uint8Array>();\n\n constructor(source: ArrayBuffer | Uint8Array | DocxDocument) {\n this.doc = source instanceof DocxDocument ? source : DocxDocument.load(source);\n this.nextId = this.doc.enableStableIds().nextId();\n }\n\n get version(): number {\n return this.revision;\n }\n\n get renderSignal(): number {\n return this.renderRevision;\n }\n\n getDocument(): DocxDocument {\n return this.doc;\n }\n\n getRevision(): number {\n return this.revision;\n }\n\n getConnectionState(): \"local\" {\n return \"local\";\n }\n\n allocateIds(count: number): number[] {\n if (!Number.isInteger(count) || count < 0) throw new Error(\"ID count must be a non-negative integer\");\n return Array.from({ length: count }, () => this.nextId++);\n }\n\n allocIds = (count: number): number[] => this.allocateIds(count);\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n takeRenderScope = (): Scope | null => {\n const scope = this.dirtyScope;\n this.dirtyScope = null;\n return scope;\n };\n\n submit = (operation: IntentBody): void => {\n const intent = this.fullIntent(operation);\n const error = validateIntent(intent);\n if (error) throw new Error(error);\n const ids = this.doc.enableStableIds();\n const result = applyIntentScoped(this.doc, ids, intent);\n if (!result.applied) throw new Error(`${operation.kind} could not apply to the referenced document state`);\n resyncScope(this.doc, ids, result);\n this.installUploadedImage(operation);\n this.dirtyScope = unionScopes(this.dirtyScope, result);\n this.revision++;\n this.renderRevision++;\n for (const listener of this.listeners) listener();\n };\n\n submitOp = (operation: IntentBody): void => this.submit(operation);\n\n /** Record an operation that DocxView already applied to this same object. */\n submitPreApplied = (operation: IntentBody): void => {\n const error = validateIntent(this.fullIntent(operation));\n if (error) throw new Error(error);\n this.revision++;\n };\n\n async uploadMedia(bytes: Uint8Array): Promise<{ blobSha: string; bytesLen: number }> {\n const blobSha = await sha256Hex(bytes);\n this.uploadedMedia.set(blobSha, new Uint8Array(bytes));\n return { blobSha, bytesLen: bytes.length };\n }\n\n private fullIntent(operation: IntentBody): Intent {\n return { ...operation, clientId: \"local-document-session\", clientSeq: ++this.clientSequence, base: this.revision } as Intent;\n }\n\n private installUploadedImage(operation: IntentBody): void {\n
|
|
1
|
+
{"version":3,"sources":["../src/session.ts"],"sourcesContent":["import { DocxDocument, type XmlElement } from \"@wordinweb/core\";\nimport { applyIntentScoped, resyncScope, sha256Hex, unionScopes, type Intent, type IntentBody, type Scope } from \"@wordinweb/collab/client\";\nimport { validateIntent } from \"@wordinweb/collab/server\";\nimport type { AgentCollaborativeTarget } from \"./types.js\";\n\n/**\n * A canonical document session for one process. It lets a browser editor and\n * an AgentDocument share one DocxDocument without a server or a DOM dependency.\n */\nexport class LocalDocumentSession implements AgentCollaborativeTarget {\n readonly doc: DocxDocument;\n private revision = 0;\n private renderRevision = 0;\n private clientSequence = 0;\n private nextId: number;\n private dirtyScope: Scope | null = null;\n private readonly listeners = new Set<() => void>();\n private readonly uploadedMedia = new Map<string, Uint8Array>();\n\n constructor(source: ArrayBuffer | Uint8Array | DocxDocument) {\n this.doc = source instanceof DocxDocument ? source : DocxDocument.load(source);\n this.nextId = this.doc.enableStableIds().nextId();\n }\n\n get version(): number {\n return this.revision;\n }\n\n get renderSignal(): number {\n return this.renderRevision;\n }\n\n getDocument(): DocxDocument {\n return this.doc;\n }\n\n getRevision(): number {\n return this.revision;\n }\n\n getConnectionState(): \"local\" {\n return \"local\";\n }\n\n allocateIds(count: number): number[] {\n if (!Number.isInteger(count) || count < 0) throw new Error(\"ID count must be a non-negative integer\");\n // A suggested insertion creates nodes whose ids come from the id table's\n // own counter (scoped reparse), not from this allocator — resync before\n // handing out numbers, or the next carried id collides with them.\n this.nextId = Math.max(this.nextId, this.doc.enableStableIds().nextId());\n return Array.from({ length: count }, () => this.nextId++);\n }\n\n allocIds = (count: number): number[] => this.allocateIds(count);\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n takeRenderScope = (): Scope | null => {\n const scope = this.dirtyScope;\n this.dirtyScope = null;\n return scope;\n };\n\n /**\n * Called immediately before an intent mutates the document.\n *\n * A host that also renders this document — the desktop app, whose editor owns\n * an undo stack — sets this to take a checkpoint, so an edit made by an agent\n * is reachable with Cmd+Z like any other. Without it the agent's changes are\n * applied behind the editor's back: undo cannot reverse them, and structural\n * ones have no tracked form to reject either, leaving no way back.\n */\n onBeforeApply: (() => void) | null = null;\n\n submit = (operation: IntentBody): void => {\n const intent = this.fullIntent(operation);\n const error = validateIntent(intent);\n if (error) throw new Error(error);\n // Before the mutation, and only once validation has passed: a rejected\n // intent must not leave an empty undo step behind.\n this.onBeforeApply?.();\n const ids = this.doc.enableStableIds();\n const result = applyIntentScoped(this.doc, ids, intent);\n if (!result.applied) throw new Error(`${operation.kind} could not apply to the referenced document state`);\n resyncScope(this.doc, ids, result);\n this.installUploadedImage(operation);\n this.dirtyScope = unionScopes(this.dirtyScope, result);\n this.revision++;\n this.renderRevision++;\n for (const listener of this.listeners) listener();\n };\n\n submitOp = (operation: IntentBody): void => this.submit(operation);\n\n /** Record a local history undo/redo that mutated the shared doc outside the\n * intent path (the editor already re-rendered itself). Matches the\n * pre-applied contract: bump the revision so agent-side caches keyed on it\n * (projections, inspection fingerprints) never serve the pre-undo tree. */\n noteHistory = (): void => {\n this.revision++;\n };\n\n /** Record an operation that DocxView already applied to this same object. */\n submitPreApplied = (operation: IntentBody): void => {\n const error = validateIntent(this.fullIntent(operation));\n if (error) throw new Error(error);\n this.revision++;\n };\n\n async uploadMedia(bytes: Uint8Array): Promise<{ blobSha: string; bytesLen: number }> {\n const blobSha = await sha256Hex(bytes);\n this.uploadedMedia.set(blobSha, new Uint8Array(bytes));\n return { blobSha, bytesLen: bytes.length };\n }\n\n private fullIntent(operation: IntentBody): Intent {\n return { ...operation, clientId: \"local-document-session\", clientSeq: ++this.clientSequence, base: this.revision } as Intent;\n }\n\n /**\n * Fill the part an operation just reserved with the bytes this session is\n * already holding.\n *\n * Keyed on the blobSha the operation carries, not on its kind: the sha IS\n * the media reservation, and every operation that reserves media carries\n * one (insertImage, insertPictureWatermark). Naming one kind here left\n * every later one's picture pending forever.\n */\n private installUploadedImage(operation: IntentBody): void {\n const blobSha = (operation as { blobSha?: unknown }).blobSha;\n if (typeof blobSha !== \"string\") return;\n const bytes = this.uploadedMedia.get(blobSha);\n if (!bytes) return;\n for (const [part, metadata] of this.doc.pendingMedia) {\n if (metadata.sha !== blobSha) continue;\n this.doc.installMedia(part, bytes);\n this.uploadedMedia.delete(blobSha);\n return;\n }\n }\n}\n\nexport interface LocalDocumentViewBinding {\n subscribe(listener: () => void): () => void;\n getSnapshot(): number;\n doc: DocxDocument;\n submit(operation: IntentBody): void;\n submitOp(operation: IntentBody): void;\n allocIds(count: number): number[];\n uploadMedia(bytes: Uint8Array): Promise<{ blobSha: string; bytesLen: number }>;\n noteHistory(): void;\n takeRenderScope():\n | { kind: \"doc\" }\n | { kind: \"block\"; blocks: XmlElement[] }\n | { kind: \"split\"; before: XmlElement; after: XmlElement }\n | null;\n}\n\nexport function localDocumentViewBinding(session: LocalDocumentSession): LocalDocumentViewBinding {\n return {\n subscribe: (listener) => session.subscribe(listener),\n getSnapshot: () => session.renderSignal,\n doc: session.doc,\n submit: session.submitPreApplied,\n submitOp: session.submitOp,\n allocIds: session.allocIds,\n uploadMedia: (bytes) => session.uploadMedia(bytes),\n noteHistory: session.noteHistory,\n takeRenderScope: session.takeRenderScope,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AASO,IAAM,uBAAN,MAA+D;AAAA,EAUpE,YAAY,QAAiD;AAR7D,SAAQ,WAAW;AACnB,SAAQ,iBAAiB;AACzB,SAAQ,iBAAiB;AAEzB,SAAQ,aAA2B;AACnC,SAAiB,YAAY,oBAAI,IAAgB;AACjD,SAAiB,gBAAgB,oBAAI,IAAwB;AAoC7D,oBAAW,CAAC,UAA4B,KAAK,YAAY,KAAK;AAO9D,2BAAkB,MAAoB;AACpC,YAAM,QAAQ,KAAK;AACnB,WAAK,aAAa;AAClB,aAAO;AAAA,IACT;AAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAqC;AAErC,kBAAS,CAAC,cAAgC;AACxC,YAAM,SAAS,KAAK,WAAW,SAAS;AACxC,YAAM,QAAQ,eAAe,MAAM;AACnC,UAAI,MAAO,OAAM,IAAI,MAAM,KAAK;AAGhC,WAAK,gBAAgB;AACrB,YAAM,MAAM,KAAK,IAAI,gBAAgB;AACrC,YAAM,SAAS,kBAAkB,KAAK,KAAK,KAAK,MAAM;AACtD,UAAI,CAAC,OAAO,QAAS,OAAM,IAAI,MAAM,GAAG,UAAU,IAAI,mDAAmD;AACzG,kBAAY,KAAK,KAAK,KAAK,MAAM;AACjC,WAAK,qBAAqB,SAAS;AACnC,WAAK,aAAa,YAAY,KAAK,YAAY,MAAM;AACrD,WAAK;AACL,WAAK;AACL,iBAAW,YAAY,KAAK,UAAW,UAAS;AAAA,IAClD;AAEA,oBAAW,CAAC,cAAgC,KAAK,OAAO,SAAS;AAMjE;AAAA;AAAA;AAAA;AAAA,uBAAc,MAAY;AACxB,WAAK;AAAA,IACP;AAGA;AAAA,4BAAmB,CAAC,cAAgC;AAClD,YAAM,QAAQ,eAAe,KAAK,WAAW,SAAS,CAAC;AACvD,UAAI,MAAO,OAAM,IAAI,MAAM,KAAK;AAChC,WAAK;AAAA,IACP;AA1FE,SAAK,MAAM,kBAAkB,eAAe,SAAS,aAAa,KAAK,MAAM;AAC7E,SAAK,SAAS,KAAK,IAAI,gBAAgB,EAAE,OAAO;AAAA,EAClD;AAAA,EAEA,IAAI,UAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,eAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,qBAA8B;AAC5B,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,OAAyB;AACnC,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,EAAG,OAAM,IAAI,MAAM,yCAAyC;AAIpG,SAAK,SAAS,KAAK,IAAI,KAAK,QAAQ,KAAK,IAAI,gBAAgB,EAAE,OAAO,CAAC;AACvE,WAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,MAAM,KAAK,QAAQ;AAAA,EAC1D;AAAA,EAIA,UAAU,UAAkC;AAC1C,SAAK,UAAU,IAAI,QAAQ;AAC3B,WAAO,MAAM,KAAK,UAAU,OAAO,QAAQ;AAAA,EAC7C;AAAA,EAsDA,MAAM,YAAY,OAAmE;AACnF,UAAM,UAAU,MAAM,UAAU,KAAK;AACrC,SAAK,cAAc,IAAI,SAAS,IAAI,WAAW,KAAK,CAAC;AACrD,WAAO,EAAE,SAAS,UAAU,MAAM,OAAO;AAAA,EAC3C;AAAA,EAEQ,WAAW,WAA+B;AAChD,WAAO,EAAE,GAAG,WAAW,UAAU,0BAA0B,WAAW,EAAE,KAAK,gBAAgB,MAAM,KAAK,SAAS;AAAA,EACnH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,qBAAqB,WAA6B;AACxD,UAAM,UAAW,UAAoC;AACrD,QAAI,OAAO,YAAY,SAAU;AACjC,UAAM,QAAQ,KAAK,cAAc,IAAI,OAAO;AAC5C,QAAI,CAAC,MAAO;AACZ,eAAW,CAAC,MAAM,QAAQ,KAAK,KAAK,IAAI,cAAc;AACpD,UAAI,SAAS,QAAQ,QAAS;AAC9B,WAAK,IAAI,aAAa,MAAM,KAAK;AACjC,WAAK,cAAc,OAAO,OAAO;AACjC;AAAA,IACF;AAAA,EACF;AACF;AAkBO,SAAS,yBAAyB,SAAyD;AAChG,SAAO;AAAA,IACL,WAAW,CAAC,aAAa,QAAQ,UAAU,QAAQ;AAAA,IACnD,aAAa,MAAM,QAAQ;AAAA,IAC3B,KAAK,QAAQ;AAAA,IACb,QAAQ,QAAQ;AAAA,IAChB,UAAU,QAAQ;AAAA,IAClB,UAAU,QAAQ;AAAA,IAClB,aAAa,CAAC,UAAU,QAAQ,YAAY,KAAK;AAAA,IACjD,aAAa,QAAQ;AAAA,IACrB,iBAAiB,QAAQ;AAAA,EAC3B;AACF;","names":[]}
|