@mcpher/gas-fakes 2.3.15 → 2.3.17
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/gf_agent/SKILL.md +75 -11
- package/gf_agent/index.md +2 -2
- package/gf_agent/knowledge/00-execution-context.md +1 -0
- package/gf_agent/knowledge/02-syntax.md +3 -2
- package/gf_agent/knowledge/04-advanced.md +25 -3
- package/gf_agent/knowledge/05-sheets-forms.md +1 -0
- package/gf_agent/knowledge/09-orchestrator-pattern.md +5 -4
- package/gf_agent/knowledge/10-sandbox-security.md +1 -0
- package/gf_agent/knowledge/13-advanced-services-discovery.md +23 -0
- package/gf_agent/knowledge/14-utilities-parity.md +13 -0
- package/gf_agent/scripts/SKILL.template.md +0 -2
- package/gf_agent/skills/document.md +126 -0
- package/gf_agent/skills/gmail.md +1 -1
- package/gf_agent/skills/spreadsheet.md +1 -1
- package/gf_agent/skills/utilities.md +17 -0
- package/package.json +1 -1
- package/src/services/documentapp/fakecontainerelement.js +88 -0
- package/src/services/enums/utilitiesenums.js +26 -0
- package/src/services/slidesapp/fakecolorscheme.js +29 -10
- package/src/services/slidesapp/fakepresentation.js +0 -8
- package/src/services/spreadsheetapp/fakespreadsheetapp.js +15 -1
- package/src/services/utilities/fakeutilities.js +331 -15
- package/src/support/sxjdbc.js +16 -3
- package/src/support/utils.js +2 -2
package/gf_agent/SKILL.md
CHANGED
|
@@ -25,7 +25,6 @@ description: >
|
|
|
25
25
|
- **Remote URL**: `https://raw.githubusercontent.com/brucemcpherson/gas-fakes/main/progress/{service}.md` (Note: `{service}` is lowercase, e.g., `spreadsheet.md`).
|
|
26
26
|
- Use these details to construct precise, parity-compliant code without relying on external search engines unless documentation is missing.
|
|
27
27
|
3. **Generate Script**: Create a Node.js script that:
|
|
28
|
-
- Imports `@mcpher/gas-fakes`.
|
|
29
28
|
- Uses standard GAS syntax.
|
|
30
29
|
- (Optional) Uses `ScriptApp.isFake` for local-only logic like logging or cleanup.
|
|
31
30
|
4. **Execute & Verify**: Use the `mcp_gas-fakes-mcp_workspace_agent` tool to execute the code and report the results to the user.
|
|
@@ -39,7 +38,6 @@ Agent:
|
|
|
39
38
|
- (Optional) Fetch `progress/gmail.md` and `progress/document.md` from GitHub for detailed signatures.
|
|
40
39
|
3. **Generate Script**:
|
|
41
40
|
```javascript
|
|
42
|
-
import '@mcpher/gas-fakes';
|
|
43
41
|
const threads = GmailApp.getInboxThreads(0, 5);
|
|
44
42
|
let summary = 'Email Summary:\n\n';
|
|
45
43
|
threads.forEach(t => {
|
|
@@ -67,6 +65,7 @@ Agent:
|
|
|
67
65
|
### Execution Context & Artifacts (CRITICAL)
|
|
68
66
|
- **Role Boundary**: You are the `gf_agent` operating on behalf of an end-user to automate Google Workspace tasks. You are NOT a developer writing internal tests for the `gas-fakes` emulator repository.
|
|
69
67
|
- **Transient Execution**: When fulfilling automation requests (e.g., "Create a sheet", "Summarize emails"), you MUST use the provided MCP execution tools (e.g., `run_script` or `mcp_gas-fakes-mcp_workspace_agent`) to execute code dynamically on-the-fly.
|
|
68
|
+
- **No Import Required**: Do NOT include `import '@mcpher/gas-fakes';` at the top of your scripts when using the MCP execution tools. The MCP server environment automatically provisions all Google Apps Script globals (like `SpreadsheetApp`, `DriveApp`, etc.) into the execution context for you.
|
|
70
69
|
- **No Permanent Artifacts**: DO NOT write script files to disk (e.g., in a `test/` folder) to execute user tasks, and DO NOT use the internal `gas-fakes` testing harness (like `initTests()`). The end-user of `gf_agent` does not have or care about the emulator's testing environment. Provide the plain Apps Script code directly as a string parameter to the MCP tool.
|
|
71
70
|
|
|
72
71
|
### Efficient Drive Searching (Best Practice)
|
|
@@ -84,8 +83,9 @@ Agent:
|
|
|
84
83
|
|
|
85
84
|
|
|
86
85
|
### Common Apps Script Syntax Gotchas (First-Time Accuracy)
|
|
87
|
-
- **File Conversion (Exporting to PDF)**:
|
|
88
|
-
-
|
|
86
|
+
- **File Conversion (Exporting to PDF)**:
|
|
87
|
+
- **`DriveApp.File.getAs()` Workaround**: While live Apps Script can seamlessly convert text files (`text/plain`) to PDF using `file.getAs('application/pdf')`, the underlying Google Drive API **only supports exporting Docs Editor files** (Docs, Sheets, Slides). `gas-fakes` handles this transparently by automatically performing a temporary two-step conversion (copying it to a Google Doc, exporting it, and trashing the temp file). This ensures parity with live Apps Script without manual intervention.
|
|
88
|
+
- **`Spreadsheet.getAs()` Limitation**: The `getAs()` method is **NOT** implemented directly on `Spreadsheet`, `Document`, or `Presentation` objects in `gas-fakes`. If you try to call `ss.getAs('application/pdf')`, the script will crash. **Crucial Rule**: You MUST fetch the file via DriveApp first to convert it: `DriveApp.getFileById(ss.getId()).getAs('application/pdf')`.
|
|
89
89
|
- **Google Docs Formatting**: You CANNOT apply formatting (bold, italic, etc.) directly to a `Paragraph` or `ListItem`. You MUST use `editAsText()` first.
|
|
90
90
|
- *Incorrect*: `paragraph.setItalic(true)`
|
|
91
91
|
- *Correct*: `paragraph.editAsText().setItalic(true)`
|
|
@@ -126,14 +126,36 @@ Agent:
|
|
|
126
126
|
- **Iterators**: `gas-fakes` iterators (like `FileIterator`) implement the native Apps Script `hasNext()` and `next()` methods, which differ from standard JavaScript iterators.
|
|
127
127
|
|
|
128
128
|
### Google Docs & Images
|
|
129
|
-
- **Inline Image Resizing**: Native methods like `setWidth()
|
|
129
|
+
- **Inline Image Resizing (DocumentApp)**: Native methods like `setWidth()` and `setHeight()` on `InlineImage` objects are **NOT** implemented in `gas-fakes`. If you call these, the script will crash with a "not yet implemented" error.
|
|
130
130
|
- **Conversion**: To create a Google Doc from HTML, use `Drive.Files.create()` with the correct v3 parameters:
|
|
131
131
|
```javascript
|
|
132
132
|
const resource = { name: "Doc Name", mimeType: "application/vnd.google-apps.document" };
|
|
133
133
|
Drive.Files.create(resource, htmlBlob);
|
|
134
134
|
```
|
|
135
|
-
- **Resizing Workaround**:
|
|
136
|
-
-
|
|
135
|
+
- **Resizing Workaround (Advanced Docs Service)**: Because the Docs API does not support updating image properties directly, you must use the Advanced Docs Service (`Docs.Documents.batchUpdate`) to **delete and re-insert** the image with the new dimensions.
|
|
136
|
+
- To do this, fetch the document via `Docs.Documents.get()`, extract the `contentUri` from the existing inline image, and construct `deleteObject` and `insertInlineImage` requests.
|
|
137
|
+
- **Crucial**: Always sort your delete/insert operations by `startIndex` in **descending order** so you don't corrupt the document's indices during a batch update.
|
|
138
|
+
- **Example Code Pattern**:
|
|
139
|
+
```javascript
|
|
140
|
+
const docData = Docs.Documents.get(docId);
|
|
141
|
+
const requests = [];
|
|
142
|
+
// ... logic to find images in docData.body.content, saving objectId, contentUri, startIndex, and dimensions ...
|
|
143
|
+
// ... sort found images by startIndex DESCENDING ...
|
|
144
|
+
images.forEach(img => {
|
|
145
|
+
requests.push({ deleteObject: { objectId: img.objectId } });
|
|
146
|
+
requests.push({
|
|
147
|
+
insertInlineImage: {
|
|
148
|
+
uri: img.contentUri,
|
|
149
|
+
location: { index: img.startIndex },
|
|
150
|
+
objectSize: {
|
|
151
|
+
width: { magnitude: img.width * 0.25, unit: 'PT' },
|
|
152
|
+
height: { magnitude: img.height * 0.25, unit: 'PT' }
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
if (requests.length > 0) Docs.Documents.batchUpdate({ requests }, docId);
|
|
158
|
+
```
|
|
137
159
|
- **Shadow Document & Named Ranges**: `gas-fakes` uses a "Shadow Document" approach. Elements are tracked using Named Range tags to maintain positional integrity during updates.
|
|
138
160
|
- **Table Creation**: `appendTable()` without arguments creates a 1x1 table in `gas-fakes`, whereas live Apps Script creates an empty table stub.
|
|
139
161
|
- **Rate Limiting (429 Errors)**: Because `gas-fakes` translates local calls into real-time API requests, making rapid, successive calls like `appendParagraph()` in a loop will trigger Google's rate limit.
|
|
@@ -149,6 +171,7 @@ Agent:
|
|
|
149
171
|
- `getDisplayValues()` returns formatted strings.
|
|
150
172
|
- `setValues()` uses "USER_ENTERED" mode.
|
|
151
173
|
- **Bulk Operations (RangeList)**: Use `sheet.getRangeList(['A1', 'C1', 'E1'])` for multi-range formatting.
|
|
174
|
+
- **Exporting to PDF (`getAs`)**: The `Spreadsheet.getAs()` method is **NOT** implemented in `gas-fakes`. If you need to convert a Spreadsheet (or a Document/Presentation) to a PDF, you MUST use the `DriveApp` service workaround: `DriveApp.getFileById(spreadsheet.getId()).getAs('application/pdf')`.
|
|
152
175
|
|
|
153
176
|
### Google Forms (FormApp)
|
|
154
177
|
- **Programmatic Submission**: The public Forms API does **not** support submitting responses. `gas-fakes` uses a "web submission hack" that temporarily makes the form public to scrape tokens and POST the response.
|
|
@@ -273,12 +296,13 @@ Once all required service-specific knowledge is gathered:
|
|
|
273
296
|
- **Parity Guarantee**: The remote documentation is generated directly from the `gas-fakes` source code, ensuring 100% parity with the local environment.
|
|
274
297
|
|
|
275
298
|
## Delegation Anti-Patterns (CRITICAL)
|
|
276
|
-
- **NEVER Delegate Execution**: The main orchestrator agent MUST retain control of script generation and the execution tool (
|
|
277
|
-
- **
|
|
278
|
-
- **
|
|
299
|
+
- **NEVER Delegate Execution**: The main orchestrator agent MUST retain control of script generation and the execution tool (`mcp_gas-fakes-mcp_workspace_agent`).
|
|
300
|
+
- **Unauthorized Tool Call Error**: Sub-agents (like `generalist`) DO NOT have access to MCP tools. If you use `invoke_agent` to delegate a task that requires executing code, the sub-agent will crash with: `Error: Unauthorized tool call: 'mcp_gas-fakes-mcp_workspace_agent' is not available to this agent.`
|
|
301
|
+
- **Subagent Context Loss**: Subagents do **not** inherit the `gf_agent` knowledge base, parity rules, or active skills. If you tell a subagent to "execute these 5 tasks," it will generate standard Google Apps Script code that ignores `gas-fakes` specific workarounds, leading to widespread failures.
|
|
302
|
+
- **Strict Role Boundary**: Subagents are strictly for **isolated documentation retrieval** (the Service Agent Phase) via standard shell commands like `curl`. The main agent writes and runs the code.
|
|
279
303
|
|
|
280
304
|
## Safe Parallelism (Performance)
|
|
281
|
-
|
|
305
|
+
If the user asks you to run multiple tasks in parallel, DO NOT use `invoke_agent`. You must handle them directly in the main session. The orchestrator should achieve parallelism in two ways:
|
|
282
306
|
1. **Tool Call Parallelism**: The Main Agent generates multiple, parity-compliant scripts and issues them as independent, simultaneous calls to `mcp_gas-fakes-mcp_workspace_agent` within a single turn.
|
|
283
307
|
2. **Execution-Level Async**: Since `gas-fakes` runs on Node.js, the Main Agent can generate a single script that uses `Promise.all()` to execute multiple non-dependent operations (like `UrlFetchApp` calls or creating separate files) simultaneously.
|
|
284
308
|
3. **Sequence when Dependent**: Only use `wait_for_previous: true` or sequential turns when a task depends on the side-effect of a previous one (e.g., reading a sheet that was just created).
|
|
@@ -344,6 +368,7 @@ ScriptApp.__behavior.sandboxService.GmailApp.cleanup = false;
|
|
|
344
368
|
## Best Practices for `gf_agent`
|
|
345
369
|
- **Session Isolation**: When a user provides a list of files or emails, always initialize the sandbox with those specific whitelists at the top of the script.
|
|
346
370
|
- **Explicit Whitelisting**: Use `behavior.addIdWhitelist` for file access. DO NOT assume `sandboxService.SpreadsheetApp` has an `addFileWhitelist` method (it is handled globally by the behavior ID whitelist).
|
|
371
|
+
- **Cross-Platform Portability**: The `ScriptApp.__behavior` object is a `gas-fakes` exclusive feature. If the generated script is intended to be copied and run in Live Apps Script later, you MUST wrap all sandbox-related boilerplate in an `if (ScriptApp.isFake)` block to prevent `TypeError` crashes in the cloud.
|
|
347
372
|
- **Safe Execution**: In the Orchestrator Phase, identify if the task requires external access and include the necessary sandbox boilerplate in the generated script.
|
|
348
373
|
|
|
349
374
|
|
|
@@ -377,6 +402,45 @@ When writing scripts that modify Gmail objects (e.g., `GmailMessage.markRead()`,
|
|
|
377
402
|
```
|
|
378
403
|
- **gas-fakes Execution**: When executing transient scripts locally via `gas-fakes` that don't need immediate assertions, this pattern is not strictly necessary as `gas-fakes` handles the REST API synchronization reliably, but it is best practice for cross-platform parity.
|
|
379
404
|
|
|
405
|
+
### Researching Advanced Services (Google API Discovery)
|
|
406
|
+
|
|
407
|
+
Unlike the standard Apps Script Services (`SpreadsheetApp`, `DriveApp`), the signatures and payloads for **Advanced Services** (`Docs`, `Sheets`, `Drive`, etc.) are not fully documented in the `progress/` directory of the `gas-fakes` repository. Advanced Services are 1:1 mappings of the underlying Google REST APIs.
|
|
408
|
+
|
|
409
|
+
If you are orchestrating a complex task that requires an Advanced Service (such as resizing an image via `Docs.Documents.batchUpdate` or applying granular formatting via `Sheets.Spreadsheets.batchUpdate`) and you do not know the exact JSON payload structure, you MUST research it using the Google API Discovery documents.
|
|
410
|
+
|
|
411
|
+
**How to Research Advanced Services:**
|
|
412
|
+
Do not guess the payload structure. Instead, use the `run_shell_command` tool to `curl` and `grep` the official Discovery Document for the specific API version.
|
|
413
|
+
|
|
414
|
+
**Discovery Document URLs:**
|
|
415
|
+
- **Docs API v1**: `https://docs.googleapis.com/$discovery/rest?version=v1`
|
|
416
|
+
- **Sheets API v4**: `https://sheets.googleapis.com/$discovery/rest?version=v4`
|
|
417
|
+
- **Drive API v3**: `https://drive.googleapis.com/$discovery/rest?version=v3`
|
|
418
|
+
- **Slides API v1**: `https://slides.googleapis.com/$discovery/rest?version=v1`
|
|
419
|
+
- **Gmail API v1**: `https://gmail.googleapis.com/$discovery/rest?version=v1`
|
|
420
|
+
|
|
421
|
+
**Example Research Command:**
|
|
422
|
+
If you need to know how to structure an `insertInlineImage` request for the Docs API, you would run:
|
|
423
|
+
```bash
|
|
424
|
+
curl -s "https://docs.googleapis.com/$discovery/rest?version=v1" | grep -A 30 '"InsertInlineImageRequest":'
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
By fetching the exact schema from the discovery document, you ensure your `batchUpdate` arrays and payload objects are 100% accurate before generating the execution script.
|
|
428
|
+
|
|
429
|
+
### Utilities Service Constraints (API Parity)
|
|
430
|
+
|
|
431
|
+
When generating code that uses the `Utilities` service, you must adhere to the following restrictions to ensure parity with Live Apps Script:
|
|
432
|
+
|
|
433
|
+
1. **`formatString` Format Specifiers**:
|
|
434
|
+
- Live Apps Script uses Java's underlying `String.format` implementation. Therefore, it **does not** support Node.js-specific format specifiers like `%j` for JSON.
|
|
435
|
+
- You MUST stick to standard Java/C-style format specifiers: `%s` (string), `%d` / `%i` (integer), and `%f` (float).
|
|
436
|
+
- *Incorrect*: `Utilities.formatString("Data: %j", obj)`
|
|
437
|
+
- *Correct*: `Utilities.formatString("Data: %s", JSON.stringify(obj))`
|
|
438
|
+
|
|
439
|
+
2. **`parseDate` Error Handling**:
|
|
440
|
+
- If `Utilities.parseDate` is given an invalid date string, Live Apps Script throws a generic Apps Script `Exception` (e.g., `{"name":"Exception"}`) rather than a standard JavaScript `Error` object.
|
|
441
|
+
- If you are writing tests or robust `try/catch` blocks intended to run cross-platform, DO NOT assert against the exact string value of the error message (like `e.message.includes("failed")`). Simply check that an exception was thrown.
|
|
442
|
+
|
|
443
|
+
|
|
380
444
|
# gf_agent Knowledge Base
|
|
381
445
|
|
|
382
446
|
This directory contains modular markdown files representing the "Lessons Learned & Best Practices" for the `gf_agent` skill.
|
package/gf_agent/index.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This index lists all Google Apps Script services and classes supported by `gf_agent` via `gas-fakes`.
|
|
4
4
|
|
|
5
|
+
- [Gmail](skills/gmail.md)
|
|
6
|
+
- [Spreadsheet](skills/spreadsheet.md)
|
|
5
7
|
- [base](skills/base.md)
|
|
6
8
|
- [cache](skills/cache.md)
|
|
7
9
|
- [calendar](skills/calendar.md)
|
|
@@ -9,13 +11,11 @@ This index lists all Google Apps Script services and classes supported by `gf_ag
|
|
|
9
11
|
- [document](skills/document.md)
|
|
10
12
|
- [drive](skills/drive.md)
|
|
11
13
|
- [forms](skills/forms.md)
|
|
12
|
-
- [gmail](skills/gmail.md)
|
|
13
14
|
- [jdbc](skills/jdbc.md)
|
|
14
15
|
- [lock](skills/lock.md)
|
|
15
16
|
- [properties](skills/properties.md)
|
|
16
17
|
- [script](skills/script.md)
|
|
17
18
|
- [slides](skills/slides.md)
|
|
18
|
-
- [spreadsheet](skills/spreadsheet.md)
|
|
19
19
|
- [urlfetch](skills/urlfetch.md)
|
|
20
20
|
- [utilities](skills/utilities.md)
|
|
21
21
|
- [xml](skills/xml.md)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
### Execution Context & Artifacts (CRITICAL)
|
|
2
2
|
- **Role Boundary**: You are the `gf_agent` operating on behalf of an end-user to automate Google Workspace tasks. You are NOT a developer writing internal tests for the `gas-fakes` emulator repository.
|
|
3
3
|
- **Transient Execution**: When fulfilling automation requests (e.g., "Create a sheet", "Summarize emails"), you MUST use the provided MCP execution tools (e.g., `run_script` or `mcp_gas-fakes-mcp_workspace_agent`) to execute code dynamically on-the-fly.
|
|
4
|
+
- **No Import Required**: Do NOT include `import '@mcpher/gas-fakes';` at the top of your scripts when using the MCP execution tools. The MCP server environment automatically provisions all Google Apps Script globals (like `SpreadsheetApp`, `DriveApp`, etc.) into the execution context for you.
|
|
4
5
|
- **No Permanent Artifacts**: DO NOT write script files to disk (e.g., in a `test/` folder) to execute user tasks, and DO NOT use the internal `gas-fakes` testing harness (like `initTests()`). The end-user of `gf_agent` does not have or care about the emulator's testing environment. Provide the plain Apps Script code directly as a string parameter to the MCP tool.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
### Common Apps Script Syntax Gotchas (First-Time Accuracy)
|
|
2
|
-
- **File Conversion (Exporting to PDF)**:
|
|
3
|
-
-
|
|
2
|
+
- **File Conversion (Exporting to PDF)**:
|
|
3
|
+
- **`DriveApp.File.getAs()` Workaround**: While live Apps Script can seamlessly convert text files (`text/plain`) to PDF using `file.getAs('application/pdf')`, the underlying Google Drive API **only supports exporting Docs Editor files** (Docs, Sheets, Slides). `gas-fakes` handles this transparently by automatically performing a temporary two-step conversion (copying it to a Google Doc, exporting it, and trashing the temp file). This ensures parity with live Apps Script without manual intervention.
|
|
4
|
+
- **`Spreadsheet.getAs()` Limitation**: The `getAs()` method is **NOT** implemented directly on `Spreadsheet`, `Document`, or `Presentation` objects in `gas-fakes`. If you try to call `ss.getAs('application/pdf')`, the script will crash. **Crucial Rule**: You MUST fetch the file via DriveApp first to convert it: `DriveApp.getFileById(ss.getId()).getAs('application/pdf')`.
|
|
4
5
|
- **Google Docs Formatting**: You CANNOT apply formatting (bold, italic, etc.) directly to a `Paragraph` or `ListItem`. You MUST use `editAsText()` first.
|
|
5
6
|
- *Incorrect*: `paragraph.setItalic(true)`
|
|
6
7
|
- *Correct*: `paragraph.editAsText().setItalic(true)`
|
|
@@ -9,14 +9,36 @@
|
|
|
9
9
|
- **Iterators**: `gas-fakes` iterators (like `FileIterator`) implement the native Apps Script `hasNext()` and `next()` methods, which differ from standard JavaScript iterators.
|
|
10
10
|
|
|
11
11
|
### Google Docs & Images
|
|
12
|
-
- **Inline Image Resizing**: Native methods like `setWidth()
|
|
12
|
+
- **Inline Image Resizing (DocumentApp)**: Native methods like `setWidth()` and `setHeight()` on `InlineImage` objects are **NOT** implemented in `gas-fakes`. If you call these, the script will crash with a "not yet implemented" error.
|
|
13
13
|
- **Conversion**: To create a Google Doc from HTML, use `Drive.Files.create()` with the correct v3 parameters:
|
|
14
14
|
```javascript
|
|
15
15
|
const resource = { name: "Doc Name", mimeType: "application/vnd.google-apps.document" };
|
|
16
16
|
Drive.Files.create(resource, htmlBlob);
|
|
17
17
|
```
|
|
18
|
-
- **Resizing Workaround**:
|
|
19
|
-
-
|
|
18
|
+
- **Resizing Workaround (Advanced Docs Service)**: Because the Docs API does not support updating image properties directly, you must use the Advanced Docs Service (`Docs.Documents.batchUpdate`) to **delete and re-insert** the image with the new dimensions.
|
|
19
|
+
- To do this, fetch the document via `Docs.Documents.get()`, extract the `contentUri` from the existing inline image, and construct `deleteObject` and `insertInlineImage` requests.
|
|
20
|
+
- **Crucial**: Always sort your delete/insert operations by `startIndex` in **descending order** so you don't corrupt the document's indices during a batch update.
|
|
21
|
+
- **Example Code Pattern**:
|
|
22
|
+
```javascript
|
|
23
|
+
const docData = Docs.Documents.get(docId);
|
|
24
|
+
const requests = [];
|
|
25
|
+
// ... logic to find images in docData.body.content, saving objectId, contentUri, startIndex, and dimensions ...
|
|
26
|
+
// ... sort found images by startIndex DESCENDING ...
|
|
27
|
+
images.forEach(img => {
|
|
28
|
+
requests.push({ deleteObject: { objectId: img.objectId } });
|
|
29
|
+
requests.push({
|
|
30
|
+
insertInlineImage: {
|
|
31
|
+
uri: img.contentUri,
|
|
32
|
+
location: { index: img.startIndex },
|
|
33
|
+
objectSize: {
|
|
34
|
+
width: { magnitude: img.width * 0.25, unit: 'PT' },
|
|
35
|
+
height: { magnitude: img.height * 0.25, unit: 'PT' }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
if (requests.length > 0) Docs.Documents.batchUpdate({ requests }, docId);
|
|
41
|
+
```
|
|
20
42
|
- **Shadow Document & Named Ranges**: `gas-fakes` uses a "Shadow Document" approach. Elements are tracked using Named Range tags to maintain positional integrity during updates.
|
|
21
43
|
- **Table Creation**: `appendTable()` without arguments creates a 1x1 table in `gas-fakes`, whereas live Apps Script creates an empty table stub.
|
|
22
44
|
- **Rate Limiting (429 Errors)**: Because `gas-fakes` translates local calls into real-time API requests, making rapid, successive calls like `appendParagraph()` in a loop will trigger Google's rate limit.
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
- `getDisplayValues()` returns formatted strings.
|
|
7
7
|
- `setValues()` uses "USER_ENTERED" mode.
|
|
8
8
|
- **Bulk Operations (RangeList)**: Use `sheet.getRangeList(['A1', 'C1', 'E1'])` for multi-range formatting.
|
|
9
|
+
- **Exporting to PDF (`getAs`)**: The `Spreadsheet.getAs()` method is **NOT** implemented in `gas-fakes`. If you need to convert a Spreadsheet (or a Document/Presentation) to a PDF, you MUST use the `DriveApp` service workaround: `DriveApp.getFileById(spreadsheet.getId()).getAs('application/pdf')`.
|
|
9
10
|
|
|
10
11
|
### Google Forms (FormApp)
|
|
11
12
|
- **Programmatic Submission**: The public Forms API does **not** support submitting responses. `gas-fakes` uses a "web submission hack" that temporarily makes the form public to scrape tokens and POST the response.
|
|
@@ -43,12 +43,13 @@ Once all required service-specific knowledge is gathered:
|
|
|
43
43
|
- **Parity Guarantee**: The remote documentation is generated directly from the `gas-fakes` source code, ensuring 100% parity with the local environment.
|
|
44
44
|
|
|
45
45
|
## Delegation Anti-Patterns (CRITICAL)
|
|
46
|
-
- **NEVER Delegate Execution**: The main orchestrator agent MUST retain control of script generation and the execution tool (
|
|
47
|
-
- **
|
|
48
|
-
- **
|
|
46
|
+
- **NEVER Delegate Execution**: The main orchestrator agent MUST retain control of script generation and the execution tool (`mcp_gas-fakes-mcp_workspace_agent`).
|
|
47
|
+
- **Unauthorized Tool Call Error**: Sub-agents (like `generalist`) DO NOT have access to MCP tools. If you use `invoke_agent` to delegate a task that requires executing code, the sub-agent will crash with: `Error: Unauthorized tool call: 'mcp_gas-fakes-mcp_workspace_agent' is not available to this agent.`
|
|
48
|
+
- **Subagent Context Loss**: Subagents do **not** inherit the `gf_agent` knowledge base, parity rules, or active skills. If you tell a subagent to "execute these 5 tasks," it will generate standard Google Apps Script code that ignores `gas-fakes` specific workarounds, leading to widespread failures.
|
|
49
|
+
- **Strict Role Boundary**: Subagents are strictly for **isolated documentation retrieval** (the Service Agent Phase) via standard shell commands like `curl`. The main agent writes and runs the code.
|
|
49
50
|
|
|
50
51
|
## Safe Parallelism (Performance)
|
|
51
|
-
|
|
52
|
+
If the user asks you to run multiple tasks in parallel, DO NOT use `invoke_agent`. You must handle them directly in the main session. The orchestrator should achieve parallelism in two ways:
|
|
52
53
|
1. **Tool Call Parallelism**: The Main Agent generates multiple, parity-compliant scripts and issues them as independent, simultaneous calls to `mcp_gas-fakes-mcp_workspace_agent` within a single turn.
|
|
53
54
|
2. **Execution-Level Async**: Since `gas-fakes` runs on Node.js, the Main Agent can generate a single script that uses `Promise.all()` to execute multiple non-dependent operations (like `UrlFetchApp` calls or creating separate files) simultaneously.
|
|
54
55
|
3. **Sequence when Dependent**: Only use `wait_for_previous: true` or sequential turns when a task depends on the side-effect of a previous one (e.g., reading a sheet that was just created).
|
|
@@ -58,4 +58,5 @@ ScriptApp.__behavior.sandboxService.GmailApp.cleanup = false;
|
|
|
58
58
|
## Best Practices for `gf_agent`
|
|
59
59
|
- **Session Isolation**: When a user provides a list of files or emails, always initialize the sandbox with those specific whitelists at the top of the script.
|
|
60
60
|
- **Explicit Whitelisting**: Use `behavior.addIdWhitelist` for file access. DO NOT assume `sandboxService.SpreadsheetApp` has an `addFileWhitelist` method (it is handled globally by the behavior ID whitelist).
|
|
61
|
+
- **Cross-Platform Portability**: The `ScriptApp.__behavior` object is a `gas-fakes` exclusive feature. If the generated script is intended to be copied and run in Live Apps Script later, you MUST wrap all sandbox-related boilerplate in an `if (ScriptApp.isFake)` block to prevent `TypeError` crashes in the cloud.
|
|
61
62
|
- **Safe Execution**: In the Orchestrator Phase, identify if the task requires external access and include the necessary sandbox boilerplate in the generated script.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
### Researching Advanced Services (Google API Discovery)
|
|
2
|
+
|
|
3
|
+
Unlike the standard Apps Script Services (`SpreadsheetApp`, `DriveApp`), the signatures and payloads for **Advanced Services** (`Docs`, `Sheets`, `Drive`, etc.) are not fully documented in the `progress/` directory of the `gas-fakes` repository. Advanced Services are 1:1 mappings of the underlying Google REST APIs.
|
|
4
|
+
|
|
5
|
+
If you are orchestrating a complex task that requires an Advanced Service (such as resizing an image via `Docs.Documents.batchUpdate` or applying granular formatting via `Sheets.Spreadsheets.batchUpdate`) and you do not know the exact JSON payload structure, you MUST research it using the Google API Discovery documents.
|
|
6
|
+
|
|
7
|
+
**How to Research Advanced Services:**
|
|
8
|
+
Do not guess the payload structure. Instead, use the `run_shell_command` tool to `curl` and `grep` the official Discovery Document for the specific API version.
|
|
9
|
+
|
|
10
|
+
**Discovery Document URLs:**
|
|
11
|
+
- **Docs API v1**: `https://docs.googleapis.com/$discovery/rest?version=v1`
|
|
12
|
+
- **Sheets API v4**: `https://sheets.googleapis.com/$discovery/rest?version=v4`
|
|
13
|
+
- **Drive API v3**: `https://drive.googleapis.com/$discovery/rest?version=v3`
|
|
14
|
+
- **Slides API v1**: `https://slides.googleapis.com/$discovery/rest?version=v1`
|
|
15
|
+
- **Gmail API v1**: `https://gmail.googleapis.com/$discovery/rest?version=v1`
|
|
16
|
+
|
|
17
|
+
**Example Research Command:**
|
|
18
|
+
If you need to know how to structure an `insertInlineImage` request for the Docs API, you would run:
|
|
19
|
+
```bash
|
|
20
|
+
curl -s "https://docs.googleapis.com/$discovery/rest?version=v1" | grep -A 30 '"InsertInlineImageRequest":'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
By fetching the exact schema from the discovery document, you ensure your `batchUpdate` arrays and payload objects are 100% accurate before generating the execution script.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
### Utilities Service Constraints (API Parity)
|
|
2
|
+
|
|
3
|
+
When generating code that uses the `Utilities` service, you must adhere to the following restrictions to ensure parity with Live Apps Script:
|
|
4
|
+
|
|
5
|
+
1. **`formatString` Format Specifiers**:
|
|
6
|
+
- Live Apps Script uses Java's underlying `String.format` implementation. Therefore, it **does not** support Node.js-specific format specifiers like `%j` for JSON.
|
|
7
|
+
- You MUST stick to standard Java/C-style format specifiers: `%s` (string), `%d` / `%i` (integer), and `%f` (float).
|
|
8
|
+
- *Incorrect*: `Utilities.formatString("Data: %j", obj)`
|
|
9
|
+
- *Correct*: `Utilities.formatString("Data: %s", JSON.stringify(obj))`
|
|
10
|
+
|
|
11
|
+
2. **`parseDate` Error Handling**:
|
|
12
|
+
- If `Utilities.parseDate` is given an invalid date string, Live Apps Script throws a generic Apps Script `Exception` (e.g., `{"name":"Exception"}`) rather than a standard JavaScript `Error` object.
|
|
13
|
+
- If you are writing tests or robust `try/catch` blocks intended to run cross-platform, DO NOT assert against the exact string value of the error message (like `e.message.includes("failed")`). Simply check that an exception was thrown.
|
|
@@ -25,7 +25,6 @@ description: >
|
|
|
25
25
|
- **Remote URL**: `https://raw.githubusercontent.com/brucemcpherson/gas-fakes/main/progress/{service}.md` (Note: `{service}` is lowercase, e.g., `spreadsheet.md`).
|
|
26
26
|
- Use these details to construct precise, parity-compliant code without relying on external search engines unless documentation is missing.
|
|
27
27
|
3. **Generate Script**: Create a Node.js script that:
|
|
28
|
-
- Imports `@mcpher/gas-fakes`.
|
|
29
28
|
- Uses standard GAS syntax.
|
|
30
29
|
- (Optional) Uses `ScriptApp.isFake` for local-only logic like logging or cleanup.
|
|
31
30
|
4. **Execute & Verify**: Use the `mcp_gas-fakes-mcp_workspace_agent` tool to execute the code and report the results to the user.
|
|
@@ -39,7 +38,6 @@ Agent:
|
|
|
39
38
|
- (Optional) Fetch `progress/gmail.md` and `progress/document.md` from GitHub for detailed signatures.
|
|
40
39
|
3. **Generate Script**:
|
|
41
40
|
```javascript
|
|
42
|
-
import '@mcpher/gas-fakes';
|
|
43
41
|
const threads = GmailApp.getInboxThreads(0, 5);
|
|
44
42
|
let summary = 'Email Summary:\n\n';
|
|
45
43
|
threads.forEach(t => {
|