@google/clasp 3.0.6-alpha → 3.1.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.
Files changed (54) hide show
  1. package/README.md +35 -2
  2. package/build/src/auth/auth.js +54 -10
  3. package/build/src/auth/auth_code_flow.js +51 -0
  4. package/build/src/auth/credential_store.js +13 -0
  5. package/build/src/auth/file_credential_store.js +62 -7
  6. package/build/src/auth/localhost_auth_code_flow.js +47 -5
  7. package/build/src/auth/serverless_auth_code_flow.js +39 -2
  8. package/build/src/commands/clone-script.js +37 -5
  9. package/build/src/commands/create-deployment.js +31 -6
  10. package/build/src/commands/create-script.js +65 -24
  11. package/build/src/commands/create-version.js +21 -1
  12. package/build/src/commands/delete-deployment.js +36 -5
  13. package/build/src/commands/delete-script.js +41 -0
  14. package/build/src/commands/disable-api.js +20 -1
  15. package/build/src/commands/enable-api.js +20 -1
  16. package/build/src/commands/list-apis.js +24 -1
  17. package/build/src/commands/list-deployments.js +35 -5
  18. package/build/src/commands/list-scripts.js +26 -2
  19. package/build/src/commands/list-versions.js +35 -7
  20. package/build/src/commands/login.js +36 -10
  21. package/build/src/commands/logout.js +23 -1
  22. package/build/src/commands/open-apis.js +20 -1
  23. package/build/src/commands/open-container.js +20 -1
  24. package/build/src/commands/open-credentials.js +20 -1
  25. package/build/src/commands/open-logs.js +20 -1
  26. package/build/src/commands/open-script.js +20 -1
  27. package/build/src/commands/open-webapp.js +20 -1
  28. package/build/src/commands/program.js +48 -7
  29. package/build/src/commands/pull.js +54 -13
  30. package/build/src/commands/push.js +49 -9
  31. package/build/src/commands/run-function.js +56 -13
  32. package/build/src/commands/setup-logs.js +20 -1
  33. package/build/src/commands/show-authorized-user.js +29 -2
  34. package/build/src/commands/show-file-status.js +17 -2
  35. package/build/src/commands/start-mcp.js +17 -1
  36. package/build/src/commands/tail-logs.js +20 -5
  37. package/build/src/commands/update-deployment.js +32 -6
  38. package/build/src/commands/utils.js +68 -0
  39. package/build/src/constants.js +15 -0
  40. package/build/src/core/apis.js +13 -3
  41. package/build/src/core/clasp.js +71 -12
  42. package/build/src/core/files.js +135 -32
  43. package/build/src/core/functions.js +36 -0
  44. package/build/src/core/logs.js +29 -0
  45. package/build/src/core/manifest.js +13 -0
  46. package/build/src/core/project.js +154 -7
  47. package/build/src/core/services.js +105 -16
  48. package/build/src/core/utils.js +57 -1
  49. package/build/src/experiments.js +23 -0
  50. package/build/src/index.js +2 -0
  51. package/build/src/intl.js +28 -0
  52. package/build/src/mcp/server.js +82 -6
  53. package/docs/run.md +10 -4
  54. package/package.json +3 -3
@@ -1,3 +1,18 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'create-deployment' (alias 'deploy') command for the
15
+ // clasp CLI.
1
16
  import { Command } from 'commander';
2
17
  import { intl } from '../intl.js';
3
18
  import { withSpinner } from './utils.js';
@@ -7,25 +22,35 @@ export const command = new Command('create-deployment')
7
22
  .option('-V, --versionNumber <version>', 'The project version')
8
23
  .option('-d, --description <description>', 'The deployment description')
9
24
  .option('-i, --deploymentId <id>', 'The deployment ID to redeploy')
