@mcpher/gas-fakes 1.2.8 → 1.2.9
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/gas-fakes.js +108 -22
- package/gasfakes.json +8 -0
- package/package.json +4 -2
package/gas-fakes.js
CHANGED
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* cli for gas-fakes
|
|
5
|
-
* v0.0.1
|
|
6
5
|
*/
|
|
7
6
|
import fs from "fs";
|
|
8
7
|
import path from "path";
|
|
9
8
|
import { Command } from "commander";
|
|
10
|
-
import dotenv from
|
|
9
|
+
import dotenv from "dotenv";
|
|
10
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
|
+
import z from "zod";
|
|
13
|
+
import { exec } from "child_process";
|
|
14
|
+
import { promisify } from "util";
|
|
11
15
|
|
|
12
|
-
const version = "0.0.
|
|
16
|
+
const version = "0.0.3";
|
|
13
17
|
|
|
14
18
|
const program = new Command();
|
|
15
19
|
|
|
@@ -18,7 +22,6 @@ program
|
|
|
18
22
|
.description("CLI tool for gas-fakes")
|
|
19
23
|
.version(version, "-v, --version", "display the current version");
|
|
20
24
|
|
|
21
|
-
|
|
22
25
|
program
|
|
23
26
|
.description("Execute Google Apps Script using gas-fakes.")
|
|
24
27
|
.option(
|
|
@@ -57,9 +60,19 @@ program
|
|
|
57
60
|
if (Object.keys(options).length == 0) {
|
|
58
61
|
program.help();
|
|
59
62
|
} else {
|
|
60
|
-
const {
|
|
63
|
+
const {
|
|
64
|
+
filename,
|
|
65
|
+
script,
|
|
66
|
+
sandbox,
|
|
67
|
+
whitelist,
|
|
68
|
+
json,
|
|
69
|
+
display,
|
|
70
|
+
env,
|
|
71
|
+
gfsettings,
|
|
72
|
+
} = options;
|
|
61
73
|
const obj = { sandbox: !!sandbox, display };
|
|
62
|
-
|
|
74
|
+
|
|
75
|
+
if (!filename && !script && !obj.script) {
|
|
63
76
|
console.error(
|
|
64
77
|
"error: Provide the filename or the script of Google Apps Script."
|
|
65
78
|
);
|
|
@@ -67,24 +80,24 @@ program
|
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
if (env) {
|
|
70
|
-
const envPath = path.resolve(process.cwd(), env)
|
|
71
|
-
console.log
|
|
72
|
-
dotenv.config({ path: envPath, quiet: true});
|
|
83
|
+
const envPath = path.resolve(process.cwd(), env);
|
|
84
|
+
console.log("...using env file in", envPath);
|
|
85
|
+
dotenv.config({ path: envPath, quiet: true });
|
|
73
86
|
}
|
|
74
87
|
|
|
75
88
|
// note this must come after any env file fiddling.
|
|
76
89
|
if (gfsettings) {
|
|
77
|
-
const gfPath = path.resolve(process.cwd(), gfsettings
|
|
78
|
-
console.log
|
|
90
|
+
const gfPath = path.resolve(process.cwd(), gfsettings);
|
|
91
|
+
console.log("...using gasfakes settings file in", gfPath);
|
|
79
92
|
obj.gfSettings = gfPath;
|
|
80
93
|
// override whatever is in env
|
|
81
|
-
process.env.GF_SETTINGS_PATH = gfPath
|
|
94
|
+
process.env.GF_SETTINGS_PATH = gfPath;
|
|
82
95
|
}
|
|
83
96
|
|
|
84
97
|
if (filename) {
|
|
85
98
|
obj.filename = filename;
|
|
86
99
|
}
|
|
87
|
-
if (script) {
|
|
100
|
+
if (!obj.script && script) {
|
|
88
101
|
obj.script = script;
|
|
89
102
|
}
|
|
90
103
|
|
|
@@ -108,15 +121,22 @@ program
|
|
|
108
121
|
}
|
|
109
122
|
});
|
|
110
123
|
|
|
124
|
+
const execAsync = promisify(exec);
|
|
125
|
+
program
|
|
126
|
+
.command("mcp")
|
|
127
|
+
.description("Launch gas-fakes as the MCP server")
|
|
128
|
+
.action(mcp_server);
|
|
129
|
+
|
|
111
130
|
program.showHelpAfterError("(add --help for additional information)");
|
|
112
131
|
program.parse();
|
|
113
132
|
|
|
114
133
|
function __getImportScript(o) {
|
|
115
|
-
const { scriptText, sandbox, whitelistItems, json_sandbox
|
|
134
|
+
const { scriptText, sandbox, whitelistItems, json_sandbox } = o;
|
|
116
135
|
if (scriptText.trim() == "") {
|
|
117
136
|
console.error("error: Google Apps Script was not found.");
|
|
118
137
|
process.exit();
|
|
119
138
|
}
|
|
139
|
+
let gasScriptStr = "";
|
|
120
140
|
const gasScriptAr = [];
|
|
121
141
|
if (json_sandbox) {
|
|
122
142
|
gasScriptAr.push(
|
|
@@ -179,8 +199,7 @@ function __getImportScript(o) {
|
|
|
179
199
|
`const behavior = ScriptApp.__behavior;`,
|
|
180
200
|
`behavior.sandboxMode = true;`,
|
|
181
201
|
`behavior.strictSandbox = true;`,
|
|
182
|
-
`behavior.setIdWhitelist([${wl}])
|
|
183
|
-
`\n\n${scriptText}\n\n`,
|
|
202
|
+
`behavior.setIdWhitelist([${wl}]);``\n\n${scriptText}\n\n`,
|
|
184
203
|
`ScriptApp.__behavior.trash();`
|
|
185
204
|
);
|
|
186
205
|
} else {
|
|
@@ -202,15 +221,14 @@ function __getImportScript(o) {
|
|
|
202
221
|
}
|
|
203
222
|
|
|
204
223
|
async function loadScript(o) {
|
|
205
|
-
|
|
206
224
|
const { filename, script, display } = o;
|
|
207
|
-
|
|
208
225
|
const scriptText = filename ? fs.readFileSync(filename, "utf8") : script;
|
|
209
|
-
const { mainScript, gasScript } = __getImportScript({
|
|
226
|
+
const { mainScript, gasScript } = __getImportScript({
|
|
227
|
+
scriptText: scriptText.replace(/\\n/g, "\n"),
|
|
228
|
+
...o,
|
|
229
|
+
});
|
|
210
230
|
if (display) {
|
|
211
|
-
console.log(
|
|
212
|
-
console.log(gasScript);
|
|
213
|
-
console.log(`--- /script ---`);
|
|
231
|
+
console.log(`\n--- script ---\n${gasScript}\n--- /script ---\n`);
|
|
214
232
|
}
|
|
215
233
|
const gasFunc = new Function(mainScript);
|
|
216
234
|
// The script needs access to the settings path variable we just created
|
|
@@ -221,3 +239,71 @@ async function loadScript(o) {
|
|
|
221
239
|
});
|
|
222
240
|
gasFunc();
|
|
223
241
|
}
|
|
242
|
+
|
|
243
|
+
async function mcp_server() {
|
|
244
|
+
const server = new McpServer({
|
|
245
|
+
name: "gas-fakes-mcp",
|
|
246
|
+
version: "0.0.1",
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const { name, schema, func } = {
|
|
250
|
+
name: "run-gas-by-gas-fakes",
|
|
251
|
+
schema: {
|
|
252
|
+
description:
|
|
253
|
+
"Use this to safely run Google Apps Script in a sandbox using gas-fakes.",
|
|
254
|
+
inputSchema: {
|
|
255
|
+
script: z.string().describe(`Provide Google Apps Script as a string.`),
|
|
256
|
+
sandbox: z
|
|
257
|
+
.boolean()
|
|
258
|
+
.describe("Use to run Google Apps Script in a sandbox."),
|
|
259
|
+
whitelist: z
|
|
260
|
+
.string()
|
|
261
|
+
.describe(
|
|
262
|
+
"Use this to use the specific files and folders on Google Drive. whitelist of file IDs. Set the file IDs in comma-separated list. In this case, the files of the file IDs are used for both read and write. When this is used, the script is run in a sandbox."
|
|
263
|
+
)
|
|
264
|
+
.optional(),
|
|
265
|
+
json: z
|
|
266
|
+
.string()
|
|
267
|
+
.describe(
|
|
268
|
+
`Use this to manage the sandbox more if the detailed information about the sandbox is provided. JSON string including parameters for managing a sandbox. Enclose it with ' or ". When this is used, the option "whitelist" is ignored. When this is used, the script is run in a sandbox.`
|
|
269
|
+
)
|
|
270
|
+
.optional(),
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
func: async (options = {}) => {
|
|
274
|
+
const { sandbox, whitelist, json } = options;
|
|
275
|
+
try {
|
|
276
|
+
const opts = [
|
|
277
|
+
{ v: sandbox, k: "-x" },
|
|
278
|
+
{ v: whitelist, k: "-w" },
|
|
279
|
+
{ v: json, k: "-j" },
|
|
280
|
+
].reduce((ar, { v, k }) => {
|
|
281
|
+
if (v) {
|
|
282
|
+
ar.push(k != "-x" ? `${k} ${v}` : `${k}`);
|
|
283
|
+
}
|
|
284
|
+
return ar;
|
|
285
|
+
}, []);
|
|
286
|
+
const scriptArg = JSON.stringify(options.script.toString());
|
|
287
|
+
const c = `gas-fakes ${opts.join(" ")} -s ${scriptArg.replace(
|
|
288
|
+
/\\n/g,
|
|
289
|
+
"\n"
|
|
290
|
+
)}`;
|
|
291
|
+
const { stdout } = await execAsync(c);
|
|
292
|
+
return {
|
|
293
|
+
content: [{ type: "text", text: stdout || "Done." }],
|
|
294
|
+
isError: false,
|
|
295
|
+
};
|
|
296
|
+
} catch (err) {
|
|
297
|
+
return {
|
|
298
|
+
content: [{ type: "text", text: err.message }],
|
|
299
|
+
isError: true,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
server.registerTool(name, schema, func);
|
|
306
|
+
|
|
307
|
+
const transport = new StdioServerTransport();
|
|
308
|
+
await server.connect(transport);
|
|
309
|
+
}
|
package/gasfakes.json
ADDED
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@mcpher/fake-gasenum": "^1.0.2",
|
|
7
7
|
"@mcpher/gas-flex-cache": "^1.1.2",
|
|
8
|
+
"@modelcontextprotocol/sdk": "^1.20.2",
|
|
8
9
|
"@sindresorhus/is": "^7.0.1",
|
|
9
10
|
"archiver": "^7.0.1",
|
|
10
11
|
"commander": "^14.0.1",
|
|
@@ -24,7 +25,8 @@
|
|
|
24
25
|
"subsume": "^4.0.0",
|
|
25
26
|
"to-readable-stream": "^4.0.0",
|
|
26
27
|
"unzipper": "^0.12.3",
|
|
27
|
-
"yoctocolors": "^2.1.2"
|
|
28
|
+
"yoctocolors": "^2.1.2",
|
|
29
|
+
"zod": "^3.25.76"
|
|
28
30
|
},
|
|
29
31
|
"type": "module",
|
|
30
32
|
"scripts": {
|
|
@@ -32,7 +34,7 @@
|
|
|
32
34
|
},
|
|
33
35
|
"name": "@mcpher/gas-fakes",
|
|
34
36
|
"author": "bruce mcpherson",
|
|
35
|
-
"version": "1.2.
|
|
37
|
+
"version": "1.2.9",
|
|
36
38
|
"license": "MIT",
|
|
37
39
|
"main": "main.js",
|
|
38
40
|
"description": "A proof of concept implementation of Apps Script Environment on Node",
|