@orchagent/cli 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/README.md +18 -0
- package/dist/commands/agents.js +26 -0
- package/dist/commands/call.js +264 -0
- package/dist/commands/fork.js +42 -0
- package/dist/commands/index.js +33 -0
- package/dist/commands/info.js +88 -0
- package/dist/commands/init.js +101 -0
- package/dist/commands/keys.js +172 -0
- package/dist/commands/llm-config.js +40 -0
- package/dist/commands/login.js +94 -0
- package/dist/commands/publish.js +192 -0
- package/dist/commands/publish.test.js +475 -0
- package/dist/commands/run.js +421 -0
- package/dist/commands/run.test.js +330 -0
- package/dist/commands/search.js +46 -0
- package/dist/commands/skill.js +141 -0
- package/dist/commands/star.js +41 -0
- package/dist/commands/whoami.js +17 -0
- package/dist/index.js +55 -0
- package/dist/lib/analytics.js +27 -0
- package/dist/lib/api.js +179 -0
- package/dist/lib/api.test.js +230 -0
- package/dist/lib/browser-auth.js +278 -0
- package/dist/lib/bundle.js +213 -0
- package/dist/lib/config.js +54 -0
- package/dist/lib/config.test.js +144 -0
- package/dist/lib/errors.js +75 -0
- package/dist/lib/llm.js +252 -0
- package/dist/lib/output.js +50 -0
- package/dist/types.js +2 -0
- package/package.json +59 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for the publish command.
|
|
4
|
+
*
|
|
5
|
+
* These tests cover publishing agents and skills from local files:
|
|
6
|
+
* - Reading orchagent.json manifest
|
|
7
|
+
* - Reading prompt.md for prompt agents
|
|
8
|
+
* - Reading SKILL.md for skills
|
|
9
|
+
* - Calling createAgent API with correct payload
|
|
10
|
+
* - Error handling for missing files
|
|
11
|
+
*/
|
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
const vitest_1 = require("vitest");
|
|
17
|
+
const commander_1 = require("commander");
|
|
18
|
+
// Mock modules before importing the command
|
|
19
|
+
vitest_1.vi.mock('fs/promises');
|
|
20
|
+
vitest_1.vi.mock('../lib/config');
|
|
21
|
+
vitest_1.vi.mock('../lib/api');
|
|
22
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
23
|
+
const publish_1 = require("./publish");
|
|
24
|
+
const config_1 = require("../lib/config");
|
|
25
|
+
const api_1 = require("../lib/api");
|
|
26
|
+
const mockFs = vitest_1.vi.mocked(promises_1.default);
|
|
27
|
+
const mockGetResolvedConfig = vitest_1.vi.mocked(config_1.getResolvedConfig);
|
|
28
|
+
const mockCreateAgent = vitest_1.vi.mocked(api_1.createAgent);
|
|
29
|
+
const mockGetOrg = vitest_1.vi.mocked(api_1.getOrg);
|
|
30
|
+
(0, vitest_1.describe)('publish command', () => {
|
|
31
|
+
let program;
|
|
32
|
+
let stdoutSpy;
|
|
33
|
+
let stderrSpy;
|
|
34
|
+
let originalCwd;
|
|
35
|
+
(0, vitest_1.beforeEach)(() => {
|
|
36
|
+
vitest_1.vi.clearAllMocks();
|
|
37
|
+
program = new commander_1.Command();
|
|
38
|
+
program.exitOverride();
|
|
39
|
+
(0, publish_1.registerPublishCommand)(program);
|
|
40
|
+
// Mock stdout/stderr
|
|
41
|
+
stdoutSpy = vitest_1.vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
42
|
+
stderrSpy = vitest_1.vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
|
43
|
+
// Mock config
|
|
44
|
+
mockGetResolvedConfig.mockResolvedValue({
|
|
45
|
+
apiKey: 'sk_test_123',
|
|
46
|
+
apiUrl: 'https://api.test.com',
|
|
47
|
+
});
|
|
48
|
+
// Mock getOrg
|
|
49
|
+
mockGetOrg.mockResolvedValue({
|
|
50
|
+
id: 'org-123',
|
|
51
|
+
slug: 'test-org',
|
|
52
|
+
name: 'Test Org',
|
|
53
|
+
});
|
|
54
|
+
// Mock createAgent
|
|
55
|
+
mockCreateAgent.mockResolvedValue({ id: 'agent-123' });
|
|
56
|
+
// Store original cwd
|
|
57
|
+
originalCwd = process.cwd;
|
|
58
|
+
process.cwd = () => '/test/project';
|
|
59
|
+
});
|
|
60
|
+
(0, vitest_1.afterEach)(() => {
|
|
61
|
+
stdoutSpy.mockRestore();
|
|
62
|
+
stderrSpy.mockRestore();
|
|
63
|
+
process.cwd = originalCwd;
|
|
64
|
+
vitest_1.vi.restoreAllMocks();
|
|
65
|
+
});
|
|
66
|
+
(0, vitest_1.describe)('publishing from orchagent.json', () => {
|
|
67
|
+
(0, vitest_1.it)('reads manifest and publishes prompt agent', async () => {
|
|
68
|
+
const manifest = {
|
|
69
|
+
name: 'my-agent',
|
|
70
|
+
version: 'v1',
|
|
71
|
+
type: 'prompt',
|
|
72
|
+
description: 'Test agent',
|
|
73
|
+
tags: ['test'],
|
|
74
|
+
};
|
|
75
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
76
|
+
const path = String(filePath);
|
|
77
|
+
if (path.includes('SKILL.md')) {
|
|
78
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
79
|
+
}
|
|
80
|
+
if (path.includes('orchagent.json')) {
|
|
81
|
+
return JSON.stringify(manifest);
|
|
82
|
+
}
|
|
83
|
+
if (path.includes('prompt.md')) {
|
|
84
|
+
return 'You are a helpful assistant.\n\nAnalyze: {{input}}';
|
|
85
|
+
}
|
|
86
|
+
if (path.includes('schema.json')) {
|
|
87
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
90
|
+
});
|
|
91
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
92
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
93
|
+
name: 'my-agent',
|
|
94
|
+
version: 'v1',
|
|
95
|
+
type: 'prompt',
|
|
96
|
+
description: 'Test agent',
|
|
97
|
+
prompt: 'You are a helpful assistant.\n\nAnalyze: {{input}}',
|
|
98
|
+
tags: ['test'],
|
|
99
|
+
is_public: true,
|
|
100
|
+
supported_providers: ['any'],
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
(0, vitest_1.it)('reads schema.json when present', async () => {
|
|
104
|
+
const manifest = {
|
|
105
|
+
name: 'schema-agent',
|
|
106
|
+
version: 'v1',
|
|
107
|
+
type: 'prompt',
|
|
108
|
+
description: 'Agent with schemas',
|
|
109
|
+
};
|
|
110
|
+
const schemas = {
|
|
111
|
+
input: { type: 'object', properties: { text: { type: 'string' } } },
|
|
112
|
+
output: { type: 'object', properties: { result: { type: 'string' } } },
|
|
113
|
+
};
|
|
114
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
115
|
+
const path = String(filePath);
|
|
116
|
+
if (path.includes('SKILL.md')) {
|
|
117
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
118
|
+
}
|
|
119
|
+
if (path.includes('orchagent.json')) {
|
|
120
|
+
return JSON.stringify(manifest);
|
|
121
|
+
}
|
|
122
|
+
if (path.includes('prompt.md')) {
|
|
123
|
+
return 'Process: {{text}}';
|
|
124
|
+
}
|
|
125
|
+
if (path.includes('schema.json')) {
|
|
126
|
+
return JSON.stringify(schemas);
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
129
|
+
});
|
|
130
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
131
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
132
|
+
input_schema: schemas.input,
|
|
133
|
+
output_schema: schemas.output,
|
|
134
|
+
}));
|
|
135
|
+
});
|
|
136
|
+
(0, vitest_1.it)('throws error when orchagent.json is missing', async () => {
|
|
137
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
138
|
+
const path = String(filePath);
|
|
139
|
+
if (path.includes('SKILL.md')) {
|
|
140
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
141
|
+
}
|
|
142
|
+
if (path.includes('orchagent.json')) {
|
|
143
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
144
|
+
}
|
|
145
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
146
|
+
});
|
|
147
|
+
await (0, vitest_1.expect)(program.parseAsync(['node', 'test', 'publish'])).rejects.toThrow('No orchagent.json found');
|
|
148
|
+
});
|
|
149
|
+
(0, vitest_1.it)('throws error when prompt.md is missing for prompt agent', async () => {
|
|
150
|
+
const manifest = {
|
|
151
|
+
name: 'prompt-agent',
|
|
152
|
+
version: 'v1',
|
|
153
|
+
type: 'prompt',
|
|
154
|
+
};
|
|
155
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
156
|
+
const path = String(filePath);
|
|
157
|
+
if (path.includes('SKILL.md')) {
|
|
158
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
159
|
+
}
|
|
160
|
+
if (path.includes('orchagent.json')) {
|
|
161
|
+
return JSON.stringify(manifest);
|
|
162
|
+
}
|
|
163
|
+
if (path.includes('prompt.md')) {
|
|
164
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
165
|
+
}
|
|
166
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
167
|
+
});
|
|
168
|
+
await (0, vitest_1.expect)(program.parseAsync(['node', 'test', 'publish'])).rejects.toThrow('No prompt.md found');
|
|
169
|
+
});
|
|
170
|
+
(0, vitest_1.it)('throws error when manifest missing required fields', async () => {
|
|
171
|
+
const manifest = {
|
|
172
|
+
name: 'incomplete-agent',
|
|
173
|
+
// missing version
|
|
174
|
+
};
|
|
175
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
176
|
+
const path = String(filePath);
|
|
177
|
+
if (path.includes('SKILL.md')) {
|
|
178
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
179
|
+
}
|
|
180
|
+
if (path.includes('orchagent.json')) {
|
|
181
|
+
return JSON.stringify(manifest);
|
|
182
|
+
}
|
|
183
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
184
|
+
});
|
|
185
|
+
await (0, vitest_1.expect)(program.parseAsync(['node', 'test', 'publish'])).rejects.toThrow('must have name and version');
|
|
186
|
+
});
|
|
187
|
+
(0, vitest_1.it)('requires URL for code-based agents', async () => {
|
|
188
|
+
const manifest = {
|
|
189
|
+
name: 'code-agent',
|
|
190
|
+
version: 'v1',
|
|
191
|
+
type: 'code',
|
|
192
|
+
};
|
|
193
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
194
|
+
const path = String(filePath);
|
|
195
|
+
if (path.includes('SKILL.md')) {
|
|
196
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
197
|
+
}
|
|
198
|
+
if (path.includes('orchagent.json')) {
|
|
199
|
+
return JSON.stringify(manifest);
|
|
200
|
+
}
|
|
201
|
+
if (path.includes('schema.json')) {
|
|
202
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
203
|
+
}
|
|
204
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
205
|
+
});
|
|
206
|
+
await (0, vitest_1.expect)(program.parseAsync(['node', 'test', 'publish'])).rejects.toThrow('URL is required for code-based agents');
|
|
207
|
+
});
|
|
208
|
+
(0, vitest_1.it)('publishes code agent with --url option', async () => {
|
|
209
|
+
const manifest = {
|
|
210
|
+
name: 'code-agent',
|
|
211
|
+
version: 'v1',
|
|
212
|
+
type: 'code',
|
|
213
|
+
description: 'Code agent',
|
|
214
|
+
};
|
|
215
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
216
|
+
const path = String(filePath);
|
|
217
|
+
if (path.includes('SKILL.md')) {
|
|
218
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
219
|
+
}
|
|
220
|
+
if (path.includes('orchagent.json')) {
|
|
221
|
+
return JSON.stringify(manifest);
|
|
222
|
+
}
|
|
223
|
+
if (path.includes('schema.json')) {
|
|
224
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
225
|
+
}
|
|
226
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
227
|
+
});
|
|
228
|
+
await program.parseAsync([
|
|
229
|
+
'node',
|
|
230
|
+
'test',
|
|
231
|
+
'publish',
|
|
232
|
+
'--url',
|
|
233
|
+
'https://my-agent.run.app',
|
|
234
|
+
]);
|
|
235
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
236
|
+
name: 'code-agent',
|
|
237
|
+
type: 'code',
|
|
238
|
+
url: 'https://my-agent.run.app',
|
|
239
|
+
}));
|
|
240
|
+
});
|
|
241
|
+
(0, vitest_1.it)('respects --private flag', async () => {
|
|
242
|
+
const manifest = {
|
|
243
|
+
name: 'private-agent',
|
|
244
|
+
version: 'v1',
|
|
245
|
+
type: 'prompt',
|
|
246
|
+
};
|
|
247
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
248
|
+
const path = String(filePath);
|
|
249
|
+
if (path.includes('SKILL.md')) {
|
|
250
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
251
|
+
}
|
|
252
|
+
if (path.includes('orchagent.json')) {
|
|
253
|
+
return JSON.stringify(manifest);
|
|
254
|
+
}
|
|
255
|
+
if (path.includes('prompt.md')) {
|
|
256
|
+
return 'Private prompt';
|
|
257
|
+
}
|
|
258
|
+
if (path.includes('schema.json')) {
|
|
259
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
260
|
+
}
|
|
261
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
262
|
+
});
|
|
263
|
+
await program.parseAsync(['node', 'test', 'publish', '--private']);
|
|
264
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
265
|
+
is_public: false,
|
|
266
|
+
}));
|
|
267
|
+
});
|
|
268
|
+
(0, vitest_1.it)('uses manifest supported_providers', async () => {
|
|
269
|
+
const manifest = {
|
|
270
|
+
name: 'openai-agent',
|
|
271
|
+
version: 'v1',
|
|
272
|
+
type: 'prompt',
|
|
273
|
+
supported_providers: ['openai', 'anthropic'],
|
|
274
|
+
};
|
|
275
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
276
|
+
const path = String(filePath);
|
|
277
|
+
if (path.includes('SKILL.md')) {
|
|
278
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
279
|
+
}
|
|
280
|
+
if (path.includes('orchagent.json')) {
|
|
281
|
+
return JSON.stringify(manifest);
|
|
282
|
+
}
|
|
283
|
+
if (path.includes('prompt.md')) {
|
|
284
|
+
return 'Provider-specific prompt';
|
|
285
|
+
}
|
|
286
|
+
if (path.includes('schema.json')) {
|
|
287
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
288
|
+
}
|
|
289
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
290
|
+
});
|
|
291
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
292
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
293
|
+
supported_providers: ['openai', 'anthropic'],
|
|
294
|
+
}));
|
|
295
|
+
});
|
|
296
|
+
(0, vitest_1.it)('outputs service key when returned', async () => {
|
|
297
|
+
const manifest = {
|
|
298
|
+
name: 'service-agent',
|
|
299
|
+
version: 'v1',
|
|
300
|
+
type: 'prompt',
|
|
301
|
+
};
|
|
302
|
+
mockCreateAgent.mockResolvedValue({
|
|
303
|
+
id: 'agent-123',
|
|
304
|
+
service_key: 'sk_service_abc123',
|
|
305
|
+
});
|
|
306
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
307
|
+
const path = String(filePath);
|
|
308
|
+
if (path.includes('SKILL.md')) {
|
|
309
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
310
|
+
}
|
|
311
|
+
if (path.includes('orchagent.json')) {
|
|
312
|
+
return JSON.stringify(manifest);
|
|
313
|
+
}
|
|
314
|
+
if (path.includes('prompt.md')) {
|
|
315
|
+
return 'Service prompt';
|
|
316
|
+
}
|
|
317
|
+
if (path.includes('schema.json')) {
|
|
318
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
319
|
+
}
|
|
320
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
321
|
+
});
|
|
322
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
323
|
+
(0, vitest_1.expect)(stdoutSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining('sk_service_abc123'));
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
(0, vitest_1.describe)('publishing from SKILL.md', () => {
|
|
327
|
+
(0, vitest_1.it)('publishes skill from SKILL.md with frontmatter', async () => {
|
|
328
|
+
const skillMd = `---
|
|
329
|
+
name: my-skill
|
|
330
|
+
description: A helpful skill
|
|
331
|
+
metadata:
|
|
332
|
+
version: v2
|
|
333
|
+
---
|
|
334
|
+
You are a helpful skill that does specific things.
|
|
335
|
+
|
|
336
|
+
Use this prompt to guide the agent.`;
|
|
337
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
338
|
+
const path = String(filePath);
|
|
339
|
+
if (path.includes('SKILL.md')) {
|
|
340
|
+
return skillMd;
|
|
341
|
+
}
|
|
342
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
343
|
+
});
|
|
344
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
345
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
346
|
+
name: 'my-skill',
|
|
347
|
+
type: 'skill',
|
|
348
|
+
description: 'A helpful skill',
|
|
349
|
+
version: 'v2',
|
|
350
|
+
prompt: vitest_1.expect.stringContaining('You are a helpful skill'),
|
|
351
|
+
is_public: true,
|
|
352
|
+
supported_providers: ['any'],
|
|
353
|
+
}));
|
|
354
|
+
});
|
|
355
|
+
(0, vitest_1.it)('uses default version v1 when not specified', async () => {
|
|
356
|
+
const skillMd = `---
|
|
357
|
+
name: simple-skill
|
|
358
|
+
description: Simple skill
|
|
359
|
+
---
|
|
360
|
+
Skill content here.`;
|
|
361
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
362
|
+
const path = String(filePath);
|
|
363
|
+
if (path.includes('SKILL.md')) {
|
|
364
|
+
return skillMd;
|
|
365
|
+
}
|
|
366
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
367
|
+
});
|
|
368
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
369
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
370
|
+
version: 'v1',
|
|
371
|
+
}));
|
|
372
|
+
});
|
|
373
|
+
(0, vitest_1.it)('respects --private flag for skills', async () => {
|
|
374
|
+
const skillMd = `---
|
|
375
|
+
name: private-skill
|
|
376
|
+
description: Private skill
|
|
377
|
+
---
|
|
378
|
+
Private skill content.`;
|
|
379
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
380
|
+
const path = String(filePath);
|
|
381
|
+
if (path.includes('SKILL.md')) {
|
|
382
|
+
return skillMd;
|
|
383
|
+
}
|
|
384
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
385
|
+
});
|
|
386
|
+
await program.parseAsync(['node', 'test', 'publish', '--private']);
|
|
387
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
388
|
+
is_public: false,
|
|
389
|
+
}));
|
|
390
|
+
});
|
|
391
|
+
(0, vitest_1.it)('falls back to manifest if SKILL.md has no frontmatter', async () => {
|
|
392
|
+
const manifest = {
|
|
393
|
+
name: 'fallback-agent',
|
|
394
|
+
version: 'v1',
|
|
395
|
+
type: 'prompt',
|
|
396
|
+
};
|
|
397
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
398
|
+
const path = String(filePath);
|
|
399
|
+
if (path.includes('SKILL.md')) {
|
|
400
|
+
// No frontmatter - just content
|
|
401
|
+
return 'Just some content without frontmatter';
|
|
402
|
+
}
|
|
403
|
+
if (path.includes('orchagent.json')) {
|
|
404
|
+
return JSON.stringify(manifest);
|
|
405
|
+
}
|
|
406
|
+
if (path.includes('prompt.md')) {
|
|
407
|
+
return 'Fallback prompt';
|
|
408
|
+
}
|
|
409
|
+
if (path.includes('schema.json')) {
|
|
410
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
411
|
+
}
|
|
412
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
413
|
+
});
|
|
414
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
415
|
+
// Should fall back to manifest
|
|
416
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
417
|
+
name: 'fallback-agent',
|
|
418
|
+
type: 'prompt',
|
|
419
|
+
}));
|
|
420
|
+
});
|
|
421
|
+
(0, vitest_1.it)('falls back to manifest if SKILL.md missing required fields', async () => {
|
|
422
|
+
const skillMd = `---
|
|
423
|
+
name: incomplete-skill
|
|
424
|
+
---
|
|
425
|
+
Missing description field.`;
|
|
426
|
+
const manifest = {
|
|
427
|
+
name: 'manifest-agent',
|
|
428
|
+
version: 'v1',
|
|
429
|
+
type: 'prompt',
|
|
430
|
+
};
|
|
431
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
432
|
+
const path = String(filePath);
|
|
433
|
+
if (path.includes('SKILL.md')) {
|
|
434
|
+
return skillMd;
|
|
435
|
+
}
|
|
436
|
+
if (path.includes('orchagent.json')) {
|
|
437
|
+
return JSON.stringify(manifest);
|
|
438
|
+
}
|
|
439
|
+
if (path.includes('prompt.md')) {
|
|
440
|
+
return 'Manifest prompt';
|
|
441
|
+
}
|
|
442
|
+
if (path.includes('schema.json')) {
|
|
443
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
444
|
+
}
|
|
445
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
446
|
+
});
|
|
447
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
448
|
+
// Should fall back to manifest since SKILL.md is incomplete
|
|
449
|
+
(0, vitest_1.expect)(mockCreateAgent).toHaveBeenCalledWith(vitest_1.expect.any(Object), vitest_1.expect.objectContaining({
|
|
450
|
+
name: 'manifest-agent',
|
|
451
|
+
type: 'prompt',
|
|
452
|
+
}));
|
|
453
|
+
});
|
|
454
|
+
(0, vitest_1.it)('outputs correct skill publish message', async () => {
|
|
455
|
+
const skillMd = `---
|
|
456
|
+
name: output-skill
|
|
457
|
+
description: Test output
|
|
458
|
+
metadata:
|
|
459
|
+
version: v3
|
|
460
|
+
---
|
|
461
|
+
Skill prompt.`;
|
|
462
|
+
mockFs.readFile.mockImplementation(async (filePath) => {
|
|
463
|
+
const path = String(filePath);
|
|
464
|
+
if (path.includes('SKILL.md')) {
|
|
465
|
+
return skillMd;
|
|
466
|
+
}
|
|
467
|
+
throw new Error(`Unexpected file: ${path}`);
|
|
468
|
+
});
|
|
469
|
+
await program.parseAsync(['node', 'test', 'publish']);
|
|
470
|
+
(0, vitest_1.expect)(stdoutSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining('Published skill'));
|
|
471
|
+
(0, vitest_1.expect)(stdoutSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining('test-org/output-skill'));
|
|
472
|
+
(0, vitest_1.expect)(stdoutSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining('Version: v3'));
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
});
|