@my-life-buddies/cli 0.13.3 → 0.15.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 +74 -22
- package/dist/bin/buddy.js +29 -10
- package/dist/bin/buddy.js.map +2 -2
- package/dist/bin/core.js +1480 -611
- package/dist/bin/core.js.map +4 -4
- package/dist/bin/preview.js +324 -27
- package/dist/bin/preview.js.map +4 -4
- package/dist/web/app.css +65 -6
- package/dist/web/app.js +103 -39
- package/dist/web/diagnostics.js +184 -0
- package/dist/web/index.html +34 -34
- package/dist/web/widgets.css +59 -28
- package/dist/web/widgets.js +230 -76
- package/package.json +3 -3
- package/resources/README.md +6 -50
- package/resources/agent-template/package-lock.json +4 -4
- package/resources/agent-template/package.json +2 -2
- package/resources/buddy-creator/INSTALL.md +0 -25
- package/resources/buddy-creator/PATCHES.md +0 -53
- package/resources/buddy-creator/SKILL.md +0 -76
- package/resources/buddy-creator/THIRD_PARTY_NOTICES.md +0 -154
- package/resources/buddy-creator/agents/openai.yaml +0 -4
- package/resources/buddy-creator/assets/licenses/bail.txt +0 -26
- package/resources/buddy-creator/assets/licenses/ccount.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities-html4.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities-legacy.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-reference-invalid.txt +0 -26
- package/resources/buddy-creator/assets/licenses/comma-separated-tokens.txt +0 -26
- package/resources/buddy-creator/assets/licenses/debug.txt +0 -24
- package/resources/buddy-creator/assets/licenses/decode-named-character-reference.txt +0 -26
- package/resources/buddy-creator/assets/licenses/dequal.txt +0 -25
- package/resources/buddy-creator/assets/licenses/devlop.txt +0 -26
- package/resources/buddy-creator/assets/licenses/escape-string-regexp.txt +0 -13
- package/resources/buddy-creator/assets/licenses/estree-util-is-identifier-name.txt +0 -26
- package/resources/buddy-creator/assets/licenses/extend.txt +0 -27
- package/resources/buddy-creator/assets/licenses/hast-util-to-jsx-runtime.txt +0 -26
- package/resources/buddy-creator/assets/licenses/hast-util-whitespace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/html-url-attributes.txt +0 -25
- package/resources/buddy-creator/assets/licenses/inline-style-parser.txt +0 -13
- package/resources/buddy-creator/assets/licenses/is-alphabetical.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-alphanumerical.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-decimal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-hexadecimal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-plain-obj.txt +0 -13
- package/resources/buddy-creator/assets/licenses/longest-streak.txt +0 -26
- package/resources/buddy-creator/assets/licenses/markdown-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-find-and-replace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-from-markdown.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-autolink-literal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-footnote.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-strikethrough.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-task-list-item.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdx-expression.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdx-jsx.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdxjs-esm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-phrasing.txt +0 -27
- package/resources/buddy-creator/assets/licenses/mdast-util-to-hast.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-to-markdown.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-to-string.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-core-commonmark.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-autolink-literal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-footnote.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-strikethrough.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-tagfilter.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-task-list-item.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-destination.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-label.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-space.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-title.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-whitespace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-character.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-chunked.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-classify-character.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-combine-extensions.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-decode-numeric-character-reference.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-decode-string.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-encode.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-html-tag-name.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-normalize-identifier.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-resolve-all.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-sanitize-uri.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-subtokenize.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-symbol.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-types.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark.txt +0 -26
- package/resources/buddy-creator/assets/licenses/ms.txt +0 -25
- package/resources/buddy-creator/assets/licenses/parse-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/phosphor-icons--react.txt +0 -25
- package/resources/buddy-creator/assets/licenses/property-information.txt +0 -26
- package/resources/buddy-creator/assets/licenses/react-dom.txt +0 -25
- package/resources/buddy-creator/assets/licenses/react-markdown.txt +0 -25
- package/resources/buddy-creator/assets/licenses/react.txt +0 -25
- package/resources/buddy-creator/assets/licenses/remark-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/remark-parse.txt +0 -25
- package/resources/buddy-creator/assets/licenses/remark-rehype.txt +0 -26
- package/resources/buddy-creator/assets/licenses/remark-stringify.txt +0 -25
- package/resources/buddy-creator/assets/licenses/scheduler.txt +0 -25
- package/resources/buddy-creator/assets/licenses/space-separated-tokens.txt +0 -26
- package/resources/buddy-creator/assets/licenses/stringify-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/style-to-js.txt +0 -26
- package/resources/buddy-creator/assets/licenses/style-to-object.txt +0 -26
- package/resources/buddy-creator/assets/licenses/trim-lines.txt +0 -26
- package/resources/buddy-creator/assets/licenses/trough.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--debug.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--estree-jsx.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--estree.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--hast.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--mdast.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--ms.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--unist.txt +0 -25
- package/resources/buddy-creator/assets/licenses/ungap--structured-clone.txt +0 -19
- package/resources/buddy-creator/assets/licenses/unified.txt +0 -25
- package/resources/buddy-creator/assets/licenses/unist-util-is.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-position.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-stringify-position.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-visit-parents.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-visit.txt +0 -26
- package/resources/buddy-creator/assets/licenses/vfile-message.txt +0 -26
- package/resources/buddy-creator/assets/licenses/vfile.txt +0 -25
- package/resources/buddy-creator/assets/licenses/zwitch.txt +0 -26
- package/resources/buddy-creator/assets/preview/assets/index-B5VmkoSx.js +0 -39
- package/resources/buddy-creator/assets/preview/assets/index-DWKP6b-3.css +0 -4
- package/resources/buddy-creator/assets/preview/brand-logo.png +0 -0
- package/resources/buddy-creator/assets/preview/brand.css +0 -100
- package/resources/buddy-creator/assets/preview/index.html +0 -7
- package/resources/buddy-creator/assets/preview/reader.css +0 -165
- package/resources/buddy-creator/assets/preview/reader.js +0 -135
- package/resources/buddy-creator/assets/preview/widgets.css +0 -1
- package/resources/buddy-creator/assets/preview/widgets.js +0 -168
- package/resources/buddy-creator/assets/widget-reference/conversation.png +0 -0
- package/resources/buddy-creator/assets/widget-reference/expanded.png +0 -0
- package/resources/buddy-creator/assets/widget-v2/app.js +0 -62
- package/resources/buddy-creator/assets/widget-v2/style.css +0 -1
- package/resources/buddy-creator/assets/widget-v3/app.js +0 -65
- package/resources/buddy-creator/assets/widget-v3/style.css +0 -103
- package/resources/buddy-creator/assets/widget-v4/app.js +0 -66
- package/resources/buddy-creator/assets/widget-v4/style.css +0 -187
- package/resources/buddy-creator/references/artifact-schema.md +0 -70
- package/resources/buddy-creator/references/catalog.json +0 -401
- package/resources/buddy-creator/references/definition.md +0 -24
- package/resources/buddy-creator/references/dialogue-examples.md +0 -133
- package/resources/buddy-creator/references/host-guide.md +0 -219
- package/resources/buddy-creator/references/interview.md +0 -235
- package/resources/buddy-creator/references/knowledge.md +0 -40
- package/resources/buddy-creator/references/methods.md +0 -77
- package/resources/buddy-creator/references/opening.md +0 -14
- package/resources/buddy-creator/references/preview-panel.md +0 -66
- package/resources/buddy-creator/references/recovery.md +0 -46
- package/resources/buddy-creator/references/service.md +0 -76
- package/resources/buddy-creator/references/widgets-protocol.md +0 -83
- package/resources/buddy-creator/references/widgets.md +0 -99
- package/resources/buddy-creator/scripts/buddy.py +0 -108
- package/resources/buddy-creator/scripts/buddy_client.py +0 -67
- package/resources/buddy-creator/scripts/buddy_core.py +0 -865
- package/resources/buddy-creator/scripts/completion.py +0 -296
- package/resources/buddy-creator/scripts/interview.py +0 -215
- package/resources/buddy-creator/scripts/preview.py +0 -617
- package/resources/buddy-creator/scripts/preview_panel.py +0 -80
- package/resources/buddy-creator/scripts/sources.py +0 -239
- package/resources/buddy-creator/scripts/widget_render.py +0 -66
- package/resources/buddy-creator/scripts/widget_render_v1.py +0 -176
- package/resources/buddy-creator/scripts/widget_render_v2.py +0 -98
- package/resources/buddy-creator/scripts/widget_render_v3.py +0 -86
- package/resources/buddy-creator/scripts/widget_render_v4.py +0 -121
- package/resources/buddy-creator/scripts/widgets.py +0 -227
- package/resources/buddy-creator/version.json +0 -8
- package/resources/buddy-creator.manifest.json +0 -791
- package/resources/dada-object-avatar/SKILL.md +0 -37
- package/resources/dada-object-avatar/agents/openai.yaml +0 -4
- package/resources/dada-object-avatar/assets/examples/cat.png +0 -0
- package/resources/dada-object-avatar/assets/examples/cooking.png +0 -0
- package/resources/dada-object-avatar/assets/examples/divination.png +0 -0
- package/resources/dada-object-avatar/assets/examples/doctor.png +0 -0
- package/resources/dada-object-avatar/assets/examples/relationship.png +0 -0
- package/resources/dada-object-avatar/assets/examples/work.png +0 -0
- package/resources/dada-object-avatar/assets/preview.png +0 -0
- package/resources/dada-object-avatar/references/evaluation-rubric.md +0 -22
- package/resources/dada-object-avatar/references/examples.json +0 -8
- package/resources/dada-object-avatar/references/prompt-template.md +0 -27
- package/resources/dada-object-avatar/references/style-system.md +0 -54
- package/resources/dada-object-avatar/references/subject-design.md +0 -23
- package/resources/dada-object-avatar/references/training-guide.md +0 -14
- package/resources/dada-object-avatar/references/training-log.jsonl +0 -0
- package/resources/dada-object-avatar/references/training-record.schema.json +0 -20
- package/resources/dada-object-avatar/scripts/choose_gaze.py +0 -36
- package/resources/dada-object-avatar/scripts/record_example.py +0 -22
- package/resources/dada-object-avatar/scripts/validate_png.py +0 -52
- package/resources/dada-object-avatar.manifest.json +0 -85
package/dist/bin/preview.js
CHANGED
|
@@ -9,6 +9,175 @@ function createBuddyPreviewUrl(buddyId) {
|
|
|
9
9
|
return `mlb://preview?${new URLSearchParams({ buddyId })}`;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
// apps/preview/src/runtime-diagnostics.ts
|
|
13
|
+
function parseInspectedData(text2) {
|
|
14
|
+
let at = 0;
|
|
15
|
+
const space = () => {
|
|
16
|
+
while (/\s/u.test(text2[at] ?? "") && at < text2.length) at++;
|
|
17
|
+
};
|
|
18
|
+
const fail = () => {
|
|
19
|
+
throw new Error("Unsupported log data");
|
|
20
|
+
};
|
|
21
|
+
function string() {
|
|
22
|
+
const quote = text2[at++];
|
|
23
|
+
let result = "";
|
|
24
|
+
while (at < text2.length) {
|
|
25
|
+
const char = text2[at++];
|
|
26
|
+
if (char === quote) return result;
|
|
27
|
+
if (char !== "\\") {
|
|
28
|
+
result += char;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const escaped = text2[at++];
|
|
32
|
+
const escapes = { n: "\n", r: "\r", t: " ", b: "\b", f: "\f", v: "\v", "0": "\0", "\\": "\\", "'": "'", '"': '"', "`": "`", "$": "$" };
|
|
33
|
+
if (escaped === "x" || escaped === "u") {
|
|
34
|
+
const length = escaped === "x" ? 2 : 4;
|
|
35
|
+
const hex = text2.slice(at, at + length);
|
|
36
|
+
if (!new RegExp(`^[0-9a-fA-F]{${length}}$`, "u").test(hex)) fail();
|
|
37
|
+
result += String.fromCharCode(parseInt(hex, 16));
|
|
38
|
+
at += length;
|
|
39
|
+
} else if (escaped !== void 0 && Object.hasOwn(escapes, escaped)) result += escapes[escaped];
|
|
40
|
+
else fail();
|
|
41
|
+
}
|
|
42
|
+
return fail();
|
|
43
|
+
}
|
|
44
|
+
function value(depth = 0) {
|
|
45
|
+
if (depth > 40) fail();
|
|
46
|
+
space();
|
|
47
|
+
const char = text2[at];
|
|
48
|
+
if (char === "'" || char === '"' || char === "`") {
|
|
49
|
+
let result = string();
|
|
50
|
+
space();
|
|
51
|
+
while (text2[at] === "+") {
|
|
52
|
+
at++;
|
|
53
|
+
space();
|
|
54
|
+
if (!["'", '"', "`"].includes(text2[at] ?? "")) fail();
|
|
55
|
+
result += string();
|
|
56
|
+
space();
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
if (char === "{" || char === "[") {
|
|
61
|
+
const array = char === "[";
|
|
62
|
+
const end = array ? "]" : "}";
|
|
63
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
64
|
+
const items = [];
|
|
65
|
+
at++;
|
|
66
|
+
space();
|
|
67
|
+
while (text2[at] !== end) {
|
|
68
|
+
if (at >= text2.length) fail();
|
|
69
|
+
if (array) items.push(value(depth + 1));
|
|
70
|
+
else {
|
|
71
|
+
const quoted = ["'", '"', "`"].includes(text2[at] ?? "");
|
|
72
|
+
const key = quoted ? string() : /^[\w$]+/u.exec(text2.slice(at))?.[0];
|
|
73
|
+
if (key === void 0) return fail();
|
|
74
|
+
if (!quoted) at += key.length;
|
|
75
|
+
space();
|
|
76
|
+
if (text2[at++] !== ":" || Object.hasOwn(result, key)) fail();
|
|
77
|
+
result[key] = value(depth + 1);
|
|
78
|
+
}
|
|
79
|
+
space();
|
|
80
|
+
if (text2[at] === end) break;
|
|
81
|
+
if (text2[at++] !== ",") fail();
|
|
82
|
+
space();
|
|
83
|
+
}
|
|
84
|
+
at++;
|
|
85
|
+
return array ? items : result;
|
|
86
|
+
}
|
|
87
|
+
const literal = /^(true|false|null|undefined|[-+]?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(?=[\s,\]}]|$)/iu.exec(text2.slice(at))?.[0];
|
|
88
|
+
if (!literal) return fail();
|
|
89
|
+
at += literal.length;
|
|
90
|
+
if (literal === "true") return true;
|
|
91
|
+
if (literal === "false") return false;
|
|
92
|
+
if (literal === "null" || literal === "undefined") return null;
|
|
93
|
+
const number = Number(literal);
|
|
94
|
+
return Number.isFinite(number) ? number : fail();
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
if (text2.length > 98304) return void 0;
|
|
98
|
+
const result = value();
|
|
99
|
+
space();
|
|
100
|
+
return at === text2.length && result !== null && typeof result === "object" && !Array.isArray(result) ? result : void 0;
|
|
101
|
+
} catch {
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
var HEADER = /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) \[[^\]\r\n]+\] (INFO|WARN|ERROR)\s+(.+)$/u;
|
|
106
|
+
var MAX_RECORD = 98304;
|
|
107
|
+
var MAX_BYTES = 15e5;
|
|
108
|
+
var RuntimeDiagnostics = class {
|
|
109
|
+
#sequence = 0;
|
|
110
|
+
#records = [];
|
|
111
|
+
#active = /* @__PURE__ */ new Map();
|
|
112
|
+
#sizes = /* @__PURE__ */ new Map();
|
|
113
|
+
#bytes = 0;
|
|
114
|
+
#dropped = 0;
|
|
115
|
+
write(source, text2, observedAt) {
|
|
116
|
+
for (const line of text2.split(/\r?\n/u)) {
|
|
117
|
+
if (!line) continue;
|
|
118
|
+
const header = HEADER.exec(line);
|
|
119
|
+
const previousIndex = this.#records.findIndex((record3) => record3.id === this.#active.get(source));
|
|
120
|
+
const previous = this.#records[previousIndex];
|
|
121
|
+
const continuation = !header && previous && (/^\s/u.test(line) || line === "}");
|
|
122
|
+
let record2;
|
|
123
|
+
if (continuation) {
|
|
124
|
+
const raw = `${previous.raw}
|
|
125
|
+
${line}`;
|
|
126
|
+
record2 = { ...previous, raw: raw.slice(0, MAX_RECORD), truncated: previous.truncated || raw.length > MAX_RECORD || line.endsWith(" \u2026[truncated]") };
|
|
127
|
+
} else {
|
|
128
|
+
const title = header ? header[3].replace(/ \{.*$/u, "") : line.slice(0, 180);
|
|
129
|
+
const time = header ? Date.parse(`${header[1].replace(" ", "T")}+08:00`) : NaN;
|
|
130
|
+
record2 = {
|
|
131
|
+
id: `runtime-${++this.#sequence}`,
|
|
132
|
+
timestamp: Number.isFinite(time) ? new Date(time).toISOString() : observedAt,
|
|
133
|
+
source,
|
|
134
|
+
level: header ? header[2].toLowerCase() : source === "agent.stderr" ? "error" : "info",
|
|
135
|
+
title,
|
|
136
|
+
kind: header && title === "\u6A21\u578B\u8BF7\u6C42\u4F53" ? "request" : header && title === "\u6A21\u578B\u54CD\u5E94" ? "response" : "log",
|
|
137
|
+
raw: line.slice(0, MAX_RECORD),
|
|
138
|
+
truncated: line.length > MAX_RECORD || line.endsWith(" \u2026[truncated]")
|
|
139
|
+
};
|
|
140
|
+
this.#active.set(source, record2.id);
|
|
141
|
+
}
|
|
142
|
+
if (!record2.truncated && line.trimEnd().endsWith("}")) {
|
|
143
|
+
const head = HEADER.exec(record2.raw.split("\n")[0]);
|
|
144
|
+
const offset = head ? record2.raw.indexOf(" {", record2.raw.indexOf(head[3])) : -1;
|
|
145
|
+
const data = offset < 0 ? void 0 : parseInspectedData(record2.raw.slice(offset + 1));
|
|
146
|
+
if (data) record2 = { ...record2, data, ...typeof data.convoKey === "string" ? { convoKey: data.convoKey } : {} };
|
|
147
|
+
}
|
|
148
|
+
if (continuation && previous.data) {
|
|
149
|
+
const { data: _data, convoKey: _convoKey, ...rawRecord } = record2;
|
|
150
|
+
record2 = rawRecord;
|
|
151
|
+
}
|
|
152
|
+
this.#bytes -= this.#sizes.get(record2.id) ?? 0;
|
|
153
|
+
const size = Buffer.byteLength(JSON.stringify(record2));
|
|
154
|
+
this.#sizes.set(record2.id, size);
|
|
155
|
+
this.#bytes += size;
|
|
156
|
+
if (continuation) this.#records[previousIndex] = record2;
|
|
157
|
+
else this.#records.push(record2);
|
|
158
|
+
while (this.#records.length > 200 || this.#bytes > MAX_BYTES) {
|
|
159
|
+
const removed = this.#records.shift();
|
|
160
|
+
this.#bytes -= this.#sizes.get(removed.id) ?? 0;
|
|
161
|
+
this.#sizes.delete(removed.id);
|
|
162
|
+
this.#dropped++;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
boundary() {
|
|
167
|
+
this.#active.clear();
|
|
168
|
+
}
|
|
169
|
+
clear() {
|
|
170
|
+
this.#records = [];
|
|
171
|
+
this.#active.clear();
|
|
172
|
+
this.#sizes.clear();
|
|
173
|
+
this.#bytes = 0;
|
|
174
|
+
this.#dropped = 0;
|
|
175
|
+
}
|
|
176
|
+
snapshot() {
|
|
177
|
+
return { records: [...this.#records].reverse(), dropped: this.#dropped };
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
12
181
|
// apps/preview/src/controller.ts
|
|
13
182
|
var TERMINAL_RUN_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
14
183
|
function publicFailure(cause) {
|
|
@@ -31,8 +200,10 @@ var PreviewController = class {
|
|
|
31
200
|
#failedOutputRuns = /* @__PURE__ */ new Set();
|
|
32
201
|
#observedActiveRuns = /* @__PURE__ */ new Set();
|
|
33
202
|
#events = [];
|
|
203
|
+
#diagnostics = new RuntimeDiagnostics();
|
|
34
204
|
#runOrdinal = 0;
|
|
35
205
|
#conversationRevision = 0;
|
|
206
|
+
#simulatorRevision = 0;
|
|
36
207
|
#resetting = false;
|
|
37
208
|
#sendingMessage = false;
|
|
38
209
|
get resetting() {
|
|
@@ -78,24 +249,32 @@ var PreviewController = class {
|
|
|
78
249
|
return () => this.#simulatorListeners.delete(listener);
|
|
79
250
|
}
|
|
80
251
|
simulatorSnapshot() {
|
|
81
|
-
return Object.freeze({ ...this.#simulatorState, conversationRevision: this.#conversationRevision });
|
|
252
|
+
return Object.freeze({ ...this.#simulatorState, conversationRevision: this.#conversationRevision, stateRevision: this.#simulatorRevision });
|
|
82
253
|
}
|
|
83
254
|
start() {
|
|
84
255
|
if (this.#startPromise) return this.#startPromise;
|
|
85
|
-
if (this.#
|
|
256
|
+
if (this.#handle) return Promise.resolve(this.#state);
|
|
86
257
|
if (this.#state.phase === "stopping") {
|
|
87
258
|
return Promise.reject(Object.assign(new Error("DEV \u4F1A\u8BDD\u6B63\u5728\u505C\u6B62"), { code: "DEV_STOPPING" }));
|
|
88
259
|
}
|
|
89
260
|
const controller = new AbortController();
|
|
261
|
+
this.#diagnostics.boundary();
|
|
90
262
|
this.#startController = controller;
|
|
91
263
|
this.#record({ channel: "dev", type: "dev.start_requested", summary: "\u8BF7\u6C42\u542F\u52A8 DEV \u4F1A\u8BDD" });
|
|
92
264
|
this.#setState({ phase: "starting" });
|
|
93
265
|
const startPromise = this.#devStarter.start({
|
|
94
266
|
projectRoot: this.#projectRoot,
|
|
95
267
|
signal: controller.signal,
|
|
268
|
+
onLifecycle: ({ phase, error }) => {
|
|
269
|
+
if (controller.signal.aborted || !this.#handle || this.#state.phase === "stopping") return;
|
|
270
|
+
if (phase === "reloading") this.#stopOutputWatchers();
|
|
271
|
+
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" });
|
|
272
|
+
this.#setState({ phase, ready: this.#state.ready, ...error ? { error } : {} });
|
|
273
|
+
},
|
|
96
274
|
onLog: ({ source, text: text2 }) => {
|
|
97
275
|
if (controller.signal.aborted) return;
|
|
98
|
-
this.#
|
|
276
|
+
this.#diagnostics.write(source, text2, this.#now().toISOString());
|
|
277
|
+
this.#record({ channel: "dev", type: source, summary: text2.slice(0, 512) });
|
|
99
278
|
this.#notifySimulator();
|
|
100
279
|
}
|
|
101
280
|
}).then(({ handle, ready, simulator }) => {
|
|
@@ -192,9 +371,12 @@ var PreviewController = class {
|
|
|
192
371
|
const client = this.#requiredSimulator();
|
|
193
372
|
const revision = this.#conversationRevision;
|
|
194
373
|
let result;
|
|
195
|
-
if (action === "list" && client.widgets) result = { widgets: await client.widgets(), conversationRevision: revision };
|
|
374
|
+
if (action === "list" && client.widgets) result = { widgets: await client.widgets(), conversationRevision: revision, capabilities: { documentLifecycle: true, deleteWidget: Boolean(client.deleteWidget) } };
|
|
196
375
|
else if (action === "html" && client.widgetHtml) result = await client.widgetHtml(id);
|
|
197
|
-
else if (action === "
|
|
376
|
+
else if (action === "delete" && client.deleteWidget) {
|
|
377
|
+
await client.deleteWidget(id);
|
|
378
|
+
result = { ok: true };
|
|
379
|
+
} else if (action === "image" && client.widgetImage) result = await client.widgetImage(id, mediaId);
|
|
198
380
|
else if ((action === "pin" || action === "unpin") && client.pinWidget) {
|
|
199
381
|
await client.pinWidget(id, action === "pin");
|
|
200
382
|
result = { ok: true };
|
|
@@ -218,6 +400,7 @@ var PreviewController = class {
|
|
|
218
400
|
this.#runs.clear();
|
|
219
401
|
this.#observedActiveRuns.clear();
|
|
220
402
|
this.#events.length = 0;
|
|
403
|
+
this.#diagnostics.clear();
|
|
221
404
|
this.#runOrdinal = 0;
|
|
222
405
|
this.#lastActiveRunId = void 0;
|
|
223
406
|
this.#messages = Object.freeze([]);
|
|
@@ -235,7 +418,29 @@ var PreviewController = class {
|
|
|
235
418
|
const started = this.#now();
|
|
236
419
|
this.#record({ channel: "client", type: "message.send", summary: "\u53D1\u9001\u4E00\u6761\u79C1\u804A\u6D88\u606F" });
|
|
237
420
|
const accepted = await this.#requiredSimulator().send(input, { signal });
|
|
238
|
-
if (this.#runs.has(accepted.runId))
|
|
421
|
+
if (this.#runs.has(accepted.runId)) {
|
|
422
|
+
if (this.#simulatorState.activeRun?.runId === accepted.runId && !this.#simulatorState.messages.some((message2) => message2.messageId === accepted.messageId)) {
|
|
423
|
+
this.#record({
|
|
424
|
+
channel: "app_server",
|
|
425
|
+
type: "message.accepted",
|
|
426
|
+
summary: "\u8FFD\u52A0\u6D88\u606F\u5DF2\u63A5\u6536",
|
|
427
|
+
runId: accepted.runId,
|
|
428
|
+
durationMs: Math.max(0, this.#now().getTime() - started.getTime())
|
|
429
|
+
});
|
|
430
|
+
this.#simulatorState = Object.freeze({
|
|
431
|
+
...this.#simulatorState,
|
|
432
|
+
messages: Object.freeze([...this.#simulatorState.messages, Object.freeze({
|
|
433
|
+
messageId: accepted.messageId,
|
|
434
|
+
role: "user",
|
|
435
|
+
text: input.text,
|
|
436
|
+
createdAt: this.#now().toISOString()
|
|
437
|
+
})])
|
|
438
|
+
});
|
|
439
|
+
this.#messages = this.#simulatorState.messages;
|
|
440
|
+
this.#notifySimulator();
|
|
441
|
+
}
|
|
442
|
+
return accepted;
|
|
443
|
+
}
|
|
239
444
|
const acceptedAt = this.#now();
|
|
240
445
|
const latency = Math.max(0, acceptedAt.getTime() - started.getTime());
|
|
241
446
|
this.#upsertRun({
|
|
@@ -314,7 +519,8 @@ var PreviewController = class {
|
|
|
314
519
|
generatedAt: this.#now().toISOString(),
|
|
315
520
|
runs: Object.freeze([...this.#runs.values()].reverse()),
|
|
316
521
|
events: Object.freeze([...this.#events].reverse()),
|
|
317
|
-
messages: Object.freeze([...this.#messages])
|
|
522
|
+
messages: Object.freeze([...this.#messages]),
|
|
523
|
+
diagnostics: this.#diagnostics.snapshot()
|
|
318
524
|
});
|
|
319
525
|
}
|
|
320
526
|
devicePairing() {
|
|
@@ -460,7 +666,7 @@ var PreviewController = class {
|
|
|
460
666
|
void simulator.watchOutput(runId, {
|
|
461
667
|
signal: controller.signal,
|
|
462
668
|
onEvent: (event) => {
|
|
463
|
-
if (this.#resetting || simulator !== this.#simulator) return;
|
|
669
|
+
if (controller.signal.aborted || this.#resetting || simulator !== this.#simulator) return;
|
|
464
670
|
return this.#observeOutputEvent(event);
|
|
465
671
|
}
|
|
466
672
|
}).catch((cause) => {
|
|
@@ -479,6 +685,14 @@ var PreviewController = class {
|
|
|
479
685
|
});
|
|
480
686
|
}
|
|
481
687
|
async #observeOutputEvent(event) {
|
|
688
|
+
if (event.type === "state") {
|
|
689
|
+
if (event.resetStreaming) {
|
|
690
|
+
const { streaming: _streaming, ...state } = this.#simulatorState;
|
|
691
|
+
this.#simulatorState = Object.freeze(state);
|
|
692
|
+
}
|
|
693
|
+
this.#observeSimulatorState(event.state);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
482
696
|
if (event.type === "reset") {
|
|
483
697
|
if (this.#simulatorState.streaming?.runId === event.runId) {
|
|
484
698
|
const { streaming: _streaming, ...state } = this.#simulatorState;
|
|
@@ -560,6 +774,7 @@ var PreviewController = class {
|
|
|
560
774
|
controller.abort(new Error("Agent local turn reached a terminal state"));
|
|
561
775
|
}
|
|
562
776
|
#notifySimulator() {
|
|
777
|
+
this.#simulatorRevision++;
|
|
563
778
|
if (this.#simulatorListeners.size === 0) return;
|
|
564
779
|
const value = Object.freeze({ state: this.simulatorSnapshot(), debug: this.debugSnapshot() });
|
|
565
780
|
for (const listener of this.#simulatorListeners) {
|
|
@@ -640,6 +855,7 @@ var WEB_ASSETS = Object.freeze(/* @__PURE__ */ new Map([
|
|
|
640
855
|
contentType: "text/javascript; charset=utf-8",
|
|
641
856
|
body: readFileSync(new URL("../web/app.js", import.meta.url))
|
|
642
857
|
}],
|
|
858
|
+
["/assets/diagnostics.js", { contentType: "text/javascript; charset=utf-8", body: readFileSync(new URL("../web/diagnostics.js", import.meta.url)) }],
|
|
643
859
|
["/assets/developer-platform-icon.png", {
|
|
644
860
|
contentType: "image/png",
|
|
645
861
|
body: BRAND_ICON
|
|
@@ -715,6 +931,22 @@ function allowedOrigin(request, origin) {
|
|
|
715
931
|
const value = request.headers.origin;
|
|
716
932
|
return value === void 0 || value === origin.origin;
|
|
717
933
|
}
|
|
934
|
+
function validWidgetRender(value) {
|
|
935
|
+
return value !== null && /^[a-zA-Z0-9-]{16,64}$/u.test(value);
|
|
936
|
+
}
|
|
937
|
+
function widgetDocument(response, html, render, state = "ready", status = 200) {
|
|
938
|
+
writeHeaders(response);
|
|
939
|
+
response.statusCode = status;
|
|
940
|
+
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'");
|
|
941
|
+
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
942
|
+
if (validWidgetRender(render)) {
|
|
943
|
+
const signal = `<script>window.addEventListener('load',()=>parent.postMessage({channel:'buddy-widget-document',render:${JSON.stringify(render)},state:${JSON.stringify(state)}},'*'),{once:true})</script>`;
|
|
944
|
+
if (/<head(?:\s[^>]*)?>/iu.test(html)) html = html.replace(/<head(?:\s[^>]*)?>/iu, (match) => match + signal);
|
|
945
|
+
else if (/<!doctype[^>]*>/iu.test(html)) html = html.replace(/<!doctype[^>]*>/iu, (match) => match + signal);
|
|
946
|
+
else html = signal + html;
|
|
947
|
+
}
|
|
948
|
+
response.end(html);
|
|
949
|
+
}
|
|
718
950
|
function apiError(response, status, code, message2) {
|
|
719
951
|
json(response, status, { error: { code, message: message2 } });
|
|
720
952
|
}
|
|
@@ -868,6 +1100,7 @@ data: ${JSON.stringify(value)}
|
|
|
868
1100
|
try {
|
|
869
1101
|
const id = widgetRoute[1] ? decodeURIComponent(widgetRoute[1]) : "";
|
|
870
1102
|
const suffix = widgetRoute[2];
|
|
1103
|
+
if (id && !suffix && request.method === "DELETE") return json(response, 200, await options.controller.simulatorWidgets("delete", id));
|
|
871
1104
|
if (request.method === "GET" && !id) return json(response, 200, await options.controller.simulatorWidgets("list"));
|
|
872
1105
|
if (id && suffix === "pin" && (request.method === "PUT" || request.method === "DELETE")) return json(response, 200, await options.controller.simulatorWidgets(request.method === "PUT" ? "pin" : "unpin", id));
|
|
873
1106
|
if (id && request.method === "GET" && suffix === "image") {
|
|
@@ -880,15 +1113,17 @@ data: ${JSON.stringify(value)}
|
|
|
880
1113
|
}
|
|
881
1114
|
if (id && request.method === "GET" && !suffix) {
|
|
882
1115
|
const html = await options.controller.simulatorWidgets("html", id);
|
|
883
|
-
|
|
884
|
-
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'");
|
|
885
|
-
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
886
|
-
response.end(html);
|
|
1116
|
+
widgetDocument(response, html, url.searchParams.get("render"));
|
|
887
1117
|
return;
|
|
888
1118
|
}
|
|
889
1119
|
return apiError(response, 405, "METHOD_NOT_ALLOWED", "\u4E0D\u652F\u6301\u8FD9\u4E2A\u5C0F\u6302\u4EF6\u64CD\u4F5C");
|
|
890
1120
|
} catch (cause) {
|
|
891
1121
|
const failure = requestFailure(cause);
|
|
1122
|
+
const render = url.searchParams.get("render");
|
|
1123
|
+
if (request.method === "GET" && widgetRoute[1] && !widgetRoute[2] && validWidgetRender(render)) {
|
|
1124
|
+
widgetDocument(response, '<!doctype html><html><head><meta charset="utf-8"></head><body>\u5C0F\u6302\u4EF6\u6682\u65F6\u65E0\u6CD5\u6253\u5F00</body></html>', render, "error", failure.status);
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
892
1127
|
return apiError(response, failure.status, failure.code, failure.message);
|
|
893
1128
|
}
|
|
894
1129
|
}
|
|
@@ -1332,7 +1567,9 @@ function parseWidget(value) {
|
|
|
1332
1567
|
...typeof item?.type === "string" ? { type: item.type } : {},
|
|
1333
1568
|
...typeof item?.summary === "string" ? { summary: item.summary } : {},
|
|
1334
1569
|
...typeof item?.imageMediaId === "string" && /^media_[a-zA-Z0-9_-]+$/u.test(item.imageMediaId) ? { imageMediaId: item.imageMediaId } : {},
|
|
1335
|
-
...typeof item?.isPinned === "boolean" ? { isPinned: item.isPinned } : {}
|
|
1570
|
+
...typeof item?.isPinned === "boolean" ? { isPinned: item.isPinned } : {},
|
|
1571
|
+
...typeof item?.creatorName === "string" ? { creatorName: item.creatorName } : {},
|
|
1572
|
+
...item?.role === "owner" || item?.role === "editor" || item?.role === "viewer" ? { role: item.role } : {}
|
|
1336
1573
|
});
|
|
1337
1574
|
}
|
|
1338
1575
|
function localReceipt(prefix, value) {
|
|
@@ -1413,6 +1650,11 @@ var MlbSimulatorClient = class {
|
|
|
1413
1650
|
const privateId = await this.#ensurePrivate();
|
|
1414
1651
|
await this.#request(pinned ? "PUT" : "DELETE", `/app/widgets/${encodeURIComponent(widgetId(id))}/pin`, { ...pinned ? { body: { sourceConversationId: privateId } } : {} });
|
|
1415
1652
|
}
|
|
1653
|
+
async deleteWidget(id) {
|
|
1654
|
+
this.#assertResetComplete();
|
|
1655
|
+
const privateId = await this.#ensurePrivate();
|
|
1656
|
+
await this.#request("DELETE", `/app/widgets/${encodeURIComponent(widgetId(id))}?conversationId=${encodeURIComponent(privateId)}`, {});
|
|
1657
|
+
}
|
|
1416
1658
|
async widgetImage(id, mediaId) {
|
|
1417
1659
|
this.#assertResetComplete();
|
|
1418
1660
|
if (!/^media_[a-zA-Z0-9_-]+$/u.test(mediaId)) throw new TypeError("Invalid media ID");
|
|
@@ -1463,7 +1705,7 @@ var MlbSimulatorClient = class {
|
|
|
1463
1705
|
this.#active = void 0;
|
|
1464
1706
|
this.#streaming = void 0;
|
|
1465
1707
|
} else if (this.#active.observedReplying) {
|
|
1466
|
-
this.#latest = Object.freeze({ runId: this.#active.runId, status: "
|
|
1708
|
+
this.#latest = Object.freeze({ runId: this.#active.runId, status: "completed" });
|
|
1467
1709
|
this.#active = void 0;
|
|
1468
1710
|
this.#streaming = void 0;
|
|
1469
1711
|
}
|
|
@@ -1490,11 +1732,11 @@ var MlbSimulatorClient = class {
|
|
|
1490
1732
|
if (this.#lastSend.text !== input.text.trim()) throw httpError(409, { error: "\u540C\u4E00\u6761\u6D88\u606F\u4E0D\u80FD\u6539\u5199\u5185\u5BB9" });
|
|
1491
1733
|
return this.#lastSend.receipt;
|
|
1492
1734
|
}
|
|
1493
|
-
if (this.#
|
|
1494
|
-
throw Object.assign(new Error("\
|
|
1495
|
-
code: "
|
|
1735
|
+
if (this.#sending) {
|
|
1736
|
+
throw Object.assign(new Error("\u6D88\u606F\u6B63\u5728\u53D1\u9001"), {
|
|
1737
|
+
code: "SEND_IN_PROGRESS",
|
|
1496
1738
|
status: 409,
|
|
1497
|
-
publicMessage: "\
|
|
1739
|
+
publicMessage: "\u6D88\u606F\u6B63\u5728\u53D1\u9001\uFF0C\u8BF7\u7A0D\u5019"
|
|
1498
1740
|
});
|
|
1499
1741
|
}
|
|
1500
1742
|
this.#sending = true;
|
|
@@ -1528,15 +1770,17 @@ var MlbSimulatorClient = class {
|
|
|
1528
1770
|
}
|
|
1529
1771
|
const receipt = object(value);
|
|
1530
1772
|
const item = object(receipt.items[0]);
|
|
1531
|
-
const runId = localReceipt("turn", idempotencyKey);
|
|
1773
|
+
const runId = this.#active?.runId ?? localReceipt("turn", idempotencyKey);
|
|
1532
1774
|
const messageId = safeText(item.messageId, "receipt.items[0].messageId", 256);
|
|
1533
|
-
this.#active
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1775
|
+
if (!this.#active) {
|
|
1776
|
+
this.#active = receipt.shouldReply ? Object.freeze({
|
|
1777
|
+
runId,
|
|
1778
|
+
messageTimestamp: item.timestamp,
|
|
1779
|
+
observedReplying: false
|
|
1780
|
+
}) : void 0;
|
|
1781
|
+
this.#latest = Object.freeze({ runId, status: receipt.shouldReply ? "pending" : "completed" });
|
|
1782
|
+
this.#streaming = void 0;
|
|
1783
|
+
}
|
|
1540
1784
|
const accepted = Object.freeze({ messageId, runId });
|
|
1541
1785
|
this.#lastSend = { key: idempotencyKey, text: input.text.trim(), receipt: accepted };
|
|
1542
1786
|
return accepted;
|
|
@@ -1604,6 +1848,7 @@ var MlbSimulatorClient = class {
|
|
|
1604
1848
|
const url = endpoint(this.#baseUrl, "/app/ws");
|
|
1605
1849
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
1606
1850
|
let sequence = 0;
|
|
1851
|
+
let assistantIds = new Set(this.#messages.filter((message2) => message2.role === "assistant").map((message2) => message2.messageId));
|
|
1607
1852
|
const reset = async () => {
|
|
1608
1853
|
sequence = 0;
|
|
1609
1854
|
this.#streaming = void 0;
|
|
@@ -1629,11 +1874,21 @@ var MlbSimulatorClient = class {
|
|
|
1629
1874
|
continue;
|
|
1630
1875
|
}
|
|
1631
1876
|
if (frame.event !== "chat" && frame.event !== "ready") continue;
|
|
1632
|
-
|
|
1877
|
+
let state = await this.state({ signal: options.signal });
|
|
1878
|
+
const nextAssistantIds = new Set(state.messages.filter((message2) => message2.role === "assistant").map((message2) => message2.messageId));
|
|
1879
|
+
const committedReply = [...nextAssistantIds].some((id) => !assistantIds.has(id));
|
|
1880
|
+
assistantIds = nextAssistantIds;
|
|
1881
|
+
if (committedReply && state.activeRun) {
|
|
1882
|
+
sequence = 0;
|
|
1883
|
+
this.#streaming = void 0;
|
|
1884
|
+
const { streaming: _streaming, ...snapshot } = state;
|
|
1885
|
+
state = snapshot;
|
|
1886
|
+
}
|
|
1633
1887
|
if (state.latestRun?.runId === safeRunId && (state.latestRun.status === "completed" || state.latestRun.status === "failed")) {
|
|
1634
1888
|
await options.onEvent({ type: state.latestRun.status, runId: safeRunId, status: state.latestRun.status });
|
|
1635
1889
|
return;
|
|
1636
1890
|
}
|
|
1891
|
+
await options.onEvent({ type: "state", runId: safeRunId, state, resetStreaming: committedReply });
|
|
1637
1892
|
}
|
|
1638
1893
|
if (options.signal?.aborted) return;
|
|
1639
1894
|
} catch (cause) {
|
|
@@ -1728,6 +1983,42 @@ async function connectPreviewBridge(options) {
|
|
|
1728
1983
|
const initial = await attach();
|
|
1729
1984
|
if (initial.reused) return { reused: true, completion: Promise.resolve(), async close() {
|
|
1730
1985
|
} };
|
|
1986
|
+
const pendingEvents = /* @__PURE__ */ new Map();
|
|
1987
|
+
let eventSequence = 0;
|
|
1988
|
+
let publishing;
|
|
1989
|
+
let retryEvents;
|
|
1990
|
+
const flushEvents = () => {
|
|
1991
|
+
if (!initial.liveEvents || signal.aborted || publishing || retryEvents || !pendingEvents.size) return;
|
|
1992
|
+
publishing = (async () => {
|
|
1993
|
+
while (!signal.aborted && pendingEvents.size) {
|
|
1994
|
+
const events = [...pendingEvents.values()].sort((a, b) => a.sequence - b.sequence);
|
|
1995
|
+
try {
|
|
1996
|
+
await call("api/preview/events", connectionId, { events });
|
|
1997
|
+
for (const event of events) if (pendingEvents.get(event.type) === event) pendingEvents.delete(event.type);
|
|
1998
|
+
} catch {
|
|
1999
|
+
if (!signal.aborted) retryEvents = setTimeout(() => {
|
|
2000
|
+
retryEvents = void 0;
|
|
2001
|
+
flushEvents();
|
|
2002
|
+
}, 500);
|
|
2003
|
+
break;
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
})().finally(() => {
|
|
2007
|
+
publishing = void 0;
|
|
2008
|
+
});
|
|
2009
|
+
};
|
|
2010
|
+
const queueEvent = (type, value) => {
|
|
2011
|
+
if (!initial.liveEvents || signal.aborted) return;
|
|
2012
|
+
pendingEvents.set(type, { sequence: eventSequence++, type, value });
|
|
2013
|
+
flushEvents();
|
|
2014
|
+
};
|
|
2015
|
+
const snapshotEvents = () => {
|
|
2016
|
+
queueEvent("dev.state", options.controller.state());
|
|
2017
|
+
queueEvent("simulator.state", { state: options.controller.simulatorSnapshot() });
|
|
2018
|
+
};
|
|
2019
|
+
const unsubscribeDev = options.controller.subscribe((state) => queueEvent("dev.state", state));
|
|
2020
|
+
const unsubscribeSimulator = options.controller.subscribeSimulator(({ state }) => queueEvent("simulator.state", { state }));
|
|
2021
|
+
snapshotEvents();
|
|
1731
2022
|
const watchdog = setInterval(() => {
|
|
1732
2023
|
if (Date.now() - lastContact < 1e4 || stopping || interrupted) return;
|
|
1733
2024
|
interrupted = true;
|
|
@@ -1801,12 +2092,18 @@ async function connectPreviewBridge(options) {
|
|
|
1801
2092
|
if (status === 410) {
|
|
1802
2093
|
await options.controller.stop();
|
|
1803
2094
|
if ((await attach()).reused) throw new Error("\u5F53\u524D\u5DE5\u7A0B\u5DF2\u6709\u5176\u4ED6 CLI \u8FDE\u63A5\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C preview \u6253\u5F00\u540E\u53F0");
|
|
2095
|
+
snapshotEvents();
|
|
1804
2096
|
} else if (status && status >= 400 && status < 500 && status !== 429) throw cause;
|
|
1805
2097
|
}
|
|
1806
2098
|
await delay(replies.size ? 20 : 500, void 0, { signal }).catch(() => void 0);
|
|
1807
2099
|
}
|
|
1808
2100
|
} finally {
|
|
1809
2101
|
clearInterval(watchdog);
|
|
2102
|
+
unsubscribeDev();
|
|
2103
|
+
unsubscribeSimulator();
|
|
2104
|
+
if (retryEvents) clearTimeout(retryEvents);
|
|
2105
|
+
shutdown.abort();
|
|
2106
|
+
await publishing;
|
|
1810
2107
|
}
|
|
1811
2108
|
})();
|
|
1812
2109
|
void completion.catch(() => void 0);
|