@dk/jolly 0.1.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.
Files changed (44) hide show
  1. package/.env.example +3 -0
  2. package/.mcp.json +7 -0
  3. package/.sisyphus/boulder.json +13 -0
  4. package/.sisyphus/notepads/saleor-agent-cli/decisions.md +11 -0
  5. package/.sisyphus/notepads/saleor-agent-cli/issues.md +6 -0
  6. package/.sisyphus/notepads/saleor-agent-cli/learnings.md +6 -0
  7. package/.sisyphus/plans/saleor-agent-cli.md +600 -0
  8. package/AGENTS.md +46 -0
  9. package/README.md +121 -0
  10. package/bun.lock +65 -0
  11. package/bunfig.toml +8 -0
  12. package/dist/agent.js +259 -0
  13. package/dist/bootstrap.js +492 -0
  14. package/dist/index.js +5798 -0
  15. package/package.json +29 -0
  16. package/src/agents/index.ts +1 -0
  17. package/src/agents/setup.ts +210 -0
  18. package/src/api/auth.ts +21 -0
  19. package/src/api/client.ts +78 -0
  20. package/src/api/endpoints.ts +8 -0
  21. package/src/api/index.ts +4 -0
  22. package/src/cli/agent.ts +26 -0
  23. package/src/cli/bootstrap.ts +24 -0
  24. package/src/cli/commands/agent.ts +40 -0
  25. package/src/cli/commands/app.ts +51 -0
  26. package/src/cli/commands/config.ts +38 -0
  27. package/src/cli/commands/store.ts +65 -0
  28. package/src/cli/index.ts +16 -0
  29. package/src/commands/app.ts +126 -0
  30. package/src/commands/index.ts +1 -0
  31. package/src/commands/store.ts +64 -0
  32. package/src/test/command-handlers.test.ts +227 -0
  33. package/src/test/e2e-flows.test.ts +212 -0
  34. package/src/test/entry-points.test.ts +123 -0
  35. package/src/test/error-handling.test.ts +137 -0
  36. package/src/test/helpers.ts +49 -0
  37. package/src/test/index.ts +1 -0
  38. package/src/test/mocks.ts +132 -0
  39. package/src/test/setup.ts +29 -0
  40. package/src/tui/components.ts +77 -0
  41. package/src/tui/index.ts +3 -0
  42. package/src/tui/renderer.ts +34 -0
  43. package/src/tui/theme.ts +38 -0
  44. package/tsconfig.json +20 -0
