@my-life-buddies/cli 0.21.0 → 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 +19 -43
- package/dist/bin/buddy.js +83 -35
- package/dist/bin/buddy.js.map +4 -4
- package/dist/bin/core.js +491 -524
- 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,59 +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 normalizePlatformUrl(value) {
|
|
145
|
-
const url = new URL(value);
|
|
146
|
-
if (url.username || url.password || url.search || url.hash) {
|
|
147
|
-
throw new TypeError("\u5E73\u53F0\u5730\u5740\u4E0D\u80FD\u5305\u542B credentials\u3001query \u6216 fragment");
|
|
148
|
-
}
|
|
149
|
-
if (url.protocol !== "https:" && !(url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname))) {
|
|
150
|
-
throw new TypeError(`\u5E73\u53F0\u5730\u5740\u5FC5\u987B\u4F7F\u7528 HTTPS\uFF1BHTTP \u4EC5\u5141\u8BB8\u672C\u673A\u5F00\u53D1`);
|
|
151
|
-
}
|
|
152
|
-
if (!url.pathname.endsWith("/")) url.pathname += "/";
|
|
153
|
-
return url;
|
|
154
|
-
}
|
|
155
|
-
function resolvePlatformUrl(options = {}) {
|
|
156
|
-
const env = options.env ?? process.env;
|
|
157
|
-
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;
|
|
158
|
-
const url = normalizePlatformUrl(options.override ?? env.MLB_GATEWAY_URL ?? legacy ?? DEFAULT_MLB_TEST_URL);
|
|
159
|
-
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");
|
|
160
|
-
return url;
|
|
161
|
-
}
|
|
162
|
-
function resolveDeveloperWebUrl(platformUrl, override) {
|
|
163
|
-
const url = normalizePlatformUrl(override ?? new URL("/developer/", platformUrl));
|
|
164
|
-
if (url.origin !== platformUrl.origin) {
|
|
165
|
-
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");
|
|
166
|
-
}
|
|
167
|
-
return url;
|
|
168
|
-
}
|
|
169
|
-
function allowsRuntimeVersionSelection(options = {}) {
|
|
170
|
-
const env = options.env ?? process.env;
|
|
171
|
-
if (!env.MLB_GATEWAY_URL?.trim()) return false;
|
|
172
|
-
const configured = resolvePlatformUrl({ env });
|
|
173
|
-
return configured.origin !== new URL(DEFAULT_MLB_TEST_URL).origin && (options.platformUrl === void 0 || options.platformUrl.origin === configured.origin);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
342
|
// packages/cli-core/src/config/runtime-update.ts
|
|
177
343
|
async function projectRuntimeVersion(root) {
|
|
178
344
|
try {
|
|
179
|
-
return runtimeDependencyVersion(JSON.parse(await readFile2(
|
|
345
|
+
return runtimeDependencyVersion(JSON.parse(await readFile2(join3(root, "package.json"), "utf8")));
|
|
180
346
|
} catch (cause) {
|
|
181
347
|
if (cause.code === "ENOENT") return void 0;
|
|
182
348
|
throw cause;
|
|
183
349
|
}
|
|
184
350
|
}
|
|
185
|
-
async function runtimeVersionStatus(project, latest
|
|
351
|
+
async function runtimeVersionStatus(project, latest) {
|
|
186
352
|
const current = project ? await projectRuntimeVersion(project) : void 0;
|
|
187
|
-
if (selected) return {
|
|
188
|
-
projectRuntimeVersion: current ?? null,
|
|
189
|
-
latestRuntimeVersion: null,
|
|
190
|
-
selectedRuntimeVersion: latest,
|
|
191
|
-
versionStatus: !project ? "no_project" : current === latest ? "selected" : "unconfigured",
|
|
192
|
-
adaptationRequired: !!project && current !== latest
|
|
193
|
-
};
|
|
194
353
|
let versionStatus;
|
|
195
354
|
if (!project) versionStatus = "no_project";
|
|
196
355
|
else if (!current) versionStatus = "unconfigured";
|
|
@@ -210,10 +369,6 @@ async function runtimeVersionStatus(project, latest, selected = false) {
|
|
|
210
369
|
}
|
|
211
370
|
function reportRuntimeVersion(status, report) {
|
|
212
371
|
if (status.versionStatus === "no_project") return;
|
|
213
|
-
if (status.selectedRuntimeVersion !== void 0) {
|
|
214
|
-
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`);
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
372
|
report(`Runtime \u7248\u672C\uFF1A\u5DE5\u7A0B ${status.projectRuntimeVersion ?? "\u672A\u9501\u5B9A\u51C6\u786E\u7248\u672C"}\uFF0Cnpm \u6700\u65B0 ${status.latestRuntimeVersion}\u3002`);
|
|
218
373
|
if (status.adaptationRequired) {
|
|
219
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");
|
|
@@ -223,69 +378,13 @@ function reportRuntimeVersion(status, report) {
|
|
|
223
378
|
async function checkRuntimeUpdate(root, report, options = {}) {
|
|
224
379
|
options.signal?.throwIfAborted();
|
|
225
380
|
try {
|
|
226
|
-
if (allowsRuntimeVersionSelection(options)) {
|
|
227
|
-
const current = await projectRuntimeVersion(root);
|
|
228
|
-
if (!current) {
|
|
229
|
-
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");
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
const selected = await resolveRuntimeVersion(current, options);
|
|
233
|
-
reportRuntimeVersion(await runtimeVersionStatus(root, selected, true), report);
|
|
234
|
-
options.signal?.throwIfAborted();
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
381
|
const latest = await latestRuntimeVersion(options);
|
|
238
382
|
const status = await runtimeVersionStatus(root, latest);
|
|
239
383
|
options.signal?.throwIfAborted();
|
|
240
384
|
reportRuntimeVersion(status, report);
|
|
241
385
|
} catch (cause) {
|
|
242
386
|
options.signal?.throwIfAborted();
|
|
243
|
-
report(`\u65E0\u6CD5\u68C0\u67E5 Runtime \u66F4\u65B0\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u672C\u6B21\u672A\u786E\u8BA4
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// packages/cli-core/src/init/runtime-selection.ts
|
|
248
|
-
import { readFile as readFile3 } from "node:fs/promises";
|
|
249
|
-
import { join as join3 } from "node:path";
|
|
250
|
-
var RuntimeSelectionError = class extends Error {
|
|
251
|
-
};
|
|
252
|
-
async function selectInitRuntime(root, requested, io, options = {}) {
|
|
253
|
-
if (!allowsRuntimeVersionSelection(options)) {
|
|
254
|
-
if (requested !== void 0) throw new RuntimeSelectionError("\u672A\u77E5 init \u53C2\u6570 --runtime-version");
|
|
255
|
-
return void 0;
|
|
256
|
-
}
|
|
257
|
-
let pkg;
|
|
258
|
-
try {
|
|
259
|
-
pkg = JSON.parse(await readFile3(join3(root, "package.json"), "utf8"));
|
|
260
|
-
} catch (cause) {
|
|
261
|
-
if (cause.code !== "ENOENT") throw cause;
|
|
262
|
-
}
|
|
263
|
-
const existing = runtimeDependencyVersion(pkg);
|
|
264
|
-
if (pkg?.dependencies?.[BUDDY_RUNTIME_PACKAGE] !== void 0) {
|
|
265
|
-
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");
|
|
266
|
-
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`);
|
|
267
|
-
return existing;
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
let selector = requested;
|
|
271
|
-
if (!selector) {
|
|
272
|
-
if (!io.canPrompt) throw new RuntimeSelectionError(await runtimeSelectionPrompt(options));
|
|
273
|
-
const releases = await runtimeReleaseChoices(options);
|
|
274
|
-
selector = await io.select("\u8FD9\u4E2A\u642D\u5B50\u4F7F\u7528\u54EA\u4E2A Runtime \u7248\u672C\uFF1F", [
|
|
275
|
-
{ value: releases.latest, label: `\u6700\u65B0\u7A33\u5B9A\u7248 ${releases.latest}\uFF08\u63A8\u8350\uFF09` },
|
|
276
|
-
...releases.dev ? [{ value: releases.dev, label: `\u6700\u65B0\u6D4B\u8BD5\u7248 ${releases.dev}` }] : [],
|
|
277
|
-
{ value: "other", label: "\u6307\u5B9A\u5176\u4ED6\u5DF2\u53D1\u5E03\u7248\u672C" }
|
|
278
|
-
]);
|
|
279
|
-
if (selector === "other") {
|
|
280
|
-
io.write(`\u53EF\u7528\u7248\u672C\uFF1A${releases.versions.join("\u3001")}`);
|
|
281
|
-
selector = (await io.input("\u8F93\u5165 Runtime \u7684\u51C6\u786E\u7248\u672C")).trim();
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
return await resolveRuntimeVersion(selector, options);
|
|
285
|
-
} catch (cause) {
|
|
286
|
-
options.signal?.throwIfAborted();
|
|
287
|
-
if (cause instanceof RuntimeSelectionError || cause instanceof Error && cause.name === "PromptCancelledError") throw cause;
|
|
288
|
-
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`);
|
|
289
388
|
}
|
|
290
389
|
}
|
|
291
390
|
|
|
@@ -293,13 +392,13 @@ async function selectInitRuntime(root, requested, io, options = {}) {
|
|
|
293
392
|
import { resolve as resolve6 } from "node:path";
|
|
294
393
|
|
|
295
394
|
// packages/cli-core/src/config/runtime-catalog.ts
|
|
296
|
-
import { readFile as
|
|
395
|
+
import { readFile as readFile3, realpath } from "node:fs/promises";
|
|
297
396
|
import { createRequire } from "node:module";
|
|
298
397
|
import { resolve } from "node:path";
|
|
299
398
|
import { pathToFileURL } from "node:url";
|
|
300
399
|
async function loadRuntime(projectRoot) {
|
|
301
400
|
const packagePath = resolve(projectRoot, "package.json");
|
|
302
|
-
const expected = runtimeDependencyVersion(JSON.parse(await
|
|
401
|
+
const expected = runtimeDependencyVersion(JSON.parse(await readFile3(packagePath, "utf8")));
|
|
303
402
|
if (!expected) throw new Error(`package.json \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
|
|
304
403
|
const projectRequire = createRequire(packagePath);
|
|
305
404
|
let runtimePath;
|
|
@@ -308,7 +407,7 @@ async function loadRuntime(projectRoot) {
|
|
|
308
407
|
if (await realpath(projectRequire.resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`)) !== installedPath) {
|
|
309
408
|
throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
|
|
310
409
|
}
|
|
311
|
-
const installed2 = JSON.parse(await
|
|
410
|
+
const installed2 = JSON.parse(await readFile3(installedPath, "utf8"));
|
|
312
411
|
if (installed2.version !== expected) throw new Error(`\u5DF2\u5B89\u88C5 ${installed2.version}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
|
|
313
412
|
runtimePath = projectRequire.resolve(BUDDY_RUNTIME_PACKAGE);
|
|
314
413
|
} catch (cause) {
|
|
@@ -359,7 +458,7 @@ async function validateRuntimeDatasets(projectRoot, requirements = []) {
|
|
|
359
458
|
}
|
|
360
459
|
|
|
361
460
|
// packages/cli-core/src/project-context.ts
|
|
362
|
-
import { lstat as lstat7, realpath as realpath3, readFile as
|
|
461
|
+
import { lstat as lstat7, realpath as realpath3, readFile as readFile10 } from "node:fs/promises";
|
|
363
462
|
import { dirname, join as join10, resolve as resolve5 } from "node:path";
|
|
364
463
|
|
|
365
464
|
// packages/cli-core/src/config/index.ts
|
|
@@ -367,13 +466,13 @@ import {
|
|
|
367
466
|
link,
|
|
368
467
|
lstat as lstat6,
|
|
369
468
|
mkdir as mkdir6,
|
|
370
|
-
open as
|
|
371
|
-
readFile as
|
|
469
|
+
open as open4,
|
|
470
|
+
readFile as readFile9,
|
|
372
471
|
readdir as readdir3,
|
|
373
|
-
rename as
|
|
374
|
-
unlink as
|
|
472
|
+
rename as rename7,
|
|
473
|
+
unlink as unlink5
|
|
375
474
|
} from "node:fs/promises";
|
|
376
|
-
import { randomUUID as
|
|
475
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
377
476
|
import { isAbsolute as isAbsolute2, join as join9, resolve as resolve4, win32 } from "node:path";
|
|
378
477
|
import { isDeepStrictEqual } from "node:util";
|
|
379
478
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
@@ -398,13 +497,13 @@ var buddy_package_schema_default = {
|
|
|
398
497
|
};
|
|
399
498
|
|
|
400
499
|
// packages/cli-core/src/init/meta.ts
|
|
401
|
-
import { createHash, randomUUID as
|
|
402
|
-
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";
|
|
403
502
|
import { join as join6, resolve as resolve2 } from "node:path";
|
|
404
503
|
|
|
405
504
|
// packages/cli-core/src/init/skill-package.ts
|
|
406
505
|
import { execFile as execFile2 } from "node:child_process";
|
|
407
|
-
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";
|
|
408
507
|
import { homedir as homedir2 } from "node:os";
|
|
409
508
|
import { isAbsolute, join as join4 } from "node:path";
|
|
410
509
|
import { promisify as promisify2 } from "node:util";
|
|
@@ -427,9 +526,9 @@ function checkProtocol(definition3, pkg) {
|
|
|
427
526
|
}
|
|
428
527
|
async function installed(definition3, root, version) {
|
|
429
528
|
if (!(await lstat2(root)).isDirectory()) throw new Error(`${definition3.label} \u7F13\u5B58\u4E0D\u80FD\u4F7F\u7528\u7B26\u53F7\u94FE\u63A5\u3002`);
|
|
430
|
-
const pkg = JSON.parse(await
|
|
529
|
+
const pkg = JSON.parse(await readFile4(join4(root, "package.json"), "utf8"));
|
|
431
530
|
checkProtocol(definition3, pkg);
|
|
432
|
-
const meta2 = JSON.parse(await
|
|
531
|
+
const meta2 = JSON.parse(await readFile4(join4(root, "version.json"), "utf8"));
|
|
433
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`);
|
|
434
533
|
for (const file of definition3.requiredFiles) {
|
|
435
534
|
const path = join4(root, file);
|
|
@@ -445,7 +544,7 @@ async function cached(definition3, root, lock) {
|
|
|
445
544
|
}
|
|
446
545
|
const skill = join4(root, "node_modules", definition3.name);
|
|
447
546
|
try {
|
|
448
|
-
const record2 = JSON.parse(await
|
|
547
|
+
const record2 = JSON.parse(await readFile4(join4(root, "package-lock.json"), "utf8"));
|
|
449
548
|
const entry2 = record2.packages?.[`node_modules/${definition3.name}`];
|
|
450
549
|
if (entry2?.version !== lock.version || entry2.integrity !== lock.integrity) throw new Error("\u7F13\u5B58\u6821\u9A8C\u8BB0\u5F55\u4E0D\u5339\u914D");
|
|
451
550
|
await installed(definition3, skill, lock.version);
|
|
@@ -462,7 +561,7 @@ async function resolveSkillPackage(definition3, previous, options = {}) {
|
|
|
462
561
|
if (local) {
|
|
463
562
|
if (!isAbsolute(local)) throw new Error(`${definition3.pathEnvironment} \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002`);
|
|
464
563
|
const root = await realpath2(local);
|
|
465
|
-
const pkg2 = JSON.parse(await
|
|
564
|
+
const pkg2 = JSON.parse(await readFile4(join4(root, "package.json"), "utf8"));
|
|
466
565
|
await installed(definition3, root, pkg2.version);
|
|
467
566
|
options.report?.(`\u4F7F\u7528\u672C\u5730 ${definition3.label} Skill ${pkg2.version}\uFF1A${root}`);
|
|
468
567
|
return { root, lock: { source: "local", path: root, version: pkg2.version, protocolVersion: 1 } };
|
|
@@ -523,7 +622,7 @@ async function resolveSkillPackage(definition3, previous, options = {}) {
|
|
|
523
622
|
await cached(definition3, temporary, lock);
|
|
524
623
|
options.signal?.throwIfAborted();
|
|
525
624
|
try {
|
|
526
|
-
await
|
|
625
|
+
await rename3(temporary, destination);
|
|
527
626
|
} catch (error2) {
|
|
528
627
|
if (!["EEXIST", "ENOTEMPTY"].includes(error2.code ?? "")) throw error2;
|
|
529
628
|
}
|
|
@@ -547,11 +646,11 @@ var definition = {
|
|
|
547
646
|
var resolveAvatarSkill = (previous, options = {}) => resolveSkillPackage(definition, previous, options);
|
|
548
647
|
|
|
549
648
|
// packages/cli-core/src/cloud/avatar.ts
|
|
550
|
-
import { open } from "node:fs/promises";
|
|
649
|
+
import { open as open2 } from "node:fs/promises";
|
|
551
650
|
import { basename } from "node:path";
|
|
552
651
|
var MAX_BUDDY_AVATAR_BYTES = 5 * 1024 * 1024;
|
|
553
652
|
async function readBuddyAvatarFile(path) {
|
|
554
|
-
const file = await
|
|
653
|
+
const file = await open2(path, "r");
|
|
555
654
|
try {
|
|
556
655
|
const stat2 = await file.stat();
|
|
557
656
|
if (!stat2.isFile()) throw new Error("\u5934\u50CF\u5FC5\u987B\u662F\u666E\u901A\u56FE\u7247\u6587\u4EF6");
|
|
@@ -574,8 +673,8 @@ async function readBuddyAvatarFile(path) {
|
|
|
574
673
|
}
|
|
575
674
|
|
|
576
675
|
// packages/cli-core/src/process-lock.ts
|
|
577
|
-
import { randomUUID } from "node:crypto";
|
|
578
|
-
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";
|
|
579
678
|
import { join as join5 } from "node:path";
|
|
580
679
|
function alive(pid) {
|
|
581
680
|
try {
|
|
@@ -598,8 +697,8 @@ async function acquireProcessLock(options) {
|
|
|
598
697
|
const root = options.directory;
|
|
599
698
|
const key = options.key;
|
|
600
699
|
const path = join5(root, key);
|
|
601
|
-
const ownerName = `owner-${
|
|
602
|
-
const candidate = join5(root, `.pending-${
|
|
700
|
+
const ownerName = `owner-${randomUUID2()}.json`;
|
|
701
|
+
const candidate = join5(root, `.pending-${randomUUID2()}`);
|
|
603
702
|
const owner = { ...options.ownerData, pid: process.pid };
|
|
604
703
|
await mkdir3(root, { recursive: true, mode: 448 });
|
|
605
704
|
await mkdir3(candidate, { mode: 448 });
|
|
@@ -607,7 +706,7 @@ async function acquireProcessLock(options) {
|
|
|
607
706
|
try {
|
|
608
707
|
for (let attempt = 0; ; attempt++) {
|
|
609
708
|
try {
|
|
610
|
-
await
|
|
709
|
+
await rename4(candidate, path);
|
|
611
710
|
break;
|
|
612
711
|
} catch (error2) {
|
|
613
712
|
if (!["EEXIST", "ENOTEMPTY"].includes(code(error2) ?? "")) throw error2;
|
|
@@ -625,14 +724,14 @@ async function acquireProcessLock(options) {
|
|
|
625
724
|
const previousPath = join5(path, names[0]);
|
|
626
725
|
let previous;
|
|
627
726
|
try {
|
|
628
|
-
previous = JSON.parse(await
|
|
727
|
+
previous = JSON.parse(await readFile5(previousPath, "utf8"));
|
|
629
728
|
} catch (error2) {
|
|
630
729
|
if (code(error2) === "ENOENT") continue;
|
|
631
730
|
throw options.busyError();
|
|
632
731
|
}
|
|
633
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();
|
|
634
733
|
try {
|
|
635
|
-
await
|
|
734
|
+
await unlink2(previousPath);
|
|
636
735
|
} catch (error2) {
|
|
637
736
|
if (code(error2) === "ENOENT") continue;
|
|
638
737
|
throw error2;
|
|
@@ -642,25 +741,25 @@ async function acquireProcessLock(options) {
|
|
|
642
741
|
});
|
|
643
742
|
}
|
|
644
743
|
} finally {
|
|
645
|
-
await
|
|
744
|
+
await unlink2(join5(candidate, ownerName)).catch(() => void 0);
|
|
646
745
|
await rmdir(candidate).catch(() => void 0);
|
|
647
746
|
}
|
|
648
747
|
let released = false;
|
|
649
748
|
return {
|
|
650
749
|
async attachRuntime(pid) {
|
|
651
750
|
if (!validPid(pid)) throw new TypeError("Runtime PID is invalid");
|
|
652
|
-
const temporary = join5(root, `.update-${
|
|
751
|
+
const temporary = join5(root, `.update-${randomUUID2()}`);
|
|
653
752
|
try {
|
|
654
753
|
await writeFile3(temporary, JSON.stringify({ ...owner, ...await options.runtimeData?.(pid), runtimePid: pid }), { mode: 384, flag: "wx" });
|
|
655
|
-
await
|
|
754
|
+
await rename4(temporary, join5(path, ownerName));
|
|
656
755
|
} finally {
|
|
657
|
-
await
|
|
756
|
+
await unlink2(temporary).catch(() => void 0);
|
|
658
757
|
}
|
|
659
758
|
},
|
|
660
759
|
async release() {
|
|
661
760
|
if (released) return;
|
|
662
761
|
released = true;
|
|
663
|
-
await
|
|
762
|
+
await unlink2(join5(path, ownerName)).catch((error2) => {
|
|
664
763
|
if (code(error2) !== "ENOENT") throw error2;
|
|
665
764
|
});
|
|
666
765
|
await rmdir(path).catch((error2) => {
|
|
@@ -695,16 +794,16 @@ async function localFile(path) {
|
|
|
695
794
|
const item = await entry(path);
|
|
696
795
|
if (!item) return void 0;
|
|
697
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}`);
|
|
698
|
-
return
|
|
797
|
+
return readFile6(path);
|
|
699
798
|
}
|
|
700
799
|
async function save(path, content) {
|
|
701
800
|
await localFile(path);
|
|
702
|
-
const temporary = `${path}.${
|
|
801
|
+
const temporary = `${path}.${randomUUID3()}.tmp`;
|
|
703
802
|
try {
|
|
704
803
|
await writeFile4(temporary, content, { flag: "wx", mode: 384 });
|
|
705
|
-
await
|
|
804
|
+
await rename5(temporary, path);
|
|
706
805
|
} finally {
|
|
707
|
-
await
|
|
806
|
+
await unlink3(temporary).catch((e) => {
|
|
708
807
|
if (e.code !== "ENOENT") throw e;
|
|
709
808
|
});
|
|
710
809
|
}
|
|
@@ -912,9 +1011,9 @@ import { lstat as lstat5 } from "node:fs/promises";
|
|
|
912
1011
|
import { join as join8 } from "node:path";
|
|
913
1012
|
|
|
914
1013
|
// packages/cli-core/src/init/scaffold.ts
|
|
915
|
-
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";
|
|
916
1015
|
import { resolve as resolve3 } from "node:path";
|
|
917
|
-
import { randomUUID as
|
|
1016
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
918
1017
|
|
|
919
1018
|
// packages/cli-core/src/config/models.ts
|
|
920
1019
|
var MODEL_IDS = Object.freeze([
|
|
@@ -927,7 +1026,7 @@ var DEFAULT_MODEL_ID = "kimi-k2.6";
|
|
|
927
1026
|
|
|
928
1027
|
// packages/cli-core/src/init/runtime-template.ts
|
|
929
1028
|
import { execFile as execFile3 } from "node:child_process";
|
|
930
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
1029
|
+
import { mkdtemp as mkdtemp3, readFile as readFile7, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
|
|
931
1030
|
import { tmpdir } from "node:os";
|
|
932
1031
|
import { join as join7 } from "node:path";
|
|
933
1032
|
import { promisify as promisify3 } from "node:util";
|
|
@@ -938,8 +1037,8 @@ async function latestRuntimeTemplate(template, options) {
|
|
|
938
1037
|
let temporaryRoot;
|
|
939
1038
|
try {
|
|
940
1039
|
options.signal?.throwIfAborted();
|
|
941
|
-
options.report(
|
|
942
|
-
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);
|
|
943
1042
|
let result = template;
|
|
944
1043
|
if (version !== bundledVersion) {
|
|
945
1044
|
temporaryRoot = await mkdtemp3(join7(tmpdir(), "buddy-runtime-template-"));
|
|
@@ -967,8 +1066,8 @@ async function latestRuntimeTemplate(template, options) {
|
|
|
967
1066
|
"--fetch-timeout=20000"
|
|
968
1067
|
], { cwd: temporaryRoot, signal: options.signal, timeout: 6e4 });
|
|
969
1068
|
result = {
|
|
970
|
-
packageJson: await
|
|
971
|
-
packageLock: await
|
|
1069
|
+
packageJson: await readFile7(join7(temporaryRoot, "package.json"), "utf8"),
|
|
1070
|
+
packageLock: await readFile7(join7(temporaryRoot, "package-lock.json"), "utf8")
|
|
972
1071
|
};
|
|
973
1072
|
}
|
|
974
1073
|
const pkg = JSON.parse(result.packageJson);
|
|
@@ -978,12 +1077,12 @@ async function latestRuntimeTemplate(template, options) {
|
|
|
978
1077
|
throw new Error("\u751F\u6210\u7684 Runtime \u7248\u672C\u4E0E\u4F9D\u8D56\u9501\u6587\u4EF6\u4E0D\u4E00\u81F4");
|
|
979
1078
|
}
|
|
980
1079
|
options.signal?.throwIfAborted();
|
|
981
|
-
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`);
|
|
982
1081
|
return result;
|
|
983
1082
|
} catch (cause) {
|
|
984
1083
|
if (options.signal?.aborted) throw new Error("Runtime \u7248\u672C\u9009\u62E9\u5DF2\u53D6\u6D88");
|
|
985
1084
|
const reason = cause instanceof Error && !cause.message.includes("Command failed") ? cause.message : "npm \u672A\u5B8C\u6210\u9501\u6587\u4EF6\u751F\u6210";
|
|
986
|
-
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 });
|
|
987
1086
|
} finally {
|
|
988
1087
|
if (temporaryRoot) await rm3(temporaryRoot, { recursive: true, force: true });
|
|
989
1088
|
}
|
|
@@ -1073,7 +1172,7 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1073
1172
|
const path = resolve3(projectRoot, BUDDY_PLATFORM_AGENT_ENTRY);
|
|
1074
1173
|
const packagePath = resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
|
|
1075
1174
|
if (!(await lstat4(packagePath)).isFile()) throw new Error("package.json \u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6");
|
|
1076
|
-
const originalPackage = await
|
|
1175
|
+
const originalPackage = await readFile8(packagePath, "utf8");
|
|
1077
1176
|
const projectPackage = parseBuddyProjectManifest(originalPackage);
|
|
1078
1177
|
const isIdentityDraft = Object.keys(projectPackage).every((key) => key === "buddyId");
|
|
1079
1178
|
const hasAlternateLockfile = (await Promise.all(["pnpm-lock.yaml", "yarn.lock"].map(async (name2) => {
|
|
@@ -1090,12 +1189,12 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1090
1189
|
const files = [
|
|
1091
1190
|
{ path, content: platformAgentTemplate(name) },
|
|
1092
1191
|
{ path: resolve3(projectRoot, BUDDY_PLATFORM_FACTORY_ENTRY), content: platformFactoryTemplate(options.model) },
|
|
1093
|
-
{ path: resolve3(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await
|
|
1094
|
-
...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") }],
|
|
1095
1194
|
{ path: resolve3(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() },
|
|
1096
1195
|
{ path: resolve3(projectRoot, "data-access.json"), content: '{\n "requirements": []\n}\n' },
|
|
1097
1196
|
{ path: resolve3(projectRoot, ".gitignore"), content: "node_modules/\n/.env\n" },
|
|
1098
|
-
{ 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" }
|
|
1099
1198
|
];
|
|
1100
1199
|
const handles = [];
|
|
1101
1200
|
const createdDirectories = [];
|
|
@@ -1114,7 +1213,7 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1114
1213
|
}
|
|
1115
1214
|
for (const file of files) {
|
|
1116
1215
|
try {
|
|
1117
|
-
handles.push({ path: file.path, handle: await
|
|
1216
|
+
handles.push({ path: file.path, handle: await open3(file.path, "wx", 384) });
|
|
1118
1217
|
} catch (cause) {
|
|
1119
1218
|
if (cause.code !== "EEXIST") throw cause;
|
|
1120
1219
|
if (!(await lstat4(file.path)).isFile()) {
|
|
@@ -1134,8 +1233,8 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1134
1233
|
lockFile.content = template.packageLock;
|
|
1135
1234
|
}
|
|
1136
1235
|
if (lockFile && (isIdentityDraft || handles.some((file) => file.path === lockFile.path))) {
|
|
1137
|
-
const packageContents = isIdentityDraft ? packageFile.content : await
|
|
1138
|
-
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");
|
|
1139
1238
|
const declared = JSON.parse(packageContents).dependencies ?? {};
|
|
1140
1239
|
const locked = JSON.parse(lockContents).packages?.[""]?.dependencies ?? {};
|
|
1141
1240
|
if (JSON.stringify(Object.entries(declared).sort()) !== JSON.stringify(Object.entries(locked).sort())) {
|
|
@@ -1148,19 +1247,19 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1148
1247
|
await handle.sync();
|
|
1149
1248
|
}
|
|
1150
1249
|
if (isIdentityDraft) {
|
|
1151
|
-
const temporary = `${packagePath}.${
|
|
1152
|
-
const handle = await
|
|
1250
|
+
const temporary = `${packagePath}.${randomUUID4()}.tmp`;
|
|
1251
|
+
const handle = await open3(temporary, "wx", 384);
|
|
1153
1252
|
try {
|
|
1154
1253
|
await handle.writeFile(packageFile.content, "utf8");
|
|
1155
1254
|
await handle.sync();
|
|
1156
1255
|
await handle.close();
|
|
1157
|
-
if (!(await lstat4(packagePath)).isFile() || await
|
|
1256
|
+
if (!(await lstat4(packagePath)).isFile() || await readFile8(packagePath, "utf8") !== originalPackage) {
|
|
1158
1257
|
throw new Error("\u8865\u9F50\u5DE5\u7A0B\u65F6 package.json \u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u8BD5");
|
|
1159
1258
|
}
|
|
1160
|
-
await
|
|
1259
|
+
await rename6(temporary, packagePath);
|
|
1161
1260
|
} finally {
|
|
1162
1261
|
await handle.close().catch(() => void 0);
|
|
1163
|
-
await
|
|
1262
|
+
await unlink4(temporary).catch((cause) => {
|
|
1164
1263
|
if (cause.code !== "ENOENT") throw cause;
|
|
1165
1264
|
});
|
|
1166
1265
|
}
|
|
@@ -1168,7 +1267,7 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
|
|
|
1168
1267
|
return Object.freeze({ path, created: isIdentityDraft || handles.length > 0 || createdDirectories.length > 0 });
|
|
1169
1268
|
} catch (cause) {
|
|
1170
1269
|
await Promise.all(handles.map(({ handle }) => handle.close().catch(() => void 0)));
|
|
1171
|
-
await Promise.all(handles.map(({ path: createdPath }) =>
|
|
1270
|
+
await Promise.all(handles.map(({ path: createdPath }) => unlink4(createdPath).catch(() => void 0)));
|
|
1172
1271
|
for (const directory of createdDirectories.reverse()) {
|
|
1173
1272
|
await rmdir2(directory).catch(() => void 0);
|
|
1174
1273
|
}
|
|
@@ -1336,7 +1435,7 @@ async function unlinkMatchingFile(targetPath, expectedIdentity) {
|
|
|
1336
1435
|
if (!entry2.isFile() || entry2.isSymbolicLink() || entryIdentity(entry2) !== expectedIdentity) {
|
|
1337
1436
|
return false;
|
|
1338
1437
|
}
|
|
1339
|
-
await
|
|
1438
|
+
await unlink5(targetPath);
|
|
1340
1439
|
return true;
|
|
1341
1440
|
} catch (cause) {
|
|
1342
1441
|
return cause.code === "ENOENT";
|
|
@@ -1379,7 +1478,7 @@ async function readExistingManifest(agentConfigPath) {
|
|
|
1379
1478
|
);
|
|
1380
1479
|
}
|
|
1381
1480
|
try {
|
|
1382
|
-
return parseBuddyProjectManifest(await
|
|
1481
|
+
return parseBuddyProjectManifest(await readFile9(agentConfigPath, "utf8"));
|
|
1383
1482
|
} catch (cause) {
|
|
1384
1483
|
throw new ProjectInitializationError(
|
|
1385
1484
|
"TARGET_CHANGED",
|
|
@@ -1465,12 +1564,12 @@ async function publishNewFile(options) {
|
|
|
1465
1564
|
let publishedHandle;
|
|
1466
1565
|
const temporaryPath = join9(
|
|
1467
1566
|
options.rootDirectory,
|
|
1468
|
-
`.${options.temporaryLabel}.${process.pid}.${
|
|
1567
|
+
`.${options.temporaryLabel}.${process.pid}.${randomUUID5()}.tmp`
|
|
1469
1568
|
);
|
|
1470
1569
|
let temporaryIdentity;
|
|
1471
1570
|
let publishedIdentity;
|
|
1472
1571
|
try {
|
|
1473
|
-
temporaryHandle = await
|
|
1572
|
+
temporaryHandle = await open4(temporaryPath, "wx");
|
|
1474
1573
|
temporaryIdentity = entryIdentity(await temporaryHandle.stat());
|
|
1475
1574
|
await temporaryHandle.writeFile(options.contents, "utf8");
|
|
1476
1575
|
await temporaryHandle.sync();
|
|
@@ -1493,7 +1592,7 @@ async function publishNewFile(options) {
|
|
|
1493
1592
|
if (fallbackBeforeOpen.kind !== "directory" || fallbackBeforeOpen.identity !== options.directoryIdentity) {
|
|
1494
1593
|
throw targetChanged({ rootDirectory: options.rootDirectory });
|
|
1495
1594
|
}
|
|
1496
|
-
publishedHandle = await
|
|
1595
|
+
publishedHandle = await open4(options.targetPath, "wx");
|
|
1497
1596
|
publishedIdentity = entryIdentity(await publishedHandle.stat());
|
|
1498
1597
|
const fallbackRoot = await pathState(options.rootDirectory);
|
|
1499
1598
|
if (fallbackRoot.kind !== "directory" || fallbackRoot.identity !== options.directoryIdentity) {
|
|
@@ -1507,7 +1606,7 @@ async function publishNewFile(options) {
|
|
|
1507
1606
|
const afterPublish = await pathState(options.rootDirectory);
|
|
1508
1607
|
const publishedFileIdentity = await fileIdentity(options.targetPath);
|
|
1509
1608
|
const temporaryFileIdentity = await fileIdentity(temporaryPath);
|
|
1510
|
-
const publishedContents = publishedFileIdentity ? await
|
|
1609
|
+
const publishedContents = publishedFileIdentity ? await readFile9(options.targetPath, "utf8") : void 0;
|
|
1511
1610
|
if (afterPublish.kind !== "directory" || afterPublish.identity !== options.directoryIdentity || !publishedIdentity || publishedFileIdentity !== publishedIdentity || temporaryFileIdentity !== temporaryIdentity || publishedContents !== options.contents) {
|
|
1512
1611
|
if (afterPublish.kind === "directory" && afterPublish.identity === options.directoryIdentity && publishedIdentity) {
|
|
1513
1612
|
await unlinkMatchingFile(options.targetPath, publishedIdentity);
|
|
@@ -1536,9 +1635,9 @@ async function publishNewFile(options) {
|
|
|
1536
1635
|
async function replaceExistingFile(options) {
|
|
1537
1636
|
const temporaryPath = join9(
|
|
1538
1637
|
options.rootDirectory,
|
|
1539
|
-
`.${options.temporaryLabel}.${process.pid}.${
|
|
1638
|
+
`.${options.temporaryLabel}.${process.pid}.${randomUUID5()}.tmp`
|
|
1540
1639
|
);
|
|
1541
|
-
const handle = await
|
|
1640
|
+
const handle = await open4(temporaryPath, "wx", 384);
|
|
1542
1641
|
try {
|
|
1543
1642
|
await handle.writeFile(options.contents, "utf8");
|
|
1544
1643
|
await handle.sync();
|
|
@@ -1548,12 +1647,12 @@ async function replaceExistingFile(options) {
|
|
|
1548
1647
|
try {
|
|
1549
1648
|
const root = await pathState(options.rootDirectory);
|
|
1550
1649
|
if (root.kind !== "directory" || root.identity !== options.directoryIdentity || await fileIdentity(options.targetPath) !== options.expectedFileIdentity) throw targetChanged({ rootDirectory: options.rootDirectory });
|
|
1551
|
-
await
|
|
1552
|
-
if (await
|
|
1650
|
+
await rename7(temporaryPath, options.targetPath);
|
|
1651
|
+
if (await readFile9(options.targetPath, "utf8") !== options.contents) {
|
|
1553
1652
|
throw targetChanged({ rootDirectory: options.rootDirectory });
|
|
1554
1653
|
}
|
|
1555
1654
|
} finally {
|
|
1556
|
-
await
|
|
1655
|
+
await unlink5(temporaryPath).catch((cause) => {
|
|
1557
1656
|
if (cause.code !== "ENOENT") throw cause;
|
|
1558
1657
|
});
|
|
1559
1658
|
}
|
|
@@ -1675,11 +1774,11 @@ async function initializeBuddyProject(options) {
|
|
|
1675
1774
|
}
|
|
1676
1775
|
async function readBuddyProjectManifest(projectRoot) {
|
|
1677
1776
|
const rootDirectory = resolve4(projectRoot);
|
|
1678
|
-
return parseBuddyProjectManifest(await
|
|
1777
|
+
return parseBuddyProjectManifest(await readFile9(resolve4(rootDirectory, BUDDY_PACKAGE_FILENAME), "utf8"));
|
|
1679
1778
|
}
|
|
1680
1779
|
async function readBuddyAgentConfig(projectRoot) {
|
|
1681
1780
|
const rootDirectory = resolve4(projectRoot);
|
|
1682
|
-
const source = await
|
|
1781
|
+
const source = await readFile9(resolve4(rootDirectory, BUDDY_PACKAGE_FILENAME), "utf8");
|
|
1683
1782
|
return parseBuddyAgentConfig(source);
|
|
1684
1783
|
}
|
|
1685
1784
|
async function readBuddyConfig(projectRoot) {
|
|
@@ -1746,7 +1845,7 @@ async function searchUp(startDirectory) {
|
|
|
1746
1845
|
if (await projectFileState(directory, BUDDY_PACKAGE_FILENAME) === "valid") {
|
|
1747
1846
|
let pkg;
|
|
1748
1847
|
try {
|
|
1749
|
-
pkg = JSON.parse(await
|
|
1848
|
+
pkg = JSON.parse(await readFile10(join10(directory, BUDDY_PACKAGE_FILENAME), "utf8"));
|
|
1750
1849
|
} catch (cause) {
|
|
1751
1850
|
throw new BuddyProjectContextError("PROJECT_CONFIG_INVALID", `\u65E0\u6CD5\u89E3\u6790 ${join10(directory, BUDDY_PACKAGE_FILENAME)}`, directory, { cause });
|
|
1752
1851
|
}
|
|
@@ -1865,20 +1964,6 @@ async function assertInitializableBuddyTarget(target) {
|
|
|
1865
1964
|
// packages/cli-core/src/commands/runtime-source.ts
|
|
1866
1965
|
async function runtimeCatalogSource(directory, options = {}) {
|
|
1867
1966
|
const project = await findBuddyProjectRoot(directory);
|
|
1868
|
-
if (allowsRuntimeVersionSelection(options)) {
|
|
1869
|
-
const declared = project ? await projectRuntimeVersion(project) : void 0;
|
|
1870
|
-
if (declared && options.runtimeVersion !== void 0 && options.runtimeVersion !== declared) {
|
|
1871
|
-
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`);
|
|
1872
|
-
}
|
|
1873
|
-
const requested = declared ?? options.runtimeVersion;
|
|
1874
|
-
if (!requested) throw new Error(await runtimeSelectionPrompt(options));
|
|
1875
|
-
const selected = await resolveRuntimeVersion(requested, options);
|
|
1876
|
-
const root2 = await cachedRuntimeRoot(selected, options);
|
|
1877
|
-
const version2 = await runtimeVersionStatus(project, selected, true);
|
|
1878
|
-
if (options.report) reportRuntimeVersion(version2, options.report);
|
|
1879
|
-
return { root: root2, source: "npm", version: version2 };
|
|
1880
|
-
}
|
|
1881
|
-
if (options.runtimeVersion !== void 0) throw new Error("\u5F53\u524D\u5E73\u53F0\u7684\u80FD\u529B\u76EE\u5F55\u4F7F\u7528\u6700\u65B0\u7A33\u5B9A\u7248");
|
|
1882
1967
|
const root = await (options.latestRuntimeRoot?.() ?? cachedLatestRuntimeRoot(options));
|
|
1883
1968
|
const latest = await projectRuntimeVersion(root);
|
|
1884
1969
|
if (!latest) throw new Error("npm Runtime \u7F13\u5B58\u7F3A\u5C11\u51C6\u786E\u7248\u672C");
|
|
@@ -1894,28 +1979,24 @@ var MODELS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli models [--directory <\u9879\u
|
|
|
1894
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`;
|
|
1895
1980
|
async function runModelsCommand(args, io, cwd, options = {}) {
|
|
1896
1981
|
try {
|
|
1897
|
-
const
|
|
1898
|
-
const help = selected ? `\u7528\u6CD5: buddy-cli models [--directory <\u9879\u76EE\u76EE\u5F55>] [--runtime-version <\u51C6\u786E\u7248\u672C|latest|dev>] [--json]
|
|
1899
|
-
\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;
|
|
1900
1983
|
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
1901
1984
|
io.write(help);
|
|
1902
1985
|
return { exitCode: 0 };
|
|
1903
1986
|
}
|
|
1904
1987
|
let directory;
|
|
1905
1988
|
let json2 = false;
|
|
1906
|
-
let runtimeVersion;
|
|
1907
1989
|
for (let i = 0; i < args.length; i++) {
|
|
1908
1990
|
if (args[i] === "--json" && !json2) json2 = true;
|
|
1909
1991
|
else if (args[i] === "--directory" && directory === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) directory = args[++i];
|
|
1910
|
-
else if (selected && args[i] === "--runtime-version" && runtimeVersion === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) runtimeVersion = args[++i];
|
|
1911
1992
|
else throw new Error(`models \u53C2\u6570\u65E0\u6548\uFF1A${args[i]}
|
|
1912
1993
|
${help}`);
|
|
1913
1994
|
}
|
|
1914
|
-
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 });
|
|
1915
1996
|
const catalog = await readRuntimeModelCatalog(root);
|
|
1916
1997
|
if (json2) io.write(JSON.stringify({ source, ...catalog, ...version }, null, 2));
|
|
1917
1998
|
else {
|
|
1918
|
-
io.write(`npm
|
|
1999
|
+
io.write(`npm \u6700\u65B0\u6B63\u5F0F\u7248 Runtime ${catalog.runtimeVersion} \u63D0\u4F9B ${catalog.models.length} \u4E2A\u6A21\u578B\uFF1A`);
|
|
1919
2000
|
for (const id of catalog.models) io.write(`- ${id}`);
|
|
1920
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");
|
|
1921
2002
|
}
|
|
@@ -1937,28 +2018,24 @@ var DATASETS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli datasets [--directory <\u98
|
|
|
1937
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`;
|
|
1938
2019
|
async function runDatasetsCommand(args, io, cwd, options = {}) {
|
|
1939
2020
|
try {
|
|
1940
|
-
const
|
|
1941
|
-
const help = selected ? `\u7528\u6CD5: buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--runtime-version <\u51C6\u786E\u7248\u672C|latest|dev>] [--json]
|
|
1942
|
-
\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;
|
|
1943
2022
|
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
|
|
1944
2023
|
io.write(help);
|
|
1945
2024
|
return { exitCode: 0 };
|
|
1946
2025
|
}
|
|
1947
2026
|
let directory;
|
|
1948
2027
|
let json2 = false;
|
|
1949
|
-
let runtimeVersion;
|
|
1950
2028
|
for (let i = 0; i < args.length; i++) {
|
|
1951
2029
|
if (args[i] === "--json" && !json2) json2 = true;
|
|
1952
2030
|
else if (args[i] === "--directory" && directory === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) directory = args[++i];
|
|
1953
|
-
else if (selected && args[i] === "--runtime-version" && runtimeVersion === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) runtimeVersion = args[++i];
|
|
1954
2031
|
else throw new Error(`datasets \u53C2\u6570\u65E0\u6548\uFF1A${args[i]}
|
|
1955
2032
|
${help}`);
|
|
1956
2033
|
}
|
|
1957
|
-
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 });
|
|
1958
2035
|
const catalog = await readRuntimeDataCatalog(root);
|
|
1959
2036
|
if (json2) io.write(JSON.stringify({ source, ...catalog, ...version }, null, 2));
|
|
1960
2037
|
else {
|
|
1961
|
-
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`);
|
|
1962
2039
|
for (const item of catalog.datasets) io.write(`- ${item.id} \u2014 ${item.title}\uFF08${item.source}\uFF0CSchema ${item.schemaVersion}\uFF09`);
|
|
1963
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");
|
|
1964
2041
|
}
|
|
@@ -1970,8 +2047,8 @@ ${help}`);
|
|
|
1970
2047
|
}
|
|
1971
2048
|
|
|
1972
2049
|
// packages/cli-core/src/commands/knowledge.ts
|
|
1973
|
-
import { createHash as createHash2, randomUUID as
|
|
1974
|
-
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";
|
|
1975
2052
|
import { dirname as dirname2, join as join11, resolve as resolve8 } from "node:path";
|
|
1976
2053
|
var MANIFEST = "knowledge-manifest.json";
|
|
1977
2054
|
var INDEX = "resources/knowledge/index.md";
|
|
@@ -2030,7 +2107,7 @@ async function read(root, path) {
|
|
|
2030
2107
|
});
|
|
2031
2108
|
if (!entry2) return void 0;
|
|
2032
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}`);
|
|
2033
|
-
return
|
|
2110
|
+
return readFile11(full);
|
|
2034
2111
|
}
|
|
2035
2112
|
async function requiredRead(root, path) {
|
|
2036
2113
|
const bytes = await read(root, path);
|
|
@@ -2040,12 +2117,12 @@ async function requiredRead(root, path) {
|
|
|
2040
2117
|
async function atomicWrite(root, path, value) {
|
|
2041
2118
|
const full = await safePath(root, path);
|
|
2042
2119
|
await mkdir7(dirname2(full), { recursive: true });
|
|
2043
|
-
const temporary = `${full}.${
|
|
2120
|
+
const temporary = `${full}.${randomUUID6()}.tmp`;
|
|
2044
2121
|
await writeFile6(temporary, value, { flag: "wx", mode: 384 });
|
|
2045
2122
|
try {
|
|
2046
|
-
await
|
|
2123
|
+
await rename8(temporary, full);
|
|
2047
2124
|
} finally {
|
|
2048
|
-
await
|
|
2125
|
+
await unlink6(temporary).catch((error2) => {
|
|
2049
2126
|
if (!missing(error2)) throw error2;
|
|
2050
2127
|
});
|
|
2051
2128
|
}
|
|
@@ -2216,7 +2293,7 @@ async function syncKnowledge(root, planPath) {
|
|
|
2216
2293
|
if (current && hash2(current) !== hash2(content) && hash2(current) !== expected.get(path)) conflicts.push(path);
|
|
2217
2294
|
}
|
|
2218
2295
|
if (conflicts.length) {
|
|
2219
|
-
const directory = `.buddy/knowledge/conflicts/${
|
|
2296
|
+
const directory = `.buddy/knowledge/conflicts/${randomUUID6()}`;
|
|
2220
2297
|
for (const [path, content] of files) await atomicWrite(root, `${directory}/${path}`, content);
|
|
2221
2298
|
await atomicWrite(root, `${directory}/${MANIFEST}`, json(next));
|
|
2222
2299
|
return { status: "conflict", conflicts, candidateDirectory: directory, written: [] };
|
|
@@ -2283,11 +2360,11 @@ ${KNOWLEDGE_HELP}`);
|
|
|
2283
2360
|
}
|
|
2284
2361
|
|
|
2285
2362
|
// packages/cli-core/src/index.ts
|
|
2286
|
-
import { join as
|
|
2363
|
+
import { join as join22, resolve as resolve18 } from "node:path";
|
|
2287
2364
|
|
|
2288
2365
|
// packages/cli-core/src/init/creator.ts
|
|
2289
|
-
import { createHash as createHash3, randomUUID as
|
|
2290
|
-
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";
|
|
2291
2368
|
import { dirname as dirname3, join as join13 } from "node:path";
|
|
2292
2369
|
|
|
2293
2370
|
// packages/cli-core/src/init/creator-package.ts
|
|
@@ -2539,26 +2616,26 @@ async function safeRead(path) {
|
|
|
2539
2616
|
if (!entry2.isFile() || entry2.size > MAX_LOCAL_FILE_BYTES) {
|
|
2540
2617
|
throw new CreatorPreparationError(`\u521B\u4F5C\u6587\u4EF6\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u6216\u8D85\u51FA\u5927\u5C0F\u9650\u5236\uFF1A${path}`);
|
|
2541
2618
|
}
|
|
2542
|
-
return
|
|
2619
|
+
return readFile12(path);
|
|
2543
2620
|
}
|
|
2544
2621
|
async function writeOnce(path, bytes) {
|
|
2545
|
-
const temporary = `${path}.${
|
|
2622
|
+
const temporary = `${path}.${randomUUID7()}.tmp`;
|
|
2546
2623
|
await writeFile7(temporary, bytes, { flag: "wx", mode: 384 });
|
|
2547
2624
|
try {
|
|
2548
2625
|
await link2(temporary, path).catch((cause) => {
|
|
2549
2626
|
if (cause.code !== "EEXIST") throw cause;
|
|
2550
2627
|
});
|
|
2551
2628
|
} finally {
|
|
2552
|
-
await
|
|
2629
|
+
await unlink7(temporary);
|
|
2553
2630
|
}
|
|
2554
2631
|
}
|
|
2555
|
-
async function
|
|
2556
|
-
const temporary = `${path}.${
|
|
2632
|
+
async function replaceFile2(path, content) {
|
|
2633
|
+
const temporary = `${path}.${randomUUID7()}.tmp`;
|
|
2557
2634
|
try {
|
|
2558
2635
|
await writeFile7(temporary, content, { flag: "wx", mode: 384 });
|
|
2559
|
-
await
|
|
2636
|
+
await rename9(temporary, path);
|
|
2560
2637
|
} finally {
|
|
2561
|
-
await
|
|
2638
|
+
await unlink7(temporary).catch((error2) => {
|
|
2562
2639
|
if (error2.code !== "ENOENT") throw error2;
|
|
2563
2640
|
});
|
|
2564
2641
|
}
|
|
@@ -2623,7 +2700,7 @@ async function prepareCreatorSkill(context, io, options = {}) {
|
|
|
2623
2700
|
await writeOnce(sessionPath, JSON.stringify({
|
|
2624
2701
|
schemaVersion: 1,
|
|
2625
2702
|
platformBuddyId: context.buddyId,
|
|
2626
|
-
creationKey:
|
|
2703
|
+
creationKey: randomUUID7()
|
|
2627
2704
|
}, null, 2) + "\n");
|
|
2628
2705
|
const session = JSON.parse((await safeRead(sessionPath)).toString("utf8"));
|
|
2629
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)) {
|
|
@@ -2683,9 +2760,9 @@ async function prepareCreatorSkill(context, io, options = {}) {
|
|
|
2683
2760
|
}
|
|
2684
2761
|
await writeOnce(join13(root, `HANDOFF.${hash3(existing).slice(0, 12)}.bak.md`), existing);
|
|
2685
2762
|
}
|
|
2686
|
-
await
|
|
2687
|
-
await
|
|
2688
|
-
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");
|
|
2689
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")}`);
|
|
2690
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`);
|
|
2691
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");
|
|
@@ -2750,7 +2827,7 @@ function validateBuddyMetaUpdate(meta2) {
|
|
|
2750
2827
|
|
|
2751
2828
|
// packages/cli-core/src/init/implementation-guide.ts
|
|
2752
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";
|
|
2753
|
-
function implementationGuide(
|
|
2830
|
+
function implementationGuide() {
|
|
2754
2831
|
return `## \u4ECE\u9700\u6C42\u624B\u518C\u843D\u5B9E\u5230\u4EE3\u7801
|
|
2755
2832
|
|
|
2756
2833
|
${IMPLEMENTATION_GUIDE_SUMMARY}
|
|
@@ -2777,12 +2854,14 @@ ${KNOWLEDGE_GUIDE}
|
|
|
2777
2854
|
|
|
2778
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
|
|
2779
2856
|
|
|
2780
|
-
|
|
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
|
|
2781
2858
|
|
|
2782
2859
|
### \u672C\u5730\u8C03\u8BD5\u7684\u9000\u51FA\u548C\u6E05\u7406
|
|
2783
2860
|
|
|
2784
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
|
|
2785
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
|
+
|
|
2786
2865
|
### \u4E3B\u52A8\u63D0\u9192\u4E0E\u6570\u636E\u6743\u9650
|
|
2787
2866
|
|
|
2788
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
|
|
@@ -2834,14 +2913,16 @@ Tool \u548C Hook \u662F Runtime \u7684\u6269\u5C55\u70B9\uFF1BService \u53EA\u66
|
|
|
2834
2913
|
|
|
2835
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
|
|
2836
2915
|
|
|
2837
|
-
\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
|
|
2838
2917
|
|
|
2839
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
|
|
2840
2919
|
|
|
2841
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
|
|
2842
2921
|
|
|
2843
|
-
|
|
2844
|
-
|
|
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
|
+
|
|
2845
2926
|
|
|
2846
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
|
|
2847
2928
|
|
|
@@ -2962,7 +3043,8 @@ var LoopbackBrowserLoginAdapter = class {
|
|
|
2962
3043
|
#fetch;
|
|
2963
3044
|
constructor(options) {
|
|
2964
3045
|
this.#platformUrl = normalizePlatformUrl(options.platformUrl);
|
|
2965
|
-
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");
|
|
2966
3048
|
this.#openBrowser = options.openBrowser ?? openExternalUrl;
|
|
2967
3049
|
this.#onLoginUrl = options.onLoginUrl;
|
|
2968
3050
|
this.#timeoutMs = positive(options.timeoutMs, DEFAULT_LOGIN_TIMEOUT_MS, "timeoutMs");
|
|
@@ -3133,10 +3215,11 @@ var CLI_HELP = `\u642D\u642D Developer Platform CLI
|
|
|
3133
3215
|
--version \u67E5\u770B\u5F53\u524D CLI \u7248\u672C
|
|
3134
3216
|
|
|
3135
3217
|
\u76F4\u63A5\u8FD0\u884C buddy-cli \u53EF\u8BC6\u522B\u5F53\u524D\u5DE5\u7A0B\u6216\u5F15\u5BFC\u521B\u5EFA\u3002
|
|
3136
|
-
\
|
|
3137
|
-
\u8BBE\u7F6E
|
|
3138
|
-
\
|
|
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
|
|
3139
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
|
|
3140
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
|
|
3141
3224
|
\u53C2\u6570\u4E0E\u793A\u4F8B: buddy-cli <\u547D\u4EE4> --help\uFF0C\u4F8B\u5982 buddy-cli init --help\u3002
|
|
3142
3225
|
Coding Agent \u5F00\u59CB\u5DE5\u4F5C\u524D\u8BF7\u8BFB\u53D6 buddy-cli guide\u3002`;
|
|
@@ -3168,9 +3251,9 @@ var GUIDE_HELP = `\u7528\u6CD5: buddy-cli guide
|
|
|
3168
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
|
|
3169
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`;
|
|
3170
3253
|
function agentGuide(options = {}) {
|
|
3171
|
-
return renderAgentGuide(
|
|
3254
|
+
return renderAgentGuide();
|
|
3172
3255
|
}
|
|
3173
|
-
function renderAgentGuide(
|
|
3256
|
+
function renderAgentGuide() {
|
|
3174
3257
|
return `# Coding Agent \u5F00\u53D1\u6307\u5F15
|
|
3175
3258
|
|
|
3176
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
|
|
@@ -3179,11 +3262,7 @@ Skill \u7684\u5177\u4F53\u6D41\u7A0B\u8BFB\u53D6 HANDOFF.md \u4E2D\u7684\u6587\u
|
|
|
3179
3262
|
## \u51C6\u5907\u5B8C\u6210\u540E\uFF0C\u5F00\u59CB\u521B\u4F5C\u5BF9\u8BDD
|
|
3180
3263
|
|
|
3181
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
|
|
3182
|
-
|
|
3183
|
-
\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
|
|
3184
|
-
\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
|
|
3185
|
-
\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
|
|
3186
|
-
` : ""}
|
|
3265
|
+
|
|
3187
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
|
|
3188
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
|
|
3189
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
|
|
@@ -3191,11 +3270,13 @@ ${selectedRuntime ? `\u5F53\u524D\u7EC8\u7AEF\u914D\u7F6E\u4E86\u81EA\u5B9A\u4E4
|
|
|
3191
3270
|
|
|
3192
3271
|
## CLI \u7248\u672C\u4E0E\u6267\u884C\u89C4\u5219
|
|
3193
3272
|
|
|
3194
|
-
\
|
|
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
|
|
3274
|
+
|
|
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
|
|
3195
3276
|
|
|
3196
3277
|
\u4F7F\u7528\u5B98\u65B9 buddy-cli \u5165\u53E3\u3002\u6BCF\u6761\u6B63\u5E38\u547D\u4EE4\uFF08\u5305\u62EC guide\uFF09\u6267\u884C\u524D\u90FD\u4F1A\u67E5\u8BE2\u516C\u5171 npm latest\uFF1B\u7248\u672C\u8FC7\u65E7\u65F6\u81EA\u52A8\u66F4\u65B0\uFF0C\u518D\u7531\u65B0\u7248\u6267\u884C\u540C\u4E00\u547D\u4EE4\u3002\u7B49\u5F85\u5F53\u524D\u547D\u4EE4\u5B8C\u6210\uFF0C\u4E0D\u91CD\u590D\u53D1\u8D77\uFF0C\u4E0D\u53E6\u5F00\u8FDB\u7A0B\u540C\u65F6\u91CD\u8DD1\u3002
|
|
3197
3278
|
\u5168\u5C40\u5B89\u88C5\u66F4\u65B0\u5BF9\u5E94 npm \u73AF\u5883\u7684\u5B89\u88C5\uFF1B\u6E90\u7801\u3001npm link\u3001\u9879\u76EE\u5185\u5B89\u88C5\u548C npx \u901A\u8FC7\u7F13\u5B58\u7684\u65B0\u7248\u7EE7\u7EED\u6267\u884C\uFF0C\u4E0D\u6539\u5199\u6E90\u7801\u6216\u9879\u76EE\u4F9D\u8D56\u3002\u53C2\u6570\u3001\u5DE5\u4F5C\u76EE\u5F55\u3001\u7EC8\u7AEF\u8F93\u5165\u8F93\u51FA\u548C\u9000\u51FA\u72B6\u6001\u4FDD\u7559\u3002\u4E00\u6B21\u8C03\u7528\u6700\u591A\u81EA\u52A8\u5207\u6362\u4E00\u6B21\uFF1B\u5F53\u524D\u7248\u672C\u9AD8\u4E8E latest \u65F6\u4E0D\u964D\u7EA7\uFF0C\u5DF2\u8FD0\u884C\u7684 DEV \u4E0D\u4F1A\u56E0\u53D1\u5E03\u65B0 CLI \u81EA\u52A8\u91CD\u542F\u3002
|
|
3198
|
-
\u5E2E\u52A9\u3001\u5404\u547D\u4EE4 --help\u3001--version \u548C\u5E94\u6025\u6E05\u7406 dev stop \u79BB\u7EBF\u53EF\u7528\uFF1Bupdate \u662F\u5355\u72EC\u68C0\u67E5\u6216\u66F4\u65B0\u5165\u53E3\u3002\u67E5\u8BE2\u6216\u66F4\u65B0\u5931\u8D25\u65F6\u539F\u4E1A\u52A1\u64CD\u4F5C\u4E0D\u4F1A\u5F00\u59CB\uFF0C\u6839\u636E\u9519\u8BEF\u5904\u7406\u540E\u91CD\u8BD5\uFF0C\u4E0D\u8C03\u7528\u65E7\u7248\u6E90\u7801\u7ED5\u8FC7\u68C0\u67E5\u3002\u65E7 CLI \u9700\u5148\u901A\u8FC7\u5B98\u65B9 npm \u5B89\u88C5\u547D\u4EE4\u5347\u7EA7\u4E00\u6B21\uFF0C\u624D\u80FD\u83B7\u5F97\u6B64\u673A\u5236\u3002
|
|
3279
|
+
\u5E2E\u52A9\u3001\u5404\u547D\u4EE4 --help\u3001--version \u548C\u5E94\u6025\u6E05\u7406 dev stop \u79BB\u7EBF\u53EF\u7528\uFF1Bupdate \u662F\u5355\u72EC\u68C0\u67E5\u6216\u66F4\u65B0\u5165\u53E3\u3002\u5B89\u88C5\u4E3B\u52A8\u5237\u65B0 npm \u7248\u672C\u7F13\u5B58\uFF0CETARGET \u6700\u591A\u91CD\u8BD5\u4E00\u6B21\uFF1B\u4ECD\u5931\u8D25\u4F1A\u8BF4\u660E\u5177\u4F53\u539F\u56E0\u3002\u67E5\u8BE2\u6216\u66F4\u65B0\u5931\u8D25\u65F6\u539F\u4E1A\u52A1\u64CD\u4F5C\u4E0D\u4F1A\u5F00\u59CB\uFF0C\u6839\u636E\u9519\u8BEF\u5904\u7406\u540E\u91CD\u8BD5\uFF0C\u4E0D\u8C03\u7528\u65E7\u7248\u6E90\u7801\u7ED5\u8FC7\u68C0\u67E5\u3002\u65E7 CLI \u9700\u5148\u901A\u8FC7\u5B98\u65B9 npm \u5B89\u88C5\u547D\u4EE4\u5347\u7EA7\u4E00\u6B21\uFF0C\u624D\u80FD\u83B7\u5F97\u6B64\u673A\u5236\u3002
|
|
3199
3280
|
CLI \u81EA\u52A8\u66F4\u65B0\u4E0D\u7B49\u4E8E\u5DE5\u7A0B Runtime \u5DF2\u9002\u914D\u3002\u4ECD\u987B\u6839\u636E Runtime \u68C0\u67E5\u7ED3\u679C\u66F4\u65B0\u5DE5\u7A0B\u4F9D\u8D56\u3001\u9501\u6587\u4EF6\u548C\u5FC5\u8981\u7684\u4E1A\u52A1\u4EE3\u7801\uFF0C\u5B8C\u6210\u9A8C\u8BC1\u540E\u518D\u542F\u52A8\u6216\u4E0A\u4F20\uFF1B\u4E0D\u8981\u53EA\u4FEE\u6539\u7248\u672C\u53F7\u5C31\u5BA3\u79F0\u9002\u914D\u5B8C\u6210\u3002
|
|
3200
3281
|
\u901A\u7528\u89C4\u5219\u4EE5\u672C\u547D\u4EE4\u7684\u5F53\u524D\u8F93\u51FA\u4E3A\u51C6\u3002HANDOFF.md \u53EA\u63D0\u4F9B\u5F53\u524D\u5DE5\u7A0B\u3001Skill \u8DEF\u5F84\u53CA\u5177\u4F53\u63A5\u7EED\u65B9\u5F0F\uFF0C\u4E0D\u5305\u542B\u6574\u4EFD\u5F00\u53D1\u6307\u5357\u3002
|
|
3201
3282
|
|
|
@@ -3218,56 +3299,25 @@ Coding Agent \u5E94\u4F20\u5165\u6309\u4E0A\u8FF0\u89C4\u5219\u786E\u5B9A\u7684\
|
|
|
3218
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
|
|
3219
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
|
|
3220
3301
|
|
|
3221
|
-
${implementationGuide(
|
|
3302
|
+
${implementationGuide()}
|
|
3222
3303
|
|
|
3223
3304
|
${DEVELOPMENT_HANDOFF}`;
|
|
3224
3305
|
}
|
|
3225
3306
|
var AGENT_GUIDE = renderAgentGuide();
|
|
3226
|
-
function initHelp(
|
|
3227
|
-
return
|
|
3228
|
-
\u5F53\u524D\u73AF\u5883\u7684 Runtime \u7248\u672C\u9009\u62E9\uFF1A
|
|
3229
|
-
--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
|
|
3230
|
-
\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;
|
|
3231
3309
|
}
|
|
3232
|
-
function cliHelp(
|
|
3233
|
-
return
|
|
3310
|
+
function cliHelp(_options = {}) {
|
|
3311
|
+
return CLI_HELP;
|
|
3234
3312
|
}
|
|
3235
3313
|
|
|
3236
3314
|
// packages/cli-core/src/dev/local-stop.ts
|
|
3237
3315
|
import { execFile as execFile5 } from "node:child_process";
|
|
3238
3316
|
import { promisify as promisify5 } from "node:util";
|
|
3239
|
-
import { readFile as
|
|
3317
|
+
import { readFile as readFile13, readdir as readdir4, realpath as realpath5, rmdir as rmdir3, unlink as unlink8 } from "node:fs/promises";
|
|
3240
3318
|
import { join as join15 } from "node:path";
|
|
3241
3319
|
import { setTimeout as delay } from "node:timers/promises";
|
|
3242
3320
|
|
|
3243
|
-
// packages/cli-core/src/dev/errors.ts
|
|
3244
|
-
var BuddyDevError = class extends Error {
|
|
3245
|
-
code;
|
|
3246
|
-
phase;
|
|
3247
|
-
retryable;
|
|
3248
|
-
constructor(options) {
|
|
3249
|
-
super(options.message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
3250
|
-
this.name = "BuddyDevError";
|
|
3251
|
-
this.code = options.code;
|
|
3252
|
-
this.phase = options.phase;
|
|
3253
|
-
this.retryable = options.retryable ?? false;
|
|
3254
|
-
}
|
|
3255
|
-
};
|
|
3256
|
-
function isAbortLike(error2) {
|
|
3257
|
-
return error2 instanceof DOMException && error2.name === "AbortError" || error2 instanceof Error && error2.name === "AbortError";
|
|
3258
|
-
}
|
|
3259
|
-
function abortedDevError(signal) {
|
|
3260
|
-
return new BuddyDevError({
|
|
3261
|
-
code: "DEV_ABORTED",
|
|
3262
|
-
phase: "stop",
|
|
3263
|
-
message: "\u642D\u642D DEV \u542F\u52A8\u5DF2\u53D6\u6D88\u3002",
|
|
3264
|
-
...signal?.reason === void 0 ? {} : { cause: signal.reason }
|
|
3265
|
-
});
|
|
3266
|
-
}
|
|
3267
|
-
function throwIfDevAborted(signal) {
|
|
3268
|
-
if (signal?.aborted) throw abortedDevError(signal);
|
|
3269
|
-
}
|
|
3270
|
-
|
|
3271
3321
|
// packages/cli-core/src/dev/process.ts
|
|
3272
3322
|
import { promisify as promisify4 } from "node:util";
|
|
3273
3323
|
import { spawn as spawnChild, execFile as execFile4 } from "node:child_process";
|
|
@@ -3565,7 +3615,7 @@ async function stopLocalDev(options) {
|
|
|
3565
3615
|
}
|
|
3566
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");
|
|
3567
3617
|
const ownerPath = join15(path, names[0]);
|
|
3568
|
-
const source = await
|
|
3618
|
+
const source = await readFile13(ownerPath, "utf8");
|
|
3569
3619
|
const owner = JSON.parse(source);
|
|
3570
3620
|
if (!validPid2(owner.pid) || owner.runtimePid !== void 0 && !validPid2(owner.runtimePid)) throw failure("DEV \u9501\u4E2D\u7684 PID \u65E0\u6548\u3002");
|
|
3571
3621
|
const root = await realpath5(options.projectRoot);
|
|
@@ -3593,7 +3643,7 @@ async function stopLocalDev(options) {
|
|
|
3593
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);
|
|
3594
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`);
|
|
3595
3645
|
}
|
|
3596
|
-
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");
|
|
3597
3647
|
try {
|
|
3598
3648
|
process.kill(-pid, "SIGTERM");
|
|
3599
3649
|
} catch (error2) {
|
|
@@ -3620,7 +3670,7 @@ async function stopLocalDev(options) {
|
|
|
3620
3670
|
}
|
|
3621
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`);
|
|
3622
3672
|
try {
|
|
3623
|
-
if (await
|
|
3673
|
+
if (await readFile13(ownerPath, "utf8") === source) await unlink8(ownerPath);
|
|
3624
3674
|
} catch (error2) {
|
|
3625
3675
|
if (error2.code !== "ENOENT") throw error2;
|
|
3626
3676
|
}
|
|
@@ -3633,127 +3683,6 @@ async function stopLocalDev(options) {
|
|
|
3633
3683
|
// packages/cli-core/src/commands/dev.ts
|
|
3634
3684
|
import { resolve as resolve14 } from "node:path";
|
|
3635
3685
|
|
|
3636
|
-
// packages/cli-core/src/dev/project-env.ts
|
|
3637
|
-
import { constants } from "node:fs";
|
|
3638
|
-
import { open as open4, rename as rename9, unlink as unlink8 } from "node:fs/promises";
|
|
3639
|
-
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
3640
|
-
import { join as join16 } from "node:path";
|
|
3641
|
-
import { parseEnv } from "node:util";
|
|
3642
|
-
function invalid(message) {
|
|
3643
|
-
return new BuddyDevError({ code: "DEV_CONFIG_INVALID", phase: "config", message });
|
|
3644
|
-
}
|
|
3645
|
-
async function readLocalFile(path) {
|
|
3646
|
-
let file;
|
|
3647
|
-
try {
|
|
3648
|
-
file = await open4(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
3649
|
-
const stat2 = await file.stat();
|
|
3650
|
-
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");
|
|
3651
|
-
return await file.readFile("utf8");
|
|
3652
|
-
} catch (cause) {
|
|
3653
|
-
if (cause.code === "ENOENT") return "";
|
|
3654
|
-
if (cause instanceof BuddyDevError) throw cause;
|
|
3655
|
-
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");
|
|
3656
|
-
} finally {
|
|
3657
|
-
await file?.close();
|
|
3658
|
-
}
|
|
3659
|
-
}
|
|
3660
|
-
async function readProjectEnvironment(projectRoot) {
|
|
3661
|
-
const source = await readLocalFile(join16(projectRoot, ".env"));
|
|
3662
|
-
let values;
|
|
3663
|
-
try {
|
|
3664
|
-
values = parseEnv(source);
|
|
3665
|
-
} catch {
|
|
3666
|
-
throw invalid("\u5DE5\u7A0B .env \u683C\u5F0F\u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002");
|
|
3667
|
-
}
|
|
3668
|
-
return values;
|
|
3669
|
-
}
|
|
3670
|
-
async function projectBuddyToken(projectRoot, gatewayUrl) {
|
|
3671
|
-
const values = await readProjectEnvironment(projectRoot);
|
|
3672
|
-
if (!values.BUDDY_TOKEN) return void 0;
|
|
3673
|
-
if (values.MLB_GATEWAY_URL) {
|
|
3674
|
-
let gateway;
|
|
3675
|
-
try {
|
|
3676
|
-
gateway = normalizePlatformUrl(values.MLB_GATEWAY_URL);
|
|
3677
|
-
} catch {
|
|
3678
|
-
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");
|
|
3679
|
-
}
|
|
3680
|
-
if (gateway.href !== gatewayUrl.href) throw invalid(".env \u7684\u5E73\u53F0\u5730\u5740\u4E0E\u672C\u6B21\u542F\u52A8\u4E0D\u540C\uFF1B\u8BF7\u786E\u8BA4\u5E73\u53F0\u540E\u4F7F\u7528 --refresh-token \u91CD\u65B0\u9886\u53D6\u5F00\u53D1\u4EE4\u724C\u3002");
|
|
3681
|
-
}
|
|
3682
|
-
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");
|
|
3683
|
-
return values.BUDDY_TOKEN;
|
|
3684
|
-
}
|
|
3685
|
-
function quote(value) {
|
|
3686
|
-
if (/[\u0000-\u001f\u007f]/u.test(value)) throw invalid("\u672C\u5730\u8FD0\u884C\u914D\u7F6E\u4E0D\u80FD\u5305\u542B\u63A7\u5236\u5B57\u7B26\u3002");
|
|
3687
|
-
const delimiter = ["'", '"', "`"].find((character) => !value.includes(character));
|
|
3688
|
-
if (!delimiter) throw invalid("\u672C\u5730\u8FD0\u884C\u914D\u7F6E\u5305\u542B\u65E0\u6CD5\u5199\u5165 .env \u7684\u5F15\u53F7\u7EC4\u5408\u3002");
|
|
3689
|
-
return `${delimiter}${value}${delimiter}`;
|
|
3690
|
-
}
|
|
3691
|
-
function updateValues(source, values) {
|
|
3692
|
-
const assignment = /^[\t ]*(?:export[\t ]+)?([A-Za-z_][A-Za-z0-9_]*)[\t ]*=[\t ]*/gm;
|
|
3693
|
-
let output = "", cursor = 0, match;
|
|
3694
|
-
const written = /* @__PURE__ */ new Set();
|
|
3695
|
-
while (match = assignment.exec(source)) {
|
|
3696
|
-
const valueStart = assignment.lastIndex;
|
|
3697
|
-
let end = source.indexOf("\n", valueStart);
|
|
3698
|
-
if (end < 0) end = source.length;
|
|
3699
|
-
let commentStart = valueStart;
|
|
3700
|
-
const delimiter = source[valueStart];
|
|
3701
|
-
if (delimiter && ["'", '"', "`"].includes(delimiter)) {
|
|
3702
|
-
const close = source.indexOf(delimiter, valueStart + 1);
|
|
3703
|
-
if (close < 0) throw invalid(".env \u4E2D\u6709\u672A\u95ED\u5408\u7684\u5F15\u53F7\uFF0C\u8BF7\u4FEE\u6B63\u540E\u91CD\u8BD5\u3002");
|
|
3704
|
-
commentStart = close + 1;
|
|
3705
|
-
end = source.indexOf("\n", close + 1);
|
|
3706
|
-
if (end < 0) end = source.length;
|
|
3707
|
-
}
|
|
3708
|
-
assignment.lastIndex = end;
|
|
3709
|
-
const name = match[1];
|
|
3710
|
-
if (!(name in values)) continue;
|
|
3711
|
-
const comment = source.slice(commentStart, end).match(/[\t ]*#[^\r\n]*/u)?.[0] ?? "";
|
|
3712
|
-
output += source.slice(cursor, match.index);
|
|
3713
|
-
output += written.has(name) || values[name] === void 0 ? comment : `${name}=${quote(values[name])}${comment ? ` ${comment.trimStart()}` : ""}`;
|
|
3714
|
-
if (source[end - 1] === "\r") output += "\r";
|
|
3715
|
-
cursor = end;
|
|
3716
|
-
written.add(name);
|
|
3717
|
-
}
|
|
3718
|
-
output += source.slice(cursor);
|
|
3719
|
-
const newline = source.includes("\r\n") ? "\r\n" : "\n";
|
|
3720
|
-
for (const [name, value] of Object.entries(values)) if (value !== void 0 && !written.has(name)) {
|
|
3721
|
-
if (output && !output.endsWith("\n")) output += newline;
|
|
3722
|
-
output += `${name}=${quote(value)}${newline}`;
|
|
3723
|
-
}
|
|
3724
|
-
const parsed = parseEnv(output);
|
|
3725
|
-
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");
|
|
3726
|
-
return output;
|
|
3727
|
-
}
|
|
3728
|
-
async function replaceFile2(path, contents, mode) {
|
|
3729
|
-
const temporary = `${path}.${randomUUID7()}.tmp`;
|
|
3730
|
-
let file;
|
|
3731
|
-
try {
|
|
3732
|
-
file = await open4(temporary, "wx", mode);
|
|
3733
|
-
await file.writeFile(contents, "utf8");
|
|
3734
|
-
await file.sync();
|
|
3735
|
-
await file.close();
|
|
3736
|
-
file = void 0;
|
|
3737
|
-
await rename9(temporary, path);
|
|
3738
|
-
} finally {
|
|
3739
|
-
await file?.close();
|
|
3740
|
-
await unlink8(temporary).catch((cause) => {
|
|
3741
|
-
if (cause.code !== "ENOENT") throw cause;
|
|
3742
|
-
});
|
|
3743
|
-
}
|
|
3744
|
-
}
|
|
3745
|
-
async function writeProjectEnvironment(projectRoot, values) {
|
|
3746
|
-
const envPath = join16(projectRoot, ".env"), ignorePath = join16(projectRoot, ".gitignore");
|
|
3747
|
-
const contents = updateValues(await readLocalFile(envPath), { ...values, BUDDY_ID: void 0 });
|
|
3748
|
-
const ignored = await readLocalFile(ignorePath);
|
|
3749
|
-
if (ignored.trimEnd().split(/\r?\n/u).at(-1) !== "/.env") {
|
|
3750
|
-
await replaceFile2(ignorePath, `${ignored}${ignored && !ignored.endsWith("\n") ? "\n" : ""}/.env
|
|
3751
|
-
`, 420);
|
|
3752
|
-
}
|
|
3753
|
-
await replaceFile2(envPath, contents, 384);
|
|
3754
|
-
return contents;
|
|
3755
|
-
}
|
|
3756
|
-
|
|
3757
3686
|
// packages/cli-core/src/dev/app-server.ts
|
|
3758
3687
|
var MAX_JSON_BODY_LENGTH = 1048576;
|
|
3759
3688
|
function safeCredential(value, name) {
|
|
@@ -3784,7 +3713,8 @@ async function responseJson(response) {
|
|
|
3784
3713
|
throw new BuddyDevError({
|
|
3785
3714
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3786
3715
|
phase: "registration",
|
|
3787
|
-
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"
|
|
3788
3718
|
});
|
|
3789
3719
|
}
|
|
3790
3720
|
parts.push(decoder.decode(item.value, { stream: true }));
|
|
@@ -3802,6 +3732,7 @@ async function responseJson(response) {
|
|
|
3802
3732
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3803
3733
|
phase: "registration",
|
|
3804
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`,
|
|
3805
3736
|
cause
|
|
3806
3737
|
});
|
|
3807
3738
|
}
|
|
@@ -3811,6 +3742,13 @@ function safeServerError(value, fallback) {
|
|
|
3811
3742
|
if (typeof candidate !== "string" || !candidate.trim()) return fallback;
|
|
3812
3743
|
return candidate.slice(0, 1024).replace(/[\u0000-\u001f\u007f]/gu, " ");
|
|
3813
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
|
+
}
|
|
3814
3752
|
var MlbDevRegistrationClient = class {
|
|
3815
3753
|
#baseUrl;
|
|
3816
3754
|
#developerToken;
|
|
@@ -3846,6 +3784,7 @@ var MlbDevRegistrationClient = class {
|
|
|
3846
3784
|
code: "DEV_APP_SERVER_HTTP_ERROR",
|
|
3847
3785
|
phase: "registration",
|
|
3848
3786
|
message: "\u65E0\u6CD5\u8FDE\u63A5 DEV App Server\u3002",
|
|
3787
|
+
publicMessage: "\u65E0\u6CD5\u8FDE\u63A5\u5F00\u53D1\u5E73\u53F0\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u548C\u672C\u6B21\u8FDE\u63A5\u7684\u5E73\u53F0\u5730\u5740\u3002",
|
|
3849
3788
|
retryable: true,
|
|
3850
3789
|
cause
|
|
3851
3790
|
});
|
|
@@ -3856,7 +3795,8 @@ var MlbDevRegistrationClient = class {
|
|
|
3856
3795
|
throw new BuddyDevError({
|
|
3857
3796
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3858
3797
|
phase: "registration",
|
|
3859
|
-
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"
|
|
3860
3800
|
});
|
|
3861
3801
|
}
|
|
3862
3802
|
let body;
|
|
@@ -3868,6 +3808,7 @@ var MlbDevRegistrationClient = class {
|
|
|
3868
3808
|
code: "DEV_APP_SERVER_HTTP_ERROR",
|
|
3869
3809
|
phase: "registration",
|
|
3870
3810
|
message: `DEV App Server \u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${response.status}\uFF09\u3002`,
|
|
3811
|
+
publicMessage: httpFailureMessage(response.status),
|
|
3871
3812
|
retryable: response.status === 408 || response.status === 429 || response.status >= 500,
|
|
3872
3813
|
cause
|
|
3873
3814
|
});
|
|
@@ -3879,6 +3820,7 @@ var MlbDevRegistrationClient = class {
|
|
|
3879
3820
|
code: "DEV_APP_SERVER_HTTP_ERROR",
|
|
3880
3821
|
phase: "registration",
|
|
3881
3822
|
message: safeServerError(body, `DEV App Server \u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${response.status}\uFF09\u3002`),
|
|
3823
|
+
publicMessage: httpFailureMessage(response.status),
|
|
3882
3824
|
retryable: response.status === 408 || response.status === 429 || response.status >= 500
|
|
3883
3825
|
});
|
|
3884
3826
|
}
|
|
@@ -3893,7 +3835,7 @@ var MlbDevRegistrationClient = class {
|
|
|
3893
3835
|
});
|
|
3894
3836
|
}
|
|
3895
3837
|
options.signal.throwIfAborted();
|
|
3896
|
-
if (request.projectRoot) await
|
|
3838
|
+
if (request.projectRoot) await checkProjectGateway(request.projectRoot, this.#baseUrl);
|
|
3897
3839
|
const localToken = request.projectRoot && !this.#refreshToken ? await projectBuddyToken(request.projectRoot, this.#baseUrl) : void 0;
|
|
3898
3840
|
const store = request.projectRoot ? void 0 : this.#tokenStoreFor?.(request.devAgentId);
|
|
3899
3841
|
const cached2 = this.#refreshToken ? void 0 : await store?.load();
|
|
@@ -3912,7 +3854,8 @@ var MlbDevRegistrationClient = class {
|
|
|
3912
3854
|
throw new BuddyDevError({
|
|
3913
3855
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3914
3856
|
phase: "registration",
|
|
3915
|
-
message: "\u642D\u5B50\u8BE6\u60C5\u54CD\u5E94\u7F3A\u5C11\u5339\u914D\u7684 id \u6216 Buddy token\u3002"
|
|
3857
|
+
message: "\u642D\u5B50\u8BE6\u60C5\u54CD\u5E94\u7F3A\u5C11\u5339\u914D\u7684 id \u6216 Buddy token\u3002",
|
|
3858
|
+
publicMessage: "\u5F00\u53D1\u5E73\u53F0\u8FD4\u56DE\u7684\u642D\u5B50\u8EAB\u4EFD\u6216\u51ED\u636E\u4E0D\u5B8C\u6574\uFF0C\u5DF2\u505C\u6B62\u542F\u52A8\uFF1B\u8BF7\u786E\u8BA4\u5E73\u53F0\u548C\u642D\u5B50\u540E\u91CD\u8BD5\u3002"
|
|
3916
3859
|
});
|
|
3917
3860
|
}
|
|
3918
3861
|
const token = safeCredential(body.token, "agentToken");
|
|
@@ -3920,7 +3863,8 @@ var MlbDevRegistrationClient = class {
|
|
|
3920
3863
|
if (localToken !== void 0 && localToken !== token) throw new BuddyDevError({
|
|
3921
3864
|
code: "DEV_CONFIG_INVALID",
|
|
3922
3865
|
phase: "registration",
|
|
3923
|
-
message: ".env \u4E2D\u7684\u5F00\u53D1\u4EE4\u724C\u4E0E Server \u8FD4\u56DE\u7684\u5F53\u524D\u642D\u5B50\u4EE4\u724C\u4E0D\u4E00\u81F4\uFF1B\u8BF7\u786E\u8BA4 package.json.buddyId \u540E\u4F7F\u7528 --refresh-token \u91CD\u65B0\u9886\u53D6\u3002"
|
|
3866
|
+
message: ".env \u4E2D\u7684\u5F00\u53D1\u4EE4\u724C\u4E0E Server \u8FD4\u56DE\u7684\u5F53\u524D\u642D\u5B50\u4EE4\u724C\u4E0D\u4E00\u81F4\uFF1B\u8BF7\u786E\u8BA4 package.json.buddyId \u540E\u4F7F\u7528 --refresh-token \u91CD\u65B0\u9886\u53D6\u3002",
|
|
3867
|
+
publicMessage: "\u5DE5\u7A0B\u4FDD\u5B58\u7684\u5F00\u53D1\u51ED\u636E\u4E0E\u5F53\u524D\u642D\u5B50\u4E0D\u4E00\u81F4\uFF1B\u8BF7\u786E\u8BA4 package.json.buddyId \u540E\u4F7F\u7528 --refresh-token \u66F4\u65B0\u51ED\u636E\u3002"
|
|
3924
3868
|
});
|
|
3925
3869
|
if (!request.projectRoot) await store?.save(token);
|
|
3926
3870
|
return Object.freeze({
|
|
@@ -3938,19 +3882,22 @@ var MlbDevRegistrationClient = class {
|
|
|
3938
3882
|
throw new BuddyDevError({
|
|
3939
3883
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3940
3884
|
phase: "registration",
|
|
3941
|
-
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"
|
|
3942
3887
|
});
|
|
3943
3888
|
}
|
|
3944
3889
|
const states = body.online.flatMap((item, index) => {
|
|
3945
|
-
|
|
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") {
|
|
3946
3892
|
throw new BuddyDevError({
|
|
3947
3893
|
code: "DEV_APP_SERVER_RESPONSE_INVALID",
|
|
3948
3894
|
phase: "registration",
|
|
3949
|
-
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`
|
|
3950
3897
|
});
|
|
3951
3898
|
}
|
|
3952
|
-
if (!
|
|
3953
|
-
const devAgentId =
|
|
3899
|
+
if (!id.endsWith("-dev")) return [];
|
|
3900
|
+
const devAgentId = id.slice(0, -4);
|
|
3954
3901
|
return [Object.freeze({ devAgentId, online: true })];
|
|
3955
3902
|
});
|
|
3956
3903
|
return Object.freeze(states);
|
|
@@ -4022,23 +3969,24 @@ function buildAgentEnvironment(options) {
|
|
|
4022
3969
|
|
|
4023
3970
|
// packages/cli-core/src/dev/orchestrator.ts
|
|
4024
3971
|
import { createHash as createHash7 } from "node:crypto";
|
|
4025
|
-
import { readFile as
|
|
4026
|
-
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";
|
|
4027
3975
|
|
|
4028
3976
|
// packages/cli-core/src/dev/reload.ts
|
|
4029
3977
|
import { watch } from "node:fs";
|
|
4030
3978
|
import { createHash as createHash6 } from "node:crypto";
|
|
4031
|
-
import { readFile as
|
|
4032
|
-
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";
|
|
4033
3981
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
4034
3982
|
var digest2 = (contents) => createHash6("sha256").update(contents).digest("hex");
|
|
4035
3983
|
async function snapshot(root, prefix = "", result = /* @__PURE__ */ new Map()) {
|
|
4036
|
-
for (const entry2 of await readdir5(
|
|
3984
|
+
for (const entry2 of await readdir5(join16(root, prefix), { withFileTypes: true })) {
|
|
4037
3985
|
const path = prefix ? `${prefix}/${entry2.name}` : entry2.name;
|
|
4038
3986
|
if (!relevant(path)) continue;
|
|
4039
3987
|
try {
|
|
4040
3988
|
if (entry2.isDirectory()) await snapshot(root, path, result);
|
|
4041
|
-
else if (entry2.isFile()) result.set(path, digest2(await
|
|
3989
|
+
else if (entry2.isFile()) result.set(path, digest2(await readFile14(join16(root, path))));
|
|
4042
3990
|
} catch (cause) {
|
|
4043
3991
|
if (cause.code !== "ENOENT") throw cause;
|
|
4044
3992
|
}
|
|
@@ -4128,7 +4076,7 @@ var ReloadingDevSession = class {
|
|
|
4128
4076
|
const path = String(name);
|
|
4129
4077
|
if (!relevant(path)) return;
|
|
4130
4078
|
if (path === ".env") {
|
|
4131
|
-
void
|
|
4079
|
+
void readFile14(join16(this.projectRoot, path), "utf8").then((contents) => {
|
|
4132
4080
|
if (contents !== this.#environment) {
|
|
4133
4081
|
this.#environment = contents;
|
|
4134
4082
|
this.#changed();
|
|
@@ -4311,7 +4259,7 @@ function startReloadingDev(options, startProcess) {
|
|
|
4311
4259
|
}
|
|
4312
4260
|
|
|
4313
4261
|
// packages/cli-core/src/config/runtime-policy.ts
|
|
4314
|
-
import { readFile as
|
|
4262
|
+
import { readFile as readFile15, realpath as realpath6 } from "node:fs/promises";
|
|
4315
4263
|
import { createRequire as createRequire2 } from "node:module";
|
|
4316
4264
|
import { resolve as resolve10 } from "node:path";
|
|
4317
4265
|
var RuntimeRequirementError = class extends Error {
|
|
@@ -4339,26 +4287,23 @@ function assertNpmRuntimeLock(contents, expected) {
|
|
|
4339
4287
|
}
|
|
4340
4288
|
}
|
|
4341
4289
|
async function requireProjectRuntime(root, options = {}) {
|
|
4342
|
-
const selected = allowsRuntimeVersionSelection(options);
|
|
4343
|
-
const declared = await projectRuntimeVersion(root);
|
|
4344
|
-
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");
|
|
4345
4290
|
let expected;
|
|
4346
4291
|
try {
|
|
4347
|
-
expected =
|
|
4292
|
+
expected = await latestRuntimeVersion(options);
|
|
4348
4293
|
} catch (cause) {
|
|
4349
4294
|
options.signal?.throwIfAborted();
|
|
4350
|
-
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 });
|
|
4351
4296
|
}
|
|
4352
4297
|
try {
|
|
4353
4298
|
assertRequiredRuntime(await projectRuntimeVersion(root), expected);
|
|
4354
4299
|
const installedPath = await realpath6(resolve10(root, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"));
|
|
4355
4300
|
const fromProject = createRequire2(resolve10(root, "package.json")).resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`);
|
|
4356
4301
|
if (await realpath6(fromProject) !== installedPath) throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
|
|
4357
|
-
const installed2 = JSON.parse(await
|
|
4302
|
+
const installed2 = JSON.parse(await readFile15(installedPath, "utf8"));
|
|
4358
4303
|
if (installed2.version !== expected) throw new Error(`Runtime \u5B9E\u9645\u5B89\u88C5 ${installed2.version}\uFF0C\u8981\u6C42 ${expected}`);
|
|
4359
4304
|
let lock;
|
|
4360
4305
|
try {
|
|
4361
|
-
lock = await
|
|
4306
|
+
lock = await readFile15(resolve10(root, "package-lock.json"), "utf8");
|
|
4362
4307
|
} catch (cause) {
|
|
4363
4308
|
if (cause.code !== "ENOENT") throw cause;
|
|
4364
4309
|
}
|
|
@@ -4378,8 +4323,8 @@ import { createRequire as createRequire3 } from "node:module";
|
|
|
4378
4323
|
import { dirname as dirname4, resolve as resolve11 } from "node:path";
|
|
4379
4324
|
|
|
4380
4325
|
// packages/cli-core/src/config/data-access.ts
|
|
4381
|
-
import { lstat as lstat10, readFile as
|
|
4382
|
-
import { join as
|
|
4326
|
+
import { lstat as lstat10, readFile as readFile16 } from "node:fs/promises";
|
|
4327
|
+
import { join as join17 } from "node:path";
|
|
4383
4328
|
var DATA_ACCESS_FILENAME = "data-access.json";
|
|
4384
4329
|
function parseDataAccessRequirements(source) {
|
|
4385
4330
|
if (source === void 0) return [];
|
|
@@ -4407,10 +4352,10 @@ function parseDataAccessRequirements(source) {
|
|
|
4407
4352
|
});
|
|
4408
4353
|
}
|
|
4409
4354
|
async function readDataAccessRequirements(projectRoot) {
|
|
4410
|
-
const path =
|
|
4355
|
+
const path = join17(projectRoot, DATA_ACCESS_FILENAME);
|
|
4411
4356
|
try {
|
|
4412
4357
|
if (!(await lstat10(path)).isFile()) throw new Error(`${DATA_ACCESS_FILENAME} \u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6`);
|
|
4413
|
-
return parseDataAccessRequirements(await
|
|
4358
|
+
return parseDataAccessRequirements(await readFile16(path, "utf8"));
|
|
4414
4359
|
} catch (cause) {
|
|
4415
4360
|
if (cause.code === "ENOENT") return [];
|
|
4416
4361
|
throw cause;
|
|
@@ -4566,6 +4511,7 @@ async function waitForAgentOnline(options) {
|
|
|
4566
4511
|
code: "DEV_AGENT_ONLINE_TIMEOUT",
|
|
4567
4512
|
phase: "online",
|
|
4568
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",
|
|
4569
4515
|
retryable: true,
|
|
4570
4516
|
...lastError === void 0 ? {} : { cause: lastError }
|
|
4571
4517
|
});
|
|
@@ -4584,12 +4530,13 @@ async function waitForAgentOnline(options) {
|
|
|
4584
4530
|
await delay2(Math.min(options.pollIntervalMs, Math.max(1, deadline - Date.now())), options.signal);
|
|
4585
4531
|
}
|
|
4586
4532
|
}
|
|
4587
|
-
function agentExitedError(exit,
|
|
4533
|
+
function agentExitedError(exit, diagnostics = "") {
|
|
4588
4534
|
const detail = exit.error !== void 0 ? exit.error.message : exit.signal !== null ? `signal ${exit.signal}` : `exit code ${exit.code ?? "unknown"}`;
|
|
4589
4535
|
return new BuddyDevError({
|
|
4590
4536
|
code: "DEV_AGENT_EXITED",
|
|
4591
4537
|
phase: "running",
|
|
4592
|
-
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),
|
|
4593
4540
|
...exit.error === void 0 ? {} : { cause: exit.error }
|
|
4594
4541
|
});
|
|
4595
4542
|
}
|
|
@@ -4605,6 +4552,7 @@ var ReadyBuddyDevHandle = class {
|
|
|
4605
4552
|
#lifecycle;
|
|
4606
4553
|
#stopGracePeriodMs;
|
|
4607
4554
|
#onStateChange;
|
|
4555
|
+
#failureDetail;
|
|
4608
4556
|
#signal;
|
|
4609
4557
|
#onAbort;
|
|
4610
4558
|
#state = "ready";
|
|
@@ -4622,6 +4570,7 @@ var ReadyBuddyDevHandle = class {
|
|
|
4622
4570
|
this.#stopGracePeriodMs = options.stopGracePeriodMs;
|
|
4623
4571
|
this.#signal = options.signal;
|
|
4624
4572
|
this.#onStateChange = options.onStateChange;
|
|
4573
|
+
this.#failureDetail = options.failureDetail;
|
|
4625
4574
|
this.#onAbort = () => {
|
|
4626
4575
|
void this.stop().catch(() => void 0);
|
|
4627
4576
|
};
|
|
@@ -4632,7 +4581,7 @@ var ReadyBuddyDevHandle = class {
|
|
|
4632
4581
|
else options.signal?.addEventListener("abort", this.#onAbort, { once: true });
|
|
4633
4582
|
this.#emit("ready");
|
|
4634
4583
|
void this.#process.exit.then(async (exit) => {
|
|
4635
|
-
if (this.#state === "ready") await this.#fail(agentExitedError(exit));
|
|
4584
|
+
if (this.#state === "ready") await this.#fail(agentExitedError(exit, this.#failureDetail()));
|
|
4636
4585
|
});
|
|
4637
4586
|
}
|
|
4638
4587
|
get state() {
|
|
@@ -4714,12 +4663,35 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4714
4663
|
let agentProcess;
|
|
4715
4664
|
let processTree;
|
|
4716
4665
|
let instanceLock;
|
|
4717
|
-
|
|
4666
|
+
const output = { stdout: "", stderr: "" };
|
|
4667
|
+
const truncated = { stdout: false, stderr: false };
|
|
4718
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
|
+
};
|
|
4719
4675
|
const failureDetail = () => {
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
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);
|
|
4723
4695
|
};
|
|
4724
4696
|
const emit = (state2) => {
|
|
4725
4697
|
try {
|
|
@@ -4733,7 +4705,7 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4733
4705
|
let config;
|
|
4734
4706
|
let configSource;
|
|
4735
4707
|
try {
|
|
4736
|
-
configSource = await
|
|
4708
|
+
configSource = await readFile17(join18(projectRoot, BUDDY_PACKAGE_FILENAME), "utf8");
|
|
4737
4709
|
config = combineBuddyProject(parseBuddyAgentConfig(configSource));
|
|
4738
4710
|
} catch (cause) {
|
|
4739
4711
|
throw new BuddyDevError({
|
|
@@ -4745,7 +4717,7 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4745
4717
|
}
|
|
4746
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" });
|
|
4747
4719
|
const projectEnv = await readProjectEnvironment(projectRoot);
|
|
4748
|
-
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 ?? "");
|
|
4749
4721
|
const launchPlan = await launchPlanFor(config, options, projectRoot, signal);
|
|
4750
4722
|
const registration = await registerDevAgent({
|
|
4751
4723
|
projectRoot,
|
|
@@ -4786,11 +4758,8 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4786
4758
|
env: childEnvironment,
|
|
4787
4759
|
shell: false,
|
|
4788
4760
|
detached: platform === "darwin",
|
|
4789
|
-
onStdout: (text2) =>
|
|
4790
|
-
onStderr: (text2) =>
|
|
4791
|
-
stderr = (stderr + text2).slice(-16384);
|
|
4792
|
-
options.onLog?.({ source: "agent.stderr", text: text2 });
|
|
4793
|
-
}
|
|
4761
|
+
onStdout: (text2) => capture2("stdout", text2),
|
|
4762
|
+
onStderr: (text2) => capture2("stderr", text2)
|
|
4794
4763
|
});
|
|
4795
4764
|
await instanceLock.attachRuntime(agentProcess.pid);
|
|
4796
4765
|
const exited = agentProcess.exit.then((exit) => {
|
|
@@ -4817,6 +4786,7 @@ async function startBuddyDevProcess(options, hooks) {
|
|
|
4817
4786
|
instanceLock,
|
|
4818
4787
|
lifecycle,
|
|
4819
4788
|
stopGracePeriodMs,
|
|
4789
|
+
failureDetail,
|
|
4820
4790
|
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
4821
4791
|
...options.onStateChange === void 0 ? {} : { onStateChange: options.onStateChange }
|
|
4822
4792
|
});
|
|
@@ -5062,11 +5032,12 @@ var DEV_COMMAND_HELP = `\u7528\u6CD5:
|
|
|
5062
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
|
|
5063
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
|
|
5064
5034
|
\u672A\u914D\u7F6E\u5730\u5740\u65F6\u8FDE\u63A5 MLB \u6D4B\u8BD5\u73AF\u5883 ${DEFAULT_MLB_TEST_URL}\uFF08HTTPS\uFF09\u3002
|
|
5065
|
-
|
|
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
|
|
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
|
|
5066
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
|
|
5067
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
|
|
5068
5039
|
\u8EAB\u4EFD\u53EA\u8BFB\u53D6 package.json.buddyId\uFF0C.env \u4E0D\u9700\u8981 BUDDY_ID\u3002
|
|
5069
|
-
--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`;
|
|
5070
5041
|
function valueAfter(args, index, flag2) {
|
|
5071
5042
|
const value = args[index + 1];
|
|
5072
5043
|
if (value === void 0 || !value.trim()) throw new DevCommandUsageError(`${flag2} \u7F3A\u5C11\u503C`);
|
|
@@ -5121,7 +5092,7 @@ function parseDevArguments(args) {
|
|
|
5121
5092
|
}
|
|
5122
5093
|
function appServerUrl(override, env) {
|
|
5123
5094
|
try {
|
|
5124
|
-
return resolvePlatformUrl({ override, env
|
|
5095
|
+
return resolvePlatformUrl({ override, env });
|
|
5125
5096
|
} catch (cause) {
|
|
5126
5097
|
throw new DevCommandUsageError(`App Server \u5730\u5740\u65E0\u6548\uFF1A${cause instanceof Error ? cause.message : "\u4E0D\u662F\u6709\u6548 URL"}`);
|
|
5127
5098
|
}
|
|
@@ -5158,6 +5129,7 @@ async function runDevCommand(args, io, options = {}) {
|
|
|
5158
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");
|
|
5159
5130
|
return { exitCode: 0 };
|
|
5160
5131
|
}
|
|
5132
|
+
await checkProjectGateway(root, url, { report: (message) => io.write(message) });
|
|
5161
5133
|
const authorizationInput = { appServerUrl: url, ...parsed.refreshToken ? { refreshToken: true } : {} };
|
|
5162
5134
|
if (!options.authorize) {
|
|
5163
5135
|
throw new DevCommandUsageError("\u5F53\u524D CLI Host \u5C1A\u672A\u914D\u7F6E\u642D\u642D\u8D26\u53F7\u767B\u5F55 Adapter");
|
|
@@ -5169,7 +5141,7 @@ async function runDevCommand(args, io, options = {}) {
|
|
|
5169
5141
|
startDev: options.startDev ?? startBuddyDev
|
|
5170
5142
|
});
|
|
5171
5143
|
const handle = await starter.start({
|
|
5172
|
-
runtimeUpdate: { ...options.runtimeUpdate, env: environment
|
|
5144
|
+
runtimeUpdate: { ...options.runtimeUpdate, env: environment },
|
|
5173
5145
|
projectRoot: root,
|
|
5174
5146
|
registrationClient,
|
|
5175
5147
|
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
@@ -5917,6 +5889,7 @@ async function runLogout(io, options) {
|
|
|
5917
5889
|
}
|
|
5918
5890
|
async function runPush(parsed, io, options) {
|
|
5919
5891
|
const root = await (options.resolveProjectRoot ?? requireBuddyAgentProjectRoot)(requestedDirectory(options, parsed));
|
|
5892
|
+
await checkProjectGateway(root, resolvePlatformUrl({ env: options.runtimeUpdate?.env }));
|
|
5920
5893
|
const config = await (options.readConfig ?? readBuddyConfig)(root);
|
|
5921
5894
|
const commit = await pushCommit(parsed, io);
|
|
5922
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");
|
|
@@ -5982,6 +5955,7 @@ async function runMeta(parsed, io, options, legacyAvatar = false) {
|
|
|
5982
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");
|
|
5983
5956
|
if (id === void 0) {
|
|
5984
5957
|
const root = await (options.resolveProjectRoot ?? requireBuddyProjectRoot)(requestedDirectory(options, parsed));
|
|
5958
|
+
await checkProjectGateway(root, resolvePlatformUrl({ env: options.runtimeUpdate?.env }));
|
|
5985
5959
|
id = (await (options.readManifest ?? readBuddyProjectManifest)(root)).buddyId;
|
|
5986
5960
|
}
|
|
5987
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");
|
|
@@ -6031,6 +6005,7 @@ async function runCloudCommand(command, args, io, options = {}) {
|
|
|
6031
6005
|
if (command === "push") return await runPush(parsed, io, options);
|
|
6032
6006
|
if (command === "meta" || command === "avatar") return await runMeta(parsed, io, options, command === "avatar");
|
|
6033
6007
|
const root = await (options.resolveProjectRoot ?? requireBuddyProjectRoot)(requestedDirectory(options, parsed));
|
|
6008
|
+
await checkProjectGateway(root, resolvePlatformUrl({ env: options.runtimeUpdate?.env }));
|
|
6034
6009
|
const manifest = await (options.readManifest ?? readBuddyProjectManifest)(root);
|
|
6035
6010
|
if (options.mode === "local-mock") {
|
|
6036
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");
|
|
@@ -6044,7 +6019,7 @@ async function runCloudCommand(command, args, io, options = {}) {
|
|
|
6044
6019
|
printStatus(io, buddy2, packages);
|
|
6045
6020
|
return { exitCode: 0, buddyId: buddy2.id };
|
|
6046
6021
|
} catch (cause) {
|
|
6047
|
-
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) {
|
|
6048
6023
|
io.writeError(`buddy-cli: ${cause.message}`);
|
|
6049
6024
|
if (cause instanceof CloudLifecycleError || cause instanceof RuntimeRequirementError || cause instanceof PushPreflightError) io.writeError(`\u9519\u8BEF\u7801\uFF1A${cause.code}`);
|
|
6050
6025
|
return {
|
|
@@ -6058,7 +6033,7 @@ var CLOUD_COMMAND_HELP = HELP;
|
|
|
6058
6033
|
|
|
6059
6034
|
// packages/cli-core/src/migration/index.ts
|
|
6060
6035
|
import { lstat as lstat11, open as open5, readdir as readdir6, realpath as realpath7, stat } from "node:fs/promises";
|
|
6061
|
-
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";
|
|
6062
6037
|
var DEFAULT_SKILL_SCAN_LIMITS = Object.freeze({
|
|
6063
6038
|
maxFiles: 128,
|
|
6064
6039
|
maxFileBytes: 256 * 1024,
|
|
@@ -6227,7 +6202,7 @@ async function existingProjectRoot(value) {
|
|
|
6227
6202
|
}
|
|
6228
6203
|
}
|
|
6229
6204
|
async function existingSkillRoot(projectRoot, skillPath) {
|
|
6230
|
-
const candidate = skillPath === "." ? projectRoot :
|
|
6205
|
+
const candidate = skillPath === "." ? projectRoot : join19(projectRoot, ...skillPath.split("/"));
|
|
6231
6206
|
try {
|
|
6232
6207
|
await lstat11(candidate);
|
|
6233
6208
|
} catch (cause) {
|
|
@@ -6264,7 +6239,7 @@ async function existingSkillRoot(projectRoot, skillPath) {
|
|
|
6264
6239
|
}
|
|
6265
6240
|
async function assertEntrypoint(context) {
|
|
6266
6241
|
const entryPath = reportChild(context.skillPath, "SKILL.md");
|
|
6267
|
-
const candidate =
|
|
6242
|
+
const candidate = join19(context.skillRoot, "SKILL.md");
|
|
6268
6243
|
try {
|
|
6269
6244
|
await lstat11(candidate);
|
|
6270
6245
|
const target = await realpath7(candidate);
|
|
@@ -6368,7 +6343,7 @@ async function walkDirectory(actualDirectory, reportDirectory, ancestors, contex
|
|
|
6368
6343
|
}
|
|
6369
6344
|
for (const entry2 of entries) {
|
|
6370
6345
|
const childReportPath = reportChild(reportDirectory, entry2.name);
|
|
6371
|
-
const childPath =
|
|
6346
|
+
const childPath = join19(directory, entry2.name);
|
|
6372
6347
|
let target;
|
|
6373
6348
|
try {
|
|
6374
6349
|
target = await realpath7(childPath);
|
|
@@ -6824,7 +6799,7 @@ async function scanExternalSkillPortability(options) {
|
|
|
6824
6799
|
// packages/cli-core/src/push/preflight.ts
|
|
6825
6800
|
import { createHash as createHash10 } from "node:crypto";
|
|
6826
6801
|
import { lstat as lstat12, open as open6, readdir as readdir7, realpath as realpath8 } from "node:fs/promises";
|
|
6827
|
-
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";
|
|
6828
6803
|
var MEBIBYTE = 1024 * 1024;
|
|
6829
6804
|
var DEFAULT_PUSH_MANIFEST_LIMITS = Object.freeze({
|
|
6830
6805
|
maxFiles: 1e4,
|
|
@@ -7029,7 +7004,7 @@ async function canonicalProjectRoot(projectRoot) {
|
|
|
7029
7004
|
}
|
|
7030
7005
|
}
|
|
7031
7006
|
async function captureConfigWithinLimit(projectRoot, maxFileBytes, filename) {
|
|
7032
|
-
const path =
|
|
7007
|
+
const path = join20(projectRoot, filename);
|
|
7033
7008
|
let entry2;
|
|
7034
7009
|
try {
|
|
7035
7010
|
entry2 = await lstat12(path);
|
|
@@ -7232,7 +7207,7 @@ async function createManifest(options) {
|
|
|
7232
7207
|
sensitiveEntriesExcluded += 1;
|
|
7233
7208
|
continue;
|
|
7234
7209
|
}
|
|
7235
|
-
const absolutePath =
|
|
7210
|
+
const absolutePath = join20(directory, name);
|
|
7236
7211
|
let entry2;
|
|
7237
7212
|
try {
|
|
7238
7213
|
entry2 = await lstat12(absolutePath);
|
|
@@ -7486,7 +7461,7 @@ async function assertCapturedConfigStable(options) {
|
|
|
7486
7461
|
}
|
|
7487
7462
|
let current;
|
|
7488
7463
|
try {
|
|
7489
|
-
const path =
|
|
7464
|
+
const path = join20(options.projectRoot, options.filename);
|
|
7490
7465
|
const entry2 = await lstat12(path);
|
|
7491
7466
|
if (!entry2.isFile() || entry2.isSymbolicLink()) {
|
|
7492
7467
|
error({
|
|
@@ -7532,7 +7507,7 @@ async function createPushPreflight(options) {
|
|
|
7532
7507
|
parseCapturedProject(initialAgentEntry);
|
|
7533
7508
|
let initialDataEntry;
|
|
7534
7509
|
try {
|
|
7535
|
-
await lstat12(
|
|
7510
|
+
await lstat12(join20(projectRoot, DATA_ACCESS_FILENAME));
|
|
7536
7511
|
initialDataEntry = await captureConfigWithinLimit(projectRoot, limits.maxFileBytes, DATA_ACCESS_FILENAME);
|
|
7537
7512
|
} catch (cause) {
|
|
7538
7513
|
if (cause.code !== "ENOENT") throw cause;
|
|
@@ -7634,8 +7609,8 @@ async function createPushPreflight(options) {
|
|
|
7634
7609
|
|
|
7635
7610
|
// packages/cli-core/src/push/bundle.ts
|
|
7636
7611
|
import { createHash as createHash11 } from "node:crypto";
|
|
7637
|
-
import { lstat as lstat13, readFile as
|
|
7638
|
-
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";
|
|
7639
7614
|
import { Writable } from "node:stream";
|
|
7640
7615
|
import { pipeline } from "node:stream/promises";
|
|
7641
7616
|
import { createGzip } from "node:zlib";
|
|
@@ -7657,7 +7632,7 @@ function inside(root, target) {
|
|
|
7657
7632
|
return path === "" || path !== ".." && !path.startsWith(`..${sep3}`) && !path.startsWith("/") && !win324.isAbsolute(path);
|
|
7658
7633
|
}
|
|
7659
7634
|
async function capture(root, file) {
|
|
7660
|
-
const absolute =
|
|
7635
|
+
const absolute = join21(root, ...file.path.split("/"));
|
|
7661
7636
|
try {
|
|
7662
7637
|
const entry2 = await lstat13(absolute);
|
|
7663
7638
|
if (!entry2.isFile() || entry2.isSymbolicLink() || entry2.size !== file.bytes) {
|
|
@@ -7665,7 +7640,7 @@ async function capture(root, file) {
|
|
|
7665
7640
|
}
|
|
7666
7641
|
const canonical = await realpath9(absolute);
|
|
7667
7642
|
if (!inside(root, canonical)) changed(file.path, `\u63D0\u4EA4\u6587\u4EF6\u8D8A\u8FC7\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${file.path}`);
|
|
7668
|
-
const contents = await
|
|
7643
|
+
const contents = await readFile18(absolute);
|
|
7669
7644
|
if (contents.byteLength !== file.bytes || digest3(contents) !== file.digest) {
|
|
7670
7645
|
changed(file.path, `\u63D0\u4EA4\u524D\u6587\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316\uFF1A${file.path}`);
|
|
7671
7646
|
}
|
|
@@ -7783,6 +7758,7 @@ function validateRecoverableBuddyId(value) {
|
|
|
7783
7758
|
return buddyId;
|
|
7784
7759
|
}
|
|
7785
7760
|
async function resolveApplicationDraft(name, tagline, intro, requestedBuddyId, options, root, args, io) {
|
|
7761
|
+
await checkProjectGateway(root, resolvePlatformUrl({ env: options.runtimeCatalog?.env }));
|
|
7786
7762
|
const register = () => (options.registerMeta ?? prepareAndRegisterMeta)({
|
|
7787
7763
|
root,
|
|
7788
7764
|
profile: { name, tagline, intro },
|
|
@@ -7876,9 +7852,6 @@ function parseInitArguments(args) {
|
|
|
7876
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");
|
|
7877
7853
|
parsed.creatorVersion = setOnce2(parsed.creatorVersion, value, flag2);
|
|
7878
7854
|
break;
|
|
7879
|
-
case "--runtime-version":
|
|
7880
|
-
parsed.runtimeVersion = setOnce2(parsed.runtimeVersion, value, flag2);
|
|
7881
|
-
break;
|
|
7882
7855
|
case "--avatar":
|
|
7883
7856
|
parsed.avatar = setOnce2(parsed.avatar, value, flag2);
|
|
7884
7857
|
break;
|
|
@@ -7967,7 +7940,6 @@ async function initializeProjectRoute(route, args, io, options, application) {
|
|
|
7967
7940
|
const initializationTarget = { directory: rootDirectory, kind: "new" };
|
|
7968
7941
|
let initializationPlan = options.initializeProject ? void 0 : await planBuddyProjectInitialization(initializationTarget);
|
|
7969
7942
|
const existingBuddyId = initializationPlan?.existingManifest?.buddyId;
|
|
7970
|
-
const runtimeVersion = args.resolvedRuntimeVersion ?? await selectInitRuntime(rootDirectory, args.runtimeVersion, io, options.runtimeCatalog);
|
|
7971
7943
|
if (existingBuddyId !== void 0 && args.buddyId !== void 0 && existingBuddyId !== args.buddyId) {
|
|
7972
7944
|
throw new CliUsageError(
|
|
7973
7945
|
`\u5DF2\u6709 package.json \u7ED1\u5B9A\u7684\u662F ${existingBuddyId}\uFF0C\u4E0E --buddy-id ${args.buddyId} \u4E0D\u4E00\u81F4`
|
|
@@ -7990,9 +7962,9 @@ async function initializeProjectRoute(route, args, io, options, application) {
|
|
|
7990
7962
|
}
|
|
7991
7963
|
let platformTemplate;
|
|
7992
7964
|
try {
|
|
7993
|
-
platformTemplate = options.scaffoldPlatformAgent ? await options.scaffoldPlatformAgent(project.rootDirectory, name
|
|
7994
|
-
resolveDependencies: (template) => latestRuntimeTemplate(template, { ...options.runtimeCatalog,
|
|
7995
|
-
}
|
|
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
|
+
});
|
|
7996
7968
|
} catch (cause) {
|
|
7997
7969
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
7998
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`);
|
|
@@ -8075,7 +8047,7 @@ async function resumeProjectArguments(args, cwd, options, io) {
|
|
|
8075
8047
|
await assertInitializableBuddyTarget(root);
|
|
8076
8048
|
let entry2;
|
|
8077
8049
|
try {
|
|
8078
|
-
entry2 = await lstat14(
|
|
8050
|
+
entry2 = await lstat14(join22(root, "package.json"));
|
|
8079
8051
|
} catch (cause) {
|
|
8080
8052
|
if (cause.code === "ENOENT") {
|
|
8081
8053
|
const draft = await readMetaDraft(root);
|
|
@@ -8123,6 +8095,7 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
8123
8095
|
} catch (cause) {
|
|
8124
8096
|
if (!(cause instanceof BuddyProjectContextError) || cause.code !== "PROJECT_DIRECTORY_NOT_FOUND") throw cause;
|
|
8125
8097
|
}
|
|
8098
|
+
if (projectRoot !== void 0) await checkProjectGateway(projectRoot, resolvePlatformUrl({ env: options.runtimeCatalog?.env }));
|
|
8126
8099
|
await authenticate(options);
|
|
8127
8100
|
if (projectRoot !== void 0) {
|
|
8128
8101
|
io.write(`\u5DF2\u8BC6\u522B\u642D\u642D\u9879\u76EE\uFF1A${projectRoot}`);
|
|
@@ -8179,10 +8152,6 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
8179
8152
|
return { exitCode: 0 };
|
|
8180
8153
|
}
|
|
8181
8154
|
let route = routeFromMode(parsed.mode);
|
|
8182
|
-
if (parsed.runtimeVersion !== void 0) {
|
|
8183
|
-
if (!allowsRuntimeVersionSelection(options.runtimeCatalog)) throw new CliUsageError("\u672A\u77E5 init \u53C2\u6570 --runtime-version");
|
|
8184
|
-
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");
|
|
8185
|
-
}
|
|
8186
8155
|
if (route === void 0 && !io.canPrompt) requireModeForNonInteractive();
|
|
8187
8156
|
const cwd = resolve18(options.cwd ?? process.cwd());
|
|
8188
8157
|
await assertInitializableBuddyTarget(cwd);
|
|
@@ -8190,10 +8159,7 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
8190
8159
|
if (!parsed.directory.trim()) throw new CliUsageError("--directory \u4E0D\u80FD\u4E3A\u7A7A");
|
|
8191
8160
|
await assertInitializableBuddyTarget(resolve18(cwd, parsed.directory));
|
|
8192
8161
|
}
|
|
8193
|
-
|
|
8194
|
-
const target = resolve18(cwd, parsed.directory ?? (parsed.name ? defaultProjectDirectory(parsed.name) : "."));
|
|
8195
|
-
parsed.resolvedRuntimeVersion = await selectInitRuntime(target, parsed.runtimeVersion, io, options.runtimeCatalog);
|
|
8196
|
-
}
|
|
8162
|
+
await checkProjectGateway(resolve18(cwd, parsed.directory ?? "."), resolvePlatformUrl({ env: options.runtimeCatalog?.env }));
|
|
8197
8163
|
await authenticate(options);
|
|
8198
8164
|
await resumeProjectArguments(parsed, cwd, options, io);
|
|
8199
8165
|
route ??= routeFromMode(parsed.mode);
|
|
@@ -8209,7 +8175,7 @@ async function runBuddyCli(args, io, options = {}) {
|
|
|
8209
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");
|
|
8210
8176
|
return { exitCode: 130 };
|
|
8211
8177
|
}
|
|
8212
|
-
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) {
|
|
8213
8179
|
return failure2(cause.message, io, cause instanceof CliUsageError);
|
|
8214
8180
|
}
|
|
8215
8181
|
throw cause;
|
|
@@ -8337,6 +8303,7 @@ export {
|
|
|
8337
8303
|
assertOutsideBuddyProject,
|
|
8338
8304
|
buddyAgentConfig,
|
|
8339
8305
|
buildAgentEnvironment,
|
|
8306
|
+
checkProjectGateway,
|
|
8340
8307
|
checkRuntimeUpdate,
|
|
8341
8308
|
combineBuddyProject,
|
|
8342
8309
|
createBuddyConfig,
|