@my-life-buddies/cli 0.8.0 → 0.10.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 +14 -15
- package/dist/bin/buddy.js +8 -0
- package/dist/bin/buddy.js.map +2 -2
- package/dist/bin/core.js +558 -678
- package/dist/bin/core.js.map +4 -4
- package/dist/bin/preview.js +0 -5
- package/dist/bin/preview.js.map +2 -2
- package/dist/web/app.css +0 -8
- package/dist/web/index.html +0 -7
- package/package.json +3 -3
- package/resources/agent-template/package-lock.json +4 -4
- package/resources/agent-template/package.json +1 -1
- package/dist/web/widget-delivery.js +0 -28
package/dist/bin/core.js
CHANGED
|
@@ -1,53 +1,106 @@
|
|
|
1
|
-
// packages/cli-core/src/config/models.ts
|
|
2
|
-
var MODEL_IDS = Object.freeze([
|
|
3
|
-
"kimi-k2.6",
|
|
4
|
-
"kimi-k3",
|
|
5
|
-
"deepseek-v4-flash",
|
|
6
|
-
"deepseek-v4-pro"
|
|
7
|
-
]);
|
|
8
|
-
var DEFAULT_MODEL_ID = MODEL_IDS[0];
|
|
9
|
-
|
|
10
1
|
// packages/cli-core/src/commands/models.ts
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
return { exitCode: 0 };
|
|
2
|
+
import { resolve as resolve5 } from "node:path";
|
|
3
|
+
|
|
4
|
+
// packages/cli-core/src/config/runtime-catalog.ts
|
|
5
|
+
import { readFile, realpath } from "node:fs/promises";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { resolve } from "node:path";
|
|
8
|
+
import { pathToFileURL } from "node:url";
|
|
9
|
+
|
|
10
|
+
// packages/cli-core/src/config/runtime-dependency.ts
|
|
11
|
+
var BUDDY_RUNTIME_PACKAGE = "@my-life-buddies/buddy-runtime";
|
|
12
|
+
function runtimeDependencyVersion(pkg) {
|
|
13
|
+
if (typeof pkg !== "object" || pkg === null || !("dependencies" in pkg)) return void 0;
|
|
14
|
+
const dependencies2 = pkg.dependencies;
|
|
15
|
+
if (typeof dependencies2 !== "object" || dependencies2 === null || !(BUDDY_RUNTIME_PACKAGE in dependencies2)) return void 0;
|
|
16
|
+
const version = dependencies2[BUDDY_RUNTIME_PACKAGE];
|
|
17
|
+
return typeof version === "string" && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(version) ? version : void 0;
|
|
29
18
|
}
|
|
30
19
|
|
|
31
|
-
// packages/cli-core/src/
|
|
32
|
-
|
|
20
|
+
// packages/cli-core/src/config/runtime-catalog.ts
|
|
21
|
+
async function loadRuntime(projectRoot) {
|
|
22
|
+
const packagePath = resolve(projectRoot, "package.json");
|
|
23
|
+
const expected = runtimeDependencyVersion(JSON.parse(await readFile(packagePath, "utf8")));
|
|
24
|
+
if (!expected) throw new Error(`package.json \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
|
|
25
|
+
const projectRequire = createRequire(packagePath);
|
|
26
|
+
let runtimePath;
|
|
27
|
+
try {
|
|
28
|
+
const installedPath = await realpath(resolve(projectRoot, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"));
|
|
29
|
+
if (await realpath(projectRequire.resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`)) !== installedPath) {
|
|
30
|
+
throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
|
|
31
|
+
}
|
|
32
|
+
const installed = JSON.parse(await readFile(installedPath, "utf8"));
|
|
33
|
+
if (installed.version !== expected) throw new Error(`\u5DF2\u5B89\u88C5 ${installed.version}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
|
|
34
|
+
runtimePath = projectRequire.resolve(BUDDY_RUNTIME_PACKAGE);
|
|
35
|
+
} catch (cause) {
|
|
36
|
+
throw new Error(`\u5DE5\u7A0B\u7684 Runtime \u4F9D\u8D56\u672A\u6B63\u786E\u5B89\u88C5\uFF0C\u8BF7\u6309\u9501\u6587\u4EF6\u5B89\u88C5\u4F9D\u8D56\uFF1A${cause instanceof Error ? cause.message : String(cause)}`);
|
|
37
|
+
}
|
|
38
|
+
const runtime = await import(pathToFileURL(runtimePath).href);
|
|
39
|
+
return { runtime, runtimeVersion: expected, runtimePath };
|
|
40
|
+
}
|
|
41
|
+
async function readRuntimeDataCatalog(projectRoot) {
|
|
42
|
+
const { runtime, runtimeVersion: expected } = await loadRuntime(projectRoot);
|
|
43
|
+
const catalog = runtime.DATA_ACCESS_CAPABILITIES;
|
|
44
|
+
if (!Array.isArray(catalog)) {
|
|
45
|
+
throw new Error(`\u5DE5\u7A0B\u7684 Runtime ${expected} \u672A\u5BFC\u51FA DATA_ACCESS_CAPABILITIES\uFF0C\u8BF7\u4F7F\u7528\u5305\u542B\u6570\u636E\u76EE\u5F55\u7684\u65B0 Runtime \u5305\u3002`);
|
|
46
|
+
}
|
|
47
|
+
const seen = /* @__PURE__ */ new Set();
|
|
48
|
+
const datasets = catalog.map((value) => {
|
|
49
|
+
if (!value || typeof value !== "object") throw new Error("Runtime \u6570\u636E\u76EE\u5F55\u683C\u5F0F\u65E0\u6548");
|
|
50
|
+
const item = value;
|
|
51
|
+
if (typeof item.id !== "string" || !item.id.trim() || seen.has(item.id) || typeof item.title !== "string" || !item.title.trim() || typeof item.source !== "string" || !item.source.trim() || !Number.isSafeInteger(item.schemaVersion) || item.schemaVersion < 1) {
|
|
52
|
+
throw new Error("Runtime \u6570\u636E\u76EE\u5F55\u683C\u5F0F\u65E0\u6548\u6216\u5305\u542B\u91CD\u590D ID");
|
|
53
|
+
}
|
|
54
|
+
seen.add(item.id);
|
|
55
|
+
return Object.freeze({ id: item.id, title: item.title, source: item.source, schemaVersion: item.schemaVersion });
|
|
56
|
+
});
|
|
57
|
+
return Object.freeze({ runtimeVersion: expected, datasets: Object.freeze(datasets) });
|
|
58
|
+
}
|
|
59
|
+
async function readRuntimeModelCatalog(projectRoot) {
|
|
60
|
+
const { runtime, runtimeVersion, runtimePath } = await loadRuntime(projectRoot);
|
|
61
|
+
let models = runtime.MODEL_IDS;
|
|
62
|
+
if (models === void 0) {
|
|
63
|
+
try {
|
|
64
|
+
models = (await import(new URL("./model.js", pathToFileURL(runtimePath)).href)).MODEL_IDS;
|
|
65
|
+
} catch (cause) {
|
|
66
|
+
throw new Error(`Runtime ${runtimeVersion} \u7684\u6A21\u578B\u76EE\u5F55\u4E0D\u53EF\u8BFB\u53D6\uFF1A${cause instanceof Error ? cause.message : String(cause)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!Array.isArray(models) || models.length === 0 || models.some((id) => typeof id !== "string" || !id.trim()) || new Set(models).size !== models.length) {
|
|
70
|
+
throw new Error(`Runtime ${runtimeVersion} \u7684 MODEL_IDS \u7F3A\u5931\u6216\u683C\u5F0F\u65E0\u6548`);
|
|
71
|
+
}
|
|
72
|
+
return Object.freeze({ runtimeVersion, models: Object.freeze([...models]) });
|
|
73
|
+
}
|
|
74
|
+
async function validateRuntimeModel(projectRoot, model) {
|
|
75
|
+
if (model === void 0) return;
|
|
76
|
+
const catalog = await readRuntimeModelCatalog(projectRoot);
|
|
77
|
+
if (!catalog.models.includes(model)) throw new Error(`/model\uFF1A\u5DE5\u7A0B Runtime ${catalog.runtimeVersion} \u4E0D\u652F\u6301 ${model}\uFF1B\u53EF\u9009 ${catalog.models.join("\u3001")}`);
|
|
78
|
+
}
|
|
79
|
+
async function validateRuntimeDatasets(projectRoot, requirements = []) {
|
|
80
|
+
const catalog = await readRuntimeDataCatalog(projectRoot);
|
|
81
|
+
const ids = new Set(catalog.datasets.map((item) => item.id));
|
|
82
|
+
for (const [index, item] of requirements.entries()) {
|
|
83
|
+
if (!ids.has(item.id)) throw new Error(`/datasets/${index}/id\uFF1A\u5DE5\u7A0B Runtime ${catalog.runtimeVersion} \u4E0D\u652F\u6301 ${item.id}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
33
86
|
|
|
34
87
|
// packages/cli-core/src/project-context.ts
|
|
35
|
-
import { lstat as
|
|
36
|
-
import { dirname, join as
|
|
88
|
+
import { lstat as lstat5, realpath as realpath2 } from "node:fs/promises";
|
|
89
|
+
import { dirname, join as join5, resolve as resolve4 } from "node:path";
|
|
37
90
|
|
|
38
91
|
// packages/cli-core/src/config/index.ts
|
|
39
92
|
import {
|
|
40
93
|
link,
|
|
41
|
-
lstat as
|
|
42
|
-
mkdir as
|
|
94
|
+
lstat as lstat4,
|
|
95
|
+
mkdir as mkdir3,
|
|
43
96
|
open as open2,
|
|
44
|
-
readFile as
|
|
97
|
+
readFile as readFile5,
|
|
45
98
|
readdir,
|
|
46
|
-
rename,
|
|
99
|
+
rename as rename2,
|
|
47
100
|
unlink as unlink2
|
|
48
101
|
} from "node:fs/promises";
|
|
49
102
|
import { randomUUID } from "node:crypto";
|
|
50
|
-
import { isAbsolute, join as
|
|
103
|
+
import { isAbsolute, join as join4, resolve as resolve3, win32 } from "node:path";
|
|
51
104
|
import { isDeepStrictEqual } from "node:util";
|
|
52
105
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
53
106
|
|
|
@@ -78,7 +131,7 @@ var buddy_agent_schema_default = {
|
|
|
78
131
|
minLength: 1,
|
|
79
132
|
maxLength: 128,
|
|
80
133
|
pattern: "^[^\\s\\u0000-\\u001f\\u007f]+$",
|
|
81
|
-
description: "\u4ECE buddy-cli models \
|
|
134
|
+
description: "\u4ECE buddy-cli models \u67E5\u770B Runtime \u6A21\u578B\u76EE\u5F55\uFF1B\u5DE5\u7A0B\u5185\u8BFB\u53D6\u5B89\u88C5\u7248\u672C\uFF0C\u5DE5\u7A0B\u5916\u8BFB\u53D6 npm \u6700\u65B0\u7248\u3002\u8FD0\u884C\u4E0E\u4E0A\u4F20\u9884\u68C0\u6309\u5DE5\u7A0B Runtime \u6821\u9A8C\u3002"
|
|
82
135
|
},
|
|
83
136
|
datasets: {
|
|
84
137
|
type: "array",
|
|
@@ -110,12 +163,177 @@ var buddy_agent_schema_default = {
|
|
|
110
163
|
};
|
|
111
164
|
|
|
112
165
|
// packages/cli-core/src/project-files.ts
|
|
113
|
-
import { lstat as
|
|
166
|
+
import { lstat as lstat3 } from "node:fs/promises";
|
|
167
|
+
import { join as join3 } from "node:path";
|
|
168
|
+
|
|
169
|
+
// packages/cli-core/src/init/scaffold.ts
|
|
170
|
+
import { lstat as lstat2, mkdir as mkdir2, open, readFile as readFile4, rmdir, unlink } from "node:fs/promises";
|
|
171
|
+
import { resolve as resolve2 } from "node:path";
|
|
172
|
+
|
|
173
|
+
// packages/cli-core/src/config/models.ts
|
|
174
|
+
var MODEL_IDS = Object.freeze([
|
|
175
|
+
"kimi-k2.6",
|
|
176
|
+
"kimi-k3",
|
|
177
|
+
"deepseek-v4-flash",
|
|
178
|
+
"deepseek-v4-pro"
|
|
179
|
+
]);
|
|
180
|
+
var DEFAULT_MODEL_ID = "kimi-k2.6";
|
|
181
|
+
|
|
182
|
+
// packages/cli-core/src/init/runtime-template.ts
|
|
183
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
184
|
+
import { mkdtemp as mkdtemp2, readFile as readFile3, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
|
|
185
|
+
import { tmpdir } from "node:os";
|
|
186
|
+
import { join as join2 } from "node:path";
|
|
187
|
+
import { promisify as promisify2 } from "node:util";
|
|
188
|
+
|
|
189
|
+
// packages/cli-core/src/config/runtime-package.ts
|
|
190
|
+
import { execFile } from "node:child_process";
|
|
191
|
+
import { lstat, mkdir, mkdtemp, readFile as readFile2, rename, rm, writeFile } from "node:fs/promises";
|
|
192
|
+
import { homedir } from "node:os";
|
|
114
193
|
import { join } from "node:path";
|
|
194
|
+
import { promisify } from "node:util";
|
|
195
|
+
var RUNTIME_REGISTRY = "https://registry.npmjs.org/";
|
|
196
|
+
var execute = promisify(execFile);
|
|
197
|
+
async function latestRuntimeVersion(options = {}) {
|
|
198
|
+
options.signal?.throwIfAborted();
|
|
199
|
+
const timeout = AbortSignal.timeout(1e4);
|
|
200
|
+
const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
|
|
201
|
+
const response = await (options.fetch ?? globalThis.fetch)(`${RUNTIME_REGISTRY}${encodeURIComponent(BUDDY_RUNTIME_PACKAGE)}/latest`, {
|
|
202
|
+
signal,
|
|
203
|
+
headers: { Accept: "application/json" },
|
|
204
|
+
redirect: "error"
|
|
205
|
+
});
|
|
206
|
+
if (!response.ok) throw new Error(`npm \u8FD4\u56DE HTTP ${response.status}`);
|
|
207
|
+
const metadata = await response.json();
|
|
208
|
+
if (metadata?.name !== BUDDY_RUNTIME_PACKAGE || typeof metadata.version !== "string" || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(metadata.version)) {
|
|
209
|
+
throw new Error("npm latest \u672A\u8FD4\u56DE\u6B64 Runtime \u7684\u51C6\u786E\u7A33\u5B9A\u7248\u672C");
|
|
210
|
+
}
|
|
211
|
+
return metadata.version;
|
|
212
|
+
}
|
|
213
|
+
async function cachedLatestRuntimeRoot(options = {}) {
|
|
214
|
+
options.report?.("\u6B63\u5728\u67E5\u8BE2\u516C\u5171 npm \u7684\u6700\u65B0 Runtime\u2026");
|
|
215
|
+
const version = await latestRuntimeVersion(options);
|
|
216
|
+
const cache = options.cacheDirectory ?? join(homedir(), ".cache", "buddy-cli", "runtimes");
|
|
217
|
+
const destination = join(cache, version);
|
|
218
|
+
let cacheExists = false;
|
|
219
|
+
try {
|
|
220
|
+
await lstat(destination);
|
|
221
|
+
cacheExists = true;
|
|
222
|
+
} catch (cause) {
|
|
223
|
+
if (cause.code !== "ENOENT") throw cause;
|
|
224
|
+
}
|
|
225
|
+
if (cacheExists) {
|
|
226
|
+
try {
|
|
227
|
+
const pkg = JSON.parse(await readFile2(join(destination, "package.json"), "utf8"));
|
|
228
|
+
const installed = JSON.parse(await readFile2(join(destination, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"), "utf8"));
|
|
229
|
+
if (runtimeDependencyVersion(pkg) === version && installed.version === version) return destination;
|
|
230
|
+
throw new Error("\u7F13\u5B58\u7248\u672C\u4E0D\u5339\u914D");
|
|
231
|
+
} catch (cause) {
|
|
232
|
+
throw new Error(`Runtime ${version} \u7684\u7F13\u5B58\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u5220\u9664 ${destination} \u540E\u91CD\u8BD5`, { cause });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
await mkdir(cache, { recursive: true });
|
|
236
|
+
const temporaryRoot = await mkdtemp(join(cache, `.install-${version}-`));
|
|
237
|
+
try {
|
|
238
|
+
await writeFile(join(temporaryRoot, "package.json"), JSON.stringify({
|
|
239
|
+
name: "buddy-runtime-catalog",
|
|
240
|
+
private: true,
|
|
241
|
+
type: "module",
|
|
242
|
+
dependencies: { [BUDDY_RUNTIME_PACKAGE]: version }
|
|
243
|
+
}));
|
|
244
|
+
const userConfig = join(temporaryRoot, ".npmrc");
|
|
245
|
+
await writeFile(userConfig, `registry=${RUNTIME_REGISTRY}
|
|
246
|
+
`);
|
|
247
|
+
options.report?.(`\u6B63\u5728\u7F13\u5B58 Runtime ${version} \u7684\u80FD\u529B\u76EE\u5F55\uFF0C\u9996\u6B21\u4F7F\u7528\u9700\u8981\u4E0B\u8F7D\u4F9D\u8D56\u2026`);
|
|
248
|
+
const runNpm = options.runNpm ?? ((args, settings) => execute("npm", args, { ...settings, encoding: "utf8", maxBuffer: 4 * 1024 * 1024 }));
|
|
249
|
+
await runNpm([
|
|
250
|
+
"install",
|
|
251
|
+
"--ignore-scripts",
|
|
252
|
+
"--no-audit",
|
|
253
|
+
"--no-fund",
|
|
254
|
+
"--engine-strict",
|
|
255
|
+
`--registry=${RUNTIME_REGISTRY}`,
|
|
256
|
+
`--@my-life-buddies:registry=${RUNTIME_REGISTRY}`,
|
|
257
|
+
`--userconfig=${userConfig}`,
|
|
258
|
+
"--prefer-online",
|
|
259
|
+
"--fetch-retries=0",
|
|
260
|
+
"--fetch-timeout=20000"
|
|
261
|
+
], { cwd: temporaryRoot, signal: options.signal, timeout: 18e4 });
|
|
262
|
+
const installed = JSON.parse(await readFile2(join(temporaryRoot, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"), "utf8"));
|
|
263
|
+
if (installed.version !== version) throw new Error(`\u7F13\u5B58\u7684 Runtime \u7248\u672C\u4E0E npm latest ${version} \u4E0D\u4E00\u81F4`);
|
|
264
|
+
options.signal?.throwIfAborted();
|
|
265
|
+
try {
|
|
266
|
+
await rename(temporaryRoot, destination);
|
|
267
|
+
} catch (cause) {
|
|
268
|
+
if (!["EEXIST", "ENOTEMPTY"].includes(cause.code ?? "")) throw cause;
|
|
269
|
+
}
|
|
270
|
+
return destination;
|
|
271
|
+
} finally {
|
|
272
|
+
await rm(temporaryRoot, { recursive: true, force: true });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// packages/cli-core/src/init/runtime-template.ts
|
|
277
|
+
var execute2 = promisify2(execFile2);
|
|
278
|
+
async function latestRuntimeTemplate(template, options) {
|
|
279
|
+
const bundledVersion = runtimeDependencyVersion(JSON.parse(template.packageJson));
|
|
280
|
+
if (!bundledVersion) throw new Error("CLI \u5DE5\u7A0B\u6A21\u677F\u7F3A\u5C11 Runtime \u7684\u51C6\u786E\u7248\u672C");
|
|
281
|
+
let temporaryRoot;
|
|
282
|
+
try {
|
|
283
|
+
options.signal?.throwIfAborted();
|
|
284
|
+
options.report("\u6B63\u5728\u67E5\u8BE2\u516C\u5171 npm \u7684\u6700\u65B0 Runtime\u2026");
|
|
285
|
+
const version = await latestRuntimeVersion(options);
|
|
286
|
+
let result = template;
|
|
287
|
+
if (version !== bundledVersion) {
|
|
288
|
+
temporaryRoot = await mkdtemp2(join2(tmpdir(), "buddy-runtime-template-"));
|
|
289
|
+
await writeFile2(join2(temporaryRoot, "package.json"), template.packageJson);
|
|
290
|
+
await writeFile2(join2(temporaryRoot, "package-lock.json"), template.packageLock);
|
|
291
|
+
const userConfig = join2(temporaryRoot, ".npmrc");
|
|
292
|
+
await writeFile2(userConfig, `registry=${RUNTIME_REGISTRY}
|
|
293
|
+
`);
|
|
294
|
+
options.report(`\u6B63\u5728\u4E3A Runtime ${version} \u751F\u6210\u4F9D\u8D56\u9501\u6587\u4EF6\u2026`);
|
|
295
|
+
const runNpm = options.runNpm ?? ((args, settings) => execute2("npm", args, { ...settings, encoding: "utf8", maxBuffer: 4 * 1024 * 1024 }));
|
|
296
|
+
await runNpm([
|
|
297
|
+
"install",
|
|
298
|
+
"--package-lock-only",
|
|
299
|
+
"--save-exact",
|
|
300
|
+
`${BUDDY_RUNTIME_PACKAGE}@${version}`,
|
|
301
|
+
"--ignore-scripts",
|
|
302
|
+
"--no-audit",
|
|
303
|
+
"--no-fund",
|
|
304
|
+
"--engine-strict",
|
|
305
|
+
`--registry=${RUNTIME_REGISTRY}`,
|
|
306
|
+
`--@my-life-buddies:registry=${RUNTIME_REGISTRY}`,
|
|
307
|
+
`--userconfig=${userConfig}`,
|
|
308
|
+
"--prefer-online",
|
|
309
|
+
"--fetch-retries=0",
|
|
310
|
+
"--fetch-timeout=20000"
|
|
311
|
+
], { cwd: temporaryRoot, signal: options.signal, timeout: 6e4 });
|
|
312
|
+
result = {
|
|
313
|
+
packageJson: await readFile3(join2(temporaryRoot, "package.json"), "utf8"),
|
|
314
|
+
packageLock: await readFile3(join2(temporaryRoot, "package-lock.json"), "utf8")
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
const pkg = JSON.parse(result.packageJson);
|
|
318
|
+
const lock = JSON.parse(result.packageLock);
|
|
319
|
+
const locked = lock.packages?.[`node_modules/${BUDDY_RUNTIME_PACKAGE}`];
|
|
320
|
+
if (runtimeDependencyVersion(pkg) !== version || runtimeDependencyVersion(lock.packages?.[""]) !== version || locked?.version !== version || typeof locked.integrity !== "string" || !locked.integrity || typeof locked.resolved !== "string" || !locked.resolved.startsWith(RUNTIME_REGISTRY)) {
|
|
321
|
+
throw new Error("\u751F\u6210\u7684 Runtime \u7248\u672C\u4E0E\u4F9D\u8D56\u9501\u6587\u4EF6\u4E0D\u4E00\u81F4");
|
|
322
|
+
}
|
|
323
|
+
options.signal?.throwIfAborted();
|
|
324
|
+
options.report(`\u5DF2\u4ECE\u516C\u5171 npm latest \u9501\u5B9A Runtime ${version}\uFF08package.json \u4E0E package-lock.json\uFF09\u3002`);
|
|
325
|
+
return result;
|
|
326
|
+
} catch (cause) {
|
|
327
|
+
if (options.signal?.aborted) throw new Error("Runtime \u7248\u672C\u9009\u62E9\u5DF2\u53D6\u6D88");
|
|
328
|
+
const reason = cause instanceof Error && !cause.message.includes("Command failed") ? cause.message : "npm \u672A\u5B8C\u6210\u9501\u6587\u4EF6\u751F\u6210";
|
|
329
|
+
options.report(`\u672A\u80FD\u9501\u5B9A\u6700\u65B0 Runtime\uFF1A${reason}\u3002\u672C\u6B21\u4F7F\u7528 CLI \u968F\u9644\u7684 Runtime ${bundledVersion} \u53CA\u5176\u9501\u6587\u4EF6\uFF1B\u5B89\u88C5\u540E\u53EF\u663E\u5F0F\u5347\u7EA7\u5DE5\u7A0B\u4F9D\u8D56\u3002`);
|
|
330
|
+
return template;
|
|
331
|
+
} finally {
|
|
332
|
+
if (temporaryRoot) await rm2(temporaryRoot, { recursive: true, force: true });
|
|
333
|
+
}
|
|
334
|
+
}
|
|
115
335
|
|
|
116
336
|
// packages/cli-core/src/init/scaffold.ts
|
|
117
|
-
import { lstat, mkdir, open, readFile, rmdir, unlink } from "node:fs/promises";
|
|
118
|
-
import { resolve } from "node:path";
|
|
119
337
|
var BUDDY_PLATFORM_AGENT_ENTRY = "agent.md";
|
|
120
338
|
var BUDDY_PLATFORM_FACTORY_ENTRY = "src/buddy-options.mjs";
|
|
121
339
|
var BUDDY_PLATFORM_PACKAGE_JSON = "package.json";
|
|
@@ -206,11 +424,11 @@ try {
|
|
|
206
424
|
}
|
|
207
425
|
`;
|
|
208
426
|
}
|
|
209
|
-
async function scaffoldPlatformAgent(projectRoot, name) {
|
|
210
|
-
const path =
|
|
427
|
+
async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
428
|
+
const path = resolve2(projectRoot, BUDDY_PLATFORM_AGENT_ENTRY);
|
|
211
429
|
const hasAlternateLockfile = (await Promise.all(["pnpm-lock.yaml", "yarn.lock"].map(async (name2) => {
|
|
212
430
|
try {
|
|
213
|
-
if (!(await
|
|
431
|
+
if (!(await lstat2(resolve2(projectRoot, name2))).isFile()) {
|
|
214
432
|
throw new TypeError(`\u4F9D\u8D56\u9501\u6587\u4EF6\u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6\uFF1A${name2}`);
|
|
215
433
|
}
|
|
216
434
|
return true;
|
|
@@ -221,39 +439,55 @@ async function scaffoldPlatformAgent(projectRoot, name) {
|
|
|
221
439
|
}))).some(Boolean);
|
|
222
440
|
const files = [
|
|
223
441
|
{ path, content: platformAgentTemplate(name) },
|
|
224
|
-
{ path:
|
|
225
|
-
{ path:
|
|
226
|
-
...hasAlternateLockfile ? [] : [{ path:
|
|
227
|
-
{ path:
|
|
442
|
+
{ path: resolve2(projectRoot, BUDDY_PLATFORM_FACTORY_ENTRY), content: platformFactoryTemplate() },
|
|
443
|
+
{ path: resolve2(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await readFile4(new URL("../../resources/agent-template/package.json", import.meta.url), "utf8") },
|
|
444
|
+
...hasAlternateLockfile ? [] : [{ path: resolve2(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK), content: await readFile4(new URL("../../resources/agent-template/package-lock.json", import.meta.url), "utf8") }],
|
|
445
|
+
{ path: resolve2(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() }
|
|
228
446
|
];
|
|
229
447
|
const handles = [];
|
|
230
448
|
const createdDirectories = [];
|
|
231
449
|
try {
|
|
232
450
|
for (const directory of PLATFORM_DIRECTORIES) {
|
|
233
|
-
const directoryPath =
|
|
451
|
+
const directoryPath = resolve2(projectRoot, directory);
|
|
234
452
|
try {
|
|
235
|
-
await
|
|
453
|
+
await mkdir2(directoryPath, { mode: 448 });
|
|
236
454
|
createdDirectories.push(directoryPath);
|
|
237
455
|
} catch (cause) {
|
|
238
456
|
if (cause.code !== "EEXIST") throw cause;
|
|
239
457
|
}
|
|
240
|
-
if (!(await
|
|
458
|
+
if (!(await lstat2(directoryPath)).isDirectory()) {
|
|
241
459
|
throw new TypeError(`\u5B98\u65B9\u5DE5\u7A0B\u76EE\u5F55\u5FC5\u987B\u662F\u666E\u901A\u76EE\u5F55\uFF0C\u4E0D\u80FD\u4F7F\u7528\u6587\u4EF6\u6216\u7B26\u53F7\u94FE\u63A5\uFF1A${directoryPath}`);
|
|
242
460
|
}
|
|
243
461
|
}
|
|
244
|
-
for (const
|
|
462
|
+
for (const file of files) {
|
|
245
463
|
try {
|
|
246
|
-
handles.push({ path:
|
|
464
|
+
handles.push({ path: file.path, handle: await open(file.path, "wx", 384) });
|
|
247
465
|
} catch (cause) {
|
|
248
466
|
if (cause.code !== "EEXIST") throw cause;
|
|
249
|
-
if (!(await
|
|
250
|
-
throw new TypeError(`\u5B98\u65B9\u5DE5\u7A0B\u6587\u4EF6\u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6\uFF0C\u4E0D\u80FD\u4F7F\u7528\u76EE\u5F55\u6216\u7B26\u53F7\u94FE\u63A5\uFF1A${
|
|
467
|
+
if (!(await lstat2(file.path)).isFile()) {
|
|
468
|
+
throw new TypeError(`\u5B98\u65B9\u5DE5\u7A0B\u6587\u4EF6\u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6\uFF0C\u4E0D\u80FD\u4F7F\u7528\u76EE\u5F55\u6216\u7B26\u53F7\u94FE\u63A5\uFF1A${file.path}`);
|
|
251
469
|
}
|
|
252
470
|
}
|
|
253
471
|
}
|
|
472
|
+
const packageFile = files.find((file) => file.path === resolve2(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON));
|
|
473
|
+
const lockFile = files.find((file) => file.path === resolve2(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK));
|
|
474
|
+
if (options.resolveDependencies && lockFile && handles.some((file) => file.path === packageFile.path) && handles.some((file) => file.path === lockFile.path)) {
|
|
475
|
+
const template = await options.resolveDependencies({ packageJson: packageFile.content, packageLock: lockFile.content });
|
|
476
|
+
packageFile.content = template.packageJson;
|
|
477
|
+
lockFile.content = template.packageLock;
|
|
478
|
+
}
|
|
479
|
+
if (lockFile && (handles.some((file) => file.path === packageFile.path) || handles.some((file) => file.path === lockFile.path))) {
|
|
480
|
+
const packageContents = handles.some((file) => file.path === packageFile.path) ? packageFile.content : await readFile4(packageFile.path, "utf8");
|
|
481
|
+
const lockContents = handles.some((file) => file.path === lockFile.path) ? lockFile.content : await readFile4(lockFile.path, "utf8");
|
|
482
|
+
const declared = JSON.parse(packageContents).dependencies ?? {};
|
|
483
|
+
const locked = JSON.parse(lockContents).packages?.[""]?.dependencies ?? {};
|
|
484
|
+
if (JSON.stringify(Object.entries(declared).sort()) !== JSON.stringify(Object.entries(locked).sort())) {
|
|
485
|
+
throw new Error("\u5DF2\u6709 package.json \u4E0E\u5F85\u8865\u9F50\u7684\u9501\u6587\u4EF6\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u7528\u5DE5\u7A0B\u7684\u5305\u7BA1\u7406\u5668\u6062\u590D\u5339\u914D\u7684\u4F9D\u8D56\u6587\u4EF6\u540E\u91CD\u8BD5");
|
|
486
|
+
}
|
|
487
|
+
}
|
|
254
488
|
for (const { path: filePath, handle } of handles) {
|
|
255
|
-
const
|
|
256
|
-
await handle.writeFile(
|
|
489
|
+
const file = files.find((candidate) => candidate.path === filePath);
|
|
490
|
+
await handle.writeFile(file.content, "utf8");
|
|
257
491
|
await handle.sync();
|
|
258
492
|
}
|
|
259
493
|
return Object.freeze({ path, created: handles.length > 0 || createdDirectories.length > 0 });
|
|
@@ -280,7 +514,7 @@ async function missingBuddyAgentFiles(projectRoot) {
|
|
|
280
514
|
];
|
|
281
515
|
const missing = await Promise.all(entries.map(async ([path, kind]) => {
|
|
282
516
|
try {
|
|
283
|
-
const entry = await
|
|
517
|
+
const entry = await lstat3(join3(projectRoot, path));
|
|
284
518
|
return (kind === "directory" ? entry.isDirectory() : entry.isFile()) ? void 0 : path;
|
|
285
519
|
} catch (cause) {
|
|
286
520
|
if (["ENOENT", "ENOTDIR"].includes(cause.code ?? "")) return path;
|
|
@@ -349,9 +583,6 @@ function validateBuddyProjectManifest(value) {
|
|
|
349
583
|
return { ok: false, issues: schemaIssues(validateAgentSchema.errors) };
|
|
350
584
|
}
|
|
351
585
|
const manifest = value;
|
|
352
|
-
if (manifest.model !== void 0 && !MODEL_IDS.includes(manifest.model)) {
|
|
353
|
-
return { ok: false, issues: [{ path: "/model", message: `\u4E0D\u652F\u6301\u7684\u6A21\u578B ID\uFF1B\u53EF\u9009 ${MODEL_IDS.join("\u3001")}\uFF08buddy-cli models\uFF09` }] };
|
|
354
|
-
}
|
|
355
586
|
const seen = /* @__PURE__ */ new Set();
|
|
356
587
|
for (const [index, dataset] of (manifest.datasets ?? []).entries()) {
|
|
357
588
|
if (seen.has(dataset.id)) {
|
|
@@ -410,7 +641,7 @@ var ProjectInitializationError = class extends Error {
|
|
|
410
641
|
};
|
|
411
642
|
async function pathState(targetPath) {
|
|
412
643
|
try {
|
|
413
|
-
const entry = await
|
|
644
|
+
const entry = await lstat4(targetPath);
|
|
414
645
|
if (!entry.isDirectory() || entry.isSymbolicLink()) return { kind: "other" };
|
|
415
646
|
return { kind: "directory", identity: `${entry.dev}:${entry.ino}` };
|
|
416
647
|
} catch (cause) {
|
|
@@ -430,7 +661,7 @@ function entryIdentity(entry) {
|
|
|
430
661
|
}
|
|
431
662
|
async function fileIdentity(targetPath) {
|
|
432
663
|
try {
|
|
433
|
-
const entry = await
|
|
664
|
+
const entry = await lstat4(targetPath);
|
|
434
665
|
return entry.isFile() && !entry.isSymbolicLink() ? entryIdentity(entry) : void 0;
|
|
435
666
|
} catch (cause) {
|
|
436
667
|
if (cause.code === "ENOENT") return void 0;
|
|
@@ -439,7 +670,7 @@ async function fileIdentity(targetPath) {
|
|
|
439
670
|
}
|
|
440
671
|
async function unlinkMatchingFile(targetPath, expectedIdentity) {
|
|
441
672
|
try {
|
|
442
|
-
const entry = await
|
|
673
|
+
const entry = await lstat4(targetPath);
|
|
443
674
|
if (!entry.isFile() || entry.isSymbolicLink() || entryIdentity(entry) !== expectedIdentity) {
|
|
444
675
|
return false;
|
|
445
676
|
}
|
|
@@ -477,7 +708,7 @@ async function readExistingManifest(agentConfigPath) {
|
|
|
477
708
|
agentConfigPath
|
|
478
709
|
);
|
|
479
710
|
}
|
|
480
|
-
const entry = await
|
|
711
|
+
const entry = await lstat4(agentConfigPath);
|
|
481
712
|
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
482
713
|
throw new ProjectInitializationError(
|
|
483
714
|
"TARGET_CHANGED",
|
|
@@ -486,7 +717,7 @@ async function readExistingManifest(agentConfigPath) {
|
|
|
486
717
|
);
|
|
487
718
|
}
|
|
488
719
|
try {
|
|
489
|
-
return parseBuddyProjectManifest(await
|
|
720
|
+
return parseBuddyProjectManifest(await readFile5(agentConfigPath, "utf8"));
|
|
490
721
|
} catch (cause) {
|
|
491
722
|
throw new ProjectInitializationError(
|
|
492
723
|
"TARGET_CHANGED",
|
|
@@ -497,8 +728,8 @@ async function readExistingManifest(agentConfigPath) {
|
|
|
497
728
|
}
|
|
498
729
|
}
|
|
499
730
|
async function planBuddyDraftInitialization(directory) {
|
|
500
|
-
const rootDirectory =
|
|
501
|
-
const agentConfigPath =
|
|
731
|
+
const rootDirectory = resolve3(directory);
|
|
732
|
+
const agentConfigPath = join4(rootDirectory, BUDDY_AGENT_FILENAME);
|
|
502
733
|
const state2 = await pathState(rootDirectory);
|
|
503
734
|
if (state2.kind === "other") {
|
|
504
735
|
throw new ProjectInitializationError(
|
|
@@ -525,8 +756,8 @@ async function planBuddyDraftInitialization(directory) {
|
|
|
525
756
|
};
|
|
526
757
|
}
|
|
527
758
|
async function planBuddyProjectInitialization(options) {
|
|
528
|
-
const rootDirectory =
|
|
529
|
-
const agentConfigPath =
|
|
759
|
+
const rootDirectory = resolve3(options.directory);
|
|
760
|
+
const agentConfigPath = resolve3(rootDirectory, BUDDY_AGENT_FILENAME);
|
|
530
761
|
const state2 = await pathState(rootDirectory);
|
|
531
762
|
if (state2.kind === "other") {
|
|
532
763
|
throw new ProjectInitializationError(
|
|
@@ -555,7 +786,7 @@ async function planBuddyProjectInitialization(options) {
|
|
|
555
786
|
async function prepareInitializationDirectory(plan) {
|
|
556
787
|
if (plan.createRootDirectory) {
|
|
557
788
|
if ((await pathState(plan.rootDirectory)).kind !== "missing") throw targetChanged(plan);
|
|
558
|
-
const firstCreatedDirectory = await
|
|
789
|
+
const firstCreatedDirectory = await mkdir3(plan.rootDirectory, { recursive: true });
|
|
559
790
|
if (firstCreatedDirectory === void 0) throw targetChanged(plan);
|
|
560
791
|
const created = await pathState(plan.rootDirectory);
|
|
561
792
|
if (created.kind !== "directory") throw targetChanged(plan);
|
|
@@ -570,7 +801,7 @@ async function prepareInitializationDirectory(plan) {
|
|
|
570
801
|
async function publishNewFile(options) {
|
|
571
802
|
let temporaryHandle;
|
|
572
803
|
let publishedHandle;
|
|
573
|
-
const temporaryPath =
|
|
804
|
+
const temporaryPath = join4(
|
|
574
805
|
options.rootDirectory,
|
|
575
806
|
`.${options.temporaryLabel}.${process.pid}.${randomUUID()}.tmp`
|
|
576
807
|
);
|
|
@@ -614,7 +845,7 @@ async function publishNewFile(options) {
|
|
|
614
845
|
const afterPublish = await pathState(options.rootDirectory);
|
|
615
846
|
const publishedFileIdentity = await fileIdentity(options.targetPath);
|
|
616
847
|
const temporaryFileIdentity = await fileIdentity(temporaryPath);
|
|
617
|
-
const publishedContents = publishedFileIdentity ? await
|
|
848
|
+
const publishedContents = publishedFileIdentity ? await readFile5(options.targetPath, "utf8") : void 0;
|
|
618
849
|
if (afterPublish.kind !== "directory" || afterPublish.identity !== options.directoryIdentity || !publishedIdentity || publishedFileIdentity !== publishedIdentity || temporaryFileIdentity !== temporaryIdentity || publishedContents !== options.contents) {
|
|
619
850
|
if (afterPublish.kind === "directory" && afterPublish.identity === options.directoryIdentity && publishedIdentity) {
|
|
620
851
|
await unlinkMatchingFile(options.targetPath, publishedIdentity);
|
|
@@ -641,7 +872,7 @@ async function publishNewFile(options) {
|
|
|
641
872
|
}
|
|
642
873
|
}
|
|
643
874
|
async function replaceExistingFile(options) {
|
|
644
|
-
const temporaryPath =
|
|
875
|
+
const temporaryPath = join4(
|
|
645
876
|
options.rootDirectory,
|
|
646
877
|
`.${options.temporaryLabel}.${process.pid}.${randomUUID()}.tmp`
|
|
647
878
|
);
|
|
@@ -655,8 +886,8 @@ async function replaceExistingFile(options) {
|
|
|
655
886
|
try {
|
|
656
887
|
const root = await pathState(options.rootDirectory);
|
|
657
888
|
if (root.kind !== "directory" || root.identity !== options.directoryIdentity || await fileIdentity(options.targetPath) !== options.expectedFileIdentity) throw targetChanged({ rootDirectory: options.rootDirectory });
|
|
658
|
-
await
|
|
659
|
-
if (await
|
|
889
|
+
await rename2(temporaryPath, options.targetPath);
|
|
890
|
+
if (await readFile5(options.targetPath, "utf8") !== options.contents) {
|
|
660
891
|
throw targetChanged({ rootDirectory: options.rootDirectory });
|
|
661
892
|
}
|
|
662
893
|
} finally {
|
|
@@ -781,16 +1012,16 @@ async function initializeBuddyProject(options) {
|
|
|
781
1012
|
return applyBuddyProjectInitialization(plan, options.config);
|
|
782
1013
|
}
|
|
783
1014
|
async function readBuddyProjectManifest(projectRoot) {
|
|
784
|
-
const rootDirectory =
|
|
785
|
-
return parseBuddyProjectManifest(await
|
|
1015
|
+
const rootDirectory = resolve3(projectRoot);
|
|
1016
|
+
return parseBuddyProjectManifest(await readFile5(resolve3(rootDirectory, BUDDY_AGENT_FILENAME), "utf8"));
|
|
786
1017
|
}
|
|
787
1018
|
async function readBuddyAgentConfig(projectRoot) {
|
|
788
|
-
const rootDirectory =
|
|
789
|
-
const source = await
|
|
1019
|
+
const rootDirectory = resolve3(projectRoot);
|
|
1020
|
+
const source = await readFile5(resolve3(rootDirectory, BUDDY_AGENT_FILENAME), "utf8");
|
|
790
1021
|
return parseBuddyAgentConfig(source);
|
|
791
1022
|
}
|
|
792
1023
|
async function readBuddyConfig(projectRoot) {
|
|
793
|
-
const rootDirectory =
|
|
1024
|
+
const rootDirectory = resolve3(projectRoot);
|
|
794
1025
|
return combineBuddyProject(await readBuddyAgentConfig(rootDirectory));
|
|
795
1026
|
}
|
|
796
1027
|
|
|
@@ -806,10 +1037,10 @@ var BuddyProjectContextError = class extends Error {
|
|
|
806
1037
|
targetPath;
|
|
807
1038
|
};
|
|
808
1039
|
async function existingDirectory(target) {
|
|
809
|
-
const requested =
|
|
1040
|
+
const requested = resolve4(target);
|
|
810
1041
|
let entry;
|
|
811
1042
|
try {
|
|
812
|
-
entry = await
|
|
1043
|
+
entry = await lstat5(requested);
|
|
813
1044
|
} catch (cause) {
|
|
814
1045
|
if (cause.code === "ENOENT") {
|
|
815
1046
|
throw new BuddyProjectContextError(
|
|
@@ -828,12 +1059,12 @@ async function existingDirectory(target) {
|
|
|
828
1059
|
requested
|
|
829
1060
|
);
|
|
830
1061
|
}
|
|
831
|
-
return
|
|
1062
|
+
return realpath2(requested);
|
|
832
1063
|
}
|
|
833
1064
|
async function projectFileState(directory, filename) {
|
|
834
|
-
const configPath =
|
|
1065
|
+
const configPath = join5(directory, filename);
|
|
835
1066
|
try {
|
|
836
|
-
const entry = await
|
|
1067
|
+
const entry = await lstat5(configPath);
|
|
837
1068
|
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
838
1069
|
throw new BuddyProjectContextError(
|
|
839
1070
|
"PROJECT_CONFIG_INVALID",
|
|
@@ -860,7 +1091,7 @@ async function findBuddyProjectRoot(startDirectory) {
|
|
|
860
1091
|
return searchUp(await existingDirectory(startDirectory));
|
|
861
1092
|
}
|
|
862
1093
|
async function requireBuddyProjectRoot(startDirectory) {
|
|
863
|
-
const requested =
|
|
1094
|
+
const requested = resolve4(startDirectory);
|
|
864
1095
|
const root = await findBuddyProjectRoot(requested);
|
|
865
1096
|
if (root !== void 0) return root;
|
|
866
1097
|
throw new BuddyProjectContextError(
|
|
@@ -874,7 +1105,7 @@ async function requireBuddyProjectRoot(startDirectory) {
|
|
|
874
1105
|
}
|
|
875
1106
|
async function requireBuddyAgentProjectRoot(startDirectory) {
|
|
876
1107
|
const root = await requireBuddyProjectRoot(startDirectory);
|
|
877
|
-
const agentPath =
|
|
1108
|
+
const agentPath = join5(root, BUDDY_AGENT_FILENAME);
|
|
878
1109
|
try {
|
|
879
1110
|
await readBuddyAgentConfig(root);
|
|
880
1111
|
const missing = await missingBuddyAgentFiles(root);
|
|
@@ -893,10 +1124,10 @@ async function requireBuddyAgentProjectRoot(startDirectory) {
|
|
|
893
1124
|
}
|
|
894
1125
|
}
|
|
895
1126
|
async function nearestExistingDirectory(target) {
|
|
896
|
-
let candidate =
|
|
1127
|
+
let candidate = resolve4(target);
|
|
897
1128
|
while (true) {
|
|
898
1129
|
try {
|
|
899
|
-
const entry = await
|
|
1130
|
+
const entry = await lstat5(candidate);
|
|
900
1131
|
if (!entry.isDirectory()) {
|
|
901
1132
|
throw new BuddyProjectContextError(
|
|
902
1133
|
"PROJECT_DIRECTORY_INVALID",
|
|
@@ -904,7 +1135,7 @@ async function nearestExistingDirectory(target) {
|
|
|
904
1135
|
candidate
|
|
905
1136
|
);
|
|
906
1137
|
}
|
|
907
|
-
return
|
|
1138
|
+
return realpath2(candidate);
|
|
908
1139
|
} catch (cause) {
|
|
909
1140
|
if (cause.code !== "ENOENT") throw cause;
|
|
910
1141
|
const parent = dirname(candidate);
|
|
@@ -914,7 +1145,7 @@ async function nearestExistingDirectory(target) {
|
|
|
914
1145
|
}
|
|
915
1146
|
}
|
|
916
1147
|
async function assertOutsideBuddyProject(target) {
|
|
917
|
-
const requested =
|
|
1148
|
+
const requested = resolve4(target);
|
|
918
1149
|
const container = await nearestExistingDirectory(requested);
|
|
919
1150
|
const projectRoot = await searchUp(container);
|
|
920
1151
|
if (projectRoot === void 0) return;
|
|
@@ -928,13 +1159,13 @@ async function assertOutsideBuddyProject(target) {
|
|
|
928
1159
|
);
|
|
929
1160
|
}
|
|
930
1161
|
async function assertInitializableBuddyTarget(target) {
|
|
931
|
-
const requested =
|
|
1162
|
+
const requested = resolve4(target);
|
|
932
1163
|
const container = await nearestExistingDirectory(requested);
|
|
933
1164
|
const projectRoot = await searchUp(container);
|
|
934
1165
|
if (projectRoot === void 0) return;
|
|
935
1166
|
let requestedRoot = requested;
|
|
936
1167
|
try {
|
|
937
|
-
requestedRoot = await
|
|
1168
|
+
requestedRoot = await realpath2(requested);
|
|
938
1169
|
} catch (cause) {
|
|
939
1170
|
if (cause.code !== "ENOENT") throw cause;
|
|
940
1171
|
}
|
|
@@ -945,7 +1176,7 @@ async function assertInitializableBuddyTarget(target) {
|
|
|
945
1176
|
} catch (cause) {
|
|
946
1177
|
throw new BuddyProjectContextError(
|
|
947
1178
|
"PROJECT_CONFIG_INVALID",
|
|
948
|
-
`${
|
|
1179
|
+
`${join5(projectRoot, BUDDY_AGENT_FILENAME)} \u4E0D\u662F\u6709\u6548\u7684\u9879\u76EE\u6E05\u5355\u3002`,
|
|
949
1180
|
requested,
|
|
950
1181
|
{ cause }
|
|
951
1182
|
);
|
|
@@ -961,322 +1192,44 @@ async function assertInitializableBuddyTarget(target) {
|
|
|
961
1192
|
);
|
|
962
1193
|
}
|
|
963
1194
|
|
|
964
|
-
// packages/cli-core/src/
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
var IMPLEMENTATION = "widget-implementation.json";
|
|
970
|
-
var RECEIPTS = ".buddy/widget-verification.json";
|
|
971
|
-
var idPattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
|
|
972
|
-
var hashPattern = /^[a-f0-9]{64}$/u;
|
|
973
|
-
var sha = (raw) => createHash("sha256").update(raw).digest("hex");
|
|
974
|
-
var object = (value) => value && typeof value === "object" && !Array.isArray(value);
|
|
975
|
-
var text = (value) => typeof value === "string" && value.trim().length > 0;
|
|
976
|
-
var WIDGET_REVIEW_CHECKS = ["visual", "interactions", "data-update", "trigger", "read-only"];
|
|
977
|
-
var WIDGET_REVIEW_STATES = ["initial", "partial", "updated"];
|
|
978
|
-
var NOTICE = "\u7ED3\u6784\u68C0\u67E5\u4E0E\u9884\u89C8\u6838\u5BF9\u8BB0\u5F55\u5206\u522B\u5C55\u793A\uFF1B\u6838\u5BF9\u8BB0\u5F55\u7531\u6267\u884C\u6838\u5BF9\u8005\u63D0\u4F9B\uFF0C\u5DE5\u5177\u4E0D\u81EA\u52A8\u5224\u65AD\u89C6\u89C9\u4E00\u81F4\uFF0C\u4E5F\u4E0D\u4EE3\u8868\u5F00\u53D1\u8005\u4F53\u9A8C\u9A8C\u6536\u6216\u53D1\u5E03\u6210\u529F\u3002";
|
|
979
|
-
function portable(path) {
|
|
980
|
-
if (!text(path) || path.startsWith("/") || path.includes("\\") || /[\x00-\x1f:]/u.test(path) || path.split("/").some((p) => !p || p === "." || p === "..")) throw new Error("\u5C0F\u6302\u4EF6\u8DEF\u5F84\u5FC5\u987B\u662F\u9879\u76EE\u5185\u76F8\u5BF9\u8DEF\u5F84");
|
|
981
|
-
return path;
|
|
982
|
-
}
|
|
983
|
-
async function file(root, path, optional = false) {
|
|
984
|
-
portable(path);
|
|
985
|
-
const base = await realpath2(root);
|
|
986
|
-
let cursor = base;
|
|
987
|
-
const parts = path.split("/");
|
|
988
|
-
for (const [index, part] of parts.entries()) {
|
|
989
|
-
cursor = join4(cursor, part);
|
|
990
|
-
const stat2 = await lstat5(cursor).catch((e) => {
|
|
991
|
-
if (e.code === "ENOENT") return void 0;
|
|
992
|
-
throw e;
|
|
993
|
-
});
|
|
994
|
-
if (!stat2) {
|
|
995
|
-
if (optional) return void 0;
|
|
996
|
-
throw new Error(`\u7F3A\u5C11\u6587\u4EF6\uFF1A${path}`);
|
|
997
|
-
}
|
|
998
|
-
if (stat2.isSymbolicLink() || (index < parts.length - 1 ? !stat2.isDirectory() : !stat2.isFile())) throw new Error(`\u4E0D\u63A5\u53D7\u7B26\u53F7\u94FE\u63A5\u6216\u7279\u6B8A\u6587\u4EF6\uFF1A${path}`);
|
|
999
|
-
if (index === parts.length - 1 && stat2.size > 8 * 1024 * 1024) throw new Error(`\u6587\u4EF6\u8D85\u8FC7 8 MB\uFF1A${path}`);
|
|
1000
|
-
}
|
|
1001
|
-
return readFile3(cursor);
|
|
1002
|
-
}
|
|
1003
|
-
async function jsonFile(root, path, optional = false) {
|
|
1004
|
-
const bytes = await file(root, path, optional);
|
|
1005
|
-
if (!bytes) return void 0;
|
|
1006
|
-
try {
|
|
1007
|
-
return JSON.parse(bytes.toString("utf8"));
|
|
1008
|
-
} catch {
|
|
1009
|
-
throw new Error(`JSON \u65E0\u6548\uFF1A${path}`);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
async function save(root, path, value) {
|
|
1013
|
-
portable(path);
|
|
1014
|
-
let cursor = resolve4(root);
|
|
1015
|
-
for (const segment of path.split("/").slice(0, -1)) {
|
|
1016
|
-
cursor = join4(cursor, segment);
|
|
1017
|
-
await mkdir3(cursor).catch((e) => {
|
|
1018
|
-
if (e.code !== "EEXIST") throw e;
|
|
1019
|
-
});
|
|
1020
|
-
const stat2 = await lstat5(cursor);
|
|
1021
|
-
if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw new Error("\u5199\u5165\u76EE\u5F55\u4E0D\u5B89\u5168");
|
|
1022
|
-
}
|
|
1023
|
-
await file(root, path, true);
|
|
1024
|
-
const target = join4(root, path), temp = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
1025
|
-
await writeFile(temp, JSON.stringify(value, null, 2) + "\n", { flag: "wx", mode: 384 });
|
|
1026
|
-
await rename2(temp, target);
|
|
1027
|
-
}
|
|
1028
|
-
function validateLock(value) {
|
|
1029
|
-
if (!object(value) || value.schemaVersion !== 1 || !text(value.buddyId) || !text(value.revision) || !hashPattern.test(value.catalogHash) || !Array.isArray(value.items) || value.items.length > 100) throw new Error("\u8BBE\u8BA1\u7ED1\u5B9A\u6587\u4EF6\u65E0\u6548\uFF0C\u8BF7\u8FD0\u884C buddy-cli widgets sync");
|
|
1030
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1031
|
-
for (const item of value.items) {
|
|
1032
|
-
if (!object(item) || typeof item.id !== "string" || item.id.length > 64 || !idPattern.test(item.id) || seen.has(item.id) || !text(item.name) || !hashPattern.test(item.prototypeHash) || !Array.isArray(item.fields) || !item.fields.every(text) || new Set(item.fields).size !== item.fields.length) throw new Error("\u8BBE\u8BA1\u6E05\u5355\u5305\u542B\u65E0\u6548\u6216\u91CD\u590D\u7684\u5C0F\u6302\u4EF6");
|
|
1033
|
-
seen.add(item.id);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
async function creatorDesign(root) {
|
|
1037
|
-
const session = await jsonFile(root, ".buddy/creator/session.json", true);
|
|
1038
|
-
if (!session) return void 0;
|
|
1039
|
-
if (session.schemaVersion !== 1 || !text(session.platformBuddyId) || !/^[a-f0-9-]{36}$/u.test(session.creationKey)) throw new Error("Creator \u9879\u76EE\u8EAB\u4EFD\u65E0\u6548");
|
|
1040
|
-
const workspace = `.buddy/creator/workspaces/${session.creationKey}`;
|
|
1041
|
-
const state2 = await jsonFile(root, `${workspace}/state.json`);
|
|
1042
|
-
if (!state2.artifacts?.["widget.catalog"]) return void 0;
|
|
1043
|
-
const completion = await jsonFile(root, `${workspace}/completion.json`);
|
|
1044
|
-
if (completion.status !== "ready" || completion.revision !== state2.revision || state2.paused || state2.pendingTurnId || !/^[a-zA-Z0-9_-]+$/u.test(state2.revision)) throw new Error("\u5C0F\u6302\u4EF6\u8BBE\u8BA1\u4EA4\u4ED8\u672A\u5B8C\u6210\u6216\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5148\u6062\u590D Creator \u5F53\u524D\u8BBE\u8BA1\u9A8C\u6536");
|
|
1045
|
-
const directory = `${workspace}/deliverables/${state2.revision}`;
|
|
1046
|
-
const manifest = await jsonFile(root, `${directory}/MANIFEST.json`);
|
|
1047
|
-
if (state2.buddyId !== session.creationKey || manifest.buddyId !== state2.buddyId) throw new Error("Creator \u4F5C\u54C1\u4E0E\u4EA4\u4ED8\u8EAB\u4EFD\u4E0D\u4E00\u81F4");
|
|
1048
|
-
if (manifest.complete !== true || manifest.revision !== state2.revision || !Array.isArray(manifest.files)) throw new Error("\u8BBE\u8BA1\u4EA4\u4ED8\u6E05\u5355\u65E0\u6548");
|
|
1049
|
-
const artifact = async (path) => {
|
|
1050
|
-
const bytes = await file(root, `${directory}/${path}`);
|
|
1051
|
-
const entry = manifest.files.find((e) => e.path === path);
|
|
1052
|
-
if (!entry || entry.sha256 !== sha(bytes) || entry.bytes !== bytes.length) throw new Error(`\u8BBE\u8BA1\u6210\u679C\u88AB\u4FEE\u6539\uFF1A${path}\uFF1B\u5148\u6062\u590D\u4EA4\u4ED8`);
|
|
1053
|
-
return bytes;
|
|
1054
|
-
};
|
|
1055
|
-
const confirmed = (id, hash) => state2.artifacts?.[id]?.hash === hash && state2.confirmations?.some((c) => c.objectId === id && c.hash === hash && c.decision === "confirmed" && !c.invalidatedBy);
|
|
1056
|
-
const catalog = JSON.parse((await artifact("widgets/catalog.json")).toString());
|
|
1057
|
-
if (!confirmed("widget.catalog", catalog.hash) || !Array.isArray(catalog.data?.widgets)) throw new Error("\u5C0F\u6302\u4EF6\u6E05\u5355\u4E0D\u662F\u5F53\u524D\u5DF2\u786E\u8BA4\u7248\u672C");
|
|
1058
|
-
const items = [];
|
|
1059
|
-
for (const item of catalog.data.widgets) {
|
|
1060
|
-
if (!text(item.id) || item.id.length > 64 || !idPattern.test(item.id)) throw new Error("\u8BBE\u8BA1\u7C7B\u578B ID \u65E0\u6548");
|
|
1061
|
-
const prefix = `widgets/${item.id}`;
|
|
1062
|
-
const prototype = JSON.parse((await artifact(`${prefix}/prototype.json`)).toString());
|
|
1063
|
-
const acceptance = JSON.parse((await artifact(`${prefix}/acceptance.json`)).toString()).artifact;
|
|
1064
|
-
if (!confirmed(`widget.${item.id}.prototype`, prototype.hash) || !confirmed(`widget.${item.id}.acceptance`, acceptance.hash) || acceptance.data?.prototypeHash !== prototype.hash) throw new Error(`\u8BBE\u8BA1\u5C1A\u672A\u6709\u6548\u9A8C\u6536\uFF1A${item.id}`);
|
|
1065
|
-
for (const asset of ["index.html", "style.css", "app.js"]) await artifact(`${prefix}/${asset}`);
|
|
1066
|
-
items.push({ id: item.id, name: item.name, prototypeHash: prototype.hash, fields: item.fields.map((f) => f.key) });
|
|
1067
|
-
}
|
|
1068
|
-
const result = { schemaVersion: 1, buddyId: session.platformBuddyId, revision: state2.revision, catalogHash: catalog.hash, items };
|
|
1069
|
-
validateLock(result);
|
|
1070
|
-
return result;
|
|
1071
|
-
}
|
|
1072
|
-
async function syncWidgetDesign(root) {
|
|
1073
|
-
const design = await creatorDesign(root);
|
|
1074
|
-
if (!design) throw new Error("\u5F53\u524D\u9879\u76EE\u6CA1\u6709\u5DF2\u9A8C\u6536\u7684\u5C0F\u6302\u4EF6\u8BBE\u8BA1\uFF1B\u76F4\u63A5\u5F00\u53D1\u9879\u76EE\u53EF\u7EE7\u7EED\u4F7F\u7528\u539F\u6D41\u7A0B");
|
|
1075
|
-
const config = await jsonFile(root, "buddy.agent.json");
|
|
1076
|
-
if (config.buddyId !== design.buddyId) throw new Error("\u8BBE\u8BA1\u4E0E\u642D\u5B50\u8EAB\u4EFD\u4E0D\u4E00\u81F4");
|
|
1077
|
-
const old = await jsonFile(root, IMPLEMENTATION, true);
|
|
1078
|
-
if (old && (!object(old) || old.schemaVersion !== 1 || !Array.isArray(old.widgets))) throw new Error("\u5DF2\u6709\u5B9E\u73B0\u6620\u5C04\u635F\u574F\uFF0C\u4FDD\u7559\u539F\u6587\u4EF6\uFF0C\u8BF7\u4FEE\u590D\u540E\u518D\u540C\u6B65");
|
|
1079
|
-
const mappings = design.items.map((item) => old?.widgets.find((w) => w.designId === item.id) ?? {
|
|
1080
|
-
designId: item.id,
|
|
1081
|
-
typeId: item.id,
|
|
1082
|
-
prototypeHash: item.prototypeHash,
|
|
1083
|
-
fields: Object.fromEntries(item.fields.map((key) => [key, ""])),
|
|
1084
|
-
lifecycle: { create: [], update: [], present: [] }
|
|
1085
|
-
});
|
|
1086
|
-
const next = { schemaVersion: 1, widgets: mappings };
|
|
1087
|
-
if (JSON.stringify(old) !== JSON.stringify(next)) await save(root, IMPLEMENTATION, next);
|
|
1088
|
-
await save(root, LOCK, design);
|
|
1089
|
-
}
|
|
1090
|
-
async function sourceSnapshot(root) {
|
|
1091
|
-
const result = [];
|
|
1092
|
-
const visit = async (path, depth = 0) => {
|
|
1093
|
-
if (depth > 32 || result.length > 1e4) throw new Error("\u5B9E\u73B0\u6E90\u7801\u8D85\u51FA\u68C0\u67E5\u8303\u56F4");
|
|
1094
|
-
const stat2 = await lstat5(join4(root, path)).catch((e) => {
|
|
1095
|
-
if (e.code === "ENOENT") return void 0;
|
|
1096
|
-
throw e;
|
|
1097
|
-
});
|
|
1098
|
-
if (!stat2) return;
|
|
1099
|
-
if (stat2.isSymbolicLink()) throw new Error(`\u5B9E\u73B0\u4E0D\u80FD\u4F7F\u7528\u7B26\u53F7\u94FE\u63A5\uFF1A${path}`);
|
|
1100
|
-
if (stat2.isDirectory()) {
|
|
1101
|
-
for (const name of (await readdir2(join4(root, path))).sort()) await visit(`${path}/${name}`, depth + 1);
|
|
1102
|
-
} else result.push([path, sha(await file(root, path))]);
|
|
1103
|
-
};
|
|
1104
|
-
for (const name of ["src", "resources", "widgets", "start.mjs", "agent.md", "buddy.agent.json", "package.json", "package-lock.json", "pnpm-lock.yaml", "yarn.lock"]) await visit(name);
|
|
1105
|
-
return result;
|
|
1106
|
-
}
|
|
1107
|
-
async function checkWidgetDelivery(root) {
|
|
1108
|
-
const report = { status: "not-configured", items: [], issues: [], notice: NOTICE };
|
|
1109
|
-
try {
|
|
1110
|
-
const current = await creatorDesign(root);
|
|
1111
|
-
const lockBytes = await file(root, LOCK, true);
|
|
1112
|
-
let lock = lockBytes ? JSON.parse(lockBytes.toString()) : void 0;
|
|
1113
|
-
if (!current && !lock) {
|
|
1114
|
-
if (await file(root, IMPLEMENTATION, true)) throw new Error("\u5B9E\u73B0\u6620\u5C04\u5B58\u5728\uFF0C\u4F46\u8BBE\u8BA1\u7ED1\u5B9A\u7F3A\u5931\uFF0C\u8BF7\u6062\u590D widget-design.lock.json");
|
|
1115
|
-
return report;
|
|
1116
|
-
}
|
|
1117
|
-
report.status = "incomplete";
|
|
1118
|
-
if (!lock) {
|
|
1119
|
-
report.issues.push("\u5DF2\u9A8C\u6536\u8BBE\u8BA1\u5C1A\u672A\u7ED1\u5B9A\u5230\u5DE5\u7A0B\uFF0C\u8BF7\u8FD0\u884C buddy-cli widgets sync");
|
|
1120
|
-
lock = current;
|
|
1121
|
-
}
|
|
1122
|
-
validateLock(lock);
|
|
1123
|
-
report.designRevision = lock.revision;
|
|
1124
|
-
const config = await jsonFile(root, "buddy.agent.json");
|
|
1125
|
-
if (config.buddyId !== lock.buddyId) throw new Error("\u8BBE\u8BA1\u4E0E\u642D\u5B50\u8EAB\u4EFD\u4E0D\u4E00\u81F4");
|
|
1126
|
-
if (current && JSON.stringify(current) !== JSON.stringify(lock)) report.issues.push("\u8BBE\u8BA1\u5DF2\u53D8\u5316\uFF0C\u8BF7\u8FD0\u884C buddy-cli widgets sync\uFF1B\u65E7\u5B9E\u73B0\u548C\u6838\u5BF9\u8BB0\u5F55\u4E0D\u80FD\u6CBF\u7528\u4E3A\u65B0\u7248\u9A8C\u6536");
|
|
1127
|
-
const implementationBytes = await file(root, IMPLEMENTATION, true);
|
|
1128
|
-
const implementation = implementationBytes ? JSON.parse(implementationBytes.toString()) : void 0;
|
|
1129
|
-
const mappings = implementation?.schemaVersion === 1 && Array.isArray(implementation.widgets) ? implementation.widgets : [];
|
|
1130
|
-
if (!implementation || mappings.length !== lock.items.length) report.issues.push("\u5B9E\u73B0\u6620\u5C04\u4E0E\u5DF2\u9A8C\u6536\u6E05\u5355\u6570\u91CF\u4E0D\u7B26");
|
|
1131
|
-
const receipts = await jsonFile(root, RECEIPTS, true);
|
|
1132
|
-
const snapshot = await sourceSnapshot(root);
|
|
1133
|
-
report.files = snapshot.map(([path, digest2]) => ({ path, digest: `sha256:${digest2}` }));
|
|
1134
|
-
if (lockBytes) report.files.push({ path: LOCK, digest: `sha256:${sha(lockBytes)}` });
|
|
1135
|
-
if (implementationBytes) report.files.push({ path: IMPLEMENTATION, digest: `sha256:${sha(implementationBytes)}` });
|
|
1136
|
-
const usedTypes = /* @__PURE__ */ new Set();
|
|
1137
|
-
for (const mapping of mappings) if (!lock.items.some((item) => item.id === mapping.designId)) report.issues.push("\u5B58\u5728\u4E0D\u5C5E\u4E8E\u5F53\u524D\u8BBE\u8BA1\u7684\u5B9E\u73B0\u6620\u5C04\uFF0C\u8BF7\u8FD0\u884C widgets sync");
|
|
1138
|
-
for (const item of lock.items) {
|
|
1139
|
-
const row = { id: item.id, name: item.name, status: "missing", issues: [] };
|
|
1140
|
-
report.items.push(row);
|
|
1141
|
-
try {
|
|
1142
|
-
const matches = mappings.filter((w) => w.designId === item.id);
|
|
1143
|
-
if (matches.length !== 1) throw new Error("\u7F3A\u5C11\u6216\u91CD\u590D\u7684\u5B9E\u73B0\u6620\u5C04");
|
|
1144
|
-
const m = matches[0];
|
|
1145
|
-
if (!text(m.typeId) || m.typeId.length > 64 || !/^[\p{L}\p{N}][\p{L}\p{N}_-]*$/u.test(m.typeId) || usedTypes.has(m.typeId)) throw new Error("\u6BCF\u4E2A\u5DF2\u9A8C\u6536\u8BBE\u8BA1\u5FC5\u987B\u5BF9\u5E94\u4E00\u4E2A\u72EC\u7ACB\u3001\u6709\u6548\u7684\u7C7B\u578B ID\uFF0C\u4E0D\u80FD\u5408\u5E76\u6210\u540C\u4E00\u4E2A\u5DE5\u4F5C\u53F0");
|
|
1146
|
-
usedTypes.add(m.typeId);
|
|
1147
|
-
row.typeId = m.typeId;
|
|
1148
|
-
if (m.prototypeHash !== item.prototypeHash) row.issues.push("\u5B9E\u73B0\u7ED1\u5B9A\u7684\u539F\u578B\u7248\u672C\u5DF2\u8FC7\u671F");
|
|
1149
|
-
const html = (await file(root, `widgets/${m.typeId}/index.html`)).toString();
|
|
1150
|
-
if (!html.trim()) throw new Error("\u9875\u9762\u4E3A\u7A7A");
|
|
1151
|
-
const schema = await jsonFile(root, `widgets/${m.typeId}/schema.json`);
|
|
1152
|
-
if (!object(schema.modules) || !Object.keys(schema.modules).length) throw new Error("\u7F3A\u5C11\u6709\u6548\u7684\u6570\u636E\u6A21\u5757");
|
|
1153
|
-
for (const key of item.fields) {
|
|
1154
|
-
const binding = m.fields?.[key];
|
|
1155
|
-
if (!text(binding) || !object(schema.modules[binding.split(".")[0]]?.record)) row.issues.push(`\u5B57\u6BB5 ${key} \u672A\u6620\u5C04\u5230\u5B9E\u9645\u6570\u636E\u6A21\u5757`);
|
|
1156
|
-
}
|
|
1157
|
-
for (const phase of ["create", "update", "present"]) {
|
|
1158
|
-
const paths = m.lifecycle?.[phase];
|
|
1159
|
-
if (!Array.isArray(paths) || !paths.length || paths.length > 50 || !paths.every(text)) {
|
|
1160
|
-
row.issues.push(`\u7F3A\u5C11${phase}\u4EE3\u7801\u8DEF\u5F84`);
|
|
1161
|
-
continue;
|
|
1162
|
-
}
|
|
1163
|
-
for (const path of paths) {
|
|
1164
|
-
if (!path.startsWith("src/") || !/\.(?:mjs|js|ts|cjs)$/u.test(path)) throw new Error("\u521B\u5EFA\u3001\u66F4\u65B0\u548C\u5C55\u793A\u5FC5\u987B\u6620\u5C04\u5230 src/ \u4E0B\u7684\u4EE3\u7801");
|
|
1165
|
-
if (!(await file(root, path)).toString().trim()) throw new Error(`\u4EE3\u7801\u4E3A\u7A7A\uFF1A${path}`);
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
if (row.issues.length) continue;
|
|
1169
|
-
row.status = "implemented";
|
|
1170
|
-
row.implementationDigest = sha(JSON.stringify({ design: lock, mapping: m, snapshot }));
|
|
1171
|
-
const receipt = receipts?.items?.[item.id];
|
|
1172
|
-
if (receipt?.implementationDigest === row.implementationDigest) {
|
|
1173
|
-
validateEvidence(receipt.evidence);
|
|
1174
|
-
if (!Array.isArray(receipt.artifacts) || receipt.artifacts.length !== 3) throw new Error("\u6838\u5BF9\u8BC1\u636E\u8BB0\u5F55\u65E0\u6548");
|
|
1175
|
-
for (const [index, artifact] of receipt.artifacts.entries()) {
|
|
1176
|
-
if (artifact.path !== receipt.evidence.states[WIDGET_REVIEW_STATES[index]].artifact) throw new Error("\u6838\u5BF9\u8BC1\u636E\u8DEF\u5F84\u4E0D\u5339\u914D");
|
|
1177
|
-
if (sha(await file(root, artifact.path)) !== artifact.digest) throw new Error("\u9884\u89C8\u6838\u5BF9\u8BC1\u636E\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6838\u5BF9");
|
|
1178
|
-
}
|
|
1179
|
-
if (!receipt.artifacts.length) throw new Error("\u7F3A\u5C11\u9884\u89C8\u6838\u5BF9\u8BC1\u636E");
|
|
1180
|
-
row.status = "verified";
|
|
1181
|
-
} else row.issues.push("\u5C1A\u672A\u8BB0\u5F55\u5F53\u524D\u5B9E\u73B0\u7248\u672C\u7684\u771F\u5B9E\u9884\u89C8\u6838\u5BF9\uFF1B\u6587\u4EF6\u5B58\u5728\u4E0D\u7B49\u4E8E\u6837\u5F0F\u4E0E\u884C\u4E3A\u5DF2\u9A8C\u8BC1");
|
|
1182
|
-
} catch (cause) {
|
|
1183
|
-
row.issues.push(cause instanceof Error ? cause.message : String(cause));
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
if (!report.issues.length && report.items.every((item) => item.status === "verified" && !item.issues.length)) report.status = "ready";
|
|
1187
|
-
} catch (cause) {
|
|
1188
|
-
report.status = "incomplete";
|
|
1189
|
-
report.issues.push(cause instanceof Error ? cause.message : String(cause));
|
|
1190
|
-
}
|
|
1191
|
-
return report;
|
|
1192
|
-
}
|
|
1193
|
-
function validateEvidence(value) {
|
|
1194
|
-
if (!object(value) || !text(value.previewUrl) || !text(value.observedAt) || !Number.isFinite(Date.parse(value.observedAt)) || !text(value.reviewer) || !object(value.states) || !object(value.checks)) throw new Error("\u6838\u5BF9\u8BB0\u5F55\u9700\u5305\u542B previewUrl\u3001observedAt\u3001reviewer\u3001states \u548C checks");
|
|
1195
|
-
const url = new URL(value.previewUrl);
|
|
1196
|
-
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.pathname.includes("bootstrap") || url.search || url.hash) throw new Error("\u9884\u89C8\u5730\u5740\u9700\u4F7F\u7528\u4E0D\u542B\u767B\u5F55\u51ED\u636E\u7684\u9875\u9762\u5730\u5740");
|
|
1197
|
-
for (const state2 of WIDGET_REVIEW_STATES) {
|
|
1198
|
-
if (!text(value.states[state2]?.notes) || !text(value.states[state2]?.artifact)) throw new Error(`\u7F3A\u5C11 ${state2} \u7684\u89C2\u5BDF\u8BF4\u660E\u4E0E\u8BC1\u636E\u6587\u4EF6`);
|
|
1199
|
-
portable(value.states[state2].artifact);
|
|
1200
|
-
}
|
|
1201
|
-
for (const check of WIDGET_REVIEW_CHECKS) if (!text(value.checks[check])) throw new Error(`\u7F3A\u5C11 ${check} \u7684\u5B9E\u9645\u89C2\u5BDF\u8BF4\u660E`);
|
|
1202
|
-
}
|
|
1203
|
-
async function recordWidgetVerification(root, designId, evidencePath) {
|
|
1204
|
-
const report = await checkWidgetDelivery(root);
|
|
1205
|
-
const row = report.items.find((item) => item.id === designId);
|
|
1206
|
-
if (report.issues.length || !row?.implementationDigest) throw new Error("\u5148\u5B8C\u6210\u5F53\u524D\u8BBE\u8BA1\u4E0E\u5B9E\u73B0\u7684\u7ED3\u6784\u68C0\u67E5\uFF0C\u518D\u8BB0\u5F55\u9884\u89C8\u6838\u5BF9");
|
|
1207
|
-
const evidence = await jsonFile(root, evidencePath);
|
|
1208
|
-
validateEvidence(evidence);
|
|
1209
|
-
if (evidence.implementationDigest !== row.implementationDigest) throw new Error("\u6838\u5BF9\u8BB0\u5F55\u7684 implementationDigest \u4E0E\u5F53\u524D\u4EE3\u7801\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u5148\u6838\u5BF9\u5F53\u524D\u5B9E\u73B0");
|
|
1210
|
-
const artifacts = [];
|
|
1211
|
-
for (const state2 of WIDGET_REVIEW_STATES) {
|
|
1212
|
-
const path = evidence.states[state2].artifact;
|
|
1213
|
-
artifacts.push({ path, digest: sha(await file(root, path)) });
|
|
1214
|
-
}
|
|
1215
|
-
const old = await jsonFile(root, RECEIPTS, true);
|
|
1216
|
-
if (old && (old.schemaVersion !== 1 || !object(old.items))) throw new Error("\u5DF2\u6709\u6838\u5BF9\u8BB0\u5F55\u635F\u574F\uFF0C\u4FDD\u7559\u6587\u4EF6\u8BF7\u5148\u4FEE\u590D");
|
|
1217
|
-
await save(root, RECEIPTS, { schemaVersion: 1, items: { ...old?.items, [designId]: {
|
|
1218
|
-
implementationDigest: row.implementationDigest,
|
|
1219
|
-
evidence,
|
|
1220
|
-
artifacts
|
|
1221
|
-
} } });
|
|
1222
|
-
}
|
|
1223
|
-
function widgetDeliverySummary(report) {
|
|
1224
|
-
if (report.status === "not-configured") return "\u5F53\u524D\u5DE5\u7A0B\u6CA1\u6709\u7ED1\u5B9A\u7684 Creator \u5C0F\u6302\u4EF6\u8BBE\u8BA1\uFF1B\u672A\u6267\u884C\u8BBE\u8BA1\u4E00\u81F4\u6027\u68C0\u67E5\u3002";
|
|
1225
|
-
return [
|
|
1226
|
-
report.status === "ready" ? "\u5C0F\u6302\u4EF6\u7ED3\u6784\u68C0\u67E5\u4E0E\u5F53\u524D\u7248\u672C\u9884\u89C8\u6838\u5BF9\u8BB0\u5F55\u9F50\u5168\u3002" : "\u5C0F\u6302\u4EF6\u4EA4\u4ED8\u672A\u5B8C\u6210\uFF1A",
|
|
1227
|
-
...report.issues,
|
|
1228
|
-
...report.items.map((item) => `${item.name}\uFF08${item.id}\uFF09\uFF1A${item.status === "verified" ? "\u6838\u5BF9\u5DF2\u8BB0\u5F55" : item.status === "implemented" ? "\u5DF2\u5B9E\u73B0\uFF0C\u5F85\u6838\u5BF9" : "\u5F85\u8865\u9F50\u5B9E\u73B0"}${item.issues.length ? "\uFF1B" + item.issues.join("\uFF1B") : ""}`),
|
|
1229
|
-
report.notice
|
|
1230
|
-
].join("\n");
|
|
1195
|
+
// packages/cli-core/src/commands/runtime-source.ts
|
|
1196
|
+
async function runtimeCatalogSource(directory, options = {}) {
|
|
1197
|
+
const project = await findBuddyProjectRoot(directory);
|
|
1198
|
+
if (project) return { root: project, source: "project" };
|
|
1199
|
+
return { root: await (options.latestRuntimeRoot?.() ?? cachedLatestRuntimeRoot(options)), source: "npm" };
|
|
1231
1200
|
}
|
|
1232
1201
|
|
|
1233
|
-
// packages/cli-core/src/commands/
|
|
1234
|
-
var
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
check \u9010\u9879\u5217\u51FA\u9057\u6F0F\u3001\u8FC7\u671F\u7248\u672C\u548C\u5F85\u6838\u5BF9\u9879\uFF1B\u9000\u51FA\u7801 1 \u8868\u793A\u672A\u5B8C\u6210\u3002DEV \u53EF\u7EE7\u7EED\u8C03\u8BD5\uFF0Cpush \u4F1A\u62E6\u622A\u3002
|
|
1240
|
-
verify \u8BB0\u5F55\u771F\u5B9E\u9884\u89C8\u7684\u4E09\u6001\u8BC1\u636E\u4E0E\u4E94\u9879\u89C2\u5BDF\uFF0C\u5E76\u7ED1\u5B9A\u5F53\u524D\u4EE3\u7801\u6458\u8981\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u5224\u65AD\u89C6\u89C9\u4E00\u81F4\u3002`;
|
|
1241
|
-
async function runWidgetsCommand(args, io, cwd) {
|
|
1202
|
+
// packages/cli-core/src/commands/models.ts
|
|
1203
|
+
var MODELS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli models [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
|
|
1204
|
+
\u5DE5\u7A0B\u5185\u8BFB\u53D6\u5DF2\u5B89\u88C5 Runtime \u7684\u6A21\u578B\u76EE\u5F55\uFF1B\u5DE5\u7A0B\u5916\u8054\u7F51\u8BFB\u53D6\u5E76\u7F13\u5B58\u516C\u5171 npm \u6700\u65B0 Runtime\u3002
|
|
1205
|
+
\u65E0\u9700\u767B\u5F55\u642D\u642D\u8D26\u53F7\u3002\u8F93\u51FA\u5305\u542B\u5B9E\u9645 Runtime \u7248\u672C\u548C\u6765\u6E90\u3002
|
|
1206
|
+
\u5C06\u6240\u9009 ID \u5199\u5165 buddy.agent.json.model\uFF1B\u6A21\u677F\u5728 initialState.model \u4E2D\u4F7F\u7528\u5B83\u3002`;
|
|
1207
|
+
async function runModelsCommand(args, io, cwd, options = {}) {
|
|
1242
1208
|
try {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
io.write(WIDGET_COMMAND_HELP);
|
|
1209
|
+
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
1210
|
+
io.write(MODELS_COMMAND_HELP);
|
|
1246
1211
|
return { exitCode: 0 };
|
|
1247
1212
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
for (let i = 0; i <
|
|
1251
|
-
|
|
1252
|
-
if (
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
const value = rest[++i];
|
|
1256
|
-
if (!value || value.startsWith("--")) throw new Error(`\u7F3A\u5C11\u53C2\u6570\uFF1A${key}`);
|
|
1257
|
-
flags.set(key, value);
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
if (action !== "verify" && (flags.has("--id") || flags.has("--evidence"))) throw new Error("--id / --evidence \u4EC5\u7528\u4E8E verify");
|
|
1261
|
-
if (action !== "check" && flags.has("--json")) throw new Error("--json \u4EC5\u7528\u4E8E check");
|
|
1262
|
-
const root = await findBuddyProjectRoot(resolve5(cwd, flags.get("--directory") ?? "."));
|
|
1263
|
-
if (!root) throw new Error("\u8BF7\u5728\u642D\u5B50\u5DE5\u7A0B\u4E2D\u8FD0\u884C\uFF0C\u6216\u6307\u5B9A --directory");
|
|
1264
|
-
if (action === "sync") {
|
|
1265
|
-
await syncWidgetDesign(root);
|
|
1266
|
-
io.write("\u5DF2\u540C\u6B65\u5F53\u524D\u9A8C\u6536\u8BBE\u8BA1\u5230 widget-design.lock.json\uFF0C\u5E76\u751F\u6210 widget-implementation.json\uFF1B\u8BF7\u9010\u9879\u586B\u5199\u5B57\u6BB5\u4E0E\u5B9E\u73B0\u8DEF\u5F84\uFF0C\u968F\u540E\u8FD0\u884C widgets check\u3002");
|
|
1267
|
-
return { exitCode: 0 };
|
|
1213
|
+
let directory;
|
|
1214
|
+
let json = false;
|
|
1215
|
+
for (let i = 0; i < args.length; i++) {
|
|
1216
|
+
if (args[i] === "--json" && !json) json = true;
|
|
1217
|
+
else if (args[i] === "--directory" && directory === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) directory = args[++i];
|
|
1218
|
+
else throw new Error(`models \u53C2\u6570\u65E0\u6548\uFF1A${args[i]}
|
|
1219
|
+
${MODELS_COMMAND_HELP}`);
|
|
1268
1220
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1221
|
+
const { root, source } = await runtimeCatalogSource(resolve5(cwd, directory ?? "."), { report: (message) => io.writeError(message), ...options });
|
|
1222
|
+
const catalog = await readRuntimeModelCatalog(root);
|
|
1223
|
+
if (json) io.write(JSON.stringify({ source, ...catalog }, null, 2));
|
|
1224
|
+
else {
|
|
1225
|
+
io.write(`${source === "project" ? "\u5DE5\u7A0B" : "npm \u6700\u65B0"} Runtime ${catalog.runtimeVersion} \u63D0\u4F9B ${catalog.models.length} \u4E2A\u6A21\u578B\uFF1A`);
|
|
1226
|
+
for (const id of catalog.models) io.write(`- ${id}`);
|
|
1227
|
+
io.write("\u5C06\u6240\u9009 ID \u5199\u5165 buddy.agent.json.model\uFF1B\u81EA\u5B9A\u4E49\u4F1A\u8BDD\u5DE5\u5382\u4E5F\u53EF\u6309\u4F1A\u8BDD\u8BBE\u7F6E initialState.model\u3002");
|
|
1273
1228
|
}
|
|
1274
|
-
|
|
1275
|
-
io.write(flags.has("--json") ? JSON.stringify(report, null, 2) : widgetDeliverySummary(report));
|
|
1276
|
-
return { exitCode: report.status === "incomplete" ? 1 : 0 };
|
|
1229
|
+
return { exitCode: 0 };
|
|
1277
1230
|
} catch (cause) {
|
|
1278
1231
|
io.writeError(cause instanceof Error ? cause.message : String(cause));
|
|
1279
|
-
return { exitCode:
|
|
1232
|
+
return { exitCode: 2 };
|
|
1280
1233
|
}
|
|
1281
1234
|
}
|
|
1282
1235
|
|
|
@@ -1284,72 +1237,11 @@ async function runWidgetsCommand(args, io, cwd) {
|
|
|
1284
1237
|
import { lstat as lstat10 } from "node:fs/promises";
|
|
1285
1238
|
|
|
1286
1239
|
// packages/cli-core/src/commands/datasets.ts
|
|
1287
|
-
import { resolve as resolve7 } from "node:path";
|
|
1288
|
-
|
|
1289
|
-
// packages/cli-core/src/config/runtime-catalog.ts
|
|
1290
|
-
import { readFile as readFile4, realpath as realpath3 } from "node:fs/promises";
|
|
1291
|
-
import { createRequire } from "node:module";
|
|
1292
1240
|
import { resolve as resolve6 } from "node:path";
|
|
1293
|
-
import { pathToFileURL } from "node:url";
|
|
1294
|
-
|
|
1295
|
-
// packages/cli-core/src/config/runtime-dependency.ts
|
|
1296
|
-
var BUDDY_RUNTIME_PACKAGE = "@my-life-buddies/buddy-runtime";
|
|
1297
|
-
function runtimeDependencyVersion(pkg) {
|
|
1298
|
-
if (typeof pkg !== "object" || pkg === null || !("dependencies" in pkg)) return void 0;
|
|
1299
|
-
const dependencies2 = pkg.dependencies;
|
|
1300
|
-
if (typeof dependencies2 !== "object" || dependencies2 === null || !(BUDDY_RUNTIME_PACKAGE in dependencies2)) return void 0;
|
|
1301
|
-
const version = dependencies2[BUDDY_RUNTIME_PACKAGE];
|
|
1302
|
-
return typeof version === "string" && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(version) ? version : void 0;
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
// packages/cli-core/src/config/runtime-catalog.ts
|
|
1306
|
-
async function readRuntimeDataCatalog(projectRoot) {
|
|
1307
|
-
const packagePath = resolve6(projectRoot, "package.json");
|
|
1308
|
-
const expected = runtimeDependencyVersion(JSON.parse(await readFile4(packagePath, "utf8")));
|
|
1309
|
-
if (!expected) throw new Error(`package.json \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
|
|
1310
|
-
const projectRequire = createRequire(packagePath);
|
|
1311
|
-
let runtimePath;
|
|
1312
|
-
try {
|
|
1313
|
-
const installedPath = await realpath3(resolve6(projectRoot, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"));
|
|
1314
|
-
if (await realpath3(projectRequire.resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`)) !== installedPath) {
|
|
1315
|
-
throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
|
|
1316
|
-
}
|
|
1317
|
-
const installed = JSON.parse(await readFile4(installedPath, "utf8"));
|
|
1318
|
-
if (installed.version !== expected) throw new Error(`\u5DF2\u5B89\u88C5 ${installed.version}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
|
|
1319
|
-
runtimePath = projectRequire.resolve(BUDDY_RUNTIME_PACKAGE);
|
|
1320
|
-
} catch (cause) {
|
|
1321
|
-
throw new Error(`\u5DE5\u7A0B\u7684 Runtime \u4F9D\u8D56\u672A\u6B63\u786E\u5B89\u88C5\uFF0C\u8BF7\u6309\u9501\u6587\u4EF6\u5B89\u88C5\u4F9D\u8D56\uFF1A${cause instanceof Error ? cause.message : String(cause)}`);
|
|
1322
|
-
}
|
|
1323
|
-
const runtime = await import(pathToFileURL(runtimePath).href);
|
|
1324
|
-
const catalog = runtime.DATA_ACCESS_CAPABILITIES;
|
|
1325
|
-
if (!Array.isArray(catalog)) {
|
|
1326
|
-
throw new Error(`\u5DE5\u7A0B\u7684 Runtime ${expected} \u672A\u5BFC\u51FA DATA_ACCESS_CAPABILITIES\uFF0C\u8BF7\u4F7F\u7528\u5305\u542B\u6570\u636E\u76EE\u5F55\u7684\u65B0 Runtime \u5305\u3002`);
|
|
1327
|
-
}
|
|
1328
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1329
|
-
const datasets = catalog.map((value) => {
|
|
1330
|
-
if (!value || typeof value !== "object") throw new Error("Runtime \u6570\u636E\u76EE\u5F55\u683C\u5F0F\u65E0\u6548");
|
|
1331
|
-
const item = value;
|
|
1332
|
-
if (typeof item.id !== "string" || !item.id.trim() || seen.has(item.id) || typeof item.title !== "string" || !item.title.trim() || typeof item.source !== "string" || !item.source.trim() || !Number.isSafeInteger(item.schemaVersion) || item.schemaVersion < 1) {
|
|
1333
|
-
throw new Error("Runtime \u6570\u636E\u76EE\u5F55\u683C\u5F0F\u65E0\u6548\u6216\u5305\u542B\u91CD\u590D ID");
|
|
1334
|
-
}
|
|
1335
|
-
seen.add(item.id);
|
|
1336
|
-
return Object.freeze({ id: item.id, title: item.title, source: item.source, schemaVersion: item.schemaVersion });
|
|
1337
|
-
});
|
|
1338
|
-
return Object.freeze({ runtimeVersion: expected, datasets: Object.freeze(datasets) });
|
|
1339
|
-
}
|
|
1340
|
-
async function validateRuntimeDatasets(projectRoot, requirements = []) {
|
|
1341
|
-
const catalog = await readRuntimeDataCatalog(projectRoot);
|
|
1342
|
-
const ids = new Set(catalog.datasets.map((item) => item.id));
|
|
1343
|
-
for (const [index, item] of requirements.entries()) {
|
|
1344
|
-
if (!ids.has(item.id)) throw new Error(`/datasets/${index}/id\uFF1A\u5DE5\u7A0B Runtime ${catalog.runtimeVersion} \u4E0D\u652F\u6301 ${item.id}`);
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
// packages/cli-core/src/commands/datasets.ts
|
|
1349
1241
|
var DATASETS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
|
|
1350
|
-
\u8BFB\u53D6\
|
|
1351
|
-
\
|
|
1352
|
-
async function runDatasetsCommand(args, io, cwd) {
|
|
1242
|
+
\u5DE5\u7A0B\u5185\u8BFB\u53D6\u5DF2\u5B89\u88C5 Runtime \u7684 DATA_ACCESS_CAPABILITIES\uFF1B\u5DE5\u7A0B\u5916\u8054\u7F51\u8BFB\u53D6\u5E76\u7F13\u5B58\u516C\u5171 npm \u6700\u65B0 Runtime\u3002
|
|
1243
|
+
\u65E0\u9700\u767B\u5F55\u642D\u642D\u8D26\u53F7\u3002\u5C06\u6240\u9009 id \u4E0E\u7528\u9014 purpose \u5199\u5165 buddy.agent.json.datasets\uFF1B\u76EE\u5F55\u4E0D\u4EE3\u8868\u7528\u6237\u5DF2\u6388\u6743\u3002`;
|
|
1244
|
+
async function runDatasetsCommand(args, io, cwd, options = {}) {
|
|
1353
1245
|
try {
|
|
1354
1246
|
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
1355
1247
|
io.write(DATASETS_COMMAND_HELP);
|
|
@@ -1363,13 +1255,14 @@ async function runDatasetsCommand(args, io, cwd) {
|
|
|
1363
1255
|
else throw new Error(`datasets \u53C2\u6570\u65E0\u6548\uFF1A${args[i]}
|
|
1364
1256
|
${DATASETS_COMMAND_HELP}`);
|
|
1365
1257
|
}
|
|
1366
|
-
const root = await
|
|
1258
|
+
const { root, source } = await runtimeCatalogSource(resolve6(cwd, directory ?? "."), { report: (message) => io.writeError(message), ...options });
|
|
1367
1259
|
const catalog = await readRuntimeDataCatalog(root);
|
|
1368
|
-
if (json) io.write(JSON.stringify(catalog, null, 2));
|
|
1260
|
+
if (json) io.write(JSON.stringify({ source, ...catalog }, null, 2));
|
|
1369
1261
|
else {
|
|
1370
|
-
io.write(
|
|
1262
|
+
io.write(`${source === "project" ? "\u5DE5\u7A0B" : "npm \u6700\u65B0"} Runtime ${catalog.runtimeVersion} \u63D0\u4F9B ${catalog.datasets.length} \u9879\u6570\u636E\u80FD\u529B\uFF1A`);
|
|
1371
1263
|
for (const item of catalog.datasets) io.write(`- ${item.id} \u2014 ${item.title}\uFF08${item.source}\uFF0CSchema ${item.schemaVersion}\uFF09`);
|
|
1372
1264
|
io.write("\u5C06\u6240\u9009 id \u548C purpose \u5199\u5165 buddy.agent.json.datasets\uFF1B\u7528\u6237\u6388\u6743\u7531\u5E73\u53F0\u5904\u7406\u3002");
|
|
1265
|
+
if (source === "project") io.write(`\u66F4\u65B0 CLI \u4E0D\u4F1A\u66F4\u65B0\u5DE5\u7A0B Runtime\u3002\u5982\u9700\u5347\u7EA7\u5230\u516C\u5171 npm \u6700\u65B0\u7248\uFF0C\u5728\u5DE5\u7A0B\u6839\u76EE\u5F55\u8FD0\u884C\uFF1Anpm install --save-exact ${BUDDY_RUNTIME_PACKAGE}@latest --registry=https://registry.npmjs.org/ --@my-life-buddies:registry=https://registry.npmjs.org/`);
|
|
1373
1266
|
}
|
|
1374
1267
|
return { exitCode: 0 };
|
|
1375
1268
|
} catch (cause) {
|
|
@@ -1379,12 +1272,12 @@ ${DATASETS_COMMAND_HELP}`);
|
|
|
1379
1272
|
}
|
|
1380
1273
|
|
|
1381
1274
|
// packages/cli-core/src/index.ts
|
|
1382
|
-
import { join as
|
|
1275
|
+
import { join as join12, resolve as resolve14 } from "node:path";
|
|
1383
1276
|
|
|
1384
1277
|
// packages/cli-core/src/init/creator.ts
|
|
1385
1278
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1386
|
-
import { link as link2, lstat as lstat6, mkdir as mkdir4, readFile as
|
|
1387
|
-
import { join as
|
|
1279
|
+
import { link as link2, lstat as lstat6, mkdir as mkdir4, readFile as readFile6, unlink as unlink3, writeFile as writeFile3 } from "node:fs/promises";
|
|
1280
|
+
import { join as join6 } from "node:path";
|
|
1388
1281
|
import { fileURLToPath } from "node:url";
|
|
1389
1282
|
|
|
1390
1283
|
// packages/cli-core/src/init/development-handoff.ts
|
|
@@ -1394,7 +1287,7 @@ var DEVELOPMENT_HANDOFF = `## \u5F00\u53D1\u5B8C\u6210\u540E\u4EA4\u7ED9\u5F00\u
|
|
|
1394
1287
|
${DEVELOPMENT_HANDOFF_SUMMARY}
|
|
1395
1288
|
|
|
1396
1289
|
1. \u6839\u636E\u5DF2\u786E\u8BA4\u7684\u9700\u6C42\u5B8C\u6210 Agent / Prompt / Tool \u4E0E\u56DE\u5408\u94A9\u5B50\uFF1B\u6709 Booklet \u65F6\u4EE5\u5DF2\u786E\u8BA4\u624B\u518C\u4E3A\u51C6\u3002\u6A21\u677F\u751F\u6210\u4E0D\u7B49\u4E8E\u4E1A\u52A1\u5DF2\u5B9E\u73B0\u3002
|
|
1397
|
-
2. \u6709\
|
|
1290
|
+
2. \u6709 Creator \u5C0F\u6302\u4EF6\u8BBE\u8BA1\u65F6\uFF0C\u6309\u5DF2\u786E\u8BA4\u7684\u9700\u6C42\u3001\u539F\u578B\u548C\u8BBE\u8BA1\u8BF4\u660E\u5B9E\u73B0\u9875\u9762\u3001\u6570\u636E\u7ED3\u6784\u4E0E\u4E1A\u52A1\u4EA4\u4E92\uFF0C\u5E76\u8BF4\u660E\u672A\u5B8C\u6210\u9879\u3002\u505A\u57FA\u7840\u6280\u672F\u81EA\u6D4B\uFF1A\u68C0\u67E5\u914D\u7F6E\u3001\u4F9D\u8D56\u3001\u6784\u5EFA\u548C\u542F\u52A8\u5165\u53E3\uFF0C\u6267\u884C\u5DF2\u6709\u81EA\u52A8\u5316\u6D4B\u8BD5\u53CA\u660E\u786E\u4E1A\u52A1\u89C4\u5219\u3001\u5B89\u5168\u8FB9\u754C\u7684\u57FA\u7840\u6D4B\u8BD5\u3002\u4E0D\u8981\u628A\u6280\u672F\u68C0\u67E5\u901A\u8FC7\u8BF4\u6210\u4EA7\u54C1\u4F53\u9A8C\u5DF2\u9A8C\u6536\u3002
|
|
1398
1291
|
3. \u4F7F\u7528 \`buddy-cli preview\` \u6253\u5F00\u5F53\u524D\u5DE5\u7A0B\uFF0C\u5728\u9875\u9762\u542F\u52A8 DEV\uFF1B\u5DF2\u6709\u53EF\u7528\u9884\u89C8\u5219\u590D\u7528\uFF0C\u4E0D\u540C\u65F6\u518D\u542F\u52A8\u4E00\u5957 \`dev\` \u8FDB\u7A0B\u3002\u786E\u8BA4\u540D\u79F0\u3001DEV \u72B6\u6001\u548C\u79C1\u804A\u6D88\u606F\u5F80\u8FD4\uFF1B\u82E5\u7F3A\u5C11\u5F80\u8FD4\u8BC1\u636E\uFF0C\u53EA\u53D1\u9001\u4E00\u6761\u4E0D\u542B\u4E2A\u4EBA\u654F\u611F\u4FE1\u606F\u7684\u8054\u8C03\u6D88\u606F\uFF0C\u5DF2\u6709\u5F80\u8FD4\u8BC1\u636E\u65F6\u4E0D\u91CD\u590D\u53D1\u9001\u3002\u5931\u8D25\u5148\u5B9A\u4F4D\u6280\u672F\u95EE\u9898\uFF1B\u4ECD\u672A\u89E3\u51B3\u65F6\u8BF4\u660E\u963B\u585E\uFF0C\u4E0D\u628A Mock\u3001\u9875\u9762\u6253\u5F00\u6216\u8FDB\u7A0B\u542F\u52A8\u5F53\u6210\u94FE\u8DEF\u5DF2\u901A\u3002
|
|
1399
1292
|
4. \u53EF\u4F53\u9A8C\u540E\u4FDD\u7559\u9884\u89C8\u548C DEV\uFF0C\u63D0\u4F9B\u5B9E\u9645\u6253\u5F00\u7684\u9875\u9762\u5730\u5740\uFF0C\u544A\u8BC9\u5F00\u53D1\u8005\u201C\u73B0\u5728\u53EF\u4EE5\u5F00\u59CB\u8BD5\u804A\u4E86\u201D\uFF0C\u8BF4\u660E\u5DF2\u9A8C\u8BC1\u8303\u56F4\u548C\u5DF2\u77E5\u9650\u5236\uFF0C\u7136\u540E\u7B49\u5F85\u53CD\u9988\u3002\u4E0B\u4E00\u8F6E\u7531\u5F00\u53D1\u8005\u4F53\u9A8C\u540E\u53CD\u9988\uFF0C\u518D\u6309\u53CD\u9988\u4FEE\u6539\u548C\u9A8C\u8BC1\u3002
|
|
1400
1293
|
|
|
@@ -1462,11 +1355,11 @@ Tool \u548C Hook \u662F Runtime \u7684\u6269\u5C55\u70B9\uFF1BService \u53EA\u66
|
|
|
1462
1355
|
|
|
1463
1356
|
\u5E73\u53F0\u80FD\u529B\u8981\u4EE5\u5B9E\u9645\u63A5\u5165\u4E3A\u51C6\u3002\u5F53\u524D Runtime \u63D0\u4F9B\u4F1A\u8BDD\u6D88\u606F\u3001Memory\u3001\u6388\u6743\u6570\u636E\u3001\u5C0F\u6302\u4EF6\u548C\u672C\u5730 Markdown \u8D44\u6599\u80FD\u529B\uFF1B\u6CA1\u6709\u63A5\u901A\u7684 Files\u3001Knowledge \u4E0D\u80FD\u56E0\u624B\u518C\u63D0\u5230\u5C31\u5BA3\u79F0\u53EF\u7528\u3002\u666E\u901A Tool \u4E5F\u4E0D\u4EE3\u8868\u5DF2\u7ECF\u63D0\u4F9B\u5B9A\u65F6\u3001\u957F\u671F\u4EFB\u52A1\u3001\u540E\u53F0\u8C03\u5EA6\u6216\u4E3B\u52A8\u89E6\u8FBE\u3002\u624B\u518C\u63CF\u8FF0\u7684\u4ED8\u8D39\u3001\u53D1\u5E03\u7B49\u670D\u52A1\u8BBE\u8BA1\u4E5F\u4E0D\u6784\u6210\u6267\u884C\u6536\u8D39\u6216\u53D1\u5E03\u52A8\u4F5C\u7684\u6388\u6743\u3002
|
|
1464
1357
|
|
|
1465
|
-
\u9700\u8981\u7528\u6237\u6570\u636E\u65F6\uFF0C\u5148\u5728\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C \`buddy-cli datasets\`\uFF08\u811A\u672C\u53EF\u7528 \`--json\`\uFF09\uFF0C\u4ECE\u5F53\u524D\u5B89\u88C5\u7684 Runtime \u5BFC\u51FA\u8BFB\u53D6\u5168\u90E8\u6570\u636E\u96C6\uFF1B\u4E0D\u8981\u6C42\u767B\u5F55\uFF0C\u4E0D\u4ECE Server \u62C9\u76EE\u5F55\u3002Runtime 0.12.
|
|
1358
|
+
\u9700\u8981\u7528\u6237\u6570\u636E\u65F6\uFF0C\u5148\u5728\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C \`buddy-cli datasets\`\uFF08\u811A\u672C\u53EF\u7528 \`--json\`\uFF09\uFF0C\u4ECE\u5F53\u524D\u5B89\u88C5\u7684 Runtime \u5BFC\u51FA\u8BFB\u53D6\u5168\u90E8\u6570\u636E\u96C6\uFF1B\u4E0D\u8981\u6C42\u767B\u5F55\uFF0C\u4E0D\u4ECE Server \u62C9\u76EE\u5F55\u3002Runtime 0.12.2 \u542B 10 \u9879\uFF0CCLI \u4E0D\u590D\u5236\u679A\u4E3E\u3002\u628A\u5B9E\u9645\u9700\u8981\u7684 \`id\` \u548C\u7528\u9014 \`purpose\` \u5199\u5165 \`buddy.agent.json.datasets\`\uFF0C\u540C\u4E00 ID \u53EA\u5199\u4E00\u6B21\uFF0C\u7528\u9014\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u6700\u591A 200 \u5B57\uFF1B\u65E0\u9700\u6C42\u65F6\u4FDD\u7559\u7A7A\u6570\u7EC4\u3002DEV \u548C\u58F0\u660E\u975E\u7A7A\u65F6\u7684 push \u9884\u68C0\u7528\u8FD9\u4EFD\u5DE5\u7A0B\u4F9D\u8D56\u6821\u9A8C ID\uFF1B\u9700\u8981\u5148\u5B89\u88C5\u4E0E package.json \u51C6\u786E\u7248\u672C\u4E00\u81F4\u7684 Runtime\u3002\u6E05\u5355\u58F0\u660E\u6570\u91CF\u4E0D\u7B49\u4E8E\u5355\u6B21\u67E5\u8BE2\u4E0A\u9650\uFF0C\u5F53\u524D\u4E00\u6B21\u67E5\u8BE2\u6700\u591A 8 \u9879\u3002
|
|
1466
1359
|
|
|
1467
1360
|
\`start.mjs\` \u5C06\u58F0\u660E\u4EA4\u7ED9 \`StartOptions.dataRequirements\`\u3002Runtime \u5728\u5B9E\u9645\u6570\u636E\u67E5\u8BE2\u3001HealthKit \u6388\u6743\u548C\u4E3B\u52A8\u670D\u52A1\u8BF7\u6C42\u4E2D\u643A\u5E26\u5B8C\u6574\u58F0\u660E\uFF0C\u7531 Server \u6821\u9A8C\u8303\u56F4\u4E0E\u7528\u6237\u540C\u610F\uFF1B\u586B\u5199\u914D\u7F6E\u4E0D\u8868\u793A\u5DF2\u7ECF\u6388\u6743\u3002\u670D\u52A1\u7AEF\u4ECE\u4E0A\u4F20\u5305\u89E3\u6790\u5E76\u7ED1\u5B9A\u53D1\u5E03\u7248\u672C\u4ECD\u5F85\u5B9E\u73B0\u3002
|
|
1468
1361
|
|
|
1469
|
-
\u6A21\u578B\u9700\u8981\u67E5\u6570\u636E\u65F6\uFF0C\u5728 \`src/buddy-options.mjs\` \u7684 \`initialState.tools\` \u4E2D\u52A0\u5165 \`conversation.tools.data_access_query\`\uFF1B\u9700\u8981\u5411\u7528\u6237\u7533\u8BF7\u65F6\u52A0\u5165 \`conversation.tools.data_access_request\`\uFF0C\u4F4D\u7F6E\u3001\u65E5\u5386\u7684\u4E00\u6B21\u6027\u7ED3\u679C\u901A\u8FC7 \`data_access_read_result\` \u8BFB\u53D6\uFF0CHealthKit \u5219\u91CD\u65B0\u67E5\u8BE2 Dataset\u3002\u4E1A\u52A1\u4EE3\u7801\u5BF9\u5E94\u4F7F\u7528 \`conversation.dataAccess.query/request/readResult\`\u3002\u5DE5\u7A0B\
|
|
1362
|
+
\u6A21\u578B\u9700\u8981\u67E5\u6570\u636E\u65F6\uFF0C\u5728 \`src/buddy-options.mjs\` \u7684 \`initialState.tools\` \u4E2D\u52A0\u5165 \`conversation.tools.data_access_query\`\uFF1B\u9700\u8981\u5411\u7528\u6237\u7533\u8BF7\u65F6\u52A0\u5165 \`conversation.tools.data_access_request\`\uFF0C\u4F4D\u7F6E\u3001\u65E5\u5386\u7684\u4E00\u6B21\u6027\u7ED3\u679C\u901A\u8FC7 \`data_access_read_result\` \u8BFB\u53D6\uFF0CHealthKit \u5219\u91CD\u65B0\u67E5\u8BE2 Dataset\u3002\u4E1A\u52A1\u4EE3\u7801\u5BF9\u5E94\u4F7F\u7528 \`conversation.dataAccess.query/request/readResult\`\u3002\u65B0\u5EFA\u5DE5\u7A0B\u52A8\u6001\u9009\u62E9\u516C\u5171 npm latest \u5E76\u9501\u5B9A\u51C6\u786E\u7248\u672C\uFF1B\u8054\u7F51\u5931\u8D25\u65F6\u660E\u786E\u63D0\u793A\u4F7F\u7528\u968F CLI \u9644\u5E26\u7684 Runtime 0.12.2\u3002\u5DF2\u6709\u5DE5\u7A0B\u901A\u8FC7\u5305\u7BA1\u7406\u5668\u663E\u5F0F\u5347\u7EA7\u4F9D\u8D56\u3002
|
|
1470
1363
|
|
|
1471
1364
|
\u5C0F\u6302\u4EF6\u7684\u6A21\u578B\u5DE5\u5177\u4E3A \`widget_create\`\u3001\`widget_read\`\uFF08\u6574\u4E2A\u5C0F\u6302\u4EF6\uFF09\u3001\`widget_read_module\`\uFF08\u4E00\u4E2A\u6A21\u5757\uFF09\u3001\`widget_rename\`\u3001\`widget_write_record\`\u3001\`widget_delete_record\`\u3001\`widget_delete\`\uFF08\u6574\u4E2A\u5C0F\u6302\u4EF6\u8FDE\u8BB0\u5F55\uFF09\u548C \`widget_send\`\uFF0C\u6309\u4E1A\u52A1\u9700\u8981\u6CE8\u518C\u5230 \`initialState.tools\`\u3002\u4FEE\u6539\u8BB0\u5F55\u7528 \`conversation.widget.writeRecord(id, input)\`\uFF1B\u5220\u4E00\u6761\u8BB0\u5F55\u7528 \`conversation.widget.deleteRecord(id, module, recordId)\`\uFF0C\u4E0D\u80FD\u7528\u5220\u9664\u6574\u4E2A\u5C0F\u6302\u4EF6\u7684 \`conversation.widget.delete(id)\` \u4EE3\u66FF\u3002\u4E24\u4E2A\u8BFB\u53D6\u5DE5\u5177\u53EF\u7528\u4E8E\u4E3B\u52A8\u56DE\u5408\uFF0C\u5176\u4F59\u516D\u4E2A\u5199\u5165\u5DE5\u5177\u7531 Runtime \u963B\u6B62\u5728\u4E3B\u52A8\u56DE\u5408\u6267\u884C\u3002
|
|
1472
1365
|
|
|
@@ -1482,17 +1375,13 @@ Tool \u548C Hook \u662F Runtime \u7684\u6269\u5C55\u70B9\uFF1BService \u53EA\u66
|
|
|
1482
1375
|
|
|
1483
1376
|
\u9047\u5230\u771F\u6B63\u7684\u963B\u585E\u5C31\u8BF4\u660E\u5177\u4F53\u7F3A\u53E3\u5E76\u7B49\u5F85\u7B54\u590D\uFF1B\u4E0D\u53D7\u5F71\u54CD\u7684\u5DF2\u6388\u6743\u5DE5\u4F5C\u53EF\u4EE5\u7EE7\u7EED\u3002\u65E0\u6CD5\u5B9E\u73B0\u7684\u8981\u6C42\u5982\u5B9E\u8BF4\u660E\uFF0C\u4E0D\u6697\u4E2D\u5220\u53BB\uFF0C\u4E5F\u4E0D\u4F2A\u9020\u5F00\u53D1\u8005\u540C\u610F\u964D\u7EA7\u3002\u7528\u6237\u53EA\u8981\u8BBE\u8BA1\u3001\u521D\u59CB\u5316\u6216\u5C40\u90E8\u4FEE\u6539\u65F6\u9075\u5B88\u8BE5\u8303\u56F4\uFF0C\u4E0D\u56E0\u624B\u518C\u5B58\u5728\u5C31\u81EA\u52A8\u6269\u5C55\u4EFB\u52A1\u3002
|
|
1484
1377
|
|
|
1485
|
-
### \
|
|
1486
|
-
|
|
1487
|
-
\u6709 Creator \u5C0F\u6302\u4EF6\u8BBE\u8BA1\u65F6\uFF0C\u5728\u5F00\u53D1\u5F00\u59CB\u524D\u6267\u884C \`buddy-cli widgets sync\`\u3002\u5B83\u4ECE\u5F53\u524D\u6709\u6548\u9A8C\u6536\u4EA4\u4ED8\u751F\u6210 \`widget-design.lock.json\` \u548C \`widget-implementation.json\`\uFF1B\u9010\u9879\u4FDD\u7559\u72EC\u7ACB\u7C7B\u578B ID\uFF0C\u4E0D\u5F97\u628A\u591A\u7C7B\u8BBE\u8BA1\u9759\u9ED8\u5408\u5E76\u6210\u4E00\u4E2A\u901A\u7528\u5DE5\u4F5C\u53F0\u3002\u540C\u6B65\u4E0D\u662F\u5B9E\u73B0\u5B8C\u6210\u3002
|
|
1378
|
+
### \u6309\u8BBE\u8BA1\u5F00\u53D1\u5C0F\u6302\u4EF6
|
|
1488
1379
|
|
|
1489
|
-
\
|
|
1380
|
+
\u6709 Creator \u8BBE\u8BA1\u4EA7\u7269\u65F6\uFF0C\u8BFB\u53D6\u5DF2\u786E\u8BA4\u7684\u9700\u6C42\u624B\u518C\u3001\u5C0F\u6302\u4EF6\u6E05\u5355\u3001\u539F\u578B\u548C\u8BBE\u8BA1\u8BF4\u660E\uFF0C\u6309\u7528\u9014\u5B9E\u73B0\u5404\u7C7B\u5C0F\u6302\u4EF6\u3002\u4FDD\u7559\u8BBE\u8BA1\u8981\u6C42\u7684\u5C55\u793A\u5185\u5BB9\u3001\u5E03\u5C40\u3001\u4EA4\u4E92\u548C\u51FA\u73B0\u65F6\u673A\uFF1B\u65E0\u6CD5\u5B8C\u6210\u65F6\u660E\u786E\u8BF4\u660E\u7F3A\u53E3\uFF0C\u4E0D\u9759\u9ED8\u7701\u7565\u6216\u5408\u5E76\u8BBE\u8BA1\u3002
|
|
1490
1381
|
|
|
1491
|
-
\
|
|
1382
|
+
\u5728\u5DE5\u7A0B\u7684 \`widgets/<type-id>/\` \u4E2D\u7F16\u5199 \`index.html\` \u548C \`schema.json\`\uFF0C\u5728\u4E1A\u52A1\u4EE3\u7801\u4E2D\u63A5\u5165\u521B\u5EFA\u3001\u8BFB\u53D6\u3001\u66F4\u65B0\u548C\u53D1\u9001\u80FD\u529B\u3002\u5F00\u53D1\u8005\u5728 \`buddy-cli preview\` \u4E2D\u67E5\u770B\u771F\u5B9E\u9875\u9762\u548C\u4EA4\u4E92\u6548\u679C\uFF0C\u4FEE\u6539\u540E\u91CD\u542F DEV\u3002\u51C6\u5907\u4E0A\u4F20\u65F6\u4F7F\u7528 \`buddy-cli push\`\uFF0C\u9875\u9762\u548C\u6570\u636E\u5B9A\u4E49\u968F\u5DE5\u7A0B\u6253\u5305\u3002
|
|
1492
1383
|
|
|
1493
|
-
\
|
|
1494
|
-
|
|
1495
|
-
\u6240\u6709\u7C7B\u578B\u7ED3\u6784\u548C\u6838\u5BF9\u8BB0\u5F55\u9F50\u5168\u540E\u624D\u79F0\u201C\u5C0F\u6302\u4EF6\u5F00\u53D1\u6838\u5BF9\u5B8C\u6210\u201D\u3002\u4EE3\u7801\u3001\u9875\u9762\u3001\u4F9D\u8D56\u3001\u6570\u636E\u7ED1\u5B9A\u6216\u8BBE\u8BA1\u7248\u672C\u53D8\u5316\u4F1A\u8BA9\u65E7\u8BB0\u5F55\u5931\u6548\uFF0C\u5E94\u9488\u5BF9\u53D8\u5316\u91CD\u65B0\u6838\u5BF9\u3002\u6CA1\u6709\u5B8C\u6210\u5C31\u660E\u786E\u5217\u51FA\u7F3A\u9879\u3002push \u4F1A\u5728\u4E0A\u4F20\u524D\u62E6\u622A\u4E0D\u5B8C\u6574\u4EA4\u4ED8\uFF0C\u4F46\u4E0D\u4F1A\u66FF\u5F00\u53D1\u8005\u53D1\u8D77\u63D0\u5BA1\u3002\u76F4\u63A5\u5F00\u53D1\u4E14\u65E0 Creator \u8BBE\u8BA1\u7684\u9879\u76EE\u6CBF\u7528\u539F\u6D41\u7A0B\uFF0C\u68C0\u67E5\u7ED3\u679C\u660E\u786E\u4E3A\u201C\u672A\u914D\u7F6E\u8BBE\u8BA1\u6838\u5BF9\u201D\uFF0C\u4E0D\u5192\u5145\u901A\u8FC7\u3002
|
|
1384
|
+
\u6309\u9700\u6C42\u5B8C\u6210\u57FA\u7840\u6280\u672F\u81EA\u6D4B\uFF0C\u5411\u5F00\u53D1\u8005\u8BF4\u660E\u5DF2\u5B9E\u73B0\u5185\u5BB9\u548C\u4ECD\u5B58\u5728\u7684\u95EE\u9898\uFF0C\u518D\u4EA4\u7ED9\u5F00\u53D1\u8005\u4F53\u9A8C\u3002\u8BBE\u8BA1\u8BF4\u660E\u4F5C\u4E3A\u5F00\u53D1\u53C2\u8003\uFF0CCLI \u4E0D\u8981\u6C42\u989D\u5916\u586B\u5199\u8BBE\u8BA1\u6620\u5C04\u6216\u63D0\u4EA4\u9884\u89C8\u6838\u5BF9\u8BB0\u5F55\u3002
|
|
1496
1385
|
|
|
1497
1386
|
### \u6838\u5BF9\u5B9E\u73B0\uFF0C\u518D\u4EA4\u7ED9\u5F00\u53D1\u8005\u4F53\u9A8C
|
|
1498
1387
|
|
|
@@ -1563,11 +1452,11 @@ async function safeRead(path) {
|
|
|
1563
1452
|
if (!entry.isFile() || entry.size > MAX_LOCAL_FILE_BYTES) {
|
|
1564
1453
|
throw new CreatorPreparationError(`\u521B\u4F5C\u6587\u4EF6\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u6216\u8D85\u51FA\u5927\u5C0F\u9650\u5236\uFF1A${path}`);
|
|
1565
1454
|
}
|
|
1566
|
-
return
|
|
1455
|
+
return readFile6(path);
|
|
1567
1456
|
}
|
|
1568
1457
|
async function writeOnce(path, bytes) {
|
|
1569
1458
|
const temporary = `${path}.${randomUUID2()}.tmp`;
|
|
1570
|
-
await
|
|
1459
|
+
await writeFile3(temporary, bytes, { flag: "wx", mode: 384 });
|
|
1571
1460
|
try {
|
|
1572
1461
|
await link2(temporary, path).catch((cause) => {
|
|
1573
1462
|
if (cause.code !== "EEXIST") throw cause;
|
|
@@ -1578,17 +1467,17 @@ async function writeOnce(path, bytes) {
|
|
|
1578
1467
|
}
|
|
1579
1468
|
async function bundledSkill(root) {
|
|
1580
1469
|
for (const path of REQUIRED) {
|
|
1581
|
-
if (!(await state(
|
|
1470
|
+
if (!(await state(join6(root, path)))?.isFile()) {
|
|
1582
1471
|
throw new CreatorPreparationError(`CLI \u5185\u7F6E Creator Skill \u4E0D\u5B8C\u6574\uFF0C\u8BF7\u91CD\u65B0\u5B89\u88C5 CLI\uFF08\u7F3A\u5C11 ${path}\uFF09\u3002\u4E0D\u4F1A\u5C1D\u8BD5\u5728\u7EBF\u4E0B\u8F7D\u6216\u8986\u76D6\u9879\u76EE\u8D44\u6599\u3002`);
|
|
1583
1472
|
}
|
|
1584
1473
|
}
|
|
1585
1474
|
return root;
|
|
1586
1475
|
}
|
|
1587
1476
|
function handoffMarkdown(context, skillRoot, session, workspacePath) {
|
|
1588
|
-
const contextPath =
|
|
1477
|
+
const contextPath = join6(context.projectRoot, ".buddy", "creator", "initial-context.json");
|
|
1589
1478
|
const openArgs = [
|
|
1590
1479
|
"-B",
|
|
1591
|
-
|
|
1480
|
+
join6(skillRoot, "scripts/buddy.py"),
|
|
1592
1481
|
"open",
|
|
1593
1482
|
"--workspace",
|
|
1594
1483
|
workspacePath,
|
|
@@ -1618,7 +1507,7 @@ function handoffMarkdown(context, skillRoot, session, workspacePath) {
|
|
|
1618
1507
|
|
|
1619
1508
|
## \u73B0\u5728\u7531 Coding Agent \u6267\u884C
|
|
1620
1509
|
|
|
1621
|
-
1. \u5B8C\u6574\u8BFB\u53D6 ${JSON.stringify(
|
|
1510
|
+
1. \u5B8C\u6574\u8BFB\u53D6 ${JSON.stringify(join6(skillRoot, "SKILL.md"))} \u53CA\u5176\u6307\u5B9A\u7684 references\u3002\u4FDD\u7559\u539F\u6709\u56DB\u9636\u6BB5\u89C4\u5219\uFF0C\u7531\u5F53\u524D\u4E3B\u5BF9\u8BDD\u5B8C\u6210\u91C7\u8BBF\uFF1B\u65E0\u9700\u53E6\u8D77 Sub-agent \u6216\u8FD0\u884C\u91C7\u8BBF\u6A21\u578B\u670D\u52A1\u3002
|
|
1622
1511
|
2. \u67E5\u627E\u5BBF\u4E3B\u6216\u7CFB\u7EDF\u5B9E\u9645\u53EF\u7528\u7684 Python 3.9+\uFF0C\u68C0\u67E5\u7248\u672C\uFF0C\u4FDD\u5B58\u5176\u7EDD\u5BF9\u8DEF\u5F84\u3002\u4E0D\u8981\u5199\u6B7B\u672C\u673A\u8DEF\u5F84\uFF0C\u4E0D\u5B89\u88C5 pip/npm \u4F9D\u8D56\u3002\u6CA1\u6709 Python \u65F6\u62A5\u544A\u7F3A\u53E3\uFF0C\u4FDD\u7559\u672C\u5730\u9879\u76EE\u3002\u6240\u6709 Python \u8C03\u7528\u5747\u52A0 -B\uFF0C\u5E76\u8BBE\u7F6E\u8FDB\u7A0B\u73AF\u5883\u53D8\u91CF PYTHONDONTWRITEBYTECODE=1\uFF08\u7531\u9884\u89C8\u5B50\u8FDB\u7A0B\u7EE7\u627F\uFF09\uFF0C\u907F\u514D\u5411 CLI \u5B89\u88C5\u76EE\u5F55\u5199\u5165\u5B57\u8282\u7801\u7F13\u5B58\u3002
|
|
1623
1512
|
3. \u4F7F\u7528\u5DE5\u5177\u4F20\u9012\u72EC\u7ACB\u53C2\u6570\uFF0C\u4E0D\u62FC\u63A5 shell \u5B57\u7B26\u4E32\u3002\u5DE5\u4F5C\u76EE\u5F55\u4E3A ${JSON.stringify(context.projectRoot)}\uFF1B\u4EE5\u5B9E\u9645 Python \u8DEF\u5F84\u4E3A executable\uFF0C\u9996\u6B21\u6253\u5F00\u7684 argv \u5982\u4E0B\uFF1A
|
|
1624
1513
|
|
|
@@ -1655,11 +1544,11 @@ ${DEVELOPMENT_HANDOFF}
|
|
|
1655
1544
|
`;
|
|
1656
1545
|
}
|
|
1657
1546
|
async function prepareCreatorSkill(context, io, options = {}) {
|
|
1658
|
-
const root =
|
|
1547
|
+
const root = join6(context.projectRoot, ".buddy", "creator");
|
|
1659
1548
|
try {
|
|
1660
|
-
await safeDirectory(
|
|
1549
|
+
await safeDirectory(join6(context.projectRoot, ".buddy"));
|
|
1661
1550
|
await safeDirectory(root);
|
|
1662
|
-
const sessionPath =
|
|
1551
|
+
const sessionPath = join6(root, "session.json");
|
|
1663
1552
|
await writeOnce(sessionPath, JSON.stringify({
|
|
1664
1553
|
schemaVersion: 1,
|
|
1665
1554
|
platformBuddyId: context.buddyId,
|
|
@@ -1671,11 +1560,11 @@ async function prepareCreatorSkill(context, io, options = {}) {
|
|
|
1671
1560
|
}
|
|
1672
1561
|
options.signal?.throwIfAborted();
|
|
1673
1562
|
const skillRoot = await bundledSkill(options.bundledSkillRoot ?? BUNDLED_CREATOR_SKILL_ROOT);
|
|
1674
|
-
await safeDirectory(
|
|
1675
|
-
const workspacePath =
|
|
1563
|
+
await safeDirectory(join6(root, "workspaces"));
|
|
1564
|
+
const workspacePath = join6(root, "workspaces", session.creationKey);
|
|
1676
1565
|
const workspace = await state(workspacePath);
|
|
1677
1566
|
if (workspace && !workspace.isDirectory()) throw new CreatorPreparationError("\u5DF2\u6709\u521B\u4F5C\u5DE5\u4F5C\u533A\u4E0D\u662F\u666E\u901A\u76EE\u5F55\u3002");
|
|
1678
|
-
const contextPath =
|
|
1567
|
+
const contextPath = join6(root, "initial-context.json");
|
|
1679
1568
|
await writeOnce(contextPath, JSON.stringify({
|
|
1680
1569
|
source: "platform_meta",
|
|
1681
1570
|
name: context.appName,
|
|
@@ -1691,7 +1580,7 @@ async function prepareCreatorSkill(context, io, options = {}) {
|
|
|
1691
1580
|
} catch {
|
|
1692
1581
|
throw new CreatorPreparationError(`\u5DF2\u6709\u521D\u59CB\u80CC\u666F\u65E0\u6548\uFF0C\u5DF2\u4FDD\u7559\u539F\u6587\u4EF6\uFF0C\u8BF7\u68C0\u67E5\uFF1A${contextPath}`);
|
|
1693
1582
|
}
|
|
1694
|
-
const handoffPath =
|
|
1583
|
+
const handoffPath = join6(root, "HANDOFF.md");
|
|
1695
1584
|
const handoff = handoffMarkdown({
|
|
1696
1585
|
...context,
|
|
1697
1586
|
appName: initial.name,
|
|
@@ -1702,11 +1591,11 @@ async function prepareCreatorSkill(context, io, options = {}) {
|
|
|
1702
1591
|
if ((await safeRead(handoffPath))?.toString("utf8") !== handoff) {
|
|
1703
1592
|
throw new CreatorPreparationError(`\u5DF2\u6709\u63A5\u7EED\u8BF4\u660E\u88AB\u4FEE\u6539\u6216\u9879\u76EE\u8DEF\u5F84\u5DF2\u53D8\u5316\uFF0C\u5DF2\u4FDD\u7559\u539F\u6587\u4EF6\u3002\u8BF7\u5907\u4EFD\u79FB\u8D70\u8BE5\u8BF4\u660E\u540E\u91CD\u8BD5\uFF1A${handoffPath}`);
|
|
1704
1593
|
}
|
|
1705
|
-
io.write(`\u4F7F\u7528 CLI \u5185\u7F6E Creator Skill\uFF0C\u65E0\u9700\u989D\u5916\u4E0B\u8F7D\uFF1A${
|
|
1594
|
+
io.write(`\u4F7F\u7528 CLI \u5185\u7F6E Creator Skill\uFF0C\u65E0\u9700\u989D\u5916\u4E0B\u8F7D\uFF1A${join6(skillRoot, "SKILL.md")}`);
|
|
1706
1595
|
io.write(`\u4E0B\u4E00\u6B65\u4EA4\u7ED9 Codex / Claude Code \u7B49 Coding Agent\uFF1A\u8BF7\u8BFB\u53D6 ${JSON.stringify(handoffPath)}\uFF0C\u6309\u5F53\u524D\u9636\u6BB5\u63A5\u7EED\uFF1BCreator \u5B8C\u6210\u540E\u8FD4\u56DE CLI \u5F00\u53D1\u6D41\u7A0B\u3002`);
|
|
1707
1596
|
io.write(DEVELOPMENT_HANDOFF_SUMMARY);
|
|
1708
1597
|
io.write("\u672C\u547D\u4EE4\u53EA\u8D1F\u8D23\u8EAB\u4EFD\u767B\u8BB0\u548C Skill \u51C6\u5907\uFF0C\u4E0D\u4EE3\u8868\u91C7\u8BBF\u3001Booklet \u6216 Agent \u5DF2\u5B8C\u6210\u3002\u8BF7\u6309\u5DF2\u6709\u4F5C\u54C1\u8FDB\u5EA6\u63A5\u7EED\uFF0C\u56DB\u518C\u53CA\u5C0F\u6302\u4EF6\u8BBE\u8BA1\u9A8C\u6536\u3001\u4EA4\u4ED8\u6821\u9A8C\u5B8C\u6210\u540E\u81EA\u52A8\u8FDB\u5165\u5B98\u65B9 Runtime \u5F00\u53D1\uFF1B\u91CD\u590D create \u4F1A\u590D\u7528\u540C\u4E00\u4F5C\u54C1\u3002");
|
|
1709
|
-
return { exitCode: 0, creator: { skillPath:
|
|
1598
|
+
return { exitCode: 0, creator: { skillPath: join6(skillRoot, "SKILL.md"), handoffPath, workspacePath } };
|
|
1710
1599
|
} catch (cause) {
|
|
1711
1600
|
const message = cause instanceof CreatorPreparationError ? cause.message : "\u5185\u7F6E\u8D44\u6E90\u8BFB\u53D6\u6216\u672C\u5730\u5199\u5165\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 CLI \u5B89\u88C5\u548C\u76EE\u5F55\u6743\u9650\u3002";
|
|
1712
1601
|
io.writeError(`Creator Skill \u51C6\u5907\u5931\u8D25\uFF1A${message}`);
|
|
@@ -1766,7 +1655,7 @@ function validateBuddyMetaUpdate(meta2) {
|
|
|
1766
1655
|
}
|
|
1767
1656
|
|
|
1768
1657
|
// packages/cli-core/src/commands/dev.ts
|
|
1769
|
-
import { resolve as
|
|
1658
|
+
import { resolve as resolve10 } from "node:path";
|
|
1770
1659
|
|
|
1771
1660
|
// packages/cli-core/src/platform-url.ts
|
|
1772
1661
|
var DEFAULT_MLB_TEST_URL = "http://47.116.168.81:8788";
|
|
@@ -1827,7 +1716,7 @@ function safeCredential(value, name) {
|
|
|
1827
1716
|
function endpoint(baseUrl, path) {
|
|
1828
1717
|
return new URL(path.replace(/^\//u, ""), baseUrl);
|
|
1829
1718
|
}
|
|
1830
|
-
function
|
|
1719
|
+
function object(value) {
|
|
1831
1720
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1832
1721
|
}
|
|
1833
1722
|
async function responseJson(response) {
|
|
@@ -1869,7 +1758,7 @@ async function responseJson(response) {
|
|
|
1869
1758
|
}
|
|
1870
1759
|
}
|
|
1871
1760
|
function safeServerError(value, fallback) {
|
|
1872
|
-
const candidate =
|
|
1761
|
+
const candidate = object(value)?.error;
|
|
1873
1762
|
if (typeof candidate !== "string" || !candidate.trim()) return fallback;
|
|
1874
1763
|
return candidate.slice(0, 1024).replace(/[\u0000-\u001f\u007f]/gu, " ");
|
|
1875
1764
|
}
|
|
@@ -1950,7 +1839,7 @@ var MlbDevRegistrationClient = class {
|
|
|
1950
1839
|
message: "buddy.agent.json \u4E2D\u7684 buddyId \u65E0\u6548\u3002"
|
|
1951
1840
|
});
|
|
1952
1841
|
}
|
|
1953
|
-
const body =
|
|
1842
|
+
const body = object(await this.#request(
|
|
1954
1843
|
`/cli/buddies/${encodeURIComponent(request.devAgentId)}`,
|
|
1955
1844
|
{
|
|
1956
1845
|
method: "GET",
|
|
@@ -1971,7 +1860,7 @@ var MlbDevRegistrationClient = class {
|
|
|
1971
1860
|
});
|
|
1972
1861
|
}
|
|
1973
1862
|
async listOnline(options) {
|
|
1974
|
-
const body =
|
|
1863
|
+
const body = object(await this.#request("/cli/fleet", {
|
|
1975
1864
|
method: "GET",
|
|
1976
1865
|
signal: options.signal
|
|
1977
1866
|
}));
|
|
@@ -2063,16 +1952,16 @@ function buildAgentEnvironment(options) {
|
|
|
2063
1952
|
}
|
|
2064
1953
|
|
|
2065
1954
|
// packages/cli-core/src/dev/orchestrator.ts
|
|
2066
|
-
import { createHash as
|
|
2067
|
-
import { readFile as
|
|
2068
|
-
import { join as
|
|
1955
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
1956
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
1957
|
+
import { join as join8, resolve as resolve8 } from "node:path";
|
|
2069
1958
|
|
|
2070
1959
|
// packages/cli-core/src/dev/launch.ts
|
|
2071
1960
|
import { lstatSync, readFileSync } from "node:fs";
|
|
2072
1961
|
import { createRequire as createRequire2 } from "node:module";
|
|
2073
|
-
import { dirname as dirname2, resolve as
|
|
1962
|
+
import { dirname as dirname2, resolve as resolve7 } from "node:path";
|
|
2074
1963
|
async function officialAgentLaunchPlan(input) {
|
|
2075
|
-
const entry =
|
|
1964
|
+
const entry = resolve7(input.projectRoot, BUDDY_PLATFORM_START_ENTRY);
|
|
2076
1965
|
for (const [filename, kind] of [
|
|
2077
1966
|
[dirname2(BUDDY_PLATFORM_FACTORY_ENTRY), "directory"],
|
|
2078
1967
|
[BUDDY_PLATFORM_START_ENTRY, "file"],
|
|
@@ -2080,7 +1969,7 @@ async function officialAgentLaunchPlan(input) {
|
|
|
2080
1969
|
[BUDDY_PLATFORM_PACKAGE_JSON, "file"]
|
|
2081
1970
|
]) {
|
|
2082
1971
|
try {
|
|
2083
|
-
const entry2 = lstatSync(
|
|
1972
|
+
const entry2 = lstatSync(resolve7(input.projectRoot, filename));
|
|
2084
1973
|
if (!(kind === "directory" ? entry2.isDirectory() : entry2.isFile())) {
|
|
2085
1974
|
throw new Error(`${filename} must be a regular ${kind}`);
|
|
2086
1975
|
}
|
|
@@ -2093,7 +1982,7 @@ async function officialAgentLaunchPlan(input) {
|
|
|
2093
1982
|
});
|
|
2094
1983
|
}
|
|
2095
1984
|
}
|
|
2096
|
-
const packagePath =
|
|
1985
|
+
const packagePath = resolve7(input.projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
|
|
2097
1986
|
try {
|
|
2098
1987
|
const expected = runtimeDependencyVersion(JSON.parse(readFileSync(packagePath, "utf8")));
|
|
2099
1988
|
if (!expected) throw new Error(`package.json \u7684 dependencies \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
|
|
@@ -2101,6 +1990,7 @@ async function officialAgentLaunchPlan(input) {
|
|
|
2101
1990
|
const installed = JSON.parse(readFileSync(runtimePath, "utf8")).version;
|
|
2102
1991
|
if (installed !== expected) throw new Error(`Runtime \u5DF2\u5B89\u88C5 ${installed}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
|
|
2103
1992
|
await validateRuntimeDatasets(input.projectRoot, input.datasets);
|
|
1993
|
+
await validateRuntimeModel(input.projectRoot, input.model);
|
|
2104
1994
|
} catch (cause) {
|
|
2105
1995
|
throw new BuddyDevError({
|
|
2106
1996
|
code: "DEV_CONFIG_INVALID",
|
|
@@ -2143,16 +2033,16 @@ var NodeAgentProcessLauncher = class {
|
|
|
2143
2033
|
}
|
|
2144
2034
|
let hasExited = false;
|
|
2145
2035
|
let spawned = false;
|
|
2146
|
-
const exit = new Promise((
|
|
2036
|
+
const exit = new Promise((resolve15) => {
|
|
2147
2037
|
child.once("error", (error2) => {
|
|
2148
2038
|
if (!spawned) {
|
|
2149
2039
|
hasExited = true;
|
|
2150
|
-
|
|
2040
|
+
resolve15({ code: null, signal: null, error: error2 });
|
|
2151
2041
|
}
|
|
2152
2042
|
});
|
|
2153
2043
|
child.once("exit", (code2, signal) => {
|
|
2154
2044
|
hasExited = true;
|
|
2155
|
-
|
|
2045
|
+
resolve15({ code: code2, signal });
|
|
2156
2046
|
});
|
|
2157
2047
|
});
|
|
2158
2048
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -2168,11 +2058,11 @@ var NodeAgentProcessLauncher = class {
|
|
|
2168
2058
|
}
|
|
2169
2059
|
});
|
|
2170
2060
|
try {
|
|
2171
|
-
await new Promise((
|
|
2061
|
+
await new Promise((resolve15, reject) => {
|
|
2172
2062
|
const onSpawn = () => {
|
|
2173
2063
|
spawned = true;
|
|
2174
2064
|
child.off("error", onError);
|
|
2175
|
-
|
|
2065
|
+
resolve15();
|
|
2176
2066
|
};
|
|
2177
2067
|
const onError = (error2) => {
|
|
2178
2068
|
child.off("spawn", onSpawn);
|
|
@@ -2211,11 +2101,11 @@ var NodeAgentProcessLauncher = class {
|
|
|
2211
2101
|
};
|
|
2212
2102
|
function waitForExit(process2, timeoutMs) {
|
|
2213
2103
|
if (process2.hasExited()) return Promise.resolve(true);
|
|
2214
|
-
return new Promise((
|
|
2215
|
-
const timeout = setTimeout(() =>
|
|
2104
|
+
return new Promise((resolve15) => {
|
|
2105
|
+
const timeout = setTimeout(() => resolve15(false), timeoutMs);
|
|
2216
2106
|
process2.exit.then(() => {
|
|
2217
2107
|
clearTimeout(timeout);
|
|
2218
|
-
|
|
2108
|
+
resolve15(true);
|
|
2219
2109
|
});
|
|
2220
2110
|
});
|
|
2221
2111
|
}
|
|
@@ -2298,7 +2188,7 @@ async function waitForGroupExit(pid, isGroupAlive, timeoutMs) {
|
|
|
2298
2188
|
while (isGroupAlive(pid)) {
|
|
2299
2189
|
const remaining = deadline - Date.now();
|
|
2300
2190
|
if (remaining <= 0) return false;
|
|
2301
|
-
await new Promise((
|
|
2191
|
+
await new Promise((resolve15) => setTimeout(resolve15, Math.min(25, remaining)));
|
|
2302
2192
|
}
|
|
2303
2193
|
return true;
|
|
2304
2194
|
}
|
|
@@ -2312,10 +2202,10 @@ function processTreeControllerFor(platform) {
|
|
|
2312
2202
|
}
|
|
2313
2203
|
|
|
2314
2204
|
// packages/cli-core/src/dev/instance-lock.ts
|
|
2315
|
-
import { createHash
|
|
2316
|
-
import { mkdir as mkdir5, readFile as
|
|
2317
|
-
import { homedir } from "node:os";
|
|
2318
|
-
import { join as
|
|
2205
|
+
import { createHash, randomUUID as randomUUID3 } from "node:crypto";
|
|
2206
|
+
import { mkdir as mkdir5, readFile as readFile7, readdir as readdir2, rename as rename3, rmdir as rmdir2, unlink as unlink4, writeFile as writeFile4 } from "node:fs/promises";
|
|
2207
|
+
import { homedir as homedir2 } from "node:os";
|
|
2208
|
+
import { join as join7 } from "node:path";
|
|
2319
2209
|
function alreadyRunningError() {
|
|
2320
2210
|
const message = "\u8FD9\u4E2A\u642D\u5B50\u5DF2\u6709 DEV \u5B9E\u4F8B\u5728\u8FD0\u884C\u3002\u8BF7\u5148\u5728\u539F\u9884\u89C8\u9875\u70B9\u51FB\u300C\u505C\u6B62 DEV\u300D\uFF0C\u6216\u5728\u8FD0\u884C dev \u7684\u7EC8\u7AEF\u6309 Ctrl+C\uFF0C\u518D\u542F\u52A8\u3002";
|
|
2321
2211
|
return Object.assign(new BuddyDevError({ code: "DEV_ALREADY_RUNNING", phase: "launch", message }), { publicMessage: message });
|
|
@@ -2335,16 +2225,16 @@ function code(error2) {
|
|
|
2335
2225
|
return error2?.code;
|
|
2336
2226
|
}
|
|
2337
2227
|
async function acquireDevInstanceLock(options) {
|
|
2338
|
-
const root = options.directory ??
|
|
2339
|
-
const key =
|
|
2228
|
+
const root = options.directory ?? join7(homedir2(), ".buddy", "dev-locks");
|
|
2229
|
+
const key = createHash("sha256").update(`${new URL(options.gatewayUrl).origin}
|
|
2340
2230
|
${options.devAgentId}`).digest("hex");
|
|
2341
|
-
const path =
|
|
2231
|
+
const path = join7(root, key);
|
|
2342
2232
|
const ownerName = `owner-${randomUUID3()}.json`;
|
|
2343
|
-
const candidate =
|
|
2233
|
+
const candidate = join7(root, `.pending-${randomUUID3()}`);
|
|
2344
2234
|
const owner = { pid: process.pid };
|
|
2345
2235
|
await mkdir5(root, { recursive: true, mode: 448 });
|
|
2346
2236
|
await mkdir5(candidate, { mode: 448 });
|
|
2347
|
-
await
|
|
2237
|
+
await writeFile4(join7(candidate, ownerName), JSON.stringify(owner), { mode: 384, flag: "wx" });
|
|
2348
2238
|
try {
|
|
2349
2239
|
for (let attempt = 0; ; attempt++) {
|
|
2350
2240
|
try {
|
|
@@ -2356,17 +2246,17 @@ ${options.devAgentId}`).digest("hex");
|
|
|
2356
2246
|
}
|
|
2357
2247
|
let names;
|
|
2358
2248
|
try {
|
|
2359
|
-
names = await
|
|
2249
|
+
names = await readdir2(path);
|
|
2360
2250
|
} catch (error2) {
|
|
2361
2251
|
if (code(error2) === "ENOENT") continue;
|
|
2362
2252
|
throw error2;
|
|
2363
2253
|
}
|
|
2364
2254
|
if (names.length === 0) continue;
|
|
2365
2255
|
if (names.length !== 1 || !/^owner-[a-f0-9-]+\.json$/u.test(names[0])) throw alreadyRunningError();
|
|
2366
|
-
const previousPath =
|
|
2256
|
+
const previousPath = join7(path, names[0]);
|
|
2367
2257
|
let previous;
|
|
2368
2258
|
try {
|
|
2369
|
-
previous = JSON.parse(await
|
|
2259
|
+
previous = JSON.parse(await readFile7(previousPath, "utf8"));
|
|
2370
2260
|
} catch (error2) {
|
|
2371
2261
|
if (code(error2) === "ENOENT") continue;
|
|
2372
2262
|
throw alreadyRunningError();
|
|
@@ -2383,17 +2273,17 @@ ${options.devAgentId}`).digest("hex");
|
|
|
2383
2273
|
});
|
|
2384
2274
|
}
|
|
2385
2275
|
} finally {
|
|
2386
|
-
await unlink4(
|
|
2276
|
+
await unlink4(join7(candidate, ownerName)).catch(() => void 0);
|
|
2387
2277
|
await rmdir2(candidate).catch(() => void 0);
|
|
2388
2278
|
}
|
|
2389
2279
|
let released = false;
|
|
2390
2280
|
return {
|
|
2391
2281
|
async attachRuntime(pid) {
|
|
2392
2282
|
if (!validPid(pid)) throw new TypeError("Runtime PID is invalid");
|
|
2393
|
-
const temporary =
|
|
2283
|
+
const temporary = join7(root, `.update-${randomUUID3()}`);
|
|
2394
2284
|
try {
|
|
2395
|
-
await
|
|
2396
|
-
await rename3(temporary,
|
|
2285
|
+
await writeFile4(temporary, JSON.stringify({ ...owner, runtimePid: pid }), { mode: 384, flag: "wx" });
|
|
2286
|
+
await rename3(temporary, join7(path, ownerName));
|
|
2397
2287
|
} finally {
|
|
2398
2288
|
await unlink4(temporary).catch(() => void 0);
|
|
2399
2289
|
}
|
|
@@ -2401,7 +2291,7 @@ ${options.devAgentId}`).digest("hex");
|
|
|
2401
2291
|
async release() {
|
|
2402
2292
|
if (released) return;
|
|
2403
2293
|
released = true;
|
|
2404
|
-
await unlink4(
|
|
2294
|
+
await unlink4(join7(path, ownerName)).catch((error2) => {
|
|
2405
2295
|
if (code(error2) !== "ENOENT") throw error2;
|
|
2406
2296
|
});
|
|
2407
2297
|
await rmdir2(path).catch((error2) => {
|
|
@@ -2454,6 +2344,7 @@ function validateLaunchPlan(value) {
|
|
|
2454
2344
|
async function launchPlanFor(config, options, projectRoot, signal) {
|
|
2455
2345
|
const provider = options.platformLaunchPlan ?? ((context) => officialAgentLaunchPlan({
|
|
2456
2346
|
datasets: config.datasets,
|
|
2347
|
+
model: config.model,
|
|
2457
2348
|
projectRoot: context.projectRoot
|
|
2458
2349
|
}));
|
|
2459
2350
|
try {
|
|
@@ -2644,7 +2535,7 @@ async function startBuddyDev(options) {
|
|
|
2644
2535
|
const pollIntervalMs = positiveDuration(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS, "pollIntervalMs");
|
|
2645
2536
|
const stopGracePeriodMs = positiveDuration(options.stopGracePeriodMs ?? DEFAULT_STOP_GRACE_PERIOD_MS, "stopGracePeriodMs");
|
|
2646
2537
|
const devAgentId = safeDevAgentId(options.devAgentId);
|
|
2647
|
-
const projectRoot =
|
|
2538
|
+
const projectRoot = resolve8(options.projectRoot);
|
|
2648
2539
|
const lifecycle = new AbortController();
|
|
2649
2540
|
const signal = options.signal === void 0 ? lifecycle.signal : AbortSignal.any([lifecycle.signal, options.signal]);
|
|
2650
2541
|
let agentProcess;
|
|
@@ -2662,7 +2553,7 @@ async function startBuddyDev(options) {
|
|
|
2662
2553
|
let config;
|
|
2663
2554
|
let configSource;
|
|
2664
2555
|
try {
|
|
2665
|
-
configSource = await
|
|
2556
|
+
configSource = await readFile8(join8(projectRoot, BUDDY_AGENT_FILENAME), "utf8");
|
|
2666
2557
|
config = combineBuddyProject(parseBuddyAgentConfig(configSource));
|
|
2667
2558
|
} catch (cause) {
|
|
2668
2559
|
throw new BuddyDevError({
|
|
@@ -2672,14 +2563,12 @@ async function startBuddyDev(options) {
|
|
|
2672
2563
|
cause
|
|
2673
2564
|
});
|
|
2674
2565
|
}
|
|
2675
|
-
const widgetDelivery = await checkWidgetDelivery(projectRoot);
|
|
2676
|
-
if (widgetDelivery.status === "incomplete") options.onLog?.({ source: "agent.stderr", text: widgetDeliverySummary(widgetDelivery) + "\nDEV \u5141\u8BB8\u7EE7\u7EED\u8C03\u8BD5\uFF0C\u63D0\u5BA1\u524D\u987B\u8865\u9F50\u3002\n" });
|
|
2677
2566
|
const launchPlan = await launchPlanFor(config, options, projectRoot, signal);
|
|
2678
2567
|
const registration = await registerDevAgent({
|
|
2679
2568
|
client: options.registrationClient,
|
|
2680
2569
|
devAgentId,
|
|
2681
2570
|
configSource,
|
|
2682
|
-
configDigest: `sha256:${
|
|
2571
|
+
configDigest: `sha256:${createHash2("sha256").update(configSource).digest("hex")}`,
|
|
2683
2572
|
signal
|
|
2684
2573
|
});
|
|
2685
2574
|
throwIfDevAborted(signal);
|
|
@@ -2709,8 +2598,8 @@ async function startBuddyDev(options) {
|
|
|
2709
2598
|
shell: false,
|
|
2710
2599
|
detached: platform === "darwin",
|
|
2711
2600
|
...options.onLog === void 0 ? {} : {
|
|
2712
|
-
onStdout: (
|
|
2713
|
-
onStderr: (
|
|
2601
|
+
onStdout: (text) => options.onLog?.({ source: "agent.stdout", text }),
|
|
2602
|
+
onStderr: (text) => options.onLog?.({ source: "agent.stderr", text })
|
|
2714
2603
|
}
|
|
2715
2604
|
});
|
|
2716
2605
|
await instanceLock.attachRuntime(agentProcess.pid);
|
|
@@ -2766,7 +2655,7 @@ async function startBuddyDev(options) {
|
|
|
2766
2655
|
}
|
|
2767
2656
|
|
|
2768
2657
|
// packages/cli-core/src/dev/starter.ts
|
|
2769
|
-
import { resolve as
|
|
2658
|
+
import { resolve as resolve9 } from "node:path";
|
|
2770
2659
|
function createBuddyDevStarter(options = {}) {
|
|
2771
2660
|
const readManifest = options.readManifest ?? (async (projectRoot) => {
|
|
2772
2661
|
const manifest = await readBuddyProjectManifest(projectRoot);
|
|
@@ -2775,7 +2664,7 @@ function createBuddyDevStarter(options = {}) {
|
|
|
2775
2664
|
const startDev = options.startDev ?? startBuddyDev;
|
|
2776
2665
|
return Object.freeze({
|
|
2777
2666
|
async start(input) {
|
|
2778
|
-
const projectRoot =
|
|
2667
|
+
const projectRoot = resolve9(input.projectRoot);
|
|
2779
2668
|
const manifest = await readManifest(projectRoot);
|
|
2780
2669
|
return startDev({
|
|
2781
2670
|
...input,
|
|
@@ -2866,7 +2755,7 @@ async function runDevCommand(args, io, options = {}) {
|
|
|
2866
2755
|
return { exitCode: 0 };
|
|
2867
2756
|
}
|
|
2868
2757
|
try {
|
|
2869
|
-
const requestedRoot =
|
|
2758
|
+
const requestedRoot = resolve10(options.cwd ?? process.cwd(), parsed.directory);
|
|
2870
2759
|
const root = await (options.resolveProjectRoot ?? requireBuddyAgentProjectRoot)(requestedRoot);
|
|
2871
2760
|
const environment = options.env ?? process.env;
|
|
2872
2761
|
const url = appServerUrl(parsed.appServer, environment);
|
|
@@ -2919,22 +2808,22 @@ async function runDevCommand(args, io, options = {}) {
|
|
|
2919
2808
|
}
|
|
2920
2809
|
|
|
2921
2810
|
// packages/cli-core/src/commands/cloud.ts
|
|
2922
|
-
import { resolve as
|
|
2811
|
+
import { resolve as resolve11 } from "node:path";
|
|
2923
2812
|
|
|
2924
2813
|
// packages/cli-core/src/cloud/avatar.ts
|
|
2925
2814
|
import { open as open3 } from "node:fs/promises";
|
|
2926
2815
|
import { basename } from "node:path";
|
|
2927
2816
|
var MAX_BUDDY_AVATAR_BYTES = 5 * 1024 * 1024;
|
|
2928
2817
|
async function readBuddyAvatarFile(path) {
|
|
2929
|
-
const
|
|
2818
|
+
const file = await open3(path, "r");
|
|
2930
2819
|
try {
|
|
2931
|
-
const stat2 = await
|
|
2820
|
+
const stat2 = await file.stat();
|
|
2932
2821
|
if (!stat2.isFile()) throw new Error("\u5934\u50CF\u5FC5\u987B\u662F\u666E\u901A\u56FE\u7247\u6587\u4EF6");
|
|
2933
2822
|
if (!stat2.size || stat2.size > MAX_BUDDY_AVATAR_BYTES) throw new Error("\u5934\u50CF\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u4E0D\u80FD\u8D85\u8FC7 5 MiB");
|
|
2934
2823
|
const buffer = Buffer.alloc(MAX_BUDDY_AVATAR_BYTES + 1);
|
|
2935
2824
|
let size = 0;
|
|
2936
2825
|
while (size < buffer.length) {
|
|
2937
|
-
const { bytesRead } = await
|
|
2826
|
+
const { bytesRead } = await file.read(buffer, size, buffer.length - size, null);
|
|
2938
2827
|
if (!bytesRead) break;
|
|
2939
2828
|
size += bytesRead;
|
|
2940
2829
|
}
|
|
@@ -2944,7 +2833,7 @@ async function readBuddyAvatarFile(path) {
|
|
|
2944
2833
|
if (!mediaType) throw new Error("\u4EC5\u652F\u6301 PNG\u3001JPEG\u3001WebP \u56FE\u7247\u6587\u4EF6");
|
|
2945
2834
|
return { bytes, fileName: basename(path), mediaType };
|
|
2946
2835
|
} finally {
|
|
2947
|
-
await
|
|
2836
|
+
await file.close();
|
|
2948
2837
|
}
|
|
2949
2838
|
}
|
|
2950
2839
|
|
|
@@ -3117,7 +3006,7 @@ function positiveTimeout(value, fallback, name) {
|
|
|
3117
3006
|
if (!Number.isSafeInteger(result) || result <= 0) throw new TypeError(`${name} must be a positive safe integer`);
|
|
3118
3007
|
return result;
|
|
3119
3008
|
}
|
|
3120
|
-
function
|
|
3009
|
+
function object2(value, path) {
|
|
3121
3010
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3122
3011
|
throw invalid(`${path} \u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
3123
3012
|
}
|
|
@@ -3137,7 +3026,7 @@ function optionalText(value, path, allowNewlines = false) {
|
|
|
3137
3026
|
}
|
|
3138
3027
|
function meta(value, path) {
|
|
3139
3028
|
if (value === null) return null;
|
|
3140
|
-
const source =
|
|
3029
|
+
const source = object2(value, path);
|
|
3141
3030
|
const name = source.name === void 0 ? void 0 : safeText(source.name, `${path}.name`);
|
|
3142
3031
|
const avatar = optionalText(source.avatar, `${path}.avatar`);
|
|
3143
3032
|
const tagline = optionalText(source.tagline, `${path}.tagline`);
|
|
@@ -3172,7 +3061,7 @@ function auditStatus(value, path) {
|
|
|
3172
3061
|
return value;
|
|
3173
3062
|
}
|
|
3174
3063
|
function packageVersion(value, path) {
|
|
3175
|
-
const source =
|
|
3064
|
+
const source = object2(value, path);
|
|
3176
3065
|
const auditNote = source.auditNote === null ? null : safeText(source.auditNote, `${path}.auditNote`, true);
|
|
3177
3066
|
return Object.freeze({
|
|
3178
3067
|
version: safeText(source.version, `${path}.version`),
|
|
@@ -3190,7 +3079,7 @@ function positivePage(value, name) {
|
|
|
3190
3079
|
return value;
|
|
3191
3080
|
}
|
|
3192
3081
|
function buddy(value, includeToken) {
|
|
3193
|
-
const source =
|
|
3082
|
+
const source = object2(value, "response");
|
|
3194
3083
|
const token = includeToken ? safeText(source.token, "response.token") : void 0;
|
|
3195
3084
|
return Object.freeze({
|
|
3196
3085
|
id: safeText(source.id, "response.id"),
|
|
@@ -3326,7 +3215,7 @@ var HttpDeveloperPlatformClient = class {
|
|
|
3326
3215
|
}), true);
|
|
3327
3216
|
}
|
|
3328
3217
|
async listBuddies() {
|
|
3329
|
-
const source =
|
|
3218
|
+
const source = object2(await this.#request("/cli/buddies", "GET"), "response");
|
|
3330
3219
|
if (!Array.isArray(source.buddies)) throw invalid("response.buddies \u5FC5\u987B\u662F\u6570\u7EC4");
|
|
3331
3220
|
return Object.freeze({
|
|
3332
3221
|
buddies: Object.freeze(source.buddies.map((item) => buddy(item, false)))
|
|
@@ -3343,7 +3232,7 @@ var HttpDeveloperPlatformClient = class {
|
|
|
3343
3232
|
...pageSize === void 0 ? {} : { pageSize: String(pageSize) }
|
|
3344
3233
|
});
|
|
3345
3234
|
const suffix = query.size === 0 ? "" : `?${query.toString()}`;
|
|
3346
|
-
const source =
|
|
3235
|
+
const source = object2(await this.#request(
|
|
3347
3236
|
`/cli/buddies/${encodeURIComponent(request.id)}/packages${suffix}`,
|
|
3348
3237
|
"GET"
|
|
3349
3238
|
), "response");
|
|
@@ -3365,7 +3254,7 @@ var HttpDeveloperPlatformClient = class {
|
|
|
3365
3254
|
throw new CloudLifecycleError("INVALID_REQUEST", "\u63D0\u4EA4\u5305\u4E0D\u80FD\u4E3A\u7A7A");
|
|
3366
3255
|
}
|
|
3367
3256
|
const query = new URLSearchParams({ commit });
|
|
3368
|
-
const source =
|
|
3257
|
+
const source = object2(await this.#request(
|
|
3369
3258
|
`/cli/buddies/${encodeURIComponent(request.id)}/packages/push?${query.toString()}`,
|
|
3370
3259
|
"POST",
|
|
3371
3260
|
{
|
|
@@ -3382,13 +3271,13 @@ var HttpDeveloperPlatformClient = class {
|
|
|
3382
3271
|
});
|
|
3383
3272
|
}
|
|
3384
3273
|
async logout(accessToken) {
|
|
3385
|
-
const source =
|
|
3274
|
+
const source = object2(await this.#request("/cli/auth/logout", "POST", { accessToken }), "response");
|
|
3386
3275
|
if (source.ok !== true) throw invalid("response.ok \u5FC5\u987B\u662F true");
|
|
3387
3276
|
}
|
|
3388
3277
|
};
|
|
3389
3278
|
|
|
3390
3279
|
// packages/cli-core/src/cloud/browser-login.ts
|
|
3391
|
-
import { createHash as
|
|
3280
|
+
import { createHash as createHash3, randomBytes } from "node:crypto";
|
|
3392
3281
|
import { spawn } from "node:child_process";
|
|
3393
3282
|
import { createServer } from "node:http";
|
|
3394
3283
|
|
|
@@ -3448,10 +3337,10 @@ function browserCommand(url) {
|
|
|
3448
3337
|
}
|
|
3449
3338
|
async function openExternalUrl(url) {
|
|
3450
3339
|
const launch = browserCommand(url);
|
|
3451
|
-
await new Promise((
|
|
3340
|
+
await new Promise((resolve15, reject) => {
|
|
3452
3341
|
const child = spawn(launch.command, launch.args, { shell: false, stdio: "ignore", windowsHide: true });
|
|
3453
3342
|
child.once("error", reject);
|
|
3454
|
-
child.once("exit", (code2) => code2 === 0 ?
|
|
3343
|
+
child.once("exit", (code2) => code2 === 0 ? resolve15() : reject(new Error(`browser launcher exited with ${code2 ?? "unknown"}`)));
|
|
3455
3344
|
});
|
|
3456
3345
|
}
|
|
3457
3346
|
async function write(res, status, title, message, webUrl, tone = "error") {
|
|
@@ -3463,10 +3352,10 @@ async function write(res, status, title, message, webUrl, tone = "error") {
|
|
|
3463
3352
|
"referrer-policy": "no-referrer",
|
|
3464
3353
|
"x-content-type-options": "nosniff"
|
|
3465
3354
|
});
|
|
3466
|
-
await new Promise((
|
|
3355
|
+
await new Promise((resolve15, reject) => {
|
|
3467
3356
|
res.once("error", reject);
|
|
3468
|
-
res.once("close",
|
|
3469
|
-
res.end(renderLoginResult(title, message, webUrl, tone),
|
|
3357
|
+
res.once("close", resolve15);
|
|
3358
|
+
res.end(renderLoginResult(title, message, webUrl, tone), resolve15);
|
|
3470
3359
|
});
|
|
3471
3360
|
}
|
|
3472
3361
|
async function readJson(response) {
|
|
@@ -3496,16 +3385,16 @@ var LoopbackBrowserLoginAdapter = class {
|
|
|
3496
3385
|
if (request.signal?.aborted) throw request.signal.reason;
|
|
3497
3386
|
const callbackSecret = randomBytes(24).toString("hex");
|
|
3498
3387
|
const codeVerifier = randomBytes(32).toString("base64url");
|
|
3499
|
-
const codeChallenge =
|
|
3388
|
+
const codeChallenge = createHash3("sha256").update(codeVerifier).digest("base64url");
|
|
3500
3389
|
let requestId = "";
|
|
3501
3390
|
let settle;
|
|
3502
3391
|
let reject;
|
|
3503
3392
|
let settled = false;
|
|
3504
|
-
const result = new Promise((
|
|
3393
|
+
const result = new Promise((resolve15, rejectResult) => {
|
|
3505
3394
|
settle = (value) => {
|
|
3506
3395
|
if (!settled) {
|
|
3507
3396
|
settled = true;
|
|
3508
|
-
|
|
3397
|
+
resolve15(value);
|
|
3509
3398
|
}
|
|
3510
3399
|
};
|
|
3511
3400
|
reject = (reason) => {
|
|
@@ -3524,9 +3413,9 @@ var LoopbackBrowserLoginAdapter = class {
|
|
|
3524
3413
|
state: request.state
|
|
3525
3414
|
}).then(settle, reject);
|
|
3526
3415
|
});
|
|
3527
|
-
await new Promise((
|
|
3416
|
+
await new Promise((resolve15, rejectListen) => {
|
|
3528
3417
|
server.once("error", rejectListen);
|
|
3529
|
-
server.listen(0, "127.0.0.1", () =>
|
|
3418
|
+
server.listen(0, "127.0.0.1", () => resolve15());
|
|
3530
3419
|
});
|
|
3531
3420
|
const address = server.address();
|
|
3532
3421
|
if (!address || typeof address === "string") {
|
|
@@ -3559,8 +3448,8 @@ var LoopbackBrowserLoginAdapter = class {
|
|
|
3559
3448
|
} finally {
|
|
3560
3449
|
clearTimeout(timer);
|
|
3561
3450
|
request.signal?.removeEventListener("abort", abort);
|
|
3562
|
-
await new Promise((
|
|
3563
|
-
server.close(() =>
|
|
3451
|
+
await new Promise((resolve15) => {
|
|
3452
|
+
server.close(() => resolve15());
|
|
3564
3453
|
server.closeIdleConnections();
|
|
3565
3454
|
server.closeAllConnections();
|
|
3566
3455
|
});
|
|
@@ -3675,7 +3564,7 @@ function parse(source) {
|
|
|
3675
3564
|
});
|
|
3676
3565
|
}
|
|
3677
3566
|
async function runCredentialCommand(input) {
|
|
3678
|
-
return await new Promise((
|
|
3567
|
+
return await new Promise((resolve15, reject) => {
|
|
3679
3568
|
const child = spawn2(input.command, [...input.args], {
|
|
3680
3569
|
shell: false,
|
|
3681
3570
|
windowsHide: true,
|
|
@@ -3691,7 +3580,7 @@ async function runCredentialCommand(input) {
|
|
|
3691
3580
|
child.stdout.on("data", (chunk) => collect(stdout, chunk));
|
|
3692
3581
|
child.stderr.on("data", (chunk) => collect(stderr, chunk));
|
|
3693
3582
|
child.once("error", reject);
|
|
3694
|
-
child.once("close", (code2) =>
|
|
3583
|
+
child.once("close", (code2) => resolve15({
|
|
3695
3584
|
code: code2 ?? 1,
|
|
3696
3585
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
3697
3586
|
stderr: Buffer.concat(stderr).toString("utf8")
|
|
@@ -3751,7 +3640,7 @@ var SystemCloudTokenStore = class {
|
|
|
3751
3640
|
};
|
|
3752
3641
|
|
|
3753
3642
|
// packages/cli-core/src/cloud/mock-client.ts
|
|
3754
|
-
import { createHash as
|
|
3643
|
+
import { createHash as createHash4, randomBytes as randomBytes2 } from "node:crypto";
|
|
3755
3644
|
var MockDeveloperPlatformClient = class {
|
|
3756
3645
|
#now;
|
|
3757
3646
|
#buddies = /* @__PURE__ */ new Map();
|
|
@@ -3779,7 +3668,7 @@ var MockDeveloperPlatformClient = class {
|
|
|
3779
3668
|
const current = this.#require(request.id);
|
|
3780
3669
|
validateBuddyMetaUpdate(request.meta);
|
|
3781
3670
|
const onlyAvatar = Object.keys(request.meta).every((key) => key === "avatar");
|
|
3782
|
-
const avatar = request.avatar ? `/media/avatar-${request.id}.webp?v=${
|
|
3671
|
+
const avatar = request.avatar ? `/media/avatar-${request.id}.webp?v=${createHash4("sha256").update(request.avatar.bytes).digest("hex").slice(0, 16)}` : request.meta.avatar === null ? null : current.meta?.avatar ?? null;
|
|
3783
3672
|
const next = this.#value({ ...current, meta: { ...onlyAvatar ? current.meta : request.meta, avatar }, updatedAt: this.#now() });
|
|
3784
3673
|
this.#buddies.set(request.id, next);
|
|
3785
3674
|
return structuredClone(next);
|
|
@@ -3923,7 +3812,7 @@ function dependencies(options) {
|
|
|
3923
3812
|
return { session: options.session, client: options.client };
|
|
3924
3813
|
}
|
|
3925
3814
|
function requestedDirectory(options, parsed) {
|
|
3926
|
-
return
|
|
3815
|
+
return resolve11(options.cwd ?? process.cwd(), parsed.values.get("--directory") ?? ".");
|
|
3927
3816
|
}
|
|
3928
3817
|
function auditLabel(status) {
|
|
3929
3818
|
if (status === "auditing") return "\u5BA1\u6838\u4E2D";
|
|
@@ -4004,10 +3893,10 @@ async function runAvatar(parsed, io, options) {
|
|
|
4004
3893
|
if (parsed.values.has("--buddy-id") && parsed.values.has("--directory")) {
|
|
4005
3894
|
throw new CloudCommandUsageError("--buddy-id \u548C --directory \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
4006
3895
|
}
|
|
4007
|
-
const
|
|
3896
|
+
const file = parsed.values.get("--file");
|
|
4008
3897
|
let upload;
|
|
4009
3898
|
try {
|
|
4010
|
-
upload =
|
|
3899
|
+
upload = file ? await readBuddyAvatarFile(resolve11(options.cwd ?? process.cwd(), file)) : void 0;
|
|
4011
3900
|
} catch (error2) {
|
|
4012
3901
|
throw new CloudCommandUsageError(error2 instanceof Error ? error2.message : "\u65E0\u6CD5\u8BFB\u53D6\u5934\u50CF\u56FE\u7247");
|
|
4013
3902
|
}
|
|
@@ -4076,8 +3965,8 @@ async function runCloudCommand(command, args, io, options = {}) {
|
|
|
4076
3965
|
var CLOUD_COMMAND_HELP = HELP;
|
|
4077
3966
|
|
|
4078
3967
|
// packages/cli-core/src/migration/index.ts
|
|
4079
|
-
import { lstat as lstat7, open as open4, readdir as
|
|
4080
|
-
import { extname, isAbsolute as isAbsolute2, join as
|
|
3968
|
+
import { lstat as lstat7, open as open4, readdir as readdir3, realpath as realpath3, stat } from "node:fs/promises";
|
|
3969
|
+
import { extname, isAbsolute as isAbsolute2, join as join9, relative, resolve as resolve12, sep, win32 as win322 } from "node:path";
|
|
4081
3970
|
var DEFAULT_SKILL_SCAN_LIMITS = Object.freeze({
|
|
4082
3971
|
maxFiles: 128,
|
|
4083
3972
|
maxFileBytes: 256 * 1024,
|
|
@@ -4230,7 +4119,7 @@ async function existingProjectRoot(value) {
|
|
|
4230
4119
|
return rejectScan("SKILL_PROJECT_ROOT_INVALID", ".", "projectRoot \u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u5DF2\u6709\u9879\u76EE\u76EE\u5F55\u3002");
|
|
4231
4120
|
}
|
|
4232
4121
|
try {
|
|
4233
|
-
const root = await
|
|
4122
|
+
const root = await realpath3(resolve12(value));
|
|
4234
4123
|
if (!(await stat(root)).isDirectory()) {
|
|
4235
4124
|
return rejectScan("SKILL_PROJECT_ROOT_INVALID", ".", "projectRoot \u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u5DF2\u6709\u9879\u76EE\u76EE\u5F55\u3002");
|
|
4236
4125
|
}
|
|
@@ -4246,7 +4135,7 @@ async function existingProjectRoot(value) {
|
|
|
4246
4135
|
}
|
|
4247
4136
|
}
|
|
4248
4137
|
async function existingSkillRoot(projectRoot, skillPath) {
|
|
4249
|
-
const candidate = skillPath === "." ? projectRoot :
|
|
4138
|
+
const candidate = skillPath === "." ? projectRoot : join9(projectRoot, ...skillPath.split("/"));
|
|
4250
4139
|
try {
|
|
4251
4140
|
await lstat7(candidate);
|
|
4252
4141
|
} catch (cause) {
|
|
@@ -4257,7 +4146,7 @@ async function existingSkillRoot(projectRoot, skillPath) {
|
|
|
4257
4146
|
}
|
|
4258
4147
|
let root;
|
|
4259
4148
|
try {
|
|
4260
|
-
root = await
|
|
4149
|
+
root = await realpath3(candidate);
|
|
4261
4150
|
} catch (cause) {
|
|
4262
4151
|
if (filesystemCode(cause) === "ELOOP") {
|
|
4263
4152
|
return rejectScan("SKILL_SYMLINK_CYCLE", skillPath, "Skill \u8DEF\u5F84\u5305\u542B\u7B26\u53F7\u94FE\u63A5\u5FAA\u73AF\u3002", cause);
|
|
@@ -4283,10 +4172,10 @@ async function existingSkillRoot(projectRoot, skillPath) {
|
|
|
4283
4172
|
}
|
|
4284
4173
|
async function assertEntrypoint(context) {
|
|
4285
4174
|
const entryPath = reportChild(context.skillPath, "SKILL.md");
|
|
4286
|
-
const candidate =
|
|
4175
|
+
const candidate = join9(context.skillRoot, "SKILL.md");
|
|
4287
4176
|
try {
|
|
4288
4177
|
await lstat7(candidate);
|
|
4289
|
-
const target = await
|
|
4178
|
+
const target = await realpath3(candidate);
|
|
4290
4179
|
if (!isWithin(context.projectRoot, target) || !isWithin(context.skillRoot, target)) {
|
|
4291
4180
|
rejectScan(
|
|
4292
4181
|
"SKILL_SYMLINK_ESCAPE",
|
|
@@ -4330,7 +4219,7 @@ async function walkDirectory(actualDirectory, reportDirectory, ancestors, contex
|
|
|
4330
4219
|
}
|
|
4331
4220
|
let directory;
|
|
4332
4221
|
try {
|
|
4333
|
-
directory = await
|
|
4222
|
+
directory = await realpath3(actualDirectory);
|
|
4334
4223
|
} catch (cause) {
|
|
4335
4224
|
if (filesystemCode(cause) === "ELOOP") {
|
|
4336
4225
|
return rejectScan("SKILL_SYMLINK_CYCLE", reportDirectory, "Skill \u76EE\u5F55\u5305\u542B\u7B26\u53F7\u94FE\u63A5\u5FAA\u73AF\u3002", cause);
|
|
@@ -4350,7 +4239,7 @@ async function walkDirectory(actualDirectory, reportDirectory, ancestors, contex
|
|
|
4350
4239
|
nextAncestors.add(directoryKey);
|
|
4351
4240
|
let entries;
|
|
4352
4241
|
try {
|
|
4353
|
-
entries = await
|
|
4242
|
+
entries = await readdir3(directory, { withFileTypes: true, encoding: "utf8" });
|
|
4354
4243
|
} catch (cause) {
|
|
4355
4244
|
return rejectScan("SKILL_SCAN_IO_ERROR", reportDirectory, "\u65E0\u6CD5\u5217\u51FA Skill \u5B50\u76EE\u5F55\u3002", cause);
|
|
4356
4245
|
}
|
|
@@ -4387,10 +4276,10 @@ async function walkDirectory(actualDirectory, reportDirectory, ancestors, contex
|
|
|
4387
4276
|
}
|
|
4388
4277
|
for (const entry of entries) {
|
|
4389
4278
|
const childReportPath = reportChild(reportDirectory, entry.name);
|
|
4390
|
-
const childPath =
|
|
4279
|
+
const childPath = join9(directory, entry.name);
|
|
4391
4280
|
let target;
|
|
4392
4281
|
try {
|
|
4393
|
-
target = await
|
|
4282
|
+
target = await realpath3(childPath);
|
|
4394
4283
|
} catch (cause) {
|
|
4395
4284
|
if (filesystemCode(cause) === "ELOOP") {
|
|
4396
4285
|
return rejectScan("SKILL_SYMLINK_CYCLE", childReportPath, "Skill \u5185\u5BB9\u5305\u542B\u7B26\u53F7\u94FE\u63A5\u5FAA\u73AF\u3002", cause);
|
|
@@ -4841,9 +4730,9 @@ async function scanExternalSkillPortability(options) {
|
|
|
4841
4730
|
}
|
|
4842
4731
|
|
|
4843
4732
|
// packages/cli-core/src/push/preflight.ts
|
|
4844
|
-
import { createHash as
|
|
4845
|
-
import { lstat as lstat8, open as open5, readdir as
|
|
4846
|
-
import { isAbsolute as isAbsolute3, join as
|
|
4733
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
4734
|
+
import { lstat as lstat8, open as open5, readdir as readdir4, realpath as realpath4 } from "node:fs/promises";
|
|
4735
|
+
import { isAbsolute as isAbsolute3, join as join10, relative as relative2, resolve as resolve13, sep as sep2, win32 as win323 } from "node:path";
|
|
4847
4736
|
|
|
4848
4737
|
// packages/cli-core/src/push/errors.ts
|
|
4849
4738
|
var PushPreflightError = class extends Error {
|
|
@@ -4941,7 +4830,7 @@ function error(options) {
|
|
|
4941
4830
|
throw new PushPreflightError(options);
|
|
4942
4831
|
}
|
|
4943
4832
|
function sha256(value) {
|
|
4944
|
-
return `sha256:${
|
|
4833
|
+
return `sha256:${createHash5("sha256").update(value).digest("hex")}`;
|
|
4945
4834
|
}
|
|
4946
4835
|
function positiveLimit(value, name, hardMaximum) {
|
|
4947
4836
|
if (!Number.isSafeInteger(value) || value < 1 || value > hardMaximum) {
|
|
@@ -5031,7 +4920,7 @@ function normalizeBookletPath(value) {
|
|
|
5031
4920
|
return normalized;
|
|
5032
4921
|
}
|
|
5033
4922
|
async function canonicalProjectRoot(projectRoot) {
|
|
5034
|
-
const absolute =
|
|
4923
|
+
const absolute = resolve13(projectRoot);
|
|
5035
4924
|
let entry;
|
|
5036
4925
|
try {
|
|
5037
4926
|
entry = await lstat8(absolute);
|
|
@@ -5051,7 +4940,7 @@ async function canonicalProjectRoot(projectRoot) {
|
|
|
5051
4940
|
});
|
|
5052
4941
|
}
|
|
5053
4942
|
try {
|
|
5054
|
-
return await
|
|
4943
|
+
return await realpath4(absolute);
|
|
5055
4944
|
} catch (cause) {
|
|
5056
4945
|
error({
|
|
5057
4946
|
code: "PUSH_PROJECT_INVALID",
|
|
@@ -5062,7 +4951,7 @@ async function canonicalProjectRoot(projectRoot) {
|
|
|
5062
4951
|
}
|
|
5063
4952
|
}
|
|
5064
4953
|
async function captureConfigWithinLimit(projectRoot, maxFileBytes, filename) {
|
|
5065
|
-
const path =
|
|
4954
|
+
const path = join10(projectRoot, filename);
|
|
5066
4955
|
let entry;
|
|
5067
4956
|
try {
|
|
5068
4957
|
entry = await lstat8(path);
|
|
@@ -5096,22 +4985,22 @@ async function captureConfigWithinLimit(projectRoot, maxFileBytes, filename) {
|
|
|
5096
4985
|
maxFileBytes
|
|
5097
4986
|
});
|
|
5098
4987
|
}
|
|
5099
|
-
function decodeCapturedConfig(
|
|
5100
|
-
if (
|
|
4988
|
+
function decodeCapturedConfig(file) {
|
|
4989
|
+
if (file.contents === void 0) {
|
|
5101
4990
|
error({
|
|
5102
4991
|
code: "PUSH_CONFIG_INVALID",
|
|
5103
|
-
path:
|
|
5104
|
-
message: `\u65E0\u6CD5\u8BFB\u53D6 ${
|
|
4992
|
+
path: file.path,
|
|
4993
|
+
message: `\u65E0\u6CD5\u8BFB\u53D6 ${file.path} \u5185\u5BB9\u3002`
|
|
5105
4994
|
});
|
|
5106
4995
|
}
|
|
5107
4996
|
let source;
|
|
5108
4997
|
try {
|
|
5109
|
-
source = new TextDecoder("utf-8", { fatal: true }).decode(
|
|
4998
|
+
source = new TextDecoder("utf-8", { fatal: true }).decode(file.contents);
|
|
5110
4999
|
} catch (cause) {
|
|
5111
5000
|
error({
|
|
5112
5001
|
code: "PUSH_CONFIG_INVALID",
|
|
5113
|
-
path:
|
|
5114
|
-
message: `${
|
|
5002
|
+
path: file.path,
|
|
5003
|
+
message: `${file.path} \u4E0D\u662F\u6709\u6548 UTF-8\u3002`,
|
|
5115
5004
|
cause
|
|
5116
5005
|
});
|
|
5117
5006
|
}
|
|
@@ -5132,7 +5021,7 @@ function parseCapturedProject(agentFile) {
|
|
|
5132
5021
|
async function selectLockfile(projectRoot) {
|
|
5133
5022
|
let names;
|
|
5134
5023
|
try {
|
|
5135
|
-
names = await
|
|
5024
|
+
names = await readdir4(projectRoot);
|
|
5136
5025
|
} catch (cause) {
|
|
5137
5026
|
error({
|
|
5138
5027
|
code: "PUSH_PROJECT_INVALID",
|
|
@@ -5187,7 +5076,7 @@ async function hashRegularFile(options) {
|
|
|
5187
5076
|
message: `\u751F\u6210\u6E05\u5355\u65F6\u6587\u4EF6\u53D1\u751F\u53D8\u5316\uFF1A${options.portablePath}`
|
|
5188
5077
|
});
|
|
5189
5078
|
}
|
|
5190
|
-
const hash =
|
|
5079
|
+
const hash = createHash5("sha256");
|
|
5191
5080
|
const captured = [];
|
|
5192
5081
|
const buffer = Buffer.allocUnsafe(READ_BUFFER_BYTES);
|
|
5193
5082
|
let bytes = 0;
|
|
@@ -5241,7 +5130,7 @@ async function createManifest(options) {
|
|
|
5241
5130
|
}
|
|
5242
5131
|
let names;
|
|
5243
5132
|
try {
|
|
5244
|
-
names = await
|
|
5133
|
+
names = await readdir4(directory);
|
|
5245
5134
|
} catch (cause) {
|
|
5246
5135
|
error({
|
|
5247
5136
|
code: "PUSH_PROJECT_INVALID",
|
|
@@ -5265,7 +5154,7 @@ async function createManifest(options) {
|
|
|
5265
5154
|
sensitiveEntriesExcluded += 1;
|
|
5266
5155
|
continue;
|
|
5267
5156
|
}
|
|
5268
|
-
const absolutePath =
|
|
5157
|
+
const absolutePath = join10(directory, name);
|
|
5269
5158
|
let entry;
|
|
5270
5159
|
try {
|
|
5271
5160
|
entry = await lstat8(absolutePath);
|
|
@@ -5299,7 +5188,7 @@ async function createManifest(options) {
|
|
|
5299
5188
|
}
|
|
5300
5189
|
let canonicalPath;
|
|
5301
5190
|
try {
|
|
5302
|
-
canonicalPath = await
|
|
5191
|
+
canonicalPath = await realpath4(absolutePath);
|
|
5303
5192
|
} catch (cause) {
|
|
5304
5193
|
error({
|
|
5305
5194
|
code: "PUSH_FILE_CHANGED",
|
|
@@ -5358,15 +5247,15 @@ async function createManifest(options) {
|
|
|
5358
5247
|
message: `\u63D0\u4EA4\u6587\u4EF6\u603B\u91CF\u8D85\u8FC7\u4E0A\u9650 ${options.limits.maxTotalBytes} bytes\u3002`
|
|
5359
5248
|
});
|
|
5360
5249
|
}
|
|
5361
|
-
const
|
|
5250
|
+
const file = await hashRegularFile({
|
|
5362
5251
|
absolutePath,
|
|
5363
5252
|
portablePath: path,
|
|
5364
5253
|
expected: entry,
|
|
5365
5254
|
captureContents: options.capturePaths.has(path),
|
|
5366
5255
|
maxFileBytes: options.limits.maxFileBytes
|
|
5367
5256
|
});
|
|
5368
|
-
files.push(
|
|
5369
|
-
totalBytes +=
|
|
5257
|
+
files.push(file);
|
|
5258
|
+
totalBytes += file.bytes;
|
|
5370
5259
|
}
|
|
5371
5260
|
};
|
|
5372
5261
|
await walk(options.projectRoot, []);
|
|
@@ -5447,10 +5336,10 @@ function validateLockfile(lockfile, contents) {
|
|
|
5447
5336
|
function bundleDigest(files) {
|
|
5448
5337
|
const descriptor = JSON.stringify({
|
|
5449
5338
|
schemaVersion: "1",
|
|
5450
|
-
files: files.map((
|
|
5451
|
-
path:
|
|
5452
|
-
bytes:
|
|
5453
|
-
digest:
|
|
5339
|
+
files: files.map((file) => ({
|
|
5340
|
+
path: file.path,
|
|
5341
|
+
bytes: file.bytes,
|
|
5342
|
+
digest: file.digest
|
|
5454
5343
|
}))
|
|
5455
5344
|
});
|
|
5456
5345
|
return sha256(`buddy-push-bundle-v1\0${descriptor}`);
|
|
@@ -5460,8 +5349,8 @@ function warning(code2, message) {
|
|
|
5460
5349
|
}
|
|
5461
5350
|
function assertOfficialProjectIncluded(files) {
|
|
5462
5351
|
for (const path of OFFICIAL_RUNTIME_INPUTS) {
|
|
5463
|
-
const
|
|
5464
|
-
if (
|
|
5352
|
+
const file = files.find((entry) => entry.path === path);
|
|
5353
|
+
if (file === void 0 || file.bytes === 0) {
|
|
5465
5354
|
error({
|
|
5466
5355
|
code: "PUSH_PROJECT_INVALID",
|
|
5467
5356
|
path,
|
|
@@ -5500,7 +5389,7 @@ function assertOfficialProjectIncluded(files) {
|
|
|
5500
5389
|
}
|
|
5501
5390
|
}
|
|
5502
5391
|
async function assertCapturedConfigStable(options) {
|
|
5503
|
-
const manifestEntry = options.manifestFiles.find((
|
|
5392
|
+
const manifestEntry = options.manifestFiles.find((file) => file.path === options.filename);
|
|
5504
5393
|
if (manifestEntry === void 0) {
|
|
5505
5394
|
error({
|
|
5506
5395
|
code: "PUSH_CONFIG_INVALID",
|
|
@@ -5517,7 +5406,7 @@ async function assertCapturedConfigStable(options) {
|
|
|
5517
5406
|
}
|
|
5518
5407
|
let current;
|
|
5519
5408
|
try {
|
|
5520
|
-
const path =
|
|
5409
|
+
const path = join10(options.projectRoot, options.filename);
|
|
5521
5410
|
const entry = await lstat8(path);
|
|
5522
5411
|
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
5523
5412
|
error({
|
|
@@ -5561,8 +5450,6 @@ async function createPushPreflight(options) {
|
|
|
5561
5450
|
BUDDY_AGENT_FILENAME
|
|
5562
5451
|
);
|
|
5563
5452
|
parseCapturedProject(initialAgentEntry);
|
|
5564
|
-
const widgetDelivery = await checkWidgetDelivery(projectRoot);
|
|
5565
|
-
if (widgetDelivery.status === "incomplete") error({ code: "PUSH_WIDGET_DELIVERY_INCOMPLETE", message: widgetDeliverySummary(widgetDelivery) });
|
|
5566
5453
|
const lockfile = await selectLockfile(projectRoot);
|
|
5567
5454
|
assertBookletIsNotRequiredInput(bookletPath, lockfile);
|
|
5568
5455
|
const manifest = await createManifest({
|
|
@@ -5571,12 +5458,7 @@ async function createPushPreflight(options) {
|
|
|
5571
5458
|
capturePaths: /* @__PURE__ */ new Set([BUDDY_AGENT_FILENAME, lockfile.path, BUDDY_PLATFORM_PACKAGE_JSON, BUDDY_PLATFORM_AGENT_ENTRY, BUDDY_PLATFORM_FACTORY_ENTRY]),
|
|
5572
5459
|
...bookletPath === void 0 ? {} : { bookletPath }
|
|
5573
5460
|
});
|
|
5574
|
-
|
|
5575
|
-
if (manifest.files.find((file2) => file2.path === checked.path)?.digest !== checked.digest) {
|
|
5576
|
-
error({ code: "PUSH_WIDGET_DELIVERY_INCOMPLETE", message: `\u5C0F\u6302\u4EF6\u6838\u5BF9\u540E\u6587\u4EF6\u53D8\u5316\u6216\u672A\u8FDB\u5165\u4E0A\u4F20\u5305\uFF1A${checked.path}\uFF1B\u8BF7\u91CD\u65B0\u68C0\u67E5\u3002` });
|
|
5577
|
-
}
|
|
5578
|
-
}
|
|
5579
|
-
const lockEntry = manifest.files.find((file2) => file2.path === lockfile.path);
|
|
5461
|
+
const lockEntry = manifest.files.find((file) => file.path === lockfile.path);
|
|
5580
5462
|
if (lockEntry?.contents === void 0) {
|
|
5581
5463
|
error({
|
|
5582
5464
|
code: "PUSH_LOCKFILE_INVALID",
|
|
@@ -5601,22 +5483,23 @@ async function createPushPreflight(options) {
|
|
|
5601
5483
|
maxFileBytes: limits.maxFileBytes
|
|
5602
5484
|
});
|
|
5603
5485
|
const config = parseCapturedProject(agentEntry);
|
|
5604
|
-
if (config.datasets?.length) {
|
|
5486
|
+
if (config.datasets?.length || config.model !== void 0) {
|
|
5605
5487
|
try {
|
|
5606
|
-
await validateRuntimeDatasets(projectRoot, config.datasets);
|
|
5488
|
+
if (config.datasets?.length) await validateRuntimeDatasets(projectRoot, config.datasets);
|
|
5489
|
+
await validateRuntimeModel(projectRoot, config.model);
|
|
5607
5490
|
} catch (cause) {
|
|
5608
5491
|
error({
|
|
5609
5492
|
code: "PUSH_CONFIG_INVALID",
|
|
5610
5493
|
path: BUDDY_AGENT_FILENAME,
|
|
5611
|
-
message: `\u65E0\u6CD5\u6309\u5DE5\u7A0B Runtime \u6821\u9A8C\u6570\u636E\u58F0\u660E\uFF1A${cause instanceof Error ? cause.message : String(cause)}`,
|
|
5494
|
+
message: `\u65E0\u6CD5\u6309\u5DE5\u7A0B Runtime \u6821\u9A8C\u6A21\u578B\u6216\u6570\u636E\u58F0\u660E\uFF1A${cause instanceof Error ? cause.message : String(cause)}`,
|
|
5612
5495
|
cause
|
|
5613
5496
|
});
|
|
5614
5497
|
}
|
|
5615
5498
|
}
|
|
5616
|
-
const files = Object.freeze(manifest.files.map((
|
|
5617
|
-
path:
|
|
5618
|
-
bytes:
|
|
5619
|
-
digest:
|
|
5499
|
+
const files = Object.freeze(manifest.files.map((file) => Object.freeze({
|
|
5500
|
+
path: file.path,
|
|
5501
|
+
bytes: file.bytes,
|
|
5502
|
+
digest: file.digest
|
|
5620
5503
|
})));
|
|
5621
5504
|
const warnings = [warning(
|
|
5622
5505
|
"PREFLIGHT_ONLY",
|
|
@@ -5652,16 +5535,16 @@ async function createPushPreflight(options) {
|
|
|
5652
5535
|
}
|
|
5653
5536
|
|
|
5654
5537
|
// packages/cli-core/src/push/bundle.ts
|
|
5655
|
-
import { createHash as
|
|
5656
|
-
import { lstat as lstat9, readFile as
|
|
5657
|
-
import { join as
|
|
5538
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
5539
|
+
import { lstat as lstat9, readFile as readFile9, realpath as realpath5 } from "node:fs/promises";
|
|
5540
|
+
import { join as join11, relative as relative3, sep as sep3, win32 as win324 } from "node:path";
|
|
5658
5541
|
import { Writable } from "node:stream";
|
|
5659
5542
|
import { pipeline } from "node:stream/promises";
|
|
5660
5543
|
import { createGzip } from "node:zlib";
|
|
5661
5544
|
import { pack } from "tar-stream";
|
|
5662
5545
|
var MEDIA_TYPE = "application/gzip";
|
|
5663
5546
|
function digest(bytes) {
|
|
5664
|
-
return `sha256:${
|
|
5547
|
+
return `sha256:${createHash6("sha256").update(bytes).digest("hex")}`;
|
|
5665
5548
|
}
|
|
5666
5549
|
function changed(path, message, cause) {
|
|
5667
5550
|
throw new PushPreflightError({
|
|
@@ -5675,42 +5558,42 @@ function inside(root, target) {
|
|
|
5675
5558
|
const path = relative3(root, target);
|
|
5676
5559
|
return path === "" || path !== ".." && !path.startsWith(`..${sep3}`) && !path.startsWith("/") && !win324.isAbsolute(path);
|
|
5677
5560
|
}
|
|
5678
|
-
async function capture(root,
|
|
5679
|
-
const absolute =
|
|
5561
|
+
async function capture(root, file) {
|
|
5562
|
+
const absolute = join11(root, ...file.path.split("/"));
|
|
5680
5563
|
try {
|
|
5681
5564
|
const entry = await lstat9(absolute);
|
|
5682
|
-
if (!entry.isFile() || entry.isSymbolicLink() || entry.size !==
|
|
5683
|
-
changed(
|
|
5565
|
+
if (!entry.isFile() || entry.isSymbolicLink() || entry.size !== file.bytes) {
|
|
5566
|
+
changed(file.path, `\u63D0\u4EA4\u524D\u6587\u4EF6\u53D1\u751F\u53D8\u5316\uFF1A${file.path}`);
|
|
5684
5567
|
}
|
|
5685
|
-
const canonical = await
|
|
5686
|
-
if (!inside(root, canonical)) changed(
|
|
5687
|
-
const contents = await
|
|
5688
|
-
if (contents.byteLength !==
|
|
5689
|
-
changed(
|
|
5568
|
+
const canonical = await realpath5(absolute);
|
|
5569
|
+
if (!inside(root, canonical)) changed(file.path, `\u63D0\u4EA4\u6587\u4EF6\u8D8A\u8FC7\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${file.path}`);
|
|
5570
|
+
const contents = await readFile9(absolute);
|
|
5571
|
+
if (contents.byteLength !== file.bytes || digest(contents) !== file.digest) {
|
|
5572
|
+
changed(file.path, `\u63D0\u4EA4\u524D\u6587\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316\uFF1A${file.path}`);
|
|
5690
5573
|
}
|
|
5691
5574
|
return Object.freeze({
|
|
5692
|
-
path:
|
|
5693
|
-
bytes:
|
|
5694
|
-
digest:
|
|
5575
|
+
path: file.path,
|
|
5576
|
+
bytes: file.bytes,
|
|
5577
|
+
digest: file.digest,
|
|
5695
5578
|
content: contents
|
|
5696
5579
|
});
|
|
5697
5580
|
} catch (cause) {
|
|
5698
5581
|
if (cause instanceof PushPreflightError) throw cause;
|
|
5699
|
-
changed(
|
|
5582
|
+
changed(file.path, `\u63D0\u4EA4\u524D\u65E0\u6CD5\u518D\u6B21\u8BFB\u53D6\u6587\u4EF6\uFF1A${file.path}`, cause);
|
|
5700
5583
|
}
|
|
5701
5584
|
}
|
|
5702
5585
|
async function createPushSourceBundle(plan) {
|
|
5703
|
-
const canonicalRoot = await
|
|
5586
|
+
const canonicalRoot = await realpath5(plan.projectRoot).catch((cause) => changed(plan.projectRoot, "\u63D0\u4EA4\u9879\u76EE\u76EE\u5F55\u5728\u6253\u5305\u524D\u5DF2\u4E0D\u53EF\u7528", cause));
|
|
5704
5587
|
if (canonicalRoot !== plan.projectRoot) {
|
|
5705
5588
|
changed(plan.projectRoot, "\u63D0\u4EA4\u9879\u76EE\u6839\u76EE\u5F55\u5728\u9884\u68C0\u540E\u53D1\u751F\u53D8\u5316");
|
|
5706
5589
|
}
|
|
5707
5590
|
const files = [];
|
|
5708
|
-
for (const
|
|
5591
|
+
for (const file of plan.files) files.push(await capture(canonicalRoot, file));
|
|
5709
5592
|
const descriptor = JSON.stringify({
|
|
5710
5593
|
schemaVersion: "1",
|
|
5711
|
-
files: files.map((
|
|
5594
|
+
files: files.map((file) => ({ path: file.path, bytes: file.bytes, digest: file.digest }))
|
|
5712
5595
|
});
|
|
5713
|
-
const calculatedBundleDigest = `sha256:${
|
|
5596
|
+
const calculatedBundleDigest = `sha256:${createHash6("sha256").update(`buddy-push-bundle-v1\0${descriptor}`).digest("hex")}`;
|
|
5714
5597
|
if (calculatedBundleDigest !== plan.bundleDigest) {
|
|
5715
5598
|
changed(plan.projectRoot, "\u63D0\u4EA4\u6E05\u5355\u8EAB\u4EFD\u5728\u6253\u5305\u524D\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C push");
|
|
5716
5599
|
}
|
|
@@ -5723,16 +5606,16 @@ async function createPushSourceBundle(plan) {
|
|
|
5723
5606
|
}
|
|
5724
5607
|
});
|
|
5725
5608
|
const completed = pipeline(archive, createGzip({ level: 9 }), output);
|
|
5726
|
-
for (const
|
|
5609
|
+
for (const file of files) {
|
|
5727
5610
|
await new Promise((resolveEntry, rejectEntry) => {
|
|
5728
5611
|
archive.entry({
|
|
5729
|
-
name:
|
|
5730
|
-
size:
|
|
5612
|
+
name: file.path,
|
|
5613
|
+
size: file.content.byteLength,
|
|
5731
5614
|
mode: 420,
|
|
5732
5615
|
uid: 0,
|
|
5733
5616
|
gid: 0,
|
|
5734
5617
|
mtime: /* @__PURE__ */ new Date(0)
|
|
5735
|
-
},
|
|
5618
|
+
}, file.content, (cause) => cause ? rejectEntry(cause) : resolveEntry());
|
|
5736
5619
|
});
|
|
5737
5620
|
}
|
|
5738
5621
|
archive.finalize();
|
|
@@ -5773,8 +5656,7 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
|
|
|
5773
5656
|
buddy-cli dev [--app-server <URL>] [--directory <\u9879\u76EE\u76EE\u5F55>]
|
|
5774
5657
|
buddy-cli login | logout | push | status
|
|
5775
5658
|
buddy-cli avatar (--file <\u56FE\u7247\u6587\u4EF6> | --clear) [--directory <\u9879\u76EE\u76EE\u5F55> | --buddy-id <\u642D\u5B50 ID>]
|
|
5776
|
-
buddy-cli models [--json]
|
|
5777
|
-
buddy-cli widgets sync | check | verify
|
|
5659
|
+
buddy-cli models [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
|
|
5778
5660
|
buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
|
|
5779
5661
|
buddy-cli preview [--app-server <URL>] [--directory <\u9879\u76EE\u76EE\u5F55>]
|
|
5780
5662
|
buddy-cli help
|
|
@@ -5786,8 +5668,8 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
|
|
|
5786
5668
|
dev \u542F\u52A8\u5B98\u65B9 Runtime \u5E76\u8FDE\u63A5 DEV App Server
|
|
5787
5669
|
login \u901A\u8FC7\u6D4F\u89C8\u5668\u767B\u5F55\u642D\u642D\u8D26\u53F7
|
|
5788
5670
|
logout \u9000\u51FA\u642D\u642D\u5F00\u53D1\u8005\u8D26\u53F7\u5E76\u6E05\u9664\u672C\u673A\u767B\u5F55\u72B6\u6001
|
|
5789
|
-
models \u67E5\u770B
|
|
5790
|
-
datasets \
|
|
5671
|
+
models \u67E5\u770B Runtime \u6A21\u578B ID\uFF08\u5DE5\u7A0B\u5916\u8054\u7F51\u8BFB\u53D6\u6700\u65B0\u7248\uFF0C\u65E0\u9700\u767B\u5F55\uFF09
|
|
5672
|
+
datasets \u67E5\u770B Runtime \u6570\u636E\u96C6\u76EE\u5F55\uFF08\u5DE5\u7A0B\u5916\u8054\u7F51\u8BFB\u53D6\u6700\u65B0\u7248\uFF0C\u65E0\u9700\u767B\u5F55\uFF09
|
|
5791
5673
|
push \u4E0A\u4F20 Agent \u5DE5\u7A0B\u548C commit\uFF0C\u63D0\u4EA4\u5E73\u53F0\u5BA1\u6838
|
|
5792
5674
|
status \u67E5\u8BE2\u642D\u5B50\u7684\u8D44\u6599\u3001\u4EE3\u7801\u3001\u8FD0\u884C\u4E0E\u53D1\u5E03\u72B6\u6001
|
|
5793
5675
|
avatar \u8BBE\u7F6E\u6216\u6E05\u9664\u642D\u5B50\u5934\u50CF\uFF0C\u4FDD\u7559\u5176\u4ED6\u4E91\u7AEF\u8D44\u6599
|
|
@@ -5996,7 +5878,7 @@ function defaultProjectDirectory(name) {
|
|
|
5996
5878
|
return `./${folder}`;
|
|
5997
5879
|
}
|
|
5998
5880
|
async function initializeProjectRoute(route, args, io, options, application) {
|
|
5999
|
-
const cwd =
|
|
5881
|
+
const cwd = resolve14(options.cwd ?? process.cwd());
|
|
6000
5882
|
const { name, tagline, intro } = application;
|
|
6001
5883
|
const directoryInput = await textAnswer(
|
|
6002
5884
|
io,
|
|
@@ -6005,7 +5887,7 @@ async function initializeProjectRoute(route, args, io, options, application) {
|
|
|
6005
5887
|
"\u9879\u76EE\u76EE\u5F55\uFF08\u7A7A\u76EE\u5F55\u6216\u5DF2\u6709\u642D\u642D\u5DE5\u7A0B\uFF09",
|
|
6006
5888
|
defaultProjectDirectory(name)
|
|
6007
5889
|
);
|
|
6008
|
-
const rootDirectory =
|
|
5890
|
+
const rootDirectory = resolve14(cwd, directoryInput);
|
|
6009
5891
|
await assertInitializableBuddyTarget(rootDirectory);
|
|
6010
5892
|
const initializationTarget = { directory: rootDirectory, kind: "new" };
|
|
6011
5893
|
const initializationPlan = options.initializeProject ? void 0 : await planBuddyProjectInitialization(initializationTarget);
|
|
@@ -6049,7 +5931,7 @@ async function initializeProjectRoute(route, args, io, options, application) {
|
|
|
6049
5931
|
}
|
|
6050
5932
|
async function runRoute(route, args, io, options) {
|
|
6051
5933
|
if (!io.canPrompt) assertNonInteractiveProjectArguments(route, args);
|
|
6052
|
-
const cwd =
|
|
5934
|
+
const cwd = resolve14(options.cwd ?? process.cwd());
|
|
6053
5935
|
const name = await textAnswer(io, args.name, "--name", "\u642D\u5B50\u540D\u79F0", void 0, BUDDY_PROFILE_TEXT_LIMITS.name);
|
|
6054
5936
|
const tagline = await textAnswer(
|
|
6055
5937
|
io,
|
|
@@ -6077,7 +5959,7 @@ async function runRoute(route, args, io, options) {
|
|
|
6077
5959
|
"\u9879\u76EE\u76EE\u5F55",
|
|
6078
5960
|
defaultProjectDirectory(name)
|
|
6079
5961
|
);
|
|
6080
|
-
const rootDirectory =
|
|
5962
|
+
const rootDirectory = resolve14(cwd, directoryInput);
|
|
6081
5963
|
await assertInitializableBuddyTarget(rootDirectory);
|
|
6082
5964
|
const plan = await planBuddyDraftInitialization(rootDirectory);
|
|
6083
5965
|
const existingBuddyId = plan.existingManifest?.buddyId;
|
|
@@ -6111,11 +5993,11 @@ async function runRoute(route, args, io, options) {
|
|
|
6111
5993
|
return { ...result, route: "create", draft, buddyId };
|
|
6112
5994
|
}
|
|
6113
5995
|
async function resumeProjectArguments(args, cwd, options) {
|
|
6114
|
-
const root =
|
|
5996
|
+
const root = resolve14(cwd, args.directory?.trim() || ".");
|
|
6115
5997
|
await assertInitializableBuddyTarget(root);
|
|
6116
5998
|
let entry;
|
|
6117
5999
|
try {
|
|
6118
|
-
entry = await lstat10(
|
|
6000
|
+
entry = await lstat10(join12(root, "buddy.agent.json"));
|
|
6119
6001
|
} catch (cause) {
|
|
6120
6002
|
if (cause.code === "ENOENT") return;
|
|
6121
6003
|
throw cause;
|
|
@@ -6144,7 +6026,7 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
6144
6026
|
try {
|
|
6145
6027
|
const [command, ...rest] = args;
|
|
6146
6028
|
if (!command) {
|
|
6147
|
-
const cwd =
|
|
6029
|
+
const cwd = resolve14(options.cwd ?? process.cwd());
|
|
6148
6030
|
let projectRoot;
|
|
6149
6031
|
try {
|
|
6150
6032
|
projectRoot = await findBuddyProjectRoot(cwd);
|
|
@@ -6172,13 +6054,12 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
6172
6054
|
io.write(HELP2);
|
|
6173
6055
|
return { exitCode: 0 };
|
|
6174
6056
|
}
|
|
6175
|
-
if (command === "models") return runModelsCommand(rest, io);
|
|
6176
|
-
if (command === "widgets") return await runWidgetsCommand(rest, io, options.cwd ?? process.cwd());
|
|
6057
|
+
if (command === "models") return await runModelsCommand(rest, io, options.cwd ?? process.cwd(), options.runtimeCatalog);
|
|
6177
6058
|
if (command === "preview") {
|
|
6178
6059
|
return options.preview?.(rest, io) ?? failure("preview \u5BBF\u4E3B\u672A\u914D\u7F6E", io, true);
|
|
6179
6060
|
}
|
|
6180
6061
|
if (command === "datasets") {
|
|
6181
|
-
return await runDatasetsCommand(rest, io, options.cwd ?? process.cwd());
|
|
6062
|
+
return await runDatasetsCommand(rest, io, options.cwd ?? process.cwd(), options.runtimeCatalog);
|
|
6182
6063
|
}
|
|
6183
6064
|
if (command === "dev") {
|
|
6184
6065
|
return await runDevCommand(rest, io, {
|
|
@@ -6200,11 +6081,11 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
6200
6081
|
}
|
|
6201
6082
|
let route = routeFromMode(parsed.mode);
|
|
6202
6083
|
if (route === void 0 && !io.canPrompt) requireModeForNonInteractive();
|
|
6203
|
-
const cwd =
|
|
6084
|
+
const cwd = resolve14(options.cwd ?? process.cwd());
|
|
6204
6085
|
await assertInitializableBuddyTarget(cwd);
|
|
6205
6086
|
if (parsed.directory !== void 0) {
|
|
6206
6087
|
if (!parsed.directory.trim()) throw new CliUsageError("--directory \u4E0D\u80FD\u4E3A\u7A7A");
|
|
6207
|
-
await assertInitializableBuddyTarget(
|
|
6088
|
+
await assertInitializableBuddyTarget(resolve14(cwd, parsed.directory));
|
|
6208
6089
|
}
|
|
6209
6090
|
await authenticate(options);
|
|
6210
6091
|
await resumeProjectArguments(parsed, cwd, options);
|
|
@@ -6346,7 +6227,6 @@ export {
|
|
|
6346
6227
|
assertOutsideBuddyProject,
|
|
6347
6228
|
buddyAgentConfig,
|
|
6348
6229
|
buildAgentEnvironment,
|
|
6349
|
-
checkWidgetDelivery,
|
|
6350
6230
|
combineBuddyProject,
|
|
6351
6231
|
createBuddyConfig,
|
|
6352
6232
|
createBuddyDevStarter,
|
|
@@ -6357,6 +6237,7 @@ export {
|
|
|
6357
6237
|
isAbortLike,
|
|
6358
6238
|
isSafeProjectRelativePath,
|
|
6359
6239
|
isWindowsReservedPathSegment,
|
|
6240
|
+
latestRuntimeTemplate,
|
|
6360
6241
|
normalizePlatformUrl,
|
|
6361
6242
|
openExternalUrl,
|
|
6362
6243
|
parseBuddyAgentConfig,
|
|
@@ -6384,7 +6265,6 @@ export {
|
|
|
6384
6265
|
throwIfDevAborted,
|
|
6385
6266
|
validateBuddyAgentConfig,
|
|
6386
6267
|
validateBuddyConfig,
|
|
6387
|
-
validateBuddyProjectManifest
|
|
6388
|
-
widgetDeliverySummary
|
|
6268
|
+
validateBuddyProjectManifest
|
|
6389
6269
|
};
|
|
6390
6270
|
//# sourceMappingURL=core.js.map
|