@storewright/cli 0.14.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 +19 -0
- package/VERSION +1 -0
- package/bin/storewright.mjs +62 -0
- package/contracts/action-registry.json +175 -0
- package/contracts/capability-registry.json +63 -0
- package/contracts/workflow-manifest.json +207 -0
- package/lib/cli/storewright-cli.mjs +259 -0
- package/lib/internal/launch-envelope.mjs +223 -0
- package/lib/internal/multi-agent-contracts.mjs +137 -0
- package/lib/internal/operation-ledger.mjs +190 -0
- package/lib/internal/pricing/default-preview-pricing.mjs +181 -0
- package/lib/internal/run-state-helpers.mjs +313 -0
- package/lib/internal/shopify-operation-adapter.mjs +456 -0
- package/package.json +38 -0
- package/schemas/action-registry.schema.json +11 -0
- package/schemas/agent-report.schema.json +14 -0
- package/schemas/approval-grant.schema.json +16 -0
- package/schemas/base-theme-report.schema.json +25 -0
- package/schemas/brand-identity.schema.json +142 -0
- package/schemas/capability-registry.schema.json +11 -0
- package/schemas/competitor-audit.schema.json +38 -0
- package/schemas/design-direction.schema.json +64 -0
- package/schemas/external-operation.schema.json +34 -0
- package/schemas/intake-blocked-report.schema.json +76 -0
- package/schemas/launch-envelope.schema.json +25 -0
- package/schemas/launch-readiness.schema.json +73 -0
- package/schemas/media-file-inspection-report.schema.json +223 -0
- package/schemas/media-manifest.schema.json +84 -0
- package/schemas/merchandising-brief.schema.json +27 -0
- package/schemas/normalized-product-catalog.schema.json +42 -0
- package/schemas/product-content-generation-input.schema.json +40 -0
- package/schemas/product-content-generation-output.schema.json +43 -0
- package/schemas/raw-product-candidates.schema.json +32 -0
- package/schemas/shopify-access-preflight-report.schema.json +213 -0
- package/schemas/shopify-content-sync-report.schema.json +190 -0
- package/schemas/shopify-media-map.schema.json +87 -0
- package/schemas/shopify-media-upload-report.schema.json +96 -0
- package/schemas/shopify-operation-request.schema.json +81 -0
- package/schemas/shopify-preflight-report.schema.json +187 -0
- package/schemas/store-blueprint.schema.json +112 -0
- package/schemas/store-content-generation-output.schema.json +102 -0
- package/schemas/store-intake.schema.json +205 -0
- package/schemas/store-ops-plan.schema.json +82 -0
- package/schemas/storefront-preview-review.schema.json +227 -0
- package/schemas/supplier-access-report.schema.json +36 -0
- package/schemas/supplier-extraction-report.schema.json +185 -0
- package/schemas/theme-build-report.schema.json +43 -0
- package/schemas/theme-code-change-summary.schema.json +65 -0
- package/schemas/theme-plan.schema.json +26 -0
- package/schemas/theme-push-report.schema.json +151 -0
- package/schemas/theme-workspace-validation-report.schema.json +61 -0
- package/schemas/workflow-manifest.schema.json +29 -0
- package/scripts/audit-run-state.mjs +472 -0
- package/scripts/execute-shopify-operation.mjs +190 -0
- package/scripts/generate-image-assets-openai.mjs +342 -0
- package/scripts/generate-media-assets.mjs +121 -0
- package/scripts/init-run-state.mjs +69 -0
- package/scripts/inspect-media-files.mjs +334 -0
- package/scripts/prepare-launch-envelope.mjs +47 -0
- package/scripts/shopify-access-preflight.mjs +432 -0
- package/scripts/upload-shopify-media.mjs +831 -0
- package/scripts/validate-agent-report.mjs +46 -0
- package/scripts/validate-artifact.mjs +196 -0
- package/scripts/validate-launch-envelope.mjs +50 -0
- package/scripts/validate-registries.mjs +50 -0
- package/scripts/validate-workflow-manifest.mjs +38 -0
- package/scripts/version.mjs +192 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
|
|
4
|
+
const WORKFLOW_SCOPES = [
|
|
5
|
+
"read_files",
|
|
6
|
+
"write_files",
|
|
7
|
+
"read_themes",
|
|
8
|
+
"write_themes",
|
|
9
|
+
"read_products",
|
|
10
|
+
"write_products",
|
|
11
|
+
"read_publications",
|
|
12
|
+
"write_publications",
|
|
13
|
+
"read_content",
|
|
14
|
+
"write_content",
|
|
15
|
+
"read_online_store_navigation",
|
|
16
|
+
"write_online_store_navigation"
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const SCOPE_PROBE_QUERY =
|
|
20
|
+
"query StorewrightScopeProbe { currentAppInstallation { accessScopes { handle } } }";
|
|
21
|
+
|
|
22
|
+
const SHOP_QUERY = "query StorewrightPreflight { shop { id name myshopifyDomain } }";
|
|
23
|
+
|
|
24
|
+
const INSTALLER_COMMANDS = {
|
|
25
|
+
npm: "install -g @shopify/cli@latest",
|
|
26
|
+
pnpm: "install -g @shopify/cli@latest",
|
|
27
|
+
yarn: "global add @shopify/cli@latest",
|
|
28
|
+
brew: "tap shopify/shopify && brew install shopify-cli"
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const DEFAULT_COMMAND_TIMEOUT_MS = 60_000;
|
|
32
|
+
const DEFAULT_AUTH_TIMEOUT_MS = 300_000;
|
|
33
|
+
|
|
34
|
+
function usage() {
|
|
35
|
+
return "Usage: shopify-access-preflight.mjs --store <myshopify-domain> [--command-timeout-ms <ms>] [--auth-timeout-ms <ms>]";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parsePositiveInteger(value, name) {
|
|
39
|
+
if (!/^[1-9]\d*$/.test(String(value ?? ""))) {
|
|
40
|
+
return { error: `${name} must be a positive integer.` };
|
|
41
|
+
}
|
|
42
|
+
const parsed = Number.parseInt(value, 10);
|
|
43
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
44
|
+
return { error: `${name} must be a positive integer.` };
|
|
45
|
+
}
|
|
46
|
+
return { value: parsed };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function parseArgs(argv) {
|
|
50
|
+
let store = "";
|
|
51
|
+
let commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS;
|
|
52
|
+
let authTimeoutMs = DEFAULT_AUTH_TIMEOUT_MS;
|
|
53
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
54
|
+
const arg = argv[i];
|
|
55
|
+
if (arg === "--store") {
|
|
56
|
+
store = argv[i + 1] ?? "";
|
|
57
|
+
i += 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (arg === "--command-timeout-ms") {
|
|
61
|
+
const parsed = parsePositiveInteger(argv[i + 1], "--command-timeout-ms");
|
|
62
|
+
if (parsed.error) return parsed;
|
|
63
|
+
commandTimeoutMs = parsed.value;
|
|
64
|
+
i += 1;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (arg === "--auth-timeout-ms") {
|
|
68
|
+
const parsed = parsePositiveInteger(argv[i + 1], "--auth-timeout-ms");
|
|
69
|
+
if (parsed.error) return parsed;
|
|
70
|
+
authTimeoutMs = parsed.value;
|
|
71
|
+
i += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (arg === "-h" || arg === "--help") {
|
|
75
|
+
return { help: true, store, commandTimeoutMs, authTimeoutMs };
|
|
76
|
+
}
|
|
77
|
+
return { error: `Unknown argument: ${arg}` };
|
|
78
|
+
}
|
|
79
|
+
if (!store) return { error: "Missing required --store argument." };
|
|
80
|
+
return { store, commandTimeoutMs, authTimeoutMs };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function parseJson(text) {
|
|
84
|
+
const raw = String(text ?? "").trim();
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(raw);
|
|
87
|
+
} catch {
|
|
88
|
+
let lastParsed = null;
|
|
89
|
+
for (let start = 0; start < raw.length; start += 1) {
|
|
90
|
+
const opener = raw[start];
|
|
91
|
+
if (opener !== "{" && opener !== "[") continue;
|
|
92
|
+
const closer = opener === "{" ? "}" : "]";
|
|
93
|
+
let depth = 0;
|
|
94
|
+
let inString = false;
|
|
95
|
+
let escaped = false;
|
|
96
|
+
for (let index = start; index < raw.length; index += 1) {
|
|
97
|
+
const char = raw[index];
|
|
98
|
+
if (inString) {
|
|
99
|
+
if (escaped) {
|
|
100
|
+
escaped = false;
|
|
101
|
+
} else if (char === "\\") {
|
|
102
|
+
escaped = true;
|
|
103
|
+
} else if (char === "\"") {
|
|
104
|
+
inString = false;
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (char === "\"") {
|
|
109
|
+
inString = true;
|
|
110
|
+
} else if (char === opener) {
|
|
111
|
+
depth += 1;
|
|
112
|
+
} else if (char === closer) {
|
|
113
|
+
depth -= 1;
|
|
114
|
+
if (depth === 0) {
|
|
115
|
+
try {
|
|
116
|
+
lastParsed = JSON.parse(raw.slice(start, index + 1));
|
|
117
|
+
} catch {
|
|
118
|
+
// Keep scanning for the final valid JSON payload in noisy CLI output.
|
|
119
|
+
}
|
|
120
|
+
start = index;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return lastParsed;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function collectScopes(value, scopes = new Set()) {
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
for (const item of value) collectScopes(item, scopes);
|
|
133
|
+
return scopes;
|
|
134
|
+
}
|
|
135
|
+
if (value && typeof value === "object") {
|
|
136
|
+
for (const item of Object.values(value)) collectScopes(item, scopes);
|
|
137
|
+
return scopes;
|
|
138
|
+
}
|
|
139
|
+
if (typeof value === "string") {
|
|
140
|
+
for (const part of value.split(/[,\s]+/)) {
|
|
141
|
+
if (/^[a-z]+_[a-z_]+$/.test(part)) scopes.add(part);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return scopes;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function effectiveScopes(rawScopes) {
|
|
148
|
+
const scopes = new Set(rawScopes);
|
|
149
|
+
for (const scope of rawScopes) {
|
|
150
|
+
if (scope.startsWith("write_")) {
|
|
151
|
+
scopes.add(scope.replace(/^write_/, "read_"));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return [...scopes].sort();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function runShopify(args, { timeoutMs = DEFAULT_COMMAND_TIMEOUT_MS } = {}) {
|
|
158
|
+
const result = spawnSync("shopify", args, {
|
|
159
|
+
encoding: "utf8",
|
|
160
|
+
timeout: timeoutMs,
|
|
161
|
+
killSignal: "SIGTERM"
|
|
162
|
+
});
|
|
163
|
+
return processResult(["shopify", ...args], result, { timeoutMs });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function runShell(command, { timeoutMs = DEFAULT_COMMAND_TIMEOUT_MS } = {}) {
|
|
167
|
+
const result = spawnSync("/bin/sh", ["-lc", command], {
|
|
168
|
+
encoding: "utf8",
|
|
169
|
+
timeout: timeoutMs,
|
|
170
|
+
killSignal: "SIGTERM"
|
|
171
|
+
});
|
|
172
|
+
return processResult(["/bin/sh", "-lc", command], result, { timeoutMs });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function commandSignals(commandParts, stdout, stderr, timedOut) {
|
|
176
|
+
const combinedOutput = `${stdout}\n${stderr}`;
|
|
177
|
+
const commandText = commandParts.join(" ");
|
|
178
|
+
const blockerHints = [];
|
|
179
|
+
if (/shopify store auth\b/.test(commandText) && timedOut) {
|
|
180
|
+
blockerHints.push("shopify-auth-timeout");
|
|
181
|
+
}
|
|
182
|
+
if (/Client network socket disconnected|ECONNRESET|ETIMEDOUT|ENOTFOUND|TLS connection/i.test(combinedOutput)) {
|
|
183
|
+
blockerHints.push("shopify-network-error");
|
|
184
|
+
}
|
|
185
|
+
return { blockerHints };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function processResult(commandParts, result, { timeoutMs = DEFAULT_COMMAND_TIMEOUT_MS } = {}) {
|
|
189
|
+
const timedOut = result.error?.code === "ETIMEDOUT";
|
|
190
|
+
const exitCode = timedOut ? 1 : result.status ?? 1;
|
|
191
|
+
const parsedJson = parseJson(result.stdout);
|
|
192
|
+
const stdout = result.stdout ?? "";
|
|
193
|
+
const stderr = result.stderr ?? "";
|
|
194
|
+
const signals = commandSignals(commandParts, stdout, stderr, timedOut);
|
|
195
|
+
return {
|
|
196
|
+
command: commandParts.join(" "),
|
|
197
|
+
exitCode,
|
|
198
|
+
commandResult: timedOut ? "timeout" : exitCode === 0 ? "ok" : "error",
|
|
199
|
+
timedOut,
|
|
200
|
+
signal: result.signal ?? null,
|
|
201
|
+
timeoutMs,
|
|
202
|
+
stdout,
|
|
203
|
+
stderr,
|
|
204
|
+
parsedJson,
|
|
205
|
+
blockerHints: signals.blockerHints
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function skippedCommand(command) {
|
|
210
|
+
return {
|
|
211
|
+
command,
|
|
212
|
+
exitCode: null,
|
|
213
|
+
commandResult: "skipped",
|
|
214
|
+
stdout: "",
|
|
215
|
+
stderr: "",
|
|
216
|
+
parsedJson: null
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function commandSummary(command) {
|
|
221
|
+
return {
|
|
222
|
+
command: command.command,
|
|
223
|
+
exitCode: command.exitCode,
|
|
224
|
+
commandResult: command.commandResult,
|
|
225
|
+
timedOut: command.timedOut ?? false,
|
|
226
|
+
signal: command.signal ?? null,
|
|
227
|
+
timeoutMs: command.timeoutMs ?? null,
|
|
228
|
+
stdoutSummary: command.stdout.slice(0, 500),
|
|
229
|
+
stderrSummary: command.stderr.slice(0, 500),
|
|
230
|
+
blockerHints: command.blockerHints ?? []
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function detectExecutable(name, { timeoutMs = DEFAULT_COMMAND_TIMEOUT_MS } = {}) {
|
|
235
|
+
const lookup = runShell(`command -v ${name}`, { timeoutMs });
|
|
236
|
+
return {
|
|
237
|
+
name,
|
|
238
|
+
lookup,
|
|
239
|
+
path: lookup.commandResult === "ok" ? lookup.stdout.trim() : null
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function createShopifyCliEvidence({ commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS } = {}) {
|
|
244
|
+
const shopify = detectExecutable("shopify", { timeoutMs: commandTimeoutMs });
|
|
245
|
+
const version = shopify.path ? runShopify(["version"], { timeoutMs: commandTimeoutMs }) : skippedCommand("shopify version");
|
|
246
|
+
const installerLookups = ["npm", "pnpm", "yarn", "brew"].map((name) => detectExecutable(name, { timeoutMs: commandTimeoutMs }));
|
|
247
|
+
const availableInstallers = installerLookups
|
|
248
|
+
.filter((installer) => installer.path)
|
|
249
|
+
.map((installer) => ({ name: installer.name, path: installer.path }));
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
status: shopify.path ? "available" : "missing",
|
|
253
|
+
path: shopify.path,
|
|
254
|
+
version: commandSummary(version),
|
|
255
|
+
availableInstallers,
|
|
256
|
+
installCandidates: shopify.path
|
|
257
|
+
? []
|
|
258
|
+
: availableInstallers.map((installer) => ({
|
|
259
|
+
name: installer.name,
|
|
260
|
+
command: `${installer.path} ${INSTALLER_COMMANDS[installer.name]}`
|
|
261
|
+
})),
|
|
262
|
+
commands: [
|
|
263
|
+
{ name: "shopifyCliLookup", ...commandSummary(shopify.lookup) },
|
|
264
|
+
{ name: "shopifyCliVersion", ...commandSummary(version) },
|
|
265
|
+
...installerLookups.map((installer) => ({
|
|
266
|
+
name: `installerLookup:${installer.name}`,
|
|
267
|
+
...commandSummary(installer.lookup)
|
|
268
|
+
}))
|
|
269
|
+
]
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function missingScopes(requestedScopes, scopes) {
|
|
274
|
+
const available = new Set(scopes);
|
|
275
|
+
return requestedScopes.filter((scope) => !available.has(scope));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function isRetryableScopeProbeFailure(command) {
|
|
279
|
+
return command.timedOut || /aborted before it completed|timed out|timeout|ECONNRESET|ETIMEDOUT/i.test(command.stderr);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function isAuthRequiredScopeProbeFailure(command) {
|
|
283
|
+
return /run .*store auth|no stored store auth|authentication required|missing .*scope|requires .*scope|access denied/i.test(command.stderr);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function run({
|
|
287
|
+
store,
|
|
288
|
+
requestedScopes = WORKFLOW_SCOPES,
|
|
289
|
+
commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS,
|
|
290
|
+
authTimeoutMs = DEFAULT_AUTH_TIMEOUT_MS
|
|
291
|
+
}) {
|
|
292
|
+
const shopifyCli = createShopifyCliEvidence({ commandTimeoutMs });
|
|
293
|
+
if (shopifyCli.status === "missing") {
|
|
294
|
+
return {
|
|
295
|
+
schemaVersion: "1.0.0",
|
|
296
|
+
store,
|
|
297
|
+
requestedScopes,
|
|
298
|
+
shopifyCli,
|
|
299
|
+
rawCurrentScopes: [],
|
|
300
|
+
effectiveCurrentScopes: [],
|
|
301
|
+
auth: {
|
|
302
|
+
action: "skipped",
|
|
303
|
+
commandResult: "skipped",
|
|
304
|
+
scopeProbeResult: "skipped",
|
|
305
|
+
rawVerifiedScopes: [],
|
|
306
|
+
verifiedScopes: [],
|
|
307
|
+
missingScopes: requestedScopes,
|
|
308
|
+
missingScopesBeforeAuth: requestedScopes
|
|
309
|
+
},
|
|
310
|
+
storeAccess: {
|
|
311
|
+
commandResult: "skipped",
|
|
312
|
+
exitCode: null,
|
|
313
|
+
themeCount: null
|
|
314
|
+
},
|
|
315
|
+
adminGraphqlAccess: {
|
|
316
|
+
commandResult: "skipped",
|
|
317
|
+
exitCode: null,
|
|
318
|
+
shop: null
|
|
319
|
+
},
|
|
320
|
+
commands: shopifyCli.commands
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const currentScopeProbeCommands = [
|
|
325
|
+
runShopify(["store", "execute", "--store", store, "--query", SCOPE_PROBE_QUERY, "--json"], { timeoutMs: commandTimeoutMs })
|
|
326
|
+
];
|
|
327
|
+
if (isRetryableScopeProbeFailure(currentScopeProbeCommands[0])) {
|
|
328
|
+
currentScopeProbeCommands.push(
|
|
329
|
+
runShopify(["store", "execute", "--store", store, "--query", SCOPE_PROBE_QUERY, "--json"], { timeoutMs: commandTimeoutMs })
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
const currentScopeProbe = currentScopeProbeCommands.at(-1);
|
|
333
|
+
const scopeProbeSucceeded = currentScopeProbe.commandResult === "ok";
|
|
334
|
+
const scopeProbeAuthRequired = !scopeProbeSucceeded && isAuthRequiredScopeProbeFailure(currentScopeProbe);
|
|
335
|
+
const rawCurrentScopes = scopeProbeSucceeded
|
|
336
|
+
? [...collectScopes(currentScopeProbe.parsedJson)].sort()
|
|
337
|
+
: [];
|
|
338
|
+
const effectiveCurrentScopes = effectiveScopes(rawCurrentScopes);
|
|
339
|
+
const missingBeforeAuth = missingScopes(requestedScopes, effectiveCurrentScopes);
|
|
340
|
+
let authAction = "skipped";
|
|
341
|
+
let authCommand = null;
|
|
342
|
+
let rawVerifiedScopes = rawCurrentScopes;
|
|
343
|
+
let verifiedScopes = effectiveCurrentScopes;
|
|
344
|
+
|
|
345
|
+
if (missingBeforeAuth.length > 0 && (scopeProbeSucceeded || scopeProbeAuthRequired)) {
|
|
346
|
+
authAction = "requested";
|
|
347
|
+
authCommand = runShopify([
|
|
348
|
+
"store",
|
|
349
|
+
"auth",
|
|
350
|
+
"--store",
|
|
351
|
+
store,
|
|
352
|
+
"--scopes",
|
|
353
|
+
requestedScopes.join(","),
|
|
354
|
+
"--json"
|
|
355
|
+
], { timeoutMs: authTimeoutMs });
|
|
356
|
+
rawVerifiedScopes = [...collectScopes(authCommand.parsedJson)].sort();
|
|
357
|
+
verifiedScopes = effectiveScopes(rawVerifiedScopes);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const themeList = runShopify(["theme", "list", "--store", store, "--json"], { timeoutMs: commandTimeoutMs });
|
|
361
|
+
const adminGraphql = runShopify([
|
|
362
|
+
"store",
|
|
363
|
+
"execute",
|
|
364
|
+
"--store",
|
|
365
|
+
store,
|
|
366
|
+
"--query",
|
|
367
|
+
SHOP_QUERY,
|
|
368
|
+
"--json"
|
|
369
|
+
], { timeoutMs: commandTimeoutMs });
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
schemaVersion: "1.0.0",
|
|
373
|
+
store,
|
|
374
|
+
requestedScopes,
|
|
375
|
+
shopifyCli,
|
|
376
|
+
rawCurrentScopes,
|
|
377
|
+
effectiveCurrentScopes,
|
|
378
|
+
auth: {
|
|
379
|
+
action: authAction,
|
|
380
|
+
commandResult: authCommand?.commandResult ?? "skipped",
|
|
381
|
+
approvalState: authCommand
|
|
382
|
+
? authCommand.commandResult === "ok"
|
|
383
|
+
? "approved"
|
|
384
|
+
: authCommand.timedOut
|
|
385
|
+
? "timeout"
|
|
386
|
+
: "unknown"
|
|
387
|
+
: "not-needed",
|
|
388
|
+
scopeProbeResult: currentScopeProbe.commandResult,
|
|
389
|
+
rawVerifiedScopes,
|
|
390
|
+
verifiedScopes,
|
|
391
|
+
missingScopes: missingScopes(requestedScopes, verifiedScopes),
|
|
392
|
+
missingScopesBeforeAuth: missingBeforeAuth
|
|
393
|
+
},
|
|
394
|
+
storeAccess: {
|
|
395
|
+
commandResult: themeList.commandResult,
|
|
396
|
+
exitCode: themeList.exitCode,
|
|
397
|
+
themeCount: Array.isArray(themeList.parsedJson) ? themeList.parsedJson.length : null,
|
|
398
|
+
blockerId: null
|
|
399
|
+
},
|
|
400
|
+
adminGraphqlAccess: {
|
|
401
|
+
commandResult: adminGraphql.commandResult,
|
|
402
|
+
exitCode: adminGraphql.exitCode,
|
|
403
|
+
shop: adminGraphql.parsedJson?.data?.shop ?? adminGraphql.parsedJson?.shop ?? null
|
|
404
|
+
},
|
|
405
|
+
commands: [
|
|
406
|
+
...shopifyCli.commands,
|
|
407
|
+
...currentScopeProbeCommands.map((command, index) => ({
|
|
408
|
+
name: index === 0 ? "currentScopeProbe" : `currentScopeProbeRetry${index}`,
|
|
409
|
+
...commandSummary(command)
|
|
410
|
+
})),
|
|
411
|
+
...(authAction === "requested" ? [{ name: "workflowScopeAuth", ...commandSummary(authCommand) }] : []),
|
|
412
|
+
{ name: "themeList", ...commandSummary(themeList) },
|
|
413
|
+
{ name: "adminGraphqlRead", ...commandSummary(adminGraphql) }
|
|
414
|
+
]
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
419
|
+
if (parsed.help) {
|
|
420
|
+
console.log(usage());
|
|
421
|
+
process.exit(0);
|
|
422
|
+
}
|
|
423
|
+
if (parsed.error) {
|
|
424
|
+
console.error(parsed.error);
|
|
425
|
+
process.exit(2);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
process.stdout.write(`${JSON.stringify(run({
|
|
429
|
+
store: parsed.store,
|
|
430
|
+
commandTimeoutMs: parsed.commandTimeoutMs,
|
|
431
|
+
authTimeoutMs: parsed.authTimeoutMs
|
|
432
|
+
}), null, 2)}\n`);
|