@aaronsb/google-workspace-mcp 2.6.1 → 2.7.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 +2 -2
- package/build/__tests__/factory/calendar-patch.test.js +79 -0
- package/build/__tests__/factory/calendar-patch.test.js.map +1 -1
- package/build/__tests__/factory/drive-patch.test.js +224 -0
- package/build/__tests__/factory/drive-patch.test.js.map +1 -1
- package/build/__tests__/factory/sheets-patch.test.js +71 -6
- package/build/__tests__/factory/sheets-patch.test.js.map +1 -1
- package/build/__tests__/server/formatting/html-sanitize.test.d.ts +7 -0
- package/build/__tests__/server/formatting/html-sanitize.test.js +174 -0
- package/build/__tests__/server/formatting/html-sanitize.test.js.map +1 -0
- package/build/__tests__/server/formatting/markdown.test.js +55 -0
- package/build/__tests__/server/formatting/markdown.test.js.map +1 -1
- package/build/__tests__/server/handlers/calendar.test.js +2 -1
- package/build/__tests__/server/handlers/calendar.test.js.map +1 -1
- package/build/executor/gws.js +41 -20
- package/build/executor/gws.js.map +1 -1
- package/build/factory/generator.d.ts +11 -3
- package/build/factory/generator.js +41 -16
- package/build/factory/generator.js.map +1 -1
- package/build/factory/manifest/README.md +12 -0
- package/build/factory/manifest/calendar.yaml +204 -0
- package/build/factory/manifest/docs.yaml +77 -0
- package/build/factory/manifest/drive.yaml +314 -0
- package/build/factory/manifest/gmail.yaml +272 -0
- package/build/factory/manifest/meet.yaml +159 -0
- package/build/factory/manifest/sheets.yaml +225 -0
- package/build/factory/manifest/tasks.yaml +137 -0
- package/build/factory/registry.d.ts +3 -3
- package/build/factory/registry.js +5 -5
- package/build/factory/registry.js.map +1 -1
- package/build/factory/types.d.ts +6 -0
- package/build/server/formatting/html-sanitize.d.ts +40 -0
- package/build/server/formatting/html-sanitize.js +146 -0
- package/build/server/formatting/html-sanitize.js.map +1 -0
- package/build/server/formatting/markdown.d.ts +13 -3
- package/build/server/formatting/markdown.js +33 -6
- package/build/server/formatting/markdown.js.map +1 -1
- package/build/server/handlers/calendar.js +1 -1
- package/build/server/handlers/calendar.js.map +1 -1
- package/build/server/scratchpad/__tests__/docs-sync-integration.test.d.ts +11 -0
- package/build/server/scratchpad/__tests__/docs-sync-integration.test.js +187 -0
- package/build/server/scratchpad/__tests__/docs-sync-integration.test.js.map +1 -0
- package/build/server/scratchpad/__tests__/docs-sync.test.d.ts +16 -0
- package/build/server/scratchpad/__tests__/docs-sync.test.js +213 -0
- package/build/server/scratchpad/__tests__/docs-sync.test.js.map +1 -0
- package/build/server/scratchpad/adapters/import-doc.js +6 -3
- package/build/server/scratchpad/adapters/import-doc.js.map +1 -1
- package/build/server/scratchpad/adapters/send-calendar.js +1 -1
- package/build/server/scratchpad/adapters/send-calendar.js.map +1 -1
- package/build/server/scratchpad/docs-sync.d.ts +65 -0
- package/build/server/scratchpad/docs-sync.js +191 -0
- package/build/server/scratchpad/docs-sync.js.map +1 -0
- package/build/server/scratchpad/handler.js +95 -14
- package/build/server/scratchpad/handler.js.map +1 -1
- package/build/server/scratchpad/manager.d.ts +7 -0
- package/build/server/scratchpad/manager.js.map +1 -1
- package/build/services/calendar/patch.js +72 -1
- package/build/services/calendar/patch.js.map +1 -1
- package/build/services/drive/patch.js +170 -0
- package/build/services/drive/patch.js.map +1 -1
- package/build/services/gmail/patch.js +7 -2
- package/build/services/gmail/patch.js.map +1 -1
- package/build/services/sheets/patch.js +57 -6
- package/build/services/sheets/patch.js.map +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/package.json +4 -2
- package/build/factory/manifest.yaml +0 -1383
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for docs-sync — translating a scratchpad JSON-mode mutation into
|
|
3
|
+
* a Docs batchUpdate request. Pure translator; no API calls (mocked or
|
|
4
|
+
* otherwise) in this file. See issue #79.
|
|
5
|
+
*/
|
|
6
|
+
import { translateMutation, isRejection } from '../docs-sync.js';
|
|
7
|
+
/** Minimal Docs-API-shaped JSON with one body content element. */
|
|
8
|
+
function docWith(element, revisionId = 'rev-1') {
|
|
9
|
+
return JSON.stringify({
|
|
10
|
+
documentId: 'doc-1',
|
|
11
|
+
revisionId,
|
|
12
|
+
body: { content: [element] },
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/** Helper — a textRun element. content/startIndex/endIndex configurable. */
|
|
16
|
+
function textRunElement(content, startIndex) {
|
|
17
|
+
return {
|
|
18
|
+
startIndex,
|
|
19
|
+
endIndex: startIndex + content.length,
|
|
20
|
+
paragraph: {
|
|
21
|
+
elements: [
|
|
22
|
+
{ startIndex, endIndex: startIndex + content.length, textRun: { content } },
|
|
23
|
+
],
|
|
24
|
+
paragraphStyle: { namedStyleType: 'NORMAL_TEXT' },
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const TEXT_PATH = '$.body.content[0].paragraph.elements[0].textRun.content';
|
|
29
|
+
const STYLE_PATH = '$.body.content[0].paragraph.paragraphStyle.namedStyleType';
|
|
30
|
+
describe('translateMutation — textRun.content path', () => {
|
|
31
|
+
it('builds deleteContentRange(start, end-1) + insertText when old content ends with \\n', () => {
|
|
32
|
+
// Trailing newline is the paragraph break — must not delete through it,
|
|
33
|
+
// or the paragraph itself disappears.
|
|
34
|
+
const beforeJson = docWith(textRunElement('Hello world\n', 1)); // endIndex = 13
|
|
35
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 'Goodbye', beforeJson }, 'rev-1');
|
|
36
|
+
if (isRejection(result))
|
|
37
|
+
throw new Error(`unexpected rejection: ${result.reason}`);
|
|
38
|
+
expect(result.body.requests).toEqual([
|
|
39
|
+
{ deleteContentRange: { range: { startIndex: 1, endIndex: 12 } } }, // end - 1 = 13 - 1
|
|
40
|
+
{ insertText: { text: 'Goodbye', location: { index: 1 } } },
|
|
41
|
+
]);
|
|
42
|
+
expect(result.body.writeControl).toEqual({ requiredRevisionId: 'rev-1' });
|
|
43
|
+
});
|
|
44
|
+
it('builds deleteContentRange(start, end) when old content has no trailing newline', () => {
|
|
45
|
+
const beforeJson = docWith(textRunElement('inline', 5)); // endIndex = 11, no trailing \n
|
|
46
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 'inlined', beforeJson }, 'rev-1');
|
|
47
|
+
if (isRejection(result))
|
|
48
|
+
throw new Error(`unexpected rejection: ${result.reason}`);
|
|
49
|
+
expect(result.body.requests).toEqual([
|
|
50
|
+
{ deleteContentRange: { range: { startIndex: 5, endIndex: 11 } } },
|
|
51
|
+
{ insertText: { text: 'inlined', location: { index: 5 } } },
|
|
52
|
+
]);
|
|
53
|
+
});
|
|
54
|
+
it('omits deleteContentRange when the run is just a paragraph-break newline', () => {
|
|
55
|
+
// oldContent='\n' → deleteEnd = endIndex - 1 = startIndex; nothing to delete.
|
|
56
|
+
const beforeJson = docWith(textRunElement('\n', 7));
|
|
57
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 'X', beforeJson }, 'rev-1');
|
|
58
|
+
if (isRejection(result))
|
|
59
|
+
throw new Error(`unexpected rejection: ${result.reason}`);
|
|
60
|
+
expect(result.body.requests).toEqual([
|
|
61
|
+
{ insertText: { text: 'X', location: { index: 7 } } },
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
64
|
+
it('rejects a newline in the new value (structural edit disguised as text)', () => {
|
|
65
|
+
const beforeJson = docWith(textRunElement('Hello\n', 1));
|
|
66
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 'line1\nline2', beforeJson }, 'rev-1');
|
|
67
|
+
expect(isRejection(result)).toBe(true);
|
|
68
|
+
if (isRejection(result))
|
|
69
|
+
expect(result.reason).toMatch(/newline/);
|
|
70
|
+
});
|
|
71
|
+
it('rejects a non-string value', () => {
|
|
72
|
+
const beforeJson = docWith(textRunElement('x', 1));
|
|
73
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 42, beforeJson }, 'rev-1');
|
|
74
|
+
expect(isRejection(result)).toBe(true);
|
|
75
|
+
if (isRejection(result))
|
|
76
|
+
expect(result.reason).toMatch(/string/);
|
|
77
|
+
});
|
|
78
|
+
it('rejects when the element has no textRun (e.g. an inline image)', () => {
|
|
79
|
+
const beforeJson = docWith({
|
|
80
|
+
startIndex: 1,
|
|
81
|
+
endIndex: 2,
|
|
82
|
+
paragraph: {
|
|
83
|
+
elements: [{ startIndex: 1, endIndex: 2, inlineObjectElement: { objectId: 'img-1' } }],
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 'x', beforeJson }, 'rev-1');
|
|
87
|
+
expect(isRejection(result)).toBe(true);
|
|
88
|
+
if (isRejection(result))
|
|
89
|
+
expect(result.reason).toMatch(/textRun/);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('translateMutation — paragraphStyle path', () => {
|
|
93
|
+
it('builds updateParagraphStyle with the element range and the leaf field mask', () => {
|
|
94
|
+
const beforeJson = docWith(textRunElement('Heading text\n', 1));
|
|
95
|
+
const result = translateMutation({ op: 'set', path: STYLE_PATH, value: 'HEADING_1', beforeJson }, 'rev-1');
|
|
96
|
+
if (isRejection(result))
|
|
97
|
+
throw new Error(`unexpected rejection: ${result.reason}`);
|
|
98
|
+
expect(result.body.requests).toEqual([{
|
|
99
|
+
updateParagraphStyle: {
|
|
100
|
+
range: { startIndex: 1, endIndex: 14 }, // 'Heading text\n'.length = 13
|
|
101
|
+
paragraphStyle: { namedStyleType: 'HEADING_1' },
|
|
102
|
+
fields: 'namedStyleType',
|
|
103
|
+
},
|
|
104
|
+
}]);
|
|
105
|
+
expect(result.body.writeControl).toEqual({ requiredRevisionId: 'rev-1' });
|
|
106
|
+
});
|
|
107
|
+
it('passes the leaf field name through unchanged (alignment, direction, etc.)', () => {
|
|
108
|
+
const beforeJson = docWith(textRunElement('x\n', 1));
|
|
109
|
+
const result = translateMutation({ op: 'set', path: '$.body.content[0].paragraph.paragraphStyle.alignment', value: 'CENTER', beforeJson }, 'rev-1');
|
|
110
|
+
if (isRejection(result))
|
|
111
|
+
throw new Error(`unexpected rejection: ${result.reason}`);
|
|
112
|
+
const r = result.body.requests[0];
|
|
113
|
+
expect(r.updateParagraphStyle.fields).toBe('alignment');
|
|
114
|
+
expect(r.updateParagraphStyle.paragraphStyle).toEqual({ alignment: 'CENTER' });
|
|
115
|
+
});
|
|
116
|
+
it('rejects when the element is not a paragraph', () => {
|
|
117
|
+
const beforeJson = docWith({
|
|
118
|
+
startIndex: 1, endIndex: 5,
|
|
119
|
+
table: { rows: 1, columns: 1 },
|
|
120
|
+
});
|
|
121
|
+
const result = translateMutation({ op: 'set', path: STYLE_PATH, value: 'HEADING_1', beforeJson }, 'rev-1');
|
|
122
|
+
expect(isRejection(result)).toBe(true);
|
|
123
|
+
if (isRejection(result))
|
|
124
|
+
expect(result.reason).toMatch(/paragraph/);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
describe('translateMutation — rejected paths and ops', () => {
|
|
128
|
+
it('rejects an unsupported path with a guidance message', () => {
|
|
129
|
+
const beforeJson = docWith(textRunElement('x\n', 1));
|
|
130
|
+
const result = translateMutation({ op: 'set', path: '$.body.content[0].paragraph.elements[0].textStyle.bold', value: true, beforeJson }, 'rev-1');
|
|
131
|
+
expect(isRejection(result)).toBe(true);
|
|
132
|
+
if (isRejection(result)) {
|
|
133
|
+
expect(result.reason).toMatch(/not supported/);
|
|
134
|
+
expect(result.reason).toMatch(/markdown mode/);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
it('rejects json_delete on a docs-bound scratchpad (structural)', () => {
|
|
138
|
+
const beforeJson = docWith(textRunElement('x\n', 1));
|
|
139
|
+
const result = translateMutation({ op: 'delete', path: TEXT_PATH, beforeJson }, 'rev-1');
|
|
140
|
+
expect(isRejection(result)).toBe(true);
|
|
141
|
+
if (isRejection(result))
|
|
142
|
+
expect(result.reason).toMatch(/structural/);
|
|
143
|
+
});
|
|
144
|
+
it('rejects json_insert on a docs-bound scratchpad (structural)', () => {
|
|
145
|
+
const beforeJson = docWith(textRunElement('x\n', 1));
|
|
146
|
+
const result = translateMutation({ op: 'insert', path: '$.body.content', value: { paragraph: {} }, beforeJson }, 'rev-1');
|
|
147
|
+
expect(isRejection(result)).toBe(true);
|
|
148
|
+
if (isRejection(result))
|
|
149
|
+
expect(result.reason).toMatch(/structural/);
|
|
150
|
+
});
|
|
151
|
+
it('rejects when the element index is out of range', () => {
|
|
152
|
+
const beforeJson = docWith(textRunElement('x\n', 1));
|
|
153
|
+
const result = translateMutation({ op: 'set', path: '$.body.content[5].paragraph.elements[0].textRun.content', value: 'y', beforeJson }, 'rev-1');
|
|
154
|
+
expect(isRejection(result)).toBe(true);
|
|
155
|
+
if (isRejection(result))
|
|
156
|
+
expect(result.reason).toMatch(/not found/);
|
|
157
|
+
});
|
|
158
|
+
it('rejects on a malformed buffer JSON (caller surfaces "fix syntax first")', () => {
|
|
159
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 'x', beforeJson: '{ this is not valid JSON' }, 'rev-1');
|
|
160
|
+
expect(isRejection(result)).toBe(true);
|
|
161
|
+
if (isRejection(result))
|
|
162
|
+
expect(result.reason).toMatch(/JSON/);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
describe('translateMutation — writeControl.requiredRevisionId', () => {
|
|
166
|
+
it('omits writeControl when no revisionId is provided', () => {
|
|
167
|
+
// E.g. an older import that didn't capture a revisionId. The API still
|
|
168
|
+
// accepts the request, just without optimistic-concurrency protection.
|
|
169
|
+
const beforeJson = docWith(textRunElement('x\n', 1));
|
|
170
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 'y', beforeJson }, undefined);
|
|
171
|
+
if (isRejection(result))
|
|
172
|
+
throw new Error('unexpected rejection');
|
|
173
|
+
expect(result.body.writeControl).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
it('includes writeControl for paragraphStyle changes as well as text', () => {
|
|
176
|
+
const beforeJson = docWith(textRunElement('x\n', 1));
|
|
177
|
+
const text = translateMutation({ op: 'set', path: TEXT_PATH, value: 'y', beforeJson }, 'rev-42');
|
|
178
|
+
const style = translateMutation({ op: 'set', path: STYLE_PATH, value: 'HEADING_2', beforeJson }, 'rev-42');
|
|
179
|
+
if (isRejection(text) || isRejection(style))
|
|
180
|
+
throw new Error('unexpected rejection');
|
|
181
|
+
expect(text.body.writeControl).toEqual({ requiredRevisionId: 'rev-42' });
|
|
182
|
+
expect(style.body.writeControl).toEqual({ requiredRevisionId: 'rev-42' });
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
describe('translateMutation — summary', () => {
|
|
186
|
+
it('summary names the path and (for text) the length delta', () => {
|
|
187
|
+
const beforeJson = docWith(textRunElement('Hello\n', 1));
|
|
188
|
+
const result = translateMutation({ op: 'set', path: TEXT_PATH, value: 'Goodbye', beforeJson }, 'rev-1');
|
|
189
|
+
if (isRejection(result))
|
|
190
|
+
throw new Error('unexpected rejection');
|
|
191
|
+
expect(result.summary).toMatch(/content\[0\].elements\[0\]/);
|
|
192
|
+
// 'Hello\n'.length = 6, 'Goodbye'.length = 7
|
|
193
|
+
expect(result.summary).toMatch(/6 → 7/);
|
|
194
|
+
});
|
|
195
|
+
it('summary names the paragraphStyle field for style changes', () => {
|
|
196
|
+
const beforeJson = docWith(textRunElement('x\n', 1));
|
|
197
|
+
const result = translateMutation({ op: 'set', path: STYLE_PATH, value: 'HEADING_1', beforeJson }, 'rev-1');
|
|
198
|
+
if (isRejection(result))
|
|
199
|
+
throw new Error('unexpected rejection');
|
|
200
|
+
expect(result.summary).toMatch(/paragraphStyle\.namedStyleType/);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
/**
|
|
204
|
+
* Suggested next pass — handler-level integration tests that mock `execute`
|
|
205
|
+
* to cover the API-error-preserves-buffer and success-reloads-buffer cases.
|
|
206
|
+
* Co-located with this file would be reasonable; a separate file under the
|
|
207
|
+
* same dir keeps the unit-vs-integration split clear.
|
|
208
|
+
*
|
|
209
|
+
* - API rejects (stale revisionId, structural error) → buffer preserved.
|
|
210
|
+
* - API succeeds → reloadDocsBuffer fires, sp.lines replaced, binding
|
|
211
|
+
* revisionId updated from the fresh response.
|
|
212
|
+
*/
|
|
213
|
+
//# sourceMappingURL=docs-sync.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-sync.test.js","sourceRoot":"","sources":["../../../../src/server/scratchpad/__tests__/docs-sync.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -52,7 +52,9 @@ async function importDocJson(scratchpads, scratchpadId, email, documentId) {
|
|
|
52
52
|
'docs', 'documents', 'get',
|
|
53
53
|
'--params', JSON.stringify({ documentId }),
|
|
54
54
|
], { account: email });
|
|
55
|
-
const
|
|
55
|
+
const doc = result.data;
|
|
56
|
+
const revisionId = typeof doc.revisionId === 'string' ? doc.revisionId : undefined;
|
|
57
|
+
const json = JSON.stringify(doc, null, 2);
|
|
56
58
|
const lines = json.split('\n');
|
|
57
59
|
scratchpads.appendRawLines(scratchpadId, lines);
|
|
58
60
|
scratchpads.setFormat(scratchpadId, 'json');
|
|
@@ -60,10 +62,11 @@ async function importDocJson(scratchpads, scratchpadId, email, documentId) {
|
|
|
60
62
|
service: 'docs',
|
|
61
63
|
resourceId: documentId,
|
|
62
64
|
account: email,
|
|
65
|
+
revisionId, // optimistic-concurrency seed for batchUpdate (#79)
|
|
63
66
|
});
|
|
64
67
|
return {
|
|
65
|
-
text: `Imported doc as JSON (${lines.length} lines) into scratchpad ${scratchpadId}.\nLive-bound to docs/${documentId} — json_set mutations
|
|
66
|
-
refs: { scratchpadId, documentId, format: 'json', linesImported: lines.length, bound: true },
|
|
68
|
+
text: `Imported doc as JSON (${lines.length} lines) into scratchpad ${scratchpadId}.\nLive-bound to docs/${documentId} — json_set mutations push back via batchUpdate.`,
|
|
69
|
+
refs: { scratchpadId, documentId, format: 'json', linesImported: lines.length, bound: true, revisionId },
|
|
67
70
|
};
|
|
68
71
|
}
|
|
69
72
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-doc.js","sourceRoot":"","sources":["../../../../src/server/scratchpad/adapters/import-doc.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"import-doc.js","sourceRoot":"","sources":["../../../../src/server/scratchpad/adapters/import-doc.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,7 +25,7 @@ export async function sendCalendarEvent(scratchpads, scratchpadId, targetParams)
|
|
|
25
25
|
if (location)
|
|
26
26
|
args.push('--location', location);
|
|
27
27
|
if (attendees)
|
|
28
|
-
args.push('--
|
|
28
|
+
args.push('--attendee', attendees);
|
|
29
29
|
try {
|
|
30
30
|
const result = await execute(args, { account: email });
|
|
31
31
|
const data = result.data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-calendar.js","sourceRoot":"","sources":["../../../../src/server/scratchpad/adapters/send-calendar.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAW3D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAA8B,EAC9B,YAAoB,EACpB,YAAiC;IAEjC,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IACrD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,EAAE,IAAI,EAAE,cAAc,YAAY,aAAa,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;IAClF,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,YAAY,CAAC;IACzE,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QACzC,OAAO;YACL,IAAI,EAAE,4FAA4F,YAAY,mBAAmB;YACjI,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE;SACpC,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG;QACX,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,OAAO;QACpB,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,GAAG;QACZ,eAAe,EAAE,OAAO;KACzB,CAAC;IACF,IAAI,QAAQ;QAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAChD,IAAI,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"send-calendar.js","sourceRoot":"","sources":["../../../../src/server/scratchpad/adapters/send-calendar.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAW3D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAA8B,EAC9B,YAAoB,EACpB,YAAiC;IAEjC,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IACrD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,EAAE,IAAI,EAAE,cAAc,YAAY,aAAa,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;IAClF,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,YAAY,CAAC;IACzE,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QACzC,OAAO;YACL,IAAI,EAAE,4FAA4F,YAAY,mBAAmB;YACjI,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE;SACpC,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG;QACX,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,OAAO;QACpB,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,GAAG;QACZ,eAAe,EAAE,OAAO;KACzB,CAAC;IACF,IAAI,QAAQ;QAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAChD,IAAI,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAElD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,MAAM,CAAC,IAA+B,CAAC;QAEpD,OAAO;YACL,IAAI,EAAE,oBAAoB,OAAO,QAAQ;gBACvC,aAAa,KAAK,MAAM,GAAG,IAAI;gBAC/B,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5C,wCAAwC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,WAAW;gBAC7E,iBAAiB,IAAI,CAAC,EAAE,IAAI,SAAS,EAAE;gBACvC,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC;YAC5C,IAAI,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE;SAC9D,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO;YACL,IAAI,EAAE,gBAAgB,OAAO,gBAAgB,YAAY,mBAAmB;YAC5E,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE;SACpC,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docs-sync — translate a single JSON-mode mutation into a Google Docs
|
|
3
|
+
* `batchUpdate` request, or reject it.
|
|
4
|
+
*
|
|
5
|
+
* Issue #79 / deferred portion of ADR-301. The scratchpad JSON-mode buffer
|
|
6
|
+
* for a Doc lets agents do `json_set` on a typed path; this module turns
|
|
7
|
+
* those intents into the discrete operations the Docs API requires
|
|
8
|
+
* (`insertText`, `deleteContentRange`, `updateParagraphStyle`) — no full
|
|
9
|
+
* JSON replace endpoint exists.
|
|
10
|
+
*
|
|
11
|
+
* Two supported path shapes:
|
|
12
|
+
*
|
|
13
|
+
* 1. `$.body.content[N].paragraph.elements[M].textRun.content`
|
|
14
|
+
* Text content change → `deleteContentRange(startIndex, endIndex)` +
|
|
15
|
+
* `insertText(text=newValue, location.index=startIndex)`. Watch the
|
|
16
|
+
* trailing-newline trap: a textRun whose content ends with `\n` includes
|
|
17
|
+
* the paragraph break in its range; deleting through it removes the
|
|
18
|
+
* paragraph. We delete `endIndex - 1` in that case to preserve the break.
|
|
19
|
+
* A `\n` in the new value is rejected — that's a structural edit dressed
|
|
20
|
+
* as a text change.
|
|
21
|
+
*
|
|
22
|
+
* 2. `$.body.content[N].paragraph.paragraphStyle.<field>`
|
|
23
|
+
* Paragraph style change → `updateParagraphStyle` over the element's
|
|
24
|
+
* range with `fields: <field>`. We don't pre-validate the field name —
|
|
25
|
+
* the API rejects unknown fields cleanly and we surface its message.
|
|
26
|
+
*
|
|
27
|
+
* Anything else (structural edits, table cells, list items, image
|
|
28
|
+
* properties, root-level changes) is rejected with guidance to use markdown
|
|
29
|
+
* mode + doc_create / doc_write for structural authoring.
|
|
30
|
+
*
|
|
31
|
+
* Optimistic concurrency: every translation includes
|
|
32
|
+
* `writeControl.requiredRevisionId` = the revisionId captured at import time
|
|
33
|
+
* (or after the previous successful sync). The Docs API rejects stale
|
|
34
|
+
* writes — the agent gets a clean error rather than silently corrupting a
|
|
35
|
+
* doc that's been edited by a collaborator since import.
|
|
36
|
+
*/
|
|
37
|
+
export type DocsSyncOp = 'set' | 'delete' | 'insert';
|
|
38
|
+
export interface DocsSyncIntent {
|
|
39
|
+
op: DocsSyncOp;
|
|
40
|
+
path: string;
|
|
41
|
+
/** New value for `set` / `insert`; undefined for `delete`. */
|
|
42
|
+
value?: unknown;
|
|
43
|
+
/** Pre-mutation buffer JSON text (for looking up startIndex/endIndex/oldContent). */
|
|
44
|
+
beforeJson: string;
|
|
45
|
+
}
|
|
46
|
+
/** Successful translation — body to POST to documents.batchUpdate. */
|
|
47
|
+
export interface DocsSyncRequest {
|
|
48
|
+
body: {
|
|
49
|
+
requests: Array<Record<string, unknown>>;
|
|
50
|
+
writeControl?: {
|
|
51
|
+
requiredRevisionId: string;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
/** A human-readable summary of what was translated, for the response text. */
|
|
55
|
+
summary: string;
|
|
56
|
+
}
|
|
57
|
+
/** Rejection — caller surfaces `reason` to the agent. */
|
|
58
|
+
export interface DocsSyncRejection {
|
|
59
|
+
reason: string;
|
|
60
|
+
}
|
|
61
|
+
export type DocsSyncResult = DocsSyncRequest | DocsSyncRejection;
|
|
62
|
+
/** Translate a mutation intent into a batchUpdate request, or reject it. */
|
|
63
|
+
export declare function translateMutation(intent: DocsSyncIntent, revisionId: string | undefined): DocsSyncResult;
|
|
64
|
+
/** Type guard — narrows DocsSyncResult to the rejection arm. */
|
|
65
|
+
export declare function isRejection(result: DocsSyncResult): result is DocsSyncRejection;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docs-sync — translate a single JSON-mode mutation into a Google Docs
|
|
3
|
+
* `batchUpdate` request, or reject it.
|
|
4
|
+
*
|
|
5
|
+
* Issue #79 / deferred portion of ADR-301. The scratchpad JSON-mode buffer
|
|
6
|
+
* for a Doc lets agents do `json_set` on a typed path; this module turns
|
|
7
|
+
* those intents into the discrete operations the Docs API requires
|
|
8
|
+
* (`insertText`, `deleteContentRange`, `updateParagraphStyle`) — no full
|
|
9
|
+
* JSON replace endpoint exists.
|
|
10
|
+
*
|
|
11
|
+
* Two supported path shapes:
|
|
12
|
+
*
|
|
13
|
+
* 1. `$.body.content[N].paragraph.elements[M].textRun.content`
|
|
14
|
+
* Text content change → `deleteContentRange(startIndex, endIndex)` +
|
|
15
|
+
* `insertText(text=newValue, location.index=startIndex)`. Watch the
|
|
16
|
+
* trailing-newline trap: a textRun whose content ends with `\n` includes
|
|
17
|
+
* the paragraph break in its range; deleting through it removes the
|
|
18
|
+
* paragraph. We delete `endIndex - 1` in that case to preserve the break.
|
|
19
|
+
* A `\n` in the new value is rejected — that's a structural edit dressed
|
|
20
|
+
* as a text change.
|
|
21
|
+
*
|
|
22
|
+
* 2. `$.body.content[N].paragraph.paragraphStyle.<field>`
|
|
23
|
+
* Paragraph style change → `updateParagraphStyle` over the element's
|
|
24
|
+
* range with `fields: <field>`. We don't pre-validate the field name —
|
|
25
|
+
* the API rejects unknown fields cleanly and we surface its message.
|
|
26
|
+
*
|
|
27
|
+
* Anything else (structural edits, table cells, list items, image
|
|
28
|
+
* properties, root-level changes) is rejected with guidance to use markdown
|
|
29
|
+
* mode + doc_create / doc_write for structural authoring.
|
|
30
|
+
*
|
|
31
|
+
* Optimistic concurrency: every translation includes
|
|
32
|
+
* `writeControl.requiredRevisionId` = the revisionId captured at import time
|
|
33
|
+
* (or after the previous successful sync). The Docs API rejects stale
|
|
34
|
+
* writes — the agent gets a clean error rather than silently corrupting a
|
|
35
|
+
* doc that's been edited by a collaborator since import.
|
|
36
|
+
*/
|
|
37
|
+
import { parsePath } from './json-path.js';
|
|
38
|
+
/** Translate a mutation intent into a batchUpdate request, or reject it. */
|
|
39
|
+
export function translateMutation(intent, revisionId) {
|
|
40
|
+
// `json_delete` and `json_insert` only ever shape up as structural edits in
|
|
41
|
+
// a Docs document (removing a paragraph, inserting into the content array).
|
|
42
|
+
// The Docs API has no JSON-replace primitive; structural changes need
|
|
43
|
+
// distinct operations per element type. Out of scope for #79 — reject so
|
|
44
|
+
// the agent uses markdown mode (re-author + doc_create / doc_write).
|
|
45
|
+
if (intent.op === 'delete' || intent.op === 'insert') {
|
|
46
|
+
return {
|
|
47
|
+
reason: `json_${intent.op} on a docs-bound scratchpad is structural — use markdown mode (export the doc, edit, doc_create or doc_write).`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const segments = parsePath(intent.path);
|
|
51
|
+
if (isTextRunContentPath(segments)) {
|
|
52
|
+
return translateTextContent(intent, segments, revisionId);
|
|
53
|
+
}
|
|
54
|
+
if (isParagraphStylePath(segments)) {
|
|
55
|
+
return translateParagraphStyle(intent, segments, revisionId);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
reason: `path ${intent.path} is not supported for live Docs sync. Supported: '$.body.content[N].paragraph.elements[M].textRun.content' (text) and '$.body.content[N].paragraph.paragraphStyle.<field>' (paragraph style). For structural edits use markdown mode.`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// ── Path-shape matchers ──────────────────────────────────────
|
|
62
|
+
function isTextRunContentPath(segments) {
|
|
63
|
+
return segments.length === 8
|
|
64
|
+
&& segments[0] === 'body'
|
|
65
|
+
&& segments[1] === 'content'
|
|
66
|
+
&& typeof segments[2] === 'number'
|
|
67
|
+
&& segments[3] === 'paragraph'
|
|
68
|
+
&& segments[4] === 'elements'
|
|
69
|
+
&& typeof segments[5] === 'number'
|
|
70
|
+
&& segments[6] === 'textRun'
|
|
71
|
+
&& segments[7] === 'content';
|
|
72
|
+
}
|
|
73
|
+
function isParagraphStylePath(segments) {
|
|
74
|
+
return segments.length === 6
|
|
75
|
+
&& segments[0] === 'body'
|
|
76
|
+
&& segments[1] === 'content'
|
|
77
|
+
&& typeof segments[2] === 'number'
|
|
78
|
+
&& segments[3] === 'paragraph'
|
|
79
|
+
&& segments[4] === 'paragraphStyle'
|
|
80
|
+
&& typeof segments[5] === 'string';
|
|
81
|
+
}
|
|
82
|
+
// ── Translators ──────────────────────────────────────────────
|
|
83
|
+
function translateTextContent(intent, segments, revisionId) {
|
|
84
|
+
if (typeof intent.value !== 'string') {
|
|
85
|
+
return { reason: `textRun.content value must be a string, got ${typeof intent.value}` };
|
|
86
|
+
}
|
|
87
|
+
// A newline in the new value adds a paragraph break — that's a structural
|
|
88
|
+
// edit, not a text-content edit. Rejecting keeps the supported surface
|
|
89
|
+
// narrow and predictable; structural authoring belongs in markdown mode.
|
|
90
|
+
if (intent.value.includes('\n')) {
|
|
91
|
+
return { reason: 'newline in new value is a structural edit (adds a paragraph break) — use markdown mode for multi-paragraph content.' };
|
|
92
|
+
}
|
|
93
|
+
const contentIdx = segments[2];
|
|
94
|
+
const elementIdx = segments[5];
|
|
95
|
+
let doc;
|
|
96
|
+
try {
|
|
97
|
+
doc = JSON.parse(intent.beforeJson);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return { reason: 'buffer JSON parse failed — fix syntax errors before sync.' };
|
|
101
|
+
}
|
|
102
|
+
const element = navigate(doc, ['body', 'content', contentIdx, 'paragraph', 'elements', elementIdx]);
|
|
103
|
+
if (!element || typeof element !== 'object') {
|
|
104
|
+
return { reason: `element at body.content[${contentIdx}].paragraph.elements[${elementIdx}] not found in buffer.` };
|
|
105
|
+
}
|
|
106
|
+
const e = element;
|
|
107
|
+
const startIndex = e.startIndex;
|
|
108
|
+
const endIndex = e.endIndex;
|
|
109
|
+
const textRun = e.textRun;
|
|
110
|
+
const oldContent = textRun?.content;
|
|
111
|
+
if (typeof startIndex !== 'number' || typeof endIndex !== 'number') {
|
|
112
|
+
return { reason: `element at content[${contentIdx}].elements[${elementIdx}] is missing startIndex/endIndex.` };
|
|
113
|
+
}
|
|
114
|
+
if (typeof oldContent !== 'string') {
|
|
115
|
+
return { reason: `element at content[${contentIdx}].elements[${elementIdx}] is not a textRun (or has no content).` };
|
|
116
|
+
}
|
|
117
|
+
// Trailing-newline trap: if the run's content ends with `\n`, that newline
|
|
118
|
+
// IS the paragraph break. Deleting through endIndex removes the paragraph;
|
|
119
|
+
// delete through endIndex-1 instead and the paragraph survives.
|
|
120
|
+
const deleteEnd = oldContent.endsWith('\n') ? endIndex - 1 : endIndex;
|
|
121
|
+
// Defensive: if the element is a bare-newline run (oldContent === '\n'),
|
|
122
|
+
// there's nothing to delete; just insert.
|
|
123
|
+
const requests = [];
|
|
124
|
+
if (deleteEnd > startIndex) {
|
|
125
|
+
requests.push({
|
|
126
|
+
deleteContentRange: { range: { startIndex, endIndex: deleteEnd } },
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
requests.push({
|
|
130
|
+
insertText: { text: intent.value, location: { index: startIndex } },
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
body: {
|
|
134
|
+
requests,
|
|
135
|
+
...(revisionId ? { writeControl: { requiredRevisionId: revisionId } } : {}),
|
|
136
|
+
},
|
|
137
|
+
summary: `text content @ content[${contentIdx}].elements[${elementIdx}] (${oldContent.length} → ${intent.value.length} chars)`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function translateParagraphStyle(intent, segments, revisionId) {
|
|
141
|
+
const contentIdx = segments[2];
|
|
142
|
+
const field = segments[5];
|
|
143
|
+
let doc;
|
|
144
|
+
try {
|
|
145
|
+
doc = JSON.parse(intent.beforeJson);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return { reason: 'buffer JSON parse failed — fix syntax errors before sync.' };
|
|
149
|
+
}
|
|
150
|
+
const structural = navigate(doc, ['body', 'content', contentIdx]);
|
|
151
|
+
if (!structural || typeof structural !== 'object') {
|
|
152
|
+
return { reason: `content[${contentIdx}] not found in buffer.` };
|
|
153
|
+
}
|
|
154
|
+
const s = structural;
|
|
155
|
+
const startIndex = s.startIndex;
|
|
156
|
+
const endIndex = s.endIndex;
|
|
157
|
+
if (typeof startIndex !== 'number' || typeof endIndex !== 'number') {
|
|
158
|
+
return { reason: `content[${contentIdx}] is missing startIndex/endIndex.` };
|
|
159
|
+
}
|
|
160
|
+
if (!s.paragraph) {
|
|
161
|
+
return { reason: `content[${contentIdx}] is not a paragraph (paragraphStyle only applies to paragraphs).` };
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
body: {
|
|
165
|
+
requests: [{
|
|
166
|
+
updateParagraphStyle: {
|
|
167
|
+
range: { startIndex, endIndex },
|
|
168
|
+
paragraphStyle: { [field]: intent.value },
|
|
169
|
+
fields: field,
|
|
170
|
+
},
|
|
171
|
+
}],
|
|
172
|
+
...(revisionId ? { writeControl: { requiredRevisionId: revisionId } } : {}),
|
|
173
|
+
},
|
|
174
|
+
summary: `paragraphStyle.${field} @ content[${contentIdx}]`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// ── Helpers ──────────────────────────────────────────────────
|
|
178
|
+
function navigate(obj, segments) {
|
|
179
|
+
let current = obj;
|
|
180
|
+
for (const seg of segments) {
|
|
181
|
+
if (current === null || current === undefined || typeof current !== 'object')
|
|
182
|
+
return undefined;
|
|
183
|
+
current = current[String(seg)];
|
|
184
|
+
}
|
|
185
|
+
return current;
|
|
186
|
+
}
|
|
187
|
+
/** Type guard — narrows DocsSyncResult to the rejection arm. */
|
|
188
|
+
export function isRejection(result) {
|
|
189
|
+
return 'reason' in result;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=docs-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-sync.js","sourceRoot":"","sources":["../../../src/server/scratchpad/docs-sync.ts"],"names":[],"mappings":"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"}
|