@my-life-buddies/cli 0.28.0-dev.1 → 0.28.0-dev.3
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 +7 -3
- package/dist/bin/buddy.js +0 -9
- package/dist/bin/buddy.js.map +3 -3
- package/dist/bin/core.js +67 -71
- package/dist/bin/core.js.map +4 -4
- package/package.json +7 -6
- package/resources/brand/README.md +0 -11
- package/resources/brand/login-result.css +0 -25
- package/resources/brand/logo.png +0 -0
- package/resources/brand/tokens.css +0 -100
package/dist/bin/core.js
CHANGED
|
@@ -386,7 +386,8 @@ var resolveAvatarSkill = (previous, options = {}) => resolveSkillPackage(definit
|
|
|
386
386
|
|
|
387
387
|
// packages/cli-core/src/cloud/avatar.ts
|
|
388
388
|
import { open } from "node:fs/promises";
|
|
389
|
-
import { basename } from "node:path";
|
|
389
|
+
import { basename, extname } from "node:path";
|
|
390
|
+
import sharp from "sharp";
|
|
390
391
|
var MAX_BUDDY_AVATAR_BYTES = 5 * 1024 * 1024;
|
|
391
392
|
async function readBuddyAvatarFile(path) {
|
|
392
393
|
const file = await open(path, "r");
|
|
@@ -410,6 +411,33 @@ async function readBuddyAvatarFile(path) {
|
|
|
410
411
|
await file.close();
|
|
411
412
|
}
|
|
412
413
|
}
|
|
414
|
+
async function prepareBuddyAvatarUpload(source) {
|
|
415
|
+
const input = Buffer.from(source.bytes);
|
|
416
|
+
if (!input.length || input.length > MAX_BUDDY_AVATAR_BYTES) throw new Error("\u5934\u50CF\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u4E0D\u80FD\u8D85\u8FC7 5 MiB");
|
|
417
|
+
if (source.mediaType === "image/png") {
|
|
418
|
+
for (let at = 8; at + 12 <= input.length; ) {
|
|
419
|
+
const length = input.readUInt32BE(at);
|
|
420
|
+
if (input.toString("ascii", at + 4, at + 8) === "acTL") throw new Error("\u4EC5\u652F\u6301\u9759\u6001\u5934\u50CF\uFF0C\u4E0D\u652F\u6301\u52A8\u56FE");
|
|
421
|
+
at += length + 12;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const image = sharp(input, { failOn: "warning", limitInputPixels: 4096 * 4096 });
|
|
425
|
+
let meta2;
|
|
426
|
+
try {
|
|
427
|
+
meta2 = await image.metadata();
|
|
428
|
+
} catch {
|
|
429
|
+
throw new Error("\u56FE\u7247\u65E0\u6CD5\u89E3\u7801\u6216\u50CF\u7D20\u8FC7\u5927\uFF0C\u8BF7\u9009\u62E9\u5BBD\u9AD8\u4E0D\u8D85\u8FC7 4096 px \u7684\u9759\u6001 PNG\u3001JPEG\u3001WebP");
|
|
430
|
+
}
|
|
431
|
+
if (!["png", "jpeg", "webp"].includes(meta2.format ?? "")) throw new Error("\u4EC5\u652F\u6301 PNG\u3001JPEG\u3001WebP \u56FE\u7247\u6587\u4EF6");
|
|
432
|
+
if ((meta2.pages ?? 1) !== 1) throw new Error("\u4EC5\u652F\u6301\u9759\u6001\u5934\u50CF\uFF0C\u4E0D\u652F\u6301\u52A8\u56FE");
|
|
433
|
+
if (!meta2.width || !meta2.height || meta2.width > 4096 || meta2.height > 4096) throw new Error("\u5934\u50CF\u5BBD\u9AD8\u4E0D\u80FD\u8D85\u8FC7 4096 px");
|
|
434
|
+
try {
|
|
435
|
+
const bytes = await image.rotate().resize(512, 512, { fit: "cover", position: "centre" }).webp({ lossless: true }).timeout({ seconds: 10 }).toBuffer();
|
|
436
|
+
return { bytes, mediaType: "image/webp", fileName: `${basename(source.fileName, extname(source.fileName))}.webp` };
|
|
437
|
+
} catch {
|
|
438
|
+
throw new Error("\u5934\u50CF\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u56FE\u7247\u662F\u5426\u5B8C\u6574\uFF0C\u6216\u6362\u4E00\u5F20\u56FE\u7247\u91CD\u8BD5");
|
|
439
|
+
}
|
|
440
|
+
}
|
|
413
441
|
|
|
414
442
|
// packages/cli-core/src/process-lock.ts
|
|
415
443
|
import { randomUUID } from "node:crypto";
|
|
@@ -547,9 +575,10 @@ async function save(path, content) {
|
|
|
547
575
|
});
|
|
548
576
|
}
|
|
549
577
|
}
|
|
550
|
-
async function readImage(path) {
|
|
578
|
+
async function readImage(path, { forUpload = false } = {}) {
|
|
551
579
|
try {
|
|
552
|
-
|
|
580
|
+
const source = await readBuddyAvatarFile(path);
|
|
581
|
+
return forUpload ? await prepareBuddyAvatarUpload(source) : source;
|
|
553
582
|
} catch (error2) {
|
|
554
583
|
throw new MetaPreparationError(`\u5934\u50CF\u672A\u5B8C\u6210\uFF1A${error2 instanceof Error ? error2.message : "\u65E0\u6CD5\u8BFB\u53D6\u56FE\u7247"}\u3002\u672C\u5730\u8D44\u6599\u5DF2\u4FDD\u7559\uFF0C\u5C1A\u672A\u63D0\u4EA4\u8FD9\u5F20\u5934\u50CF\u3002`);
|
|
555
584
|
}
|
|
@@ -603,10 +632,9 @@ ${JSON.stringify(argv, null, 2)}
|
|
|
603
632
|
|
|
604
633
|
\u4E0A\u4F20\u5931\u8D25\u6CBF\u7528\u5DF2\u4FDD\u5B58\u7684 buddyId \u548C\u5019\u9009\u56FE\u7247\uFF0C\u5728\u539F\u76EE\u5F55\u91CD\u8BD5\uFF0C\u4E0D\u53E6\u5EFA\u642D\u5B50\u3002\u5DF2\u6709\u4E91\u7AEF\u5934\u50CF\u4FDD\u7559\uFF1B\u53EA\u6709\u7528\u6237\u660E\u786E\u8981\u6C42\u66FF\u6362\u65F6\u624D\u4F7F\u7528 buddy-cli-sit meta update --avatar\u3002\u5B8C\u6210\u540E\u8BFB\u53D6 CLI \u8FD4\u56DE\u7684 Creator HANDOFF \u6216 Runtime \u5F00\u53D1\u6307\u5F15\u7EE7\u7EED\u3002
|
|
605
634
|
|
|
606
|
-
\
|
|
635
|
+
\u5DF2\u6709\u56FE\u7247\u53EF\u901A\u8FC7 --avatar \u6307\u5B9A\uFF0C\u65E0\u9700\u4F7F\u7528\u751F\u6210 Skill\u3002\u8BF7\u5728 Agent \u5BF9\u8BDD\u4E2D\u5C55\u793A\u8D44\u6599\u548C\u56FE\u7247\u5E76\u53D6\u5F97\u786E\u8BA4\uFF1BCLI \u4E0D\u751F\u6210\u6216\u6253\u5F00\u672C\u5730\u9884\u89C8\u9875\u3002
|
|
607
636
|
`;
|
|
608
637
|
}
|
|
609
|
-
var escape = (text2) => text2.replace(/[&<>"']/gu, (character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]);
|
|
610
638
|
async function prepareAndRegisterMeta(options) {
|
|
611
639
|
const draft = await readMetaDraft(options.root);
|
|
612
640
|
if (options.requestedBuddyId && (!draft || draft.status === "complete")) return options.requestedBuddyId;
|
|
@@ -679,10 +707,8 @@ async function prepareLockedMeta(options) {
|
|
|
679
707
|
io.write(`\u5934\u50CF\u672A\u5B8C\u6210\uFF0C\u5DF2\u4FDD\u5B58\u672C\u5730\u8D44\u6599\uFF0C\u5C1A\u672A\u521B\u5EFA\u4E91\u7AEF\u642D\u5B50\u3002\u8BF7\u8BA9 Coding Agent \u8BFB\u53D6 ${join4(folder(root), "HANDOFF.md")}\uFF1B\u6216\u4F7F\u7528 --avatar <\u56FE\u7247\u8DEF\u5F84> \u7EE7\u7EED\u3002`);
|
|
680
708
|
return void 0;
|
|
681
709
|
}
|
|
682
|
-
const upload = await readImage(join4(folder(root), draft.avatarPath));
|
|
710
|
+
const upload = await readImage(join4(folder(root), draft.avatarPath), { forUpload: true });
|
|
683
711
|
const confirmation = hash(JSON.stringify([profile.name, profile.tagline, profile.intro, hash(upload.bytes)]));
|
|
684
|
-
const preview = join4(folder(root), "preview.html");
|
|
685
|
-
await save(preview, `<!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>\u786E\u8BA4\u642D\u5B50\u8D44\u6599\u4E0E\u5934\u50CF</title><style>body{font:18px system-ui;max-width:800px;margin:48px auto;padding:24px;color:#163342}p{white-space:pre-wrap}section{display:flex;gap:24px}figure{margin:0;padding:24px;background:#eef4f8;border-radius:12px}figure.dark{background:#183040}img{width:220px;height:220px;object-fit:contain;border-radius:50%}</style><h1>${escape(profile.name)}</h1><p>${escape(profile.tagline)}</p><p>${escape(profile.intro)}</p><section><figure><img alt="\u6D45\u8272\u80CC\u666F\u5934\u50CF" src="data:${upload.mediaType};base64,${Buffer.from(upload.bytes).toString("base64")}"></figure><figure class="dark"><img alt="\u6DF1\u8272\u80CC\u666F\u5934\u50CF" src="data:${upload.mediaType};base64,${Buffer.from(upload.bytes).toString("base64")}"></figure></section><p>\u67E5\u770B\u5934\u50CF\u548C\u8D44\u6599\u540E\uFF0C\u56DE\u5230\u7EC8\u7AEF\u786E\u8BA4\u3002\u6B64\u9875\u9762\u4E0D\u4F1A\u4E0A\u4F20\u4EFB\u4F55\u5185\u5BB9\u3002</p></html>`);
|
|
686
712
|
if (draft.confirmed !== confirmation) {
|
|
687
713
|
draft.status = "awaiting_confirmation";
|
|
688
714
|
delete draft.confirmed;
|
|
@@ -690,16 +716,8 @@ async function prepareLockedMeta(options) {
|
|
|
690
716
|
io.write(`\u5F85\u786E\u8BA4\u8D44\u6599\uFF1A${profile.name}
|
|
691
717
|
${profile.tagline}
|
|
692
718
|
${profile.intro}
|
|
693
|
-
\u5934\u50CF\
|
|
694
|
-
|
|
695
|
-
if (!confirmed && io.canPrompt) {
|
|
696
|
-
await io.openMetaPreview?.(preview);
|
|
697
|
-
confirmed = await io.select("\u5DF2\u67E5\u770B\u5934\u50CF\uFF0C\u786E\u8BA4\u8FD9\u4EFD\u8D44\u6599\u548C\u5934\u50CF\u5E76\u767B\u8BB0\u5230\u5E73\u53F0\uFF1F", [
|
|
698
|
-
{ value: "later", label: "\u6682\u4E0D\u767B\u8BB0\uFF0C\u4FDD\u7559\u8349\u7A3F" },
|
|
699
|
-
{ value: "confirm", label: "\u786E\u8BA4\u5E76\u767B\u8BB0" }
|
|
700
|
-
], { defaultValue: "later" }) === "confirm";
|
|
701
|
-
}
|
|
702
|
-
if (!confirmed) {
|
|
719
|
+
\u5934\u50CF\u6587\u4EF6\uFF1A${join4(folder(root), draft.avatarPath)}`);
|
|
720
|
+
if (options.confirmMeta !== true) {
|
|
703
721
|
io.write("\u5F85\u5F00\u53D1\u8005\u786E\u8BA4\uFF0C\u5C1A\u672A\u8C03\u7528 Meta \u5199\u63A5\u53E3\u3002Coding Agent \u5C55\u793A\u5934\u50CF\u5E76\u53D6\u5F97\u660E\u786E\u786E\u8BA4\u540E\uFF0C\u4F7F\u7528 --avatar <\u5DF2\u786E\u8BA4\u56FE\u7247> --confirm-meta \u7EE7\u7EED\u3002");
|
|
704
722
|
return void 0;
|
|
705
723
|
}
|
|
@@ -3138,38 +3156,6 @@ var IMPLEMENTATION_GUIDE = implementationGuide();
|
|
|
3138
3156
|
import { createHash as createHash4, randomBytes } from "node:crypto";
|
|
3139
3157
|
import { spawn } from "node:child_process";
|
|
3140
3158
|
import { createServer } from "node:http";
|
|
3141
|
-
|
|
3142
|
-
// packages/cli-core/src/cloud/login-result.ts
|
|
3143
|
-
import { readFileSync } from "node:fs";
|
|
3144
|
-
var brand = new URL("../../resources/brand/", import.meta.url);
|
|
3145
|
-
var tokens = readFileSync(new URL("tokens.css", brand), "utf8");
|
|
3146
|
-
var styles = readFileSync(new URL("login-result.css", brand), "utf8");
|
|
3147
|
-
var logo = readFileSync(new URL("logo.png", brand)).toString("base64");
|
|
3148
|
-
function escapeHtml(value) {
|
|
3149
|
-
return value.replace(/[&<>"']/gu, (character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]);
|
|
3150
|
-
}
|
|
3151
|
-
function renderLoginResult(title, message, webUrl, tone) {
|
|
3152
|
-
const label = { success: "\u5DF2\u6388\u6743", neutral: "\u5DF2\u53D6\u6D88", error: "\u672A\u5B8C\u6210" }[tone];
|
|
3153
|
-
return `<!doctype html>
|
|
3154
|
-
<html lang="zh-CN"><head>
|
|
3155
|
-
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
3156
|
-
<meta name="color-scheme" content="light dark"><title>${escapeHtml(title)} \xB7 \u642D\u642D\u521B\u4F5C\u8005\u5E73\u53F0</title>
|
|
3157
|
-
<style>${tokens}
|
|
3158
|
-
${styles}</style></head>
|
|
3159
|
-
<body><div class="result-shell">
|
|
3160
|
-
<header class="result-brand"><img src="data:image/png;base64,${logo}" alt="" width="44" height="44"><span>\u642D\u642D\u521B\u4F5C\u8005\u5E73\u53F0</span></header>
|
|
3161
|
-
<main class="result-card" aria-labelledby="result-title">
|
|
3162
|
-
<div class="result-heading"><p class="result-eyebrow">buddy-cli-sit \u767B\u5F55</p><span class="result-status" data-tone="${tone}">${label}</span></div>
|
|
3163
|
-
<h1 id="result-title">${escapeHtml(title)}</h1>
|
|
3164
|
-
<p class="result-message">${escapeHtml(message)}</p>
|
|
3165
|
-
<div class="result-next"><strong>${tone === "success" ? "\u56DE\u5230\u7EC8\u7AEF\uFF0C\u7EE7\u7EED\u521B\u4F5C" : "\u56DE\u5230\u7EC8\u7AEF\uFF0C\u91CD\u65B0\u5F00\u59CB"}</strong>
|
|
3166
|
-
<p>${tone === "success" ? "\u67E5\u770B CLI \u7684\u767B\u5F55\u7ED3\u679C\uFF0C\u7EE7\u7EED\u521B\u5EFA\u3001\u5F00\u53D1\u548C\u9884\u89C8\u4F60\u7684\u642D\u5B50\u3002" : "\u9700\u8981\u7EE7\u7EED\u65F6\uFF0C\u5728\u7EC8\u7AEF\u91CD\u65B0\u8FD0\u884C\u767B\u5F55\u547D\u4EE4\u3002"}</p>
|
|
3167
|
-
${tone === "success" ? "" : "<code>buddy-cli-sit login</code>"}</div>
|
|
3168
|
-
<a class="result-link" href="${escapeHtml(webUrl.href)}">\u8FD4\u56DE\u5F00\u653E\u5E73\u53F0</a>
|
|
3169
|
-
</main><footer>\u642D\u642D\u521B\u4F5C\u8005\u5E73\u53F0</footer></div></body></html>`;
|
|
3170
|
-
}
|
|
3171
|
-
|
|
3172
|
-
// packages/cli-core/src/cloud/browser-login.ts
|
|
3173
3159
|
var DEFAULT_LOGIN_TIMEOUT_MS = 5 * 6e4;
|
|
3174
3160
|
var DEFAULT_EXCHANGE_TIMEOUT_MS = 15e3;
|
|
3175
3161
|
var DEFAULT_DEVELOPER_WEB_URL = new URL("/developer/", DEFAULT_MLB_TEST_URL).href;
|
|
@@ -3192,19 +3178,23 @@ async function openExternalUrl(url) {
|
|
|
3192
3178
|
child.once("exit", (code2) => code2 === 0 ? resolve20() : reject(new Error(`browser launcher exited with ${code2 ?? "unknown"}`)));
|
|
3193
3179
|
});
|
|
3194
3180
|
}
|
|
3195
|
-
async function
|
|
3196
|
-
|
|
3181
|
+
async function redirectResult(res, webUrl, status) {
|
|
3182
|
+
const destination = new URL(webUrl);
|
|
3183
|
+
destination.search = "";
|
|
3184
|
+
destination.hash = `/cli-result?status=${status}`;
|
|
3185
|
+
res.writeHead(303, {
|
|
3186
|
+
location: destination.href,
|
|
3197
3187
|
"cache-control": "no-store",
|
|
3198
3188
|
"connection": "close",
|
|
3199
|
-
"content-security-policy": "default-src 'none';
|
|
3200
|
-
"content-
|
|
3189
|
+
"content-security-policy": "default-src 'none'; frame-ancestors 'none'; base-uri 'none'",
|
|
3190
|
+
"content-length": "0",
|
|
3201
3191
|
"referrer-policy": "no-referrer",
|
|
3202
3192
|
"x-content-type-options": "nosniff"
|
|
3203
3193
|
});
|
|
3204
3194
|
await new Promise((resolve20, reject) => {
|
|
3205
3195
|
res.once("error", reject);
|
|
3206
3196
|
res.once("close", resolve20);
|
|
3207
|
-
res.end(
|
|
3197
|
+
res.end(resolve20);
|
|
3208
3198
|
});
|
|
3209
3199
|
}
|
|
3210
3200
|
async function readJson(response) {
|
|
@@ -3308,20 +3298,20 @@ var LoopbackBrowserLoginAdapter = class {
|
|
|
3308
3298
|
async #receiveCallback(req, res, expected) {
|
|
3309
3299
|
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
3310
3300
|
if (req.method !== "GET" || url.pathname !== `/callback/${expected.callbackSecret}`) {
|
|
3311
|
-
await
|
|
3301
|
+
await redirectResult(res, this.#developerWebUrl, "invalid");
|
|
3312
3302
|
throw new CloudLifecycleError("AUTH_LOGIN_CANCELLED", "\u6D4F\u89C8\u5668\u56DE\u8C03\u65E0\u6548\uFF0C\u8BF7\u91CD\u8BD5");
|
|
3313
3303
|
}
|
|
3314
3304
|
if (url.searchParams.get("state") !== expected.state) {
|
|
3315
|
-
await
|
|
3305
|
+
await redirectResult(res, this.#developerWebUrl, "invalid");
|
|
3316
3306
|
throw new CloudLifecycleError("AUTH_STATE_MISMATCH", "\u6D4F\u89C8\u5668\u767B\u5F55\u8FD4\u56DE\u7684 state \u4E0D\u5339\u914D\uFF1B\u51ED\u636E\u672A\u4FDD\u5B58");
|
|
3317
3307
|
}
|
|
3318
3308
|
if (url.searchParams.get("error") === "access_denied") {
|
|
3319
|
-
await
|
|
3309
|
+
await redirectResult(res, this.#developerWebUrl, "cancelled");
|
|
3320
3310
|
throw new CloudLifecycleError("AUTH_LOGIN_CANCELLED", "\u7528\u6237\u53D6\u6D88\u4E86 CLI \u6388\u6743");
|
|
3321
3311
|
}
|
|
3322
3312
|
const code2 = url.searchParams.get("code");
|
|
3323
3313
|
if (!code2 || !AUTH_CODE.test(code2) || !expected.requestId) {
|
|
3324
|
-
await
|
|
3314
|
+
await redirectResult(res, this.#developerWebUrl, "invalid");
|
|
3325
3315
|
throw new CloudLifecycleError("PLATFORM_RESPONSE_INVALID", "\u642D\u642D\u521B\u4F5C\u8005\u5E73\u53F0\u8FD4\u56DE\u4E86\u65E0\u6548\u6388\u6743\u7801");
|
|
3326
3316
|
}
|
|
3327
3317
|
try {
|
|
@@ -3333,7 +3323,7 @@ var LoopbackBrowserLoginAdapter = class {
|
|
|
3333
3323
|
if (exchanged.platformOrigin !== this.#platformUrl.origin || typeof exchanged.token !== "string" || typeof exchanged.userId !== "string" || !Number.isSafeInteger(exchanged.expiresAt)) {
|
|
3334
3324
|
throw new CloudLifecycleError("PLATFORM_RESPONSE_INVALID", "\u642D\u642D\u521B\u4F5C\u8005\u5E73\u53F0\u8FD4\u56DE\u7684\u8D26\u53F7\u51ED\u636E\u4E0D\u5B8C\u6574");
|
|
3335
3325
|
}
|
|
3336
|
-
await
|
|
3326
|
+
await redirectResult(res, this.#developerWebUrl, "authorized");
|
|
3337
3327
|
return {
|
|
3338
3328
|
state: expected.state,
|
|
3339
3329
|
token: {
|
|
@@ -3343,7 +3333,7 @@ var LoopbackBrowserLoginAdapter = class {
|
|
|
3343
3333
|
}
|
|
3344
3334
|
};
|
|
3345
3335
|
} catch (error2) {
|
|
3346
|
-
await
|
|
3336
|
+
if (!res.headersSent) await redirectResult(res, this.#developerWebUrl, "failed");
|
|
3347
3337
|
throw error2;
|
|
3348
3338
|
}
|
|
3349
3339
|
}
|
|
@@ -3425,6 +3415,7 @@ direct \u751F\u6210\u65B0\u4E1A\u52A1\u5DE5\u5382\u524D\uFF0C\u6309\u6700\u65B0
|
|
|
3425
3415
|
\u540C\u76EE\u5F55\u6062\u590D\u4FDD\u7559\u5DF2\u6709\u4E1A\u52A1\u6587\u4EF6\u3002create \u540E\u6309 .buddy/creator/HANDOFF.md \u7EE7\u7EED\uFF0Cdirect \u540E\u5B89\u88C5\u4F9D\u8D56\u5E76\u5B9E\u73B0\u4E1A\u52A1\u3002
|
|
3426
3416
|
Creator \u6BCF\u6B21\u8FDB\u5165\u6216\u6062\u590D\u90FD\u67E5\u8BE2\u516C\u5171 npm latest\uFF1B\u6709 Creator \u8BB0\u5F55\u7684\u5B8C\u6574\u5DE5\u7A0B\u4E5F\u53EF\u6267\u884C create \u63A5\u7EED\u521B\u4F5C\uFF0C\u4E0D\u91CD\u5EFA\u4E1A\u52A1\u6587\u4EF6\u3002
|
|
3427
3417
|
\u5DF2\u767B\u8BB0\u642D\u5B50\u7684\u540D\u79F0\u3001\u4ECB\u7ECD\u6216\u5934\u50CF\u7528 buddy-cli-sit meta update \u4FEE\u6539\uFF1Binit \u4E0D\u8986\u76D6\u4E91\u7AEF\u8D44\u6599\u3002
|
|
3418
|
+
\u5934\u50CF\u4E0A\u4F20\u8BF7\u6C42\u6700\u591A\u7B49\u5F85 5 \u5206\u949F\uFF0CCLI \u4E0A\u4F20\u524D\u5C45\u4E2D\u88C1\u5207\u81F3 512\xD7512 \u65E0\u635F WebP\uFF0C\u4FDD\u7559\u989C\u8272\u3001\u900F\u660E\u5EA6\u4E0E\u539F\u59CB\u6587\u4EF6\uFF1B\u666E\u901A\u8BF7\u6C42\u4ECD\u4E3A 30 \u79D2\u3002
|
|
3428
3419
|
|
|
3429
3420
|
\u793A\u4F8B:
|
|
3430
3421
|
buddy-cli-sit init --mode direct --directory ./my-buddy --name "\u505A\u996D\u642D\u5B50" --tagline "\u5E2E\u4F60\u5B89\u6392\u665A\u996D" --intro "\u6839\u636E\u73B0\u6709\u98DF\u6750\u63A8\u8350\u83DC\u8C31"
|
|
@@ -3476,8 +3467,8 @@ Coding Agent \u5E94\u76F4\u63A5\u6CBF\u7528\u7528\u6237\u660E\u786E\u63D0\u4F9B\
|
|
|
3476
3467
|
--buddy-id \u53EA\u7528\u4E8E\u6062\u590D\u5E73\u53F0\u5DF2\u7ECF\u751F\u6210\u4E14\u5C5E\u4E8E\u5F53\u524D\u8D26\u53F7\u7684\u642D\u5B50\u8EAB\u4EFD\uFF0C\u4E0D\u80FD\u81EA\u884C\u6307\u5B9A\u8EAB\u4EFD\u3002
|
|
3477
3468
|
\u65B0\u5EFA\u65F6\u9700\u8981\u751F\u6210\u5934\u50CF\u624D\u6309\u9700\u52A0\u8F7D\u72EC\u7ACB @my-life-buddies/avatar-creator-skill\uFF0C\u7531 Coding Agent \u8BFB\u53D6 .buddy/meta/HANDOFF.md \u4E0E\u5176\u4E2D\u6307\u5411\u7684 Skill\uFF0C\u8C03\u7528\u5BBF\u4E3B\u56FE\u7247\u751F\u6210\u80FD\u529B\u5E76\u5C55\u793A\u5B9E\u9645\u5934\u50CF\u3002\u5DF2\u6709\u56FE\u7247\u786E\u8BA4\u548C\u4E0A\u4F20\u4E0D\u4F9D\u8D56\u751F\u6210 Skill\u3002
|
|
3478
3469
|
\u5934\u50CF Skill \u7248\u672C\u8BB0\u5F55\u5728 .buddy/meta/skill-lock.json\uFF1B--avatar-skill-version <\u51C6\u786E\u7248\u672C> \u663E\u5F0F\u9009\u62E9\u7248\u672C\uFF0C\u672C\u5730\u8054\u8C03\u8BBE\u7F6E BUDDY_AVATAR_SKILL_PATH \u7EDD\u5BF9\u8DEF\u5F84\u3002
|
|
3479
|
-
\
|
|
3480
|
-
\
|
|
3470
|
+
\u4F7F\u7528 --avatar <\u56FE\u7247\u6587\u4EF6> \u6307\u5B9A\u5DF2\u6709\u5019\u9009\u5934\u50CF\uFF1BCLI \u4E0D\u6267\u884C\u56FE\u7247\u751F\u6210\uFF0C\u4E5F\u4E0D\u751F\u6210\u6216\u6253\u5F00\u672C\u5730\u9884\u89C8\u7F51\u9875\u3002\u8BF7\u8BA9 Coding Agent \u5728\u5BF9\u8BDD\u4E2D\u5C55\u793A\u5B9E\u9645\u56FE\u7247\u548C\u5B8C\u6574\u8D44\u6599\u3002
|
|
3471
|
+
\u53D6\u5F97\u5F00\u53D1\u8005\u5BF9\u5B9E\u9645\u5934\u50CF\u548C\u8D44\u6599\u7684\u660E\u786E\u786E\u8BA4\u540E\uFF0C\u624D\u53EF\u4F20 --avatar <\u5DF2\u786E\u8BA4\u56FE\u7247> --confirm-meta\u3002\u672A\u786E\u8BA4\u4E0D\u5F97\u4F20\u8BE5\u6807\u5FD7\uFF1B\u7F3A\u5C11\u56FE\u7247\u6216\u786E\u8BA4\u65F6\u9000\u51FA\u7801\u4E3A 2\uFF0C\u8349\u7A3F\u4FDD\u7559\uFF0C\u53EF\u4EE5\u5728\u539F\u76EE\u5F55\u7EE7\u7EED\u3002
|
|
3481
3472
|
--mode create \u5B8C\u6210\u8D44\u6599\u548C\u5934\u50CF\u767B\u8BB0\u540E\uFF0C\u52A8\u6001\u83B7\u53D6\u72EC\u7ACB Creator Skill \u5E76\u751F\u6210\u63A5\u7EED\u8BF4\u660E\uFF0C\u652F\u6301 Creator \u63A5\u5165\u534F\u8BAE 1 \u548C 2\uFF1B\u9879\u76EE .buddy/creator/ \u4FDD\u5B58\u521B\u4F5C\u8D44\u6599\u4E0E skill-lock.json \u7248\u672C\u8BB0\u5F55\u3002\u6BCF\u6B21\u8FDB\u5165\u6216\u6062\u590D\u90FD\u67E5\u8BE2\u516C\u5171 npm latest\uFF0C\u786E\u8BA4\u662F\u6700\u65B0\u7248\u540E\u624D\u590D\u7528\u7F13\u5B58\uFF1Bskill-lock.json \u53EA\u8BB0\u5F55\u672C\u6B21\u7248\u672C\uFF0C\u4E0D\u56FA\u5B9A\u65E7\u7248\u672C\u3002\u67E5\u8BE2\u3001\u4E0B\u8F7D\u6216\u534F\u8BAE\u6821\u9A8C\u5931\u8D25\u65F6\u660E\u786E\u62A5\u9519\uFF0C\u4E0D\u9000\u56DE\u65E7\u7248\u3002\u672C\u5730\u8054\u8C03\u53EF\u663E\u5F0F\u8BBE\u7F6E BUDDY_CREATOR_SKILL_PATH \u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u6E05\u9664\u540E\u6062\u590D\u67E5\u8BE2 latest\u3002
|
|
3482
3473
|
\u7531\u5F53\u524D Coding Agent \u8BFB\u53D6 .buddy/creator/HANDOFF.md \u5E76\u6267\u884C\u5176\u4E2D\u6307\u5411\u7684 Skill\uFF1B\u9700\u8981 Python 3.9+\uFF0C\u4E0D\u542F\u52A8\u65E7\u91C7\u8BBF Web \u6216\u72EC\u7ACB\u6A21\u578B\u3002
|
|
3483
3474
|
\u6309\u5F53\u524D\u4F5C\u54C1\u5DE5\u4F5C\u6D41\u5B8C\u6210\u9700\u6C42\u3001\u5C0F\u6302\u4EF6\u6E05\u5355\u3001\u539F\u578B\u548C\u8BBE\u8BA1\u9A8C\u6536\uFF1B\u53EA\u6709\u4EA4\u4ED8\u6821\u9A8C\u8FD4\u56DE creator_complete\u3001completion.status=ready \u4E14\u4EA4\u4ED8\u6709\u6548\u540E\uFF0C\u624D\u7531 Coding Agent \u81EA\u52A8\u8854\u63A5\u5F00\u53D1\u3002\u8BFB\u53D6\u5B9E\u9645 manifest\uFF0C\u4E0D\u786C\u7F16\u7801\u624B\u518C\u6570\u91CF\u6216\u6587\u4EF6\u540D\uFF1B\u65B0\u7248\u4E09\u518C\u8FD8\u6309\u80FD\u529B\u5951\u7EA6\u5B8C\u6210\u5B9E\u65BD\u62A5\u544A\u548C handoff-check\uFF0C\u7ED3\u6784\u6821\u9A8C\u4E0D\u7B49\u4E8E\u771F\u5B9E Runtime \u9A8C\u8BC1\u3002\u65E7\u56DB\u518C\u7531\u6700\u65B0\u7248 Creator \u4FDD\u5B58\u5386\u53F2\u540E\u8FC1\u79FB\u4E3A\u4E09\u518C\uFF0C\u590D\u7528\u8D44\u6599\u548C\u8FDB\u5EA6\uFF0C\u8865\u9F50\u7F3A\u53E3\u5E76\u91CD\u65B0\u786E\u8BA4\u53D8\u5316\u5185\u5BB9\uFF1B\u4E0D\u76F4\u63A5\u6CBF\u7528\u65E7\u4EA4\u4ED8\u7684\u5B8C\u6210\u6807\u8BB0\u3002\u9700\u8981\u521D\u59CB\u5316\u65F6\u6267\u884C init --mode direct \u751F\u6210\u5B98\u65B9 Runtime \u5DE5\u7A0B\u3002\u751F\u6210\u65B0\u5DE5\u5382\u524D\u5217\u51FA\u6700\u65B0 dev Runtime \u652F\u6301\u7684\u6A21\u578B\uFF0C\u5148\u8BF7\u5F00\u53D1\u8005\u660E\u786E\u9009\u62E9\uFF0C\u518D\u4F20 --model\uFF1B\u5DF2\u6709\u660E\u786E\u9009\u62E9\u4E0D\u91CD\u590D\u8BE2\u95EE\uFF0C\u4E0D\u80FD\u7531 Coding Agent \u81EA\u884C\u9ED8\u8BA4\u3002\u5DF2\u6709\u4E1A\u52A1\u5DE5\u5382\u6CBF\u7528\u539F\u6A21\u578B\uFF0C\u4E0D\u4F20 --model\u3002\u540C\u76EE\u5F55\u6062\u590D\u65F6\u4ECE package.json \u8BFB\u53D6 buddyId\uFF0C\u5E76\u4F7F\u7528\u5E73\u53F0\u6700\u65B0 Meta\u3002
|
|
@@ -4470,7 +4461,7 @@ function startReloadingDev(options, startProcess) {
|
|
|
4470
4461
|
}
|
|
4471
4462
|
|
|
4472
4463
|
// packages/cli-core/src/dev/launch.ts
|
|
4473
|
-
import { lstatSync, readFileSync
|
|
4464
|
+
import { lstatSync, readFileSync } from "node:fs";
|
|
4474
4465
|
import { createRequire as createRequire3 } from "node:module";
|
|
4475
4466
|
import { dirname as dirname4, resolve as resolve11 } from "node:path";
|
|
4476
4467
|
|
|
@@ -4540,10 +4531,10 @@ async function officialAgentLaunchPlan(input) {
|
|
|
4540
4531
|
const packagePath = resolve11(input.projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
|
|
4541
4532
|
try {
|
|
4542
4533
|
await requireProjectRuntime(input.projectRoot, input.runtimeUpdate);
|
|
4543
|
-
const expected = runtimeDependencyVersion(JSON.parse(
|
|
4534
|
+
const expected = runtimeDependencyVersion(JSON.parse(readFileSync(packagePath, "utf8")));
|
|
4544
4535
|
if (!expected) throw new Error(`package.json \u7684 dependencies \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
|
|
4545
4536
|
const runtimePath = createRequire3(packagePath).resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`);
|
|
4546
|
-
const installed2 = JSON.parse(
|
|
4537
|
+
const installed2 = JSON.parse(readFileSync(runtimePath, "utf8")).version;
|
|
4547
4538
|
if (installed2 !== expected) throw new Error(`Runtime \u5DF2\u5B89\u88C5 ${installed2}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
|
|
4548
4539
|
await validateRuntimeDatasets(input.projectRoot, await readDataAccessRequirements(input.projectRoot));
|
|
4549
4540
|
} catch (cause) {
|
|
@@ -6060,7 +6051,10 @@ var HttpDeveloperPlatformClient = class {
|
|
|
6060
6051
|
const form = new FormData();
|
|
6061
6052
|
form.set("meta", JSON.stringify(request.meta));
|
|
6062
6053
|
form.set("avatar", new Blob([new Uint8Array(request.avatar.bytes)], { type: request.avatar.mediaType }), request.avatar.fileName);
|
|
6063
|
-
return buddy(await this.#request(`/cli/buddies/${encodeURIComponent(request.id)}/meta`, "PUT", {
|
|
6054
|
+
return buddy(await this.#request(`/cli/buddies/${encodeURIComponent(request.id)}/meta`, "PUT", {
|
|
6055
|
+
form,
|
|
6056
|
+
timeoutMs: this.#uploadTimeoutMs
|
|
6057
|
+
}), true);
|
|
6064
6058
|
}
|
|
6065
6059
|
return buddy(await this.#request(`/cli/buddies/${encodeURIComponent(request.id)}/meta`, "PUT", {
|
|
6066
6060
|
json: request.meta
|
|
@@ -6285,6 +6279,7 @@ var HELP = Object.freeze({
|
|
|
6285
6279
|
meta \u53EA\u67E5\u770B\u4E91\u7AEF\u8D44\u6599\uFF1Bmeta update \u81F3\u5C11\u63D0\u4F9B\u4E00\u4E2A\u4FEE\u6539\u5B57\u6BB5\uFF0C\u672A\u4F20\u5B57\u6BB5\u4FDD\u6301\u539F\u6837\u3002
|
|
6286
6280
|
\u6587\u5B57\u5B57\u6BB5\u4E0D\u80FD\u4E3A\u7A7A\uFF1B\u540D\u79F0\u6700\u591A ${BUDDY_PROFILE_TEXT_LIMITS.name} \u5B57\uFF0C\u4E00\u53E5\u8BDD\u4ECB\u7ECD\u6700\u591A ${BUDDY_PROFILE_TEXT_LIMITS.tagline} \u5B57\uFF0C\u5B8C\u6574\u4ECB\u7ECD\u6700\u591A ${BUDDY_PROFILE_TEXT_LIMITS.intro} \u5B57\u3002
|
|
6287
6281
|
--avatar \u4E0A\u4F20\u66FF\u6362\u5934\u50CF\uFF1A\u672C\u5730\u9759\u6001 PNG\u3001JPEG\u3001WebP\uFF0C\u6700\u5927 5 MiB\uFF1B\u4E0D\u63D0\u4F9B\u6E05\u9664\u5934\u50CF\u9009\u9879\u3002
|
|
6282
|
+
\u5934\u50CF\u4E0A\u4F20\u8BF7\u6C42\u6700\u591A\u7B49\u5F85 5 \u5206\u949F\uFF0CCLI \u4E0A\u4F20\u524D\u5C45\u4E2D\u88C1\u5207\u81F3 512\xD7512 \u65E0\u635F WebP\uFF0C\u4FDD\u7559\u989C\u8272\u3001\u900F\u660E\u5EA6\u4E0E\u539F\u59CB\u6587\u4EF6\uFF1B\u67E5\u8BE2\u548C\u4EC5\u6587\u5B57\u66F4\u65B0\u4ECD\u4E3A 30 \u79D2\u3002
|
|
6288
6283
|
\u9ED8\u8BA4\u8BFB\u53D6\u5F53\u524D\u5DE5\u7A0B\u7684 package.json.buddyId\uFF1B--buddy-id \u4E0E --directory \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u3002\u56FE\u7247\u8DEF\u5F84\u76F8\u5BF9\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002
|
|
6289
6284
|
\u9700\u8981\u5F53\u524D\u8D26\u53F7\u62E5\u6709\u8BE5\u642D\u5B50\uFF1B\u66F4\u65B0\u7ACB\u5373\u5F71\u54CD\u4E91\u7AEF\u5C55\u793A\u8D44\u6599\uFF0C\u65E0\u9700 Runtime\u3001push \u6216\u91CD\u65B0\u53D1\u5E03\u7A0B\u5E8F\u5305\u3002
|
|
6290
6285
|
\u793A\u4F8B: buddy-cli-sit meta update --name "\u5DDD\u5927\u53A8" --tagline "\u5E2E\u4F60\u5B89\u6392\u6BCF\u5929\u5403\u4EC0\u4E48" --avatar ./avatar.png`,
|
|
@@ -6292,6 +6287,7 @@ meta \u53EA\u67E5\u770B\u4E91\u7AEF\u8D44\u6599\uFF1Bmeta update \u81F3\u5C11\u6
|
|
|
6292
6287
|
\u65E7\u547D\u4EE4\u517C\u5BB9\u5165\u53E3\uFF1B\u66F4\u6362\u5934\u50CF\u63A8\u8350\u4F7F\u7528 buddy-cli-sit meta update --avatar <\u56FE\u7247\u6587\u4EF6>\u3002
|
|
6293
6288
|
\u4FEE\u6539\u5F53\u524D\u9879\u76EE\u6216\u6307\u5B9A\u642D\u5B50\u7684\u4E91\u7AEF\u5934\u50CF\uFF0C\u4FDD\u7559\u5176\u4ED6\u8D44\u6599\uFF1B\u4E0D\u9700\u8981\u5B89\u88C5 Runtime \u6216\u4E0A\u4F20\u4EE3\u7801\u5305\u3002
|
|
6294
6289
|
--file \u63A5\u53D7\u672C\u5730\u9759\u6001 PNG\u3001JPEG\u3001WebP \u56FE\u7247\uFF0C\u6700\u5927 5 MiB\uFF1BServer \u81EA\u52A8\u5904\u7406\u5E76\u751F\u6210\u5730\u5740\u3002
|
|
6290
|
+
\u5934\u50CF\u4E0A\u4F20\u8BF7\u6C42\u6700\u591A\u7B49\u5F85 5 \u5206\u949F\uFF0CCLI \u4E0A\u4F20\u524D\u5C45\u4E2D\u88C1\u5207\u81F3 512\xD7512 \u65E0\u635F WebP\uFF0C\u4FDD\u7559\u989C\u8272\u3001\u900F\u660E\u5EA6\u4E0E\u539F\u59CB\u6587\u4EF6\uFF1B\u6E05\u9664\u5934\u50CF\u4ECD\u4E3A 30 \u79D2\u3002
|
|
6295
6291
|
\u9700\u8981\u5F53\u524D\u8D26\u53F7\u62E5\u6709\u8BE5\u642D\u5B50\uFF0C\u547D\u4EE4\u6267\u884C\u540E\u7ACB\u5373\u66F4\u65B0\u4E91\u7AEF\u8D44\u6599\u3002`
|
|
6296
6292
|
});
|
|
6297
6293
|
function parse3(args, command) {
|
|
@@ -6420,7 +6416,7 @@ async function runMeta(parsed, io, options, legacyAvatar = false) {
|
|
|
6420
6416
|
}
|
|
6421
6417
|
let upload;
|
|
6422
6418
|
try {
|
|
6423
|
-
upload = file ? await readBuddyAvatarFile(resolve16(options.cwd ?? process.cwd(), file)) : void 0;
|
|
6419
|
+
upload = file ? await prepareBuddyAvatarUpload(await readBuddyAvatarFile(resolve16(options.cwd ?? process.cwd(), file))) : void 0;
|
|
6424
6420
|
} catch (error2) {
|
|
6425
6421
|
throw new CloudCommandUsageError(error2 instanceof Error ? error2.message : "\u65E0\u6CD5\u8BFB\u53D6\u5934\u50CF\u56FE\u7247");
|
|
6426
6422
|
}
|
|
@@ -6518,7 +6514,7 @@ var CLOUD_COMMAND_HELP = HELP;
|
|
|
6518
6514
|
|
|
6519
6515
|
// packages/cli-core/src/migration/index.ts
|
|
6520
6516
|
import { lstat as lstat12, open as open5, readdir as readdir6, realpath as realpath7, stat } from "node:fs/promises";
|
|
6521
|
-
import { extname, isAbsolute as isAbsolute3, join as join22, relative, resolve as resolve17, sep, win32 as win322 } from "node:path";
|
|
6517
|
+
import { extname as extname2, isAbsolute as isAbsolute3, join as join22, relative, resolve as resolve17, sep, win32 as win322 } from "node:path";
|
|
6522
6518
|
var DEFAULT_SKILL_SCAN_LIMITS = Object.freeze({
|
|
6523
6519
|
maxFiles: 128,
|
|
6524
6520
|
maxFileBytes: 256 * 1024,
|
|
@@ -6950,7 +6946,7 @@ function frontmatterEnd(lines) {
|
|
|
6950
6946
|
return -1;
|
|
6951
6947
|
}
|
|
6952
6948
|
function shellLines(lines, path) {
|
|
6953
|
-
const extension =
|
|
6949
|
+
const extension = extname2(path).toLowerCase();
|
|
6954
6950
|
const shebang = lines[0] ?? "";
|
|
6955
6951
|
if (SHELL_EXTENSIONS.has(extension) || /^#!.*(?:[/\s])(?:bash|fish|powershell|pwsh|sh|zsh)(?:\s|$)/u.test(shebang)) return lines.map(() => true);
|
|
6956
6952
|
const result = lines.map(() => false);
|
|
@@ -7078,7 +7074,7 @@ function analyzeText(source, path, context) {
|
|
|
7078
7074
|
const lines = source.split(/\r\n|\n|\r/u);
|
|
7079
7075
|
const metadataEnd = frontmatterEnd(lines);
|
|
7080
7076
|
const shellContext = shellLines(lines, path);
|
|
7081
|
-
const extension =
|
|
7077
|
+
const extension = extname2(path).toLowerCase();
|
|
7082
7078
|
const localShellVariables = /* @__PURE__ */ new Set();
|
|
7083
7079
|
const localBatchVariables = /* @__PURE__ */ new Set();
|
|
7084
7080
|
const localPowerShellEnvironment = /* @__PURE__ */ new Set();
|