@my-life-buddies/cli 0.24.1 → 0.25.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 +5 -1
- package/dist/bin/buddy.js +5 -2
- package/dist/bin/buddy.js.map +2 -2
- package/dist/bin/core.js +4 -2
- package/dist/bin/core.js.map +2 -2
- package/dist/bin/preview.js +535 -26
- package/dist/bin/preview.js.map +4 -4
- package/dist/web/app.css +34 -0
- package/dist/web/app.js +30 -7
- package/dist/web/chat-markdown.js +181 -0
- package/dist/web/diagnostics.js +14 -5
- package/dist/web/index.html +27 -0
- package/dist/web/tool-inventory.js +94 -0
- package/package.json +5 -4
package/dist/bin/preview.js
CHANGED
|
@@ -178,6 +178,495 @@ ${line}`;
|
|
|
178
178
|
}
|
|
179
179
|
};
|
|
180
180
|
|
|
181
|
+
// apps/preview/src/project-inspection.ts
|
|
182
|
+
import { readFileSync, realpathSync, statSync } from "node:fs";
|
|
183
|
+
import { createRequire } from "node:module";
|
|
184
|
+
import { dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
185
|
+
import { parse } from "acorn";
|
|
186
|
+
var Unknown = class {
|
|
187
|
+
constructor(reason = "\u914D\u7F6E\u4F9D\u8D56\u8FD0\u884C\u65F6\u4FE1\u606F\u6216\u6682\u4E0D\u652F\u6301\u7684\u8868\u8FBE\u5F0F\u3002", textPrefix) {
|
|
188
|
+
this.reason = reason;
|
|
189
|
+
this.textPrefix = textPrefix;
|
|
190
|
+
}
|
|
191
|
+
reason;
|
|
192
|
+
textPrefix;
|
|
193
|
+
};
|
|
194
|
+
var Api = class {
|
|
195
|
+
constructor(name) {
|
|
196
|
+
this.name = name;
|
|
197
|
+
}
|
|
198
|
+
name;
|
|
199
|
+
};
|
|
200
|
+
var PlatformTool = class {
|
|
201
|
+
constructor(name) {
|
|
202
|
+
this.name = name;
|
|
203
|
+
}
|
|
204
|
+
name;
|
|
205
|
+
};
|
|
206
|
+
var Fn = class {
|
|
207
|
+
constructor(node, scope) {
|
|
208
|
+
this.node = node;
|
|
209
|
+
this.scope = scope;
|
|
210
|
+
}
|
|
211
|
+
node;
|
|
212
|
+
scope;
|
|
213
|
+
};
|
|
214
|
+
var Fields = class _Fields {
|
|
215
|
+
constructor(entries, optional = false) {
|
|
216
|
+
this.entries = entries;
|
|
217
|
+
this.optional = optional;
|
|
218
|
+
}
|
|
219
|
+
entries;
|
|
220
|
+
optional;
|
|
221
|
+
get(key) {
|
|
222
|
+
for (let i = this.entries.length - 1; i >= 0; i--) {
|
|
223
|
+
const entry = this.entries[i];
|
|
224
|
+
if (entry.key !== void 0) {
|
|
225
|
+
if (entry.key === key) return entry.value();
|
|
226
|
+
} else {
|
|
227
|
+
const spread = entry.value();
|
|
228
|
+
if (!(spread instanceof _Fields)) return new Unknown("\u5BF9\u8C61\u5305\u542B\u52A8\u6001\u5C55\u5F00\uFF0C\u65E0\u6CD5\u786E\u5B9A\u6700\u7EC8\u914D\u7F6E\u3002");
|
|
229
|
+
const keys = spread.keys();
|
|
230
|
+
if (!keys || keys.includes(key)) return spread.get(key);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return void 0;
|
|
234
|
+
}
|
|
235
|
+
keys() {
|
|
236
|
+
const keys = /* @__PURE__ */ new Set();
|
|
237
|
+
for (const entry of this.entries) {
|
|
238
|
+
if (entry.key !== void 0) keys.add(entry.key);
|
|
239
|
+
else {
|
|
240
|
+
const spread = entry.value(), nested = spread instanceof _Fields ? spread.keys() : void 0;
|
|
241
|
+
if (!nested) return void 0;
|
|
242
|
+
nested.forEach((key) => keys.add(key));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return [...keys];
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
var fields = (data) => new Fields(Object.entries(data).map(([key, value]) => ({ key, value: () => value })));
|
|
249
|
+
var unknown = () => new Unknown();
|
|
250
|
+
var isPrimitive = (value) => value === null || value === void 0 || ["string", "number", "boolean"].includes(typeof value);
|
|
251
|
+
var Scope = class {
|
|
252
|
+
constructor(file, parent) {
|
|
253
|
+
this.file = file;
|
|
254
|
+
this.parent = parent;
|
|
255
|
+
}
|
|
256
|
+
file;
|
|
257
|
+
parent;
|
|
258
|
+
bindings = /* @__PURE__ */ new Map();
|
|
259
|
+
mutable = /* @__PURE__ */ new Set();
|
|
260
|
+
get(name) {
|
|
261
|
+
if (this.mutable.has(name)) return new Unknown("\u914D\u7F6E\u5305\u542B\u53EF\u53D8\u503C\u6216\u540E\u7EED\u4FEE\u6539\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002");
|
|
262
|
+
const binding = this.bindings.get(name);
|
|
263
|
+
return binding ? binding() : this.parent?.get(name) ?? new Unknown();
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
var within = (root, file) => {
|
|
267
|
+
const path = relative(root, file);
|
|
268
|
+
return !isAbsolute(path) && path !== ".." && !path.startsWith(`..${sep}`);
|
|
269
|
+
};
|
|
270
|
+
var keyOf = (node, computed = false) => !computed && node.type === "Identifier" ? node.name : node.type === "Literal" && ["string", "number"].includes(typeof node.value) ? String(node.value) : void 0;
|
|
271
|
+
var unwrap = (node) => node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration" ? node.declaration ?? node : node;
|
|
272
|
+
function walk(node, visit, functions = false) {
|
|
273
|
+
visit(node);
|
|
274
|
+
if (!functions && /^(?:Function|ArrowFunction)/u.test(node.type)) return;
|
|
275
|
+
for (const value of Object.values(node)) {
|
|
276
|
+
if (Array.isArray(value)) {
|
|
277
|
+
for (const child of value) if (child?.type) walk(child, visit, functions);
|
|
278
|
+
} else if (value && typeof value === "object" && value.type) walk(value, visit, functions);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
var Reader = class {
|
|
282
|
+
sources = /* @__PURE__ */ new Map();
|
|
283
|
+
dependencies = /* @__PURE__ */ new Map();
|
|
284
|
+
root;
|
|
285
|
+
runtimeRoot;
|
|
286
|
+
bytes = 0;
|
|
287
|
+
steps = 0;
|
|
288
|
+
depth = 0;
|
|
289
|
+
constructor(root) {
|
|
290
|
+
this.root = realpathSync(root);
|
|
291
|
+
}
|
|
292
|
+
tick() {
|
|
293
|
+
if (++this.steps > 5e4) throw new Error("inspection budget");
|
|
294
|
+
}
|
|
295
|
+
lazy(read) {
|
|
296
|
+
let state = 0, result;
|
|
297
|
+
return () => {
|
|
298
|
+
this.tick();
|
|
299
|
+
if (state === 1) return new Unknown("\u914D\u7F6E\u5B58\u5728\u5FAA\u73AF\u5F15\u7528\u3002");
|
|
300
|
+
if (state === 2) return result;
|
|
301
|
+
state = 1;
|
|
302
|
+
try {
|
|
303
|
+
result = read();
|
|
304
|
+
} catch {
|
|
305
|
+
result = new Unknown("\u914D\u7F6E\u65E0\u6CD5\u9759\u6001\u8BFB\u53D6\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002");
|
|
306
|
+
}
|
|
307
|
+
state = 2;
|
|
308
|
+
return result;
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
source(path) {
|
|
312
|
+
if (!this.dependencies.has(path)) this.dependencies.set(path, fingerprint(path));
|
|
313
|
+
const file = realpathSync(path);
|
|
314
|
+
const inRuntime = this.runtimeRoot && within(this.runtimeRoot, file);
|
|
315
|
+
if ((!within(this.root, file) || relative(this.root, file).split(sep).includes("node_modules")) && !inRuntime) throw new Error("outside project");
|
|
316
|
+
if (![".js", ".mjs", ".cjs"].includes(extname(file))) throw new Error("unsupported source");
|
|
317
|
+
const existing = this.sources.get(file);
|
|
318
|
+
if (existing) return existing;
|
|
319
|
+
const size = statSync(file).size;
|
|
320
|
+
if (this.sources.size >= 80 || size > 512e3 || (this.bytes += size) > 3e6) throw new Error("inspection size");
|
|
321
|
+
const tree = parse(readFileSync(file, "utf8"), { ecmaVersion: "latest", sourceType: "module" });
|
|
322
|
+
const scope = new Scope(file), exports = /* @__PURE__ */ new Map();
|
|
323
|
+
const result = { tree, scope, exports };
|
|
324
|
+
this.sources.set(file, result);
|
|
325
|
+
this.bind(tree.body, scope);
|
|
326
|
+
for (const statement of tree.body) {
|
|
327
|
+
if (statement.type === "ImportDeclaration") {
|
|
328
|
+
for (const specifier of statement.specifiers) {
|
|
329
|
+
const name = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.type === "ImportNamespaceSpecifier" ? "*" : keyOf(specifier.imported);
|
|
330
|
+
scope.bindings.set(specifier.local.name, this.lazy(() => this.imported(scope.file, statement.source.value, name ?? "")));
|
|
331
|
+
}
|
|
332
|
+
} else if (statement.type === "ExportDefaultDeclaration") {
|
|
333
|
+
exports.set("default", this.lazy(() => this.expression(statement.declaration, scope)));
|
|
334
|
+
} else if (statement.type === "ExportNamedDeclaration") {
|
|
335
|
+
const declaration = statement.declaration;
|
|
336
|
+
if (declaration?.type === "FunctionDeclaration") exports.set(declaration.id.name, () => scope.get(declaration.id.name));
|
|
337
|
+
if (declaration?.type === "VariableDeclaration") {
|
|
338
|
+
for (const item of declaration.declarations) if (item.id.type === "Identifier") exports.set(item.id.name, () => scope.get(item.id.name));
|
|
339
|
+
}
|
|
340
|
+
for (const specifier of statement.specifiers) {
|
|
341
|
+
const name = keyOf(specifier.exported), local = keyOf(specifier.local);
|
|
342
|
+
exports.set(name, this.lazy(() => statement.source ? this.imported(file, statement.source.value, local) : scope.get(local)));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
imported(file, specifier, name) {
|
|
349
|
+
if (["typebox", "@sinclair/typebox"].includes(specifier) && name === "Type") return new Api("Type");
|
|
350
|
+
if (specifier === "@my-life-buddies/buddy-runtime" && name === "BuddyServer") return new Api("BuddyServer");
|
|
351
|
+
if (!specifier.startsWith("./") && !specifier.startsWith("../")) return new Unknown("\u914D\u7F6E\u6765\u81EA\u5916\u90E8\u4F9D\u8D56\uFF0C\u65E0\u6CD5\u9759\u6001\u786E\u5B9A\u3002");
|
|
352
|
+
const target = resolve(dirname(file), specifier);
|
|
353
|
+
for (const candidate of [target, `${target}.mjs`, `${target}.js`, join(target, "index.js")]) {
|
|
354
|
+
try {
|
|
355
|
+
const source = this.source(candidate);
|
|
356
|
+
return name === "*" ? new Fields([...source.exports].map(([key, value]) => ({ key, value }))) : source.exports.get(name)?.() ?? unknown();
|
|
357
|
+
} catch {
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return new Unknown("\u5F15\u7528\u7684\u672C\u5730\u6E90\u6587\u4EF6\u65E0\u6CD5\u8BFB\u53D6\u6216\u4E0D\u652F\u6301\u9759\u6001\u5206\u6790\u3002");
|
|
361
|
+
}
|
|
362
|
+
bind(statements, scope) {
|
|
363
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
364
|
+
const localValues = /* @__PURE__ */ new Set();
|
|
365
|
+
for (const item of statements) {
|
|
366
|
+
const statement = unwrap(item);
|
|
367
|
+
if (statement.type === "FunctionDeclaration" && statement.id) scope.bindings.set(statement.id.name, () => new Fn(statement, scope));
|
|
368
|
+
if (statement.type === "VariableDeclaration") for (const declaration of statement.declarations) {
|
|
369
|
+
this.pattern(declaration.id, this.lazy(() => this.expression(declaration.init, scope)), scope);
|
|
370
|
+
if (declaration.id.type === "Identifier") localValues.add(declaration.id.name);
|
|
371
|
+
let source = declaration.init;
|
|
372
|
+
while (source?.type === "MemberExpression") source = source.object;
|
|
373
|
+
if (declaration.id.type === "Identifier" && source?.type === "Identifier") aliases.set(declaration.id.name, source.name);
|
|
374
|
+
if (statement.kind !== "const") walk(declaration.id, (node) => {
|
|
375
|
+
if (node.type === "Identifier") scope.mutable.add(node.name);
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
for (const item of statements) walk(item, (node) => {
|
|
380
|
+
if (node.type === "ExpressionStatement" && node.expression.type === "CallExpression") {
|
|
381
|
+
for (const argument of node.expression.arguments) {
|
|
382
|
+
let root = argument;
|
|
383
|
+
while (root.type === "MemberExpression") root = root.object;
|
|
384
|
+
if (root.type === "Identifier" && localValues.has(root.name)) scope.mutable.add(root.name);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
let target;
|
|
388
|
+
if (node.type === "AssignmentExpression") target = node.left;
|
|
389
|
+
if (node.type === "UpdateExpression") target = node.argument;
|
|
390
|
+
if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && ["push", "pop", "shift", "unshift", "splice", "sort", "reverse", "fill", "copyWithin", "assign", "defineProperty"].includes(keyOf(node.callee.property, node.callee.computed) ?? "")) target = node.callee.object.name === "Object" ? node.arguments[0] : node.callee.object;
|
|
391
|
+
while (target?.type === "MemberExpression") target = target.object;
|
|
392
|
+
if (target?.type === "Identifier") scope.mutable.add(target.name);
|
|
393
|
+
});
|
|
394
|
+
for (let changed = true; changed; ) {
|
|
395
|
+
changed = false;
|
|
396
|
+
for (const [alias, original] of aliases) if (scope.mutable.has(alias) && !scope.mutable.has(original)) {
|
|
397
|
+
scope.mutable.add(original);
|
|
398
|
+
changed = true;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
pattern(pattern, value, scope) {
|
|
403
|
+
if (pattern.type === "Identifier") scope.bindings.set(pattern.name, value);
|
|
404
|
+
else if (pattern.type === "ObjectPattern") for (const property of pattern.properties) {
|
|
405
|
+
if (property.type !== "Property") continue;
|
|
406
|
+
const key = keyOf(property.key, property.computed);
|
|
407
|
+
this.pattern(property.value, this.lazy(() => key === void 0 ? unknown() : this.member(value(), key)), scope);
|
|
408
|
+
}
|
|
409
|
+
else if (pattern.type === "ArrayPattern") pattern.elements.forEach((item, index) => {
|
|
410
|
+
if (item) this.pattern(item, this.lazy(() => this.member(value(), String(index))), scope);
|
|
411
|
+
});
|
|
412
|
+
else if (pattern.type === "AssignmentPattern") this.pattern(pattern.left, this.lazy(() => {
|
|
413
|
+
const item = value();
|
|
414
|
+
return item === void 0 ? this.expression(pattern.right, scope) : item;
|
|
415
|
+
}), scope);
|
|
416
|
+
}
|
|
417
|
+
functionScope(fn, args) {
|
|
418
|
+
const scope = new Scope(fn.scope.file, fn.scope);
|
|
419
|
+
fn.node.params.forEach((param, index) => this.pattern(param, () => args[index], scope));
|
|
420
|
+
if (fn.node.body.type === "BlockStatement") this.bind(fn.node.body.body, scope);
|
|
421
|
+
return scope;
|
|
422
|
+
}
|
|
423
|
+
call(fn, args) {
|
|
424
|
+
if (fn instanceof Api && fn.name.startsWith("Type.")) return this.schema(fn.name.slice(5), args);
|
|
425
|
+
if (!(fn instanceof Fn)) return new Unknown("\u51FD\u6570\u8C03\u7528\u7684\u7ED3\u679C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002");
|
|
426
|
+
if (++this.depth > 32) {
|
|
427
|
+
this.depth--;
|
|
428
|
+
return unknown();
|
|
429
|
+
}
|
|
430
|
+
try {
|
|
431
|
+
const scope = this.functionScope(fn, args), body = fn.node.body;
|
|
432
|
+
if (body.type !== "BlockStatement") return this.expression(body, scope);
|
|
433
|
+
for (const statement of body.body) {
|
|
434
|
+
if (statement.type === "ReturnStatement") return this.expression(statement.argument, scope);
|
|
435
|
+
let conditionalReturn = false;
|
|
436
|
+
walk(statement, (node) => {
|
|
437
|
+
if (node.type === "ReturnStatement") conditionalReturn = true;
|
|
438
|
+
});
|
|
439
|
+
if (conditionalReturn) return new Unknown("\u914D\u7F6E\u5DE5\u5382\u5305\u542B\u6761\u4EF6\u8FD4\u56DE\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002");
|
|
440
|
+
}
|
|
441
|
+
return unknown();
|
|
442
|
+
} finally {
|
|
443
|
+
this.depth--;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
member(object3, key) {
|
|
447
|
+
if (object3 instanceof Fields) return object3.get(key);
|
|
448
|
+
if (object3 instanceof Api) return object3.name === "conversation.tools" ? new PlatformTool(key) : new Api(`${object3.name}.${key}`);
|
|
449
|
+
if (Array.isArray(object3)) return key === "length" ? object3.length : /^\d+$/u.test(key) ? object3[Number(key)] : unknown();
|
|
450
|
+
return object3 instanceof Unknown ? object3 : unknown();
|
|
451
|
+
}
|
|
452
|
+
expression(node, scope) {
|
|
453
|
+
this.tick();
|
|
454
|
+
if (!node) return void 0;
|
|
455
|
+
switch (node.type) {
|
|
456
|
+
case "Literal":
|
|
457
|
+
return node.regex || node.bigint ? unknown() : node.value;
|
|
458
|
+
case "Identifier":
|
|
459
|
+
return node.name === "undefined" ? void 0 : scope.get(node.name);
|
|
460
|
+
case "FunctionDeclaration":
|
|
461
|
+
case "FunctionExpression":
|
|
462
|
+
case "ArrowFunctionExpression":
|
|
463
|
+
return new Fn(node, scope);
|
|
464
|
+
case "AwaitExpression":
|
|
465
|
+
case "ChainExpression":
|
|
466
|
+
return this.expression(node.argument ?? node.expression, scope);
|
|
467
|
+
case "ObjectExpression":
|
|
468
|
+
return new Fields(node.properties.map((property) => ({ key: property.type === "SpreadElement" ? void 0 : keyOf(property.key, property.computed), value: this.lazy(() => property.type === "SpreadElement" ? this.expression(property.argument, scope) : property.kind === "get" || property.kind === "set" ? unknown() : property.computed && keyOf(property.key, true) === void 0 ? unknown() : this.expression(property.value, scope)) })));
|
|
469
|
+
case "ArrayExpression": {
|
|
470
|
+
const values = [];
|
|
471
|
+
for (const element of node.elements) {
|
|
472
|
+
if (element?.type === "SpreadElement") {
|
|
473
|
+
const value = this.expression(element.argument, scope);
|
|
474
|
+
values.push(...Array.isArray(value) ? value : [value instanceof Unknown ? value : unknown()]);
|
|
475
|
+
} else values.push(this.expression(element, scope));
|
|
476
|
+
}
|
|
477
|
+
return values;
|
|
478
|
+
}
|
|
479
|
+
case "MemberExpression": {
|
|
480
|
+
const key = node.computed ? this.expression(node.property, scope) : node.property.name;
|
|
481
|
+
return typeof key === "string" || typeof key === "number" ? this.member(this.expression(node.object, scope), String(key)) : unknown();
|
|
482
|
+
}
|
|
483
|
+
case "CallExpression": {
|
|
484
|
+
if (node.callee.type === "MemberExpression" && keyOf(node.callee.property, node.callee.computed) === "map") {
|
|
485
|
+
const values = this.expression(node.callee.object, scope), fn = this.expression(node.arguments[0], scope);
|
|
486
|
+
return Array.isArray(values) ? values.map((value, index) => this.call(fn, [value, index])) : unknown();
|
|
487
|
+
}
|
|
488
|
+
return this.call(this.expression(node.callee, scope), node.arguments.map((arg) => this.expression(arg, scope)));
|
|
489
|
+
}
|
|
490
|
+
case "ConditionalExpression": {
|
|
491
|
+
const test = this.expression(node.test, scope);
|
|
492
|
+
return isPrimitive(test) ? this.expression(test ? node.consequent : node.alternate, scope) : new Unknown("\u914D\u7F6E\u6839\u636E\u73AF\u5883\u6216\u4F1A\u8BDD\u52A8\u6001\u9009\u62E9\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002");
|
|
493
|
+
}
|
|
494
|
+
case "LogicalExpression": {
|
|
495
|
+
const left = this.expression(node.left, scope);
|
|
496
|
+
if (left instanceof Unknown) return left;
|
|
497
|
+
if (node.operator === "??") return left == null ? this.expression(node.right, scope) : left;
|
|
498
|
+
return (node.operator === "&&" ? Boolean(left) : !left) ? this.expression(node.right, scope) : left;
|
|
499
|
+
}
|
|
500
|
+
case "BinaryExpression": {
|
|
501
|
+
const left = this.expression(node.left, scope), right = this.expression(node.right, scope);
|
|
502
|
+
if (!isPrimitive(left) || !isPrimitive(right)) return node.operator === "+" && typeof left === "string" ? new Unknown("\u63CF\u8FF0\u5305\u542B\u52A8\u6001\u5185\u5BB9\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002", left) : unknown();
|
|
503
|
+
if (node.operator === "+" && (typeof left === "string" || typeof right === "string")) return `${left}${right}`;
|
|
504
|
+
if (node.operator === "===") return left === right;
|
|
505
|
+
if (node.operator === "!==") return left !== right;
|
|
506
|
+
return unknown();
|
|
507
|
+
}
|
|
508
|
+
case "UnaryExpression": {
|
|
509
|
+
const value = this.expression(node.argument, scope);
|
|
510
|
+
if (!isPrimitive(value)) return unknown();
|
|
511
|
+
return node.operator === "!" ? !value : node.operator === "-" && typeof value === "number" ? -value : unknown();
|
|
512
|
+
}
|
|
513
|
+
case "TemplateLiteral": {
|
|
514
|
+
let result = "";
|
|
515
|
+
for (let i = 0; i < node.quasis.length; i++) {
|
|
516
|
+
result += node.quasis[i].value.cooked;
|
|
517
|
+
if (i < node.expressions.length) {
|
|
518
|
+
const value = this.expression(node.expressions[i], scope);
|
|
519
|
+
if (!isPrimitive(value)) return new Unknown("\u63CF\u8FF0\u5305\u542B\u52A8\u6001\u5185\u5BB9\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002", result);
|
|
520
|
+
result += String(value);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return result;
|
|
524
|
+
}
|
|
525
|
+
default:
|
|
526
|
+
return unknown();
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
schema(name, args) {
|
|
530
|
+
const first = args[0];
|
|
531
|
+
if (name === "Optional") return first instanceof Fields ? new Fields(first.entries, true) : unknown();
|
|
532
|
+
const scalar = { String: "string", Number: "number", Integer: "integer", Boolean: "boolean", Null: "null" };
|
|
533
|
+
let schema, options;
|
|
534
|
+
if (scalar[name]) {
|
|
535
|
+
schema = fields({ type: scalar[name] });
|
|
536
|
+
options = first;
|
|
537
|
+
} else if (name === "Object" && first instanceof Fields) {
|
|
538
|
+
const keys = first.keys();
|
|
539
|
+
if (!keys) return unknown();
|
|
540
|
+
const required = [];
|
|
541
|
+
for (const key of keys) {
|
|
542
|
+
const value = first.get(key);
|
|
543
|
+
if (!(value instanceof Fields)) return unknown();
|
|
544
|
+
if (!value.optional) required.push(key);
|
|
545
|
+
}
|
|
546
|
+
schema = fields({ type: "object", properties: first, ...required.length ? { required } : {} });
|
|
547
|
+
options = args[1];
|
|
548
|
+
} else if (name === "Array") {
|
|
549
|
+
schema = fields({ type: "array", items: first });
|
|
550
|
+
options = args[1];
|
|
551
|
+
} else if (name === "Literal" && isPrimitive(first) && first !== void 0) {
|
|
552
|
+
schema = fields({ const: first, type: first === null ? "null" : typeof first });
|
|
553
|
+
options = args[1];
|
|
554
|
+
} else if (name === "Union" && Array.isArray(first)) {
|
|
555
|
+
schema = first.length === 1 && first[0] instanceof Fields ? first[0] : fields({ anyOf: first });
|
|
556
|
+
options = args[1];
|
|
557
|
+
} else if (name === "Any" || name === "Unknown") {
|
|
558
|
+
schema = fields({});
|
|
559
|
+
options = first;
|
|
560
|
+
} else return new Unknown("\u53C2\u6570\u4F7F\u7528\u6682\u4E0D\u652F\u6301\u7684 Schema \u6784\u9020\u65B9\u6CD5\u3002");
|
|
561
|
+
return options === void 0 ? schema : options instanceof Fields ? new Fields([...schema.entries, { value: () => options }]) : unknown();
|
|
562
|
+
}
|
|
563
|
+
json(value, depth = 0) {
|
|
564
|
+
this.tick();
|
|
565
|
+
if (depth > 30) throw new Error("schema depth");
|
|
566
|
+
if (isPrimitive(value)) return value;
|
|
567
|
+
if (Array.isArray(value)) return value.map((item) => this.json(item, depth + 1));
|
|
568
|
+
if (value instanceof Fields) {
|
|
569
|
+
const keys = value.keys();
|
|
570
|
+
if (!keys) throw new Error("dynamic schema");
|
|
571
|
+
return Object.fromEntries(keys.map((key) => [key, this.json(value.get(key), depth + 1)]));
|
|
572
|
+
}
|
|
573
|
+
throw new Error("dynamic schema");
|
|
574
|
+
}
|
|
575
|
+
runtime() {
|
|
576
|
+
try {
|
|
577
|
+
const path = createRequire(join(this.root, "package.json")).resolve("@my-life-buddies/buddy-runtime/package.json");
|
|
578
|
+
this.dependencies.set(path, fingerprint(path));
|
|
579
|
+
const manifest = JSON.parse(readFileSync(path, "utf8"));
|
|
580
|
+
if (manifest.name !== "@my-life-buddies/buddy-runtime") throw new Error("runtime package");
|
|
581
|
+
this.runtimeRoot = realpathSync(dirname(path));
|
|
582
|
+
const source = this.source(join(this.runtimeRoot, "dist/conversation/agent.js"));
|
|
583
|
+
const factory = source.exports.get("createAgent")?.();
|
|
584
|
+
const scope = factory instanceof Fn ? this.functionScope(factory, [unknown()]) : void 0;
|
|
585
|
+
return { tools: scope?.get("platformTools") ?? unknown(), builtin: source.exports.has("builtinTools") };
|
|
586
|
+
} catch {
|
|
587
|
+
return { tools: unknown(), builtin: true };
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
inspect() {
|
|
591
|
+
const source = this.source(join(this.root, "start.mjs"));
|
|
592
|
+
const starts = [];
|
|
593
|
+
walk(source.tree, (node) => {
|
|
594
|
+
if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression") return;
|
|
595
|
+
if (keyOf(node.callee.property, node.callee.computed) !== "start") return;
|
|
596
|
+
const owner = this.expression(node.callee.object, source.scope);
|
|
597
|
+
if (owner instanceof Api && owner.name === "BuddyServer") starts.push(node);
|
|
598
|
+
});
|
|
599
|
+
const conversation = new Fields([{ value: () => new Unknown("\u914D\u7F6E\u4F9D\u8D56\u5F53\u524D\u4F1A\u8BDD\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002") }, { key: "tools", value: () => new Api("conversation.tools") }]);
|
|
600
|
+
const options = starts.length === 1 ? this.call(this.expression(starts[0].arguments[0], source.scope), [conversation]) : new Unknown("\u672A\u8BC6\u522B\u5230\u552F\u4E00\u7684 BuddyServer.start \u5DE5\u5382\u5165\u53E3\u3002");
|
|
601
|
+
const initial = this.member(options, "initialState"), model = this.member(initial, "model");
|
|
602
|
+
const toolValues = this.member(initial, "tools"), runtime = this.runtime();
|
|
603
|
+
const tools = [], unresolved = [];
|
|
604
|
+
const list = toolValues === void 0 && initial instanceof Fields ? [] : Array.isArray(toolValues) ? toolValues : [toolValues];
|
|
605
|
+
let payloadSize = 0;
|
|
606
|
+
for (const item of list) {
|
|
607
|
+
if (tools.length + unresolved.length >= 128 || payloadSize > 25e4) {
|
|
608
|
+
unresolved.push({ reason: "\u914D\u7F6E\u6E05\u5355\u8D85\u51FA\u9759\u6001\u5C55\u793A\u4E0A\u9650\uFF0C\u5176\u4F59\u5DE5\u5177\u8BF7\u5728\u6A21\u578B\u8BF7\u6C42\u4E2D\u67E5\u770B\u3002" });
|
|
609
|
+
break;
|
|
610
|
+
}
|
|
611
|
+
const origin = item instanceof PlatformTool ? "platform" : "custom";
|
|
612
|
+
const value = item instanceof PlatformTool ? this.member(runtime.tools, item.name) : item;
|
|
613
|
+
if (item instanceof PlatformTool && value === void 0) {
|
|
614
|
+
unresolved.push({ name: item.name, reason: "\u5F53\u524D\u5B89\u88C5\u7684 Runtime \u672A\u63D0\u4F9B\u6B64\u5E73\u53F0\u5DE5\u5177\uFF0C\u8BF7\u68C0\u67E5\u6CE8\u518C\u914D\u7F6E\u3002" });
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
const name = item instanceof PlatformTool ? item.name : this.member(value, "name");
|
|
618
|
+
if (typeof name !== "string" || !/^[\w.-]{1,128}$/u.test(name)) {
|
|
619
|
+
unresolved.push({ reason: value instanceof Unknown ? value.reason : "\u5DE5\u5177\u540D\u79F0\u6216\u6CE8\u518C\u5173\u7CFB\u65E0\u6CD5\u9759\u6001\u786E\u5B9A\u3002" });
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const description = this.member(value, "description"), parameters = this.member(value, "parameters");
|
|
623
|
+
let schema;
|
|
624
|
+
try {
|
|
625
|
+
const json2 = this.json(parameters);
|
|
626
|
+
if (json2 && typeof json2 === "object" && !Array.isArray(json2) && JSON.stringify(json2).length <= 32768) schema = json2;
|
|
627
|
+
} catch {
|
|
628
|
+
}
|
|
629
|
+
const reason = [typeof description !== "string" ? description instanceof Unknown && description.textPrefix ? "\u63CF\u8FF0\u542B\u52A8\u6001\u5185\u5BB9\uFF0C\u5F53\u524D\u4EC5\u5C55\u793A\u53EF\u8BFB\u53D6\u90E8\u5206\u3002" : "\u5DE5\u5177\u63CF\u8FF0\u5C1A\u672A\u9759\u6001\u8BFB\u53D6\u3002" : "", !schema ? "\u53C2\u6570\u5B9A\u4E49\u5C1A\u672A\u9759\u6001\u8BFB\u53D6\u3002" : ""].join("");
|
|
630
|
+
const descriptionText = typeof description === "string" ? description : description instanceof Unknown ? description.textPrefix : void 0;
|
|
631
|
+
const tool = { name, origin, ...descriptionText ? { description: descriptionText.slice(0, 4096) } : {}, ...schema ? { parameters: schema } : {}, ...reason ? { reason } : {} };
|
|
632
|
+
payloadSize += Buffer.byteLength(JSON.stringify(tool));
|
|
633
|
+
tools.push(tool);
|
|
634
|
+
}
|
|
635
|
+
if (runtime.builtin) unresolved.push({ name: "Runtime \u5185\u7F6E\u5DE5\u5177", reason: "Runtime \u53EF\u80FD\u6309\u6A21\u578B\u80FD\u529B\u8FFD\u52A0\u5DE5\u5177\uFF1B\u662F\u5426\u542F\u7528\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\uFF0C\u53EF\u5728\u6A21\u578B\u8BF7\u6C42\u4E2D\u67E5\u770B\u3002" });
|
|
636
|
+
const seen = /* @__PURE__ */ new Set();
|
|
637
|
+
for (const tool of tools) {
|
|
638
|
+
if (seen.has(tool.name)) unresolved.push({ name: tool.name, reason: "\u6CE8\u518C\u5217\u8868\u4E2D\u5B58\u5728\u540C\u540D\u5DE5\u5177\uFF0C\u8BF7\u68C0\u67E5\u5DE5\u7A0B\u914D\u7F6E\u3002" });
|
|
639
|
+
seen.add(tool.name);
|
|
640
|
+
}
|
|
641
|
+
return { status: unresolved.length || tools.some((tool) => tool.reason) ? "partial" : "complete", model: typeof model === "string" && model.length > 0 && model.length <= 128 ? { status: "known", value: model } : { status: "dynamic", reason: model instanceof Unknown ? model.reason : "\u6A21\u578B\u914D\u7F6E\u65E0\u6CD5\u9759\u6001\u786E\u5B9A\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002" }, tools, unresolved };
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
var fingerprint = (path) => {
|
|
645
|
+
try {
|
|
646
|
+
const stat = statSync(path);
|
|
647
|
+
return `${realpathSync(path)}:${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}`;
|
|
648
|
+
} catch {
|
|
649
|
+
return "missing";
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
function createProjectInspector(projectRoot) {
|
|
653
|
+
let cached;
|
|
654
|
+
let files = /* @__PURE__ */ new Map();
|
|
655
|
+
return async () => {
|
|
656
|
+
if (cached && [...files].every(([path, stamp]) => fingerprint(path) === stamp)) return cached;
|
|
657
|
+
let reader;
|
|
658
|
+
try {
|
|
659
|
+
reader = new Reader(projectRoot);
|
|
660
|
+
cached = reader.inspect();
|
|
661
|
+
} catch {
|
|
662
|
+
cached = { status: "partial", model: { status: "dynamic", reason: "\u5DE5\u7A0B\u5165\u53E3\u65E0\u6CD5\u9759\u6001\u8BFB\u53D6\uFF0C\u9700\u8FD0\u884C\u65F6\u786E\u8BA4\u3002" }, tools: [], unresolved: [{ reason: "\u5DE5\u5177\u6CE8\u518C\u5173\u7CFB\u5C1A\u672A\u8BFB\u53D6\uFF1B\u8BF7\u786E\u8BA4\u5165\u53E3\u53CA\u5F15\u7528\u6587\u4EF6\u5B58\u5728\u4E14\u8BED\u6CD5\u6709\u6548\u3002" }] };
|
|
663
|
+
}
|
|
664
|
+
files = new Map([join(projectRoot, "start.mjs"), join(projectRoot, "node_modules/@my-life-buddies/buddy-runtime/package.json")].map((path) => [path, fingerprint(path)]));
|
|
665
|
+
for (const [path, stamp] of reader?.dependencies ?? []) files.set(path, stamp);
|
|
666
|
+
return cached;
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
181
670
|
// apps/preview/src/controller.ts
|
|
182
671
|
var TERMINAL_RUN_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
183
672
|
function publicFailure(cause) {
|
|
@@ -193,6 +682,8 @@ var PreviewController = class {
|
|
|
193
682
|
#readConfig;
|
|
194
683
|
#readBuddyDetails;
|
|
195
684
|
#now;
|
|
685
|
+
#readInspection;
|
|
686
|
+
#inspectionPromise;
|
|
196
687
|
#listeners = /* @__PURE__ */ new Set();
|
|
197
688
|
#simulatorListeners = /* @__PURE__ */ new Set();
|
|
198
689
|
#runs = /* @__PURE__ */ new Map();
|
|
@@ -225,6 +716,7 @@ var PreviewController = class {
|
|
|
225
716
|
this.#readConfig = options.readConfig ?? ((root) => readBuddyConfig(root));
|
|
226
717
|
this.#readBuddyDetails = options.readBuddyDetails;
|
|
227
718
|
this.#now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
719
|
+
this.#readInspection = options.readInspection ?? createProjectInspector(options.projectRoot);
|
|
228
720
|
}
|
|
229
721
|
get projectRoot() {
|
|
230
722
|
return this.#projectRoot;
|
|
@@ -232,6 +724,18 @@ var PreviewController = class {
|
|
|
232
724
|
state() {
|
|
233
725
|
return this.#state;
|
|
234
726
|
}
|
|
727
|
+
async refreshInspection() {
|
|
728
|
+
if (this.#closed) return;
|
|
729
|
+
if (this.#inspectionPromise) return this.#inspectionPromise;
|
|
730
|
+
this.#inspectionPromise = this.#readInspection().then((inspection) => {
|
|
731
|
+
if (!this.#closed && JSON.stringify(inspection) !== JSON.stringify(this.#state.inspection)) {
|
|
732
|
+
this.#setState({ ...this.#state, inspection });
|
|
733
|
+
}
|
|
734
|
+
}).finally(() => {
|
|
735
|
+
this.#inspectionPromise = void 0;
|
|
736
|
+
});
|
|
737
|
+
return this.#inspectionPromise;
|
|
738
|
+
}
|
|
235
739
|
async project() {
|
|
236
740
|
return this.#readConfig(this.#projectRoot);
|
|
237
741
|
}
|
|
@@ -275,6 +779,7 @@ var PreviewController = class {
|
|
|
275
779
|
}
|
|
276
780
|
this.#record({ channel: "dev", type: `dev.${phase}`, summary: phase === "reloading" ? "\u672C\u5730\u6587\u4EF6\u5DF2\u4FEE\u6539\uFF0C\u6B63\u5728\u91CD\u8F7D\uFF1B\u5F53\u524D\u56DE\u590D\u53EF\u80FD\u4E2D\u65AD" : phase === "reload_failed" ? error?.message ?? "\u91CD\u8F7D\u5931\u8D25\uFF0C\u4FEE\u6B63\u6587\u4EF6\u540E\u81EA\u52A8\u91CD\u8BD5" : "\u91CD\u8F7D\u5B8C\u6210\uFF0CDEV \u5DF2\u5C31\u7EEA" });
|
|
277
781
|
this.#setState({ phase, ready: this.#state.ready, ...error ? { error } : {} });
|
|
782
|
+
void this.refreshInspection();
|
|
278
783
|
},
|
|
279
784
|
onLog: ({ source, text: text2 }) => {
|
|
280
785
|
if (controller.signal.aborted) return;
|
|
@@ -835,7 +1340,7 @@ var PreviewController = class {
|
|
|
835
1340
|
if (this.#events.length > 300) this.#events.splice(0, this.#events.length - 300);
|
|
836
1341
|
}
|
|
837
1342
|
#setState(next) {
|
|
838
|
-
this.#state = Object.freeze({ ...next, revision: this.#state.revision + 1 });
|
|
1343
|
+
this.#state = Object.freeze({ ...this.#state.inspection ? { inspection: this.#state.inspection } : {}, ...next, revision: this.#state.revision + 1 });
|
|
839
1344
|
for (const listener of this.#listeners) {
|
|
840
1345
|
try {
|
|
841
1346
|
listener(this.#state);
|
|
@@ -848,54 +1353,56 @@ var PreviewController = class {
|
|
|
848
1353
|
|
|
849
1354
|
// apps/preview/src/server.ts
|
|
850
1355
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
851
|
-
import { readFileSync } from "node:fs";
|
|
1356
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
852
1357
|
import { createServer } from "node:http";
|
|
853
|
-
import { createRequire } from "node:module";
|
|
1358
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
854
1359
|
import QRCode from "qrcode";
|
|
855
1360
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
856
1361
|
var SESSION_COOKIE_PREFIX = "buddy_preview_session";
|
|
857
|
-
var require2 =
|
|
1362
|
+
var require2 = createRequire2(import.meta.url);
|
|
858
1363
|
var BRAND_ICON = Buffer.from(
|
|
859
|
-
|
|
1364
|
+
readFileSync2(new URL("../web/assets/developer-platform-icon.png.base64", import.meta.url), "utf8").trim(),
|
|
860
1365
|
"base64"
|
|
861
1366
|
);
|
|
862
1367
|
var WEB_ASSETS = Object.freeze(/* @__PURE__ */ new Map([
|
|
863
1368
|
["/", {
|
|
864
1369
|
contentType: "text/html; charset=utf-8",
|
|
865
|
-
body:
|
|
1370
|
+
body: readFileSync2(new URL("../web/index.html", import.meta.url))
|
|
866
1371
|
}],
|
|
867
1372
|
["/assets/app.css", {
|
|
868
1373
|
contentType: "text/css; charset=utf-8",
|
|
869
|
-
body:
|
|
1374
|
+
body: readFileSync2(new URL("../web/app.css", import.meta.url))
|
|
870
1375
|
}],
|
|
871
1376
|
["/assets/tokens.css", {
|
|
872
1377
|
contentType: "text/css; charset=utf-8",
|
|
873
|
-
body:
|
|
1378
|
+
body: readFileSync2(new URL("../web/tokens.css", import.meta.url))
|
|
874
1379
|
}],
|
|
875
1380
|
["/assets/brand.css", {
|
|
876
1381
|
contentType: "text/css; charset=utf-8",
|
|
877
|
-
body:
|
|
1382
|
+
body: readFileSync2(new URL("../web/brand.css", import.meta.url))
|
|
878
1383
|
}],
|
|
879
|
-
["/assets/widgets.js", { contentType: "text/javascript; charset=utf-8", body:
|
|
880
|
-
["/assets/widgets.css", { contentType: "text/css; charset=utf-8", body:
|
|
1384
|
+
["/assets/widgets.js", { contentType: "text/javascript; charset=utf-8", body: readFileSync2(new URL("../web/widgets.js", import.meta.url)) }],
|
|
1385
|
+
["/assets/widgets.css", { contentType: "text/css; charset=utf-8", body: readFileSync2(new URL("../web/widgets.css", import.meta.url)) }],
|
|
881
1386
|
["/assets/app.js", {
|
|
882
1387
|
contentType: "text/javascript; charset=utf-8",
|
|
883
|
-
body:
|
|
1388
|
+
body: readFileSync2(new URL("../web/app.js", import.meta.url))
|
|
884
1389
|
}],
|
|
885
|
-
["/assets/diagnostics.js", { contentType: "text/javascript; charset=utf-8", body:
|
|
1390
|
+
["/assets/diagnostics.js", { contentType: "text/javascript; charset=utf-8", body: readFileSync2(new URL("../web/diagnostics.js", import.meta.url)) }],
|
|
1391
|
+
["/assets/tool-inventory.js", { contentType: "text/javascript; charset=utf-8", body: readFileSync2(new URL("../web/tool-inventory.js", import.meta.url)) }],
|
|
1392
|
+
["/assets/chat-markdown.js", { contentType: "text/javascript; charset=utf-8", body: readFileSync2(new URL("../web/chat-markdown.js", import.meta.url)) }],
|
|
886
1393
|
["/assets/developer-platform-icon.png", {
|
|
887
1394
|
contentType: "image/png",
|
|
888
1395
|
body: BRAND_ICON
|
|
889
1396
|
}],
|
|
890
1397
|
["/assets/iphone-16-max.js", {
|
|
891
1398
|
contentType: "text/javascript; charset=utf-8",
|
|
892
|
-
body:
|
|
1399
|
+
body: readFileSync2(require2.resolve("@sneas/telephone/iphone-16-max.js"))
|
|
893
1400
|
}]
|
|
894
1401
|
]));
|
|
895
1402
|
function closeServer(server) {
|
|
896
1403
|
if (!server.listening) return Promise.resolve();
|
|
897
|
-
return new Promise((
|
|
898
|
-
server.close((error) => error ? reject(error) :
|
|
1404
|
+
return new Promise((resolve2, reject) => {
|
|
1405
|
+
server.close((error) => error ? reject(error) : resolve2());
|
|
899
1406
|
});
|
|
900
1407
|
}
|
|
901
1408
|
function writeHeaders(response) {
|
|
@@ -967,7 +1474,7 @@ function widgetDocument(response, html, render, state = "ready", status = 200) {
|
|
|
967
1474
|
response.setHeader("Content-Security-Policy", "sandbox allow-scripts; default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; connect-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'self'");
|
|
968
1475
|
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
969
1476
|
if (validWidgetRender(render)) {
|
|
970
|
-
const script = state === "ready" ?
|
|
1477
|
+
const script = state === "ready" ? readFileSync2(new URL("../web/widget-document.js", import.meta.url), "utf8").replace("__WIDGET_RENDER__", JSON.stringify(render)) : `window.addEventListener('load',()=>parent.postMessage({channel:'buddy-widget-document',render:${JSON.stringify(render)},state:'error'},'*'),{once:true})`;
|
|
971
1478
|
const signal = `<script>${script}</script>`;
|
|
972
1479
|
if (/<!doctype[^>]*>/iu.test(html)) html = html.replace(/<!doctype[^>]*>/iu, (match) => match + signal);
|
|
973
1480
|
else html = signal + html;
|
|
@@ -1082,12 +1589,14 @@ data: ${JSON.stringify(value)}
|
|
|
1082
1589
|
}
|
|
1083
1590
|
if (request.method === "GET" && url.pathname === "/api/project") {
|
|
1084
1591
|
try {
|
|
1085
|
-
|
|
1592
|
+
await options.controller.refreshInspection();
|
|
1593
|
+
return json(response, 200, { project: { ...publicProject(await options.controller.project()), inspection: options.controller.state().inspection } });
|
|
1086
1594
|
} catch {
|
|
1087
1595
|
return apiError(response, 422, "PROJECT_CONFIG_INVALID", "\u9879\u76EE\u914D\u7F6E\u65E0\u6CD5\u8BFB\u53D6\u6216\u6821\u9A8C\u5931\u8D25");
|
|
1088
1596
|
}
|
|
1089
1597
|
}
|
|
1090
1598
|
if (request.method === "GET" && url.pathname === "/api/dev") {
|
|
1599
|
+
await options.controller.refreshInspection();
|
|
1091
1600
|
return json(response, 200, { state: options.controller.state() });
|
|
1092
1601
|
}
|
|
1093
1602
|
if (request.method === "GET" && url.pathname === "/api/buddy") {
|
|
@@ -1248,11 +1757,11 @@ data: ${JSON.stringify({
|
|
|
1248
1757
|
return apiError(response, 404, "NOT_FOUND", "\u63A5\u53E3\u4E0D\u5B58\u5728");
|
|
1249
1758
|
});
|
|
1250
1759
|
try {
|
|
1251
|
-
await new Promise((
|
|
1760
|
+
await new Promise((resolve2, reject) => {
|
|
1252
1761
|
server.once("error", reject);
|
|
1253
1762
|
server.listen(port, host, () => {
|
|
1254
1763
|
server.off("error", reject);
|
|
1255
|
-
|
|
1764
|
+
resolve2();
|
|
1256
1765
|
});
|
|
1257
1766
|
});
|
|
1258
1767
|
const address = server.address();
|
|
@@ -1515,7 +2024,7 @@ async function mlbAppCommand(url, token, method, params, options = {}) {
|
|
|
1515
2024
|
if (options.signal?.aborted) throw options.signal.reason;
|
|
1516
2025
|
const requestId = randomUUID2();
|
|
1517
2026
|
const socket = appSocket(url, token);
|
|
1518
|
-
return await new Promise((
|
|
2027
|
+
return await new Promise((resolve2, reject) => {
|
|
1519
2028
|
let settled = false;
|
|
1520
2029
|
let ready = false;
|
|
1521
2030
|
let sent = false;
|
|
@@ -1528,7 +2037,7 @@ async function mlbAppCommand(url, token, method, params, options = {}) {
|
|
|
1528
2037
|
if (settled) return;
|
|
1529
2038
|
settled = true;
|
|
1530
2039
|
cleanup();
|
|
1531
|
-
|
|
2040
|
+
resolve2(value);
|
|
1532
2041
|
};
|
|
1533
2042
|
const fail = (cause) => {
|
|
1534
2043
|
if (settled) return;
|
|
@@ -1658,8 +2167,8 @@ async function* mlbAppEvents(url, token, options = {}) {
|
|
|
1658
2167
|
queuedBytes -= item.bytes;
|
|
1659
2168
|
yield item.frame;
|
|
1660
2169
|
} else {
|
|
1661
|
-
await new Promise((
|
|
1662
|
-
wake =
|
|
2170
|
+
await new Promise((resolve2) => {
|
|
2171
|
+
wake = resolve2;
|
|
1663
2172
|
});
|
|
1664
2173
|
wake = void 0;
|
|
1665
2174
|
}
|
|
@@ -1808,14 +2317,14 @@ function localReceipt(prefix, value) {
|
|
|
1808
2317
|
}
|
|
1809
2318
|
function waitForRetry(milliseconds, signal) {
|
|
1810
2319
|
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
1811
|
-
return new Promise((
|
|
2320
|
+
return new Promise((resolve2, reject) => {
|
|
1812
2321
|
const abort = () => {
|
|
1813
2322
|
clearTimeout(timer);
|
|
1814
2323
|
reject(signal?.reason);
|
|
1815
2324
|
};
|
|
1816
2325
|
const timer = setTimeout(() => {
|
|
1817
2326
|
signal?.removeEventListener("abort", abort);
|
|
1818
|
-
|
|
2327
|
+
resolve2();
|
|
1819
2328
|
}, milliseconds);
|
|
1820
2329
|
signal?.addEventListener("abort", abort, { once: true });
|
|
1821
2330
|
});
|