@dk/jolly 0.1.8 → 0.1.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/README.md +16 -92
- package/package.json +26 -24
- package/src/index.ts +2095 -0
- package/src/lib/cloud-api.ts +527 -0
- package/src/lib/env-file.ts +68 -0
- package/src/lib/saleor-url.ts +37 -0
- package/.env.example +0 -3
- package/.mcp.json +0 -7
- package/.sisyphus/boulder.json +0 -13
- package/.sisyphus/notepads/saleor-agent-cli/decisions.md +0 -11
- package/.sisyphus/notepads/saleor-agent-cli/issues.md +0 -6
- package/.sisyphus/notepads/saleor-agent-cli/learnings.md +0 -6
- package/.sisyphus/plans/saleor-agent-cli.md +0 -600
- package/AGENTS.md +0 -46
- package/bun.lock +0 -123
- package/bunfig.toml +0 -8
- package/dist/agent.js +0 -258
- package/dist/bootstrap.js +0 -184
- package/dist/index.js +0 -722
- package/src/agents/index.ts +0 -1
- package/src/agents/setup.ts +0 -210
- package/src/api/auth.ts +0 -75
- package/src/api/client.ts +0 -152
- package/src/api/endpoints.ts +0 -8
- package/src/api/index.ts +0 -4
- package/src/cli/agent.ts +0 -26
- package/src/cli/bootstrap.ts +0 -24
- package/src/cli/commands/agent.ts +0 -40
- package/src/cli/commands/app.ts +0 -61
- package/src/cli/commands/config.ts +0 -38
- package/src/cli/commands/store.ts +0 -75
- package/src/cli/index.ts +0 -16
- package/src/commands/app.ts +0 -126
- package/src/commands/index.ts +0 -1
- package/src/commands/store.ts +0 -64
- package/src/test/command-handlers.test.ts +0 -232
- package/src/test/e2e-flows.test.ts +0 -231
- package/src/test/entry-points.test.ts +0 -126
- package/src/test/error-handling.test.ts +0 -137
- package/src/test/helpers.ts +0 -49
- package/src/test/index.ts +0 -1
- package/src/test/mocks.ts +0 -172
- package/src/test/setup.ts +0 -29
- package/src/tui/components.ts +0 -77
- package/src/tui/index.ts +0 -3
- package/src/tui/renderer.ts +0 -34
- package/src/tui/theme.ts +0 -38
- package/tsconfig.json +0 -20
package/dist/index.js
DELETED
|
@@ -1,722 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
-
for (let key of __getOwnPropNames(mod))
|
|
12
|
-
if (!__hasOwnProp.call(to, key))
|
|
13
|
-
__defProp(to, key, {
|
|
14
|
-
get: () => mod[key],
|
|
15
|
-
enumerable: true
|
|
16
|
-
});
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
|
-
|
|
21
|
-
// src/cli/index.ts
|
|
22
|
-
import yargs from "yargs";
|
|
23
|
-
import { hideBin } from "yargs/helpers";
|
|
24
|
-
|
|
25
|
-
// src/api/client.ts
|
|
26
|
-
class SaleorCloudClient {
|
|
27
|
-
baseUrl = "https://cloud.saleor.io/api/v1";
|
|
28
|
-
token;
|
|
29
|
-
constructor(token) {
|
|
30
|
-
this.token = token || process.env.SALEOR_CLOUD_TOKEN || "";
|
|
31
|
-
if (!this.token) {
|
|
32
|
-
throw new Error("SALEOR_CLOUD_TOKEN environment variable is required");
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
async request(endpoint, options) {
|
|
36
|
-
const mergedOptions = {
|
|
37
|
-
method: options?.method || "GET",
|
|
38
|
-
...options,
|
|
39
|
-
headers: {
|
|
40
|
-
Authorization: `Token ${this.token}`,
|
|
41
|
-
"Content-Type": "application/json",
|
|
42
|
-
...options?.headers
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
const response = await fetch(`${this.baseUrl}${endpoint}`, mergedOptions);
|
|
46
|
-
if (!response.ok) {
|
|
47
|
-
const body = await response.text();
|
|
48
|
-
const truncatedBody = body.length > 200 ? body.substring(0, 200) + "..." : body;
|
|
49
|
-
throw new Error(`API error: ${response.status} ${response.statusText} - ${truncatedBody}`);
|
|
50
|
-
}
|
|
51
|
-
return response.json();
|
|
52
|
-
}
|
|
53
|
-
async getOrganizations() {
|
|
54
|
-
return this.request("/organizations");
|
|
55
|
-
}
|
|
56
|
-
async getProjects(organizationSlug) {
|
|
57
|
-
return this.request(`/organizations/${organizationSlug}/projects`);
|
|
58
|
-
}
|
|
59
|
-
async createProject(organizationSlug, name, region) {
|
|
60
|
-
return this.request(`/organizations/${organizationSlug}/projects`, {
|
|
61
|
-
method: "POST",
|
|
62
|
-
body: JSON.stringify({ name, region })
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
async getEnvironments(organizationSlug, projectSlug) {
|
|
66
|
-
return this.request(`/organizations/${organizationSlug}/projects/${projectSlug}/environments`);
|
|
67
|
-
}
|
|
68
|
-
async createEnvironment(organizationSlug, projectSlug, name, region) {
|
|
69
|
-
return this.request(`/organizations/${organizationSlug}/projects/${projectSlug}/environments`, {
|
|
70
|
-
method: "POST",
|
|
71
|
-
body: JSON.stringify({ name, region })
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
async getEnvironment(organizationSlug, projectSlug, environmentSlug) {
|
|
75
|
-
return this.request(`/organizations/${organizationSlug}/projects/${projectSlug}/environments/${environmentSlug}`);
|
|
76
|
-
}
|
|
77
|
-
async registerApp(environmentId, appType, name) {
|
|
78
|
-
return this.request(`/environments/${environmentId}/apps`, {
|
|
79
|
-
method: "POST",
|
|
80
|
-
body: JSON.stringify({ type: appType, name })
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
async getStores() {
|
|
84
|
-
return this.getOrganizations();
|
|
85
|
-
}
|
|
86
|
-
async createStore(name, region = "us-east-1") {
|
|
87
|
-
const { organizations } = await this.getOrganizations();
|
|
88
|
-
if (organizations.length === 0) {
|
|
89
|
-
throw new Error("No organizations found. Create one at https://cloud.saleor.io");
|
|
90
|
-
}
|
|
91
|
-
return this.createProject(organizations[0].slug, name, region);
|
|
92
|
-
}
|
|
93
|
-
async createEnvironmentFromStore(storeId, name) {
|
|
94
|
-
const { environments } = await this.getEnvironments(storeId, "default");
|
|
95
|
-
return this.createEnvironment(storeId, environments.length > 0 ? environments[0].project?.slug || "default" : "default", name, "default");
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// src/api/auth.ts
|
|
100
|
-
import { config } from "@dotenvx/dotenvx";
|
|
101
|
-
import { writeFileSync, existsSync, readFileSync } from "fs";
|
|
102
|
-
import { join } from "path";
|
|
103
|
-
config();
|
|
104
|
-
function requireToken() {
|
|
105
|
-
const token = process.env.SALEOR_CLOUD_TOKEN;
|
|
106
|
-
if (!token) {
|
|
107
|
-
console.error(`
|
|
108
|
-
\uD83D\uDD11 Saleor Cloud Token Required`);
|
|
109
|
-
console.error(` Get your token at: https://cloud.saleor.io/settings/api-tokens
|
|
110
|
-
`);
|
|
111
|
-
console.error("Or create a .env file with: SALEOR_CLOUD_TOKEN=your-token");
|
|
112
|
-
console.error(`
|
|
113
|
-
To set token: export SALEOR_CLOUD_TOKEN=your-token
|
|
114
|
-
`);
|
|
115
|
-
process.exit(1);
|
|
116
|
-
}
|
|
117
|
-
return token;
|
|
118
|
-
}
|
|
119
|
-
async function promptAndSaveToken() {
|
|
120
|
-
console.log(`
|
|
121
|
-
\uD83D\uDD11 Saleor Cloud Token Required`);
|
|
122
|
-
console.log(` Get your token at: https://cloud.saleor.io/settings/api-tokens
|
|
123
|
-
`);
|
|
124
|
-
const readline = await import("readline");
|
|
125
|
-
const rl = readline.createInterface({
|
|
126
|
-
input: process.stdin,
|
|
127
|
-
output: process.stdout
|
|
128
|
-
});
|
|
129
|
-
return new Promise((resolve) => {
|
|
130
|
-
rl.question("Enter your SALEOR_CLOUD_TOKEN: ", (answer) => {
|
|
131
|
-
rl.close();
|
|
132
|
-
const token = answer.trim();
|
|
133
|
-
if (!token) {
|
|
134
|
-
console.error("Error: Token cannot be empty");
|
|
135
|
-
process.exit(1);
|
|
136
|
-
}
|
|
137
|
-
const envPath = join(process.cwd(), ".env");
|
|
138
|
-
const envLine = `SALEOR_CLOUD_TOKEN=${token}
|
|
139
|
-
`;
|
|
140
|
-
try {
|
|
141
|
-
let existingContent = "";
|
|
142
|
-
if (existsSync(envPath)) {
|
|
143
|
-
existingContent = readFileSync(envPath, "utf-8");
|
|
144
|
-
if (existingContent.includes("SALEOR_CLOUD_TOKEN=")) {
|
|
145
|
-
existingContent = existingContent.replace(/SALEOR_CLOUD_TOKEN=.*\n?/g, envLine);
|
|
146
|
-
} else {
|
|
147
|
-
existingContent += envLine;
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
existingContent = envLine;
|
|
151
|
-
}
|
|
152
|
-
writeFileSync(envPath, existingContent);
|
|
153
|
-
console.log(`
|
|
154
|
-
✅ Token saved to .env file`);
|
|
155
|
-
} catch {
|
|
156
|
-
console.log(`
|
|
157
|
-
⚠️ Could not save to .env, token will not persist`);
|
|
158
|
-
}
|
|
159
|
-
process.env.SALEOR_CLOUD_TOKEN = token;
|
|
160
|
-
resolve(token);
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// src/tui/theme.ts
|
|
166
|
-
var theme = {
|
|
167
|
-
reset: "\x1B[0m",
|
|
168
|
-
bold: "\x1B[1m",
|
|
169
|
-
dim: "\x1B[2m",
|
|
170
|
-
italic: "\x1B[3m",
|
|
171
|
-
underline: "\x1B[4m",
|
|
172
|
-
fg: {
|
|
173
|
-
black: "\x1B[30m",
|
|
174
|
-
red: "\x1B[31m",
|
|
175
|
-
green: "\x1B[32m",
|
|
176
|
-
yellow: "\x1B[33m",
|
|
177
|
-
blue: "\x1B[34m",
|
|
178
|
-
magenta: "\x1B[35m",
|
|
179
|
-
cyan: "\x1B[36m",
|
|
180
|
-
white: "\x1B[37m",
|
|
181
|
-
gray: "\x1B[90m",
|
|
182
|
-
brightBlack: "\x1B[30;1m",
|
|
183
|
-
brightRed: "\x1B[31;1m",
|
|
184
|
-
brightGreen: "\x1B[32;1m",
|
|
185
|
-
brightYellow: "\x1B[33;1m",
|
|
186
|
-
brightBlue: "\x1B[34;1m",
|
|
187
|
-
brightMagenta: "\x1B[35;1m",
|
|
188
|
-
brightCyan: "\x1B[36;1m",
|
|
189
|
-
brightWhite: "\x1B[37;1m"
|
|
190
|
-
},
|
|
191
|
-
bg: {
|
|
192
|
-
black: "\x1B[40m",
|
|
193
|
-
red: "\x1B[41m",
|
|
194
|
-
green: "\x1B[42m",
|
|
195
|
-
yellow: "\x1B[43m",
|
|
196
|
-
blue: "\x1B[44m",
|
|
197
|
-
magenta: "\x1B[45m",
|
|
198
|
-
cyan: "\x1B[46m",
|
|
199
|
-
white: "\x1B[47m"
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
// src/tui/components.ts
|
|
204
|
-
function text(content, color) {
|
|
205
|
-
return `${color || theme.fg.white}${content}${theme.reset}`;
|
|
206
|
-
}
|
|
207
|
-
function success(msg) {
|
|
208
|
-
return text(msg, theme.fg.green);
|
|
209
|
-
}
|
|
210
|
-
function error(msg) {
|
|
211
|
-
return text(msg, theme.fg.red);
|
|
212
|
-
}
|
|
213
|
-
function info(msg) {
|
|
214
|
-
return text(msg, theme.fg.cyan);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// src/commands/store.ts
|
|
218
|
-
async function createStore(name, region) {
|
|
219
|
-
const token = requireToken();
|
|
220
|
-
const client = new SaleorCloudClient(token);
|
|
221
|
-
console.log(info(`Creating store: ${name} in ${region}...`));
|
|
222
|
-
try {
|
|
223
|
-
const result = await client.createStore(name, region);
|
|
224
|
-
console.log(success(`Store created successfully!`));
|
|
225
|
-
console.log(info(`Project slug: ${result.project.slug}`));
|
|
226
|
-
console.log(info(`Dashboard: https://cloud.saleor.io/organizations/default/projects/${result.project.slug}`));
|
|
227
|
-
} catch (err) {
|
|
228
|
-
console.log(error(`Failed to create store: ${err}`));
|
|
229
|
-
process.exit(1);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
async function listStores() {
|
|
233
|
-
const token = requireToken();
|
|
234
|
-
const client = new SaleorCloudClient(token);
|
|
235
|
-
console.log(info("Fetching organizations..."));
|
|
236
|
-
try {
|
|
237
|
-
const { organizations } = await client.getOrganizations();
|
|
238
|
-
if (organizations.length === 0) {
|
|
239
|
-
console.log(info("No organizations found. Create one at https://cloud.saleor.io"));
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
console.log(success(`Found ${organizations.length} organization(s):
|
|
243
|
-
`));
|
|
244
|
-
for (const org of organizations) {
|
|
245
|
-
console.log(` ${org.name} (${org.slug})`);
|
|
246
|
-
console.log(` Email: ${org.owner_email}`);
|
|
247
|
-
console.log(` Created: ${new Date(org.created).toLocaleDateString()}`);
|
|
248
|
-
console.log();
|
|
249
|
-
}
|
|
250
|
-
} catch (err) {
|
|
251
|
-
console.log(error(`Failed to list stores: ${err}`));
|
|
252
|
-
process.exit(1);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
async function createEnvironment(organizationSlug, name) {
|
|
256
|
-
const token = requireToken();
|
|
257
|
-
const client = new SaleorCloudClient(token);
|
|
258
|
-
console.log(info(`Creating environment: ${name} for organization ${organizationSlug}...`));
|
|
259
|
-
try {
|
|
260
|
-
const { environment } = await client.createEnvironment(organizationSlug, "default", name, "us-east-1");
|
|
261
|
-
console.log(success(`Environment created successfully!`));
|
|
262
|
-
console.log(info(`Environment key: ${environment.key}`));
|
|
263
|
-
console.log(info(`Domain: ${environment.domain}`));
|
|
264
|
-
} catch (err) {
|
|
265
|
-
console.log(error(`Failed to create environment: ${err}`));
|
|
266
|
-
process.exit(1);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// src/cli/commands/store.ts
|
|
271
|
-
async function ensureToken() {
|
|
272
|
-
if (!process.env.SALEOR_CLOUD_TOKEN) {
|
|
273
|
-
await promptAndSaveToken();
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
var storeCommands = {
|
|
277
|
-
command: "store <action>",
|
|
278
|
-
describe: "Manage Saleor Cloud stores",
|
|
279
|
-
builder: (yargs) => yargs.command({
|
|
280
|
-
command: "create",
|
|
281
|
-
describe: "Create a new Saleor Cloud store",
|
|
282
|
-
builder: (yargs2) => yargs2.option("name", {
|
|
283
|
-
alias: "n",
|
|
284
|
-
type: "string",
|
|
285
|
-
description: "Store name",
|
|
286
|
-
demandOption: true
|
|
287
|
-
}).option("region", {
|
|
288
|
-
alias: "r",
|
|
289
|
-
type: "string",
|
|
290
|
-
description: "Region (e.g., us-east-1)",
|
|
291
|
-
default: "us-east-1"
|
|
292
|
-
}),
|
|
293
|
-
handler: async (argv) => {
|
|
294
|
-
await ensureToken();
|
|
295
|
-
await createStore(argv.name, argv.region);
|
|
296
|
-
}
|
|
297
|
-
}).command({
|
|
298
|
-
command: "list",
|
|
299
|
-
describe: "List your Saleor Cloud stores",
|
|
300
|
-
builder: (yargs2) => yargs2,
|
|
301
|
-
handler: async () => {
|
|
302
|
-
await ensureToken();
|
|
303
|
-
await listStores();
|
|
304
|
-
}
|
|
305
|
-
}).command({
|
|
306
|
-
command: "env <action>",
|
|
307
|
-
describe: "Manage store environments",
|
|
308
|
-
builder: (yargs2) => yargs2.command({
|
|
309
|
-
command: "create",
|
|
310
|
-
describe: "Create a new environment",
|
|
311
|
-
builder: (yargs3) => yargs3.option("store", {
|
|
312
|
-
alias: "s",
|
|
313
|
-
type: "string",
|
|
314
|
-
description: "Store ID",
|
|
315
|
-
demandOption: true
|
|
316
|
-
}).option("name", {
|
|
317
|
-
alias: "n",
|
|
318
|
-
type: "string",
|
|
319
|
-
description: "Environment name",
|
|
320
|
-
demandOption: true
|
|
321
|
-
}),
|
|
322
|
-
handler: async (argv) => {
|
|
323
|
-
await ensureToken();
|
|
324
|
-
await createEnvironment(argv.store, argv.name);
|
|
325
|
-
}
|
|
326
|
-
})
|
|
327
|
-
})
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
// src/commands/app.ts
|
|
331
|
-
var APP_TEMPLATES = {
|
|
332
|
-
"dashboard-extension": {
|
|
333
|
-
repo: "https://github.com/saleor/saleor-app-sdk",
|
|
334
|
-
description: "Dashboard Extension App"
|
|
335
|
-
},
|
|
336
|
-
payment: {
|
|
337
|
-
repo: "https://github.com/saleor/saleor-apps",
|
|
338
|
-
description: "Payment App"
|
|
339
|
-
},
|
|
340
|
-
webhook: {
|
|
341
|
-
repo: "https://github.com/saleor/saleor-webhook-template",
|
|
342
|
-
description: "Webhook Handler"
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
var PAYMENT_APP_URLS = {
|
|
346
|
-
dummy: "https://dummy-payment.saleor.io",
|
|
347
|
-
stripe: "https://stripe-payment.saleor.io"
|
|
348
|
-
};
|
|
349
|
-
async function createApp(name, type, environmentId, provider) {
|
|
350
|
-
console.log(info(`Creating ${type} app: ${name}`));
|
|
351
|
-
if (type === "payment") {
|
|
352
|
-
const paymentProvider = provider || "dummy";
|
|
353
|
-
console.log(info(`Payment provider: ${paymentProvider}`));
|
|
354
|
-
console.log(info(`Using hosted payment app: ${PAYMENT_APP_URLS[paymentProvider]}`));
|
|
355
|
-
if (environmentId) {
|
|
356
|
-
await registerHostedApp(environmentId, name, paymentProvider);
|
|
357
|
-
} else {
|
|
358
|
-
console.log(success(`
|
|
359
|
-
Payment app "${name}" configured to use ${PAYMENT_APP_URLS[paymentProvider]}`));
|
|
360
|
-
console.log(info(`
|
|
361
|
-
To complete setup:`));
|
|
362
|
-
console.log(info(`1. Go to your dashboard at https://cloud.saleor.io`));
|
|
363
|
-
console.log(info(`2. Navigate to Apps > Third party apps`));
|
|
364
|
-
console.log(info(`3. Add the ${paymentProvider} payment app from ${PAYMENT_APP_URLS[paymentProvider]}`));
|
|
365
|
-
}
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
const template = APP_TEMPLATES[type];
|
|
369
|
-
console.log(info(`Cloning template from: ${template.repo}`));
|
|
370
|
-
try {
|
|
371
|
-
const { spawn } = await import("child_process");
|
|
372
|
-
const child = spawn("git", ["clone", template.repo, name], {
|
|
373
|
-
stdio: "inherit"
|
|
374
|
-
});
|
|
375
|
-
child.on("close", (code) => {
|
|
376
|
-
if (code === 0) {
|
|
377
|
-
console.log(success(`
|
|
378
|
-
${type} app "${name}" created successfully!`));
|
|
379
|
-
console.log(info(`
|
|
380
|
-
To get started:`));
|
|
381
|
-
console.log(info(`cd ${name}`));
|
|
382
|
-
console.log(info(`npm install`));
|
|
383
|
-
console.log(info(`npm run dev`));
|
|
384
|
-
if (environmentId) {
|
|
385
|
-
console.log(info(`
|
|
386
|
-
Registering app with environment ${environmentId}...`));
|
|
387
|
-
registerLocalApp(environmentId, name, type);
|
|
388
|
-
}
|
|
389
|
-
} else {
|
|
390
|
-
console.log(error(`Failed to clone template (exit code: ${code})`));
|
|
391
|
-
process.exit(1);
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
} catch (err) {
|
|
395
|
-
console.log(error(`Failed to create app: ${err}`));
|
|
396
|
-
process.exit(1);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
async function registerHostedApp(environmentId, name, provider) {
|
|
400
|
-
const token = requireToken();
|
|
401
|
-
const client = new SaleorCloudClient(token);
|
|
402
|
-
console.log(info(`Registering hosted ${provider} payment app with environment...`));
|
|
403
|
-
try {
|
|
404
|
-
const result = await client.registerApp(environmentId, "payment", name);
|
|
405
|
-
console.log(success(`Payment app registered successfully!`));
|
|
406
|
-
console.log(info(`App ID: ${result.app.id}`));
|
|
407
|
-
console.log(info(`Payment URL: ${PAYMENT_APP_URLS[provider]}`));
|
|
408
|
-
} catch (err) {
|
|
409
|
-
console.log(error(`Failed to register app: ${err}`));
|
|
410
|
-
process.exit(1);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
async function registerLocalApp(environmentId, name, type) {
|
|
414
|
-
const token = requireToken();
|
|
415
|
-
const client = new SaleorCloudClient(token);
|
|
416
|
-
try {
|
|
417
|
-
const result = await client.registerApp(environmentId, type, name);
|
|
418
|
-
console.log(success(`App registered with environment!`));
|
|
419
|
-
console.log(info(`App ID: ${result.app.id}`));
|
|
420
|
-
} catch (err) {
|
|
421
|
-
console.log(warning(`Could not register app automatically: ${err}`));
|
|
422
|
-
console.log(info(`You can register manually in the dashboard.`));
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
function warning(msg) {
|
|
426
|
-
console.log(`\x1B[33m${msg}\x1B[0m`);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// src/cli/commands/app.ts
|
|
430
|
-
async function ensureToken2() {
|
|
431
|
-
if (!process.env.SALEOR_CLOUD_TOKEN) {
|
|
432
|
-
await promptAndSaveToken();
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
var appCommands = {
|
|
436
|
-
command: "app <action>",
|
|
437
|
-
describe: "Scaffold Saleor apps",
|
|
438
|
-
builder: (yargs) => yargs.command({
|
|
439
|
-
command: "create",
|
|
440
|
-
describe: "Create a new Saleor app",
|
|
441
|
-
builder: (yargs2) => yargs2.option("name", {
|
|
442
|
-
alias: "n",
|
|
443
|
-
type: "string",
|
|
444
|
-
description: "App name",
|
|
445
|
-
demandOption: true
|
|
446
|
-
}).option("type", {
|
|
447
|
-
alias: "t",
|
|
448
|
-
type: "string",
|
|
449
|
-
choices: ["dashboard-extension", "payment", "webhook"],
|
|
450
|
-
description: "App type",
|
|
451
|
-
demandOption: true
|
|
452
|
-
}).option("provider", {
|
|
453
|
-
alias: "p",
|
|
454
|
-
type: "string",
|
|
455
|
-
choices: ["dummy", "stripe"],
|
|
456
|
-
description: "Payment provider (for payment apps)",
|
|
457
|
-
default: "dummy"
|
|
458
|
-
}).option("environment", {
|
|
459
|
-
alias: "e",
|
|
460
|
-
type: "string",
|
|
461
|
-
description: "Environment ID to register app with"
|
|
462
|
-
}),
|
|
463
|
-
handler: async (argv) => {
|
|
464
|
-
if (argv.environment) {
|
|
465
|
-
await ensureToken2();
|
|
466
|
-
}
|
|
467
|
-
await createApp(argv.name, argv.type, argv.environment, argv.provider);
|
|
468
|
-
}
|
|
469
|
-
})
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
// src/agents/setup.ts
|
|
473
|
-
import { writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync2 } from "fs";
|
|
474
|
-
import { spawnSync } from "child_process";
|
|
475
|
-
import { join as join2 } from "path";
|
|
476
|
-
var AGENT_PATHS = {
|
|
477
|
-
opencode: {
|
|
478
|
-
skills: ".agents/skills",
|
|
479
|
-
agentsMd: "AGENTS.md",
|
|
480
|
-
mcpJson: ".mcp.json"
|
|
481
|
-
},
|
|
482
|
-
claude: {
|
|
483
|
-
skills: ".claude/skills",
|
|
484
|
-
agentsMd: "CLAUDE.md",
|
|
485
|
-
mcpJson: ".mcp.json"
|
|
486
|
-
},
|
|
487
|
-
openclaw: {
|
|
488
|
-
skills: ".openclaw/skills",
|
|
489
|
-
agentsMd: "AGENTS.md",
|
|
490
|
-
mcpJson: ".mcp.json"
|
|
491
|
-
},
|
|
492
|
-
nanobot: {
|
|
493
|
-
skills: ".nanobot/skills",
|
|
494
|
-
agentsMd: "AGENTS.md",
|
|
495
|
-
mcpJson: ".mcp.json"
|
|
496
|
-
}
|
|
497
|
-
};
|
|
498
|
-
var SKILLS = [
|
|
499
|
-
"saleor-app",
|
|
500
|
-
"saleor-configurator",
|
|
501
|
-
"saleor-core",
|
|
502
|
-
"saleor-storefront"
|
|
503
|
-
];
|
|
504
|
-
async function setupAgent(projectPath = ".") {
|
|
505
|
-
info("Detecting AI agents...");
|
|
506
|
-
const detectedAgents = detectAgents(projectPath);
|
|
507
|
-
if (detectedAgents.length === 0) {
|
|
508
|
-
info("No AI agents detected. Installing skills anyway...");
|
|
509
|
-
installSkills(projectPath, "opencode");
|
|
510
|
-
createAgentsMd(projectPath);
|
|
511
|
-
createMcpConfig(projectPath);
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
info(`Detected agents: ${detectedAgents.map((a) => a.name).join(", ")}
|
|
515
|
-
`);
|
|
516
|
-
for (const agent of detectedAgents) {
|
|
517
|
-
info(`Configuring ${agent.name}...`);
|
|
518
|
-
installSkills(projectPath, agent.name);
|
|
519
|
-
createAgentsMd(projectPath, agent.name);
|
|
520
|
-
createMcpConfig(projectPath);
|
|
521
|
-
success(` ${agent.name} configured!`);
|
|
522
|
-
}
|
|
523
|
-
success(`
|
|
524
|
-
Agent setup complete!`);
|
|
525
|
-
info(`
|
|
526
|
-
Skills installed: ` + SKILLS.join(", "));
|
|
527
|
-
info("AGENTS.md created with Saleor conventions");
|
|
528
|
-
info(".mcp.json configured for saleor-mcp");
|
|
529
|
-
}
|
|
530
|
-
async function installSkillsCommand(projectPath = ".") {
|
|
531
|
-
info("Installing Saleor agent skills...");
|
|
532
|
-
info("Skills: " + SKILLS.join(", "));
|
|
533
|
-
const detectedAgents = detectAgents(projectPath);
|
|
534
|
-
if (detectedAgents.length === 0) {
|
|
535
|
-
installSkills(projectPath, "opencode");
|
|
536
|
-
} else {
|
|
537
|
-
for (const agent of detectedAgents) {
|
|
538
|
-
installSkills(projectPath, agent.name);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
success(`
|
|
542
|
-
Skills installed successfully!`);
|
|
543
|
-
}
|
|
544
|
-
function detectAgents(projectPath) {
|
|
545
|
-
const detected = [];
|
|
546
|
-
const filesToCheck = [
|
|
547
|
-
{ name: "opencode", file: ".agents/skills" },
|
|
548
|
-
{ name: "claude", file: ".claude" },
|
|
549
|
-
{ name: "openclaw", file: ".openclaw" },
|
|
550
|
-
{ name: "nanobot", file: ".nanobot" }
|
|
551
|
-
];
|
|
552
|
-
for (const { name, file } of filesToCheck) {
|
|
553
|
-
const fullPath = join2(projectPath, file);
|
|
554
|
-
if (existsSync2(fullPath)) {
|
|
555
|
-
detected.push({
|
|
556
|
-
name,
|
|
557
|
-
path: fullPath,
|
|
558
|
-
skillsPath: join2(fullPath, "skills")
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
return detected;
|
|
563
|
-
}
|
|
564
|
-
function installSkills(projectPath, agentName) {
|
|
565
|
-
const agentPaths = AGENT_PATHS[agentName];
|
|
566
|
-
const skillsDir = join2(projectPath, agentPaths.skills);
|
|
567
|
-
mkdirSync(skillsDir, { recursive: true });
|
|
568
|
-
info(` Installing skills to ${skillsDir}...`);
|
|
569
|
-
const skillUrl = "https://github.com/saleor/agent-skills";
|
|
570
|
-
const baseDir = join2(skillsDir, "..");
|
|
571
|
-
try {
|
|
572
|
-
const result = spawnSync("git", ["clone", "--depth", "1", skillUrl, "skills"], {
|
|
573
|
-
cwd: baseDir,
|
|
574
|
-
stdio: "pipe"
|
|
575
|
-
});
|
|
576
|
-
if (result.status === 0) {
|
|
577
|
-
for (const skill of SKILLS) {
|
|
578
|
-
info(` Installed ${skill}`);
|
|
579
|
-
}
|
|
580
|
-
success(` Skills installed to ${skillsDir}`);
|
|
581
|
-
} else {
|
|
582
|
-
info(` Could not clone skills, skipping...`);
|
|
583
|
-
}
|
|
584
|
-
} catch {
|
|
585
|
-
info(` Could not clone skills, skipping...`);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
function createAgentsMd(projectPath, agentName = "opencode") {
|
|
589
|
-
const agentsMdContent = `# Saleor Development Guide
|
|
590
|
-
|
|
591
|
-
This project uses Saleor e-commerce platform.
|
|
592
|
-
|
|
593
|
-
## Commands
|
|
594
|
-
|
|
595
|
-
\`\`\`bash
|
|
596
|
-
# Development
|
|
597
|
-
npm run dev
|
|
598
|
-
|
|
599
|
-
# Build
|
|
600
|
-
npm run build
|
|
601
|
-
|
|
602
|
-
# Test
|
|
603
|
-
npm run test
|
|
604
|
-
|
|
605
|
-
# Lint
|
|
606
|
-
npm run lint
|
|
607
|
-
\`\`\`
|
|
608
|
-
|
|
609
|
-
## Saleor Cloud
|
|
610
|
-
|
|
611
|
-
- Dashboard: https://cloud.saleor.io
|
|
612
|
-
- Documentation: https://docs.saleor.io
|
|
613
|
-
- API Reference: https://docs.saleor.io/api
|
|
614
|
-
|
|
615
|
-
## Saleor Skills
|
|
616
|
-
|
|
617
|
-
This project includes Saleor agent skills:
|
|
618
|
-
- saleor-app: App development patterns
|
|
619
|
-
- saleor-configurator: Config as code
|
|
620
|
-
- saleor-core: Backend internals
|
|
621
|
-
- saleor-storefront: Storefront patterns
|
|
622
|
-
|
|
623
|
-
## MCP Server
|
|
624
|
-
|
|
625
|
-
Configure saleor-mcp for AI agent capabilities:
|
|
626
|
-
\`\`\`json
|
|
627
|
-
{
|
|
628
|
-
"mcpServers": {
|
|
629
|
-
"saleor": {
|
|
630
|
-
"url": "https://mcp.saleor.app"
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
\`\`\`
|
|
635
|
-
`;
|
|
636
|
-
const agentsMdPath = join2(projectPath, "AGENTS.md");
|
|
637
|
-
writeFileSync2(agentsMdPath, agentsMdContent);
|
|
638
|
-
info(` Created AGENTS.md`);
|
|
639
|
-
}
|
|
640
|
-
function createMcpConfig(projectPath) {
|
|
641
|
-
const mcpConfig = {
|
|
642
|
-
mcpServers: {
|
|
643
|
-
saleor: {
|
|
644
|
-
url: "https://mcp.saleor.app"
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
};
|
|
648
|
-
const mcpPath = join2(projectPath, ".mcp.json");
|
|
649
|
-
writeFileSync2(mcpPath, JSON.stringify(mcpConfig, null, 2));
|
|
650
|
-
info(` Created .mcp.json`);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// src/cli/commands/agent.ts
|
|
654
|
-
var agentCommands = {
|
|
655
|
-
command: "agent <action>",
|
|
656
|
-
describe: "Configure AI agents for Saleor",
|
|
657
|
-
builder: (yargs) => yargs.command({
|
|
658
|
-
command: "setup",
|
|
659
|
-
describe: "Setup AI agent with Saleor skills and MCP",
|
|
660
|
-
builder: (yargs2) => yargs2.option("path", {
|
|
661
|
-
alias: "p",
|
|
662
|
-
type: "string",
|
|
663
|
-
description: "Project path",
|
|
664
|
-
default: "."
|
|
665
|
-
}),
|
|
666
|
-
handler: async (argv) => {
|
|
667
|
-
await setupAgent(argv.path);
|
|
668
|
-
}
|
|
669
|
-
}).command({
|
|
670
|
-
command: "skills",
|
|
671
|
-
describe: "Install Saleor agent skills",
|
|
672
|
-
builder: (yargs2) => yargs2.command({
|
|
673
|
-
command: "install",
|
|
674
|
-
describe: "Install Saleor skills",
|
|
675
|
-
builder: (yargs3) => yargs3.option("path", {
|
|
676
|
-
alias: "p",
|
|
677
|
-
type: "string",
|
|
678
|
-
description: "Project path",
|
|
679
|
-
default: "."
|
|
680
|
-
}),
|
|
681
|
-
handler: async (argv) => {
|
|
682
|
-
await installSkillsCommand(argv.path);
|
|
683
|
-
}
|
|
684
|
-
})
|
|
685
|
-
})
|
|
686
|
-
};
|
|
687
|
-
|
|
688
|
-
// src/cli/commands/config.ts
|
|
689
|
-
var configCommands = {
|
|
690
|
-
command: "config <action>",
|
|
691
|
-
describe: "Manage Saleor configuration",
|
|
692
|
-
builder: (yargs) => yargs.command({
|
|
693
|
-
command: "deploy",
|
|
694
|
-
describe: "Deploy configuration to a store",
|
|
695
|
-
builder: (yargs2) => yargs2.option("store", {
|
|
696
|
-
alias: "s",
|
|
697
|
-
type: "string",
|
|
698
|
-
description: "Store ID",
|
|
699
|
-
demandOption: true
|
|
700
|
-
}),
|
|
701
|
-
handler: async (argv) => {
|
|
702
|
-
console.log(`Deploying config to store: ${argv.store}`);
|
|
703
|
-
console.log("Config deployment not yet implemented");
|
|
704
|
-
}
|
|
705
|
-
}).command({
|
|
706
|
-
command: "introspect",
|
|
707
|
-
describe: "Introspect current store configuration",
|
|
708
|
-
builder: (yargs2) => yargs2.option("store", {
|
|
709
|
-
alias: "s",
|
|
710
|
-
type: "string",
|
|
711
|
-
description: "Store ID",
|
|
712
|
-
demandOption: true
|
|
713
|
-
}),
|
|
714
|
-
handler: async (argv) => {
|
|
715
|
-
console.log(`Introspecting store: ${argv.store}`);
|
|
716
|
-
console.log("Config introspection not yet implemented");
|
|
717
|
-
}
|
|
718
|
-
})
|
|
719
|
-
};
|
|
720
|
-
|
|
721
|
-
// src/cli/index.ts
|
|
722
|
-
yargs(hideBin(process.argv)).command(storeCommands).command(appCommands).command(agentCommands).command(configCommands).demandCommand(1, "You must provide a command").strict().parse();
|