@my-life-buddies/cli 0.21.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -44
- package/dist/bin/buddy.js +15 -11
- package/dist/bin/buddy.js.map +3 -3
- package/dist/bin/core.js +481 -548
- package/dist/bin/core.js.map +4 -4
- package/package.json +5 -4
package/dist/bin/core.js
CHANGED
|
@@ -1,6 +1,233 @@
|
|
|
1
|
+
// packages/cli-core/src/dev/project-env.ts
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { open, rename, unlink } from "node:fs/promises";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { parseEnv } from "node:util";
|
|
7
|
+
|
|
8
|
+
// packages/cli-core/src/platform-url.ts
|
|
9
|
+
var DEFAULT_MLB_TEST_URL = "https://47.116.168.81";
|
|
10
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
11
|
+
function isLegacyEcsGateway(value) {
|
|
12
|
+
try {
|
|
13
|
+
const url = new URL(value);
|
|
14
|
+
return !url.username && !url.password && !url.search && !url.hash && url.pathname === "/" && ["http://47.116.168.81:8788", "http://47.116.168.81"].includes(url.origin);
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function normalizePlatformUrl(value) {
|
|
20
|
+
const url = new URL(value);
|
|
21
|
+
if (url.username || url.password || url.search || url.hash) {
|
|
22
|
+
throw new TypeError("\u5E73\u53F0\u5730\u5740\u4E0D\u80FD\u5305\u542B credentials\u3001query \u6216 fragment");
|
|
23
|
+
}
|
|
24
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname))) {
|
|
25
|
+
throw new TypeError(`\u5E73\u53F0\u5730\u5740\u5FC5\u987B\u4F7F\u7528 HTTPS\uFF1BHTTP \u4EC5\u5141\u8BB8\u672C\u673A\u5F00\u53D1`);
|
|
26
|
+
}
|
|
27
|
+
if (!url.pathname.endsWith("/")) url.pathname += "/";
|
|
28
|
+
return url;
|
|
29
|
+
}
|
|
30
|
+
function resolvePlatformUrl(options = {}) {
|
|
31
|
+
const env = options.env ?? process.env;
|
|
32
|
+
const target = new URL(DEFAULT_MLB_TEST_URL);
|
|
33
|
+
const settings = {
|
|
34
|
+
"--app-server": options.override,
|
|
35
|
+
MLB_GATEWAY_URL: env.MLB_GATEWAY_URL,
|
|
36
|
+
BUDDY_APP_SERVER_URL: env.BUDDY_APP_SERVER_URL,
|
|
37
|
+
BUDDY_DEV_APP_SERVER_URL: env.BUDDY_DEV_APP_SERVER_URL
|
|
38
|
+
};
|
|
39
|
+
for (const [name, value] of Object.entries(settings)) {
|
|
40
|
+
if (value === void 0) continue;
|
|
41
|
+
let url;
|
|
42
|
+
try {
|
|
43
|
+
url = normalizePlatformUrl(isLegacyEcsGateway(value) ? target : value);
|
|
44
|
+
} catch {
|
|
45
|
+
throw new TypeError(`${name} \u65E0\u6548\uFF1B\u6B63\u5F0F\u7248 buddy-cli \u56FA\u5B9A\u8FDE\u63A5 ${DEFAULT_MLB_TEST_URL}\u3002${name === "--app-server" ? "\u8BF7\u79FB\u9664 --app-server \u53C2\u6570" : `\u8BF7 unset ${name}`} \u540E\u91CD\u8BD5\u3002`);
|
|
46
|
+
}
|
|
47
|
+
if (url.href !== target.href) {
|
|
48
|
+
throw new TypeError(`${name} \u4E0E\u6B63\u5F0F\u7248\u5E73\u53F0\u4E0D\u4E00\u81F4\uFF1Bbuddy-cli \u56FA\u5B9A\u8FDE\u63A5 ECS Test\uFF08${DEFAULT_MLB_TEST_URL}\uFF09\u3002\u8BF7\u79FB\u9664\u51B2\u7A81\u53C2\u6570\u6216\u73AF\u5883\u53D8\u91CF\uFF1B\u5176\u4ED6\u73AF\u5883\u7684\u5DE5\u7A0B\u8BF7\u4F7F\u7528\u5BF9\u5E94 CLI\uFF0C\u4E0D\u8981\u590D\u5236\u5176 Token\u3002`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
resolveDeveloperWebUrl(target, env.BUDDY_DEVELOPER_WEB_URL);
|
|
52
|
+
return target;
|
|
53
|
+
}
|
|
54
|
+
function resolveDeveloperWebUrl(platformUrl, override) {
|
|
55
|
+
const target = new URL("/developer/", DEFAULT_MLB_TEST_URL);
|
|
56
|
+
let url;
|
|
57
|
+
try {
|
|
58
|
+
url = normalizePlatformUrl(override ?? target);
|
|
59
|
+
} catch {
|
|
60
|
+
throw new TypeError("\u5F00\u53D1\u8005\u540E\u53F0\u5730\u5740\u65E0\u6548\uFF0C\u8BF7\u79FB\u9664 BUDDY_DEVELOPER_WEB_URL / --developer-web \u540E\u91CD\u8BD5\u3002");
|
|
61
|
+
}
|
|
62
|
+
if (platformUrl.href !== new URL(DEFAULT_MLB_TEST_URL).href || url.href !== target.href) {
|
|
63
|
+
throw new TypeError("\u5F00\u53D1\u8005\u540E\u53F0\u4E0E\u6B63\u5F0F\u7248\u56FA\u5B9A\u5E73\u53F0\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u79FB\u9664 BUDDY_DEVELOPER_WEB_URL / --developer-web\uFF1B\u6B63\u5F0F\u7248\u53EA\u8FDE\u63A5 ECS Test \u7684 /developer/\u3002");
|
|
64
|
+
}
|
|
65
|
+
return target;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// packages/cli-core/src/dev/errors.ts
|
|
69
|
+
var BuddyDevError = class extends Error {
|
|
70
|
+
/** Only explicitly safe, developer-facing explanations may be shown in Preview. */
|
|
71
|
+
publicMessage;
|
|
72
|
+
code;
|
|
73
|
+
phase;
|
|
74
|
+
retryable;
|
|
75
|
+
constructor(options) {
|
|
76
|
+
super(options.message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
77
|
+
this.name = "BuddyDevError";
|
|
78
|
+
this.publicMessage = options.publicMessage;
|
|
79
|
+
this.code = options.code;
|
|
80
|
+
this.phase = options.phase;
|
|
81
|
+
this.retryable = options.retryable ?? false;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
function isAbortLike(error2) {
|
|
85
|
+
return error2 instanceof DOMException && error2.name === "AbortError" || error2 instanceof Error && error2.name === "AbortError";
|
|
86
|
+
}
|
|
87
|
+
function abortedDevError(signal) {
|
|
88
|
+
return new BuddyDevError({
|
|
89
|
+
code: "DEV_ABORTED",
|
|
90
|
+
phase: "stop",
|
|
91
|
+
message: "\u642D\u642D DEV \u542F\u52A8\u5DF2\u53D6\u6D88\u3002",
|
|
92
|
+
...signal?.reason === void 0 ? {} : { cause: signal.reason }
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function throwIfDevAborted(signal) {
|
|
96
|
+
if (signal?.aborted) throw abortedDevError(signal);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// packages/cli-core/src/dev/project-env.ts
|
|
100
|
+
function invalid(message) {
|
|
101
|
+
return new BuddyDevError({ code: "DEV_CONFIG_INVALID", phase: "config", message, publicMessage: message });
|
|
102
|
+
}
|
|
103
|
+
async function readLocalFile(path) {
|
|
104
|
+
let file;
|
|
105
|
+
try {
|
|
106
|
+
file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
107
|
+
const stat2 = await file.stat();
|
|
108
|
+
if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > 256 * 1024) throw invalid("\u672C\u5730\u914D\u7F6E\u5FC5\u987B\u662F\u5C0F\u4E8E 256 KB \u7684\u666E\u901A\u6587\u4EF6\uFF0C\u4E0D\u80FD\u4F7F\u7528\u94FE\u63A5\u3002");
|
|
109
|
+
return await file.readFile("utf8");
|
|
110
|
+
} catch (cause) {
|
|
111
|
+
if (cause.code === "ENOENT") return "";
|
|
112
|
+
if (cause instanceof BuddyDevError) throw cause;
|
|
113
|
+
throw invalid("\u65E0\u6CD5\u8BFB\u53D6\u5DE5\u7A0B\u672C\u5730\u914D\u7F6E\uFF0C\u8BF7\u68C0\u67E5 .env \u548C .gitignore \u7684\u6587\u4EF6\u7C7B\u578B\u4E0E\u6743\u9650\u3002");
|
|
114
|
+
} finally {
|
|
115
|
+
await file?.close();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function readProjectEnvironment(projectRoot) {
|
|
119
|
+
const source = await readLocalFile(join(projectRoot, ".env"));
|
|
120
|
+
let values;
|
|
121
|
+
try {
|
|
122
|
+
values = parseEnv(source);
|
|
123
|
+
} catch {
|
|
124
|
+
throw invalid("\u5DE5\u7A0B .env \u683C\u5F0F\u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002");
|
|
125
|
+
}
|
|
126
|
+
return values;
|
|
127
|
+
}
|
|
128
|
+
function gatewayNeedsRefresh(value, gatewayUrl) {
|
|
129
|
+
if (value) {
|
|
130
|
+
if (isLegacyEcsGateway(value)) {
|
|
131
|
+
if (gatewayUrl.href === `${DEFAULT_MLB_TEST_URL}/`) return true;
|
|
132
|
+
throw invalid(".env \u4FDD\u5B58\u7684\u662F\u65E7\u516C\u5171\u73AF\u5883\u5730\u5740\uFF0C\u4E0E\u672C\u6B21\u5E73\u53F0\u4E0D\u540C\uFF1B\u8BF7\u4F7F\u7528\u5BF9\u5E94\u73AF\u5883\u7684 CLI\u3002\u8FC1\u79FB\u5230\u516C\u5171\u5E73\u53F0\u65F6\uFF0C\u8BF7\u5728\u65B0\u76EE\u5F55\u7528\u6B63\u5F0F CLI \u91CD\u65B0\u767B\u8BB0\u642D\u5B50\uFF0C\u518D\u590D\u5236\u4E1A\u52A1\u4EE3\u7801\uFF1B\u4E0D\u8981\u590D\u5236 .env\u3001buddyId \u6216\u51ED\u636E\u3002");
|
|
133
|
+
}
|
|
134
|
+
let gateway;
|
|
135
|
+
try {
|
|
136
|
+
gateway = normalizePlatformUrl(value);
|
|
137
|
+
} catch {
|
|
138
|
+
throw invalid(".env \u4E2D\u7684 MLB_GATEWAY_URL \u65E0\u6548\uFF1B\u8BF7\u4FEE\u6B63\u5730\u5740\uFF1B--refresh-token \u53EA\u80FD\u5237\u65B0\u540C\u4E00\u73AF\u5883\u7684\u51ED\u636E\uFF0C\u4E0D\u80FD\u5207\u6362\u5E73\u53F0\u3002");
|
|
139
|
+
}
|
|
140
|
+
if (gateway.href !== gatewayUrl.href) throw invalid(".env \u7684\u5E73\u53F0\u5730\u5740\u4E0E\u672C\u6B21\u542F\u52A8\u4E0D\u540C\uFF1B\u8BF7\u4F7F\u7528\u5BF9\u5E94\u73AF\u5883\u7684 CLI\u3002\u8FC1\u79FB\u5230\u516C\u5171\u5E73\u53F0\u65F6\uFF0C\u8BF7\u5728\u65B0\u76EE\u5F55\u7528\u6B63\u5F0F CLI \u91CD\u65B0\u767B\u8BB0\u642D\u5B50\uFF0C\u518D\u590D\u5236\u4E1A\u52A1\u4EE3\u7801\uFF1B\u4E0D\u8981\u590D\u5236 .env\u3001buddyId \u6216\u51ED\u636E\u3002--refresh-token \u4E0D\u80FD\u5207\u6362\u5E73\u53F0\u3002");
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
async function checkProjectGateway(projectRoot, gatewayUrl, options = {}) {
|
|
145
|
+
const values = await readProjectEnvironment(projectRoot);
|
|
146
|
+
if (gatewayNeedsRefresh(values.MLB_GATEWAY_URL, gatewayUrl)) {
|
|
147
|
+
options.report?.("\u68C0\u6D4B\u5230\u5DE5\u7A0B\u4F7F\u7528\u65E7 ECS \u5730\u5740\uFF1B\u542F\u52A8 DEV \u65F6\u5C06\u6821\u9A8C\u642D\u5B50\u5F52\u5C5E\uFF0C\u5E76\u81EA\u52A8\u66F4\u65B0\u5730\u5740\u548C\u5F00\u53D1\u51ED\u636E\u3002");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function projectBuddyToken(projectRoot, gatewayUrl) {
|
|
151
|
+
const values = await readProjectEnvironment(projectRoot);
|
|
152
|
+
if (gatewayNeedsRefresh(values.MLB_GATEWAY_URL, gatewayUrl) || !values.BUDDY_TOKEN) return void 0;
|
|
153
|
+
if (!values.BUDDY_TOKEN.trim() || /[\u0000-\u001f\u007f]/u.test(values.BUDDY_TOKEN)) throw invalid(".env \u4E2D\u7684\u5F00\u53D1\u4EE4\u724C\u683C\u5F0F\u65E0\u6548\uFF0C\u8BF7\u4F7F\u7528 --refresh-token \u91CD\u65B0\u9886\u53D6\u3002");
|
|
154
|
+
return values.BUDDY_TOKEN;
|
|
155
|
+
}
|
|
156
|
+
function quote(value) {
|
|
157
|
+
if (/[\u0000-\u001f\u007f]/u.test(value)) throw invalid("\u672C\u5730\u8FD0\u884C\u914D\u7F6E\u4E0D\u80FD\u5305\u542B\u63A7\u5236\u5B57\u7B26\u3002");
|
|
158
|
+
const delimiter = ["'", '"', "`"].find((character) => !value.includes(character));
|
|
159
|
+
if (!delimiter) throw invalid("\u672C\u5730\u8FD0\u884C\u914D\u7F6E\u5305\u542B\u65E0\u6CD5\u5199\u5165 .env \u7684\u5F15\u53F7\u7EC4\u5408\u3002");
|
|
160
|
+
return `${delimiter}${value}${delimiter}`;
|
|
161
|
+
}
|
|
162
|
+
function updateValues(source, values) {
|
|
163
|
+
const assignment = /^[\t ]*(?:export[\t ]+)?([A-Za-z_][A-Za-z0-9_]*)[\t ]*=[\t ]*/gm;
|
|
164
|
+
let output = "", cursor = 0, match;
|
|
165
|
+
const written = /* @__PURE__ */ new Set();
|
|
166
|
+
while (match = assignment.exec(source)) {
|
|
167
|
+
const valueStart = assignment.lastIndex;
|
|
168
|
+
let end = source.indexOf("\n", valueStart);
|
|
169
|
+
if (end < 0) end = source.length;
|
|
170
|
+
let commentStart = valueStart;
|
|
171
|
+
const delimiter = source[valueStart];
|
|
172
|
+
if (delimiter && ["'", '"', "`"].includes(delimiter)) {
|
|
173
|
+
const close = source.indexOf(delimiter, valueStart + 1);
|
|
174
|
+
if (close < 0) throw invalid(".env \u4E2D\u6709\u672A\u95ED\u5408\u7684\u5F15\u53F7\uFF0C\u8BF7\u4FEE\u6B63\u540E\u91CD\u8BD5\u3002");
|
|
175
|
+
commentStart = close + 1;
|
|
176
|
+
end = source.indexOf("\n", close + 1);
|
|
177
|
+
if (end < 0) end = source.length;
|
|
178
|
+
}
|
|
179
|
+
assignment.lastIndex = end;
|
|
180
|
+
const name = match[1];
|
|
181
|
+
if (!(name in values)) continue;
|
|
182
|
+
const comment = source.slice(commentStart, end).match(/[\t ]*#[^\r\n]*/u)?.[0] ?? "";
|
|
183
|
+
output += source.slice(cursor, match.index);
|
|
184
|
+
output += written.has(name) || values[name] === void 0 ? comment : `${name}=${quote(values[name])}${comment ? ` ${comment.trimStart()}` : ""}`;
|
|
185
|
+
if (source[end - 1] === "\r") output += "\r";
|
|
186
|
+
cursor = end;
|
|
187
|
+
written.add(name);
|
|
188
|
+
}
|
|
189
|
+
output += source.slice(cursor);
|
|
190
|
+
const newline = source.includes("\r\n") ? "\r\n" : "\n";
|
|
191
|
+
for (const [name, value] of Object.entries(values)) if (value !== void 0 && !written.has(name)) {
|
|
192
|
+
if (output && !output.endsWith("\n")) output += newline;
|
|
193
|
+
output += `${name}=${quote(value)}${newline}`;
|
|
194
|
+
}
|
|
195
|
+
const parsed = parseEnv(output);
|
|
196
|
+
if (Object.entries(values).some(([name, value]) => parsed[name] !== value)) throw invalid("\u65E0\u6CD5\u5B8C\u6574\u66F4\u65B0 .env\uFF0C\u8BF7\u68C0\u67E5\u6587\u4EF6\u683C\u5F0F\u3002");
|
|
197
|
+
return output;
|
|
198
|
+
}
|
|
199
|
+
async function replaceFile(path, contents, mode) {
|
|
200
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
201
|
+
let file;
|
|
202
|
+
try {
|
|
203
|
+
file = await open(temporary, "wx", mode);
|
|
204
|
+
await file.writeFile(contents, "utf8");
|
|
205
|
+
await file.sync();
|
|
206
|
+
await file.close();
|
|
207
|
+
file = void 0;
|
|
208
|
+
await rename(temporary, path);
|
|
209
|
+
} finally {
|
|
210
|
+
await file?.close();
|
|
211
|
+
await unlink(temporary).catch((cause) => {
|
|
212
|
+
if (cause.code !== "ENOENT") throw cause;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async function writeProjectEnvironment(projectRoot, values) {
|
|
217
|
+
const envPath = join(projectRoot, ".env"), ignorePath = join(projectRoot, ".gitignore");
|
|
218
|
+
const contents = updateValues(await readLocalFile(envPath), { ...values, BUDDY_ID: void 0 });
|
|
219
|
+
const ignored = await readLocalFile(ignorePath);
|
|
220
|
+
if (ignored.trimEnd().split(/\r?\n/u).at(-1) !== "/.env") {
|
|
221
|
+
await replaceFile(ignorePath, `${ignored}${ignored && !ignored.endsWith("\n") ? "\n" : ""}/.env
|
|
222
|
+
`, 420);
|
|
223
|
+
}
|
|
224
|
+
await replaceFile(envPath, contents, 384);
|
|
225
|
+
return contents;
|
|
226
|
+
}
|
|
227
|
+
|
|
1
228
|
// packages/cli-core/src/config/runtime-update.ts
|
|
2
229
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
3
|
-
import { join as
|
|
230
|
+
import { join as join3 } from "node:path";
|
|
4
231
|
|
|
5
232
|
// packages/cli-core/src/config/runtime-dependency.ts
|
|
6
233
|
var BUDDY_RUNTIME_PACKAGE = "@my-life-buddies/buddy-runtime";
|
|
@@ -23,54 +250,28 @@ function runtimeUsesEnvironmentIdentity(pkg) {
|
|
|
23
250
|
|
|
24
251
|
// packages/cli-core/src/config/runtime-package.ts
|
|
25
252
|
import { execFile } from "node:child_process";
|
|
26
|
-
import { lstat, mkdir, mkdtemp, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
253
|
+
import { lstat, mkdir, mkdtemp, readFile, rename as rename2, rm, writeFile } from "node:fs/promises";
|
|
27
254
|
import { homedir } from "node:os";
|
|
28
|
-
import { join } from "node:path";
|
|
255
|
+
import { join as join2 } from "node:path";
|
|
29
256
|
import { promisify } from "node:util";
|
|
30
257
|
var RUNTIME_REGISTRY = "https://registry.npmjs.org/";
|
|
31
258
|
var execute = promisify(execFile);
|
|
32
259
|
async function latestRuntimeVersion(options = {}) {
|
|
33
|
-
return resolveRuntimeVersion("latest", options);
|
|
34
|
-
}
|
|
35
|
-
async function runtimeMetadata(suffix, options) {
|
|
36
260
|
options.signal?.throwIfAborted();
|
|
37
261
|
const timeout = AbortSignal.timeout(1e4);
|
|
38
262
|
const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
|
|
39
|
-
const response = await (options.fetch ?? globalThis.fetch)(`${RUNTIME_REGISTRY}${encodeURIComponent(BUDDY_RUNTIME_PACKAGE)}
|
|
263
|
+
const response = await (options.fetch ?? globalThis.fetch)(`${RUNTIME_REGISTRY}${encodeURIComponent(BUDDY_RUNTIME_PACKAGE)}/latest`, {
|
|
40
264
|
signal,
|
|
41
265
|
headers: { Accept: "application/json" },
|
|
42
266
|
redirect: "error"
|
|
43
267
|
});
|
|
44
268
|
if (!response.ok) throw new Error(`npm \u8FD4\u56DE HTTP ${response.status}`);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (!isExactRuntimeVersion(selector) && selector !== "latest" && selector !== "dev") {
|
|
49
|
-
throw new Error("Runtime \u7248\u672C\u5FC5\u987B\u662F\u51C6\u786E\u7248\u672C\u3001latest \u6216 dev\uFF0C\u4E0D\u80FD\u4F7F\u7528\u8303\u56F4\u3001\u8DEF\u5F84\u6216 URL");
|
|
50
|
-
}
|
|
51
|
-
const metadata = await runtimeMetadata(`/${encodeURIComponent(selector)}`, options);
|
|
52
|
-
if (metadata?.name !== BUDDY_RUNTIME_PACKAGE || !isExactRuntimeVersion(metadata.version) || selector === "latest" && metadata.version.includes("-") || isExactRuntimeVersion(selector) && metadata.version !== selector) {
|
|
53
|
-
throw new Error(`npm ${selector} \u672A\u8FD4\u56DE\u6B64 Runtime \u7684\u51C6\u786E${selector === "latest" ? "\u7A33\u5B9A" : ""}\u7248\u672C`);
|
|
269
|
+
const metadata = await response.json();
|
|
270
|
+
if (metadata?.name !== BUDDY_RUNTIME_PACKAGE || !isExactRuntimeVersion(metadata.version) || metadata.version.includes("-")) {
|
|
271
|
+
throw new Error("npm latest \u672A\u8FD4\u56DE\u6B64 Runtime \u7684\u51C6\u786E\u7A33\u5B9A\u7248\u672C");
|
|
54
272
|
}
|
|
55
273
|
return metadata.version;
|
|
56
274
|
}
|
|
57
|
-
async function runtimeReleaseChoices(options = {}) {
|
|
58
|
-
const metadata = await runtimeMetadata("", options);
|
|
59
|
-
const latest = metadata?.["dist-tags"]?.latest;
|
|
60
|
-
const dev = metadata?.["dist-tags"]?.dev;
|
|
61
|
-
if (metadata?.name !== BUDDY_RUNTIME_PACKAGE || !isExactRuntimeVersion(latest) || latest.includes("-") || !metadata.versions || !(latest in metadata.versions)) throw new Error("npm \u672A\u8FD4\u56DE\u6709\u6548\u7684 Runtime \u7248\u672C\u5217\u8868");
|
|
62
|
-
const versions = Object.keys(metadata.versions).filter(isExactRuntimeVersion).sort((a, b) => b.localeCompare(a, "en", { numeric: true }));
|
|
63
|
-
return { latest, ...isExactRuntimeVersion(dev) && dev in metadata.versions ? { dev } : {}, versions };
|
|
64
|
-
}
|
|
65
|
-
async function runtimeSelectionPrompt(options = {}) {
|
|
66
|
-
const releases = await runtimeReleaseChoices(options);
|
|
67
|
-
return [
|
|
68
|
-
"\u8BF7\u5148\u8BE2\u95EE\u5F00\u53D1\u8005\u9009\u62E9 Runtime \u7248\u672C\uFF0C\u518D\u4F20 --runtime-version <\u51C6\u786E\u7248\u672C|latest|dev>\uFF1B\u4E0D\u8981\u66FF\u5F00\u53D1\u8005\u9ED8\u8BA4\u9009\u62E9\u3002",
|
|
69
|
-
`\u6700\u65B0\u7A33\u5B9A\u7248\uFF08\u63A8\u8350\uFF09\uFF1A${releases.latest}\uFF08latest\uFF09`,
|
|
70
|
-
...releases.dev ? [`\u6700\u65B0\u6D4B\u8BD5\u7248\uFF1A${releases.dev}\uFF08dev\uFF09`] : [],
|
|
71
|
-
`\u5176\u4ED6\u5DF2\u53D1\u5E03\u7248\u672C\uFF1A${releases.versions.join("\u3001")}`
|
|
72
|
-
].join("\n");
|
|
73
|
-
}
|
|
74
275
|
async function cachedLatestRuntimeRoot(options = {}) {
|
|
75
276
|
options.report?.("\u6B63\u5728\u67E5\u8BE2\u516C\u5171 npm \u7684\u6700\u65B0 Runtime\u2026");
|
|
76
277
|
const version = await latestRuntimeVersion(options);
|
|
@@ -78,8 +279,8 @@ async function cachedLatestRuntimeRoot(options = {}) {
|
|
|
78
279
|
}
|
|
79
280
|
async function cachedRuntimeRoot(version, options = {}) {
|
|
80
281
|
if (!isExactRuntimeVersion(version)) throw new Error("Runtime \u7F13\u5B58\u9700\u8981\u51C6\u786E\u7248\u672C");
|
|
81
|
-
const cache = options.cacheDirectory ??
|
|
82
|
-
const destination =
|
|
282
|
+
const cache = options.cacheDirectory ?? join2(homedir(), ".cache", "buddy-cli", "runtimes");
|
|
283
|
+
const destination = join2(cache, version);
|
|
83
284
|
let cacheExists = false;
|
|
84
285
|
try {
|
|
85
286
|
await lstat(destination);
|
|
@@ -89,8 +290,8 @@ async function cachedRuntimeRoot(version, options = {}) {
|
|
|
89
290
|
}
|
|
90
291
|
if (cacheExists) {
|
|
91
292
|
try {
|
|
92
|
-
const pkg = JSON.parse(await readFile(
|
|
93
|
-
const installed2 = JSON.parse(await readFile(
|
|
293
|
+
const pkg = JSON.parse(await readFile(join2(destination, "package.json"), "utf8"));
|
|
294
|
+
const installed2 = JSON.parse(await readFile(join2(destination, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"), "utf8"));
|
|
94
295
|
if (runtimeDependencyVersion(pkg) === version && installed2.version === version) return destination;
|
|
95
296
|
throw new Error("\u7F13\u5B58\u7248\u672C\u4E0D\u5339\u914D");
|
|
96
297
|
} catch (cause) {
|
|
@@ -98,15 +299,15 @@ async function cachedRuntimeRoot(version, options = {}) {
|
|
|
98
299
|
}
|
|
99
300
|
}
|
|
100
301
|
await mkdir(cache, { recursive: true });
|
|
101
|
-
const temporaryRoot = await mkdtemp(
|
|
302
|
+
const temporaryRoot = await mkdtemp(join2(cache, `.install-${version}-`));
|
|
102
303
|
try {
|
|
103
|
-
await writeFile(
|
|
304
|
+
await writeFile(join2(temporaryRoot, "package.json"), JSON.stringify({
|
|
104
305
|
name: "buddy-runtime-catalog",
|
|
105
306
|
private: true,
|
|
106
307
|
type: "module",
|
|
107
308
|
dependencies: { [BUDDY_RUNTIME_PACKAGE]: version }
|
|
108
309
|
}));
|
|
109
|
-
const userConfig =
|
|
310
|
+
const userConfig = join2(temporaryRoot, ".npmrc");
|
|
110
311
|
await writeFile(userConfig, `registry=${RUNTIME_REGISTRY}
|
|
111
312
|
`);
|
|
112
313
|
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`);
|
|
@@ -124,11 +325,11 @@ async function cachedRuntimeRoot(version, options = {}) {
|
|
|
124
325
|
"--fetch-retries=0",
|
|
125
326
|
"--fetch-timeout=20000"
|
|
126
327
|
], { cwd: temporaryRoot, signal: options.signal, timeout: 18e4 });
|
|
127
|
-
const installed2 = JSON.parse(await readFile(
|
|
328
|
+
const installed2 = JSON.parse(await readFile(join2(temporaryRoot, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"), "utf8"));
|
|
128
329
|
if (installed2.version !== version) throw new Error(`\u7F13\u5B58\u7684 Runtime \u7248\u672C\u4E0E\u9009\u5B9A\u7684 ${version} \u4E0D\u4E00\u81F4`);
|
|
129
330
|
options.signal?.throwIfAborted();
|
|
130
331
|
try {
|
|
131
|
-
await
|
|
332
|
+
await rename2(temporaryRoot, destination);
|
|
132
333
|
} catch (cause) {
|
|
133
334
|
if (!["EEXIST", "ENOTEMPTY"].includes(cause.code ?? "")) throw cause;
|
|
134
335
|
}
|
|
@@ -138,68 +339,17 @@ async function cachedRuntimeRoot(version, options = {}) {
|
|
|
138
339
|
}
|
|
139
340
|
}
|
|
140
341
|
|
|
141
|
-
// packages/cli-core/src/platform-url.ts
|
|
142
|
-
var DEFAULT_MLB_TEST_URL = "https://47.116.168.81";
|
|
143
|
-
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
144
|
-
function isLegacyEcsGateway(value) {
|
|
145
|
-
try {
|
|
146
|
-
const url = new URL(value);
|
|
147
|
-
return !url.username && !url.password && !url.search && !url.hash && url.pathname === "/" && ["http://47.116.168.81:8788", "http://47.116.168.81"].includes(url.origin);
|
|
148
|
-
} catch {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
function normalizePlatformUrl(value) {
|
|
153
|
-
const url = new URL(value);
|
|
154
|
-
if (url.username || url.password || url.search || url.hash) {
|
|
155
|
-
throw new TypeError("\u5E73\u53F0\u5730\u5740\u4E0D\u80FD\u5305\u542B credentials\u3001query \u6216 fragment");
|
|
156
|
-
}
|
|
157
|
-
if (url.protocol !== "https:" && !(url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname))) {
|
|
158
|
-
throw new TypeError(`\u5E73\u53F0\u5730\u5740\u5FC5\u987B\u4F7F\u7528 HTTPS\uFF1BHTTP \u4EC5\u5141\u8BB8\u672C\u673A\u5F00\u53D1`);
|
|
159
|
-
}
|
|
160
|
-
if (!url.pathname.endsWith("/")) url.pathname += "/";
|
|
161
|
-
return url;
|
|
162
|
-
}
|
|
163
|
-
function resolvePlatformUrl(options = {}) {
|
|
164
|
-
const env = options.env ?? process.env;
|
|
165
|
-
const legacy = options.development ? env.BUDDY_DEV_APP_SERVER_URL ?? env.BUDDY_APP_SERVER_URL : env.BUDDY_APP_SERVER_URL ?? env.BUDDY_DEV_APP_SERVER_URL;
|
|
166
|
-
const selected = options.override ?? env.MLB_GATEWAY_URL ?? legacy ?? DEFAULT_MLB_TEST_URL;
|
|
167
|
-
const url = normalizePlatformUrl(isLegacyEcsGateway(selected) ? DEFAULT_MLB_TEST_URL : selected);
|
|
168
|
-
if (url.pathname !== "/") throw new TypeError("\u5E73\u53F0\u5730\u5740\u53EA\u9700\u534F\u8BAE\u3001\u57DF\u540D\u548C\u7AEF\u53E3\uFF0C\u4E0D\u5E94\u5305\u542B /cli\u3001/developer \u6216\u5176\u4ED6\u8DEF\u5F84");
|
|
169
|
-
return url;
|
|
170
|
-
}
|
|
171
|
-
function resolveDeveloperWebUrl(platformUrl, override) {
|
|
172
|
-
const url = normalizePlatformUrl(override ?? new URL("/developer/", platformUrl));
|
|
173
|
-
if (url.origin !== platformUrl.origin) {
|
|
174
|
-
throw new TypeError("\u5F00\u53D1\u8005\u540E\u53F0\u4E0E MLB \u7F51\u5173\u5730\u5740\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u79FB\u9664\u6216\u66F4\u65B0 BUDDY_DEVELOPER_WEB_URL / --developer-web\uFF0C\u4F7F\u7528\u540C\u4E00\u5E73\u53F0");
|
|
175
|
-
}
|
|
176
|
-
return url;
|
|
177
|
-
}
|
|
178
|
-
function allowsRuntimeVersionSelection(options = {}) {
|
|
179
|
-
const env = options.env ?? process.env;
|
|
180
|
-
if (!env.MLB_GATEWAY_URL?.trim()) return false;
|
|
181
|
-
const configured = resolvePlatformUrl({ env });
|
|
182
|
-
return configured.origin !== new URL(DEFAULT_MLB_TEST_URL).origin && (options.platformUrl === void 0 || options.platformUrl.origin === configured.origin);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
342
|
// packages/cli-core/src/config/runtime-update.ts
|
|
186
343
|
async function projectRuntimeVersion(root) {
|
|
187
344
|
try {
|
|
188
|
-
return runtimeDependencyVersion(JSON.parse(await readFile2(
|
|
345
|
+
return runtimeDependencyVersion(JSON.parse(await readFile2(join3(root, "package.json"), "utf8")));
|
|
189
346
|
} catch (cause) {
|
|
190
347
|
if (cause.code === "ENOENT") return void 0;
|
|
191
348
|
throw cause;
|
|
192
349
|
}
|
|
193
350
|
}
|
|
194
|
-
async function runtimeVersionStatus(project, latest
|
|
351
|
+
async function runtimeVersionStatus(project, latest) {
|
|
195
352
|
const current = project ? await projectRuntimeVersion(project) : void 0;
|
|
196
|
-
if (selected) return {
|
|
197
|
-
projectRuntimeVersion: current ?? null,
|
|
198
|
-
latestRuntimeVersion: null,
|
|
199
|
-
selectedRuntimeVersion: latest,
|
|
200
|
-
versionStatus: !project ? "no_project" : current === latest ? "selected" : "unconfigured",
|
|
201
|
-
adaptationRequired: !!project && current !== latest
|
|
202
|
-
};
|
|
203
353
|
let versionStatus;
|
|
204
354
|
if (!project) versionStatus = "no_project";
|
|
205
355
|
else if (!current) versionStatus = "unconfigured";
|
|
@@ -219,10 +369,6 @@ async function runtimeVersionStatus(project, latest, selected = false) {
|
|
|
219
369
|
}
|
|
220
370
|
function reportRuntimeVersion(status, report) {
|
|
221
371
|
if (status.versionStatus === "no_project") return;
|
|
222
|
-
if (status.selectedRuntimeVersion !== void 0) {
|
|
223
|
-
report(status.versionStatus === "selected" ? `Runtime \u7248\u672C\uFF1A\u5DE5\u7A0B ${status.projectRuntimeVersion}\uFF0C\u6CBF\u7528\u5DE5\u7A0B\u9009\u5B9A\u7248\u672C\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u5207\u6362\u5230 latest \u6216\u65B0\u7684\u6D4B\u8BD5\u7248\u3002` : `Runtime \u76EE\u5F55\u4F7F\u7528\u9009\u5B9A\u7248\u672C ${status.selectedRuntimeVersion}\uFF1B\u5DE5\u7A0B\u5C1A\u672A\u56FA\u5B9A\u51C6\u786E\u7248\u672C\uFF0C\u751F\u6210\u6216\u5B89\u88C5\u4F9D\u8D56\u540E\u518D\u542F\u52A8 DEV\u3002`);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
372
|
report(`Runtime \u7248\u672C\uFF1A\u5DE5\u7A0B ${status.projectRuntimeVersion ?? "\u672A\u9501\u5B9A\u51C6\u786E\u7248\u672C"}\uFF0Cnpm \u6700\u65B0 ${status.latestRuntimeVersion}\u3002`);
|
|
227
373
|
if (status.adaptationRequired) {
|
|
228
374
|
report("\u8BF7\u7531\u4F60\u6216\u5F00\u53D1 Agent \u66F4\u65B0\u4F9D\u8D56\u5E76\u9002\u914D\uFF1A\u68C0\u67E5\u65B0\u7248 Runtime \u7684\u542F\u52A8\u53C2\u6570\u3001\u6A21\u578B\u3001datasets\u3001\u5DE5\u5177\u53CA Hook\uFF0C\u5B8C\u6210\u9002\u914D\u540E\u9A8C\u8BC1 DEV\u3002CLI \u672A\u4FEE\u6539\u5DE5\u7A0B\u4F9D\u8D56\u6216\u914D\u7F6E\uFF1BDEV \u542F\u52A8\u3001\u81EA\u52A8\u91CD\u8F7D\u548C push \u5FC5\u987B\u901A\u8FC7\u6700\u65B0 Runtime \u68C0\u67E5\u3002");
|
|
@@ -232,69 +378,13 @@ function reportRuntimeVersion(status, report) {
|
|
|
232
378
|
async function checkRuntimeUpdate(root, report, options = {}) {
|
|
233
379
|
options.signal?.throwIfAborted();
|
|
234
380
|
try {
|
|
235
|
-
if (allowsRuntimeVersionSelection(options)) {
|
|
236
|
-
const current = await projectRuntimeVersion(root);
|
|
237
|
-
if (!current) {
|
|
238
|
-
report("\u5DE5\u7A0B\u5C1A\u672A\u56FA\u5B9A Runtime \u51C6\u786E\u7248\u672C\uFF1B\u751F\u6210 Runtime \u5DE5\u7A0B\u524D\u8BF7\u5148\u9009\u62E9\u7248\u672C\u3002\u5DF2\u6709\u5DE5\u7A0B\u8BF7\u4FEE\u6B63\u4F9D\u8D56\u58F0\u660E\u5E76\u5B89\u88C5\u3002");
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
const selected = await resolveRuntimeVersion(current, options);
|
|
242
|
-
reportRuntimeVersion(await runtimeVersionStatus(root, selected, true), report);
|
|
243
|
-
options.signal?.throwIfAborted();
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
381
|
const latest = await latestRuntimeVersion(options);
|
|
247
382
|
const status = await runtimeVersionStatus(root, latest);
|
|
248
383
|
options.signal?.throwIfAborted();
|
|
249
384
|
reportRuntimeVersion(status, report);
|
|
250
385
|
} catch (cause) {
|
|
251
386
|
options.signal?.throwIfAborted();
|
|
252
|
-
report(`\u65E0\u6CD5\u68C0\u67E5 Runtime \u66F4\u65B0\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u672C\u6B21\u672A\u786E\u8BA4
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// packages/cli-core/src/init/runtime-selection.ts
|
|
257
|
-
import { readFile as readFile3 } from "node:fs/promises";
|
|
258
|
-
import { join as join3 } from "node:path";
|
|
259
|
-
var RuntimeSelectionError = class extends Error {
|
|
260
|
-
};
|
|
261
|
-
async function selectInitRuntime(root, requested, io, options = {}) {
|
|
262
|
-
if (!allowsRuntimeVersionSelection(options)) {
|
|
263
|
-
if (requested !== void 0) throw new RuntimeSelectionError("\u672A\u77E5 init \u53C2\u6570 --runtime-version");
|
|
264
|
-
return void 0;
|
|
265
|
-
}
|
|
266
|
-
let pkg;
|
|
267
|
-
try {
|
|
268
|
-
pkg = JSON.parse(await readFile3(join3(root, "package.json"), "utf8"));
|
|
269
|
-
} catch (cause) {
|
|
270
|
-
if (cause.code !== "ENOENT") throw cause;
|
|
271
|
-
}
|
|
272
|
-
const existing = runtimeDependencyVersion(pkg);
|
|
273
|
-
if (pkg?.dependencies?.[BUDDY_RUNTIME_PACKAGE] !== void 0) {
|
|
274
|
-
if (!existing) throw new RuntimeSelectionError("\u5DF2\u6709\u5DE5\u7A0B\u7684 Runtime \u672A\u56FA\u5B9A\u51C6\u786E\u7248\u672C\uFF0C\u8BF7\u5148\u7528 npm install --save-exact \u5B89\u88C5\u9009\u5B9A\u7248\u672C\u5E76\u66F4\u65B0\u9501\u6587\u4EF6\u3002");
|
|
275
|
-
if (requested !== void 0 && requested !== existing) throw new RuntimeSelectionError(`\u5DE5\u7A0B\u5DF2\u56FA\u5B9A Runtime ${existing}\uFF1Binit \u4E0D\u5207\u6362\u5DF2\u6709\u4F9D\u8D56\u3002\u5207\u6362\u7248\u672C\u8BF7\u5148\u5411\u5F00\u53D1\u8005\u786E\u8BA4\uFF0C\u518D\u7528 npm install --save-exact \u5B89\u88C5\u51C6\u786E\u7248\u672C\u5E76\u5B8C\u6210\u9002\u914D\u3002`);
|
|
276
|
-
return existing;
|
|
277
|
-
}
|
|
278
|
-
try {
|
|
279
|
-
let selector = requested;
|
|
280
|
-
if (!selector) {
|
|
281
|
-
if (!io.canPrompt) throw new RuntimeSelectionError(await runtimeSelectionPrompt(options));
|
|
282
|
-
const releases = await runtimeReleaseChoices(options);
|
|
283
|
-
selector = await io.select("\u8FD9\u4E2A\u642D\u5B50\u4F7F\u7528\u54EA\u4E2A Runtime \u7248\u672C\uFF1F", [
|
|
284
|
-
{ value: releases.latest, label: `\u6700\u65B0\u7A33\u5B9A\u7248 ${releases.latest}\uFF08\u63A8\u8350\uFF09` },
|
|
285
|
-
...releases.dev ? [{ value: releases.dev, label: `\u6700\u65B0\u6D4B\u8BD5\u7248 ${releases.dev}` }] : [],
|
|
286
|
-
{ value: "other", label: "\u6307\u5B9A\u5176\u4ED6\u5DF2\u53D1\u5E03\u7248\u672C" }
|
|
287
|
-
]);
|
|
288
|
-
if (selector === "other") {
|
|
289
|
-
io.write(`\u53EF\u7528\u7248\u672C\uFF1A${releases.versions.join("\u3001")}`);
|
|
290
|
-
selector = (await io.input("\u8F93\u5165 Runtime \u7684\u51C6\u786E\u7248\u672C")).trim();
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return await resolveRuntimeVersion(selector, options);
|
|
294
|
-
} catch (cause) {
|
|
295
|
-
options.signal?.throwIfAborted();
|
|
296
|
-
if (cause instanceof RuntimeSelectionError || cause instanceof Error && cause.name === "PromptCancelledError") throw cause;
|
|
297
|
-
throw new RuntimeSelectionError(`\u65E0\u6CD5\u9009\u62E9 Runtime\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u8BF7\u4FEE\u590D\u540E\u91CD\u8BD5\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u9009\u62E9\u5176\u4ED6\u7248\u672C\u3002`);
|
|
387
|
+
report(`\u65E0\u6CD5\u68C0\u67E5 Runtime \u66F4\u65B0\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u672C\u6B21\u672A\u786E\u8BA4\u662F\u5426\u4E3A\u6700\u65B0\u6B63\u5F0F\u7248\uFF1B\u53EF\u7EE7\u7EED\u67E5\u770B\u6216\u4FEE\u6539\u5DE5\u7A0B\uFF0CDEV \u542F\u52A8\u548C push \u4F1A\u53E6\u884C\u4E25\u683C\u68C0\u67E5\u3002`);
|
|
298
388
|
}
|
|
299
389
|
}
|
|
300
390
|
|
|
@@ -302,13 +392,13 @@ async function selectInitRuntime(root, requested, io, options = {}) {
|
|
|
302
392
|
import { resolve as resolve6 } from "node:path";
|
|
303
393
|
|
|
304
394
|
// packages/cli-core/src/config/runtime-catalog.ts
|
|
305
|
-
import { readFile as
|
|
395
|
+
import { readFile as readFile3, realpath } from "node:fs/promises";
|
|
306
396
|
import { createRequire } from "node:module";
|
|
307
397
|
import { resolve } from "node:path";
|
|
308
398
|
import { pathToFileURL } from "node:url";
|
|
309
399
|
async function loadRuntime(projectRoot) {
|
|
310
400
|
const packagePath = resolve(projectRoot, "package.json");
|
|
311
|
-
const expected = runtimeDependencyVersion(JSON.parse(await
|
|
401
|
+
const expected = runtimeDependencyVersion(JSON.parse(await readFile3(packagePath, "utf8")));
|
|
312
402
|
if (!expected) throw new Error(`package.json \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
|
|
313
403
|
const projectRequire = createRequire(packagePath);
|
|
314
404
|
let runtimePath;
|
|
@@ -317,7 +407,7 @@ async function loadRuntime(projectRoot) {
|
|
|
317
407
|
if (await realpath(projectRequire.resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`)) !== installedPath) {
|
|
318
408
|
throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
|
|
319
409
|
}
|
|
320
|
-
const installed2 = JSON.parse(await
|
|
410
|
+
const installed2 = JSON.parse(await readFile3(installedPath, "utf8"));
|
|
321
411
|
if (installed2.version !== expected) throw new Error(`\u5DF2\u5B89\u88C5 ${installed2.version}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
|
|
322
412
|
runtimePath = projectRequire.resolve(BUDDY_RUNTIME_PACKAGE);
|
|
323
413
|
} catch (cause) {
|
|
@@ -368,7 +458,7 @@ async function validateRuntimeDatasets(projectRoot, requirements = []) {
|
|
|
368
458
|
}
|
|
369
459
|
|
|
370
460
|
// packages/cli-core/src/project-context.ts
|
|
371
|
-
import { lstat as lstat7, realpath as realpath3, readFile as
|
|
461
|
+
import { lstat as lstat7, realpath as realpath3, readFile as readFile10 } from "node:fs/promises";
|
|
372
462
|
import { dirname, join as join10, resolve as resolve5 } from "node:path";
|
|
373
463
|
|
|
374
464
|
// packages/cli-core/src/config/index.ts
|
|
@@ -376,13 +466,13 @@ import {
|
|
|
376
466
|
link,
|
|
377
467
|
lstat as lstat6,
|
|
378
468
|
mkdir as mkdir6,
|
|
379
|
-
open as
|
|
380
|
-
readFile as
|
|
469
|
+
open as open4,
|
|
470
|
+
readFile as readFile9,
|
|
381
471
|
readdir as readdir3,
|
|
382
|
-
rename as
|
|
383
|
-
unlink as
|
|
472
|
+
rename as rename7,
|
|
473
|
+
unlink as unlink5
|
|
384
474
|
} from "node:fs/promises";
|
|
385
|
-
import { randomUUID as
|
|
475
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
386
476
|
import { isAbsolute as isAbsolute2, join as join9, resolve as resolve4, win32 } from "node:path";
|
|
387
477
|
import { isDeepStrictEqual } from "node:util";
|
|
388
478
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
@@ -407,13 +497,13 @@ var buddy_package_schema_default = {
|
|
|
407
497
|
};
|
|
408
498
|
|
|
409
499
|
// packages/cli-core/src/init/meta.ts
|
|
410
|
-
import { createHash, randomUUID as
|
|
411
|
-
import { lstat as lstat3, mkdir as mkdir4, readFile as
|
|
500
|
+
import { createHash, randomUUID as randomUUID3 } from "node:crypto";
|
|
501
|
+
import { lstat as lstat3, mkdir as mkdir4, readFile as readFile6, readdir as readdir2, rename as rename5, unlink as unlink3, writeFile as writeFile4 } from "node:fs/promises";
|
|
412
502
|
import { join as join6, resolve as resolve2 } from "node:path";
|
|
413
503
|
|
|
414
504
|
// packages/cli-core/src/init/skill-package.ts
|
|
415
505
|
import { execFile as execFile2 } from "node:child_process";
|
|
416
|
-
import { lstat as lstat2, mkdir as mkdir2, mkdtemp as mkdtemp2, readFile as
|
|
506
|
+
import { lstat as lstat2, mkdir as mkdir2, mkdtemp as mkdtemp2, readFile as readFile4, realpath as realpath2, rename as rename3, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
|
|
417
507
|
import { homedir as homedir2 } from "node:os";
|
|
418
508
|
import { isAbsolute, join as join4 } from "node:path";
|
|
419
509
|
import { promisify as promisify2 } from "node:util";
|
|
@@ -436,9 +526,9 @@ function checkProtocol(definition3, pkg) {
|
|
|
436
526
|
}
|
|
437
527
|
async function installed(definition3, root, version) {
|
|
438
528
|
if (!(await lstat2(root)).isDirectory()) throw new Error(`${definition3.label} \u7F13\u5B58\u4E0D\u80FD\u4F7F\u7528\u7B26\u53F7\u94FE\u63A5\u3002`);
|
|
439
|
-
const pkg = JSON.parse(await
|
|
529
|
+
const pkg = JSON.parse(await readFile4(join4(root, "package.json"), "utf8"));
|
|
440
530
|
checkProtocol(definition3, pkg);
|
|
441
|
-
const meta2 = JSON.parse(await
|
|
531
|
+
const meta2 = JSON.parse(await readFile4(join4(root, "version.json"), "utf8"));
|
|
442
532
|
if (pkg.version !== version || meta2.version !== version || meta2.workspaceFormat !== definition3.protocol.workspaceFormat) throw new Error(`${definition3.label} Skill \u7248\u672C\u8BB0\u5F55\u4E0D\u4E00\u81F4\u3002`);
|
|
443
533
|
for (const file of definition3.requiredFiles) {
|
|
444
534
|
const path = join4(root, file);
|
|
@@ -454,7 +544,7 @@ async function cached(definition3, root, lock) {
|
|
|
454
544
|
}
|
|
455
545
|
const skill = join4(root, "node_modules", definition3.name);
|
|
456
546
|
try {
|
|
457
|
-
const record2 = JSON.parse(await
|
|
547
|
+
const record2 = JSON.parse(await readFile4(join4(root, "package-lock.json"), "utf8"));
|
|
458
548
|
const entry2 = record2.packages?.[`node_modules/${definition3.name}`];
|
|
459
549
|
if (entry2?.version !== lock.version || entry2.integrity !== lock.integrity) throw new Error("\u7F13\u5B58\u6821\u9A8C\u8BB0\u5F55\u4E0D\u5339\u914D");
|
|
460
550
|
await installed(definition3, skill, lock.version);
|
|
@@ -471,7 +561,7 @@ async function resolveSkillPackage(definition3, previous, options = {}) {
|
|
|
471
561
|
if (local) {
|
|
472
562
|
if (!isAbsolute(local)) throw new Error(`${definition3.pathEnvironment} \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002`);
|
|
473
563
|
const root = await realpath2(local);
|
|
474
|
-
const pkg2 = JSON.parse(await
|
|
564
|
+
const pkg2 = JSON.parse(await readFile4(join4(root, "package.json"), "utf8"));
|
|
475
565
|
await installed(definition3, root, pkg2.version);
|
|
476
566
|
options.report?.(`\u4F7F\u7528\u672C\u5730 ${definition3.label} Skill ${pkg2.version}\uFF1A${root}`);
|
|
477
567
|
return { root, lock: { source: "local", path: root, version: pkg2.version, protocolVersion: 1 } };
|
|
@@ -532,7 +622,7 @@ async function resolveSkillPackage(definition3, previous, options = {}) {
|
|
|
532
622
|
await cached(definition3, temporary, lock);
|
|
533
623
|
options.signal?.throwIfAborted();
|
|
534
624
|
try {
|
|
535
|
-
await
|
|
625
|
+
await rename3(temporary, destination);
|
|
536
626
|
} catch (error2) {
|
|
537
627
|
if (!["EEXIST", "ENOTEMPTY"].includes(error2.code ?? "")) throw error2;
|
|
538
628
|
}
|
|
@@ -556,11 +646,11 @@ var definition = {
|
|
|
556
646
|
var resolveAvatarSkill = (previous, options = {}) => resolveSkillPackage(definition, previous, options);
|
|
557
647
|
|
|
558
648
|
// packages/cli-core/src/cloud/avatar.ts
|
|
559
|
-
import { open } from "node:fs/promises";
|
|
649
|
+
import { open as open2 } from "node:fs/promises";
|
|
560
650
|
import { basename } from "node:path";
|
|
561
651
|
var MAX_BUDDY_AVATAR_BYTES = 5 * 1024 * 1024;
|
|
562
652
|
async function readBuddyAvatarFile(path) {
|
|
563
|
-
const file = await
|
|
653
|
+
const file = await open2(path, "r");
|
|
564
654
|
try {
|
|
565
655
|
const stat2 = await file.stat();
|
|
566
656
|
if (!stat2.isFile()) throw new Error("\u5934\u50CF\u5FC5\u987B\u662F\u666E\u901A\u56FE\u7247\u6587\u4EF6");
|
|
@@ -583,8 +673,8 @@ async function readBuddyAvatarFile(path) {
|
|
|
583
673
|
}
|
|
584
674
|
|
|
585
675
|
// packages/cli-core/src/process-lock.ts
|
|
586
|
-
import { randomUUID } from "node:crypto";
|
|
587
|
-
import { mkdir as mkdir3, readFile as
|
|
676
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
677
|
+
import { mkdir as mkdir3, readFile as readFile5, readdir, rename as rename4, rmdir, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
|
|
588
678
|
import { join as join5 } from "node:path";
|
|
589
679
|
function alive(pid) {
|
|
590
680
|
try {
|
|
@@ -607,8 +697,8 @@ async function acquireProcessLock(options) {
|
|
|
607
697
|
const root = options.directory;
|
|
608
698
|
const key = options.key;
|
|
609
699
|
const path = join5(root, key);
|
|
610
|
-
const ownerName = `owner-${
|
|
611
|
-
const candidate = join5(root, `.pending-${
|
|
700
|
+
const ownerName = `owner-${randomUUID2()}.json`;
|
|
701
|
+
const candidate = join5(root, `.pending-${randomUUID2()}`);
|
|
612
702
|
const owner = { ...options.ownerData, pid: process.pid };
|
|
613
703
|
await mkdir3(root, { recursive: true, mode: 448 });
|
|
614
704
|
await mkdir3(candidate, { mode: 448 });
|
|
@@ -616,7 +706,7 @@ async function acquireProcessLock(options) {
|
|
|
616
706
|
try {
|
|
617
707
|
for (let attempt = 0; ; attempt++) {
|
|
618
708
|
try {
|
|
619
|
-
await
|
|
709
|
+
await rename4(candidate, path);
|
|
620
710
|
break;
|
|
621
711
|
} catch (error2) {
|
|
622
712
|
if (!["EEXIST", "ENOTEMPTY"].includes(code(error2) ?? "")) throw error2;
|
|
@@ -634,14 +724,14 @@ async function acquireProcessLock(options) {
|
|
|
634
724
|
const previousPath = join5(path, names[0]);
|
|
635
725
|
let previous;
|
|
636
726
|
try {
|
|
637
|
-
previous = JSON.parse(await
|
|
727
|
+
previous = JSON.parse(await readFile5(previousPath, "utf8"));
|
|
638
728
|
} catch (error2) {
|
|
639
729
|
if (code(error2) === "ENOENT") continue;
|
|
640
730
|
throw options.busyError();
|
|
641
731
|
}
|
|
642
732
|
if (!validPid(previous.pid) || previous.runtimePid !== void 0 && !validPid(previous.runtimePid) || alive(previous.pid) || previous.runtimePid !== void 0 && runtimeAlive(previous.runtimePid)) throw options.busyError();
|
|
643
733
|
try {
|
|
644
|
-
await
|
|
734
|
+
await unlink2(previousPath);
|
|
645
735
|
} catch (error2) {
|
|
646
736
|
if (code(error2) === "ENOENT") continue;
|
|
647
737
|
throw error2;
|
|
@@ -651,25 +741,25 @@ async function acquireProcessLock(options) {
|
|
|
651
741
|
});
|
|
652
742
|
}
|
|
653
743
|
} finally {
|
|
654
|
-
await
|
|
744
|
+
await unlink2(join5(candidate, ownerName)).catch(() => void 0);
|
|
655
745
|
await rmdir(candidate).catch(() => void 0);
|
|
656
746
|
}
|
|
657
747
|
let released = false;
|
|
658
748
|
return {
|
|
659
749
|
async attachRuntime(pid) {
|
|
660
750
|
if (!validPid(pid)) throw new TypeError("Runtime PID is invalid");
|
|
661
|
-
const temporary = join5(root, `.update-${
|
|
751
|
+
const temporary = join5(root, `.update-${randomUUID2()}`);
|
|
662
752
|
try {
|
|
663
753
|
await writeFile3(temporary, JSON.stringify({ ...owner, ...await options.runtimeData?.(pid), runtimePid: pid }), { mode: 384, flag: "wx" });
|
|
664
|
-
await
|
|
754
|
+
await rename4(temporary, join5(path, ownerName));
|
|
665
755
|
} finally {
|
|
666
|
-
await
|
|
756
|
+
await unlink2(temporary).catch(() => void 0);
|
|
667
757
|
}
|
|
668
758
|
},
|
|
669
759
|
async release() {
|
|
670
760
|
if (released) return;
|
|
671
761
|
released = true;
|
|
672
|
-
await
|
|
762
|
+
await unlink2(join5(path, ownerName)).catch((error2) => {
|
|
673
763
|
if (code(error2) !== "ENOENT") throw error2;
|
|
674
764
|
});
|
|
675
765
|
await rmdir(path).catch((error2) => {
|
|
@@ -704,16 +794,16 @@ async function localFile(path) {
|
|
|
704
794
|
const item = await entry(path);
|
|
705
795
|
if (!item) return void 0;
|
|
706
796
|
if (!item.isFile() || item.size > 8 * 1024 * 1024) throw new MetaPreparationError(`\u5934\u50CF\u8349\u7A3F\u6587\u4EF6\u65E0\u6548\uFF0C\u5DF2\u4FDD\u7559\u539F\u6587\u4EF6\uFF1A${path}`);
|
|
707
|
-
return
|
|
797
|
+
return readFile6(path);
|
|
708
798
|
}
|
|
709
799
|
async function save(path, content) {
|
|
710
800
|
await localFile(path);
|
|
711
|
-
const temporary = `${path}.${
|
|
801
|
+
const temporary = `${path}.${randomUUID3()}.tmp`;
|
|
712
802
|
try {
|
|
713
803
|
await writeFile4(temporary, content, { flag: "wx", mode: 384 });
|
|
714
|
-
await
|
|
804
|
+
await rename5(temporary, path);
|
|
715
805
|
} finally {
|
|
716
|
-
await
|
|
806
|
+
await unlink3(temporary).catch((e) => {
|
|
717
807
|
if (e.code !== "ENOENT") throw e;
|
|
718
808
|
});
|
|
719
809
|
}
|
|
@@ -921,9 +1011,9 @@ import { lstat as lstat5 } from "node:fs/promises";
|
|
|
921
1011
|
import { join as join8 } from "node:path";
|
|
922
1012
|
|
|
923
1013
|
// packages/cli-core/src/init/scaffold.ts
|
|
924
|
-
import { lstat as lstat4, mkdir as mkdir5, open as
|
|
1014
|
+
import { lstat as lstat4, mkdir as mkdir5, open as open3, readFile as readFile8, rename as rename6, rmdir as rmdir2, unlink as unlink4 } from "node:fs/promises";
|
|
925
1015
|
import { resolve as resolve3 } from "node:path";
|
|
926
|
-
import { randomUUID as
|
|
1016
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
927
1017
|
|
|
928
1018
|
// packages/cli-core/src/config/models.ts
|
|
929
1019
|
var MODEL_IDS = Object.freeze([
|
|
@@ -936,7 +1026,7 @@ var DEFAULT_MODEL_ID = "kimi-k2.6";
|
|
|
936
1026
|
|
|
937
1027
|
// packages/cli-core/src/init/runtime-template.ts
|
|
938
1028
|
import { execFile as execFile3 } from "node:child_process";
|
|
939
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
1029
|
+
import { mkdtemp as mkdtemp3, readFile as readFile7, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
|
|
940
1030
|
import { tmpdir } from "node:os";
|
|
941
1031
|
import { join as join7 } from "node:path";
|
|
942
1032
|
import { promisify as promisify3 } from "node:util";
|
|
@@ -947,8 +1037,8 @@ async function latestRuntimeTemplate(template, options) {
|
|
|
947
1037
|
let temporaryRoot;
|
|
948
1038
|
try {
|
|
949
1039
|
options.signal?.throwIfAborted();
|
|
950
|
-
options.report(
|
|
951
|
-
const version =
|
|
1040
|
+
options.report("\u6B63\u5728\u67E5\u8BE2\u516C\u5171 npm \u7684\u6700\u65B0\u6B63\u5F0F\u7248 Runtime\u2026");
|
|
1041
|
+
const version = await latestRuntimeVersion(options);
|
|
952
1042
|
let result = template;
|
|
953
1043
|
if (version !== bundledVersion) {
|
|
954
1044
|
temporaryRoot = await mkdtemp3(join7(tmpdir(), "buddy-runtime-template-"));
|
|
@@ -976,8 +1066,8 @@ async function latestRuntimeTemplate(template, options) {
|
|
|
976
1066
|
"--fetch-timeout=20000"
|
|
977
1067
|
], { cwd: temporaryRoot, signal: options.signal, timeout: 6e4 });
|
|
978
1068
|
result = {
|
|
979
|
-
packageJson: await
|
|
980
|
-
packageLock: await
|
|
1069
|
+
packageJson: await readFile7(join7(temporaryRoot, "package.json"), "utf8"),
|
|
1070
|
+
packageLock: await readFile7(join7(temporaryRoot, "package-lock.json"), "utf8")
|
|
981
1071
|
};
|
|
982
1072
|
}
|
|
983
1073
|
const pkg = JSON.parse(result.packageJson);
|
|
@@ -987,12 +1077,12 @@ async function latestRuntimeTemplate(template, options) {
|
|
|
987
1077
|
throw new Error("\u751F\u6210\u7684 Runtime \u7248\u672C\u4E0E\u4F9D\u8D56\u9501\u6587\u4EF6\u4E0D\u4E00\u81F4");
|
|
988
1078
|
}
|
|
989
1079
|
options.signal?.throwIfAborted();
|
|
990
|
-
options.report(`\u5DF2\u4ECE\u516C\u5171 npm
|
|
1080
|
+
options.report(`\u5DF2\u4ECE\u516C\u5171 npm latest \u9501\u5B9A Runtime ${version}\uFF08package.json \u4E0E package-lock.json\uFF09\u3002`);
|
|
991
1081
|
return result;
|
|
992
1082
|
} catch (cause) {
|
|
993
1083
|
if (options.signal?.aborted) throw new Error("Runtime \u7248\u672C\u9009\u62E9\u5DF2\u53D6\u6D88");
|
|
994
1084
|
const reason = cause instanceof Error && !cause.message.includes("Command failed") ? cause.message : "npm \u672A\u5B8C\u6210\u9501\u6587\u4EF6\u751F\u6210";
|
|
995
|
-
throw new Error(`\u672A\u80FD\u9501\u5B9A
|
|
1085
|
+
throw new Error(`\u672A\u80FD\u9501\u5B9A\u6700\u65B0\u6B63\u5F0F\u7248 Runtime\uFF1A${reason}\u3002\u5DF2\u505C\u6B62\u751F\u6210\u5DE5\u7A0B\u4F9D\u8D56\uFF0C\u8BF7\u4FEE\u590D\u540E\u91CD\u8BD5\uFF1B\u4E0D\u4F1A\u56DE\u9000\u5230\u5185\u7F6E\u65E7\u7248\u672C\u3002`, { cause });
|
|
996
1086
|
} finally {
|
|
997
1087
|
if (temporaryRoot) await rm3(temporaryRoot, { recursive: true, force: true });
|
|
998
1088
|
}
|
|
@@ -1082,7 +1172,7 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1082
1172
|
const path = resolve3(projectRoot, BUDDY_PLATFORM_AGENT_ENTRY);
|
|
1083
1173
|
const packagePath = resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
|
|
1084
1174
|
if (!(await lstat4(packagePath)).isFile()) throw new Error("package.json \u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6");
|
|
1085
|
-
const originalPackage = await
|
|
1175
|
+
const originalPackage = await readFile8(packagePath, "utf8");
|
|
1086
1176
|
const projectPackage = parseBuddyProjectManifest(originalPackage);
|
|
1087
1177
|
const isIdentityDraft = Object.keys(projectPackage).every((key) => key === "buddyId");
|
|
1088
1178
|
const hasAlternateLockfile = (await Promise.all(["pnpm-lock.yaml", "yarn.lock"].map(async (name2) => {
|
|
@@ -1099,12 +1189,12 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1099
1189
|
const files = [
|
|
1100
1190
|
{ path, content: platformAgentTemplate(name) },
|
|
1101
1191
|
{ path: resolve3(projectRoot, BUDDY_PLATFORM_FACTORY_ENTRY), content: platformFactoryTemplate(options.model) },
|
|
1102
|
-
{ path: resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await
|
|
1103
|
-
...hasAlternateLockfile ? [] : [{ path: resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK), content: await
|
|
1192
|
+
{ path: resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await readFile8(new URL("../../resources/agent-template/package.json", import.meta.url), "utf8") },
|
|
1193
|
+
...hasAlternateLockfile ? [] : [{ path: resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK), content: await readFile8(new URL("../../resources/agent-template/package-lock.json", import.meta.url), "utf8") }],
|
|
1104
1194
|
{ path: resolve3(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() },
|
|
1105
1195
|
{ path: resolve3(projectRoot, "data-access.json"), content: '{\n "requirements": []\n}\n' },
|
|
1106
1196
|
{ path: resolve3(projectRoot, ".gitignore"), content: "node_modules/\n/.env\n" },
|
|
1107
|
-
{ path: resolve3(projectRoot, ".env.example"), content: "# \u642D\u5B50\u8EAB\u4EFD\u7531 package.json \u9876\u5C42\u7684 buddyId \u63D0\u4F9B\u3002\n# \u9996\u6B21\u8FD0\u884C buddy-cli dev \u6216\u5728\u540E\u53F0\u542F\u52A8 DEV \u65F6\uFF0CCLI \u4F1A\u51C6\u5907 .env\u3002\nBUDDY_TOKEN=\n# CLI \u81EA\u52A8\u5199\u5165\
|
|
1197
|
+
{ path: resolve3(projectRoot, ".env.example"), content: "# \u642D\u5B50\u8EAB\u4EFD\u7531 package.json \u9876\u5C42\u7684 buddyId \u63D0\u4F9B\u3002\n# \u9996\u6B21\u8FD0\u884C buddy-cli dev \u6216\u5728\u540E\u53F0\u542F\u52A8 DEV \u65F6\uFF0CCLI \u4F1A\u51C6\u5907 .env\u3002\nBUDDY_TOKEN=\n# CLI \u81EA\u52A8\u5199\u5165 ECS Test \u7684 MLB_GATEWAY_URL\uFF0C\u4F9B Runtime \u4F7F\u7528\uFF1B\u65E0\u9700\u624B\u52A8\u8BBE\u7F6E\u3002\n# \u6B63\u5F0F CLI \u4E0D\u652F\u6301\u901A\u8FC7\u73AF\u5883\u53D8\u91CF\u6216 .env \u5207\u6362\u5E73\u53F0\u3002\n" }
|
|
1108
1198
|
];
|
|
1109
1199
|
const handles = [];
|
|
1110
1200
|
const createdDirectories = [];
|
|
@@ -1123,7 +1213,7 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1123
1213
|
}
|
|
1124
1214
|
for (const file of files) {
|
|
1125
1215
|
try {
|
|
1126
|
-
handles.push({ path: file.path, handle: await
|
|
1216
|
+
handles.push({ path: file.path, handle: await open3(file.path, "wx", 384) });
|
|
1127
1217
|
} catch (cause) {
|
|
1128
1218
|
if (cause.code !== "EEXIST") throw cause;
|
|
1129
1219
|
if (!(await lstat4(file.path)).isFile()) {
|
|
@@ -1143,8 +1233,8 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1143
1233
|
lockFile.content = template.packageLock;
|
|
1144
1234
|
}
|
|
1145
1235
|
if (lockFile && (isIdentityDraft || handles.some((file) => file.path === lockFile.path))) {
|
|
1146
|
-
const packageContents = isIdentityDraft ? packageFile.content : await
|
|
1147
|
-
const lockContents = handles.some((file) => file.path === lockFile.path) ? lockFile.content : await
|
|
1236
|
+
const packageContents = isIdentityDraft ? packageFile.content : await readFile8(packageFile.path, "utf8");
|
|
1237
|
+
const lockContents = handles.some((file) => file.path === lockFile.path) ? lockFile.content : await readFile8(lockFile.path, "utf8");
|
|
1148
1238
|
const declared = JSON.parse(packageContents).dependencies ?? {};
|
|
1149
1239
|
const locked = JSON.parse(lockContents).packages?.[""]?.dependencies ?? {};
|
|
1150
1240
|
if (JSON.stringify(Object.entries(declared).sort()) !== JSON.stringify(Object.entries(locked).sort())) {
|
|
@@ -1157,19 +1247,19 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1157
1247
|
await handle.sync();
|
|
1158
1248
|
}
|
|
1159
1249
|
if (isIdentityDraft) {
|
|
1160
|
-
const temporary = `${packagePath}.${
|
|
1161
|
-
const handle = await
|
|
1250
|
+
const temporary = `${packagePath}.${randomUUID4()}.tmp`;
|
|
1251
|
+
const handle = await open3(temporary, "wx", 384);
|
|
1162
1252
|
try {
|
|
1163
1253
|
await handle.writeFile(packageFile.content, "utf8");
|
|
1164
1254
|
await handle.sync();
|
|
1165
1255
|
await handle.close();
|
|
1166
|
-
if (!(await lstat4(packagePath)).isFile() || await
|
|
1256
|
+
if (!(await lstat4(packagePath)).isFile() || await readFile8(packagePath, "utf8") !== originalPackage) {
|
|
1167
1257
|
throw new Error("\u8865\u9F50\u5DE5\u7A0B\u65F6 package.json \u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u8BD5");
|
|
1168
1258
|
}
|
|
1169
|
-
await
|
|
1259
|
+
await rename6(temporary, packagePath);
|
|
1170
1260
|
} finally {
|
|
1171
1261
|
await handle.close().catch(() => void 0);
|
|
1172
|
-
await
|
|
1262
|
+
await unlink4(temporary).catch((cause) => {
|
|
1173
1263
|
if (cause.code !== "ENOENT") throw cause;
|
|
1174
1264
|
});
|
|
1175
1265
|
}
|
|
@@ -1177,7 +1267,7 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1177
1267
|
return Object.freeze({ path, created: isIdentityDraft || handles.length > 0 || createdDirectories.length > 0 });
|
|
1178
1268
|
} catch (cause) {
|
|
1179
1269
|
await Promise.all(handles.map(({ handle }) => handle.close().catch(() => void 0)));
|
|
1180
|
-
await Promise.all(handles.map(({ path: createdPath }) =>
|
|
1270
|
+
await Promise.all(handles.map(({ path: createdPath }) => unlink4(createdPath).catch(() => void 0)));
|
|
1181
1271
|
for (const directory of createdDirectories.reverse()) {
|
|
1182
1272
|
await rmdir2(directory).catch(() => void 0);
|
|
1183
1273
|
}
|
|
@@ -1345,7 +1435,7 @@ async function unlinkMatchingFile(targetPath, expectedIdentity) {
|
|
|
1345
1435
|
if (!entry2.isFile() || entry2.isSymbolicLink() || entryIdentity(entry2) !== expectedIdentity) {
|
|
1346
1436
|
return false;
|
|
1347
1437
|
}
|
|
1348
|
-
await
|
|
1438
|
+
await unlink5(targetPath);
|
|
1349
1439
|
return true;
|
|
1350
1440
|
} catch (cause) {
|
|
1351
1441
|
return cause.code === "ENOENT";
|
|
@@ -1388,7 +1478,7 @@ async function readExistingManifest(agentConfigPath) {
|
|
|
1388
1478
|
);
|
|
1389
1479
|
}
|
|
1390
1480
|
try {
|
|
1391
|
-
return parseBuddyProjectManifest(await
|
|
1481
|
+
return parseBuddyProjectManifest(await readFile9(agentConfigPath, "utf8"));
|
|
1392
1482
|
} catch (cause) {
|
|
1393
1483
|
throw new ProjectInitializationError(
|
|
1394
1484
|
"TARGET_CHANGED",
|
|
@@ -1474,12 +1564,12 @@ async function publishNewFile(options) {
|
|
|
1474
1564
|
let publishedHandle;
|
|
1475
1565
|
const temporaryPath = join9(
|
|
1476
1566
|
options.rootDirectory,
|
|
1477
|
-
`.${options.temporaryLabel}.${process.pid}.${
|
|
1567
|
+
`.${options.temporaryLabel}.${process.pid}.${randomUUID5()}.tmp`
|
|
1478
1568
|
);
|
|
1479
1569
|
let temporaryIdentity;
|
|
1480
1570
|
let publishedIdentity;
|
|
1481
1571
|
try {
|
|
1482
|
-
temporaryHandle = await
|
|
1572
|
+
temporaryHandle = await open4(temporaryPath, "wx");
|
|
1483
1573
|
temporaryIdentity = entryIdentity(await temporaryHandle.stat());
|
|
1484
1574
|
await temporaryHandle.writeFile(options.contents, "utf8");
|
|
1485
1575
|
await temporaryHandle.sync();
|
|
@@ -1502,7 +1592,7 @@ async function publishNewFile(options) {
|
|
|
1502
1592
|
if (fallbackBeforeOpen.kind !== "directory" || fallbackBeforeOpen.identity !== options.directoryIdentity) {
|
|
1503
1593
|
throw targetChanged({ rootDirectory: options.rootDirectory });
|
|
1504
1594
|
}
|
|
1505
|
-
publishedHandle = await
|
|
1595
|
+
publishedHandle = await open4(options.targetPath, "wx");
|
|
1506
1596
|
publishedIdentity = entryIdentity(await publishedHandle.stat());
|
|
1507
1597
|
const fallbackRoot = await pathState(options.rootDirectory);
|
|
1508
1598
|
if (fallbackRoot.kind !== "directory" || fallbackRoot.identity !== options.directoryIdentity) {
|
|
@@ -1516,7 +1606,7 @@ async function publishNewFile(options) {
|
|
|
1516
1606
|
const afterPublish = await pathState(options.rootDirectory);
|
|
1517
1607
|
const publishedFileIdentity = await fileIdentity(options.targetPath);
|
|
1518
1608
|
const temporaryFileIdentity = await fileIdentity(temporaryPath);
|
|
1519
|
-
const publishedContents = publishedFileIdentity ? await
|
|
1609
|
+
const publishedContents = publishedFileIdentity ? await readFile9(options.targetPath, "utf8") : void 0;
|
|
1520
1610
|
if (afterPublish.kind !== "directory" || afterPublish.identity !== options.directoryIdentity || !publishedIdentity || publishedFileIdentity !== publishedIdentity || temporaryFileIdentity !== temporaryIdentity || publishedContents !== options.contents) {
|
|
1521
1611
|
if (afterPublish.kind === "directory" && afterPublish.identity === options.directoryIdentity && publishedIdentity) {
|
|
1522
1612
|
await unlinkMatchingFile(options.targetPath, publishedIdentity);
|
|
@@ -1545,9 +1635,9 @@ async function publishNewFile(options) {
|
|
|
1545
1635
|
async function replaceExistingFile(options) {
|
|
1546
1636
|
const temporaryPath = join9(
|
|
1547
1637
|
options.rootDirectory,
|
|
1548
|
-
`.${options.temporaryLabel}.${process.pid}.${
|
|
1638
|
+
`.${options.temporaryLabel}.${process.pid}.${randomUUID5()}.tmp`
|
|
1549
1639
|
);
|
|
1550
|
-
const handle = await
|
|
1640
|
+
const handle = await open4(temporaryPath, "wx", 384);
|
|
1551
1641
|
try {
|
|
1552
1642
|
await handle.writeFile(options.contents, "utf8");
|
|
1553
1643
|
await handle.sync();
|
|
@@ -1557,12 +1647,12 @@ async function replaceExistingFile(options) {
|
|
|
1557
1647
|
try {
|
|
1558
1648
|
const root = await pathState(options.rootDirectory);
|
|
1559
1649
|
if (root.kind !== "directory" || root.identity !== options.directoryIdentity || await fileIdentity(options.targetPath) !== options.expectedFileIdentity) throw targetChanged({ rootDirectory: options.rootDirectory });
|
|
1560
|
-
await
|
|
1561
|
-
if (await
|
|
1650
|
+
await rename7(temporaryPath, options.targetPath);
|
|
1651
|
+
if (await readFile9(options.targetPath, "utf8") !== options.contents) {
|
|
1562
1652
|
throw targetChanged({ rootDirectory: options.rootDirectory });
|
|
1563
1653
|
}
|
|
1564
1654
|
} finally {
|
|
1565
|
-
await
|
|
1655
|
+
await unlink5(temporaryPath).catch((cause) => {
|
|
1566
1656
|
if (cause.code !== "ENOENT") throw cause;
|
|
1567
1657
|
});
|
|
1568
1658
|
}
|
|
@@ -1684,11 +1774,11 @@ async function initializeBuddyProject(options) {
|
|
|
1684
1774
|
}
|
|
1685
1775
|
async function readBuddyProjectManifest(projectRoot) {
|
|
1686
1776
|
const rootDirectory = resolve4(projectRoot);
|
|
1687
|
-
return parseBuddyProjectManifest(await
|
|
1777
|
+
return parseBuddyProjectManifest(await readFile9(resolve4(rootDirectory, BUDDY_PACKAGE_FILENAME), "utf8"));
|
|
1688
1778
|
}
|
|
1689
1779
|
async function readBuddyAgentConfig(projectRoot) {
|
|
1690
1780
|
const rootDirectory = resolve4(projectRoot);
|
|
1691
|
-
const source = await
|
|
1781
|
+
const source = await readFile9(resolve4(rootDirectory, BUDDY_PACKAGE_FILENAME), "utf8");
|
|
1692
1782
|
return parseBuddyAgentConfig(source);
|
|
1693
1783
|
}
|
|
1694
1784
|
async function readBuddyConfig(projectRoot) {
|
|
@@ -1755,7 +1845,7 @@ async function searchUp(startDirectory) {
|
|
|
1755
1845
|
if (await projectFileState(directory, BUDDY_PACKAGE_FILENAME) === "valid") {
|
|
1756
1846
|
let pkg;
|
|
1757
1847
|
try {
|
|
1758
|
-
pkg = JSON.parse(await
|
|
1848
|
+
pkg = JSON.parse(await readFile10(join10(directory, BUDDY_PACKAGE_FILENAME), "utf8"));
|
|
1759
1849
|
} catch (cause) {
|
|
1760
1850
|
throw new BuddyProjectContextError("PROJECT_CONFIG_INVALID", `\u65E0\u6CD5\u89E3\u6790 ${join10(directory, BUDDY_PACKAGE_FILENAME)}`, directory, { cause });
|
|
1761
1851
|
}
|
|
@@ -1874,20 +1964,6 @@ async function assertInitializableBuddyTarget(target) {
|
|
|
1874
1964
|
// packages/cli-core/src/commands/runtime-source.ts
|
|
1875
1965
|
async function runtimeCatalogSource(directory, options = {}) {
|
|
1876
1966
|
const project = await findBuddyProjectRoot(directory);
|
|
1877
|
-
if (allowsRuntimeVersionSelection(options)) {
|
|
1878
|
-
const declared = project ? await projectRuntimeVersion(project) : void 0;
|
|
1879
|
-
if (declared && options.runtimeVersion !== void 0 && options.runtimeVersion !== declared) {
|
|
1880
|
-
throw new Error(`\u5DE5\u7A0B\u56FA\u5B9A Runtime ${declared}\uFF0C\u76EE\u5F55\u5FC5\u987B\u4E0E\u8BE5\u7248\u672C\u4E00\u81F4\uFF1B\u5148\u786E\u8BA4\u5E76\u66F4\u65B0\u5DE5\u7A0B\u4F9D\u8D56\u540E\u518D\u67E5\u8BE2\u3002`);
|
|
1881
|
-
}
|
|
1882
|
-
const requested = declared ?? options.runtimeVersion;
|
|
1883
|
-
if (!requested) throw new Error(await runtimeSelectionPrompt(options));
|
|
1884
|
-
const selected = await resolveRuntimeVersion(requested, options);
|
|
1885
|
-
const root2 = await cachedRuntimeRoot(selected, options);
|
|
1886
|
-
const version2 = await runtimeVersionStatus(project, selected, true);
|
|
1887
|
-
if (options.report) reportRuntimeVersion(version2, options.report);
|
|
1888
|
-
return { root: root2, source: "npm", version: version2 };
|
|
1889
|
-
}
|
|
1890
|
-
if (options.runtimeVersion !== void 0) throw new Error("\u5F53\u524D\u5E73\u53F0\u7684\u80FD\u529B\u76EE\u5F55\u4F7F\u7528\u6700\u65B0\u7A33\u5B9A\u7248");
|
|
1891
1967
|
const root = await (options.latestRuntimeRoot?.() ?? cachedLatestRuntimeRoot(options));
|
|
1892
1968
|
const latest = await projectRuntimeVersion(root);
|
|
1893
1969
|
if (!latest) throw new Error("npm Runtime \u7F13\u5B58\u7F3A\u5C11\u51C6\u786E\u7248\u672C");
|
|
@@ -1903,28 +1979,24 @@ var MODELS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli models [--directory <\u9879\u
|
|
|
1903
1979
|
\u5C06\u6240\u9009 ID \u5199\u5165 src/buddy-options.mjs \u7684 initialState.model\uFF1B\u6A21\u677F\u5728 initialState.model \u4E2D\u4F7F\u7528\u5B83\u3002`;
|
|
1904
1980
|
async function runModelsCommand(args, io, cwd, options = {}) {
|
|
1905
1981
|
try {
|
|
1906
|
-
const
|
|
1907
|
-
const help = selected ? `\u7528\u6CD5: buddy-cli models [--directory <\u9879\u76EE\u76EE\u5F55>] [--runtime-version <\u51C6\u786E\u7248\u672C|latest|dev>] [--json]
|
|
1908
|
-
\u8BFB\u53D6\u5DE5\u7A0B\u56FA\u5B9A Runtime \u7684\u80FD\u529B\u76EE\u5F55\uFF1B\u5DE5\u7A0B\u5C1A\u672A\u751F\u6210\u65F6\uFF0C\u5148\u8BE2\u95EE\u5F00\u53D1\u8005\uFF0C\u518D\u7528 --runtime-version \u9009\u62E9\u7248\u672C\u3002\u4E0D\u4F1A\u81EA\u52A8\u5207\u6362\u5DE5\u7A0B\u4F9D\u8D56\u3002` : MODELS_COMMAND_HELP;
|
|
1982
|
+
const help = MODELS_COMMAND_HELP;
|
|
1909
1983
|
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
1910
1984
|
io.write(help);
|
|
1911
1985
|
return { exitCode: 0 };
|
|
1912
1986
|
}
|
|
1913
1987
|
let directory;
|
|
1914
1988
|
let json2 = false;
|
|
1915
|
-
let runtimeVersion;
|
|
1916
1989
|
for (let i = 0; i < args.length; i++) {
|
|
1917
1990
|
if (args[i] === "--json" && !json2) json2 = true;
|
|
1918
1991
|
else if (args[i] === "--directory" && directory === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) directory = args[++i];
|
|
1919
|
-
else if (selected && args[i] === "--runtime-version" && runtimeVersion === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) runtimeVersion = args[++i];
|
|
1920
1992
|
else throw new Error(`models \u53C2\u6570\u65E0\u6548\uFF1A${args[i]}
|
|
1921
1993
|
${help}`);
|
|
1922
1994
|
}
|
|
1923
|
-
const { root, source, version } = await runtimeCatalogSource(resolve6(cwd, directory ?? "."), { report: (message) => io.writeError(message), ...options
|
|
1995
|
+
const { root, source, version } = await runtimeCatalogSource(resolve6(cwd, directory ?? "."), { report: (message) => io.writeError(message), ...options });
|
|
1924
1996
|
const catalog = await readRuntimeModelCatalog(root);
|
|
1925
1997
|
if (json2) io.write(JSON.stringify({ source, ...catalog, ...version }, null, 2));
|
|
1926
1998
|
else {
|
|
1927
|
-
io.write(`npm
|
|
1999
|
+
io.write(`npm \u6700\u65B0\u6B63\u5F0F\u7248 Runtime ${catalog.runtimeVersion} \u63D0\u4F9B ${catalog.models.length} \u4E2A\u6A21\u578B\uFF1A`);
|
|
1928
2000
|
for (const id of catalog.models) io.write(`- ${id}`);
|
|
1929
2001
|
io.write("\u5C06\u6240\u9009 ID \u5199\u5165 src/buddy-options.mjs \u7684 initialState.model\uFF1B\u81EA\u5B9A\u4E49\u4F1A\u8BDD\u5DE5\u5382\u4E5F\u53EF\u6309\u4F1A\u8BDD\u8BBE\u7F6E initialState.model\u3002");
|
|
1930
2002
|
}
|
|
@@ -1946,28 +2018,24 @@ var DATASETS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli datasets [--directory <\u98
|
|
|
1946
2018
|
\u76EE\u5F55\u4E0D\u4EE3\u8868\u7528\u6237\u5DF2\u6388\u6743\u3002\u4F7F\u7528 data_access_query \u67E5\u8BE2\uFF0C\u672A\u6388\u6743\u65F6\u4EE5 datasets\u3001reason \u8BF7\u6C42\u6388\u6743\uFF0C\u7528\u6237\u5904\u7406\u540E\u518D\u6B21\u67E5\u8BE2\u3002`;
|
|
1947
2019
|
async function runDatasetsCommand(args, io, cwd, options = {}) {
|
|
1948
2020
|
try {
|
|
1949
|
-
const
|
|
1950
|
-
const help = selected ? `\u7528\u6CD5: buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--runtime-version <\u51C6\u786E\u7248\u672C|latest|dev>] [--json]
|
|
1951
|
-
\u8BFB\u53D6\u5DE5\u7A0B\u56FA\u5B9A Runtime \u7684\u80FD\u529B\u76EE\u5F55\uFF1B\u5DE5\u7A0B\u5C1A\u672A\u751F\u6210\u65F6\uFF0C\u5148\u8BE2\u95EE\u5F00\u53D1\u8005\uFF0C\u518D\u7528 --runtime-version \u9009\u62E9\u7248\u672C\u3002\u4E0D\u4F1A\u81EA\u52A8\u5207\u6362\u5DE5\u7A0B\u4F9D\u8D56\u3002` : DATASETS_COMMAND_HELP;
|
|
2021
|
+
const help = DATASETS_COMMAND_HELP;
|
|
1952
2022
|
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
1953
2023
|
io.write(help);
|
|
1954
2024
|
return { exitCode: 0 };
|
|
1955
2025
|
}
|
|
1956
2026
|
let directory;
|
|
1957
2027
|
let json2 = false;
|
|
1958
|
-
let runtimeVersion;
|
|
1959
2028
|
for (let i = 0; i < args.length; i++) {
|
|
1960
2029
|
if (args[i] === "--json" && !json2) json2 = true;
|
|
1961
2030
|
else if (args[i] === "--directory" && directory === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) directory = args[++i];
|
|
1962
|
-
else if (selected && args[i] === "--runtime-version" && runtimeVersion === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) runtimeVersion = args[++i];
|
|
1963
2031
|
else throw new Error(`datasets \u53C2\u6570\u65E0\u6548\uFF1A${args[i]}
|
|
1964
2032
|
${help}`);
|
|
1965
2033
|
}
|
|
1966
|
-
const { root, source, version } = await runtimeCatalogSource(resolve7(cwd, directory ?? "."), { report: (message) => io.writeError(message), ...options
|
|
2034
|
+
const { root, source, version } = await runtimeCatalogSource(resolve7(cwd, directory ?? "."), { report: (message) => io.writeError(message), ...options });
|
|
1967
2035
|
const catalog = await readRuntimeDataCatalog(root);
|
|
1968
2036
|
if (json2) io.write(JSON.stringify({ source, ...catalog, ...version }, null, 2));
|
|
1969
2037
|
else {
|
|
1970
|
-
io.write(`npm
|
|
2038
|
+
io.write(`npm \u6700\u65B0\u6B63\u5F0F\u7248 Runtime ${catalog.runtimeVersion} \u63D0\u4F9B ${catalog.datasets.length} \u9879\u6570\u636E\u80FD\u529B\uFF1A`);
|
|
1971
2039
|
for (const item of catalog.datasets) io.write(`- ${item.id} \u2014 ${item.title}\uFF08${item.source}\uFF0CSchema ${item.schemaVersion}\uFF09`);
|
|
1972
2040
|
io.write("\u5C06\u6240\u9009 id \u548C purpose \u5199\u5165 data-access.json.requirements\uFF1B\u7528\u6237\u6388\u6743\u7531\u5E73\u53F0\u5904\u7406\u3002");
|
|
1973
2041
|
}
|
|
@@ -1979,8 +2047,8 @@ ${help}`);
|
|
|
1979
2047
|
}
|
|
1980
2048
|
|
|
1981
2049
|
// packages/cli-core/src/commands/knowledge.ts
|
|
1982
|
-
import { createHash as createHash2, randomUUID as
|
|
1983
|
-
import { lstat as lstat8, mkdir as mkdir7, readFile as
|
|
2050
|
+
import { createHash as createHash2, randomUUID as randomUUID6 } from "node:crypto";
|
|
2051
|
+
import { lstat as lstat8, mkdir as mkdir7, readFile as readFile11, rename as rename8, unlink as unlink6, writeFile as writeFile6 } from "node:fs/promises";
|
|
1984
2052
|
import { dirname as dirname2, join as join11, resolve as resolve8 } from "node:path";
|
|
1985
2053
|
var MANIFEST = "knowledge-manifest.json";
|
|
1986
2054
|
var INDEX = "resources/knowledge/index.md";
|
|
@@ -2039,7 +2107,7 @@ async function read(root, path) {
|
|
|
2039
2107
|
});
|
|
2040
2108
|
if (!entry2) return void 0;
|
|
2041
2109
|
if (!entry2.isFile() || entry2.size > MAX_BYTES) throw new Error(`\u6587\u4EF6\u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6\u4E14\u4E0D\u8D85\u8FC7 100 MiB\uFF1A${path}`);
|
|
2042
|
-
return
|
|
2110
|
+
return readFile11(full);
|
|
2043
2111
|
}
|
|
2044
2112
|
async function requiredRead(root, path) {
|
|
2045
2113
|
const bytes = await read(root, path);
|
|
@@ -2049,12 +2117,12 @@ async function requiredRead(root, path) {
|
|
|
2049
2117
|
async function atomicWrite(root, path, value) {
|
|
2050
2118
|
const full = await safePath(root, path);
|
|
2051
2119
|
await mkdir7(dirname2(full), { recursive: true });
|
|
2052
|
-
const temporary = `${full}.${
|
|
2120
|
+
const temporary = `${full}.${randomUUID6()}.tmp`;
|
|
2053
2121
|
await writeFile6(temporary, value, { flag: "wx", mode: 384 });
|
|
2054
2122
|
try {
|
|
2055
|
-
await
|
|
2123
|
+
await rename8(temporary, full);
|
|
2056
2124
|
} finally {
|
|
2057
|
-
await
|
|
2125
|
+
await unlink6(temporary).catch((error2) => {
|
|
2058
2126
|
if (!missing(error2)) throw error2;
|
|
2059
2127
|
});
|
|
2060
2128
|
}
|
|
@@ -2225,7 +2293,7 @@ async function syncKnowledge(root, planPath) {
|
|
|
2225
2293
|
if (current && hash2(current) !== hash2(content) && hash2(current) !== expected.get(path)) conflicts.push(path);
|
|
2226
2294
|
}
|
|
2227
2295
|
if (conflicts.length) {
|
|
2228
|
-
const directory = `.buddy/knowledge/conflicts/${
|
|
2296
|
+
const directory = `.buddy/knowledge/conflicts/${randomUUID6()}`;
|
|
2229
2297
|
for (const [path, content] of files) await atomicWrite(root, `${directory}/${path}`, content);
|
|
2230
2298
|
await atomicWrite(root, `${directory}/${MANIFEST}`, json(next));
|
|
2231
2299
|
return { status: "conflict", conflicts, candidateDirectory: directory, written: [] };
|
|
@@ -2292,11 +2360,11 @@ ${KNOWLEDGE_HELP}`);
|
|
|
2292
2360
|
}
|
|
2293
2361
|
|
|
2294
2362
|
// packages/cli-core/src/index.ts
|
|
2295
|
-
import { join as
|
|
2363
|
+
import { join as join22, resolve as resolve18 } from "node:path";
|
|
2296
2364
|
|
|
2297
2365
|
// packages/cli-core/src/init/creator.ts
|
|
2298
|
-
import { createHash as createHash3, randomUUID as
|
|
2299
|
-
import { link as link2, lstat as lstat9, mkdir as mkdir8, readFile as
|
|
2366
|
+
import { createHash as createHash3, randomUUID as randomUUID7 } from "node:crypto";
|
|
2367
|
+
import { link as link2, lstat as lstat9, mkdir as mkdir8, readFile as readFile12, rename as rename9, unlink as unlink7, writeFile as writeFile7 } from "node:fs/promises";
|
|
2300
2368
|
import { dirname as dirname3, join as join13 } from "node:path";
|
|
2301
2369
|
|
|
2302
2370
|
// packages/cli-core/src/init/creator-package.ts
|
|
@@ -2548,26 +2616,26 @@ async function safeRead(path) {
|
|
|
2548
2616
|
if (!entry2.isFile() || entry2.size > MAX_LOCAL_FILE_BYTES) {
|
|
2549
2617
|
throw new CreatorPreparationError(`\u521B\u4F5C\u6587\u4EF6\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u6216\u8D85\u51FA\u5927\u5C0F\u9650\u5236\uFF1A${path}`);
|
|
2550
2618
|
}
|
|
2551
|
-
return
|
|
2619
|
+
return readFile12(path);
|
|
2552
2620
|
}
|
|
2553
2621
|
async function writeOnce(path, bytes) {
|
|
2554
|
-
const temporary = `${path}.${
|
|
2622
|
+
const temporary = `${path}.${randomUUID7()}.tmp`;
|
|
2555
2623
|
await writeFile7(temporary, bytes, { flag: "wx", mode: 384 });
|
|
2556
2624
|
try {
|
|
2557
2625
|
await link2(temporary, path).catch((cause) => {
|
|
2558
2626
|
if (cause.code !== "EEXIST") throw cause;
|
|
2559
2627
|
});
|
|
2560
2628
|
} finally {
|
|
2561
|
-
await
|
|
2629
|
+
await unlink7(temporary);
|
|
2562
2630
|
}
|
|
2563
2631
|
}
|
|
2564
|
-
async function
|
|
2565
|
-
const temporary = `${path}.${
|
|
2632
|
+
async function replaceFile2(path, content) {
|
|
2633
|
+
const temporary = `${path}.${randomUUID7()}.tmp`;
|
|
2566
2634
|
try {
|
|
2567
2635
|
await writeFile7(temporary, content, { flag: "wx", mode: 384 });
|
|
2568
|
-
await
|
|
2636
|
+
await rename9(temporary, path);
|
|
2569
2637
|
} finally {
|
|
2570
|
-
await
|
|
2638
|
+
await unlink7(temporary).catch((error2) => {
|
|
2571
2639
|
if (error2.code !== "ENOENT") throw error2;
|
|
2572
2640
|
});
|
|
2573
2641
|
}
|
|
@@ -2632,7 +2700,7 @@ async function prepareCreatorSkill(context, io, options = {}) {
|
|
|
2632
2700
|
await writeOnce(sessionPath, JSON.stringify({
|
|
2633
2701
|
schemaVersion: 1,
|
|
2634
2702
|
platformBuddyId: context.buddyId,
|
|
2635
|
-
creationKey:
|
|
2703
|
+
creationKey: randomUUID7()
|
|
2636
2704
|
}, null, 2) + "\n");
|
|
2637
2705
|
const session = JSON.parse((await safeRead(sessionPath)).toString("utf8"));
|
|
2638
2706
|
if (session.schemaVersion !== 1 || session.platformBuddyId !== context.buddyId || !/^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/u.test(session.creationKey)) {
|
|
@@ -2692,9 +2760,9 @@ async function prepareCreatorSkill(context, io, options = {}) {
|
|
|
2692
2760
|
}
|
|
2693
2761
|
await writeOnce(join13(root, `HANDOFF.${hash3(existing).slice(0, 12)}.bak.md`), existing);
|
|
2694
2762
|
}
|
|
2695
|
-
await
|
|
2696
|
-
await
|
|
2697
|
-
await
|
|
2763
|
+
await replaceFile2(lockPath, JSON.stringify({ ...selected.lock, ...existing ? { handoffSha256: hash3(existing) } : {} }, null, 2) + "\n");
|
|
2764
|
+
await replaceFile2(handoffPath, handoff2);
|
|
2765
|
+
await replaceFile2(lockPath, JSON.stringify({ ...selected.lock, handoffSha256: hash3(handoff2) }, null, 2) + "\n");
|
|
2698
2766
|
io.write(`\u4F7F\u7528 ${selected.lock.source === "npm" ? "\u72EC\u7ACB npm" : "\u672C\u5730\u5F00\u53D1"} Creator Skill ${selected.lock.version}\uFF1A${join13(skillRoot, "SKILL.md")}`);
|
|
2699
2767
|
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`);
|
|
2700
2768
|
io.write("Skill \u5DF2\u51C6\u5907\u597D\uFF0C\u521B\u4F5C\u4E0E\u5F00\u53D1\u5C1A\u672A\u5B8C\u6210\u3002\u901A\u7528\u5F00\u53D1\u6307\u5F15\uFF1Abuddy-cli guide\u3002");
|
|
@@ -2759,7 +2827,7 @@ function validateBuddyMetaUpdate(meta2) {
|
|
|
2759
2827
|
|
|
2760
2828
|
// packages/cli-core/src/init/implementation-guide.ts
|
|
2761
2829
|
var IMPLEMENTATION_GUIDE_SUMMARY = "\u5F00\u53D1\u5DF2\u83B7\u6388\u6743\u65F6\uFF0C\u5148\u8BFB\u53D6\u5DF2\u786E\u8BA4\u7684\u624B\u518C\u6216\u9700\u6C42\u53CA\u73B0\u6709\u4EE3\u7801\uFF0C\u628A\u6BCF\u9879\u8981\u6C42\u843D\u5B9E\u5230\u5B9E\u73B0\u548C\u68C0\u67E5\u3002\u5DF2\u7ECF\u660E\u786E\u6216\u80FD\u636E\u6B64\u786E\u5B9A\u7684\u76F4\u63A5\u505A\uFF1B\u53EA\u8865\u95EE\u5F71\u54CD\u4F53\u9A8C\u3001\u6570\u636E\u4F7F\u7528\u6216\u6388\u6743\u7684\u5173\u952E\u7F3A\u53E3\uFF0C\u4E0D\u518D\u9010\u9879\u8BE2\u95EE\u6280\u672F\u9009\u9879\uFF0C\u4E5F\u4E0D\u56FA\u5B9A\u589E\u52A0\u4E00\u8F6E\u65B9\u6848\u786E\u8BA4\u3002\u6A21\u677F\u751F\u6210\u4E0D\u7B49\u4E8E\u9700\u6C42\u5DF2\u5B9E\u73B0\u3002\u642D\u5B50\u4E1A\u52A1\u53EA\u4F7F\u7528\u5E73\u53F0\u63D0\u4F9B\u7684\u670D\u52A1\uFF0C\u4E0D\u76F4\u63A5\u8C03\u7528\u7B2C\u4E09\u65B9\u670D\u52A1\u3002";
|
|
2762
|
-
function implementationGuide(
|
|
2830
|
+
function implementationGuide() {
|
|
2763
2831
|
return `## \u4ECE\u9700\u6C42\u624B\u518C\u843D\u5B9E\u5230\u4EE3\u7801
|
|
2764
2832
|
|
|
2765
2833
|
${IMPLEMENTATION_GUIDE_SUMMARY}
|
|
@@ -2786,12 +2854,14 @@ ${KNOWLEDGE_GUIDE}
|
|
|
2786
2854
|
|
|
2787
2855
|
CLI \u767B\u5F55\u6388\u6743\u548C\u9884\u89C8\u8FDE\u63A5\u76F4\u63A5\u8BF7\u6C42 MLB Server\uFF1B\u5F00\u53D1\u8005\u7F51\u9875\u63D0\u4F9B\u754C\u9762\u3002\u4F7F\u7528\u5F53\u524D\u5E73\u53F0\u751F\u6210\u7684\u8FDE\u63A5\u6307\u4EE4\uFF0C\u786E\u4FDD CLI \u4E0E\u7F51\u9875\u8FDE\u63A5\u540C\u4E00\u73AF\u5883\u3002\u5347\u7EA7\u5230 CLI 0.20 \u540E\u91CD\u65B0\u767B\u5F55\uFF1B\u4E0D\u8981\u8C03\u7528\u65E7 Web \u670D\u52A1\u7684\u6388\u6743\u6216\u9884\u89C8\u63A5\u53E3\u3002
|
|
2788
2856
|
|
|
2789
|
-
|
|
2857
|
+
\u6B63\u5F0F\u7248 CLI \u56FA\u5B9A\u8FDE\u63A5 ECS Test\u3002\u542F\u52A8 DEV \u65F6\u7531 CLI \u5C06\u56FA\u5B9A\u7684 \`MLB_GATEWAY_URL\` \u4E0E\u8BE5\u73AF\u5883\u5F00\u53D1 Token \u5199\u5165\u5DE5\u7A0B \`.env\` \u5E76\u4F20\u7ED9 Runtime\uFF1B\u65E0\u9700\u624B\u52A8\u914D\u7F6E\u5730\u5740\u3002\`--app-server\`\u3001\`--developer-web\` \u4EC5\u6821\u9A8C\u76EE\u6807\uFF0C\u4E0D\u80FD\u5207\u6362\u73AF\u5883\u3002\u5DE5\u7A0B\u5730\u5740\u51B2\u7A81\u65F6\u5148\u6309\u9519\u8BEF\u63D0\u793A\u5904\u7406\uFF0C\u4E0D\u6E05\u7A7A\u51ED\u636E\u7ED5\u8FC7\u68C0\u67E5\u3002\`--refresh-token\` \u53EA\u5237\u65B0\u540C\u4E00\u73AF\u5883\u7684\u5F00\u53D1\u51ED\u636E\u3002\u6B64\u9650\u5236\u53EA\u9488\u5BF9\u5E73\u53F0\u8FDE\u63A5\uFF0C\u4E0D\u5F71\u54CD\u516C\u5171 npm \u4E0E Skill \u4E0B\u8F7D\u3002
|
|
2790
2858
|
|
|
2791
2859
|
### \u672C\u5730\u8C03\u8BD5\u7684\u9000\u51FA\u548C\u6E05\u7406
|
|
2792
2860
|
|
|
2793
2861
|
\u901A\u8FC7 \`buddy-cli preview\` \u8FDE\u63A5\u540E\u53F0\uFF0C\u9875\u9762\u542F\u52A8 DEV \u540E\u624D\u8FD0\u884C Runtime\u3002\u540E\u53F0\u590D\u5236\u7684\u6307\u4EE4\u5E26 \`--no-open\`\uFF0C\u6267\u884C\u540E\u8FD4\u56DE\u539F\u9875\u9762\uFF1B\u4E0D\u8981\u518D\u5F00\u4E00\u4E2A\u9884\u89C8\u8FDB\u7A0B\u3002\u6B63\u5E38\u505C\u6B62\u7528\u9875\u9762\u300C\u505C\u6B62 DEV\u300D\u6216 \`buddy-cli dev stop\`\uFF0C\u540E\u8005\u65E0\u9700\u8054\u7F51\u66F4\u65B0\u6216\u767B\u5F55\uFF0C\u53EA\u505C\u6B62\u5F53\u524D\u5E73\u53F0\u3001\u5F53\u524D\u642D\u5B50\u7684\u672C\u5730 Runtime \u548C\u76D1\u542C\uFF0C\u4E0D\u81EA\u52A8\u91CD\u8FDE\u6216\u91CD\u542F\u3002\u5173\u95ED\u7EC8\u7AEF\u3001Ctrl+C \u6216 SIGTERM \u4F1A\u505C\u6B62 CLI \u7BA1\u7406\u7684 Runtime \u5E76\u65AD\u5F00\u3002\u82E5\u6B8B\u7559\u5360\u7528\uFF0C\u540E\u53F0\u53EF\u300C\u5F3A\u5236\u65AD\u8FDE\u300D\uFF1B\u9875\u9762\u672A\u786E\u8BA4\u672C\u673A\u505C\u6B62\u65F6\uFF0C\u5728\u539F\u7535\u8111\u3001\u539F\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C\u5176\u505C\u6B62\u6307\u4EE4\u3002\u4E0D\u8981\u624B\u5DE5\u5220\u9501\u6587\u4EF6\uFF0C\u4E0D\u8981\u6279\u91CF\u6740\u6B7B node\uFF1B\u8EAB\u4EFD\u6821\u9A8C\u5931\u8D25\u65F6\u5148\u6838\u5BF9\u5DE5\u7A0B\u548C\u539F\u8FDB\u7A0B\u3002\u8FD9\u4E9B\u64CD\u4F5C\u4E0D\u4F1A\u63D0\u5BA1\u6216\u53D1\u5E03\u3002
|
|
2794
2862
|
|
|
2863
|
+
DEV \u542F\u52A8\u6216\u8FD0\u884C\u5931\u8D25\u65F6\uFF0C\u5148\u8BFB\u53D6\u9875\u9762\u9519\u8BEF\u548C\u8FD0\u884C\u65E5\u5FD7\u4E2D\u7684\u5177\u4F53\u539F\u56E0\uFF0C\u518D\u4FEE\u590D\u5DE5\u7A0B\u6216\u5E73\u53F0\u914D\u7F6E\uFF1B\u4E0D\u8981\u628A\u201C\u5DF2\u8FDE\u63A5\u672C\u5730\u5DE5\u7A0B\u201D\u5F53\u4F5C Runtime \u5DF2\u542F\u52A8\u3002CLI \u5347\u7EA7\u4E0D\u4F1A\u66FF\u6362\u5DF2\u8FD0\u884C\u7684 preview \u8FDB\u7A0B\uFF0C\u9700\u5728\u539F\u7EC8\u7AEF\u9000\u51FA\u65E7\u8FDE\u63A5\u540E\u91CD\u65B0\u6267\u884C\u8FDE\u63A5\u6307\u4EE4\uFF0C\u518D\u542F\u52A8 DEV\uFF1B\u53EA\u5237\u65B0\u7F51\u9875\u65E0\u6548\u3002\u4E0D\u8981\u4E3A\u4E86\u7ED5\u8FC7\u9519\u8BEF\u64C5\u81EA\u5207\u6362\u5E73\u53F0\u3001\u6539 buddyId\u3001\u5220\u9664\u8EAB\u4EFD\u9501\u6216\u63D0\u5BA1\u53D1\u5E03\u3002
|
|
2864
|
+
|
|
2795
2865
|
### \u4E3B\u52A8\u63D0\u9192\u4E0E\u6570\u636E\u6743\u9650
|
|
2796
2866
|
|
|
2797
2867
|
Creator 1.7+ \u7684 Booklet \u63D0\u4F9B\u300C\u4E3B\u52A8\u6027\u4E0E\u6570\u636E\u300D\u9875\u7B7E\u3002\u8BFB\u53D6\u4EA4\u4ED8\u76EE\u5F55\u4E2D\u7684 \`service-blueprint.json\`\uFF0C\u6309 \`data.proactiveReminders\` \u4E2D\u7684\u89E6\u53D1\u3001\u9891\u7387\u3001\u9759\u9ED8\u548C\u505C\u6B62\u7EA6\u5B9A\u5B9E\u73B0\u5E76\u9A8C\u8BC1\uFF1B\u5B57\u6BB5\u7F3A\u5931\u8868\u793A\u5C1A\u672A\u6574\u7406\uFF0C\u4E0D\u80FD\u64C5\u81EA\u6DFB\u52A0\u9ED8\u8BA4\u63D0\u9192\u3002\u9875\u9762\u5C55\u793A\u7684\u662F\u521B\u4F5C\u65B9\u6848\uFF0C\u4E0D\u4EE3\u8868\u5B9E\u9645\u8C03\u5EA6\u5DF2\u542F\u7528\u3002\u5E73\u53F0\u6570\u636E\u6743\u9650\u76F4\u63A5\u8BFB\u53D6\u5F53\u524D\u5DE5\u7A0B\u7684 \`data-access.json.requirements\`\uFF1B\u6309\u5B9E\u9645\u9700\u8981\u7EF4\u62A4 ID \u548C\u7528\u9014\uFF0C\u4FDD\u5B58\u540E\u9875\u9762\u540C\u6B65\u3002\u4E0D\u8981\u590D\u5236\u4E00\u4EFD\u5C55\u793A\u7528\u6743\u9650\u6E05\u5355\uFF0C\u4E5F\u4E0D\u8981\u628A\u4E1A\u52A1\u8BB0\u5F55\u6DF7\u4F5C\u5E73\u53F0\u6388\u6743\u3002
|
|
@@ -2843,14 +2913,16 @@ Tool \u548C Hook \u662F Runtime \u7684\u6269\u5C55\u70B9\uFF1BService \u53EA\u66
|
|
|
2843
2913
|
|
|
2844
2914
|
\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
|
|
2845
2915
|
|
|
2846
|
-
\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
|
|
2916
|
+
\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 npm \u6700\u65B0 Runtime \u5BFC\u51FA\u8BFB\u53D6\u5168\u90E8\u6570\u636E\u96C6\uFF1B\u4E0D\u8981\u6C42\u767B\u5F55\uFF0C\u4E0D\u4ECE Server \u62C9\u76EE\u5F55\u3002CLI \u6BCF\u6B21\u67E5\u8BE2 latest\uFF0C\u540C\u7248\u672C\u590D\u7528\u7F13\u5B58\uFF0C\u4E0D\u590D\u5236\u679A\u4E3E\u3002\u76EE\u5F55\u547D\u4EE4\u4F1A\u63D0\u793A\u5DE5\u7A0B\u7248\u672C\u5DEE\u5F02\uFF1B\u4F7F\u7528\u65B0\u7248\u80FD\u529B\u524D\uFF0C\u7531\u4F60\u6216\u5F00\u53D1 Agent \u6309\u63D0\u793A\u5347\u7EA7\u4F9D\u8D56\uFF0C\u68C0\u67E5\u542F\u52A8\u53C2\u6570\u3001\u6A21\u578B\u3001datasets\u3001\u5DE5\u5177\u53CA Hook \u7684\u9002\u914D\u5E76\u9A8C\u8BC1 DEV\u3002CLI \u4E0D\u81EA\u52A8\u4FEE\u6539\u5DE5\u7A0B\u4F9D\u8D56\u6216\u914D\u7F6E\u3002\u628A\u5B9E\u9645\u9700\u8981\u7684 \`id\` \u548C\u7528\u9014 \`purpose\` \u5199\u5165 \`data-access.json.requirements\`\uFF0C\u6700\u591A 32 \u9879\uFF0C\u540C\u4E00 ID \u53EA\u5199\u4E00\u6B21\uFF0CID \u548C\u7528\u9014\u53BB\u9664\u9996\u5C3E\u7A7A\u767D\uFF0C\u7528\u9014\u4E3A 1\uFF5E200 \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
|
|
2847
2917
|
|
|
2848
2918
|
Runtime \u542F\u52A8\u65F6\u8BFB\u53D6\u6839\u76EE\u5F55 \`data-access.json\`\uFF0C\u901A\u8FC7 \`PUT /internal/v1/data-access/requirements\` \u767B\u8BB0\uFF0C\u6210\u529F\u540E\u518D\u8FDE\u63A5\u4E8B\u4EF6\u6D41\uFF1B\u767B\u8BB0\u5931\u8D25\u963B\u6B62\u542F\u52A8\u3002\u6587\u4EF6\u7F3A\u5931\u6216\u7A7A\u6570\u7EC4\u90FD\u4F1A\u4E0A\u4F20\u7A7A\u58F0\u660E\u5E76\u6E05\u9664\u65E7\u58F0\u660E\u3002DEV \u4FDD\u5B58\u8BE5\u6587\u4EF6\u540E\u81EA\u52A8\u91CD\u542F\u5E76\u91CD\u65B0\u767B\u8BB0\u3002\u58F0\u660E\u4E0D\u8868\u793A\u7528\u6237\u5DF2\u6388\u6743\uFF1B\u6240\u6709\u9700\u8981\u7684\u6570\u636E\u90FD\u8981\u58F0\u660E\uFF0C\u5305\u62EC\u4F4D\u7F6E \`device.location\` \u548C\u65E5\u5386 \`device.calendar\`\u3002
|
|
2849
2919
|
|
|
2850
2920
|
\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\`\u3002\u5065\u5EB7\u3001\u4F4D\u7F6E\u3001\u65E5\u5386\u7EDF\u4E00\u5148 query\uFF1B\u8FD4\u56DE \`notGranted\` \u65F6\uFF0C\u7528 \`data_access_request({ datasets, reason })\` \u7533\u8BF7\u5DF2\u58F0\u660E\u7684 1\uFF5E8 \u9879\u6570\u636E\uFF0C\u7B49\u5F85\u7528\u6237\u5904\u7406\u540E\u518D\u6B21 query\u3002\u4E1A\u52A1\u4EE3\u7801\u5BF9\u5E94\u4F7F\u7528 \`conversation.dataAccess.query({ datasets, memberId? })\` \u4E0E \`conversation.dataAccess.request({ datasets, reason, idempotencyKey })\`\u3002\u67E5\u8BE2\u53EA\u6709 \`available\` \u643A\u5E26\u6570\u636E\uFF1B\`notDeclared\` \u8981\u4FEE\u6B63\u5DE5\u7A0B\u58F0\u660E\uFF0C\`systemPermissionDenied\` \u8868\u793A\u7CFB\u7EDF\u6743\u9650\u5173\u95ED\uFF0C\u5E94\u5F15\u5BFC\u7528\u6237\u5728 App \u6216\u7CFB\u7EDF\u8BBE\u7F6E\u4E2D\u68C0\u67E5\uFF1B\`unavailable\` \u8868\u793A\u6682\u65E0\u53EF\u7528\u7ED3\u679C\uFF0C\u4E0D\u7B49\u4E8E\u7528\u6237\u62D2\u7EDD\uFF0C\u4E5F\u4E0D\u8981\u53CD\u590D\u53D1\u6388\u6743\u5361\u3002\u4F4D\u7F6E\u3001\u65E5\u5386\u5FEB\u7167\u8FC7\u671F\u540E\u7531\u5E73\u53F0\u5C1D\u8BD5\u8BF7\u6C42\u5728\u7EBF App \u5237\u65B0\uFF0CCLI \u4E0D\u91C7\u96C6\u8BBE\u5907\u6570\u636E\u3002
|
|
2851
2921
|
|
|
2852
|
-
|
|
2853
|
-
|
|
2922
|
+
\u4F4D\u7F6E\u6216\u65E5\u5386\u7684\u6388\u6743\u8BF7\u6C42\u6BCF\u6B21\u53EA\u80FD\u5305\u542B\u4E00\u4E2A Dataset\uFF0C\u4E0D\u80FD\u628A\u4E8C\u8005\u653E\u5728\u4E00\u8D77\uFF0C\u4E5F\u4E0D\u80FD\u4E0E\u5065\u5EB7\u6570\u636E\u6DF7\u5408\u7533\u8BF7\u3002\u7FA4\u804A query \u7684 memberId \u4F7F\u7528\u6D88\u606F\u524D\u7F00\u91CC\u7684\u7A33\u5B9A\u6210\u5458\u53F7 m_\u2026\uFF0C\u4E0D\u5E26 #\uFF0C\u4E0D\u80FD\u6309\u6635\u79F0\u731C\u6D4B\u3002\u7FA4\u804A\u53D1\u6388\u6743\u5361\u524D\u6838\u5BF9\u5DE5\u7A0B Runtime \u7684 request \u662F\u5426\u652F\u6301 memberId\uFF1B\u652F\u6301\u65F6\u67E5\u8BE2\u548C\u53D1\u5361\u6307\u5411\u540C\u4E00\u6210\u5458\uFF0C\u4E0D\u652F\u6301\u65F6\u5F15\u5BFC\u6210\u5458\u5230\u79C1\u804A\u6388\u6743\uFF0C\u4E0D\u7ED5\u8FC7 Runtime \u76F4\u8C03\u5E73\u53F0\u3002\u79C1\u804A\u4E0D\u4F20 memberId\u3002
|
|
2923
|
+
|
|
2924
|
+
\u65B0\u5EFA\u5DE5\u7A0B\u52A8\u6001\u9009\u62E9\u516C\u5171 npm latest \u5E76\u9501\u5B9A\u51C6\u786E\u7248\u672C\uFF1B\u67E5\u8BE2\u6216\u9501\u6587\u4EF6\u751F\u6210\u5931\u8D25\u65F6\u505C\u6B62\uFF0C\u4E0D\u56DE\u9000\u5185\u7F6E\u65E7\u7248\u672C\u3002\u5DF2\u6709\u5DE5\u7A0B\u901A\u8FC7\u5305\u7BA1\u7406\u5668\u663E\u5F0F\u5347\u7EA7\u4F9D\u8D56\u3002CLI \u7684 DEV \u542F\u52A8\u3001\u81EA\u52A8\u91CD\u8F7D\u548C push \u5FC5\u987B\u4F7F\u7528\u672C\u6B21 npm \u6700\u65B0\u7A33\u5B9A\u7248\uFF0C\u58F0\u660E\u3001\u5B89\u88C5\u548C npm \u9501\u6587\u4EF6\u7248\u672C\u5FC5\u987B\u4E00\u81F4\uFF0C\u67E5\u8BE2\u5931\u8D25\u4F1A\u963B\u6B62\u64CD\u4F5C\u3002
|
|
2925
|
+
|
|
2854
2926
|
|
|
2855
2927
|
\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
|
|
2856
2928
|
|
|
@@ -2971,7 +3043,8 @@ var LoopbackBrowserLoginAdapter = class {
|
|
|
2971
3043
|
#fetch;
|
|
2972
3044
|
constructor(options) {
|
|
2973
3045
|
this.#platformUrl = normalizePlatformUrl(options.platformUrl);
|
|
2974
|
-
this.#developerWebUrl =
|
|
3046
|
+
this.#developerWebUrl = normalizePlatformUrl(options.developerWebUrl ?? new URL("/developer/", this.#platformUrl));
|
|
3047
|
+
if (this.#developerWebUrl.origin !== this.#platformUrl.origin) throw new TypeError("\u5F00\u53D1\u8005\u540E\u53F0\u4E0E MLB \u7F51\u5173\u5730\u5740\u4E0D\u4E00\u81F4");
|
|
2975
3048
|
this.#openBrowser = options.openBrowser ?? openExternalUrl;
|
|
2976
3049
|
this.#onLoginUrl = options.onLoginUrl;
|
|
2977
3050
|
this.#timeoutMs = positive(options.timeoutMs, DEFAULT_LOGIN_TIMEOUT_MS, "timeoutMs");
|
|
@@ -3142,10 +3215,11 @@ var CLI_HELP = `\u642D\u642D Developer Platform CLI
|
|
|
3142
3215
|
--version \u67E5\u770B\u5F53\u524D CLI \u7248\u672C
|
|
3143
3216
|
|
|
3144
3217
|
\u76F4\u63A5\u8FD0\u884C buddy-cli \u53EF\u8BC6\u522B\u5F53\u524D\u5DE5\u7A0B\u6216\u5F15\u5BFC\u521B\u5EFA\u3002
|
|
3145
|
-
\
|
|
3146
|
-
\u8BBE\u7F6E
|
|
3147
|
-
\
|
|
3218
|
+
\u6B63\u5F0F\u7248\u56FA\u5B9A\u5E73\u53F0\uFF1A${DEFAULT_MLB_TEST_URL}\uFF1B\u5F00\u53D1\u8005\u540E\u53F0\uFF1A${DEFAULT_DEVELOPER_WEB_URL}\u3002
|
|
3219
|
+
\u65E0\u9700\u8BBE\u7F6E\u5E73\u53F0\u73AF\u5883\u53D8\u91CF\uFF1Bdev/preview \u7684 --app-server \u4E0E --developer-web \u4EC5\u6821\u9A8C\u56FA\u5B9A\u76EE\u6807\uFF0C\u4E0D\u80FD\u5207\u6362\u73AF\u5883\u3002
|
|
3220
|
+
\u51B2\u7A81\u914D\u7F6E\u5148\u79FB\u9664\uFF1B--refresh-token \u53EA\u5237\u65B0\u540C\u4E00\u73AF\u5883\u7684\u5F00\u53D1\u51ED\u636E\uFF0C\u4E0D\u80FD\u8FC1\u79FB\u5DE5\u7A0B\u6216\u8DE8\u73AF\u5883\u590D\u7528 Token\u3002
|
|
3148
3221
|
CLI \u767B\u5F55\u6388\u6743\u4E0E\u9884\u89C8\u8FDE\u63A5\u76F4\u63A5\u8BF7\u6C42 MLB\uFF1B\u7F51\u9875\u627F\u8F7D\u754C\u9762\u30020.20 \u5347\u7EA7\u540E\u8BF7\u91CD\u65B0\u767B\u5F55\u3002
|
|
3222
|
+
DEV \u5931\u8D25\u65F6\u67E5\u770B\u9875\u9762\u548C\u8FD0\u884C\u65E5\u5FD7\u4E2D\u7684\u5177\u4F53\u539F\u56E0\u3002\u5347\u7EA7 CLI \u540E\uFF0C\u9000\u51FA\u65E7 preview \u8FDB\u7A0B\u5E76\u91CD\u65B0\u6267\u884C\u8FDE\u63A5\u6307\u4EE4\uFF0C\u518D\u542F\u52A8 DEV\u3002
|
|
3149
3223
|
\u6B63\u5E38\u547D\u4EE4\u5148\u8054\u7F51\u81EA\u68C0\uFF0C\u65E7\u7248\u81EA\u52A8\u66F4\u65B0\u540E\u7EE7\u7EED\u6267\u884C\uFF1B\u5931\u8D25\u65F6\u505C\u6B62\u3002\u5E2E\u52A9\u3001--version \u548C dev stop \u79BB\u7EBF\u53EF\u7528\u3002
|
|
3150
3224
|
\u53C2\u6570\u4E0E\u793A\u4F8B: buddy-cli <\u547D\u4EE4> --help\uFF0C\u4F8B\u5982 buddy-cli init --help\u3002
|
|
3151
3225
|
Coding Agent \u5F00\u59CB\u5DE5\u4F5C\u524D\u8BF7\u8BFB\u53D6 buddy-cli guide\u3002`;
|
|
@@ -3177,9 +3251,9 @@ var GUIDE_HELP = `\u7528\u6CD5: buddy-cli guide
|
|
|
3177
3251
|
\u8F93\u51FA Coding Agent \u7684\u5B8C\u6574\u5F00\u53D1\u6307\u5F15\uFF0C\u5305\u62EC\u521B\u4F5C\u5F00\u573A\u3001\u8D44\u6599\u786E\u8BA4\u3001Skill \u63A5\u7EED\u3001\u5B9E\u73B0\u4E0E\u4EA4\u4ED8\u89C4\u5219\u3002
|
|
3178
3252
|
\u65E0\u9700\u5DE5\u7A0B\u6216\u767B\u5F55\uFF1B\u5148\u8054\u7F51\u68C0\u67E5 CLI \u5E76\u6309\u9700\u81EA\u52A8\u66F4\u65B0\uFF0C\u518D\u8F93\u51FA\u65B0\u7248\u6307\u5357\uFF0C\u4E0D\u4FEE\u6539\u5DE5\u7A0B\u6216\u6267\u884C\u5F00\u53D1\u3002`;
|
|
3179
3253
|
function agentGuide(options = {}) {
|
|
3180
|
-
return renderAgentGuide(
|
|
3254
|
+
return renderAgentGuide();
|
|
3181
3255
|
}
|
|
3182
|
-
function renderAgentGuide(
|
|
3256
|
+
function renderAgentGuide() {
|
|
3183
3257
|
return `# Coding Agent \u5F00\u53D1\u6307\u5F15
|
|
3184
3258
|
|
|
3185
3259
|
\u901A\u7528\u89C4\u5219\u5728\u6B64\u8BFB\u53D6\uFF1B\u53C2\u6570\u89C1 buddy-cli <\u547D\u4EE4> --help\uFF0C\u5DE5\u7A0B\u72B6\u6001\u4E0E\u5177\u4F53\u63A5\u7EED\u6B65\u9AA4\u4EE5 CLI \u8FD4\u56DE\u7684 HANDOFF.md \u4E3A\u51C6\u3002
|
|
@@ -3188,11 +3262,7 @@ Skill \u7684\u5177\u4F53\u6D41\u7A0B\u8BFB\u53D6 HANDOFF.md \u4E2D\u7684\u6587\u
|
|
|
3188
3262
|
## \u51C6\u5907\u5B8C\u6210\u540E\uFF0C\u5F00\u59CB\u521B\u4F5C\u5BF9\u8BDD
|
|
3189
3263
|
|
|
3190
3264
|
\u7528\u6237\u4ECE\u5F00\u53D1\u8005\u540E\u53F0\u590D\u5236\u521B\u4F5C\u63D0\u793A\u8BCD\u65F6\uFF0C\u76EE\u6807\u662F\u4E0E\u4F60\u4E00\u8D77\u628A\u60F3\u6CD5\u505A\u6210\u642D\u5B50\u3002\u5B89\u88C5 CLI\u3001\u68C0\u67E5\u4F9D\u8D56\u548C\u9605\u8BFB\u672C\u6307\u5357\u662F\u51C6\u5907\u6B65\u9AA4\uFF0C\u5B8C\u6210\u540E\u8981\u4E3B\u52A8\u8FDB\u5165\u521B\u4F5C\u5BF9\u8BDD\u3002
|
|
3191
|
-
|
|
3192
|
-
\u9009\u62E9\u516C\u5171\u73AF\u5883\uFF1A\u540E\u7EED\u6BCF\u6761 CLI \u547D\u4EE4\u663E\u5F0F\u4F7F\u7528 MLB_GATEWAY_URL=${DEFAULT_MLB_TEST_URL}\uFF0C\u5148\u5728\u8BE5\u73AF\u5883\u91CD\u65B0\u8BFB\u53D6 buddy-cli guide\uFF0C\u518D\u767B\u5F55\u3001\u521B\u5EFA\u3001\u4FEE\u6539\u8D44\u6599\u3001\u9884\u89C8\u548C\u4E0A\u4F20\uFF1B\u9075\u5FAA\u516C\u5171\u73AF\u5883\u7684\u6700\u65B0\u7A33\u5B9A\u7248\u89C4\u5219\uFF0C\u4E0D\u518D\u8BE2\u95EE\u6D4B\u8BD5\u7248\u672C\u3002
|
|
3193
|
-
\u9009\u62E9\u5185\u90E8\u6D4B\u8BD5\uFF1A\u540E\u7EED\u547D\u4EE4\u6CBF\u7528\u5F53\u524D MLB_GATEWAY_URL\uFF1B\u5F00\u59CB\u751F\u6210 Runtime \u5DE5\u7A0B\u524D\uFF0C\u518D\u8BE2\u95EE\u4F7F\u7528\u6700\u65B0\u7A33\u5B9A\u7248\u3001\u6700\u65B0\u6D4B\u8BD5\u7248\u8FD8\u662F\u5176\u4ED6\u5DF2\u53D1\u5E03\u51C6\u786E\u7248\u672C\u3002\u4E0D\u80FD\u628A\u9009\u62E9\u5185\u90E8\u73AF\u5883\u7B49\u540C\u4E8E\u9009\u62E9 dev\u3002
|
|
3194
|
-
\u5728\u76EE\u6807\u73AF\u5883\u786E\u8BA4\u524D\uFF0C\u4E0D\u767B\u5F55\u3001\u767B\u8BB0\u642D\u5B50\u3001\u5B89\u88C5\u5DE5\u7A0B Runtime \u6216\u4E0A\u4F20\u3002\u5DF2\u6709\u5DE5\u7A0B\u5E94\u6838\u5BF9\u76EE\u6807\u8D26\u53F7\u4E0E\u642D\u5B50\u5F52\u5C5E\uFF0C\u4E0D\u628A\u4E00\u4E2A\u5E73\u53F0\u7684 buddyId \u6216\u51ED\u636E\u76F4\u63A5\u7528\u4E8E\u53E6\u4E00\u4E2A\u5E73\u53F0\uFF1B\u672C\u6B21\u4E0D\u81EA\u52A8\u8FC1\u79FB\u642D\u5B50\u3002\u9009\u62E9\u540E\u5728\u6574\u4E2A\u5F00\u53D1\u6D41\u7A0B\u6CBF\u7528\u5BF9\u5E94\u73AF\u5883\uFF0C\u4E0D\u8981\u6267\u884C\u5B8C\u4E00\u6B21\u547D\u4EE4\u53C8\u56DE\u5230\u7EC8\u7AEF\u9ED8\u8BA4\u5730\u5740\u3002\u5B8C\u6210\u73AF\u5883\u9009\u62E9\u540E\u518D\u6309\u4E0B\u9762\u89C4\u5219\u5F00\u59CB\u521B\u4F5C\u5BF9\u8BDD\u3002
|
|
3195
|
-
` : ""}
|
|
3265
|
+
|
|
3196
3266
|
\u51C6\u5907\u6210\u529F\u4E14\u7528\u6237\u5C1A\u672A\u8BF4\u660E\u521B\u4F5C\u60F3\u6CD5\u65F6\uFF0C\u76F4\u63A5\u7528\u4E00\u53E5\u7B80\u77ED\u95EE\u5019\u548C\u4E00\u4E2A\u95EE\u9898\u5F00\u573A\uFF0C\u4F8B\u5982\uFF1A\u201C\u51C6\u5907\u597D\u4E86\uFF01\u4F60\u60F3\u521B\u4F5C\u4E00\u4E2A\u600E\u6837\u7684\u642D\u5B50\uFF1F\u201D\u7136\u540E\u7B49\u5F85\u56DE\u7B54\uFF0C\u4E0D\u4EE5\u5B89\u88C5\u62A5\u544A\u7ED3\u675F\uFF0C\u4E0D\u5217\u51FA\u7248\u672C\u53F7\u3001\u670D\u52A1\u5668\u5730\u5740\u6216\u65E0\u5173\u7684\u73AF\u5883\u68C0\u67E5\u7ED3\u679C\u3002
|
|
3197
3267
|
\u5982\u679C\u7528\u6237\u5DF2\u7ECF\u7ED9\u51FA\u60F3\u6CD5\uFF0C\u6CBF\u7528\u5DF2\u6709\u4FE1\u606F\u63A8\u8FDB\uFF0C\u53EA\u8865\u95EE\u51B3\u5B9A\u4E0B\u4E00\u6B65\u7684\u5173\u952E\u7F3A\u53E3\uFF1B\u5982\u679C\u660E\u786E\u8981\u7EE7\u7EED\u5DF2\u6709\u5DE5\u7A0B\uFF0C\u5148\u8BFB\u53D6\u8BE5\u5DE5\u7A0B\u7684\u8D44\u6599\u3001\u4EE3\u7801\u4E0E HANDOFF.md\uFF0C\u518D\u63A5\u7EED\u5F53\u524D\u8FDB\u5EA6\u3002\u4E0D\u8981\u91CD\u65B0\u8BE2\u95EE\u7528\u6237\u5DF2\u56DE\u7B54\u7684\u95EE\u9898\uFF0C\u4E5F\u4E0D\u8981\u4EC5\u56E0\u5F53\u524D\u76EE\u5F55\u5B58\u5728\u5DE5\u7A0B\u5C31\u64C5\u81EA\u51B3\u5B9A\u6CBF\u7528\u5B83\u3002
|
|
3198
3268
|
\u7528\u6237\u5C1A\u672A\u8868\u8FBE\u521B\u4F5C\u65B9\u5411\u65F6\uFF0C\u4E0D\u63D0\u524D\u62DF\u5B9A\u642D\u5B50\u3001\u521D\u59CB\u5316\u5DE5\u7A0B\u6216\u542F\u52A8\u8BBF\u8C08\u3002\u9996\u6B21\u4EA4\u6D41\u524D\u53EA\u51C6\u5907 CLI \u53CA\u5176\u5FC5\u9700\u8FD0\u884C\u73AF\u5883\uFF1B\u767B\u5F55\u3001\u5DE5\u7A0B Runtime \u548C Creator/Avatar Skill \u6309\u540E\u7EED\u6D41\u7A0B\u9700\u8981\u518D\u51C6\u5907\uFF0C\u4E0D\u628A\u8FD9\u4E9B\u64CD\u4F5C\u8BBE\u4E3A\u5F00\u59CB\u804A\u5929\u7684\u524D\u63D0\u3002
|
|
@@ -3200,7 +3270,7 @@ ${selectedRuntime ? `\u5F53\u524D\u7EC8\u7AEF\u914D\u7F6E\u4E86\u81EA\u5B9A\u4E4
|
|
|
3200
3270
|
|
|
3201
3271
|
## CLI \u7248\u672C\u4E0E\u6267\u884C\u89C4\u5219
|
|
3202
3272
|
|
|
3203
|
-
\
|
|
3273
|
+
\u6B63\u5F0F\u7248 buddy-cli \u56FA\u5B9A\u8FDE\u63A5 ECS Test\uFF08${DEFAULT_MLB_TEST_URL}\uFF09\uFF0C\u767B\u5F55\u3001\u521B\u5EFA\u3001\u8D44\u6599\u4FEE\u6539\u3001\u4E0A\u4F20\u3001\u9884\u89C8\u4E0E Runtime \u4F7F\u7528\u540C\u4E00\u5E73\u53F0\u3002\u65E0\u9700\u8BBE\u7F6E\u7F51\u5173\u53D8\u91CF\u6216\u8BE2\u95EE\u53D1\u5E03\u73AF\u5883\u3002\u5730\u5740\u53C2\u6570\u4EC5\u6821\u9A8C\u76EE\u6807\uFF1B\u51B2\u7A81\u914D\u7F6E\u5FC5\u987B\u5148\u5904\u7406\uFF0C\u4E0D\u80FD\u7528 --refresh-token \u5207\u6362\u73AF\u5883\u3002Runtime \u5730\u5740\u7531 CLI \u6CE8\u5165\u3002\u5176\u4ED6\u73AF\u5883\u7684\u5DE5\u7A0B\u8BF7\u4F7F\u7528\u5BF9\u5E94 CLI\uFF1B\u9700\u8981\u8FC1\u79FB\u65F6\uFF0C\u5728\u65B0\u76EE\u5F55\u91CD\u65B0\u767B\u8BB0\u642D\u5B50\u540E\u590D\u5236\u4E1A\u52A1\u4EE3\u7801\uFF0C\u4E0D\u590D\u5236 .env\u3001buddyId \u6216\u51ED\u636E\u3002
|
|
3204
3274
|
|
|
3205
3275
|
preview \u8FDE\u63A5\u524D\u53CA dev \u542F\u52A8\u524D\u4F1A\u68C0\u67E5\u5DE5\u7A0B .env \u7F51\u5173\u3002\u68C0\u6D4B\u5230\u5DF2\u77E5\u65E7 ECS \u5730\u5740\u65F6\uFF0CCLI \u5728\u542F\u52A8 DEV \u65F6\u6821\u9A8C\u642D\u5B50\u5F52\u5C5E\u5E76\u81EA\u52A8\u66F4\u65B0\u8FDE\u63A5\u914D\u7F6E\uFF1BAgent \u8BFB\u53D6\u547D\u4EE4\u7ED3\u679C\u7EE7\u7EED\u64CD\u4F5C\uFF0C\u65E0\u9700\u624B\u6539 .env\u3002\u5176\u4ED6\u5E73\u53F0\u4E0D\u4E00\u81F4\u65F6\u5148\u786E\u8BA4\u76EE\u6807\u73AF\u5883\uFF0C\u4E0D\u53CD\u590D\u91CD\u8DD1\u547D\u4EE4\u6216\u64C5\u81EA\u8986\u76D6\u51ED\u636E\u3002
|
|
3206
3276
|
|
|
@@ -3229,59 +3299,25 @@ Coding Agent \u5E94\u4F20\u5165\u6309\u4E0A\u8FF0\u89C4\u5219\u786E\u5B9A\u7684\
|
|
|
3229
3299
|
Coding Agent \u6839\u636E\u5DF2\u786E\u8BA4\u624B\u518C\u6216\u9700\u6C42\u63A8\u8FDB\u5B9E\u73B0\uFF1B\u53EA\u4E3A\u5173\u952E\u7F3A\u53E3\u8BE2\u95EE\uFF0C\u4E0D\u56FA\u5B9A\u8FFD\u52A0\u7B56\u7565\u786E\u8BA4\u3002
|
|
3230
3300
|
\u6240\u6709\u642D\u5B50\u7EDF\u4E00\u4F7F\u7528\u5B98\u65B9 Runtime\uFF1B\u9700\u6C42\u660E\u786E\u65F6\u4F7F\u7528 --mode direct\uFF0C\u9700\u8981\u68B3\u7406\u9700\u6C42\u65F6\u4F7F\u7528 --mode create\u3002
|
|
3231
3301
|
|
|
3232
|
-
${implementationGuide(
|
|
3302
|
+
${implementationGuide()}
|
|
3233
3303
|
|
|
3234
3304
|
${DEVELOPMENT_HANDOFF}`;
|
|
3235
3305
|
}
|
|
3236
3306
|
var AGENT_GUIDE = renderAgentGuide();
|
|
3237
|
-
function initHelp(
|
|
3238
|
-
return
|
|
3239
|
-
\u5F53\u524D\u73AF\u5883\u7684 Runtime \u7248\u672C\u9009\u62E9\uFF1A
|
|
3240
|
-
--runtime-version <\u51C6\u786E\u7248\u672C|latest|dev> direct \u9996\u6B21\u751F\u6210 Runtime \u5DE5\u7A0B\u524D\u5FC5\u987B\u9009\u62E9\uFF1B\u975E\u4EA4\u4E92\u8C03\u7528\u7F3A\u5C11\u9009\u62E9\u4F1A\u8FD4\u56DE\u53EF\u7528\u7248\u672C\uFF0C\u4E0D\u767B\u8BB0\u8D44\u6599\u3002
|
|
3241
|
-
\u8BF7 Coding Agent \u5148\u8BE2\u95EE\u5F00\u53D1\u8005\uFF1Bcreate \u4EC5\u68B3\u7406\u9700\u6C42\uFF0C\u5728\u63A5\u7EED direct \u65F6\u518D\u9009\u62E9\u3002\u5DF2\u6709\u5DE5\u7A0B\u6CBF\u7528\u51C6\u786E\u7248\u672C\uFF0Cinit \u4E0D\u5347\u7EA7\u4F9D\u8D56\u3002` : INIT_HELP;
|
|
3307
|
+
function initHelp(_options = {}) {
|
|
3308
|
+
return INIT_HELP;
|
|
3242
3309
|
}
|
|
3243
|
-
function cliHelp(
|
|
3244
|
-
return
|
|
3310
|
+
function cliHelp(_options = {}) {
|
|
3311
|
+
return CLI_HELP;
|
|
3245
3312
|
}
|
|
3246
3313
|
|
|
3247
3314
|
// packages/cli-core/src/dev/local-stop.ts
|
|
3248
3315
|
import { execFile as execFile5 } from "node:child_process";
|
|
3249
3316
|
import { promisify as promisify5 } from "node:util";
|
|
3250
|
-
import { readFile as
|
|
3317
|
+
import { readFile as readFile13, readdir as readdir4, realpath as realpath5, rmdir as rmdir3, unlink as unlink8 } from "node:fs/promises";
|
|
3251
3318
|
import { join as join15 } from "node:path";
|
|
3252
3319
|
import { setTimeout as delay } from "node:timers/promises";
|
|
3253
3320
|
|
|
3254
|
-
// packages/cli-core/src/dev/errors.ts
|
|
3255
|
-
var BuddyDevError = class extends Error {
|
|
3256
|
-
/** Only explicitly safe, developer-facing explanations may be shown in Preview. */
|
|
3257
|
-
publicMessage;
|
|
3258
|
-
code;
|
|
3259
|
-
phase;
|
|
3260
|
-
retryable;
|
|
3261
|
-
constructor(options) {
|
|
3262
|
-
super(options.message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
3263
|
-
this.name = "BuddyDevError";
|
|
3264
|
-
this.publicMessage = options.publicMessage;
|
|
3265
|
-
this.code = options.code;
|
|
3266
|
-
this.phase = options.phase;
|
|
3267
|
-
this.retryable = options.retryable ?? false;
|
|
3268
|
-
}
|
|
3269
|
-
};
|
|
3270
|
-
function isAbortLike(error2) {
|
|
3271
|
-
return error2 instanceof DOMException && error2.name === "AbortError" || error2 instanceof Error && error2.name === "AbortError";
|
|
3272
|
-
}
|
|
3273
|
-
function abortedDevError(signal) {
|
|
3274
|
-
return new BuddyDevError({
|
|
3275
|
-
code: "DEV_ABORTED",
|
|
3276
|
-
phase: "stop",
|
|
3277
|
-
message: "\u642D\u642D DEV \u542F\u52A8\u5DF2\u53D6\u6D88\u3002",
|
|
3278
|
-
...signal?.reason === void 0 ? {} : { cause: signal.reason }
|
|
3279
|
-
});
|
|
3280
|
-
}
|
|
3281
|
-
function throwIfDevAborted(signal) {
|
|
3282
|
-
if (signal?.aborted) throw abortedDevError(signal);
|
|
3283
|
-
}
|
|
3284
|
-
|
|
3285
3321
|
// packages/cli-core/src/dev/process.ts
|
|
3286
3322
|
import { promisify as promisify4 } from "node:util";
|
|
3287
3323
|
import { spawn as spawnChild, execFile as execFile4 } from "node:child_process";
|
|
@@ -3579,7 +3615,7 @@ async function stopLocalDev(options) {
|
|
|
3579
3615
|
}
|
|
3580
3616
|
if (names.length !== 1 || !/^owner-[a-f0-9-]+\.json$/u.test(names[0])) throw failure("DEV \u9501\u4FE1\u606F\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u68C0\u67E5\u539F\u7EC8\u7AEF\uFF1B\u672A\u7EC8\u6B62\u4EFB\u4F55\u8FDB\u7A0B\u3002");
|
|
3581
3617
|
const ownerPath = join15(path, names[0]);
|
|
3582
|
-
const source = await
|
|
3618
|
+
const source = await readFile13(ownerPath, "utf8");
|
|
3583
3619
|
const owner = JSON.parse(source);
|
|
3584
3620
|
if (!validPid2(owner.pid) || owner.runtimePid !== void 0 && !validPid2(owner.runtimePid)) throw failure("DEV \u9501\u4E2D\u7684 PID \u65E0\u6548\u3002");
|
|
3585
3621
|
const root = await realpath5(options.projectRoot);
|
|
@@ -3607,7 +3643,7 @@ async function stopLocalDev(options) {
|
|
|
3607
3643
|
const cwd = (await exec("/usr/sbin/lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"])).stdout.split("\n").find((line) => line.startsWith("n"))?.slice(1);
|
|
3608
3644
|
if (!cwd || await realpath5(cwd) !== root || !identity.endsWith(` ${join15(root, "start.mjs")}`) || !/\bnode\s/u.test(identity)) throw failure(`\u65E0\u6CD5\u786E\u8BA4\u65E7 Runtime\uFF08PID ${pid}\uFF09\u5C5E\u4E8E\u5F53\u524D\u5DE5\u7A0B\uFF0C\u672A\u7EC8\u6B62\u8BE5\u8FDB\u7A0B\u3002`);
|
|
3609
3645
|
}
|
|
3610
|
-
if (await
|
|
3646
|
+
if (await readFile13(ownerPath, "utf8") !== source || await processIdentity(pid) !== identity || alive2(owner.pid)) throw failure("DEV \u8FDB\u7A0B\u72B6\u6001\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C dev stop\u3002");
|
|
3611
3647
|
try {
|
|
3612
3648
|
process.kill(-pid, "SIGTERM");
|
|
3613
3649
|
} catch (error2) {
|
|
@@ -3634,7 +3670,7 @@ async function stopLocalDev(options) {
|
|
|
3634
3670
|
}
|
|
3635
3671
|
if (pid && (alive2(pid) || alive2(-pid))) throw failure(`Runtime \u8FDB\u7A0B\u7EC4 ${pid} \u4ECD\u6709\u6B8B\u7559\u4E14\u65E0\u6CD5\u5B8C\u6574\u786E\u8BA4\u8EAB\u4EFD\uFF0C\u8BF7\u68C0\u67E5\u539F\u7EC8\u7AEF\uFF1B\u4FDD\u7559\u8FDB\u7A0B\u9501\u3002`);
|
|
3636
3672
|
try {
|
|
3637
|
-
if (await
|
|
3673
|
+
if (await readFile13(ownerPath, "utf8") === source) await unlink8(ownerPath);
|
|
3638
3674
|
} catch (error2) {
|
|
3639
3675
|
if (error2.code !== "ENOENT") throw error2;
|
|
3640
3676
|
}
|
|
@@ -3644,140 +3680,6 @@ async function stopLocalDev(options) {
|
|
|
3644
3680
|
return { stopped: true };
|
|
3645
3681
|
}
|
|
3646
3682
|
|
|
3647
|
-
// packages/cli-core/src/dev/project-env.ts
|
|
3648
|
-
import { constants } from "node:fs";
|
|
3649
|
-
import { open as open4, rename as rename9, unlink as unlink8 } from "node:fs/promises";
|
|
3650
|
-
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
3651
|
-
import { join as join16 } from "node:path";
|
|
3652
|
-
import { parseEnv } from "node:util";
|
|
3653
|
-
function invalid(message) {
|
|
3654
|
-
return new BuddyDevError({ code: "DEV_CONFIG_INVALID", phase: "config", message, publicMessage: message });
|
|
3655
|
-
}
|
|
3656
|
-
async function readLocalFile(path) {
|
|
3657
|
-
let file;
|
|
3658
|
-
try {
|
|
3659
|
-
file = await open4(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
3660
|
-
const stat2 = await file.stat();
|
|
3661
|
-
if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > 256 * 1024) throw invalid("\u672C\u5730\u914D\u7F6E\u5FC5\u987B\u662F\u5C0F\u4E8E 256 KB \u7684\u666E\u901A\u6587\u4EF6\uFF0C\u4E0D\u80FD\u4F7F\u7528\u94FE\u63A5\u3002");
|
|
3662
|
-
return await file.readFile("utf8");
|
|
3663
|
-
} catch (cause) {
|
|
3664
|
-
if (cause.code === "ENOENT") return "";
|
|
3665
|
-
if (cause instanceof BuddyDevError) throw cause;
|
|
3666
|
-
throw invalid("\u65E0\u6CD5\u8BFB\u53D6\u5DE5\u7A0B\u672C\u5730\u914D\u7F6E\uFF0C\u8BF7\u68C0\u67E5 .env \u548C .gitignore \u7684\u6587\u4EF6\u7C7B\u578B\u4E0E\u6743\u9650\u3002");
|
|
3667
|
-
} finally {
|
|
3668
|
-
await file?.close();
|
|
3669
|
-
}
|
|
3670
|
-
}
|
|
3671
|
-
async function readProjectEnvironment(projectRoot) {
|
|
3672
|
-
const source = await readLocalFile(join16(projectRoot, ".env"));
|
|
3673
|
-
let values;
|
|
3674
|
-
try {
|
|
3675
|
-
values = parseEnv(source);
|
|
3676
|
-
} catch {
|
|
3677
|
-
throw invalid("\u5DE5\u7A0B .env \u683C\u5F0F\u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002");
|
|
3678
|
-
}
|
|
3679
|
-
return values;
|
|
3680
|
-
}
|
|
3681
|
-
function gatewayNeedsRefresh(value, gatewayUrl) {
|
|
3682
|
-
if (value) {
|
|
3683
|
-
if (isLegacyEcsGateway(value)) {
|
|
3684
|
-
if (gatewayUrl.href === `${DEFAULT_MLB_TEST_URL}/`) return true;
|
|
3685
|
-
throw invalid(".env \u4FDD\u5B58\u7684\u662F\u65E7\u516C\u5171\u73AF\u5883\u5730\u5740\uFF0C\u4E0E\u672C\u6B21\u5E73\u53F0\u4E0D\u540C\uFF1B\u8BF7\u786E\u8BA4\u76EE\u6807\u5E73\u53F0\u540E\u4F7F\u7528 --refresh-token \u66F4\u65B0\u8FDE\u63A5\u914D\u7F6E\u3002");
|
|
3686
|
-
}
|
|
3687
|
-
let gateway;
|
|
3688
|
-
try {
|
|
3689
|
-
gateway = normalizePlatformUrl(value);
|
|
3690
|
-
} catch {
|
|
3691
|
-
throw invalid(".env \u4E2D\u7684 MLB_GATEWAY_URL \u65E0\u6548\uFF1B\u8BF7\u786E\u8BA4\u5E73\u53F0\u540E\u4F7F\u7528 --refresh-token \u91CD\u65B0\u9886\u53D6\u5F00\u53D1\u4EE4\u724C\u5E76\u66F4\u65B0\u5730\u5740\u3002");
|
|
3692
|
-
}
|
|
3693
|
-
if (gateway.href !== gatewayUrl.href) throw invalid(".env \u7684\u5E73\u53F0\u5730\u5740\u4E0E\u672C\u6B21\u542F\u52A8\u4E0D\u540C\uFF1B\u8BF7\u786E\u8BA4\u76EE\u6807\u5E73\u53F0\uFF0C\u6216\u5728\u660E\u786E\u5207\u6362\u5E73\u53F0\u65F6\u4F7F\u7528 --refresh-token \u66F4\u65B0\u8FDE\u63A5\u914D\u7F6E\u3002");
|
|
3694
|
-
}
|
|
3695
|
-
return false;
|
|
3696
|
-
}
|
|
3697
|
-
async function checkProjectGateway(projectRoot, gatewayUrl, options = {}) {
|
|
3698
|
-
const values = await readProjectEnvironment(projectRoot);
|
|
3699
|
-
if (!options.refreshToken && gatewayNeedsRefresh(values.MLB_GATEWAY_URL, gatewayUrl)) {
|
|
3700
|
-
options.report?.("\u68C0\u6D4B\u5230\u5DE5\u7A0B\u4F7F\u7528\u65E7 ECS \u5730\u5740\uFF1B\u542F\u52A8 DEV \u65F6\u5C06\u6821\u9A8C\u642D\u5B50\u5F52\u5C5E\uFF0C\u5E76\u81EA\u52A8\u66F4\u65B0\u5730\u5740\u548C\u5F00\u53D1\u51ED\u636E\u3002");
|
|
3701
|
-
}
|
|
3702
|
-
}
|
|
3703
|
-
async function projectBuddyToken(projectRoot, gatewayUrl) {
|
|
3704
|
-
const values = await readProjectEnvironment(projectRoot);
|
|
3705
|
-
if (gatewayNeedsRefresh(values.MLB_GATEWAY_URL, gatewayUrl) || !values.BUDDY_TOKEN) return void 0;
|
|
3706
|
-
if (!values.BUDDY_TOKEN.trim() || /[\u0000-\u001f\u007f]/u.test(values.BUDDY_TOKEN)) throw invalid(".env \u4E2D\u7684\u5F00\u53D1\u4EE4\u724C\u683C\u5F0F\u65E0\u6548\uFF0C\u8BF7\u4F7F\u7528 --refresh-token \u91CD\u65B0\u9886\u53D6\u3002");
|
|
3707
|
-
return values.BUDDY_TOKEN;
|
|
3708
|
-
}
|
|
3709
|
-
function quote(value) {
|
|
3710
|
-
if (/[\u0000-\u001f\u007f]/u.test(value)) throw invalid("\u672C\u5730\u8FD0\u884C\u914D\u7F6E\u4E0D\u80FD\u5305\u542B\u63A7\u5236\u5B57\u7B26\u3002");
|
|
3711
|
-
const delimiter = ["'", '"', "`"].find((character) => !value.includes(character));
|
|
3712
|
-
if (!delimiter) throw invalid("\u672C\u5730\u8FD0\u884C\u914D\u7F6E\u5305\u542B\u65E0\u6CD5\u5199\u5165 .env \u7684\u5F15\u53F7\u7EC4\u5408\u3002");
|
|
3713
|
-
return `${delimiter}${value}${delimiter}`;
|
|
3714
|
-
}
|
|
3715
|
-
function updateValues(source, values) {
|
|
3716
|
-
const assignment = /^[\t ]*(?:export[\t ]+)?([A-Za-z_][A-Za-z0-9_]*)[\t ]*=[\t ]*/gm;
|
|
3717
|
-
let output = "", cursor = 0, match;
|
|
3718
|
-
const written = /* @__PURE__ */ new Set();
|
|
3719
|
-
while (match = assignment.exec(source)) {
|
|
3720
|
-
const valueStart = assignment.lastIndex;
|
|
3721
|
-
let end = source.indexOf("\n", valueStart);
|
|
3722
|
-
if (end < 0) end = source.length;
|
|
3723
|
-
let commentStart = valueStart;
|
|
3724
|
-
const delimiter = source[valueStart];
|
|
3725
|
-
if (delimiter && ["'", '"', "`"].includes(delimiter)) {
|
|
3726
|
-
const close = source.indexOf(delimiter, valueStart + 1);
|
|
3727
|
-
if (close < 0) throw invalid(".env \u4E2D\u6709\u672A\u95ED\u5408\u7684\u5F15\u53F7\uFF0C\u8BF7\u4FEE\u6B63\u540E\u91CD\u8BD5\u3002");
|
|
3728
|
-
commentStart = close + 1;
|
|
3729
|
-
end = source.indexOf("\n", close + 1);
|
|
3730
|
-
if (end < 0) end = source.length;
|
|
3731
|
-
}
|
|
3732
|
-
assignment.lastIndex = end;
|
|
3733
|
-
const name = match[1];
|
|
3734
|
-
if (!(name in values)) continue;
|
|
3735
|
-
const comment = source.slice(commentStart, end).match(/[\t ]*#[^\r\n]*/u)?.[0] ?? "";
|
|
3736
|
-
output += source.slice(cursor, match.index);
|
|
3737
|
-
output += written.has(name) || values[name] === void 0 ? comment : `${name}=${quote(values[name])}${comment ? ` ${comment.trimStart()}` : ""}`;
|
|
3738
|
-
if (source[end - 1] === "\r") output += "\r";
|
|
3739
|
-
cursor = end;
|
|
3740
|
-
written.add(name);
|
|
3741
|
-
}
|
|
3742
|
-
output += source.slice(cursor);
|
|
3743
|
-
const newline = source.includes("\r\n") ? "\r\n" : "\n";
|
|
3744
|
-
for (const [name, value] of Object.entries(values)) if (value !== void 0 && !written.has(name)) {
|
|
3745
|
-
if (output && !output.endsWith("\n")) output += newline;
|
|
3746
|
-
output += `${name}=${quote(value)}${newline}`;
|
|
3747
|
-
}
|
|
3748
|
-
const parsed = parseEnv(output);
|
|
3749
|
-
if (Object.entries(values).some(([name, value]) => parsed[name] !== value)) throw invalid("\u65E0\u6CD5\u5B8C\u6574\u66F4\u65B0 .env\uFF0C\u8BF7\u68C0\u67E5\u6587\u4EF6\u683C\u5F0F\u3002");
|
|
3750
|
-
return output;
|
|
3751
|
-
}
|
|
3752
|
-
async function replaceFile2(path, contents, mode) {
|
|
3753
|
-
const temporary = `${path}.${randomUUID7()}.tmp`;
|
|
3754
|
-
let file;
|
|
3755
|
-
try {
|
|
3756
|
-
file = await open4(temporary, "wx", mode);
|
|
3757
|
-
await file.writeFile(contents, "utf8");
|
|
3758
|
-
await file.sync();
|
|
3759
|
-
await file.close();
|
|
3760
|
-
file = void 0;
|
|
3761
|
-
await rename9(temporary, path);
|
|
3762
|
-
} finally {
|
|
3763
|
-
await file?.close();
|
|
3764
|
-
await unlink8(temporary).catch((cause) => {
|
|
3765
|
-
if (cause.code !== "ENOENT") throw cause;
|
|
3766
|
-
});
|
|
3767
|
-
}
|
|
3768
|
-
}
|
|
3769
|
-
async function writeProjectEnvironment(projectRoot, values) {
|
|
3770
|
-
const envPath = join16(projectRoot, ".env"), ignorePath = join16(projectRoot, ".gitignore");
|
|
3771
|
-
const contents = updateValues(await readLocalFile(envPath), { ...values, BUDDY_ID: void 0 });
|
|
3772
|
-
const ignored = await readLocalFile(ignorePath);
|
|
3773
|
-
if (ignored.trimEnd().split(/\r?\n/u).at(-1) !== "/.env") {
|
|
3774
|
-
await replaceFile2(ignorePath, `${ignored}${ignored && !ignored.endsWith("\n") ? "\n" : ""}/.env
|
|
3775
|
-
`, 420);
|
|
3776
|
-
}
|
|
3777
|
-
await replaceFile2(envPath, contents, 384);
|
|
3778
|
-
return contents;
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
3683
|
// packages/cli-core/src/commands/dev.ts
|
|
3782
3684
|
import { resolve as resolve14 } from "node:path";
|
|
3783
3685
|
|
|
@@ -3811,7 +3713,8 @@ async function responseJson(response) {
|
|
|
3811
3713
|
throw new BuddyDevError({
|
|
3812
3714
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3813
3715
|
phase: "registration",
|
|
3814
|
-
message: "App Server \u8FD4\u56DE\u7684 JSON \u8FC7\u5927\u3002"
|
|
3716
|
+
message: "App Server \u8FD4\u56DE\u7684 JSON \u8FC7\u5927\u3002",
|
|
3717
|
+
publicMessage: "\u5F00\u53D1\u5E73\u53F0\u8FD4\u56DE\u7684\u6570\u636E\u8D85\u8FC7\u5927\u5C0F\u9650\u5236\uFF0C\u5DF2\u505C\u6B62\u542F\u52A8\uFF1B\u8BF7\u8054\u7CFB\u5E73\u53F0\u7EF4\u62A4\u8005\u3002"
|
|
3815
3718
|
});
|
|
3816
3719
|
}
|
|
3817
3720
|
parts.push(decoder.decode(item.value, { stream: true }));
|
|
@@ -3829,6 +3732,7 @@ async function responseJson(response) {
|
|
|
3829
3732
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3830
3733
|
phase: "registration",
|
|
3831
3734
|
message: `App Server \u8FD4\u56DE\u4E86\u65E0\u6548 JSON\uFF08HTTP ${response.status}\uFF09\u3002`,
|
|
3735
|
+
publicMessage: `\u5F00\u53D1\u5E73\u53F0\u8FD4\u56DE\u4E86\u65E0\u6548 JSON\uFF08HTTP ${response.status}\uFF09\uFF1B\u8BF7\u68C0\u67E5\u5E73\u53F0\u5730\u5740\uFF0C\u82E5\u4ECD\u5931\u8D25\u8BF7\u8054\u7CFB\u5E73\u53F0\u7EF4\u62A4\u8005\u3002`,
|
|
3832
3736
|
cause
|
|
3833
3737
|
});
|
|
3834
3738
|
}
|
|
@@ -3838,6 +3742,13 @@ function safeServerError(value, fallback) {
|
|
|
3838
3742
|
if (typeof candidate !== "string" || !candidate.trim()) return fallback;
|
|
3839
3743
|
return candidate.slice(0, 1024).replace(/[\u0000-\u001f\u007f]/gu, " ");
|
|
3840
3744
|
}
|
|
3745
|
+
function httpFailureMessage(status) {
|
|
3746
|
+
if (status === 401) return "\u642D\u642D\u8D26\u53F7\u767B\u5F55\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C buddy-cli login\u3002";
|
|
3747
|
+
if (status === 403) return "\u5F53\u524D\u8D26\u53F7\u65E0\u6743\u8BBF\u95EE\u8FD9\u4E2A\u642D\u5B50\uFF0C\u8BF7\u786E\u8BA4\u767B\u5F55\u8D26\u53F7\u548C\u5DE5\u7A0B\u7684 buddyId\u3002";
|
|
3748
|
+
if (status === 404) return "\u5F53\u524D\u5E73\u53F0\u672A\u627E\u5230\u8FD9\u4E2A\u642D\u5B50\uFF0C\u8BF7\u786E\u8BA4\u5E73\u53F0\u5730\u5740\u548C\u5DE5\u7A0B\u7684 buddyId\u3002";
|
|
3749
|
+
if (status === 429) return "\u5F00\u53D1\u5E73\u53F0\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
|
|
3750
|
+
return `\u5F00\u53D1\u5E73\u53F0\u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${status}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\uFF1B\u6301\u7EED\u5931\u8D25\u8BF7\u8054\u7CFB\u5E73\u53F0\u7EF4\u62A4\u8005\u3002`;
|
|
3751
|
+
}
|
|
3841
3752
|
var MlbDevRegistrationClient = class {
|
|
3842
3753
|
#baseUrl;
|
|
3843
3754
|
#developerToken;
|
|
@@ -3884,7 +3795,8 @@ var MlbDevRegistrationClient = class {
|
|
|
3884
3795
|
throw new BuddyDevError({
|
|
3885
3796
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3886
3797
|
phase: "registration",
|
|
3887
|
-
message: "DEV App Server \u6210\u529F\u54CD\u5E94\u5FC5\u987B\u4F7F\u7528 application/json\u3002"
|
|
3798
|
+
message: "DEV App Server \u6210\u529F\u54CD\u5E94\u5FC5\u987B\u4F7F\u7528 application/json\u3002",
|
|
3799
|
+
publicMessage: "\u5F00\u53D1\u5E73\u53F0\u8FD4\u56DE\u7684\u5185\u5BB9\u4E0D\u662F JSON\uFF1B\u8BF7\u68C0\u67E5\u5E73\u53F0\u5730\u5740\u662F\u5426\u6B63\u786E\uFF0C\u82E5\u4ECD\u5931\u8D25\u8BF7\u8054\u7CFB\u5E73\u53F0\u7EF4\u62A4\u8005\u3002"
|
|
3888
3800
|
});
|
|
3889
3801
|
}
|
|
3890
3802
|
let body;
|
|
@@ -3896,6 +3808,7 @@ var MlbDevRegistrationClient = class {
|
|
|
3896
3808
|
code: "DEV_APP_SERVER_HTTP_ERROR",
|
|
3897
3809
|
phase: "registration",
|
|
3898
3810
|
message: `DEV App Server \u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${response.status}\uFF09\u3002`,
|
|
3811
|
+
publicMessage: httpFailureMessage(response.status),
|
|
3899
3812
|
retryable: response.status === 408 || response.status === 429 || response.status >= 500,
|
|
3900
3813
|
cause
|
|
3901
3814
|
});
|
|
@@ -3907,7 +3820,7 @@ var MlbDevRegistrationClient = class {
|
|
|
3907
3820
|
code: "DEV_APP_SERVER_HTTP_ERROR",
|
|
3908
3821
|
phase: "registration",
|
|
3909
3822
|
message: safeServerError(body, `DEV App Server \u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${response.status}\uFF09\u3002`),
|
|
3910
|
-
publicMessage: response.status
|
|
3823
|
+
publicMessage: httpFailureMessage(response.status),
|
|
3911
3824
|
retryable: response.status === 408 || response.status === 429 || response.status >= 500
|
|
3912
3825
|
});
|
|
3913
3826
|
}
|
|
@@ -3922,7 +3835,7 @@ var MlbDevRegistrationClient = class {
|
|
|
3922
3835
|
});
|
|
3923
3836
|
}
|
|
3924
3837
|
options.signal.throwIfAborted();
|
|
3925
|
-
if (request.projectRoot) await
|
|
3838
|
+
if (request.projectRoot) await checkProjectGateway(request.projectRoot, this.#baseUrl);
|
|
3926
3839
|
const localToken = request.projectRoot && !this.#refreshToken ? await projectBuddyToken(request.projectRoot, this.#baseUrl) : void 0;
|
|
3927
3840
|
const store = request.projectRoot ? void 0 : this.#tokenStoreFor?.(request.devAgentId);
|
|
3928
3841
|
const cached2 = this.#refreshToken ? void 0 : await store?.load();
|
|
@@ -3969,19 +3882,22 @@ var MlbDevRegistrationClient = class {
|
|
|
3969
3882
|
throw new BuddyDevError({
|
|
3970
3883
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3971
3884
|
phase: "registration",
|
|
3972
|
-
message: "DEV \u5728\u7EBF\u5217\u8868\u54CD\u5E94\u7F3A\u5C11 online \u6570\u7EC4\u3002"
|
|
3885
|
+
message: "DEV \u5728\u7EBF\u5217\u8868\u54CD\u5E94\u7F3A\u5C11 online \u6570\u7EC4\u3002",
|
|
3886
|
+
publicMessage: "\u5F00\u53D1\u5E73\u53F0\u7684\u5728\u7EBF\u5217\u8868\u683C\u5F0F\u4E0D\u7B26\u5408\u9884\u671F\uFF08\u7F3A\u5C11 online \u6570\u7EC4\uFF09\uFF1B\u8BF7\u66F4\u65B0 CLI\uFF0C\u82E5\u4ECD\u5931\u8D25\u8BF7\u8054\u7CFB\u5E73\u53F0\u7EF4\u62A4\u8005\u3002"
|
|
3973
3887
|
});
|
|
3974
3888
|
}
|
|
3975
3889
|
const states = body.online.flatMap((item, index) => {
|
|
3976
|
-
|
|
3890
|
+
const id = typeof item === "string" ? item : object2(item)?.id;
|
|
3891
|
+
if (typeof id !== "string" || !id.trim() || id !== id.trim() || /[\u0000-\u001f\u007f]/u.test(id) || id === "-dev") {
|
|
3977
3892
|
throw new BuddyDevError({
|
|
3978
3893
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3979
3894
|
phase: "registration",
|
|
3980
|
-
message: `DEV \u5728\u7EBF\u5217\u8868\u7B2C ${index + 1} \u9879\u65E0\u6548\u3002
|
|
3895
|
+
message: `DEV \u5728\u7EBF\u5217\u8868\u7B2C ${index + 1} \u9879\u65E0\u6548\u3002`,
|
|
3896
|
+
publicMessage: `\u5F00\u53D1\u5E73\u53F0\u5728\u7EBF\u5217\u8868\u7B2C ${index + 1} \u9879\u7F3A\u5C11\u6709\u6548\u7684\u642D\u5B50 ID\uFF1B\u8BF7\u66F4\u65B0 CLI\uFF0C\u82E5\u4ECD\u5931\u8D25\u8BF7\u8054\u7CFB\u5E73\u53F0\u7EF4\u62A4\u8005\u3002`
|
|
3981
3897
|
});
|
|
3982
3898
|
}
|
|
3983
|
-
if (!
|
|
3984
|
-
const devAgentId =
|
|
3899
|
+
if (!id.endsWith("-dev")) return [];
|
|
3900
|
+
const devAgentId = id.slice(0, -4);
|
|
3985
3901
|
return [Object.freeze({ devAgentId, online: true })];
|
|
3986
3902
|
});
|
|
3987
3903
|
return Object.freeze(states);
|
|
@@ -4053,23 +3969,24 @@ function buildAgentEnvironment(options) {
|
|
|
4053
3969
|
|
|
4054
3970
|
// packages/cli-core/src/dev/orchestrator.ts
|
|
4055
3971
|
import { createHash as createHash7 } from "node:crypto";
|
|
4056
|
-
import { readFile as
|
|
4057
|
-
import { join as
|
|
3972
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
3973
|
+
import { join as join18, resolve as resolve12 } from "node:path";
|
|
3974
|
+
import { stripVTControlCharacters } from "node:util";
|
|
4058
3975
|
|
|
4059
3976
|
// packages/cli-core/src/dev/reload.ts
|
|
4060
3977
|
import { watch } from "node:fs";
|
|
4061
3978
|
import { createHash as createHash6 } from "node:crypto";
|
|
4062
|
-
import { readFile as
|
|
4063
|
-
import { join as
|
|
3979
|
+
import { readFile as readFile14, readdir as readdir5 } from "node:fs/promises";
|
|
3980
|
+
import { join as join16, resolve as resolve9 } from "node:path";
|
|
4064
3981
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
4065
3982
|
var digest2 = (contents) => createHash6("sha256").update(contents).digest("hex");
|
|
4066
3983
|
async function snapshot(root, prefix = "", result = /* @__PURE__ */ new Map()) {
|
|
4067
|
-
for (const entry2 of await readdir5(
|
|
3984
|
+
for (const entry2 of await readdir5(join16(root, prefix), { withFileTypes: true })) {
|
|
4068
3985
|
const path = prefix ? `${prefix}/${entry2.name}` : entry2.name;
|
|
4069
3986
|
if (!relevant(path)) continue;
|
|
4070
3987
|
try {
|
|
4071
3988
|
if (entry2.isDirectory()) await snapshot(root, path, result);
|
|
4072
|
-
else if (entry2.isFile()) result.set(path, digest2(await
|
|
3989
|
+
else if (entry2.isFile()) result.set(path, digest2(await readFile14(join16(root, path))));
|
|
4073
3990
|
} catch (cause) {
|
|
4074
3991
|
if (cause.code !== "ENOENT") throw cause;
|
|
4075
3992
|
}
|
|
@@ -4159,7 +4076,7 @@ var ReloadingDevSession = class {
|
|
|
4159
4076
|
const path = String(name);
|
|
4160
4077
|
if (!relevant(path)) return;
|
|
4161
4078
|
if (path === ".env") {
|
|
4162
|
-
void
|
|
4079
|
+
void readFile14(join16(this.projectRoot, path), "utf8").then((contents) => {
|
|
4163
4080
|
if (contents !== this.#environment) {
|
|
4164
4081
|
this.#environment = contents;
|
|
4165
4082
|
this.#changed();
|
|
@@ -4342,7 +4259,7 @@ function startReloadingDev(options, startProcess) {
|
|
|
4342
4259
|
}
|
|
4343
4260
|
|
|
4344
4261
|
// packages/cli-core/src/config/runtime-policy.ts
|
|
4345
|
-
import { readFile as
|
|
4262
|
+
import { readFile as readFile15, realpath as realpath6 } from "node:fs/promises";
|
|
4346
4263
|
import { createRequire as createRequire2 } from "node:module";
|
|
4347
4264
|
import { resolve as resolve10 } from "node:path";
|
|
4348
4265
|
var RuntimeRequirementError = class extends Error {
|
|
@@ -4370,26 +4287,23 @@ function assertNpmRuntimeLock(contents, expected) {
|
|
|
4370
4287
|
}
|
|
4371
4288
|
}
|
|
4372
4289
|
async function requireProjectRuntime(root, options = {}) {
|
|
4373
|
-
const selected = allowsRuntimeVersionSelection(options);
|
|
4374
|
-
const declared = await projectRuntimeVersion(root);
|
|
4375
|
-
if (selected && !declared) throw new RuntimeRequirementError("RUNTIME_DEPENDENCY_INVALID", "\u5DE5\u7A0B\u5FC5\u987B\u5728 package.json \u58F0\u660E Runtime \u7684\u51C6\u786E\u7248\u672C\uFF1B\u8BF7\u5148\u9009\u62E9\u7248\u672C\u5E76\u5B89\u88C5\u4F9D\u8D56\u548C\u9501\u6587\u4EF6\uFF0C\u4E0D\u80FD\u4F7F\u7528 dev\u3001latest \u6216\u7248\u672C\u8303\u56F4\u4F5C\u4E3A\u5DE5\u7A0B\u4F9D\u8D56\u3002");
|
|
4376
4290
|
let expected;
|
|
4377
4291
|
try {
|
|
4378
|
-
expected =
|
|
4292
|
+
expected = await latestRuntimeVersion(options);
|
|
4379
4293
|
} catch (cause) {
|
|
4380
4294
|
options.signal?.throwIfAborted();
|
|
4381
|
-
throw new RuntimeRequirementError("RUNTIME_CHECK_FAILED", `\u65E0\u6CD5\u786E\u8BA4 npm
|
|
4295
|
+
throw new RuntimeRequirementError("RUNTIME_CHECK_FAILED", `\u65E0\u6CD5\u786E\u8BA4 npm \u6700\u65B0\u6B63\u5F0F\u7248 Runtime\uFF0C\u5DF2\u963B\u6B62\u8FD0\u884C\u6216\u4E0A\u4F20\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u8BF7\u6062\u590D\u8FDE\u63A5\u540E\u91CD\u8BD5\u3002`, { cause });
|
|
4382
4296
|
}
|
|
4383
4297
|
try {
|
|
4384
4298
|
assertRequiredRuntime(await projectRuntimeVersion(root), expected);
|
|
4385
4299
|
const installedPath = await realpath6(resolve10(root, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"));
|
|
4386
4300
|
const fromProject = createRequire2(resolve10(root, "package.json")).resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`);
|
|
4387
4301
|
if (await realpath6(fromProject) !== installedPath) throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
|
|
4388
|
-
const installed2 = JSON.parse(await
|
|
4302
|
+
const installed2 = JSON.parse(await readFile15(installedPath, "utf8"));
|
|
4389
4303
|
if (installed2.version !== expected) throw new Error(`Runtime \u5B9E\u9645\u5B89\u88C5 ${installed2.version}\uFF0C\u8981\u6C42 ${expected}`);
|
|
4390
4304
|
let lock;
|
|
4391
4305
|
try {
|
|
4392
|
-
lock = await
|
|
4306
|
+
lock = await readFile15(resolve10(root, "package-lock.json"), "utf8");
|
|
4393
4307
|
} catch (cause) {
|
|
4394
4308
|
if (cause.code !== "ENOENT") throw cause;
|
|
4395
4309
|
}
|
|
@@ -4409,8 +4323,8 @@ import { createRequire as createRequire3 } from "node:module";
|
|
|
4409
4323
|
import { dirname as dirname4, resolve as resolve11 } from "node:path";
|
|
4410
4324
|
|
|
4411
4325
|
// packages/cli-core/src/config/data-access.ts
|
|
4412
|
-
import { lstat as lstat10, readFile as
|
|
4413
|
-
import { join as
|
|
4326
|
+
import { lstat as lstat10, readFile as readFile16 } from "node:fs/promises";
|
|
4327
|
+
import { join as join17 } from "node:path";
|
|
4414
4328
|
var DATA_ACCESS_FILENAME = "data-access.json";
|
|
4415
4329
|
function parseDataAccessRequirements(source) {
|
|
4416
4330
|
if (source === void 0) return [];
|
|
@@ -4438,10 +4352,10 @@ function parseDataAccessRequirements(source) {
|
|
|
4438
4352
|
});
|
|
4439
4353
|
}
|
|
4440
4354
|
async function readDataAccessRequirements(projectRoot) {
|
|
4441
|
-
const path =
|
|
4355
|
+
const path = join17(projectRoot, DATA_ACCESS_FILENAME);
|
|
4442
4356
|
try {
|
|
4443
4357
|
if (!(await lstat10(path)).isFile()) throw new Error(`${DATA_ACCESS_FILENAME} \u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6`);
|
|
4444
|
-
return parseDataAccessRequirements(await
|
|
4358
|
+
return parseDataAccessRequirements(await readFile16(path, "utf8"));
|
|
4445
4359
|
} catch (cause) {
|
|
4446
4360
|
if (cause.code === "ENOENT") return [];
|
|
4447
4361
|
throw cause;
|
|
@@ -4597,6 +4511,7 @@ async function waitForAgentOnline(options) {
|
|
|
4597
4511
|
code: "DEV_AGENT_ONLINE_TIMEOUT",
|
|
4598
4512
|
phase: "online",
|
|
4599
4513
|
message: `Runtime ${options.devAgentId} \u5728 ${options.timeoutMs}ms \u5185\u6CA1\u6709\u8FDE\u63A5 DEV App Server\u3002`,
|
|
4514
|
+
publicMessage: "Runtime \u672A\u5728\u7B49\u5F85\u65F6\u95F4\u5185\u8FDE\u63A5\u5F00\u53D1\u5E73\u53F0\uFF1B\u8BF7\u68C0\u67E5\u8FD0\u884C\u65E5\u5FD7\u3001\u7F51\u7EDC\u548C\u5DE5\u7A0B\u7684\u542F\u52A8\u547D\u4EE4\u540E\u91CD\u8BD5\u3002",
|
|
4600
4515
|
retryable: true,
|
|
4601
4516
|
...lastError === void 0 ? {} : { cause: lastError }
|
|
4602
4517
|
});
|
|
@@ -4615,12 +4530,13 @@ async function waitForAgentOnline(options) {
|
|
|
4615
4530
|
await delay2(Math.min(options.pollIntervalMs, Math.max(1, deadline - Date.now())), options.signal);
|
|
4616
4531
|
}
|
|
4617
4532
|
}
|
|
4618
|
-
function agentExitedError(exit,
|
|
4533
|
+
function agentExitedError(exit, diagnostics = "") {
|
|
4619
4534
|
const detail = exit.error !== void 0 ? exit.error.message : exit.signal !== null ? `signal ${exit.signal}` : `exit code ${exit.code ?? "unknown"}`;
|
|
4620
4535
|
return new BuddyDevError({
|
|
4621
4536
|
code: "DEV_AGENT_EXITED",
|
|
4622
4537
|
phase: "running",
|
|
4623
|
-
message: `Buddy Runtime \u8FDB\u7A0B\u5728 DEV \u4F1A\u8BDD\u671F\u95F4\u9000\u51FA\uFF08${detail}\uFF09\u3002${
|
|
4538
|
+
message: `Buddy Runtime \u8FDB\u7A0B\u5728 DEV \u4F1A\u8BDD\u671F\u95F4\u9000\u51FA\uFF08${detail}\uFF09\u3002${diagnostics ? ` ${diagnostics}` : ""}`,
|
|
4539
|
+
publicMessage: `Runtime \u8FDB\u7A0B\u5DF2\u9000\u51FA${exit.error ? "" : `\uFF08${detail}\uFF09`}\u3002${diagnostics || "\u8BF7\u68C0\u67E5\u8FD0\u884C\u65E5\u5FD7\u3001\u542F\u52A8\u547D\u4EE4\u548C\u5DE5\u7A0B\u4F9D\u8D56\u540E\u91CD\u8BD5\u3002"}`.slice(0, 512),
|
|
4624
4540
|
...exit.error === void 0 ? {} : { cause: exit.error }
|
|
4625
4541
|
});
|
|
4626
4542
|
}
|
|
@@ -4636,6 +4552,7 @@ var ReadyBuddyDevHandle = class {
|
|
|
4636
4552
|
#lifecycle;
|
|
4637
4553
|
#stopGracePeriodMs;
|
|
4638
4554
|
#onStateChange;
|
|
4555
|
+
#failureDetail;
|
|
4639
4556
|
#signal;
|
|
4640
4557
|
#onAbort;
|
|
4641
4558
|
#state = "ready";
|
|
@@ -4653,6 +4570,7 @@ var ReadyBuddyDevHandle = class {
|
|
|
4653
4570
|
this.#stopGracePeriodMs = options.stopGracePeriodMs;
|
|
4654
4571
|
this.#signal = options.signal;
|
|
4655
4572
|
this.#onStateChange = options.onStateChange;
|
|
4573
|
+
this.#failureDetail = options.failureDetail;
|
|
4656
4574
|
this.#onAbort = () => {
|
|
4657
4575
|
void this.stop().catch(() => void 0);
|
|
4658
4576
|
};
|
|
@@ -4663,7 +4581,7 @@ var ReadyBuddyDevHandle = class {
|
|
|
4663
4581
|
else options.signal?.addEventListener("abort", this.#onAbort, { once: true });
|
|
4664
4582
|
this.#emit("ready");
|
|
4665
4583
|
void this.#process.exit.then(async (exit) => {
|
|
4666
|
-
if (this.#state === "ready") await this.#fail(agentExitedError(exit));
|
|
4584
|
+
if (this.#state === "ready") await this.#fail(agentExitedError(exit, this.#failureDetail()));
|
|
4667
4585
|
});
|
|
4668
4586
|
}
|
|
4669
4587
|
get state() {
|
|
@@ -4745,12 +4663,35 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4745
4663
|
let agentProcess;
|
|
4746
4664
|
let processTree;
|
|
4747
4665
|
let instanceLock;
|
|
4748
|
-
|
|
4666
|
+
const output = { stdout: "", stderr: "" };
|
|
4667
|
+
const truncated = { stdout: false, stderr: false };
|
|
4749
4668
|
let secrets = [];
|
|
4669
|
+
const capture2 = (source, text2) => {
|
|
4670
|
+
const next = output[source] + text2;
|
|
4671
|
+
truncated[source] ||= next.length > 16384;
|
|
4672
|
+
output[source] = next.slice(-16384);
|
|
4673
|
+
options.onLog?.({ source: `agent.${source}`, text: text2 });
|
|
4674
|
+
};
|
|
4750
4675
|
const failureDetail = () => {
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4676
|
+
const clean = (source) => {
|
|
4677
|
+
let text2 = stripVTControlCharacters(truncated[source] ? output[source].replace(/^[^\n]*(?:\n|$)/u, "") : output[source]);
|
|
4678
|
+
for (const secret of secrets) if (secret) text2 = text2.split(secret).join("[REDACTED]");
|
|
4679
|
+
return text2.replace(/https?:\/\/[^\s<>"']+/giu, (value) => {
|
|
4680
|
+
try {
|
|
4681
|
+
const url = new URL(value);
|
|
4682
|
+
url.username = "";
|
|
4683
|
+
url.password = "";
|
|
4684
|
+
url.search = "";
|
|
4685
|
+
url.hash = "";
|
|
4686
|
+
return url.href;
|
|
4687
|
+
} catch {
|
|
4688
|
+
return "[URL]";
|
|
4689
|
+
}
|
|
4690
|
+
}).replace(/\bBearer\s+\S+/giu, "Bearer [REDACTED]").replace(/\b(?:[\w-]*(?:token|secret|password|api[_-]?key)|authorization)["']?\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,"'}]+)/giu, "[REDACTED]");
|
|
4691
|
+
};
|
|
4692
|
+
const stderr = clean("stderr"), stdout = clean("stdout");
|
|
4693
|
+
const errorLine = (text2) => text2.split("\n").reverse().find((line) => /(?:\b\w*Error\b|错误|失败)/iu.test(line));
|
|
4694
|
+
return (errorLine(stderr) ?? errorLine(stdout) ?? stderr.trim().split("\n").slice(-3).join(" ")).replace(/[\u0000-\u001f\u007f]/gu, " ").slice(0, 400);
|
|
4754
4695
|
};
|
|
4755
4696
|
const emit = (state2) => {
|
|
4756
4697
|
try {
|
|
@@ -4764,7 +4705,7 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4764
4705
|
let config;
|
|
4765
4706
|
let configSource;
|
|
4766
4707
|
try {
|
|
4767
|
-
configSource = await
|
|
4708
|
+
configSource = await readFile17(join18(projectRoot, BUDDY_PACKAGE_FILENAME), "utf8");
|
|
4768
4709
|
config = combineBuddyProject(parseBuddyAgentConfig(configSource));
|
|
4769
4710
|
} catch (cause) {
|
|
4770
4711
|
throw new BuddyDevError({
|
|
@@ -4776,7 +4717,7 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4776
4717
|
}
|
|
4777
4718
|
if (config.buddyId !== devAgentId) throw new BuddyDevError({ code: "DEV_CONFIG_INVALID", phase: "config", message: "\u5DE5\u7A0B buddyId \u5DF2\u6539\u53D8\uFF0C\u8BF7\u505C\u6B62 DEV \u540E\u5728\u6B63\u786E\u642D\u5B50\u7684\u5DE5\u7A0B\u91CD\u65B0\u8FDE\u63A5\u3002" });
|
|
4778
4719
|
const projectEnv = await readProjectEnvironment(projectRoot);
|
|
4779
|
-
secrets = Object.entries(projectEnv).filter(([key]) => /token|secret|password|key/i.test(key)).map(([, value]) => value ?? "");
|
|
4720
|
+
secrets = [...Object.entries(projectEnv), ...Object.entries(options.parentEnv ?? process.env)].filter(([key]) => /token|secret|password|key/i.test(key)).map(([, value]) => value ?? "");
|
|
4780
4721
|
const launchPlan = await launchPlanFor(config, options, projectRoot, signal);
|
|
4781
4722
|
const registration = await registerDevAgent({
|
|
4782
4723
|
projectRoot,
|
|
@@ -4817,11 +4758,8 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4817
4758
|
env: childEnvironment,
|
|
4818
4759
|
shell: false,
|
|
4819
4760
|
detached: platform === "darwin",
|
|
4820
|
-
onStdout: (text2) =>
|
|
4821
|
-
onStderr: (text2) =>
|
|
4822
|
-
stderr = (stderr + text2).slice(-16384);
|
|
4823
|
-
options.onLog?.({ source: "agent.stderr", text: text2 });
|
|
4824
|
-
}
|
|
4761
|
+
onStdout: (text2) => capture2("stdout", text2),
|
|
4762
|
+
onStderr: (text2) => capture2("stderr", text2)
|
|
4825
4763
|
});
|
|
4826
4764
|
await instanceLock.attachRuntime(agentProcess.pid);
|
|
4827
4765
|
const exited = agentProcess.exit.then((exit) => {
|
|
@@ -4848,6 +4786,7 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4848
4786
|
instanceLock,
|
|
4849
4787
|
lifecycle,
|
|
4850
4788
|
stopGracePeriodMs,
|
|
4789
|
+
failureDetail,
|
|
4851
4790
|
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
4852
4791
|
...options.onStateChange === void 0 ? {} : { onStateChange: options.onStateChange }
|
|
4853
4792
|
});
|
|
@@ -5093,12 +5032,12 @@ var DEV_COMMAND_HELP = `\u7528\u6CD5:
|
|
|
5093
5032
|
dev stop \u505C\u6B62\u5F53\u524D\u5DE5\u7A0B\u7684 DEV \u53CA\u6587\u4EF6\u76D1\u542C\uFF0C\u6E05\u7406\u5DF2\u786E\u8BA4\u9000\u51FA\u7684\u6B8B\u7559\u8FDB\u7A0B\uFF1B\u4E0D\u91CD\u8FDE\u3001\u4E0D\u91CD\u542F\uFF0C\u65E0\u9700\u767B\u5F55\u6216\u8054\u7F51\u66F4\u65B0\u3002
|
|
5094
5033
|
\u5173\u95ED\u7EC8\u7AEF\u3001Ctrl+C \u6216 SIGTERM \u4F1A\u505C\u6B62 CLI \u6258\u7BA1\u7684 Runtime\uFF1B\u5F3A\u5236\u6740\u6B7B CLI \u540E\u53EF\u7528 dev stop \u6E05\u7406\u3002
|
|
5095
5034
|
\u672A\u914D\u7F6E\u5730\u5740\u65F6\u8FDE\u63A5 MLB \u6D4B\u8BD5\u73AF\u5883 ${DEFAULT_MLB_TEST_URL}\uFF08HTTPS\uFF09\u3002
|
|
5096
|
-
|
|
5035
|
+
\u6B63\u5F0F\u7248\u56FA\u5B9A\u8FDE\u63A5 ECS Test\uFF1B\u5730\u5740\u53C2\u6570\u53EA\u6821\u9A8C\u56FA\u5B9A\u76EE\u6807\uFF0C\u4E0D\u80FD\u5207\u6362\u5E73\u53F0\u3002Runtime \u7F51\u5173\u7531 CLI \u6CE8\u5165\u3002
|
|
5097
5036
|
\u542F\u52A8\u524D\u81EA\u68C0 .env \u7F51\u5173\uFF1B\u5DF2\u77E5\u65E7 ECS \u5730\u5740\u6821\u9A8C\u642D\u5B50\u5F52\u5C5E\u540E\u81EA\u52A8\u66F4\u65B0\uFF0C\u4E0D\u540C\u5E73\u53F0\u4ECD\u9700\u660E\u786E\u786E\u8BA4\u3002
|
|
5098
5037
|
CLI \u7EDF\u4E00\u542F\u52A8\u5E76\u7BA1\u7406\u5DE5\u7A0B\u4E2D\u7684\u5B98\u65B9 Runtime\uFF1B\u6BCF\u6B21\u542F\u52A8\u6216\u91CD\u8F7D\u5FC5\u987B\u901A\u8FC7 npm \u6700\u65B0\u7A33\u5B9A\u7248\u68C0\u67E5\u3002
|
|
5099
5038
|
DEV \u4F1A\u901A\u8FC7\u6D4F\u89C8\u5668\u767B\u5F55\u83B7\u53D6\u5F00\u53D1\u8005\u4F1A\u8BDD\uFF0C\u5C06\u5F53\u524D\u642D\u5B50\u7684\u5F00\u53D1 Token \u5199\u5165\u5DE5\u7A0B .env\uFF0C\u590D\u7528\u524D\u5411 Server \u6838\u5BF9\u6240\u5C5E\u642D\u5B50\uFF1B\u767B\u5F55\u51ED\u636E\u4ECD\u4F7F\u7528\u7CFB\u7EDF\u51ED\u636E\u5B58\u50A8\u3002
|
|
5100
5039
|
\u8EAB\u4EFD\u53EA\u8BFB\u53D6 package.json.buddyId\uFF0C.env \u4E0D\u9700\u8981 BUDDY_ID\u3002
|
|
5101
|
-
--refresh-token \u91CD\u65B0\u9886\u53D6\u5DF2\u6709\u5F00\u53D1 Token\uFF0C\u7528\u4E8E\u670D\u52A1\u7AEF\u91CD\u7F6E\u540E\u7684\u672C\u673A\u66F4\u65B0\uFF1B\u4E0D\u4F1A\u751F\u6210\u65B0\u5BC6\u94A5\u3002`;
|
|
5040
|
+
--refresh-token \u91CD\u65B0\u9886\u53D6\u5DF2\u6709\u5F00\u53D1 Token\uFF0C\u7528\u4E8E\u540C\u4E00\u73AF\u5883\u670D\u52A1\u7AEF\u91CD\u7F6E\u540E\u7684\u672C\u673A\u66F4\u65B0\uFF1B\u4E0D\u80FD\u5207\u6362\u5E73\u53F0\uFF0C\u4E0D\u4F1A\u751F\u6210\u65B0\u5BC6\u94A5\u3002`;
|
|
5102
5041
|
function valueAfter(args, index, flag2) {
|
|
5103
5042
|
const value = args[index + 1];
|
|
5104
5043
|
if (value === void 0 || !value.trim()) throw new DevCommandUsageError(`${flag2} \u7F3A\u5C11\u503C`);
|
|
@@ -5153,7 +5092,7 @@ function parseDevArguments(args) {
|
|
|
5153
5092
|
}
|
|
5154
5093
|
function appServerUrl(override, env) {
|
|
5155
5094
|
try {
|
|
5156
|
-
return resolvePlatformUrl({ override, env
|
|
5095
|
+
return resolvePlatformUrl({ override, env });
|
|
5157
5096
|
} catch (cause) {
|
|
5158
5097
|
throw new DevCommandUsageError(`App Server \u5730\u5740\u65E0\u6548\uFF1A${cause instanceof Error ? cause.message : "\u4E0D\u662F\u6709\u6548 URL"}`);
|
|
5159
5098
|
}
|
|
@@ -5190,7 +5129,7 @@ async function runDevCommand(args, io, options = {}) {
|
|
|
5190
5129
|
io.write(result.stopped ? "DEV \u5DF2\u505C\u6B62\uFF0C\u6B8B\u7559\u8FDB\u7A0B\u53CA\u8FDB\u7A0B\u9501\u5DF2\u6E05\u7406\u3002\u9700\u8981\u8C03\u8BD5\u65F6\u91CD\u65B0\u8FDE\u63A5\u5E76\u542F\u52A8 DEV\u3002" : "\u5F53\u524D\u5DE5\u7A0B\u6CA1\u6709 CLI \u6258\u7BA1\u7684\u672C\u5730 DEV \u8FDB\u7A0B\u3002\u5176\u4ED6\u7535\u8111\u4E0A\u7684\u670D\u52A1\u8BF7\u5728\u5BF9\u5E94\u7535\u8111\u505C\u6B62\u3002");
|
|
5191
5130
|
return { exitCode: 0 };
|
|
5192
5131
|
}
|
|
5193
|
-
await checkProjectGateway(root, url, {
|
|
5132
|
+
await checkProjectGateway(root, url, { report: (message) => io.write(message) });
|
|
5194
5133
|
const authorizationInput = { appServerUrl: url, ...parsed.refreshToken ? { refreshToken: true } : {} };
|
|
5195
5134
|
if (!options.authorize) {
|
|
5196
5135
|
throw new DevCommandUsageError("\u5F53\u524D CLI Host \u5C1A\u672A\u914D\u7F6E\u642D\u642D\u8D26\u53F7\u767B\u5F55 Adapter");
|
|
@@ -5202,7 +5141,7 @@ async function runDevCommand(args, io, options = {}) {
|
|
|
5202
5141
|
startDev: options.startDev ?? startBuddyDev
|
|
5203
5142
|
});
|
|
5204
5143
|
const handle = await starter.start({
|
|
5205
|
-
runtimeUpdate: { ...options.runtimeUpdate, env: environment
|
|
5144
|
+
runtimeUpdate: { ...options.runtimeUpdate, env: environment },
|
|
5206
5145
|
projectRoot: root,
|
|
5207
5146
|
registrationClient,
|
|
5208
5147
|
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
@@ -5950,6 +5889,7 @@ async function runLogout(io, options) {
|
|
|
5950
5889
|
}
|
|
5951
5890
|
async function runPush(parsed, io, options) {
|
|
5952
5891
|
const root = await (options.resolveProjectRoot ?? requireBuddyAgentProjectRoot)(requestedDirectory(options, parsed));
|
|
5892
|
+
await checkProjectGateway(root, resolvePlatformUrl({ env: options.runtimeUpdate?.env }));
|
|
5953
5893
|
const config = await (options.readConfig ?? readBuddyConfig)(root);
|
|
5954
5894
|
const commit = await pushCommit(parsed, io);
|
|
5955
5895
|
if (!config.buddyId) throw new CloudCommandUsageError("\u5F53\u524D\u9879\u76EE\u7F3A\u5C11\u5E73\u53F0\u751F\u6210\u7684 buddyId\uFF0C\u8BF7\u5148\u8FD0\u884C buddy-cli init");
|
|
@@ -6015,6 +5955,7 @@ async function runMeta(parsed, io, options, legacyAvatar = false) {
|
|
|
6015
5955
|
if (id !== void 0 && !/^[A-Za-z0-9_-]{1,128}$/u.test(id)) throw new CloudCommandUsageError("--buddy-id \u5FC5\u987B\u662F\u6709\u6548\u7684\u642D\u5B50 ID");
|
|
6016
5956
|
if (id === void 0) {
|
|
6017
5957
|
const root = await (options.resolveProjectRoot ?? requireBuddyProjectRoot)(requestedDirectory(options, parsed));
|
|
5958
|
+
await checkProjectGateway(root, resolvePlatformUrl({ env: options.runtimeUpdate?.env }));
|
|
6018
5959
|
id = (await (options.readManifest ?? readBuddyProjectManifest)(root)).buddyId;
|
|
6019
5960
|
}
|
|
6020
5961
|
if (options.mode === "local-mock") throw new CloudCommandUsageError("\u672C\u5730\u6A21\u62DF\u6A21\u5F0F\u4E0D\u63D0\u4F9B\u4E91\u7AEF\u8D44\u6599\u64CD\u4F5C\uFF0C\u8BF7\u8FDE\u63A5\u771F\u5B9E MLB Server");
|
|
@@ -6064,6 +6005,7 @@ async function runCloudCommand(command, args, io, options = {}) {
|
|
|
6064
6005
|
if (command === "push") return await runPush(parsed, io, options);
|
|
6065
6006
|
if (command === "meta" || command === "avatar") return await runMeta(parsed, io, options, command === "avatar");
|
|
6066
6007
|
const root = await (options.resolveProjectRoot ?? requireBuddyProjectRoot)(requestedDirectory(options, parsed));
|
|
6008
|
+
await checkProjectGateway(root, resolvePlatformUrl({ env: options.runtimeUpdate?.env }));
|
|
6067
6009
|
const manifest = await (options.readManifest ?? readBuddyProjectManifest)(root);
|
|
6068
6010
|
if (options.mode === "local-mock") {
|
|
6069
6011
|
throw new CloudCommandUsageError("\u672C\u5730\u6A21\u62DF\u6A21\u5F0F\u53EA\u7528\u4E8E\u4F53\u9A8C\u521D\u59CB\u5316\u6D41\u7A0B\uFF0C\u4E0D\u63D0\u4F9B\u865A\u5047\u7684\u4E91\u7AEF\u72B6\u6001");
|
|
@@ -6077,7 +6019,7 @@ async function runCloudCommand(command, args, io, options = {}) {
|
|
|
6077
6019
|
printStatus(io, buddy2, packages);
|
|
6078
6020
|
return { exitCode: 0, buddyId: buddy2.id };
|
|
6079
6021
|
} catch (cause) {
|
|
6080
|
-
if (cause instanceof CloudCommandUsageError || cause instanceof CloudLifecycleError || cause instanceof BuddyProjectContextError || cause instanceof RuntimeRequirementError || cause instanceof PushPreflightError) {
|
|
6022
|
+
if (cause instanceof BuddyDevError || cause instanceof CloudCommandUsageError || cause instanceof CloudLifecycleError || cause instanceof BuddyProjectContextError || cause instanceof RuntimeRequirementError || cause instanceof PushPreflightError) {
|
|
6081
6023
|
io.writeError(`buddy-cli: ${cause.message}`);
|
|
6082
6024
|
if (cause instanceof CloudLifecycleError || cause instanceof RuntimeRequirementError || cause instanceof PushPreflightError) io.writeError(`\u9519\u8BEF\u7801\uFF1A${cause.code}`);
|
|
6083
6025
|
return {
|
|
@@ -6091,7 +6033,7 @@ var CLOUD_COMMAND_HELP = HELP;
|
|
|
6091
6033
|
|
|
6092
6034
|
// packages/cli-core/src/migration/index.ts
|
|
6093
6035
|
import { lstat as lstat11, open as open5, readdir as readdir6, realpath as realpath7, stat } from "node:fs/promises";
|
|
6094
|
-
import { extname, isAbsolute as isAbsolute3, join as
|
|
6036
|
+
import { extname, isAbsolute as isAbsolute3, join as join19, relative, resolve as resolve16, sep, win32 as win322 } from "node:path";
|
|
6095
6037
|
var DEFAULT_SKILL_SCAN_LIMITS = Object.freeze({
|
|
6096
6038
|
maxFiles: 128,
|
|
6097
6039
|
maxFileBytes: 256 * 1024,
|
|
@@ -6260,7 +6202,7 @@ async function existingProjectRoot(value) {
|
|
|
6260
6202
|
}
|
|
6261
6203
|
}
|
|
6262
6204
|
async function existingSkillRoot(projectRoot, skillPath) {
|
|
6263
|
-
const candidate = skillPath === "." ? projectRoot :
|
|
6205
|
+
const candidate = skillPath === "." ? projectRoot : join19(projectRoot, ...skillPath.split("/"));
|
|
6264
6206
|
try {
|
|
6265
6207
|
await lstat11(candidate);
|
|
6266
6208
|
} catch (cause) {
|
|
@@ -6297,7 +6239,7 @@ async function existingSkillRoot(projectRoot, skillPath) {
|
|
|
6297
6239
|
}
|
|
6298
6240
|
async function assertEntrypoint(context) {
|
|
6299
6241
|
const entryPath = reportChild(context.skillPath, "SKILL.md");
|
|
6300
|
-
const candidate =
|
|
6242
|
+
const candidate = join19(context.skillRoot, "SKILL.md");
|
|
6301
6243
|
try {
|
|
6302
6244
|
await lstat11(candidate);
|
|
6303
6245
|
const target = await realpath7(candidate);
|
|
@@ -6401,7 +6343,7 @@ async function walkDirectory(actualDirectory, reportDirectory, ancestors, contex
|
|
|
6401
6343
|
}
|
|
6402
6344
|
for (const entry2 of entries) {
|
|
6403
6345
|
const childReportPath = reportChild(reportDirectory, entry2.name);
|
|
6404
|
-
const childPath =
|
|
6346
|
+
const childPath = join19(directory, entry2.name);
|
|
6405
6347
|
let target;
|
|
6406
6348
|
try {
|
|
6407
6349
|
target = await realpath7(childPath);
|
|
@@ -6857,7 +6799,7 @@ async function scanExternalSkillPortability(options) {
|
|
|
6857
6799
|
// packages/cli-core/src/push/preflight.ts
|
|
6858
6800
|
import { createHash as createHash10 } from "node:crypto";
|
|
6859
6801
|
import { lstat as lstat12, open as open6, readdir as readdir7, realpath as realpath8 } from "node:fs/promises";
|
|
6860
|
-
import { isAbsolute as isAbsolute4, join as
|
|
6802
|
+
import { isAbsolute as isAbsolute4, join as join20, relative as relative2, resolve as resolve17, sep as sep2, win32 as win323 } from "node:path";
|
|
6861
6803
|
var MEBIBYTE = 1024 * 1024;
|
|
6862
6804
|
var DEFAULT_PUSH_MANIFEST_LIMITS = Object.freeze({
|
|
6863
6805
|
maxFiles: 1e4,
|
|
@@ -7062,7 +7004,7 @@ async function canonicalProjectRoot(projectRoot) {
|
|
|
7062
7004
|
}
|
|
7063
7005
|
}
|
|
7064
7006
|
async function captureConfigWithinLimit(projectRoot, maxFileBytes, filename) {
|
|
7065
|
-
const path =
|
|
7007
|
+
const path = join20(projectRoot, filename);
|
|
7066
7008
|
let entry2;
|
|
7067
7009
|
try {
|
|
7068
7010
|
entry2 = await lstat12(path);
|
|
@@ -7265,7 +7207,7 @@ async function createManifest(options) {
|
|
|
7265
7207
|
sensitiveEntriesExcluded += 1;
|
|
7266
7208
|
continue;
|
|
7267
7209
|
}
|
|
7268
|
-
const absolutePath =
|
|
7210
|
+
const absolutePath = join20(directory, name);
|
|
7269
7211
|
let entry2;
|
|
7270
7212
|
try {
|
|
7271
7213
|
entry2 = await lstat12(absolutePath);
|
|
@@ -7519,7 +7461,7 @@ async function assertCapturedConfigStable(options) {
|
|
|
7519
7461
|
}
|
|
7520
7462
|
let current;
|
|
7521
7463
|
try {
|
|
7522
|
-
const path =
|
|
7464
|
+
const path = join20(options.projectRoot, options.filename);
|
|
7523
7465
|
const entry2 = await lstat12(path);
|
|
7524
7466
|
if (!entry2.isFile() || entry2.isSymbolicLink()) {
|
|
7525
7467
|
error({
|
|
@@ -7565,7 +7507,7 @@ async function createPushPreflight(options) {
|
|
|
7565
7507
|
parseCapturedProject(initialAgentEntry);
|
|
7566
7508
|
let initialDataEntry;
|
|
7567
7509
|
try {
|
|
7568
|
-
await lstat12(
|
|
7510
|
+
await lstat12(join20(projectRoot, DATA_ACCESS_FILENAME));
|
|
7569
7511
|
initialDataEntry = await captureConfigWithinLimit(projectRoot, limits.maxFileBytes, DATA_ACCESS_FILENAME);
|
|
7570
7512
|
} catch (cause) {
|
|
7571
7513
|
if (cause.code !== "ENOENT") throw cause;
|
|
@@ -7667,8 +7609,8 @@ async function createPushPreflight(options) {
|
|
|
7667
7609
|
|
|
7668
7610
|
// packages/cli-core/src/push/bundle.ts
|
|
7669
7611
|
import { createHash as createHash11 } from "node:crypto";
|
|
7670
|
-
import { lstat as lstat13, readFile as
|
|
7671
|
-
import { join as
|
|
7612
|
+
import { lstat as lstat13, readFile as readFile18, realpath as realpath9 } from "node:fs/promises";
|
|
7613
|
+
import { join as join21, relative as relative3, sep as sep3, win32 as win324 } from "node:path";
|
|
7672
7614
|
import { Writable } from "node:stream";
|
|
7673
7615
|
import { pipeline } from "node:stream/promises";
|
|
7674
7616
|
import { createGzip } from "node:zlib";
|
|
@@ -7690,7 +7632,7 @@ function inside(root, target) {
|
|
|
7690
7632
|
return path === "" || path !== ".." && !path.startsWith(`..${sep3}`) && !path.startsWith("/") && !win324.isAbsolute(path);
|
|
7691
7633
|
}
|
|
7692
7634
|
async function capture(root, file) {
|
|
7693
|
-
const absolute =
|
|
7635
|
+
const absolute = join21(root, ...file.path.split("/"));
|
|
7694
7636
|
try {
|
|
7695
7637
|
const entry2 = await lstat13(absolute);
|
|
7696
7638
|
if (!entry2.isFile() || entry2.isSymbolicLink() || entry2.size !== file.bytes) {
|
|
@@ -7698,7 +7640,7 @@ async function capture(root, file) {
|
|
|
7698
7640
|
}
|
|
7699
7641
|
const canonical = await realpath9(absolute);
|
|
7700
7642
|
if (!inside(root, canonical)) changed(file.path, `\u63D0\u4EA4\u6587\u4EF6\u8D8A\u8FC7\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${file.path}`);
|
|
7701
|
-
const contents = await
|
|
7643
|
+
const contents = await readFile18(absolute);
|
|
7702
7644
|
if (contents.byteLength !== file.bytes || digest3(contents) !== file.digest) {
|
|
7703
7645
|
changed(file.path, `\u63D0\u4EA4\u524D\u6587\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316\uFF1A${file.path}`);
|
|
7704
7646
|
}
|
|
@@ -7816,6 +7758,7 @@ function validateRecoverableBuddyId(value) {
|
|
|
7816
7758
|
return buddyId;
|
|
7817
7759
|
}
|
|
7818
7760
|
async function resolveApplicationDraft(name, tagline, intro, requestedBuddyId, options, root, args, io) {
|
|
7761
|
+
await checkProjectGateway(root, resolvePlatformUrl({ env: options.runtimeCatalog?.env }));
|
|
7819
7762
|
const register = () => (options.registerMeta ?? prepareAndRegisterMeta)({
|
|
7820
7763
|
root,
|
|
7821
7764
|
profile: { name, tagline, intro },
|
|
@@ -7909,9 +7852,6 @@ function parseInitArguments(args) {
|
|
|
7909
7852
|
if (!/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(value)) throw new CliUsageError("--creator-version \u5FC5\u987B\u662F\u51C6\u786E\u7248\u672C\uFF0C\u4F8B\u5982 1.6.0");
|
|
7910
7853
|
parsed.creatorVersion = setOnce2(parsed.creatorVersion, value, flag2);
|
|
7911
7854
|
break;
|
|
7912
|
-
case "--runtime-version":
|
|
7913
|
-
parsed.runtimeVersion = setOnce2(parsed.runtimeVersion, value, flag2);
|
|
7914
|
-
break;
|
|
7915
7855
|
case "--avatar":
|
|
7916
7856
|
parsed.avatar = setOnce2(parsed.avatar, value, flag2);
|
|
7917
7857
|
break;
|
|
@@ -8000,7 +7940,6 @@ async function initializeProjectRoute(route, args, io, options, application) {
|
|
|
8000
7940
|
const initializationTarget = { directory: rootDirectory, kind: "new" };
|
|
8001
7941
|
let initializationPlan = options.initializeProject ? void 0 : await planBuddyProjectInitialization(initializationTarget);
|
|
8002
7942
|
const existingBuddyId = initializationPlan?.existingManifest?.buddyId;
|
|
8003
|
-
const runtimeVersion = args.resolvedRuntimeVersion ?? await selectInitRuntime(rootDirectory, args.runtimeVersion, io, options.runtimeCatalog);
|
|
8004
7943
|
if (existingBuddyId !== void 0 && args.buddyId !== void 0 && existingBuddyId !== args.buddyId) {
|
|
8005
7944
|
throw new CliUsageError(
|
|
8006
7945
|
`\u5DF2\u6709 package.json \u7ED1\u5B9A\u7684\u662F ${existingBuddyId}\uFF0C\u4E0E --buddy-id ${args.buddyId} \u4E0D\u4E00\u81F4`
|
|
@@ -8023,9 +7962,9 @@ async function initializeProjectRoute(route, args, io, options, application) {
|
|
|
8023
7962
|
}
|
|
8024
7963
|
let platformTemplate;
|
|
8025
7964
|
try {
|
|
8026
|
-
platformTemplate = options.scaffoldPlatformAgent ? await options.scaffoldPlatformAgent(project.rootDirectory, name
|
|
8027
|
-
resolveDependencies: (template) => latestRuntimeTemplate(template, { ...options.runtimeCatalog,
|
|
8028
|
-
}
|
|
7965
|
+
platformTemplate = options.scaffoldPlatformAgent ? await options.scaffoldPlatformAgent(project.rootDirectory, name) : await scaffoldPlatformAgent(project.rootDirectory, name, {
|
|
7966
|
+
resolveDependencies: (template) => latestRuntimeTemplate(template, { ...options.runtimeCatalog, report: (message) => io.writeError(message) })
|
|
7967
|
+
});
|
|
8029
7968
|
} catch (cause) {
|
|
8030
7969
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
8031
7970
|
io.writeError(`\u5B98\u65B9 Runtime \u5DE5\u7A0B\u5C1A\u672A\u5B8C\u6210\uFF1A${detail}\u3002\u642D\u5B50\u8EAB\u4EFD ${buddyId} \u5DF2\u4FDD\u7559\uFF1B\u4FEE\u590D\u539F\u56E0\u540E\uFF0C\u5728\u540C\u76EE\u5F55\u8FD0\u884C buddy-cli init --mode direct \u91CD\u8BD5\uFF0C\u5DF2\u6709\u914D\u7F6E\u548C\u4E1A\u52A1\u6587\u4EF6\u4F1A\u4FDD\u7559\u3002`);
|
|
@@ -8108,7 +8047,7 @@ async function resumeProjectArguments(args, cwd, options, io) {
|
|
|
8108
8047
|
await assertInitializableBuddyTarget(root);
|
|
8109
8048
|
let entry2;
|
|
8110
8049
|
try {
|
|
8111
|
-
entry2 = await lstat14(
|
|
8050
|
+
entry2 = await lstat14(join22(root, "package.json"));
|
|
8112
8051
|
} catch (cause) {
|
|
8113
8052
|
if (cause.code === "ENOENT") {
|
|
8114
8053
|
const draft = await readMetaDraft(root);
|
|
@@ -8156,6 +8095,7 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
8156
8095
|
} catch (cause) {
|
|
8157
8096
|
if (!(cause instanceof BuddyProjectContextError) || cause.code !== "PROJECT_DIRECTORY_NOT_FOUND") throw cause;
|
|
8158
8097
|
}
|
|
8098
|
+
if (projectRoot !== void 0) await checkProjectGateway(projectRoot, resolvePlatformUrl({ env: options.runtimeCatalog?.env }));
|
|
8159
8099
|
await authenticate(options);
|
|
8160
8100
|
if (projectRoot !== void 0) {
|
|
8161
8101
|
io.write(`\u5DF2\u8BC6\u522B\u642D\u642D\u9879\u76EE\uFF1A${projectRoot}`);
|
|
@@ -8212,10 +8152,6 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
8212
8152
|
return { exitCode: 0 };
|
|
8213
8153
|
}
|
|
8214
8154
|
let route = routeFromMode(parsed.mode);
|
|
8215
|
-
if (parsed.runtimeVersion !== void 0) {
|
|
8216
|
-
if (!allowsRuntimeVersionSelection(options.runtimeCatalog)) throw new CliUsageError("\u672A\u77E5 init \u53C2\u6570 --runtime-version");
|
|
8217
|
-
if (parsed.mode !== "direct") throw new CliUsageError("--runtime-version \u7528\u4E8E --mode direct \u751F\u6210 Runtime \u5DE5\u7A0B\uFF1Bcreate \u68B3\u7406\u5B8C\u6210\u540E\u5728\u8FDB\u5165 direct \u65F6\u9009\u62E9\u7248\u672C\u3002");
|
|
8218
|
-
}
|
|
8219
8155
|
if (route === void 0 && !io.canPrompt) requireModeForNonInteractive();
|
|
8220
8156
|
const cwd = resolve18(options.cwd ?? process.cwd());
|
|
8221
8157
|
await assertInitializableBuddyTarget(cwd);
|
|
@@ -8223,10 +8159,7 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
8223
8159
|
if (!parsed.directory.trim()) throw new CliUsageError("--directory \u4E0D\u80FD\u4E3A\u7A7A");
|
|
8224
8160
|
await assertInitializableBuddyTarget(resolve18(cwd, parsed.directory));
|
|
8225
8161
|
}
|
|
8226
|
-
|
|
8227
|
-
const target = resolve18(cwd, parsed.directory ?? (parsed.name ? defaultProjectDirectory(parsed.name) : "."));
|
|
8228
|
-
parsed.resolvedRuntimeVersion = await selectInitRuntime(target, parsed.runtimeVersion, io, options.runtimeCatalog);
|
|
8229
|
-
}
|
|
8162
|
+
await checkProjectGateway(resolve18(cwd, parsed.directory ?? "."), resolvePlatformUrl({ env: options.runtimeCatalog?.env }));
|
|
8230
8163
|
await authenticate(options);
|
|
8231
8164
|
await resumeProjectArguments(parsed, cwd, options, io);
|
|
8232
8165
|
route ??= routeFromMode(parsed.mode);
|
|
@@ -8242,7 +8175,7 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
8242
8175
|
io.writeError("\u5DF2\u53D6\u6D88\uFF1B\u5DF2\u4FDD\u5B58\u7684\u672C\u5730\u8349\u7A3F\u548C\u5DF2\u6709\u642D\u5B50\u8D44\u6599\u4F1A\u4FDD\u7559\uFF0C\u672A\u786E\u8BA4\u7684\u8D44\u6599\u4E0D\u4F1A\u767B\u8BB0\u3002");
|
|
8243
8176
|
return { exitCode: 130 };
|
|
8244
8177
|
}
|
|
8245
|
-
if (cause instanceof
|
|
8178
|
+
if (cause instanceof BuddyDevError || cause instanceof MetaPreparationError || cause instanceof CliUsageError || cause instanceof BuddyConfigValidationError || cause instanceof ProjectInitializationError || cause instanceof BuddyProjectContextError || cause instanceof CloudLifecycleError) {
|
|
8246
8179
|
return failure2(cause.message, io, cause instanceof CliUsageError);
|
|
8247
8180
|
}
|
|
8248
8181
|
throw cause;
|