@gscdump/cli 3.7.0 → 4.0.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 +113 -30
- package/bin/gscdump.mjs +21 -1
- package/dist/analysis-local.mjs +172 -53
- package/dist/auth-state.mjs +21 -6
- package/dist/auth.mjs +27 -18
- package/dist/bing-data.mjs +6 -2
- package/dist/bing-hosted.mjs +1 -1
- package/dist/cli-args.mjs +8 -0
- package/dist/cli.d.mts +5 -1
- package/dist/cli.mjs +41 -10
- package/dist/cloud-google.mjs +8 -1
- package/dist/command-meta.mjs +4 -4
- package/dist/command-registry.mjs +86 -10
- package/dist/commands/analyze.mjs +84 -43
- package/dist/commands/auth.mjs +46 -37
- package/dist/commands/bing.mjs +3 -3
- package/dist/commands/compact.mjs +12 -8
- package/dist/commands/config.mjs +14 -14
- package/dist/commands/doctor.mjs +26 -26
- package/dist/commands/dump.mjs +203 -105
- package/dist/commands/entities.mjs +10 -113
- package/dist/commands/gc.mjs +4 -3
- package/dist/commands/indexing-urls.mjs +185 -0
- package/dist/commands/indexing.mjs +12 -8
- package/dist/commands/init.mjs +77 -18
- package/dist/commands/inspect.mjs +97 -110
- package/dist/commands/mcp.mjs +37 -57
- package/dist/commands/papercut.mjs +1 -1
- package/dist/commands/profile.mjs +9 -17
- package/dist/commands/query.mjs +219 -210
- package/dist/commands/report.mjs +68 -85
- package/dist/commands/rollups.mjs +9 -6
- package/dist/commands/sitemaps.mjs +51 -104
- package/dist/commands/sites.mjs +40 -24
- package/dist/commands/stats.mjs +14 -17
- package/dist/commands/store-purge.mjs +9 -5
- package/dist/commands/store.mjs +0 -12
- package/dist/commands/sync.mjs +774 -296
- package/dist/config.mjs +7 -4
- package/dist/context.mjs +51 -21
- package/dist/coverage.mjs +251 -0
- package/dist/dump-bing.mjs +71 -0
- package/dist/dump-writers.mjs +246 -0
- package/dist/error-handler.mjs +108 -38
- package/dist/filters.mjs +125 -0
- package/dist/hosted-site.mjs +91 -0
- package/dist/inspect-urls.mjs +76 -0
- package/dist/inspection-record.mjs +93 -0
- package/dist/local-entities.mjs +658 -0
- package/dist/mcp/errors.mjs +71 -18
- package/dist/mcp/handlers/diagnostics.mjs +15 -12
- package/dist/mcp/handlers/reports.mjs +33 -42
- package/dist/mcp/server/index.mjs +80 -38
- package/dist/mcp/types.mjs +7 -7
- package/dist/package.mjs +1 -1
- package/dist/quota-ledger.mjs +370 -0
- package/dist/render/analysis.mjs +8 -1
- package/dist/render/report.mjs +8 -1
- package/dist/request-pacer.mjs +29 -0
- package/dist/route.mjs +295 -0
- package/dist/sitemap.mjs +4 -0
- package/dist/sql-views.mjs +117 -0
- package/dist/store-sites.mjs +134 -0
- package/dist/sync-plan.mjs +129 -0
- package/dist/sync-run.mjs +96 -0
- package/dist/table-sources.mjs +57 -0
- package/dist/token-info.mjs +54 -0
- package/dist/utils.mjs +28 -19
- package/dist/window.mjs +159 -0
- package/package.json +17 -14
- package/skills/gscdump/SKILL.md +167 -37
- package/dist/commands/export.mjs +0 -76
- package/dist/native-duckdb.mjs +0 -46
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { inspectCommandMeta } from "../command-meta.mjs";
|
|
2
|
-
import { OUTPUT_ARGS, applyOutputMode,
|
|
2
|
+
import { OUTPUT_ARGS, applyOutputMode, dim, logger, readUrlList, red } from "../utils.mjs";
|
|
3
|
+
import { formatSiteIdCollision, recordStoreSite } from "../store-sites.mjs";
|
|
3
4
|
import { createCommandContext } from "../context.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { toInspectionRecord } from "../inspection-record.mjs";
|
|
6
|
+
import { appendInspections, loadInspectionState, materializeInspectionIndex, urlInProperty } from "../local-entities.mjs";
|
|
7
|
+
import { checkInspectionBatch, inspectUrls } from "../inspect-urls.mjs";
|
|
7
8
|
import { defineCommand } from "citty";
|
|
8
|
-
import { batchInspectUrls } from "gscdump/indexing";
|
|
9
9
|
function verdictTone(verdict) {
|
|
10
10
|
if (verdict === "PASS") return "\x1B[32m";
|
|
11
11
|
if (verdict === "NEUTRAL" || verdict === "PARTIAL") return "\x1B[33m";
|
|
@@ -76,126 +76,113 @@ function printInspection(url, inspection) {
|
|
|
76
76
|
}
|
|
77
77
|
console.log();
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
function outcomeJson(outcome) {
|
|
80
|
+
if (outcome.kind === "failed") return {
|
|
81
|
+
url: outcome.url,
|
|
82
|
+
status: "failed",
|
|
83
|
+
error: outcome.error
|
|
84
|
+
};
|
|
85
|
+
const indexStatus = outcome.result?.indexStatusResult;
|
|
86
|
+
return {
|
|
87
|
+
url: outcome.url,
|
|
88
|
+
status: "inspected",
|
|
89
|
+
verdict: indexStatus?.verdict ?? null,
|
|
90
|
+
coverageState: indexStatus?.coverageState ?? null,
|
|
91
|
+
indexingState: indexStatus?.indexingState ?? null,
|
|
92
|
+
lastCrawlTime: indexStatus?.lastCrawlTime ?? null,
|
|
93
|
+
isIndexed: indexStatus?.verdict === "PASS",
|
|
94
|
+
raw: outcome.result ?? null
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function printOutcomeLine(outcome) {
|
|
98
|
+
if (outcome.kind === "failed") {
|
|
99
|
+
console.log(` ${red("ERROR")} ${outcome.url} ${dim(outcome.error)}`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const indexStatus = outcome.result?.indexStatusResult;
|
|
103
|
+
console.log(` ${colorVerdict(indexStatus?.verdict)} ${outcome.url} ${dim(indexStatus?.coverageState ?? "")}`);
|
|
104
|
+
}
|
|
105
|
+
const inspectCommand = defineCommand({
|
|
106
|
+
meta: inspectCommandMeta,
|
|
84
107
|
args: {
|
|
85
108
|
...OUTPUT_ARGS,
|
|
86
|
-
|
|
109
|
+
site: {
|
|
87
110
|
type: "string",
|
|
88
111
|
alias: "s",
|
|
89
|
-
description: "Site
|
|
112
|
+
description: "Site, for example example.com; defaults to config.defaultSite or a prompt"
|
|
90
113
|
},
|
|
91
|
-
|
|
114
|
+
urls: {
|
|
92
115
|
type: "positional",
|
|
93
116
|
required: false,
|
|
94
|
-
description: "
|
|
117
|
+
description: "One or more URLs to inspect"
|
|
95
118
|
},
|
|
96
|
-
|
|
119
|
+
file: {
|
|
97
120
|
type: "string",
|
|
98
121
|
alias: "f",
|
|
99
|
-
description: "File with URLs
|
|
100
|
-
},
|
|
101
|
-
"from-sitemap": {
|
|
102
|
-
type: "string",
|
|
103
|
-
description: "Sitemap URL (or sitemap index) to pull URLs from"
|
|
104
|
-
},
|
|
105
|
-
"delay-ms": {
|
|
106
|
-
type: "string",
|
|
107
|
-
default: "200",
|
|
108
|
-
description: "Delay between requests"
|
|
109
|
-
},
|
|
110
|
-
"concurrency": {
|
|
111
|
-
type: "string",
|
|
112
|
-
alias: "c",
|
|
113
|
-
default: "1",
|
|
114
|
-
description: "Concurrent in-flight requests"
|
|
122
|
+
description: "File with URLs, one per line"
|
|
115
123
|
}
|
|
116
124
|
},
|
|
117
125
|
async run({ args }) {
|
|
118
126
|
const { json, quiet } = applyOutputMode(args);
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
logger.error("No URLs provided. Pass URLs as args, --file, --from-sitemap, or stdin.");
|
|
133
|
-
process.exit(1);
|
|
134
|
-
}
|
|
135
|
-
const ctx = await createCommandContext({ needsAuth: true });
|
|
127
|
+
const urls = [...new Set(await readUrlList({
|
|
128
|
+
file: args.file,
|
|
129
|
+
positionals: args._
|
|
130
|
+
}))];
|
|
131
|
+
if (urls.length === 0) throw new Error("No URLs given. Pass URLs as arguments, use --file, or pipe them on stdin.");
|
|
132
|
+
const batch = checkInspectionBatch(urls);
|
|
133
|
+
if (batch.kind === "too-many") throw new Error(batch.message);
|
|
134
|
+
const ctx = await createCommandContext({
|
|
135
|
+
needsAuth: true,
|
|
136
|
+
needsStore: true
|
|
137
|
+
});
|
|
138
|
+
const client = ctx.client;
|
|
139
|
+
const store = ctx.store;
|
|
136
140
|
const siteUrl = await ctx.resolveSite(args.site ? String(args.site) : void 0);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const siteUrl = await ctx.resolveSite(args.site ? String(args.site) : void 0);
|
|
183
|
-
const result = await ctx.client.inspect(siteUrl, args.url).catch(gscErrorHandler);
|
|
184
|
-
const inspection = result?.inspectionResult;
|
|
185
|
-
const indexStatus = inspection?.indexStatusResult;
|
|
186
|
-
if (json) {
|
|
187
|
-
console.log(JSON.stringify({
|
|
188
|
-
url: args.url,
|
|
189
|
-
verdict: indexStatus?.verdict || null,
|
|
190
|
-
coverageState: indexStatus?.coverageState || null,
|
|
191
|
-
indexingState: indexStatus?.indexingState || null,
|
|
192
|
-
lastCrawlTime: indexStatus?.lastCrawlTime || null,
|
|
193
|
-
isIndexed: indexStatus?.verdict === "PASS",
|
|
194
|
-
raw: result
|
|
195
|
-
}, null, 2));
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
printInspection(args.url, inspection);
|
|
141
|
+
const claim = await recordStoreSite(store.dataDir, siteUrl, { userId: store.userId });
|
|
142
|
+
if (!claim.ok) throw new Error(formatSiteIdCollision(claim.error));
|
|
143
|
+
const tenant = {
|
|
144
|
+
userId: store.userId,
|
|
145
|
+
siteId: store.siteIdFor(siteUrl)
|
|
146
|
+
};
|
|
147
|
+
const { latest } = await loadInspectionState(store.dataSource, tenant, /* @__PURE__ */ new Date());
|
|
148
|
+
const saved = [];
|
|
149
|
+
if (!quiet && urls.length > 1) logger.info(`Inspecting ${urls.length} URLs ...`);
|
|
150
|
+
const run = await inspectUrls({
|
|
151
|
+
urls,
|
|
152
|
+
inspect: async (url) => (await client.inspect(siteUrl, url)).inspectionResult,
|
|
153
|
+
inProperty: (url) => urlInProperty(siteUrl, url),
|
|
154
|
+
onOutcome: async (outcome) => {
|
|
155
|
+
if (outcome.kind === "inspected") {
|
|
156
|
+
const record = toInspectionRecord({
|
|
157
|
+
url: outcome.url,
|
|
158
|
+
result: outcome.result,
|
|
159
|
+
inspectedAt: /* @__PURE__ */ new Date(),
|
|
160
|
+
previous: latest.get(outcome.url)
|
|
161
|
+
});
|
|
162
|
+
await appendInspections(store.dataSource, tenant, [record]);
|
|
163
|
+
saved.push(record);
|
|
164
|
+
}
|
|
165
|
+
if (!json && urls.length > 1) printOutcomeLine(outcome);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
if (saved.length > 0) await materializeInspectionIndex(store.dataSource, tenant, latest, saved);
|
|
169
|
+
const failed = run.outcomes.filter((outcome) => outcome.kind === "failed");
|
|
170
|
+
const remaining = run.stopped?.remaining ?? 0;
|
|
171
|
+
if (json) console.log(JSON.stringify({
|
|
172
|
+
site: siteUrl,
|
|
173
|
+
inspected: saved.length,
|
|
174
|
+
failed: failed.length,
|
|
175
|
+
remaining,
|
|
176
|
+
...run.stopped ? { stoppedReason: run.stopped.reason } : {},
|
|
177
|
+
results: run.outcomes.map(outcomeJson)
|
|
178
|
+
}, null, 2));
|
|
179
|
+
else if (urls.length === 1 && run.outcomes[0]?.kind === "inspected") printInspection(run.outcomes[0].url, run.outcomes[0].result);
|
|
180
|
+
else if (urls.length === 1 && run.outcomes[0]?.kind === "failed") throw new Error(run.outcomes[0].error);
|
|
181
|
+
const summary = [saved.length > 0 ? `Inspected ${saved.length} of ${urls.length} URL${urls.length === 1 ? "" : "s"} and saved the results to the Store.` : `Inspected ${saved.length} of ${urls.length} URL${urls.length === 1 ? "" : "s"}. Nothing was saved to the Store.`];
|
|
182
|
+
if (failed.length > 0) summary.push(`${failed.length} failed.`);
|
|
183
|
+
if (run.stopped) summary.push(`${remaining} remaining. ${run.stopped.reason} Run the command again after the quota resets.`);
|
|
184
|
+
if (failed.length > 0 || run.stopped) throw new Error(summary.join(" "));
|
|
185
|
+
if (!quiet) logger.success(summary[0]);
|
|
199
186
|
}
|
|
200
187
|
});
|
|
201
188
|
export { inspectCommand };
|
package/dist/commands/mcp.mjs
CHANGED
|
@@ -1,69 +1,49 @@
|
|
|
1
|
-
import { getCloudAccount, resolveAuthentication } from "../auth-state.mjs";
|
|
2
1
|
import { mcpCommandMeta } from "../command-meta.mjs";
|
|
3
|
-
import {
|
|
2
|
+
import { runWithCliRuntime, useCliRuntime } from "../runtime.mjs";
|
|
4
3
|
import { VERSION } from "../utils.mjs";
|
|
5
|
-
import {
|
|
4
|
+
import { probeAuth } from "../auth.mjs";
|
|
6
5
|
import { createCommandContext } from "../context.mjs";
|
|
7
6
|
import { createGscMcpServer } from "../mcp/server/index.mjs";
|
|
8
|
-
import process from "node:process";
|
|
9
7
|
import { defineCommand } from "citty";
|
|
10
8
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return
|
|
9
|
+
const MCP_NO_AUTH_MESSAGE = [
|
|
10
|
+
"gscdump has no Google authentication.",
|
|
11
|
+
"Run `gscdump auth login` in a terminal, then call this tool again.",
|
|
12
|
+
"For cloud mode, set GSCDUMP_API_KEY to a user API key from your gscdump.com settings.",
|
|
13
|
+
"For local mode, set GSC_SERVICE_ACCOUNT_JSON or GOOGLE_APPLICATION_CREDENTIALS to a service-account key file, set GSC_ACCESS_TOKEN, or set GSC_CLIENT_ID, GSC_CLIENT_SECRET, and GSC_REFRESH_TOKEN.",
|
|
14
|
+
"If you set environment variables, set them in the MCP server configuration and restart the MCP client.",
|
|
15
|
+
"If the gscdump command is missing, run `npm install -g @gscdump/cli`."
|
|
16
|
+
].join(" ");
|
|
17
|
+
const MCP_RETRIES = 1;
|
|
18
|
+
async function startMcpServer(transport, runtime = useCliRuntime()) {
|
|
19
|
+
const server = createGscMcpServer({
|
|
20
|
+
name: "gscdump",
|
|
21
|
+
version: VERSION,
|
|
22
|
+
getContext: async () => {
|
|
23
|
+
if (await probeAuth() === "none") throw new Error(MCP_NO_AUTH_MESSAGE);
|
|
24
|
+
const ctx = await createCommandContext({
|
|
25
|
+
needsAuth: true,
|
|
26
|
+
fetchOptions: { retry: MCP_RETRIES }
|
|
27
|
+
}).catch((error) => {
|
|
28
|
+
if (error.authError?.kind === "not-service-account") throw new Error(`${error.message}. ${MCP_NO_AUTH_MESSAGE}`);
|
|
29
|
+
throw error;
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
authentication: ctx.authentication,
|
|
33
|
+
auth: ctx.auth,
|
|
34
|
+
client: ctx.client
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
await server.connect(transport);
|
|
39
|
+
const handle = transport.onmessage;
|
|
40
|
+
if (handle) transport.onmessage = (message, extra) => runWithCliRuntime(runtime, () => handle(message, extra));
|
|
41
|
+
return server;
|
|
44
42
|
}
|
|
45
43
|
const mcpCommand = defineCommand({
|
|
46
44
|
meta: mcpCommandMeta,
|
|
47
45
|
async run() {
|
|
48
|
-
|
|
49
|
-
if (!authCheck.ok) {
|
|
50
|
-
process.stderr.write(`\n${authCheck.error}\n\n`);
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
const server = createGscMcpServer({
|
|
54
|
-
name: "gscdump",
|
|
55
|
-
version: VERSION,
|
|
56
|
-
getContext: async () => {
|
|
57
|
-
const ctx = await createCommandContext({ needsAuth: true });
|
|
58
|
-
return {
|
|
59
|
-
authentication: ctx.authentication,
|
|
60
|
-
auth: ctx.auth,
|
|
61
|
-
client: ctx.client
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
const transport = new StdioServerTransport();
|
|
66
|
-
await server.connect(transport);
|
|
46
|
+
await startMcpServer(new StdioServerTransport());
|
|
67
47
|
}
|
|
68
48
|
});
|
|
69
|
-
export { mcpCommand };
|
|
49
|
+
export { MCP_NO_AUTH_MESSAGE, mcpCommand, startMcpServer };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useCliRuntime } from "../runtime.mjs";
|
|
2
1
|
import { papercutCommandMeta } from "../command-meta.mjs";
|
|
2
|
+
import { useCliRuntime } from "../runtime.mjs";
|
|
3
3
|
import { OUTPUT_ARGS, applyOutputMode, logger } from "../utils.mjs";
|
|
4
4
|
import { buildPapercutBody, resolvePapercutUrl, submitPapercut } from "../papercut.mjs";
|
|
5
5
|
import process from "node:process";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { useCliRuntime } from "../runtime.mjs";
|
|
2
1
|
import { profileCommandMeta } from "../command-meta.mjs";
|
|
2
|
+
import { useCliRuntime } from "../runtime.mjs";
|
|
3
3
|
import { getConfigDir, setConfigDir } from "../config.mjs";
|
|
4
4
|
import { resolveCliEnvironment } from "../environment.mjs";
|
|
5
5
|
import { ACTIVE_MARKER, PROFILES_DIR, ROOT_DIR, getProfileDir, readActiveMarkerSync } from "./profile-selection.mjs";
|
|
6
|
-
import { OUTPUT_ARGS, applyOutputMode, displayPath, logger
|
|
6
|
+
import { OUTPUT_ARGS, applyOutputMode, displayPath, logger } from "../utils.mjs";
|
|
7
7
|
import process from "node:process";
|
|
8
8
|
import { defineCommand } from "citty";
|
|
9
9
|
import fs from "node:fs/promises";
|
|
@@ -151,23 +151,24 @@ const createCmd = defineCommand({
|
|
|
151
151
|
},
|
|
152
152
|
args: {
|
|
153
153
|
...OUTPUT_ARGS,
|
|
154
|
-
|
|
154
|
+
name: {
|
|
155
155
|
type: "positional",
|
|
156
156
|
required: true,
|
|
157
157
|
description: "Profile name"
|
|
158
158
|
},
|
|
159
|
-
|
|
159
|
+
use: {
|
|
160
160
|
type: "boolean",
|
|
161
|
-
default:
|
|
162
|
-
description: "
|
|
161
|
+
default: true,
|
|
162
|
+
description: "Make the new profile active",
|
|
163
|
+
negativeDescription: "Create the profile without making it active"
|
|
163
164
|
}
|
|
164
165
|
},
|
|
165
166
|
async run({ args }) {
|
|
166
167
|
applyOutputMode(args);
|
|
167
168
|
const name = String(args.name);
|
|
168
169
|
const dir = await createProfile(name);
|
|
169
|
-
if (
|
|
170
|
-
logger.success(`Created profile: ${name}${args
|
|
170
|
+
if (args.use) await setActiveProfile(name);
|
|
171
|
+
logger.success(`Created profile: ${name}${args.use ? " (active)" : ""}`);
|
|
171
172
|
logger.info(displayPath(dir));
|
|
172
173
|
}
|
|
173
174
|
});
|
|
@@ -240,15 +241,6 @@ const profileCommand = defineCommand({
|
|
|
240
241
|
delete: deleteCmd
|
|
241
242
|
},
|
|
242
243
|
async run({ args }) {
|
|
243
|
-
if (!noSubcommandSelected("profile", [
|
|
244
|
-
"list",
|
|
245
|
-
"path",
|
|
246
|
-
"current",
|
|
247
|
-
"use",
|
|
248
|
-
"create",
|
|
249
|
-
"clear",
|
|
250
|
-
"delete"
|
|
251
|
-
])) return;
|
|
252
244
|
await listCmd.run?.({
|
|
253
245
|
args,
|
|
254
246
|
cmd: listCmd,
|