10
- .action(async function (options) {
11
- var _a, _b, _c;
12
- const clasp = this.opts().clasp;
25
+ .action(async function () {
26
+ var _a, _b, _c, _d, _e;
27
+ const options = this.optsWithGlobals();
28
+ const clasp = options.clasp;
13
29
  const deploymentId = options.deploymentId;
14
30
  const description = (_a = options.description) !== null && _a !== void 0 ? _a : '';
15
31
  const versionNumber = options.versionNumber ? Number(options.versionNumber) : undefined;
16
32
  try {
17
33
  const spinnerMsg = intl.formatMessage({ id: "oL8t7p", defaultMessage: [{ type: 0, value: "Deploying project..." }] });
18
34
  const deployment = await withSpinner(spinnerMsg, async () => {
19
- return await clasp.project.deploy(description, deploymentId, versionNumber);
35
+ return clasp.project.deploy(description, deploymentId, versionNumber);
20
36
  });
37
+ if (options.json) {
38
+ const output = {
39
+ deploymentId: deployment.deploymentId,
40
+ versionNumber: (_b = deployment.deploymentConfig) === null || _b === void 0 ? void 0 : _b.versionNumber,
41
+ description: (_c = deployment.deploymentConfig) === null || _c === void 0 ? void 0 : _c.description,
42
+ };
43
+ console.log(JSON.stringify(output, null, 2));
44
+ return;
45
+ }
21
46
  const successMessage = intl.formatMessage({ id: "182gSV", defaultMessage: [{ type: 0, value: "Deployed " }, { type: 1, value: "deploymentId" }, { type: 0, value: " " }, { type: 5, value: "version", options: { undefined: { value: [{ type: 0, value: "@HEAD" }] }, other: { value: [{ type: 0, value: "@" }, { type: 1, value: "version" }] } } }] }, {
22
47
  deploymentId: deployment.deploymentId,
23
- version: (_b = deployment.deploymentConfig) === null || _b === void 0 ? void 0 : _b.versionNumber,
48
+ version: (_d = deployment.deploymentConfig) === null || _d === void 0 ? void 0 : _d.versionNumber,
24
49
  });
25
50
  console.log(successMessage);
26
51
  }
27
52
  catch (error) {
28
- if (((_c = error.cause) === null || _c === void 0 ? void 0 : _c.code) === 'INVALID_ARGUMENT') {
53
+ if (((_e = error.cause) === null || _e === void 0 ? void 0 : _e.code) === 'INVALID_ARGUMENT') {
29
54
  this.error(error.cause.message);
30
55
  }
31
56
  throw error;
@@ -1,3 +1,18 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'create-script' (alias 'create') command for the clasp
15
+ // CLI.
1
16
  import path from 'node:path';
2
17
  import { Command } from 'commander';
3
18
  import inflection from 'inflection';
@@ -17,9 +32,10 @@ export const command = new Command('create-script')
17
32
  .option('--title <title>', 'The project title.')
18
33
  .option('--parentId <id>', 'A project parent Id.')
19
34
  .option('--rootDir <rootDir>', 'Local root directory in which clasp will store your project files.')
20
- .action(async function (options) {
35
+ .action(async function () {
21
36
  var _a;
22
- const clasp = this.opts().clasp;
37
+ const options = this.optsWithGlobals();
38
+ const clasp = options.clasp;
23
39
  if (clasp.project.exists()) {
24
40
  const msg = intl.formatMessage({ id: "kk5+4G", defaultMessage: [{ type: 0, value: "Project file already exists." }] });
25
41
  this.error(msg);
@@ -30,42 +46,65 @@ export const command = new Command('create-script')
30
46
  const type = options.type ? options.type.toLowerCase() : 'standalone';
31
47
  const rootDir = (_a = options.rootDir) !== null && _a !== void 0 ? _a : '.';
32
48
  clasp.withContentDir(rootDir);
49
+ let scriptId;
50
+ let createdParentId;
51
+ // Handle container-bound script creation (e.g., for Sheets, Docs, Forms, Slides).
33
52
  if (type && type !== 'standalone') {
34
- const mimeType = DRIVE_FILE_MIMETYPES[type];
53
+ const mimeType = DRIVE_FILE_MIMETYPES[type]; // Look up MIME type for the specified container type.
35
54
  if (!mimeType) {
55
+ // If the type is invalid or not supported for container-bound scripts.
36
56
  const msg = intl.formatMessage({ id: "d2MBtN", defaultMessage: [{ type: 0, value: "Invalid container file type" }] });
37
57
  this.error(msg);
38
58
  }
39
59
  const spinnerMsg = intl.formatMessage({ id: "TMfpGK", defaultMessage: [{ type: 0, value: "Creating script..." }] });
40
- const { parentId, scriptId } = await withSpinner(spinnerMsg, async () => await clasp.project.createWithContainer(name, mimeType));
41
- const parentUrl = `https://drive.google.com/open?id=${parentId}`;
42
- const scriptUrl = `https://script.google.com/d/${scriptId}/edit`;
43
- const successMessage = intl.formatMessage({ id: "yf9wXJ", defaultMessage: [{ type: 0, value: "Created new document: " }, { type: 1, value: "parentUrl" }, { type: 1, value: "br" }, { type: 0, value: "Created new script: " }, { type: 1, value: "scriptUrl" }] }, {
44
- parentUrl,
45
- scriptUrl,
46
- br: '\n',
47
- });
48
- console.log(successMessage);
60
+ // This call creates both the Google Drive file (e.g., a new Spreadsheet)
61
+ // and the Apps Script project bound to it.
62
+ const result = await withSpinner(spinnerMsg, async () => await clasp.project.createWithContainer(name, mimeType));
63
+ scriptId = result.scriptId;
64
+ createdParentId = result.parentId;
65
+ if (!options.json) {
66
+ const parentUrl = `https://drive.google.com/open?id=${createdParentId}`; // URL to the container file.
67
+ const scriptUrl = `https://script.google.com/d/${scriptId}/edit`; // URL to the new Apps Script project.
68
+ const successMessage = intl.formatMessage({ id: "yf9wXJ", defaultMessage: [{ type: 0, value: "Created new document: " }, { type: 1, value: "parentUrl" }, { type: 1, value: "br" }, { type: 0, value: "Created new script: " }, { type: 1, value: "scriptUrl" }] }, {
69
+ parentUrl,
70
+ scriptUrl,
71
+ br: '\n',
72
+ });
73
+ console.log(successMessage);
74
+ }
49
75
  }
50
76
  else {
77
+ // Handle standalone script creation.
51
78
  const spinnerMsg = intl.formatMessage({ id: "TMfpGK", defaultMessage: [{ type: 0, value: "Creating script..." }] });
52
- const scriptId = await withSpinner(spinnerMsg, async () => await clasp.project.createScript(name, parentId));
53
- const parentUrl = `https://drive.google.com/open?id=${parentId}`;
54
- const scriptUrl = `https://script.google.com/d/${scriptId}/edit`;
55
- const successMessage = intl.formatMessage({ id: "0a429S", defaultMessage: [{ type: 0, value: "Created new script: " }, { type: 1, value: "scriptUrl" }, { type: 5, value: "parentId", options: { undefined: { value: [] }, other: { value: [{ type: 1, value: "br" }, { type: 0, value: "Bound to document: " }, { type: 1, value: "parentUrl" }] } } }] }, {
56
- parentId,
57
- parentUrl,
58
- scriptUrl,
59
- br: '\n',
60
- });
61
- console.log(successMessage);
79
+ // This call creates a standalone Apps Script project.
80
+ // If `parentId` is provided, it attempts to create it within that Drive folder.
81
+ scriptId = await withSpinner(spinnerMsg, async () => await clasp.project.createScript(name, parentId));
82
+ if (!options.json) {
83
+ const parentUrl = `https://drive.google.com/open?id=${parentId}`; // URL to parent folder if specified.
84
+ const scriptUrl = `https://script.google.com/d/${scriptId}/edit`; // URL to the new Apps Script project.
85
+ const successMessage = intl.formatMessage({ id: "0a429S", defaultMessage: [{ type: 0, value: "Created new script: " }, { type: 1, value: "scriptUrl" }, { type: 5, value: "parentId", options: { undefined: { value: [] }, other: { value: [{ type: 1, value: "br" }, { type: 0, value: "Bound to document: " }, { type: 1, value: "parentUrl" }] } } }] }, {
86
+ parentId,
87
+ parentUrl,
88
+ scriptUrl,
89
+ br: '\n',
90
+ });
91
+ console.log(successMessage);
92
+ }
62
93
  }
63
94
  const spinnerMsg = intl.formatMessage({ id: "UTMHnH", defaultMessage: [{ type: 0, value: "Cloning script..." }] });
95
+ // After creating the script (either standalone or container-bound),
96
+ // pull its initial files (e.g., Code.gs, appsscript.json) to the local directory.
64
97
  const files = await withSpinner(spinnerMsg, async () => {
65
98
  const files = await clasp.files.pull();
99
+ // Update the local .clasp.json with the new scriptId and other settings.
66
100
  clasp.project.updateSettings();
67
101
  return files;
68
102
  });
103
+ if (options.json) {
104
+ console.log(JSON.stringify({ scriptId, parentId: createdParentId, files: files.map(f => f.localPath) }, null, 2));
105
+ return;
106
+ }
107
+ // Log the paths of the pulled files.
69
108
  files.forEach(f => console.log(`└─ ${f.localPath}`));
70
109
  const successMessage = intl.formatMessage({ id: "XABSyD", defaultMessage: [{ type: 0, value: "Cloned " }, { type: 6, value: "count", options: { "=0": { value: [{ type: 0, value: "no files." }] }, one: { value: [{ type: 0, value: "one file." }] }, other: { value: [{ type: 7 }, { type: 0, value: " files" }] } }, offset: 0, pluralType: "cardinal" }, { type: 0, value: "." }] }, {
71
110
  count: files.length,
@@ -73,8 +112,10 @@ export const command = new Command('create-script')
73
112
  console.log(successMessage);
74
113
  });
75
114
  /**
76
- * Gets default project name.
77
- * @return {string} default project name.
115
+ * Generates a default project name based on the current directory's basename.
116
+ * It humanizes the directory name (e.g., 'my-project-folder' becomes 'My project folder').
117
+ * @param {string} dir - The directory path from which to derive the project name.
118
+ * @returns {string} The humanized default project name.
78
119
  */
79
120
  export function getDefaultProjectName(dir) {
80
121
  const dirName = path.basename(dir);
@@ -1,3 +1,18 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'create-version' (alias 'version') command for the
15
+ // clasp CLI.
1
16
  import { Command } from 'commander';
2
17
  import inquirer from 'inquirer';
3
18
  import { intl } from '../intl.js';
@@ -7,7 +22,8 @@ export const command = new Command('create-version')
7
22
  .arguments('[description]')
8
23
  .description('Creates an immutable version of the script')
9
24
  .action(async function (description) {
10
- const clasp = this.opts().clasp;
25
+ const options = this.optsWithGlobals();
26
+ const clasp = options.clasp;
11
27
  if (!description && isInteractive()) {
12
28
  const prompt = intl.formatMessage({ id: "6U9ksF", defaultMessage: [{ type: 0, value: "Give a description:" }] });
13
29
  const answer = await inquirer.prompt([
@@ -24,6 +40,10 @@ export const command = new Command('create-version')
24
40
  const versionNumber = await withSpinner(spinnerMsg, async () => {
25
41
  return clasp.project.version(description);
26
42
  });
43
+ if (options.json) {
44
+ console.log(JSON.stringify({ versionNumber }, null, 2));
45
+ return;
46
+ }
27
47
  const successMessage = intl.formatMessage({ id: "TVOEZz", defaultMessage: [{ type: 0, value: "Created version " }, { type: 2, value: "version", style: null }] }, {
28
48
  version: versionNumber,
29
49
  });
@@ -1,3 +1,18 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'delete-deployment' (alias 'undeploy') command for
15
+ // the clasp CLI.
1
16
  import { Command } from 'commander';
2
17
  import inquirer from 'inquirer';
3
18
  import { intl } from '../intl.js';
@@ -7,17 +22,22 @@ export const command = new Command('delete-deployment')
7
22
  .description('Delete a deployment of a project')
8
23
  .arguments('[deploymentId]')
9
24
  .option('-a, --all', 'Undeploy all deployments')
10
- .action(async function (deploymentId, options) {
25
+ .action(async function (deploymentId) {
11
26
  var _a;
12
- const clasp = this.opts().clasp;
27
+ const options = this.optsWithGlobals();
28
+ const clasp = options.clasp;
13
29
  const removeAll = options.all;
30
+ const deletedDeploymentIds = [];
14
31
  const deleteDeployment = async (id) => {
15
32
  const spinnerMsg = intl.formatMessage({ id: "d6mKEK", defaultMessage: [{ type: 0, value: "Deleting deployment..." }] });
16
33
  await withSpinner(spinnerMsg, async () => {
17
- return await clasp.project.undeploy(id);
34
+ return clasp.project.undeploy(id);
18
35
  });
19
- const successMessage = intl.formatMessage({ id: "GbtFER", defaultMessage: [{ type: 0, value: "Deleted deployment " }, { type: 1, value: "id" }] }, { id });
20
- console.log(successMessage);
36
+ deletedDeploymentIds.push(id);
37
+ if (!options.json) {
38
+ const successMessage = intl.formatMessage({ id: "GbtFER", defaultMessage: [{ type: 0, value: "Deleted deployment " }, { type: 1, value: "id" }] }, { id });
39
+ console.log(successMessage);
40
+ }
21
41
  };
22
42
  if (removeAll) {
23
43
  const spinnerMsg = intl.formatMessage({ id: "baVdkq", defaultMessage: [{ type: 0, value: "Fetching deployments..." }] });
@@ -32,6 +52,10 @@ export const command = new Command('delete-deployment')
32
52
  }
33
53
  await deleteDeployment(id);
34
54
  }
55
+ if (options.json) {
56
+ console.log(JSON.stringify({ deletedDeploymentIds }, null, 2));
57
+ return;
58
+ }
35
59
  const successMessage = intl.formatMessage({ id: "cE8hF0", defaultMessage: [{ type: 0, value: "Deleted all deployments." }] });
36
60
  console.log(successMessage);
37
61
  return;
@@ -64,8 +88,15 @@ export const command = new Command('delete-deployment')
64
88
  }
65
89
  }
66
90
  if (!deploymentId) {
91
+ if (options.json) {
92
+ console.log(JSON.stringify({ deletedDeploymentIds: [] }, null, 2));
93
+ return;
94
+ }
67
95
  const msg = intl.formatMessage({ id: "UufukD", defaultMessage: [{ type: 0, value: "No deployments found." }] });
68
96
  this.error(msg);
69
97
  }
70
98
  await deleteDeployment(deploymentId);
99
+ if (options.json) {
100
+ console.log(JSON.stringify({ deletedDeploymentIds }, null, 2));
101
+ }
71
102
  });
@@ -0,0 +1,41 @@
1
+ import { Command } from 'commander';
2
+ import inquirer from 'inquirer';
3
+ import { intl } from '../intl.js';
4
+ import { isInteractive, withSpinner } from './utils.js';
5
+ export const command = new Command('delete-script')
6
+ .alias('delete')
7
+ .description('Delete a project')
8
+ .argument('[scriptId]', 'Apps Script ID to list deployments for')
9
+ .option('-f, --force', "Bypass any confirmation messages. It's not a good idea to do this unless you want to run clasp from a script.")
10
+ .action(async function (scriptId) {
11
+ const options = this.optsWithGlobals();
12
+ const clasp = options.clasp;
13
+ if (scriptId) {
14
+ clasp.withScriptId(scriptId);
15
+ }
16
+ if (!clasp.project.scriptId) {
17
+ const msg = intl.formatMessage({ id: "6dAsTC", defaultMessage: [{ type: 0, value: "Script ID not set, unable to delete the script." }] });
18
+ this.error(msg);
19
+ }
20
+ //ask confirmation
21
+ let confirmed = options.force || false;
22
+ if (!confirmed && isInteractive()) {
23
+ const promptDeleteDriveFiles = intl.formatMessage({ id: "DKO5+J", defaultMessage: [{ type: 0, value: "Are you sure you want to delete the script?" }] });
24
+ const answerDeleteDriveFiles = await inquirer.prompt([
25
+ {
26
+ default: false,
27
+ message: promptDeleteDriveFiles,
28
+ name: 'answer',
29
+ type: 'confirm',
30
+ },
31
+ ]);
32
+ confirmed = answerDeleteDriveFiles.answer;
33
+ }
34
+ if (!confirmed) {
35
+ return;
36
+ }
37
+ const spinnerMsg = intl.formatMessage({ id: "lRbOjS", defaultMessage: [{ type: 0, value: "Deleting your scripts..." }] });
38
+ await withSpinner(spinnerMsg, async () => await clasp.project.trashScript());
39
+ const successMessage = intl.formatMessage({ id: "zDXU5q", defaultMessage: [{ type: 0, value: "Deleted script " }, { type: 1, value: "scriptId" }] }, { scriptId: clasp.project.scriptId });
40
+ console.log(successMessage);
41
+ });
@@ -1,3 +1,17 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'disable-api' command for the clasp CLI.
1
15
  import { Command } from 'commander';
2
16
  import { intl } from '../intl.js';
3
17
  import { assertGcpProjectConfigured, maybePromptForProjectId, withSpinner } from './utils.js';
@@ -5,13 +19,18 @@ export const command = new Command('disable-api')
5
19
  .description('Disable a service for the current project.')
6
20
  .argument('<api>', 'Service to disable')
7
21
  .action(async function (serviceName) {
8
- const clasp = this.opts().clasp;
22
+ const options = this.optsWithGlobals();
23
+ const clasp = options.clasp;
9
24
  await maybePromptForProjectId(clasp);
10
25
  assertGcpProjectConfigured(clasp);
11
26
  const spinnerMsg = intl.formatMessage({ id: "awbyYM", defaultMessage: [{ type: 0, value: "Disabling service..." }] });
12
27
  await withSpinner(spinnerMsg, async () => {
13
28
  await clasp.services.disableService(serviceName);
14
29
  });
30
+ if (options.json) {
31
+ console.log(JSON.stringify({ success: true, disabledService: serviceName }, null, 2));
32
+ return;
33
+ }
15
34
  const successMessage = intl.formatMessage({ id: "tjmJ+e", defaultMessage: [{ type: 0, value: "Disabled " }, { type: 1, value: "name" }, { type: 0, value: " API." }] }, {
16
35
  name: serviceName,
17
36
  });
@@ -1,3 +1,17 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'enable-api' command for the clasp CLI.
1
15
  import { Command } from 'commander';
2
16
  import { intl } from '../intl.js';
3
17
  import { assertGcpProjectConfigured, maybePromptForProjectId, withSpinner } from './utils.js';
@@ -6,7 +20,8 @@ export const command = new Command('enable-api')
6
20
  .argument('<api>', 'Service to enable')
7
21
  .action(async function (serviceName) {
8
22
  var _a;
9
- const clasp = this.opts().clasp;
23
+ const options = this.optsWithGlobals();
24
+ const clasp = options.clasp;
10
25
  await maybePromptForProjectId(clasp);
11
26
  assertGcpProjectConfigured(clasp);
12
27
  try {
@@ -24,6 +39,10 @@ export const command = new Command('enable-api')
24
39
  }
25
40
  throw error;
26
41
  }
42
+ if (options.json) {
43
+ console.log(JSON.stringify({ success: true }, null, 2));
44
+ return;
45
+ }
27
46
  const successMessage = intl.formatMessage({ id: "6lXgOl", defaultMessage: [{ type: 0, value: "Enabled " }, { type: 1, value: "name" }, { type: 0, value: " API." }] }, {
28
47
  name: serviceName,
29
48
  });
@@ -1,3 +1,17 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'list-apis' (alias 'apis') command for the clasp CLI.
1
15
  import { Command } from 'commander';
2
16
  import { intl } from '../intl.js';
3
17
  import { assertGcpProjectConfigured, maybePromptForProjectId, withSpinner } from './utils.js';
@@ -5,11 +19,20 @@ export const command = new Command('list-apis')
5
19
  .alias('apis')
6
20
  .description('List enabled APIs for the current project')
7
21
  .action(async function () {
8
- const clasp = this.opts().clasp;
22
+ const options = this.optsWithGlobals();
23
+ const clasp = options.clasp;
9
24
  await maybePromptForProjectId(clasp);
10
25
  assertGcpProjectConfigured(clasp);
11
26
  const spinnerMsg = intl.formatMessage({ id: "aY+ZR2", defaultMessage: [{ type: 0, value: "Fetching APIs..." }] });
12
27
  const [enabledApis, availableApis] = await withSpinner(spinnerMsg, () => Promise.all([clasp.services.getEnabledServices(), clasp.services.getAvailableServices()]));
28
+ if (options.json) {
29
+ const output = {
30
+ enabledApis: enabledApis.map(api => ({ name: api.name, description: api.description })),
31
+ availableApis: availableApis.map(api => ({ name: api.name, description: api.description })),
32
+ };
33
+ console.log(JSON.stringify(output, null, 2));
34
+ return;
35
+ }
13
36
  const enabledApisLabel = intl.formatMessage({ id: "QfnjZ4", defaultMessage: [{ type: 0, value: "# Currently enabled APIs:" }] });
14
37
  console.log(`\n${enabledApisLabel}`);
15
38
  for (const service of enabledApis) {
@@ -1,15 +1,45 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'list-deployments' (alias 'deployments') command for
15
+ // the clasp CLI.
1
16
  import { Command } from 'commander';
2
17
  import { intl } from '../intl.js';
3
18
  import { withSpinner } from './utils.js';
4
19
  export const command = new Command('list-deployments')
5
20
  .alias('deployments')
6
21
  .description('List deployment ids of a script')
7
- .action(async function () {
8
- const clasp = this.opts().clasp;
22
+ .argument('[scriptId]', 'Apps Script ID to list deployments for')
23
+ .action(async function (scriptId) {
24
+ const options = this.optsWithGlobals();
25
+ const clasp = options.clasp;
26
+ if (scriptId) {
27
+ clasp.withScriptId(scriptId);
28
+ }
9
29
  const spinnerMsg = intl.formatMessage({ id: "baVdkq", defaultMessage: [{ type: 0, value: "Fetching deployments..." }] });
10
- const deployments = await withSpinner(spinnerMsg, async () => {
11
- return await clasp.project.listDeployments();
12
- });
30
+ const deployments = await withSpinner(spinnerMsg, () => clasp.project.listDeployments());
31
+ if (options.json) {
32
+ const deploymentOutput = deployments.results.map(deployment => {
33
+ var _a, _b;
34
+ return ({
35
+ deploymentId: deployment.deploymentId,
36
+ versionNumber: (_a = deployment.deploymentConfig) === null || _a === void 0 ? void 0 : _a.versionNumber,
37
+ description: (_b = deployment.deploymentConfig) === null || _b === void 0 ? void 0 : _b.description,
38
+ });
39
+ });
40
+ console.log(JSON.stringify(deploymentOutput, null, 2));
41
+ return;
42
+ }
13
43
  if (!deployments.results.length) {
14
44
  const msg = intl.formatMessage({ id: "q2/XsW", defaultMessage: [{ type: 0, value: "No deployments." }] });
15
45
  console.log(msg);
@@ -1,3 +1,18 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'list-scripts' (alias 'list') command for the clasp
15
+ // CLI.
1
16
  import { Command } from 'commander';
2
17
  import { intl } from '../intl.js';
3
18
  import { ellipsize, withSpinner } from './utils.js';
@@ -5,12 +20,21 @@ export const command = new Command('list-scripts')
5
20
  .alias('list')
6
21
  .description('List App Scripts projects')
7
22
  .option('--noShorten', 'Do not shorten long names', false)
8
- .action(async function (options) {
9
- const clasp = this.opts().clasp;
23
+ .action(async function () {
24
+ const options = this.optsWithGlobals();
25
+ const clasp = options.clasp;
10
26
  const spinnerMsg = intl.formatMessage({ id: "x0awdZ", defaultMessage: [{ type: 0, value: "Finding your scripts..." }] });
11
27
  const files = await withSpinner(spinnerMsg, async () => {
12
28
  return clasp.project.listScripts();
13
29
  });
30
+ if (options.json) {
31
+ const scripts = files.results.map(file => ({
32
+ id: file.id,
33
+ name: file.name,
34
+ }));
35
+ console.log(JSON.stringify(scripts, null, 2));
36
+ return;
37
+ }
14
38
  if (!files.results.length) {
15
39
  const msg = intl.formatMessage({ id: "rPMgOk", defaultMessage: [{ type: 0, value: "No script files found." }] });
16
40
  console.log(msg);
@@ -1,18 +1,46 @@
1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ // This file defines the 'list-versions' (alias 'versions') command for the
15
+ // clasp CLI.
1
16
  import { Command } from 'commander';
2
17
  import { intl } from '../intl.js';
3
18
  import { withSpinner } from './utils.js';
4
19
  export const command = new Command('list-versions')
5
20
  .alias('versions')
6
21
  .description('List versions of a script')
7
- .action(async function () {
8
- const clasp = this.opts().clasp;
22
+ .argument('[scriptId]', 'Apps Script ID to list deployments for')
23
+ .action(async function (scriptId) {
24
+ var _a;
25
+ const options = this.optsWithGlobals();
26
+ const clasp = options.clasp;
27
+ if (scriptId) {
28
+ clasp.withScriptId(scriptId);
29
+ }
9
30
  const spinnerMsg = intl.formatMessage({ id: "Cqxqh0", defaultMessage: [{ type: 0, value: "Fetching versions..." }] });
10
- const versions = await withSpinner(spinnerMsg, async () => {
11
- return await clasp.project.listVersions();
12
- });
13
- if (versions.results.length === 0) {
31
+ const versions = await withSpinner(spinnerMsg, () => clasp.project.listVersions());
32
+ if (options.json) {
33
+ const versionOutput = versions.results.map(version => ({
34
+ versionNumber: version.versionNumber,
35
+ description: version.description,
36
+ }));
37
+ console.log(JSON.stringify(versionOutput, null, 2));
38
+ return;
39
+ }
40
+ if (!((_a = versions.results) === null || _a === void 0 ? void 0 : _a.length)) {
14
41
  const msg = intl.formatMessage({ id: "Jmvq7L", defaultMessage: [{ type: 0, value: "No deployed versions of script." }] });
15
- this.error(msg);
42
+ console.log(msg);
43
+ return;
16
44
  }
17
45
  const successMessage = intl.formatMessage({ id: "6CS9SE", defaultMessage: [{ type: 0, value: "Found " }, { type: 6, value: "count", options: { one: { value: [{ type: 7 }, { type: 0, value: " version" }] }, other: { value: [{ type: 7 }, { type: 0, value: " versions" }] } }, offset: 0, pluralType: "cardinal" }, { type: 0, value: "." }] }, {
18
46
  count: versions.results.length,