@poncho-ai/cli 0.6.0 → 0.6.2
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/.turbo/turbo-build.log +7 -7
- package/dist/chunk-2TLKQG7R.js +5360 -0
- package/dist/chunk-3FY4LP2E.js +4981 -0
- package/dist/chunk-3WQANPEG.js +5086 -0
- package/dist/chunk-44DXWF6D.js +5450 -0
- package/dist/chunk-62G3MI43.js +5316 -0
- package/dist/chunk-6J2JICGH.js +5135 -0
- package/dist/chunk-6KLC6MWK.js +5357 -0
- package/dist/chunk-6LG2DUWF.js +5181 -0
- package/dist/chunk-ASAXSYEZ.js +5179 -0
- package/dist/chunk-B5B5LAR2.js +5181 -0
- package/dist/chunk-C7T4EJNQ.js +4934 -0
- package/dist/chunk-EPG7ZYDE.js +5452 -0
- package/dist/chunk-FMRRGTJX.js +5041 -0
- package/dist/chunk-HHMFEU26.js +5451 -0
- package/dist/chunk-JRJY6LUC.js +5178 -0
- package/dist/chunk-O7SJY7YQ.js +5177 -0
- package/dist/chunk-PYP4SKOI.js +5125 -0
- package/dist/chunk-VECWMU7E.js +5276 -0
- package/dist/chunk-XEBDWQI6.js +5178 -0
- package/dist/chunk-YW2D7Z22.js +5360 -0
- package/dist/chunk-YZXMEO2T.js +5177 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +18 -2
- package/dist/index.js +11 -1
- package/dist/run-interactive-ink-6EJ6Z5HE.js +494 -0
- package/dist/run-interactive-ink-72BHZB7Q.js +494 -0
- package/dist/run-interactive-ink-BNRIM52Y.js +494 -0
- package/dist/run-interactive-ink-BZNBOELJ.js +494 -0
- package/dist/run-interactive-ink-GODBXZF3.js +494 -0
- package/dist/run-interactive-ink-J4AISGNQ.js +494 -0
- package/dist/run-interactive-ink-K75SE2J2.js +494 -0
- package/dist/run-interactive-ink-M2XKKPIJ.js +494 -0
- package/dist/run-interactive-ink-MITWAF7L.js +494 -0
- package/dist/run-interactive-ink-NR5BRFUF.js +494 -0
- package/dist/run-interactive-ink-OGNG6UYE.js +494 -0
- package/dist/run-interactive-ink-P3VNJEXK.js +494 -0
- package/dist/run-interactive-ink-PHLW5YWV.js +494 -0
- package/dist/run-interactive-ink-PVU3XABN.js +494 -0
- package/dist/run-interactive-ink-SLSK7BY5.js +494 -0
- package/dist/run-interactive-ink-TRPYQYHG.js +494 -0
- package/dist/run-interactive-ink-U2RPRBIR.js +494 -0
- package/dist/run-interactive-ink-U2WTGZJ3.js +494 -0
- package/dist/run-interactive-ink-UHBFYNNB.js +494 -0
- package/dist/run-interactive-ink-XQDUN6OS.js +494 -0
- package/dist/run-interactive-ink-XUHSJCGH.js +494 -0
- package/package.json +1 -1
- package/src/index.ts +322 -27
- package/src/web-ui.ts +350 -33
- package/test/cli.test.ts +232 -1
package/test/cli.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { lstat, mkdir, mkdtemp, readFile, symlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
@@ -151,11 +151,14 @@ vi.mock("@poncho-ai/harness", () => ({
|
|
|
151
151
|
|
|
152
152
|
import {
|
|
153
153
|
buildTarget,
|
|
154
|
+
copySkillsFromPackage,
|
|
154
155
|
initProject,
|
|
156
|
+
listInstalledSkills,
|
|
155
157
|
listTools,
|
|
156
158
|
mcpAdd,
|
|
157
159
|
mcpList,
|
|
158
160
|
mcpRemove,
|
|
161
|
+
removeSkillsFromPackage,
|
|
159
162
|
runTests,
|
|
160
163
|
startDevServer,
|
|
161
164
|
updateAgentGuidance,
|
|
@@ -278,6 +281,203 @@ describe("cli", () => {
|
|
|
278
281
|
expect(intro).toBeUndefined();
|
|
279
282
|
});
|
|
280
283
|
|
|
284
|
+
it("copies discovered skill folders into local skills directory", async () => {
|
|
285
|
+
const projectDir = join(tempDir, "copy-skills-agent");
|
|
286
|
+
const packageDir = join(tempDir, "mock-skill-package");
|
|
287
|
+
await mkdir(projectDir, { recursive: true });
|
|
288
|
+
await mkdir(join(projectDir, "skills"), { recursive: true });
|
|
289
|
+
await mkdir(join(packageDir, "alpha"), { recursive: true });
|
|
290
|
+
await mkdir(join(packageDir, "nested", "beta"), { recursive: true });
|
|
291
|
+
await mkdir(join(packageDir, "nested", "beta", "scripts"), { recursive: true });
|
|
292
|
+
|
|
293
|
+
await writeFile(
|
|
294
|
+
join(packageDir, "alpha", "SKILL.md"),
|
|
295
|
+
"---\nname: alpha\n---\nAlpha skill\n",
|
|
296
|
+
"utf8",
|
|
297
|
+
);
|
|
298
|
+
await writeFile(
|
|
299
|
+
join(packageDir, "nested", "beta", "SKILL.md"),
|
|
300
|
+
"---\nname: beta\n---\nBeta skill\n",
|
|
301
|
+
"utf8",
|
|
302
|
+
);
|
|
303
|
+
await writeFile(
|
|
304
|
+
join(packageDir, "nested", "beta", "scripts", "run.ts"),
|
|
305
|
+
"export default async function run() { return { ok: true }; }\n",
|
|
306
|
+
"utf8",
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const copied = await copySkillsFromPackage(projectDir, packageDir);
|
|
310
|
+
|
|
311
|
+
expect(copied).toEqual([
|
|
312
|
+
"skills/mock-skill-package/alpha",
|
|
313
|
+
"skills/mock-skill-package/beta",
|
|
314
|
+
]);
|
|
315
|
+
const alphaSkill = await readFile(
|
|
316
|
+
join(projectDir, "skills", "mock-skill-package", "alpha", "SKILL.md"),
|
|
317
|
+
"utf8",
|
|
318
|
+
);
|
|
319
|
+
const betaScript = await readFile(
|
|
320
|
+
join(projectDir, "skills", "mock-skill-package", "beta", "scripts", "run.ts"),
|
|
321
|
+
"utf8",
|
|
322
|
+
);
|
|
323
|
+
expect(alphaSkill).toContain("name: alpha");
|
|
324
|
+
expect(betaScript).toContain("export default async function run");
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it("fails when skill destination already exists", async () => {
|
|
328
|
+
const projectDir = join(tempDir, "collision-agent");
|
|
329
|
+
const packageDir = join(tempDir, "collision-package");
|
|
330
|
+
await mkdir(join(projectDir, "skills", "collision-package", "alpha"), { recursive: true });
|
|
331
|
+
await mkdir(join(packageDir, "alpha"), { recursive: true });
|
|
332
|
+
await writeFile(
|
|
333
|
+
join(packageDir, "alpha", "SKILL.md"),
|
|
334
|
+
"---\nname: alpha\n---\nCollision skill\n",
|
|
335
|
+
"utf8",
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
await expect(copySkillsFromPackage(projectDir, packageDir)).rejects.toThrow(
|
|
339
|
+
/destination already exists/i,
|
|
340
|
+
);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it("copies a specific skill when --path style option is used", async () => {
|
|
344
|
+
const projectDir = join(tempDir, "single-skill-agent");
|
|
345
|
+
const packageDir = join(tempDir, "single-skill-package");
|
|
346
|
+
await mkdir(projectDir, { recursive: true });
|
|
347
|
+
await mkdir(join(packageDir, "alpha"), { recursive: true });
|
|
348
|
+
await mkdir(join(packageDir, "nested", "beta"), { recursive: true });
|
|
349
|
+
await writeFile(
|
|
350
|
+
join(packageDir, "alpha", "SKILL.md"),
|
|
351
|
+
"---\nname: alpha\n---\nAlpha skill\n",
|
|
352
|
+
"utf8",
|
|
353
|
+
);
|
|
354
|
+
await writeFile(
|
|
355
|
+
join(packageDir, "nested", "beta", "SKILL.md"),
|
|
356
|
+
"---\nname: beta\n---\nBeta skill\n",
|
|
357
|
+
"utf8",
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
const copied = await copySkillsFromPackage(projectDir, packageDir, { path: "nested/beta" });
|
|
361
|
+
expect(copied).toEqual(["skills/single-skill-package/beta"]);
|
|
362
|
+
await expect(
|
|
363
|
+
readFile(join(projectDir, "skills", "single-skill-package", "alpha", "SKILL.md"), "utf8"),
|
|
364
|
+
).rejects.toThrow();
|
|
365
|
+
const betaSkill = await readFile(
|
|
366
|
+
join(projectDir, "skills", "single-skill-package", "beta", "SKILL.md"),
|
|
367
|
+
"utf8",
|
|
368
|
+
);
|
|
369
|
+
expect(betaSkill).toContain("name: beta");
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("removes all copied skills for a package in one call", async () => {
|
|
373
|
+
const projectDir = join(tempDir, "remove-skills-agent");
|
|
374
|
+
const packageDir = join(tempDir, "remove-skills-package");
|
|
375
|
+
await mkdir(join(projectDir, "skills", "remove-skills-package", "alpha"), { recursive: true });
|
|
376
|
+
await mkdir(join(projectDir, "skills", "remove-skills-package", "beta"), { recursive: true });
|
|
377
|
+
await writeFile(
|
|
378
|
+
join(projectDir, "skills", "remove-skills-package", "alpha", "SKILL.md"),
|
|
379
|
+
"alpha\n",
|
|
380
|
+
"utf8",
|
|
381
|
+
);
|
|
382
|
+
await writeFile(
|
|
383
|
+
join(projectDir, "skills", "remove-skills-package", "beta", "SKILL.md"),
|
|
384
|
+
"beta\n",
|
|
385
|
+
"utf8",
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
await mkdir(join(packageDir, "alpha"), { recursive: true });
|
|
389
|
+
await mkdir(join(packageDir, "nested", "beta"), { recursive: true });
|
|
390
|
+
await writeFile(
|
|
391
|
+
join(packageDir, "alpha", "SKILL.md"),
|
|
392
|
+
"---\nname: alpha\n---\nAlpha skill\n",
|
|
393
|
+
"utf8",
|
|
394
|
+
);
|
|
395
|
+
await writeFile(
|
|
396
|
+
join(packageDir, "nested", "beta", "SKILL.md"),
|
|
397
|
+
"---\nname: beta\n---\nBeta skill\n",
|
|
398
|
+
"utf8",
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
const result = await removeSkillsFromPackage(projectDir, packageDir);
|
|
402
|
+
expect(result.removed).toEqual(["skills/remove-skills-package"]);
|
|
403
|
+
expect(result.missing).toEqual([]);
|
|
404
|
+
await expect(lstat(join(projectDir, "skills", "remove-skills-package"))).rejects.toThrow();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it("removes a specific skill path from namespaced folder", async () => {
|
|
408
|
+
const projectDir = join(tempDir, "remove-single-skill-agent");
|
|
409
|
+
const packageDir = join(tempDir, "remove-single-skill-package");
|
|
410
|
+
await mkdir(
|
|
411
|
+
join(projectDir, "skills", "remove-single-skill-package", "alpha"),
|
|
412
|
+
{ recursive: true },
|
|
413
|
+
);
|
|
414
|
+
await mkdir(
|
|
415
|
+
join(projectDir, "skills", "remove-single-skill-package", "beta"),
|
|
416
|
+
{ recursive: true },
|
|
417
|
+
);
|
|
418
|
+
await writeFile(
|
|
419
|
+
join(projectDir, "skills", "remove-single-skill-package", "alpha", "SKILL.md"),
|
|
420
|
+
"alpha\n",
|
|
421
|
+
"utf8",
|
|
422
|
+
);
|
|
423
|
+
await writeFile(
|
|
424
|
+
join(projectDir, "skills", "remove-single-skill-package", "beta", "SKILL.md"),
|
|
425
|
+
"beta\n",
|
|
426
|
+
"utf8",
|
|
427
|
+
);
|
|
428
|
+
await mkdir(join(packageDir, "alpha"), { recursive: true });
|
|
429
|
+
await mkdir(join(packageDir, "nested", "beta"), { recursive: true });
|
|
430
|
+
await writeFile(join(packageDir, "alpha", "SKILL.md"), "---\nname: alpha\n---\n", "utf8");
|
|
431
|
+
await writeFile(
|
|
432
|
+
join(packageDir, "nested", "beta", "SKILL.md"),
|
|
433
|
+
"---\nname: beta\n---\n",
|
|
434
|
+
"utf8",
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
const result = await removeSkillsFromPackage(projectDir, packageDir, { path: "nested/beta" });
|
|
438
|
+
expect(result.removed).toEqual(["skills/remove-single-skill-package/beta"]);
|
|
439
|
+
await expect(
|
|
440
|
+
lstat(join(projectDir, "skills", "remove-single-skill-package", "beta")),
|
|
441
|
+
).rejects.toThrow();
|
|
442
|
+
const alphaStillExists = await readFile(
|
|
443
|
+
join(projectDir, "skills", "remove-single-skill-package", "alpha", "SKILL.md"),
|
|
444
|
+
"utf8",
|
|
445
|
+
);
|
|
446
|
+
expect(alphaStillExists).toContain("alpha");
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it("lists installed skills with and without source filter", async () => {
|
|
450
|
+
const projectDir = join(tempDir, "list-skills-agent");
|
|
451
|
+
await mkdir(join(projectDir, "skills", "agent-skills", "alpha"), { recursive: true });
|
|
452
|
+
await mkdir(join(projectDir, "skills", "agent-skills", "beta"), { recursive: true });
|
|
453
|
+
await mkdir(join(projectDir, "skills", "other-source", "gamma"), { recursive: true });
|
|
454
|
+
await writeFile(
|
|
455
|
+
join(projectDir, "skills", "agent-skills", "alpha", "SKILL.md"),
|
|
456
|
+
"---\nname: alpha\n---\n",
|
|
457
|
+
"utf8",
|
|
458
|
+
);
|
|
459
|
+
await writeFile(
|
|
460
|
+
join(projectDir, "skills", "agent-skills", "beta", "SKILL.md"),
|
|
461
|
+
"---\nname: beta\n---\n",
|
|
462
|
+
"utf8",
|
|
463
|
+
);
|
|
464
|
+
await writeFile(
|
|
465
|
+
join(projectDir, "skills", "other-source", "gamma", "SKILL.md"),
|
|
466
|
+
"---\nname: gamma\n---\n",
|
|
467
|
+
"utf8",
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
const all = await listInstalledSkills(projectDir);
|
|
471
|
+
const filtered = await listInstalledSkills(projectDir, "vercel-labs/agent-skills");
|
|
472
|
+
|
|
473
|
+
expect(all).toEqual([
|
|
474
|
+
"skills/agent-skills/alpha",
|
|
475
|
+
"skills/agent-skills/beta",
|
|
476
|
+
"skills/other-source/gamma",
|
|
477
|
+
]);
|
|
478
|
+
expect(filtered).toEqual(["skills/agent-skills/alpha", "skills/agent-skills/beta"]);
|
|
479
|
+
});
|
|
480
|
+
|
|
281
481
|
it("supports smoke flow init -> dev -> api conversation endpoint", async () => {
|
|
282
482
|
await initProject("smoke-agent", { workingDir: tempDir });
|
|
283
483
|
const projectDir = join(tempDir, "smoke-agent");
|
|
@@ -634,6 +834,37 @@ describe("cli", () => {
|
|
|
634
834
|
expect(result.failed).toBe(0);
|
|
635
835
|
});
|
|
636
836
|
|
|
837
|
+
it("materializes symlinked skills into vercel build output", async () => {
|
|
838
|
+
const projectDir = join(tempDir, "symlink-skill-agent");
|
|
839
|
+
await mkdir(projectDir, { recursive: true });
|
|
840
|
+
await writeFile(join(projectDir, "AGENT.md"), "---\nname: symlink-agent\n---\n", "utf8");
|
|
841
|
+
await mkdir(join(projectDir, "skills"), { recursive: true });
|
|
842
|
+
|
|
843
|
+
const sourceSkillDir = join(projectDir, ".agents", "skills", "linked-skill");
|
|
844
|
+
await mkdir(sourceSkillDir, { recursive: true });
|
|
845
|
+
await writeFile(
|
|
846
|
+
join(sourceSkillDir, "SKILL.md"),
|
|
847
|
+
"---\nname: linked-skill\n---\nLinked skill\n",
|
|
848
|
+
"utf8",
|
|
849
|
+
);
|
|
850
|
+
|
|
851
|
+
await symlink(sourceSkillDir, join(projectDir, "skills", "linked-skill"));
|
|
852
|
+
await buildTarget(projectDir, "vercel");
|
|
853
|
+
|
|
854
|
+
const builtSkillDir = join(
|
|
855
|
+
projectDir,
|
|
856
|
+
".poncho-build",
|
|
857
|
+
"vercel",
|
|
858
|
+
"skills",
|
|
859
|
+
"linked-skill",
|
|
860
|
+
);
|
|
861
|
+
const builtSkillDirStat = await lstat(builtSkillDir);
|
|
862
|
+
const builtSkill = await readFile(join(builtSkillDir, "SKILL.md"), "utf8");
|
|
863
|
+
|
|
864
|
+
expect(builtSkillDirStat.isSymbolicLink()).toBe(false);
|
|
865
|
+
expect(builtSkill).toContain("name: linked-skill");
|
|
866
|
+
});
|
|
867
|
+
|
|
637
868
|
it("seeds bearer token placeholders in env files when adding mcp auth", async () => {
|
|
638
869
|
await initProject("mcp-env-seed-agent", { workingDir: tempDir });
|
|
639
870
|
const projectDir = join(tempDir, "mcp-env-seed-agent");
|