@dk/jolly 0.1.7 → 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 -183
- package/dist/index.js +0 -721
- 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 -151
- 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/src/test/mocks.ts
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { mock, spyOn } from 'bun:test';
|
|
2
|
-
import type { Organization, Project, Environment, App } from '../api/client';
|
|
3
|
-
|
|
4
|
-
export const fixtures = {
|
|
5
|
-
token: 'test-token-abc123',
|
|
6
|
-
|
|
7
|
-
// New API structure: Organizations → Projects → Environments
|
|
8
|
-
organization: {
|
|
9
|
-
slug: 'my-org',
|
|
10
|
-
name: 'My Organization',
|
|
11
|
-
created: '2025-01-01T00:00:00Z',
|
|
12
|
-
owner_email: 'owner@example.com',
|
|
13
|
-
company_name: 'My Company',
|
|
14
|
-
} satisfies Organization,
|
|
15
|
-
|
|
16
|
-
organization2: {
|
|
17
|
-
slug: 'other-org',
|
|
18
|
-
name: 'Other Organization',
|
|
19
|
-
created: '2025-06-15T00:00:00Z',
|
|
20
|
-
owner_email: 'other@example.com',
|
|
21
|
-
} satisfies Organization,
|
|
22
|
-
|
|
23
|
-
project: {
|
|
24
|
-
slug: 'my-store',
|
|
25
|
-
name: 'my-store',
|
|
26
|
-
region: 'us-east-1',
|
|
27
|
-
created: '2025-01-01T00:00:00Z',
|
|
28
|
-
sandboxes: { count: 2 },
|
|
29
|
-
} satisfies Project,
|
|
30
|
-
|
|
31
|
-
project2: {
|
|
32
|
-
slug: 'other-store',
|
|
33
|
-
name: 'other-store',
|
|
34
|
-
region: 'eu-west-1',
|
|
35
|
-
created: '2025-06-15T00:00:00Z',
|
|
36
|
-
sandboxes: { count: 1 },
|
|
37
|
-
} satisfies Project,
|
|
38
|
-
|
|
39
|
-
environment: {
|
|
40
|
-
key: 'staging',
|
|
41
|
-
name: 'staging',
|
|
42
|
-
domain: 'staging-my-store.saleor.cloud',
|
|
43
|
-
service: {
|
|
44
|
-
version: '3.15.0',
|
|
45
|
-
type: 'main',
|
|
46
|
-
region: 'us-east-1',
|
|
47
|
-
},
|
|
48
|
-
created: '2025-01-02T00:00:00Z',
|
|
49
|
-
project: { name: 'my-store', slug: 'my-store' },
|
|
50
|
-
} satisfies Environment,
|
|
51
|
-
|
|
52
|
-
app: {
|
|
53
|
-
id: 'app-1',
|
|
54
|
-
name: 'my-app',
|
|
55
|
-
type: 'payment',
|
|
56
|
-
environment_id: 'staging',
|
|
57
|
-
} satisfies App,
|
|
58
|
-
|
|
59
|
-
// Backward compat aliases (for tests that haven't been migrated yet)
|
|
60
|
-
store: {
|
|
61
|
-
id: 'my-org',
|
|
62
|
-
name: 'My Organization',
|
|
63
|
-
region: 'us-east-1',
|
|
64
|
-
created_at: '2025-01-01T00:00:00Z',
|
|
65
|
-
},
|
|
66
|
-
store2: {
|
|
67
|
-
id: 'other-org',
|
|
68
|
-
name: 'Other Organization',
|
|
69
|
-
region: 'eu-west-1',
|
|
70
|
-
created_at: '2025-06-15T00:00:00Z',
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export function mockFetch(routes: Record<string, unknown>): ReturnType<typeof mock> {
|
|
75
|
-
const handler = mock((url: string | URL | Request, init?: RequestInit) => {
|
|
76
|
-
const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
|
|
77
|
-
|
|
78
|
-
const sortedEntries = Object.entries(routes).sort((a, b) => b[0].length - a[0].length);
|
|
79
|
-
|
|
80
|
-
for (const [pattern, body] of sortedEntries) {
|
|
81
|
-
if (urlStr.endsWith(pattern)) {
|
|
82
|
-
return Promise.resolve(new Response(JSON.stringify(body), {
|
|
83
|
-
status: 200,
|
|
84
|
-
headers: { 'Content-Type': 'application/json' },
|
|
85
|
-
}));
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return Promise.resolve(new Response('Not Found', { status: 404 }));
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
globalThis.fetch = handler as typeof fetch;
|
|
93
|
-
return handler;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function mockFetchError(status: number, statusText: string): ReturnType<typeof mock> {
|
|
97
|
-
const handler = mock(() =>
|
|
98
|
-
Promise.resolve(new Response(JSON.stringify({ error: statusText }), {
|
|
99
|
-
status,
|
|
100
|
-
statusText,
|
|
101
|
-
}))
|
|
102
|
-
);
|
|
103
|
-
globalThis.fetch = handler as typeof fetch;
|
|
104
|
-
return handler;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function mockProcessExit() {
|
|
108
|
-
return spyOn(process, 'exit').mockImplementation((() => {
|
|
109
|
-
throw new Error('process.exit called');
|
|
110
|
-
}) as () => never);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function captureConsole() {
|
|
114
|
-
const logs: string[] = [];
|
|
115
|
-
const errors: string[] = [];
|
|
116
|
-
|
|
117
|
-
const logSpy = spyOn(console, 'log').mockImplementation((...args: unknown[]) => {
|
|
118
|
-
logs.push(args.map(String).join(' '));
|
|
119
|
-
});
|
|
120
|
-
const errorSpy = spyOn(console, 'error').mockImplementation((...args: unknown[]) => {
|
|
121
|
-
errors.push(args.map(String).join(' '));
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
return {
|
|
125
|
-
logs,
|
|
126
|
-
errors,
|
|
127
|
-
logSpy,
|
|
128
|
-
errorSpy,
|
|
129
|
-
restore() {
|
|
130
|
-
logSpy.mockRestore();
|
|
131
|
-
errorSpy.mockRestore();
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function withToken(token = fixtures.token) {
|
|
137
|
-
process.env.SALEOR_CLOUD_TOKEN = token;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function withoutToken() {
|
|
141
|
-
delete process.env.SALEOR_CLOUD_TOKEN;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export async function parseArgs(
|
|
145
|
-
commandModule: unknown,
|
|
146
|
-
args: string[]
|
|
147
|
-
): Promise<{ argv?: Record<string, unknown>; error?: string }> {
|
|
148
|
-
const yargsModule = await import('yargs');
|
|
149
|
-
const yargs = yargsModule.default;
|
|
150
|
-
const helpers = await import('yargs/helpers');
|
|
151
|
-
const hideBin = helpers.hideBin;
|
|
152
|
-
|
|
153
|
-
return new Promise((resolve) => {
|
|
154
|
-
try {
|
|
155
|
-
const parser = (yargs(hideBin(args)) as any)
|
|
156
|
-
.command(commandModule)
|
|
157
|
-
.strict()
|
|
158
|
-
.exitProcess(false);
|
|
159
|
-
|
|
160
|
-
parser.fail((msg: string) => {
|
|
161
|
-
resolve({ error: msg });
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
const parsed = parser.parse(args);
|
|
165
|
-
if (parsed && typeof parsed === 'object') {
|
|
166
|
-
resolve({ argv: parsed as Record<string, unknown> });
|
|
167
|
-
}
|
|
168
|
-
} catch (err) {
|
|
169
|
-
resolve({ error: (err as Error).message });
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
}
|
package/src/test/setup.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll, afterAll } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
export { describe, it, expect, beforeAll, afterAll };
|
|
4
|
-
|
|
5
|
-
export const testEnv = {
|
|
6
|
-
clear: () => {
|
|
7
|
-
delete process.env.SALEOR_CLOUD_TOKEN;
|
|
8
|
-
delete process.env.SALEOR_API_URL;
|
|
9
|
-
},
|
|
10
|
-
setToken: (token: string) => {
|
|
11
|
-
process.env.SALEOR_CLOUD_TOKEN = token;
|
|
12
|
-
},
|
|
13
|
-
setApiUrl: (url: string) => {
|
|
14
|
-
process.env.SALEOR_API_URL = url;
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export async function mockFetch(response: unknown, status = 200): Promise<void> {
|
|
19
|
-
const globalFetch = globalThis.fetch;
|
|
20
|
-
|
|
21
|
-
globalThis.fetch = (url: string | URL | Request, init?: RequestInit) => {
|
|
22
|
-
return Promise.resolve({
|
|
23
|
-
ok: status >= 200 && status < 300,
|
|
24
|
-
status,
|
|
25
|
-
statusText: status === 200 ? 'OK' : 'Error',
|
|
26
|
-
json: () => Promise.resolve(response),
|
|
27
|
-
}) as Response;
|
|
28
|
-
};
|
|
29
|
-
}
|
package/src/tui/components.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { theme } from './theme.js';
|
|
2
|
-
|
|
3
|
-
export function text(content: string, color?: string): string {
|
|
4
|
-
return `${color || theme.fg.white}${content}${theme.reset}`;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function bold(content: string): string {
|
|
8
|
-
return `${theme.bold}${content}${theme.reset}`;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function dim(content: string): string {
|
|
12
|
-
return `${theme.dim}${content}${theme.reset}`;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function color(content: string, fg?: string): string {
|
|
16
|
-
if (!fg) return content;
|
|
17
|
-
return `${fg}${content}${theme.reset}`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function spinner(label?: string): { stop: () => void } {
|
|
21
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
22
|
-
let i = 0;
|
|
23
|
-
let interval: ReturnType<typeof setInterval>;
|
|
24
|
-
|
|
25
|
-
const stop = () => {
|
|
26
|
-
clearInterval(interval);
|
|
27
|
-
process.stdout.write('\r' + ' '.repeat(50) + '\r');
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
interval = setInterval(() => {
|
|
31
|
-
process.stdout.write(`\r${frames[i % frames.length]} ${label || ''}`);
|
|
32
|
-
i++;
|
|
33
|
-
}, 80);
|
|
34
|
-
|
|
35
|
-
return { stop };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function progress(current: number, total: number, label?: string): string {
|
|
39
|
-
const width = 30;
|
|
40
|
-
const filled = Math.round((current / total) * width);
|
|
41
|
-
const empty = width - filled;
|
|
42
|
-
const bar = '█'.repeat(filled) + '░'.repeat(empty);
|
|
43
|
-
return `${bar} ${Math.round((current / total) * 100)}% ${label || ''}`;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function box(content: string, title?: string): string {
|
|
47
|
-
const lines = content.split('\n');
|
|
48
|
-
const maxLen = Math.max(...lines.map(l => l.length), title?.length || 0);
|
|
49
|
-
const border = '─'.repeat(maxLen + 2);
|
|
50
|
-
|
|
51
|
-
let result = `┌${border}┐\n`;
|
|
52
|
-
if (title) {
|
|
53
|
-
result += `│ ${title.padEnd(maxLen)} │\n`;
|
|
54
|
-
result += `├${border}┤\n`;
|
|
55
|
-
}
|
|
56
|
-
for (const line of lines) {
|
|
57
|
-
result += `│ ${line.padEnd(maxLen)} │\n`;
|
|
58
|
-
}
|
|
59
|
-
result += `└${border}┘`;
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function success(msg: string): string {
|
|
64
|
-
return text(msg, theme.fg.green);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function error(msg: string): string {
|
|
68
|
-
return text(msg, theme.fg.red);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function warning(msg: string): string {
|
|
72
|
-
return text(msg, theme.fg.yellow);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function info(msg: string): string {
|
|
76
|
-
return text(msg, theme.fg.cyan);
|
|
77
|
-
}
|
package/src/tui/index.ts
DELETED
package/src/tui/renderer.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { box, success, error, warning, info, bold } from './components.js';
|
|
2
|
-
import { theme } from './theme.js';
|
|
3
|
-
|
|
4
|
-
export function render(content: string): void {
|
|
5
|
-
console.log(content);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function renderBox(content: string, title?: string): void {
|
|
9
|
-
console.log(box(content, title));
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function renderSuccess(msg: string): void {
|
|
13
|
-
console.log(success(msg));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function renderError(msg: string): void {
|
|
17
|
-
console.error(error(msg));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function renderWarning(msg: string): void {
|
|
21
|
-
console.log(warning(msg));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function renderInfo(msg: string): void {
|
|
25
|
-
console.log(info(msg));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function renderHeader(text: string): void {
|
|
29
|
-
console.log(`\n${bold(text)}\n`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function clearScreen(): void {
|
|
33
|
-
process.stdout.write('\x1b[2J\x1b[0f');
|
|
34
|
-
}
|
package/src/tui/theme.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export const theme = {
|
|
2
|
-
reset: '\x1b[0m',
|
|
3
|
-
bold: '\x1b[1m',
|
|
4
|
-
dim: '\x1b[2m',
|
|
5
|
-
italic: '\x1b[3m',
|
|
6
|
-
underline: '\x1b[4m',
|
|
7
|
-
|
|
8
|
-
fg: {
|
|
9
|
-
black: '\x1b[30m',
|
|
10
|
-
red: '\x1b[31m',
|
|
11
|
-
green: '\x1b[32m',
|
|
12
|
-
yellow: '\x1b[33m',
|
|
13
|
-
blue: '\x1b[34m',
|
|
14
|
-
magenta: '\x1b[35m',
|
|
15
|
-
cyan: '\x1b[36m',
|
|
16
|
-
white: '\x1b[37m',
|
|
17
|
-
gray: '\x1b[90m',
|
|
18
|
-
brightBlack: '\x1b[30;1m',
|
|
19
|
-
brightRed: '\x1b[31;1m',
|
|
20
|
-
brightGreen: '\x1b[32;1m',
|
|
21
|
-
brightYellow: '\x1b[33;1m',
|
|
22
|
-
brightBlue: '\x1b[34;1m',
|
|
23
|
-
brightMagenta: '\x1b[35;1m',
|
|
24
|
-
brightCyan: '\x1b[36;1m',
|
|
25
|
-
brightWhite: '\x1b[37;1m',
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
bg: {
|
|
29
|
-
black: '\x1b[40m',
|
|
30
|
-
red: '\x1b[41m',
|
|
31
|
-
green: '\x1b[42m',
|
|
32
|
-
yellow: '\x1b[43m',
|
|
33
|
-
blue: '\x1b[44m',
|
|
34
|
-
magenta: '\x1b[45m',
|
|
35
|
-
cyan: '\x1b[46m',
|
|
36
|
-
white: '\x1b[47m',
|
|
37
|
-
},
|
|
38
|
-
};
|
package/tsconfig.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": ["ESNext"],
|
|
7
|
-
"types": ["bun-types"],
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"outDir": "dist",
|
|
13
|
-
"rootDir": "src",
|
|
14
|
-
"declaration": true,
|
|
15
|
-
"declarationMap": true,
|
|
16
|
-
"sourceMap": true
|
|
17
|
-
},
|
|
18
|
-
"include": ["src/**/*"],
|
|
19
|
-
"exclude": ["node_modules", "dist", "src/test/**/*.ts"]
|
|
20
|
-
}
|