package/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # Jolly - Saleor CLI for AI Agents
2
+
3
+ Bootstraps Saleor projects and configures AI agents with Saleor skills.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @saleor/jolly
9
+ ```
10
+
11
+ ## Commands
12
+
13
+ ### Store Management
14
+
15
+ ```bash
16
+ # Create a new Saleor Cloud store
17
+ jolly store create --name my-store
18
+
19
+ # Create with specific region
20
+ jolly store create --name my-store --region eu-west-1
21
+
22
+ # List your stores
23
+ jolly store list
24
+
25
+ # Create environment
26
+ jolly store env create --store <store-id> --name production
27
+ ```
28
+
29
+ ### App Scaffolding
30
+
31
+ ```bash
32
+ # Create a dashboard extension
33
+ jolly app create --name my-dashboard --type dashboard-extension
34
+
35
+ # Create a payment app (hosted)
36
+ jolly app create --name my-payment --type payment --provider stripe
37
+
38
+ # Create a webhook handler
39
+ jolly app create --name my-webhook --type webhook
40
+ ```
41
+
42
+ ### Agent Setup
43
+
44
+ ```bash
45
+ # Setup AI agent with Saleor skills and MCP
46
+ jolly agent setup
47
+
48
+ # Install skills only
49
+ jolly agent skills install
50
+
51
+ # Setup in specific directory
52
+ jolly agent setup --path /my/project
53
+ ```
54
+
55
+ ### Configuration
56
+
57
+ ```bash
58
+ # Deploy configuration to store
59
+ jolly config deploy --store <store-id>
60
+
61
+ # Introspect current configuration
62
+ jolly config introspect --store <store-id>
63
+ ```
64
+
65
+ ## npm Entry Points
66
+
67
+ ```bash
68
+ # Bootstrap new Saleor project
69
+ npm create @saleor/jolly my-project
70
+
71
+ # Configure AI agent for Saleor
72
+ npm init @saleor/jolly
73
+ ```
74
+
75
+ ## Environment Variables
76
+
77
+ You can set environment variables via a `.env` file:
78
+
79
+ ```bash
80
+ # Copy the example file
81
+ cp .env.example .env
82
+
83
+ # Edit with your token
84
+ SALEOR_CLOUD_TOKEN=your-token-here
85
+ ```
86
+
87
+ Or export directly:
88
+
89
+ ```bash
90
+ export SALEOR_CLOUD_TOKEN=your-token-here
91
+ ```
92
+
93
+ Get your token at: https://cloud.saleor.io/settings/api-tokens
94
+
95
+ ## Development
96
+
97
+ ```bash
98
+ # Install dependencies
99
+ bun install
100
+
101
+ # Build
102
+ bun run build
103
+
104
+ # Run tests
105
+ bun test
106
+
107
+ # Type check
108
+ bun run typecheck
109
+ ```
110
+
111
+ ## Architecture
112
+
113
+ - **CLI Framework**: yargs for argument parsing
114
+ - **Runtime**: Bun
115
+ - **API Client**: Direct Saleor Cloud API integration
116
+ - **Agent Skills**: saleor/agent-skills from GitHub
117
+ - **MCP**: Official saleor-mcp at mcp.saleor.app
118
+
119
+ ## License
120
+
121
+ MIT
package/bun.lock ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "@saleor/jolly",
7
+ "dependencies": {
8
+ "dotenv": "^17.4.0",
9
+ "yargs": "^17.7.2",
10
+ },
11
+ "devDependencies": {
12
+ "@types/yargs": "^17.0.32",
13
+ "bun-types": "^1.3.11",
14
+ "typescript": "^5.4.0",
15
+ },
16
+ },
17
+ },
18
+ "packages": {
19
+ "@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="],
20
+
21
+ "@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="],
22
+
23
+ "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="],
24
+
25
+ "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
26
+
27
+ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
28
+
29
+ "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="],
30
+
31
+ "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
32
+
33
+ "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
34
+
35
+ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
36
+
37
+ "dotenv": ["dotenv@17.4.0", "", {}, "sha512-kCKF62fwtzwYm0IGBNjRUjtJgMfGapII+FslMHIjMR5KTnwEmBmWLDRSnc3XSNP8bNy34tekgQyDT0hr7pERRQ=="],
38
+
39
+ "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
40
+
41
+ "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
42
+
43
+ "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
44
+
45
+ "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
46
+
47
+ "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
48
+
49
+ "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
50
+
51
+ "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
52
+
53
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
54
+
55
+ "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
56
+
57
+ "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
58
+
59
+ "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
60
+
61
+ "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
62
+
63
+ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
64
+ }
65
+ }
package/bunfig.toml ADDED
@@ -0,0 +1,8 @@
1
+ [build]
2
+ target = "bun"
3
+
4
+ [install]
5
+ peer = true
6
+
7
+ [test]
8
+ root = "src/test"
package/dist/agent.js ADDED
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+
4
+ // src/agents/setup.ts
5
+ import { writeFileSync, mkdirSync, existsSync } from "fs";
6
+ import { spawnSync } from "child_process";
7
+ import { join } from "path";
8
+
9
+ // src/tui/theme.ts
10
+ var theme = {
11
+ reset: "\x1B[0m",
12
+ bold: "\x1B[1m",
13
+ dim: "\x1B[2m",
14
+ italic: "\x1B[3m",
15
+ underline: "\x1B[4m",
16
+ fg: {
17
+ black: "\x1B[30m",
18
+ red: "\x1B[31m",
19
+ green: "\x1B[32m",
20
+ yellow: "\x1B[33m",
21
+ blue: "\x1B[34m",
22
+ magenta: "\x1B[35m",
23
+ cyan: "\x1B[36m",
24
+ white: "\x1B[37m",
25
+ gray: "\x1B[90m",
26
+ brightBlack: "\x1B[30;1m",
27
+ brightRed: "\x1B[31;1m",
28
+ brightGreen: "\x1B[32;1m",
29
+ brightYellow: "\x1B[33;1m",
30
+ brightBlue: "\x1B[34;1m",
31
+ brightMagenta: "\x1B[35;1m",
32
+ brightCyan: "\x1B[36;1m",
33
+ brightWhite: "\x1B[37;1m"
34
+ },
35
+ bg: {
36
+ black: "\x1B[40m",
37
+ red: "\x1B[41m",
38
+ green: "\x1B[42m",
39
+ yellow: "\x1B[43m",
40
+ blue: "\x1B[44m",
41
+ magenta: "\x1B[45m",
42
+ cyan: "\x1B[46m",
43
+ white: "\x1B[47m"
44
+ }
45
+ };
46
+
47
+ // src/tui/components.ts
48
+ function text(content, color) {
49
+ return `${color || theme.fg.white}${content}${theme.reset}`;
50
+ }
51
+ function success(msg) {
52
+ return text(msg, theme.fg.green);
53
+ }
54
+ function info(msg) {
55
+ return text(msg, theme.fg.cyan);
56
+ }
57
+
58
+ // src/agents/setup.ts
59
+ var AGENT_PATHS = {
60
+ opencode: {
61
+ skills: ".agents/skills",
62
+ agentsMd: "AGENTS.md",
63
+ mcpJson: ".mcp.json"
64
+ },
65
+ claude: {
66
+ skills: ".claude/skills",
67
+ agentsMd: "CLAUDE.md",
68
+ mcpJson: ".mcp.json"
69
+ },
70
+ openclaw: {
71
+ skills: ".openclaw/skills",
72
+ agentsMd: "AGENTS.md",
73
+ mcpJson: ".mcp.json"
74
+ },
75
+ nanobot: {
76
+ skills: ".nanobot/skills",
77
+ agentsMd: "AGENTS.md",
78
+ mcpJson: ".mcp.json"
79
+ }
80
+ };
81
+ var SKILLS = [
82
+ "saleor-app",
83
+ "saleor-configurator",
84
+ "saleor-core",
85
+ "saleor-storefront"
86
+ ];
87
+ async function setupAgent(projectPath = ".") {
88
+ info("Detecting AI agents...");
89
+ const detectedAgents = detectAgents(projectPath);
90
+ if (detectedAgents.length === 0) {
91
+ info("No AI agents detected. Installing skills anyway...");
92
+ installSkills(projectPath, "opencode");
93
+ createAgentsMd(projectPath);
94
+ createMcpConfig(projectPath);
95
+ return;
96
+ }
97
+ info(`Detected agents: ${detectedAgents.map((a) => a.name).join(", ")}
98
+ `);
99
+ for (const agent of detectedAgents) {
100
+ info(`Configuring ${agent.name}...`);
101
+ installSkills(projectPath, agent.name);
102
+ createAgentsMd(projectPath, agent.name);
103
+ createMcpConfig(projectPath);
104
+ success(` ${agent.name} configured!`);
105
+ }
106
+ success(`
107
+ Agent setup complete!`);
108
+ info(`
109
+ Skills installed: ` + SKILLS.join(", "));
110
+ info("AGENTS.md created with Saleor conventions");
111
+ info(".mcp.json configured for saleor-mcp");
112
+ }
113
+ async function installSkillsCommand(projectPath = ".") {
114
+ info("Installing Saleor agent skills...");
115
+ info("Skills: " + SKILLS.join(", "));
116
+ const detectedAgents = detectAgents(projectPath);
117
+ if (detectedAgents.length === 0) {
118
+ installSkills(projectPath, "opencode");
119
+ } else {
120
+ for (const agent of detectedAgents) {
121
+ installSkills(projectPath, agent.name);
122
+ }
123
+ }
124
+ success(`
125
+ Skills installed successfully!`);
126
+ }
127
+ function detectAgents(projectPath) {
128
+ const detected = [];
129
+ const filesToCheck = [
130
+ { name: "opencode", file: ".agents/skills" },
131
+ { name: "claude", file: ".claude" },
132
+ { name: "openclaw", file: ".openclaw" },
133
+ { name: "nanobot", file: ".nanobot" }
134
+ ];
135
+ for (const { name, file } of filesToCheck) {
136
+ const fullPath = join(projectPath, file);
137
+ if (existsSync(fullPath)) {
138
+ detected.push({
139
+ name,
140
+ path: fullPath,
141
+ skillsPath: join(fullPath, "skills")
142
+ });
143
+ }
144
+ }
145
+ return detected;
146
+ }
147
+ function installSkills(projectPath, agentName) {
148
+ const agentPaths = AGENT_PATHS[agentName];
149
+ const skillsDir = join(projectPath, agentPaths.skills);
150
+ mkdirSync(skillsDir, { recursive: true });
151
+ info(` Installing skills to ${skillsDir}...`);
152
+ const skillUrl = "https://github.com/saleor/agent-skills";
153
+ const baseDir = join(skillsDir, "..");
154
+ try {
155
+ const result = spawnSync("git", ["clone", "--depth", "1", skillUrl, "skills"], {
156
+ cwd: baseDir,
157
+ stdio: "pipe"
158
+ });
159
+ if (result.status === 0) {
160
+ for (const skill of SKILLS) {
161
+ info(` Installed ${skill}`);
162
+ }
163
+ success(` Skills installed to ${skillsDir}`);
164
+ } else {
165
+ info(` Could not clone skills, skipping...`);
166
+ }
167
+ } catch {
168
+ info(` Could not clone skills, skipping...`);
169
+ }
170
+ }
171
+ function createAgentsMd(projectPath, agentName = "opencode") {
172
+ const agentsMdContent = `# Saleor Development Guide
173
+
174
+ This project uses Saleor e-commerce platform.
175
+
176
+ ## Commands
177
+
178
+ \`\`\`bash
179
+ # Development
180
+ npm run dev
181
+
182
+ # Build
183
+ npm run build
184
+
185
+ # Test
186
+ npm run test
187
+
188
+ # Lint
189
+ npm run lint
190
+ \`\`\`
191
+
192
+ ## Saleor Cloud
193
+
194
+ - Dashboard: https://cloud.saleor.io
195
+ - Documentation: https://docs.saleor.io
196
+ - API Reference: https://docs.saleor.io/api
197
+
198
+ ## Saleor Skills
199
+
200
+ This project includes Saleor agent skills:
201
+ - saleor-app: App development patterns
202
+ - saleor-configurator: Config as code
203
+ - saleor-core: Backend internals
204
+ - saleor-storefront: Storefront patterns
205
+
206
+ ## MCP Server
207
+
208
+ Configure saleor-mcp for AI agent capabilities:
209
+ \`\`\`json
210
+ {
211
+ "mcpServers": {
212
+ "saleor": {
213
+ "url": "https://mcp.saleor.app"
214
+ }
215
+ }
216
+ }
217
+ \`\`\`
218
+ `;
219
+ const agentsMdPath = join(projectPath, "AGENTS.md");
220
+ writeFileSync(agentsMdPath, agentsMdContent);
221
+ info(` Created AGENTS.md`);
222
+ }
223
+ function createMcpConfig(projectPath) {
224
+ const mcpConfig = {
225
+ mcpServers: {
226
+ saleor: {
227
+ url: "https://mcp.saleor.app"
228
+ }
229
+ }
230
+ };
231
+ const mcpPath = join(projectPath, ".mcp.json");
232
+ writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2));
233
+ info(` Created .mcp.json`);
234
+ }
235
+
236
+ // src/cli/agent.ts
237
+ async function main() {
238
+ const args = process.argv.slice(2);
239
+ const action = args[0] || "setup";
240
+ if (action === "setup" || action === "install") {
241
+ console.log("Saleor Agent Setup");
242
+ console.log(`-------------------
243
+ `);
244
+ await setupAgent(".");
245
+ console.log(`
246
+ Agent configured successfully!`);
247
+ console.log("Restart your AI agent to enable Saleor capabilities.");
248
+ } else if (action === "skills") {
249
+ await installSkillsCommand(".");
250
+ } else {
251
+ console.error(`Unknown action: ${action}`);
252
+ console.log("Usage: jolly-agent [setup|skills]");
253
+ process.exit(1);
254
+ }
255
+ }
256
+ main().catch((err) => {
257
+ console.error(`Agent setup failed: ${err}`);
258
+ process.exit(1);
259
+ });