@yoyo-bot/cli 0.1.0 → 0.1.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/README.md +10 -0
- package/dist/commands/bind.d.ts.map +1 -1
- package/dist/commands/bind.js +40 -68
- package/dist/commands/bind.js.map +1 -1
- package/dist/commands/list.d.ts +0 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +10 -10
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +43 -30
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +9 -6
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +13 -7
- package/dist/commands/whoami.js.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +68 -30
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +21 -10
- package/dist/lib/api.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/bind.ts +41 -71
- package/src/commands/list.ts +12 -12
- package/src/commands/publish.ts +48 -32
- package/src/commands/search.ts +10 -6
- package/src/commands/whoami.ts +12 -6
- package/src/index.ts +1 -2
- package/src/lib/api.ts +65 -39
package/dist/lib/api.d.ts
CHANGED
|
@@ -4,57 +4,95 @@ export declare class ApiError extends Error {
|
|
|
4
4
|
constructor(status: number, message: string, body?: unknown | undefined);
|
|
5
5
|
}
|
|
6
6
|
export interface BinderSummary {
|
|
7
|
-
owner: string;
|
|
8
7
|
slug: string;
|
|
9
|
-
|
|
8
|
+
name: string;
|
|
10
9
|
description?: string;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
category?: string;
|
|
11
|
+
latestVersion?: string;
|
|
12
|
+
installCount?: number;
|
|
13
|
+
starCount?: number;
|
|
15
14
|
tags?: string[];
|
|
15
|
+
featured?: boolean;
|
|
16
|
+
authorName?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface BinderFile {
|
|
19
|
+
id: string;
|
|
20
|
+
filename: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
content: string;
|
|
23
|
+
fileType: string;
|
|
24
|
+
fileSize: number;
|
|
25
|
+
sortOrder: number;
|
|
16
26
|
}
|
|
17
27
|
export interface BinderDetail extends BinderSummary {
|
|
18
|
-
|
|
19
|
-
|
|
28
|
+
id: string;
|
|
29
|
+
longDescription?: string;
|
|
30
|
+
files?: BinderFile[];
|
|
31
|
+
versions?: Array<{
|
|
20
32
|
version: string;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
publishedAt: string;
|
|
34
|
+
}>;
|
|
35
|
+
author?: {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
displayName?: string;
|
|
24
39
|
};
|
|
25
40
|
}
|
|
26
41
|
export interface SearchResult {
|
|
27
|
-
|
|
42
|
+
binders: BinderSummary[];
|
|
28
43
|
total: number;
|
|
29
|
-
page: number;
|
|
30
|
-
pageSize: number;
|
|
31
44
|
}
|
|
32
45
|
export interface WhoamiResult {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
agent: {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
displayName?: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
avatarUrl?: string;
|
|
52
|
+
};
|
|
37
53
|
}
|
|
38
54
|
export declare const api: {
|
|
39
55
|
search: (q: string, page?: number, pageSize?: number) => Promise<SearchResult>;
|
|
40
|
-
getBinder: (
|
|
41
|
-
|
|
56
|
+
getBinder: (slug: string) => Promise<{
|
|
57
|
+
binder: BinderDetail;
|
|
58
|
+
}>;
|
|
59
|
+
getInstallBundle: (slug: string) => Promise<{
|
|
60
|
+
instructions: string;
|
|
61
|
+
binder: unknown;
|
|
62
|
+
}>;
|
|
63
|
+
listBinders: (page?: number, pageSize?: number) => Promise<SearchResult>;
|
|
64
|
+
listMyBinders: () => Promise<{
|
|
65
|
+
binders: BinderSummary[];
|
|
66
|
+
}>;
|
|
42
67
|
whoami: () => Promise<WhoamiResult>;
|
|
43
68
|
publish: (data: {
|
|
44
69
|
slug: string;
|
|
45
|
-
|
|
70
|
+
name: string;
|
|
46
71
|
description?: string;
|
|
47
|
-
|
|
48
|
-
|
|
72
|
+
longDescription?: string;
|
|
73
|
+
category?: string;
|
|
49
74
|
tags?: string[];
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
latestVersion?: string;
|
|
76
|
+
files?: Array<{
|
|
77
|
+
filename: string;
|
|
78
|
+
content: string;
|
|
79
|
+
fileType?: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
}>;
|
|
54
82
|
}) => Promise<{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
83
|
+
binder: BinderDetail;
|
|
84
|
+
}>;
|
|
85
|
+
addFiles: (slug: string, files: Array<{
|
|
86
|
+
filename: string;
|
|
87
|
+
content: string;
|
|
88
|
+
fileType?: string;
|
|
89
|
+
description?: string;
|
|
90
|
+
}>) => Promise<{
|
|
91
|
+
success: boolean;
|
|
92
|
+
filesAdded: number;
|
|
93
|
+
}>;
|
|
94
|
+
deleteBinder: (slug: string) => Promise<{
|
|
95
|
+
success: boolean;
|
|
58
96
|
}>;
|
|
59
97
|
};
|
|
60
98
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/lib/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAEA,qBAAa,QAAS,SAAQ,KAAK;IAExB,MAAM,EAAE,MAAM;IAEd,IAAI,CAAC,EAAE,OAAO;gBAFd,MAAM,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACR,IAAI,CAAC,EAAE,OAAO,YAAA;CAKxB;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/api.js
CHANGED
|
@@ -27,7 +27,15 @@ async function request(method, path, opts = {}) {
|
|
|
27
27
|
let detail = "";
|
|
28
28
|
try {
|
|
29
29
|
const j = (await res.json());
|
|
30
|
-
|
|
30
|
+
if (typeof j.error === "string") {
|
|
31
|
+
detail = j.error;
|
|
32
|
+
}
|
|
33
|
+
else if (j.error && typeof j.error === "object") {
|
|
34
|
+
detail = j.error.message || JSON.stringify(j.error);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
detail = j.message ?? "";
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
40
|
catch { }
|
|
33
41
|
throw new ApiError(res.status, detail || res.statusText);
|
|
@@ -36,19 +44,22 @@ async function request(method, path, opts = {}) {
|
|
|
36
44
|
}
|
|
37
45
|
// ── API calls ──────────────────────────────────────────────────────────────
|
|
38
46
|
export const api = {
|
|
39
|
-
search: (q, page = 1, pageSize = 20) => request("GET", `/binders?q=${encodeURIComponent(q)}&
|
|
47
|
+
search: (q, page = 1, pageSize = 20) => request("GET", `/binders?q=${encodeURIComponent(q)}&limit=${pageSize}&offset=${(page - 1) * pageSize}`, {
|
|
40
48
|
auth: false,
|
|
41
49
|
}),
|
|
42
|
-
getBinder: (
|
|
50
|
+
getBinder: (slug) => request("GET", `/binders/${encodeURIComponent(slug)}`, {
|
|
43
51
|
auth: false,
|
|
44
52
|
}),
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
|
|
53
|
+
getInstallBundle: (slug) => request("GET", `/binders/${encodeURIComponent(slug)}/install`, {
|
|
54
|
+
auth: false,
|
|
55
|
+
}),
|
|
56
|
+
listBinders: (page = 1, pageSize = 20) => request("GET", `/binders?limit=${pageSize}&offset=${(page - 1) * pageSize}`, {
|
|
57
|
+
auth: false,
|
|
58
|
+
}),
|
|
59
|
+
listMyBinders: () => request("GET", "/binders/my"),
|
|
60
|
+
whoami: () => request("GET", "/agents/me"),
|
|
52
61
|
publish: (data) => request("POST", "/binders", { body: data }),
|
|
62
|
+
addFiles: (slug, files) => request("POST", `/binders/${encodeURIComponent(slug)}/files`, { body: { files } }),
|
|
63
|
+
deleteBinder: (slug) => request("DELETE", `/binders/${encodeURIComponent(slug)}`),
|
|
53
64
|
};
|
|
54
65
|
//# sourceMappingURL=api.js.map
|
package/dist/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,OAAO,QAAS,SAAQ,KAAK;IAExB;IAEA;IAHT,YACS,MAAc,EACrB,OAAe,EACR,IAAc;QAErB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJR,WAAM,GAAN,MAAM,CAAQ;QAEd,SAAI,GAAJ,IAAI,CAAU;QAGrB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,KAAK,UAAU,OAAO,CACpB,MAAc,EACd,IAAY,EACZ,OAA2C,EAAE;IAE7C,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;IAC7B,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;IAE/E,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC;QAC9B,IAAI,GAAG;YAAE,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,GAAG,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM;QACN,OAAO;QACP,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KACtE,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/commands/bind.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { writeFile, mkdir } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { createHash } from "node:crypto";
|
|
5
|
-
import { unlink } from "node:fs/promises";
|
|
6
4
|
import pc from "picocolors";
|
|
7
5
|
import { api, ApiError } from "../lib/api.js";
|
|
8
6
|
|
|
@@ -17,12 +15,17 @@ function defaultBindRoot(): string {
|
|
|
17
15
|
return join(homedir(), ".yoyo", "binders");
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
// Bug fix #5: Accept both "owner/slug" and just "slug"
|
|
19
|
+
function parseRef(ref: string): { slug: string } {
|
|
21
20
|
const parts = ref.split("/");
|
|
22
|
-
if (parts.length
|
|
23
|
-
|
|
21
|
+
if (parts.length === 2) {
|
|
22
|
+
// owner/slug format — use just the slug
|
|
23
|
+
return { slug: parts[1] };
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
if (parts.length === 1 && parts[0]) {
|
|
26
|
+
return { slug: parts[0] };
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`Invalid binder ref "${ref}". Use: yoyo bind <slug> or yoyo bind <owner>/<slug>`);
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
function formatBytes(n: number): string {
|
|
@@ -32,50 +35,39 @@ function formatBytes(n: number): string {
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
export async function bindCommand(ref: string, opts: BindOptions): Promise<void> {
|
|
35
|
-
let
|
|
38
|
+
let slug: string;
|
|
36
39
|
try {
|
|
37
|
-
({
|
|
40
|
+
({ slug } = parseRef(ref));
|
|
38
41
|
} catch (err) {
|
|
39
42
|
console.error(pc.red(String(err)));
|
|
40
43
|
process.exit(1);
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
if (!opts.json) process.stdout.write(pc.dim(`Fetching ${
|
|
46
|
+
if (!opts.json) process.stdout.write(pc.dim(`Fetching ${slug}…\n`));
|
|
44
47
|
|
|
45
|
-
let
|
|
48
|
+
let binderData;
|
|
46
49
|
try {
|
|
47
|
-
|
|
50
|
+
binderData = await api.getBinder(slug);
|
|
48
51
|
} catch (err) {
|
|
49
52
|
if (err instanceof ApiError && err.status === 404) {
|
|
50
|
-
console.error(pc.red(`Binder not found: ${
|
|
53
|
+
console.error(pc.red(`Binder not found: ${slug}`));
|
|
51
54
|
} else {
|
|
52
55
|
console.error(pc.red(`API error: ${String(err)}`));
|
|
53
56
|
}
|
|
54
57
|
process.exit(1);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
console.error(pc.red(`Binder ${ref} has no published versions.`));
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const bindDir = join(opts.dir ? resolve(opts.dir) : defaultBindRoot(), owner, slug);
|
|
60
|
+
const binder = binderData.binder;
|
|
61
|
+
const bindDir = join(opts.dir ? resolve(opts.dir) : defaultBindRoot(), slug);
|
|
64
62
|
|
|
65
63
|
if (opts.json) {
|
|
66
|
-
console.log(JSON.stringify({ ref, bindDir, dryRun: opts.dryRun ?? false, binder }, null, 2));
|
|
64
|
+
console.log(JSON.stringify({ ref, slug, bindDir, dryRun: opts.dryRun ?? false, binder }, null, 2));
|
|
67
65
|
return;
|
|
68
66
|
}
|
|
69
67
|
|
|
70
|
-
|
|
71
|
-
binder.verification === "official"
|
|
72
|
-
? pc.yellow(" ✦ Official")
|
|
73
|
-
: binder.verification === "verified"
|
|
74
|
-
? pc.green(" ✓ Verified")
|
|
75
|
-
: "";
|
|
76
|
-
|
|
77
|
-
console.log(`\n${pc.bold(binder.displayName ?? ref)}${badge} ${pc.dim(`v${spine.version}`)}`);
|
|
68
|
+
console.log(`\n${pc.bold(binder.name ?? slug)} ${pc.dim(`v${binder.latestVersion || "1.0.0"}`)}`);
|
|
78
69
|
if (binder.description) console.log(pc.dim(binder.description.slice(0, 80)));
|
|
70
|
+
if (binder.starCount) console.log(pc.yellow(`★ ${binder.starCount}`));
|
|
79
71
|
console.log(pc.dim("─".repeat(50)));
|
|
80
72
|
console.log(` ${pc.dim("Bind to")} ${pc.dim(bindDir)}`);
|
|
81
73
|
console.log();
|
|
@@ -89,59 +81,37 @@ export async function bindCommand(ref: string, opts: BindOptions): Promise<void>
|
|
|
89
81
|
|
|
90
82
|
// Write manifest
|
|
91
83
|
const manifest = {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
version: spine.version,
|
|
84
|
+
slug,
|
|
85
|
+
name: binder.name,
|
|
86
|
+
version: binder.latestVersion || "1.0.0",
|
|
96
87
|
description: binder.description,
|
|
97
|
-
|
|
88
|
+
category: binder.category,
|
|
98
89
|
tags: binder.tags ?? [],
|
|
99
90
|
boundAt: new Date().toISOString(),
|
|
100
|
-
tarballUrl: spine.tarballUrl,
|
|
101
|
-
tarballSha256: spine.tarballSha256,
|
|
102
91
|
};
|
|
103
92
|
await writeFile(join(bindDir, "binder.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
104
93
|
console.log(` ${pc.green("✓")} binder.json`);
|
|
105
94
|
|
|
106
|
-
//
|
|
107
|
-
if (
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
for (;;) {
|
|
117
|
-
const { done, value } = await reader.read();
|
|
118
|
-
if (done) break;
|
|
119
|
-
chunks.push(value);
|
|
120
|
-
total += value.byteLength;
|
|
121
|
-
}
|
|
122
|
-
const buf = Buffer.concat(chunks, total);
|
|
123
|
-
|
|
124
|
-
if (spine.tarballSha256) {
|
|
125
|
-
const actual = createHash("sha256").update(buf).digest("hex");
|
|
126
|
-
if (actual !== spine.tarballSha256) {
|
|
127
|
-
process.stdout.write(`\r ${pc.red("✗")} tarball SHA256 mismatch — aborting\n`);
|
|
128
|
-
console.error(pc.dim(` expected: ${spine.tarballSha256}\n got: ${actual}`));
|
|
129
|
-
await unlink(tarPath).catch(() => {});
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
await writeFile(tarPath, buf);
|
|
135
|
-
process.stdout.write(`\r ${pc.green("✓")} tarball (${pc.dim(formatBytes(total))})\n`);
|
|
136
|
-
} else {
|
|
137
|
-
process.stdout.write(`\r ${pc.dim("~ tarball skipped")}\n`);
|
|
138
|
-
}
|
|
139
|
-
} catch {
|
|
140
|
-
process.stdout.write(`\r ${pc.dim("~ tarball unavailable")}\n`);
|
|
95
|
+
// Write files
|
|
96
|
+
if (binder.files && binder.files.length > 0) {
|
|
97
|
+
for (const f of binder.files) {
|
|
98
|
+
const filePath = join(bindDir, f.filename);
|
|
99
|
+
// Create subdirectories if filename contains slashes
|
|
100
|
+
const dir = join(bindDir, f.filename.split("/").slice(0, -1).join("/"));
|
|
101
|
+
if (dir !== bindDir) await mkdir(dir, { recursive: true });
|
|
102
|
+
|
|
103
|
+
await writeFile(filePath, f.content, "utf8");
|
|
104
|
+
console.log(` ${pc.green("✓")} ${f.filename} ${pc.dim(`(${formatBytes(f.fileSize || f.content.length)})`)}`);
|
|
141
105
|
}
|
|
142
106
|
}
|
|
143
107
|
|
|
108
|
+
// Write longDescription as README.md
|
|
109
|
+
if (binder.longDescription) {
|
|
110
|
+
await writeFile(join(bindDir, "README.md"), binder.longDescription, "utf8");
|
|
111
|
+
console.log(` ${pc.green("✓")} README.md`);
|
|
112
|
+
}
|
|
113
|
+
|
|
144
114
|
console.log();
|
|
145
|
-
console.log(pc.green(`Bound ${
|
|
115
|
+
console.log(pc.green(`Bound ${slug}@${binder.latestVersion || "1.0.0"}`));
|
|
146
116
|
console.log(pc.dim(`Location: ${bindDir}`));
|
|
147
117
|
}
|
package/src/commands/list.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import pc from "picocolors";
|
|
2
2
|
import { api } from "../lib/api.js";
|
|
3
3
|
|
|
4
|
-
export async function listCommand(opts: {
|
|
4
|
+
export async function listCommand(opts: { page?: string; json?: boolean }): Promise<void> {
|
|
5
5
|
const page = Number(opts.page ?? 1);
|
|
6
6
|
const pageSize = 20;
|
|
7
7
|
|
|
8
8
|
let result;
|
|
9
9
|
try {
|
|
10
|
-
result = await api.listBinders(
|
|
10
|
+
result = await api.listBinders(page, pageSize);
|
|
11
11
|
} catch (err) {
|
|
12
12
|
console.error(pc.red(`Failed to list binders: ${String(err)}`));
|
|
13
13
|
process.exit(1);
|
|
@@ -18,21 +18,21 @@ export async function listCommand(opts: { owner?: string; page?: string; json?:
|
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const binders = result.binders ?? [];
|
|
22
|
+
|
|
23
|
+
if (binders.length === 0) {
|
|
22
24
|
console.log(pc.dim("No binders found."));
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
console.log(pc.bold(`\n${title}`) + pc.dim(` (${result.total} total)\n`));
|
|
28
|
+
console.log(pc.bold(`\nBinders`) + pc.dim(` (${result.total} total)\n`));
|
|
28
29
|
|
|
29
|
-
for (const b of
|
|
30
|
-
const name = pc.cyan(
|
|
31
|
-
const ver = b.
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
console.log(` ${name}${badge} ${ver}${dl}`);
|
|
30
|
+
for (const b of binders) {
|
|
31
|
+
const name = pc.cyan(b.slug);
|
|
32
|
+
const ver = b.latestVersion ? pc.dim(`v${b.latestVersion}`) : "";
|
|
33
|
+
const stars = b.starCount ? pc.yellow(` ★${b.starCount}`) : "";
|
|
34
|
+
const installs = b.installCount ? pc.dim(` ↓${b.installCount}`) : "";
|
|
35
|
+
console.log(` ${name}${stars}${installs} ${ver}`);
|
|
36
36
|
if (b.description) console.log(` ${pc.dim(b.description.slice(0, 80))}`);
|
|
37
37
|
console.log();
|
|
38
38
|
}
|
package/src/commands/publish.ts
CHANGED
|
@@ -14,9 +14,10 @@ interface PublishOptions {
|
|
|
14
14
|
interface BinderManifest {
|
|
15
15
|
slug: string;
|
|
16
16
|
displayName?: string;
|
|
17
|
+
name?: string;
|
|
17
18
|
description?: string;
|
|
18
19
|
version: string;
|
|
19
|
-
|
|
20
|
+
category?: string;
|
|
20
21
|
tags?: string[];
|
|
21
22
|
platforms?: string[];
|
|
22
23
|
license?: string;
|
|
@@ -56,34 +57,58 @@ export async function publishCommand(opts: PublishOptions): Promise<void> {
|
|
|
56
57
|
process.exit(1);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
// Read page.md
|
|
60
|
-
let
|
|
60
|
+
// Read page.md or README.md as longDescription
|
|
61
|
+
let longDescription: string | undefined;
|
|
61
62
|
const pagePath = join(cwd, "page.md");
|
|
62
63
|
if (existsSync(pagePath)) {
|
|
63
|
-
|
|
64
|
+
longDescription = await readFile(pagePath, "utf8");
|
|
64
65
|
} else {
|
|
65
66
|
const readmePath = join(cwd, "README.md");
|
|
66
|
-
if (existsSync(readmePath))
|
|
67
|
+
if (existsSync(readmePath)) longDescription = await readFile(readmePath, "utf8");
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
// Collect files from the binder directory
|
|
71
|
+
const files: Array<{ filename: string; content: string; fileType?: string; description?: string }> = [];
|
|
72
|
+
|
|
73
|
+
// Include common binder files if they exist
|
|
74
|
+
const filePatterns = [
|
|
75
|
+
{ path: "binder.md", fileType: "skill" },
|
|
76
|
+
{ path: "SKILL.md", fileType: "skill" },
|
|
77
|
+
{ path: "config.yaml", fileType: "config" },
|
|
78
|
+
{ path: "config.json", fileType: "config" },
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
for (const fp of filePatterns) {
|
|
82
|
+
const fullPath = join(cwd, fp.path);
|
|
83
|
+
if (existsSync(fullPath)) {
|
|
84
|
+
const content = await readFile(fullPath, "utf8");
|
|
85
|
+
files.push({ filename: fp.path, content, fileType: fp.fileType });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Bug fix #1: Map displayName → name (API requires "name", manifest uses "displayName")
|
|
90
|
+
const name = manifest.name || manifest.displayName || manifest.slug;
|
|
91
|
+
|
|
92
|
+
const payload = {
|
|
93
|
+
slug: manifest.slug,
|
|
94
|
+
name,
|
|
95
|
+
description: manifest.description,
|
|
96
|
+
longDescription,
|
|
97
|
+
category: manifest.category,
|
|
98
|
+
tags: manifest.tags ?? [],
|
|
99
|
+
latestVersion: manifest.version,
|
|
100
|
+
files: files.length > 0 ? files : undefined,
|
|
101
|
+
};
|
|
102
|
+
|
|
69
103
|
if (opts.dryRun || opts.json) {
|
|
70
|
-
const payload = {
|
|
71
|
-
slug: manifest.slug,
|
|
72
|
-
displayName: manifest.displayName,
|
|
73
|
-
description: manifest.description,
|
|
74
|
-
version: manifest.version,
|
|
75
|
-
readme,
|
|
76
|
-
tags: manifest.tags ?? [],
|
|
77
|
-
tab: manifest.tab,
|
|
78
|
-
license: manifest.license,
|
|
79
|
-
platforms: manifest.platforms ?? [],
|
|
80
|
-
dependencies: manifest.dependencies ?? {},
|
|
81
|
-
};
|
|
82
104
|
if (opts.json) {
|
|
83
105
|
console.log(JSON.stringify({ dryRun: opts.dryRun ?? false, payload }, null, 2));
|
|
84
106
|
} else {
|
|
85
107
|
console.log(pc.yellow("Dry run — would publish:"));
|
|
86
108
|
console.log(` ${manifest.slug}@${manifest.version}`);
|
|
109
|
+
console.log(` name: ${name}`);
|
|
110
|
+
if (longDescription) console.log(` longDescription: ${longDescription.length} chars`);
|
|
111
|
+
if (files.length) console.log(` files: ${files.map(f => f.filename).join(", ")}`);
|
|
87
112
|
}
|
|
88
113
|
return;
|
|
89
114
|
}
|
|
@@ -91,21 +116,12 @@ export async function publishCommand(opts: PublishOptions): Promise<void> {
|
|
|
91
116
|
console.log(pc.dim(`Publishing ${manifest.slug}@${manifest.version}…`));
|
|
92
117
|
|
|
93
118
|
try {
|
|
94
|
-
const result = await api.publish(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
tags: manifest.tags ?? [],
|
|
101
|
-
tab: manifest.tab,
|
|
102
|
-
license: manifest.license,
|
|
103
|
-
platforms: manifest.platforms ?? [],
|
|
104
|
-
dependencies: manifest.dependencies ?? {},
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
console.log(pc.green(`\nPublished ${result.slug}@${result.version}`));
|
|
108
|
-
console.log(pc.dim(`ID: ${result.id}`));
|
|
119
|
+
const result = await api.publish(payload);
|
|
120
|
+
|
|
121
|
+
console.log(pc.green(`\nPublished ${result.binder.slug}@${result.binder.latestVersion || manifest.version}`));
|
|
122
|
+
console.log(pc.dim(`ID: ${result.binder.id}`));
|
|
123
|
+
if (files.length) console.log(pc.dim(`Files: ${files.length} uploaded`));
|
|
124
|
+
console.log(pc.dim(`View: https://yoyo.bot/binders/${manifest.slug}`));
|
|
109
125
|
} catch (err) {
|
|
110
126
|
if (err instanceof ApiError) {
|
|
111
127
|
console.error(pc.red(`Publish failed (${err.status}): ${err.message}`));
|
package/src/commands/search.ts
CHANGED
|
@@ -17,18 +17,22 @@ export async function searchCommand(query: string, opts: { limit?: string; json?
|
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
// Bug fix #3: API returns result.binders, not result.items
|
|
21
|
+
const binders = result.binders ?? [];
|
|
22
|
+
|
|
23
|
+
if (binders.length === 0) {
|
|
21
24
|
console.log(pc.dim(`No results for "${query}"`));
|
|
22
25
|
return;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
console.log(pc.bold(`\nSearch results for "${query}"`) + pc.dim(` (${result.total} total)\n`));
|
|
26
29
|
|
|
27
|
-
for (const b of
|
|
28
|
-
const name = pc.cyan(
|
|
29
|
-
const ver = b.
|
|
30
|
-
const
|
|
31
|
-
|
|
30
|
+
for (const b of binders) {
|
|
31
|
+
const name = pc.cyan(b.slug);
|
|
32
|
+
const ver = b.latestVersion ? pc.dim(`v${b.latestVersion}`) : "";
|
|
33
|
+
const stars = b.starCount ? pc.yellow(` ★${b.starCount}`) : "";
|
|
34
|
+
const installs = b.installCount ? pc.dim(` ↓${b.installCount}`) : "";
|
|
35
|
+
console.log(` ${name}${stars}${installs} ${ver}`);
|
|
32
36
|
if (b.description) {
|
|
33
37
|
console.log(` ${pc.dim(b.description.slice(0, 80))}`);
|
|
34
38
|
}
|
package/src/commands/whoami.ts
CHANGED
|
@@ -9,26 +9,32 @@ export async function whoamiCommand(opts: { json?: boolean }): Promise<void> {
|
|
|
9
9
|
process.exit(1);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
let
|
|
12
|
+
let result;
|
|
13
13
|
try {
|
|
14
|
-
|
|
14
|
+
result = await api.whoami();
|
|
15
15
|
} catch (err) {
|
|
16
16
|
if (err instanceof ApiError && err.status === 401) {
|
|
17
17
|
console.error(pc.red("Invalid or expired API key. Run: yoyo auth"));
|
|
18
|
+
} else if (err instanceof ApiError) {
|
|
19
|
+
// Bug fix #4: properly stringify the error (was showing [object Object])
|
|
20
|
+
console.error(pc.red(`Error (${err.status}): ${err.message}`));
|
|
18
21
|
} else {
|
|
19
22
|
console.error(pc.red(`Error: ${String(err)}`));
|
|
20
23
|
}
|
|
21
24
|
process.exit(1);
|
|
22
25
|
}
|
|
23
26
|
|
|
27
|
+
const agent = result.agent;
|
|
28
|
+
|
|
24
29
|
if (opts.json) {
|
|
25
|
-
console.log(JSON.stringify(
|
|
30
|
+
console.log(JSON.stringify(agent, null, 2));
|
|
26
31
|
return;
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
console.log();
|
|
30
|
-
console.log(` ${pc.bold(
|
|
31
|
-
console.log(` ${pc.dim("
|
|
32
|
-
if (
|
|
35
|
+
console.log(` ${pc.bold(agent.displayName ?? agent.name)}`);
|
|
36
|
+
console.log(` ${pc.dim("Name")} ${agent.name}`);
|
|
37
|
+
if (agent.description) console.log(` ${pc.dim("About")} ${agent.description}`);
|
|
38
|
+
console.log(` ${pc.dim("ID")} ${agent.id}`);
|
|
33
39
|
console.log();
|
|
34
40
|
}
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ program
|
|
|
22
22
|
.action((query: string, opts) => searchCommand(query, opts));
|
|
23
23
|
|
|
24
24
|
program
|
|
25
|
-
.command("bind <
|
|
25
|
+
.command("bind <slug>")
|
|
26
26
|
.description("Bind (install) a binder to ~/.yoyo/binders/")
|
|
27
27
|
.option("-v, --version <ver>", "specific version")
|
|
28
28
|
.option("-d, --dir <path>", "bind root directory")
|
|
@@ -40,7 +40,6 @@ program
|
|
|
40
40
|
program
|
|
41
41
|
.command("list")
|
|
42
42
|
.description("List binders in the registry")
|
|
43
|
-
.option("--owner <slug>", "filter by owner")
|
|
44
43
|
.option("--page <n>", "page number", "1")
|
|
45
44
|
.option("--json", "output JSON")
|
|
46
45
|
.action((opts) => listCommand(opts));
|