@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.
- package/.env.example +3 -0
- package/.mcp.json +7 -0
- package/.sisyphus/boulder.json +13 -0
- package/.sisyphus/notepads/saleor-agent-cli/decisions.md +11 -0
- package/.sisyphus/notepads/saleor-agent-cli/issues.md +6 -0
- package/.sisyphus/notepads/saleor-agent-cli/learnings.md +6 -0
- package/.sisyphus/plans/saleor-agent-cli.md +600 -0
- package/AGENTS.md +46 -0
- package/README.md +121 -0
- package/bun.lock +65 -0
- package/bunfig.toml +8 -0
- package/dist/agent.js +259 -0
- package/dist/bootstrap.js +492 -0
- package/dist/index.js +5798 -0
- package/package.json +29 -0
- package/src/agents/index.ts +1 -0
- package/src/agents/setup.ts +210 -0
- package/src/api/auth.ts +21 -0
- package/src/api/client.ts +78 -0
- package/src/api/endpoints.ts +8 -0
- package/src/api/index.ts +4 -0
- package/src/cli/agent.ts +26 -0
- package/src/cli/bootstrap.ts +24 -0
- package/src/cli/commands/agent.ts +40 -0
- package/src/cli/commands/app.ts +51 -0
- package/src/cli/commands/config.ts +38 -0
- package/src/cli/commands/store.ts +65 -0
- package/src/cli/index.ts +16 -0
- package/src/commands/app.ts +126 -0
- package/src/commands/index.ts +1 -0
- package/src/commands/store.ts +64 -0
- package/src/test/command-handlers.test.ts +227 -0
- package/src/test/e2e-flows.test.ts +212 -0
- package/src/test/entry-points.test.ts +123 -0
- package/src/test/error-handling.test.ts +137 -0
- package/src/test/helpers.ts +49 -0
- package/src/test/index.ts +1 -0
- package/src/test/mocks.ts +132 -0
- package/src/test/setup.ts +29 -0
- package/src/tui/components.ts +77 -0
- package/src/tui/index.ts +3 -0
- package/src/tui/renderer.ts +34 -0
- package/src/tui/theme.ts +38 -0
- package/tsconfig.json +20 -0
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dk/jolly",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Saleor project bootstrapper and agent configurator",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"jolly": "./dist/index.js",
|
|
8
|
+
"create-saleor-jolly": "./dist/bootstrap.js",
|
|
9
|
+
"init-saleor-jolly": "./dist/agent.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "bun build src/cli/index.ts --outdir=dist --target=bun && bun build src/cli/bootstrap.ts --outdir=dist --target=bun && bun build src/cli/agent.ts --outdir=dist --target=bun",
|
|
13
|
+
"dev": "bun --watch src/cli/index.ts",
|
|
14
|
+
"test": "bun test",
|
|
15
|
+
"typecheck": "bun tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"dotenv": "^17.4.0",
|
|
19
|
+
"yargs": "^17.7.2"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/yargs": "^17.0.32",
|
|
23
|
+
"bun-types": "^1.3.11",
|
|
24
|
+
"typescript": "^5.4.0"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { success, error, info } from '../tui/components.js';
|
|
5
|
+
|
|
6
|
+
interface DetectedAgent {
|
|
7
|
+
name: string;
|
|
8
|
+
path: string;
|
|
9
|
+
skillsPath: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const AGENT_PATHS = {
|
|
13
|
+
opencode: {
|
|
14
|
+
skills: '.agents/skills',
|
|
15
|
+
agentsMd: 'AGENTS.md',
|
|
16
|
+
mcpJson: '.mcp.json',
|
|
17
|
+
},
|
|
18
|
+
claude: {
|
|
19
|
+
skills: '.claude/skills',
|
|
20
|
+
agentsMd: 'CLAUDE.md',
|
|
21
|
+
mcpJson: '.mcp.json',
|
|
22
|
+
},
|
|
23
|
+
openclaw: {
|
|
24
|
+
skills: '.openclaw/skills',
|
|
25
|
+
agentsMd: 'AGENTS.md',
|
|
26
|
+
mcpJson: '.mcp.json',
|
|
27
|
+
},
|
|
28
|
+
nanobot: {
|
|
29
|
+
skills: '.nanobot/skills',
|
|
30
|
+
agentsMd: 'AGENTS.md',
|
|
31
|
+
mcpJson: '.mcp.json',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const SKILLS = [
|
|
36
|
+
'saleor-app',
|
|
37
|
+
'saleor-configurator',
|
|
38
|
+
'saleor-core',
|
|
39
|
+
'saleor-storefront',
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
export async function setupAgent(projectPath: string = '.'): Promise<void> {
|
|
43
|
+
info('Detecting AI agents...');
|
|
44
|
+
|
|
45
|
+
const detectedAgents = detectAgents(projectPath);
|
|
46
|
+
|
|
47
|
+
if (detectedAgents.length === 0) {
|
|
48
|
+
info('No AI agents detected. Installing skills anyway...');
|
|
49
|
+
installSkills(projectPath, 'opencode');
|
|
50
|
+
createAgentsMd(projectPath);
|
|
51
|
+
createMcpConfig(projectPath);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
info(`Detected agents: ${detectedAgents.map(a => a.name).join(', ')}\n`);
|
|
56
|
+
|
|
57
|
+
for (const agent of detectedAgents) {
|
|
58
|
+
info(`Configuring ${agent.name}...`);
|
|
59
|
+
installSkills(projectPath, agent.name as keyof typeof AGENT_PATHS);
|
|
60
|
+
createAgentsMd(projectPath, agent.name as keyof typeof AGENT_PATHS);
|
|
61
|
+
createMcpConfig(projectPath);
|
|
62
|
+
success(` ${agent.name} configured!`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
success('\nAgent setup complete!');
|
|
66
|
+
info('\nSkills installed: ' + SKILLS.join(', '));
|
|
67
|
+
info('AGENTS.md created with Saleor conventions');
|
|
68
|
+
info('.mcp.json configured for saleor-mcp');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function installSkillsCommand(projectPath: string = '.'): Promise<void> {
|
|
72
|
+
info('Installing Saleor agent skills...');
|
|
73
|
+
info('Skills: ' + SKILLS.join(', '));
|
|
74
|
+
|
|
75
|
+
const detectedAgents = detectAgents(projectPath);
|
|
76
|
+
|
|
77
|
+
if (detectedAgents.length === 0) {
|
|
78
|
+
installSkills(projectPath, 'opencode');
|
|
79
|
+
} else {
|
|
80
|
+
for (const agent of detectedAgents) {
|
|
81
|
+
installSkills(projectPath, agent.name as keyof typeof AGENT_PATHS);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
success('\nSkills installed successfully!');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function detectAgents(projectPath: string): DetectedAgent[] {
|
|
89
|
+
const detected: DetectedAgent[] = [];
|
|
90
|
+
|
|
91
|
+
const filesToCheck = [
|
|
92
|
+
{ name: 'opencode', file: '.agents/skills' },
|
|
93
|
+
{ name: 'claude', file: '.claude' },
|
|
94
|
+
{ name: 'openclaw', file: '.openclaw' },
|
|
95
|
+
{ name: 'nanobot', file: '.nanobot' },
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
for (const { name, file } of filesToCheck) {
|
|
99
|
+
const fullPath = join(projectPath, file);
|
|
100
|
+
if (existsSync(fullPath)) {
|
|
101
|
+
detected.push({
|
|
102
|
+
name,
|
|
103
|
+
path: fullPath,
|
|
104
|
+
skillsPath: join(fullPath, 'skills'),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return detected;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function installSkills(projectPath: string, agentName: keyof typeof AGENT_PATHS): void {
|
|
113
|
+
const agentPaths = AGENT_PATHS[agentName];
|
|
114
|
+
const skillsDir = join(projectPath, agentPaths.skills);
|
|
115
|
+
|
|
116
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
117
|
+
|
|
118
|
+
info(` Installing skills to ${skillsDir}...`);
|
|
119
|
+
|
|
120
|
+
// Skills are installed via git clone from saleor/agent-skills repo
|
|
121
|
+
// Each skill is a subdirectory in the repo
|
|
122
|
+
const skillUrl = 'https://github.com/saleor/agent-skills';
|
|
123
|
+
const baseDir = join(skillsDir, '..');
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const result = spawnSync('git', ['clone', '--depth', '1', skillUrl, 'skills'], {
|
|
127
|
+
cwd: baseDir,
|
|
128
|
+
stdio: 'pipe',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (result.status === 0) {
|
|
132
|
+
for (const skill of SKILLS) {
|
|
133
|
+
info(` Installed ${skill}`);
|
|
134
|
+
}
|
|
135
|
+
success(` Skills installed to ${skillsDir}`);
|
|
136
|
+
} else {
|
|
137
|
+
info(` Could not clone skills, skipping...`);
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
info(` Could not clone skills, skipping...`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function createAgentsMd(projectPath: string, agentName: keyof typeof AGENT_PATHS = 'opencode'): void {
|
|
145
|
+
const agentsMdContent = `# Saleor Development Guide
|
|
146
|
+
|
|
147
|
+
This project uses Saleor e-commerce platform.
|
|
148
|
+
|
|
149
|
+
## Commands
|
|
150
|
+
|
|
151
|
+
\`\`\`bash
|
|
152
|
+
# Development
|
|
153
|
+
npm run dev
|
|
154
|
+
|
|
155
|
+
# Build
|
|
156
|
+
npm run build
|
|
157
|
+
|
|
158
|
+
# Test
|
|
159
|
+
npm run test
|
|
160
|
+
|
|
161
|
+
# Lint
|
|
162
|
+
npm run lint
|
|
163
|
+
\`\`\`
|
|
164
|
+
|
|
165
|
+
## Saleor Cloud
|
|
166
|
+
|
|
167
|
+
- Dashboard: https://cloud.saleor.io
|
|
168
|
+
- Documentation: https://docs.saleor.io
|
|
169
|
+
- API Reference: https://docs.saleor.io/api
|
|
170
|
+
|
|
171
|
+
## Saleor Skills
|
|
172
|
+
|
|
173
|
+
This project includes Saleor agent skills:
|
|
174
|
+
- saleor-app: App development patterns
|
|
175
|
+
- saleor-configurator: Config as code
|
|
176
|
+
- saleor-core: Backend internals
|
|
177
|
+
- saleor-storefront: Storefront patterns
|
|
178
|
+
|
|
179
|
+
## MCP Server
|
|
180
|
+
|
|
181
|
+
Configure saleor-mcp for AI agent capabilities:
|
|
182
|
+
\`\`\`json
|
|
183
|
+
{
|
|
184
|
+
"mcpServers": {
|
|
185
|
+
"saleor": {
|
|
186
|
+
"url": "https://mcp.saleor.app"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
\`\`\`
|
|
191
|
+
`;
|
|
192
|
+
|
|
193
|
+
const agentsMdPath = join(projectPath, 'AGENTS.md');
|
|
194
|
+
writeFileSync(agentsMdPath, agentsMdContent);
|
|
195
|
+
info(` Created AGENTS.md`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function createMcpConfig(projectPath: string): void {
|
|
199
|
+
const mcpConfig = {
|
|
200
|
+
mcpServers: {
|
|
201
|
+
saleor: {
|
|
202
|
+
url: 'https://mcp.saleor.app',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const mcpPath = join(projectPath, '.mcp.json');
|
|
208
|
+
writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2));
|
|
209
|
+
info(` Created .mcp.json`);
|
|
210
|
+
}
|
package/src/api/auth.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { config } from 'dotenv';
|
|
2
|
+
|
|
3
|
+
config();
|
|
4
|
+
|
|
5
|
+
export function getToken(): string {
|
|
6
|
+
const token = process.env.SALEOR_CLOUD_TOKEN;
|
|
7
|
+
if (!token) {
|
|
8
|
+
throw new Error('SALEOR_CLOUD_TOKEN environment variable is required');
|
|
9
|
+
}
|
|
10
|
+
return token;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function requireToken(): string {
|
|
14
|
+
const token = process.env.SALEOR_CLOUD_TOKEN;
|
|
15
|
+
if (!token) {
|
|
16
|
+
console.error('Error: SALEOR_CLOUD_TOKEN environment variable is required');
|
|
17
|
+
console.error('Get your token at: https://cloud.saleor.io/settings/api-tokens');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
return token;
|
|
21
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export class SaleorCloudClient {
|
|
2
|
+
private baseUrl = 'https://cloud.saleor.io/api';
|
|
3
|
+
private token: string;
|
|
4
|
+
|
|
5
|
+
constructor(token?: string) {
|
|
6
|
+
this.token = token || process.env.SALEOR_CLOUD_TOKEN || '';
|
|
7
|
+
if (!this.token) {
|
|
8
|
+
throw new Error('SALEOR_CLOUD_TOKEN environment variable is required');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async request<T>(endpoint: string, options?: RequestInit): Promise<T> {
|
|
13
|
+
const response = await fetch(`${this.baseUrl}${endpoint}`, {
|
|
14
|
+
...options,
|
|
15
|
+
headers: {
|
|
16
|
+
'Authorization': `Bearer ${this.token}`,
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
...options?.headers,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
throw new Error(`API error: ${response.status} ${response.statusText}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return response.json();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async getStores() {
|
|
30
|
+
return this.request<{ stores: Store[] }>('/stores');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async createStore(name: string, region: string = 'us-east-1') {
|
|
34
|
+
return this.request<{ store: Store }>('/stores', {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
body: JSON.stringify({ name, region }),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getEnvironments(storeId: string) {
|
|
41
|
+
return this.request<{ environments: Environment[] }>(`/stores/${storeId}/environments`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async createEnvironment(storeId: string, name: string) {
|
|
45
|
+
return this.request<{ environment: Environment }>(`/stores/${storeId}/environments`, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
body: JSON.stringify({ name }),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async registerApp(environmentId: string, appType: string, name: string) {
|
|
52
|
+
return this.request<{ app: App }>(`/environments/${environmentId}/apps`, {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
body: JSON.stringify({ type: appType, name }),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Store {
|
|
60
|
+
id: string;
|
|
61
|
+
name: string;
|
|
62
|
+
region: string;
|
|
63
|
+
created_at: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface Environment {
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
store_id: string;
|
|
70
|
+
created_at: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface App {
|
|
74
|
+
id: string;
|
|
75
|
+
name: string;
|
|
76
|
+
type: string;
|
|
77
|
+
environment_id: string;
|
|
78
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const endpoints = {
|
|
2
|
+
stores: '/stores',
|
|
3
|
+
store: (id: string) => `/stores/${id}`,
|
|
4
|
+
environments: (storeId: string) => `/stores/${storeId}/environments`,
|
|
5
|
+
environment: (storeId: string, envId: string) => `/stores/${storeId}/environments/${envId}`,
|
|
6
|
+
apps: (environmentId: string) => `/environments/${environmentId}/apps`,
|
|
7
|
+
registerApp: '/apps/register',
|
|
8
|
+
};
|
package/src/api/index.ts
ADDED
package/src/cli/agent.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { setupAgent, installSkillsCommand } from '../agents/setup.js';
|
|
3
|
+
|
|
4
|
+
async function main() {
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const action = args[0] || 'setup';
|
|
7
|
+
|
|
8
|
+
if (action === 'setup' || action === 'install') {
|
|
9
|
+
console.log('Saleor Agent Setup');
|
|
10
|
+
console.log('-------------------\n');
|
|
11
|
+
await setupAgent('.');
|
|
12
|
+
console.log('\nAgent configured successfully!');
|
|
13
|
+
console.log('Restart your AI agent to enable Saleor capabilities.');
|
|
14
|
+
} else if (action === 'skills') {
|
|
15
|
+
await installSkillsCommand('.');
|
|
16
|
+
} else {
|
|
17
|
+
console.error(`Unknown action: ${action}`);
|
|
18
|
+
console.log('Usage: jolly-agent [setup|skills]');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
main().catch((err) => {
|
|
24
|
+
console.error(`Agent setup failed: ${err}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { createStore } from '../commands/store.js';
|
|
3
|
+
|
|
4
|
+
async function main() {
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const projectName = args[0];
|
|
7
|
+
|
|
8
|
+
if (projectName) {
|
|
9
|
+
console.log(`Bootstrapping Saleor project: ${projectName}...`);
|
|
10
|
+
await createStore(projectName, 'us-east-1');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
console.log('Saleor Store Bootstrapper');
|
|
15
|
+
console.log('------------------------\n');
|
|
16
|
+
console.log('Usage: npm create @saleor/jolly <project-name>');
|
|
17
|
+
console.log('Or: jolly store create --name <name>');
|
|
18
|
+
console.log('\nFor app scaffolding: jolly app create --name <name> --type <type>');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
main().catch((err) => {
|
|
22
|
+
console.error(`Bootstrap failed: ${err}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CommandModule } from 'yargs';
|
|
2
|
+
import { setupAgent, installSkillsCommand } from '../../agents/setup.js';
|
|
3
|
+
|
|
4
|
+
export const agentCommands: CommandModule = {
|
|
5
|
+
command: 'agent <action>',
|
|
6
|
+
describe: 'Configure AI agents for Saleor',
|
|
7
|
+
builder: (yargs) =>
|
|
8
|
+
yargs
|
|
9
|
+
.command({
|
|
10
|
+
command: 'setup',
|
|
11
|
+
describe: 'Setup AI agent with Saleor skills and MCP',
|
|
12
|
+
builder: (yargs) => yargs.option('path', {
|
|
13
|
+
alias: 'p',
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Project path',
|
|
16
|
+
default: '.',
|
|
17
|
+
}),
|
|
18
|
+
handler: async (argv) => {
|
|
19
|
+
await setupAgent(argv.path as string);
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
.command({
|
|
23
|
+
command: 'skills',
|
|
24
|
+
describe: 'Install Saleor agent skills',
|
|
25
|
+
builder: (yargs) =>
|
|
26
|
+
yargs.command({
|
|
27
|
+
command: 'install',
|
|
28
|
+
describe: 'Install Saleor skills',
|
|
29
|
+
builder: (yargs) => yargs.option('path', {
|
|
30
|
+
alias: 'p',
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'Project path',
|
|
33
|
+
default: '.',
|
|
34
|
+
}),
|
|
35
|
+
handler: async (argv) => {
|
|
36
|
+
await installSkillsCommand(argv.path as string);
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { CommandModule } from 'yargs';
|
|
2
|
+
import { createApp } from '../../commands/app.js';
|
|
3
|
+
|
|
4
|
+
type AppType = 'dashboard-extension' | 'payment' | 'webhook';
|
|
5
|
+
type PaymentProvider = 'dummy' | 'stripe';
|
|
6
|
+
|
|
7
|
+
export const appCommands: CommandModule = {
|
|
8
|
+
command: 'app <action>',
|
|
9
|
+
describe: 'Scaffold Saleor apps',
|
|
10
|
+
builder: (yargs) =>
|
|
11
|
+
yargs
|
|
12
|
+
.command({
|
|
13
|
+
command: 'create',
|
|
14
|
+
describe: 'Create a new Saleor app',
|
|
15
|
+
builder: (yargs) =>
|
|
16
|
+
yargs
|
|
17
|
+
.option('name', {
|
|
18
|
+
alias: 'n',
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'App name',
|
|
21
|
+
demandOption: true,
|
|
22
|
+
})
|
|
23
|
+
.option('type', {
|
|
24
|
+
alias: 't',
|
|
25
|
+
type: 'string',
|
|
26
|
+
choices: ['dashboard-extension', 'payment', 'webhook'],
|
|
27
|
+
description: 'App type',
|
|
28
|
+
demandOption: true,
|
|
29
|
+
})
|
|
30
|
+
.option('provider', {
|
|
31
|
+
alias: 'p',
|
|
32
|
+
type: 'string',
|
|
33
|
+
choices: ['dummy', 'stripe'],
|
|
34
|
+
description: 'Payment provider (for payment apps)',
|
|
35
|
+
default: 'dummy',
|
|
36
|
+
})
|
|
37
|
+
.option('environment', {
|
|
38
|
+
alias: 'e',
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Environment ID to register app with',
|
|
41
|
+
}),
|
|
42
|
+
handler: async (argv) => {
|
|
43
|
+
await createApp(
|
|
44
|
+
argv.name,
|
|
45
|
+
argv.type as AppType,
|
|
46
|
+
argv.environment,
|
|
47
|
+
argv.provider as PaymentProvider
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CommandModule } from 'yargs';
|
|
2
|
+
|
|
3
|
+
export const configCommands: CommandModule = {
|
|
4
|
+
command: 'config <action>',
|
|
5
|
+
describe: 'Manage Saleor configuration',
|
|
6
|
+
builder: (yargs) =>
|
|
7
|
+
yargs
|
|
8
|
+
.command({
|
|
9
|
+
command: 'deploy',
|
|
10
|
+
describe: 'Deploy configuration to a store',
|
|
11
|
+
builder: (yargs) =>
|
|
12
|
+
yargs.option('store', {
|
|
13
|
+
alias: 's',
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Store ID',
|
|
16
|
+
demandOption: true,
|
|
17
|
+
}),
|
|
18
|
+
handler: async (argv) => {
|
|
19
|
+
console.log(`Deploying config to store: ${argv.store}`);
|
|
20
|
+
console.log('Config deployment not yet implemented');
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
.command({
|
|
24
|
+
command: 'introspect',
|
|
25
|
+
describe: 'Introspect current store configuration',
|
|
26
|
+
builder: (yargs) =>
|
|
27
|
+
yargs.option('store', {
|
|
28
|
+
alias: 's',
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Store ID',
|
|
31
|
+
demandOption: true,
|
|
32
|
+
}),
|
|
33
|
+
handler: async (argv) => {
|
|
34
|
+
console.log(`Introspecting store: ${argv.store}`);
|
|
35
|
+
console.log('Config introspection not yet implemented');
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { CommandModule } from 'yargs';
|
|
2
|
+
import { createStore, listStores, createEnvironment } from '../../commands/store.js';
|
|
3
|
+
|
|
4
|
+
export const storeCommands: CommandModule = {
|
|
5
|
+
command: 'store <action>',
|
|
6
|
+
describe: 'Manage Saleor Cloud stores',
|
|
7
|
+
builder: (yargs) =>
|
|
8
|
+
yargs
|
|
9
|
+
.command({
|
|
10
|
+
command: 'create',
|
|
11
|
+
describe: 'Create a new Saleor Cloud store',
|
|
12
|
+
builder: (yargs) =>
|
|
13
|
+
yargs
|
|
14
|
+
.option('name', {
|
|
15
|
+
alias: 'n',
|
|
16
|
+
type: 'string',
|
|
17
|
+
description: 'Store name',
|
|
18
|
+
demandOption: true,
|
|
19
|
+
})
|
|
20
|
+
.option('region', {
|
|
21
|
+
alias: 'r',
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Region (e.g., us-east-1)',
|
|
24
|
+
default: 'us-east-1',
|
|
25
|
+
}),
|
|
26
|
+
handler: async (argv) => {
|
|
27
|
+
await createStore(argv.name, argv.region);
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
.command({
|
|
31
|
+
command: 'list',
|
|
32
|
+
describe: 'List your Saleor Cloud stores',
|
|
33
|
+
builder: (yargs) => yargs,
|
|
34
|
+
handler: async () => {
|
|
35
|
+
await listStores();
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
.command({
|
|
39
|
+
command: 'env <action>',
|
|
40
|
+
describe: 'Manage store environments',
|
|
41
|
+
builder: (yargs) =>
|
|
42
|
+
yargs
|
|
43
|
+
.command({
|
|
44
|
+
command: 'create',
|
|
45
|
+
describe: 'Create a new environment',
|
|
46
|
+
builder: (yargs) =>
|
|
47
|
+
yargs
|
|
48
|
+
.option('store', {
|
|
49
|
+
alias: 's',
|
|
50
|
+
type: 'string',
|
|
51
|
+
description: 'Store ID',
|
|
52
|
+
demandOption: true,
|
|
53
|
+
})
|
|
54
|
+
.option('name', {
|
|
55
|
+
alias: 'n',
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'Environment name',
|
|
58
|
+
demandOption: true,
|
|
59
|
+
}),
|
|
60
|
+
handler: async (argv) => {
|
|
61
|
+
await createEnvironment(argv.store as string, argv.name as string);
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
}),
|
|
65
|
+
};
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import yargs from 'yargs';
|
|
3
|
+
import { hideBin } from 'yargs/helpers';
|
|
4
|
+
import { storeCommands } from './commands/store.js';
|
|
5
|
+
import { appCommands } from './commands/app.js';
|
|
6
|
+
import { agentCommands } from './commands/agent.js';
|
|
7
|
+
import { configCommands } from './commands/config.js';
|
|
8
|
+
|
|
9
|
+
yargs(hideBin(process.argv))
|
|
10
|
+
.command(storeCommands)
|
|
11
|
+
.command(appCommands)
|
|
12
|
+
.command(agentCommands)
|
|
13
|
+
.command(configCommands)
|
|
14
|
+
.demandCommand(1, 'You must provide a command')
|
|
15
|
+
.strict()
|
|
16
|
+
.parse();
|