@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.
Files changed (193) hide show
  1. package/README.md +74 -22
  2. package/dist/bin/buddy.js +29 -10
  3. package/dist/bin/buddy.js.map +2 -2
  4. package/dist/bin/core.js +1480 -611
  5. package/dist/bin/core.js.map +4 -4
  6. package/dist/bin/preview.js +324 -27
  7. package/dist/bin/preview.js.map +4 -4
  8. package/dist/web/app.css +65 -6
  9. package/dist/web/app.js +103 -39
  10. package/dist/web/diagnostics.js +184 -0
  11. package/dist/web/index.html +34 -34
  12. package/dist/web/widgets.css +59 -28
  13. package/dist/web/widgets.js +230 -76
  14. package/package.json +3 -3
  15. package/resources/README.md +6 -50
  16. package/resources/agent-template/package-lock.json +4 -4
  17. package/resources/agent-template/package.json +2 -2
  18. package/resources/buddy-creator/INSTALL.md +0 -25
  19. package/resources/buddy-creator/PATCHES.md +0 -53
  20. package/resources/buddy-creator/SKILL.md +0 -76
  21. package/resources/buddy-creator/THIRD_PARTY_NOTICES.md +0 -154
  22. package/resources/buddy-creator/agents/openai.yaml +0 -4
  23. package/resources/buddy-creator/assets/licenses/bail.txt +0 -26
  24. package/resources/buddy-creator/assets/licenses/ccount.txt +0 -26
  25. package/resources/buddy-creator/assets/licenses/character-entities-html4.txt +0 -26
  26. package/resources/buddy-creator/assets/licenses/character-entities-legacy.txt +0 -26
  27. package/resources/buddy-creator/assets/licenses/character-entities.txt +0 -26
  28. package/resources/buddy-creator/assets/licenses/character-reference-invalid.txt +0 -26
  29. package/resources/buddy-creator/assets/licenses/comma-separated-tokens.txt +0 -26
  30. package/resources/buddy-creator/assets/licenses/debug.txt +0 -24
  31. package/resources/buddy-creator/assets/licenses/decode-named-character-reference.txt +0 -26
  32. package/resources/buddy-creator/assets/licenses/dequal.txt +0 -25
  33. package/resources/buddy-creator/assets/licenses/devlop.txt +0 -26
  34. package/resources/buddy-creator/assets/licenses/escape-string-regexp.txt +0 -13
  35. package/resources/buddy-creator/assets/licenses/estree-util-is-identifier-name.txt +0 -26
  36. package/resources/buddy-creator/assets/licenses/extend.txt +0 -27
  37. package/resources/buddy-creator/assets/licenses/hast-util-to-jsx-runtime.txt +0 -26
  38. package/resources/buddy-creator/assets/licenses/hast-util-whitespace.txt +0 -26
  39. package/resources/buddy-creator/assets/licenses/html-url-attributes.txt +0 -25
  40. package/resources/buddy-creator/assets/licenses/inline-style-parser.txt +0 -13
  41. package/resources/buddy-creator/assets/licenses/is-alphabetical.txt +0 -26
  42. package/resources/buddy-creator/assets/licenses/is-alphanumerical.txt +0 -26
  43. package/resources/buddy-creator/assets/licenses/is-decimal.txt +0 -26
  44. package/resources/buddy-creator/assets/licenses/is-hexadecimal.txt +0 -26
  45. package/resources/buddy-creator/assets/licenses/is-plain-obj.txt +0 -13
  46. package/resources/buddy-creator/assets/licenses/longest-streak.txt +0 -26
  47. package/resources/buddy-creator/assets/licenses/markdown-table.txt +0 -26
  48. package/resources/buddy-creator/assets/licenses/mdast-util-find-and-replace.txt +0 -26
  49. package/resources/buddy-creator/assets/licenses/mdast-util-from-markdown.txt +0 -26
  50. package/resources/buddy-creator/assets/licenses/mdast-util-gfm-autolink-literal.txt +0 -26
  51. package/resources/buddy-creator/assets/licenses/mdast-util-gfm-footnote.txt +0 -26
  52. package/resources/buddy-creator/assets/licenses/mdast-util-gfm-strikethrough.txt +0 -26
  53. package/resources/buddy-creator/assets/licenses/mdast-util-gfm-table.txt +0 -26
  54. package/resources/buddy-creator/assets/licenses/mdast-util-gfm-task-list-item.txt +0 -26
  55. package/resources/buddy-creator/assets/licenses/mdast-util-gfm.txt +0 -26
  56. package/resources/buddy-creator/assets/licenses/mdast-util-mdx-expression.txt +0 -26
  57. package/resources/buddy-creator/assets/licenses/mdast-util-mdx-jsx.txt +0 -26
  58. package/resources/buddy-creator/assets/licenses/mdast-util-mdxjs-esm.txt +0 -26
  59. package/resources/buddy-creator/assets/licenses/mdast-util-phrasing.txt +0 -27
  60. package/resources/buddy-creator/assets/licenses/mdast-util-to-hast.txt +0 -26
  61. package/resources/buddy-creator/assets/licenses/mdast-util-to-markdown.txt +0 -26
  62. package/resources/buddy-creator/assets/licenses/mdast-util-to-string.txt +0 -26
  63. package/resources/buddy-creator/assets/licenses/micromark-core-commonmark.txt +0 -26
  64. package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-autolink-literal.txt +0 -26
  65. package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-footnote.txt +0 -26
  66. package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-strikethrough.txt +0 -26
  67. package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-table.txt +0 -26
  68. package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-tagfilter.txt +0 -26
  69. package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-task-list-item.txt +0 -26
  70. package/resources/buddy-creator/assets/licenses/micromark-extension-gfm.txt +0 -26
  71. package/resources/buddy-creator/assets/licenses/micromark-factory-destination.txt +0 -26
  72. package/resources/buddy-creator/assets/licenses/micromark-factory-label.txt +0 -26
  73. package/resources/buddy-creator/assets/licenses/micromark-factory-space.txt +0 -26
  74. package/resources/buddy-creator/assets/licenses/micromark-factory-title.txt +0 -26
  75. package/resources/buddy-creator/assets/licenses/micromark-factory-whitespace.txt +0 -26
  76. package/resources/buddy-creator/assets/licenses/micromark-util-character.txt +0 -26
  77. package/resources/buddy-creator/assets/licenses/micromark-util-chunked.txt +0 -26
  78. package/resources/buddy-creator/assets/licenses/micromark-util-classify-character.txt +0 -26
  79. package/resources/buddy-creator/assets/licenses/micromark-util-combine-extensions.txt +0 -26
  80. package/resources/buddy-creator/assets/licenses/micromark-util-decode-numeric-character-reference.txt +0 -26
  81. package/resources/buddy-creator/assets/licenses/micromark-util-decode-string.txt +0 -26
  82. package/resources/buddy-creator/assets/licenses/micromark-util-encode.txt +0 -26
  83. package/resources/buddy-creator/assets/licenses/micromark-util-html-tag-name.txt +0 -26
  84. package/resources/buddy-creator/assets/licenses/micromark-util-normalize-identifier.txt +0 -26
  85. package/resources/buddy-creator/assets/licenses/micromark-util-resolve-all.txt +0 -26
  86. package/resources/buddy-creator/assets/licenses/micromark-util-sanitize-uri.txt +0 -26
  87. package/resources/buddy-creator/assets/licenses/micromark-util-subtokenize.txt +0 -26
  88. package/resources/buddy-creator/assets/licenses/micromark-util-symbol.txt +0 -26
  89. package/resources/buddy-creator/assets/licenses/micromark-util-types.txt +0 -26
  90. package/resources/buddy-creator/assets/licenses/micromark.txt +0 -26
  91. package/resources/buddy-creator/assets/licenses/ms.txt +0 -25
  92. package/resources/buddy-creator/assets/licenses/parse-entities.txt +0 -26
  93. package/resources/buddy-creator/assets/licenses/phosphor-icons--react.txt +0 -25
  94. package/resources/buddy-creator/assets/licenses/property-information.txt +0 -26
  95. package/resources/buddy-creator/assets/licenses/react-dom.txt +0 -25
  96. package/resources/buddy-creator/assets/licenses/react-markdown.txt +0 -25
  97. package/resources/buddy-creator/assets/licenses/react.txt +0 -25
  98. package/resources/buddy-creator/assets/licenses/remark-gfm.txt +0 -26
  99. package/resources/buddy-creator/assets/licenses/remark-parse.txt +0 -25
  100. package/resources/buddy-creator/assets/licenses/remark-rehype.txt +0 -26
  101. package/resources/buddy-creator/assets/licenses/remark-stringify.txt +0 -25
  102. package/resources/buddy-creator/assets/licenses/scheduler.txt +0 -25
  103. package/resources/buddy-creator/assets/licenses/space-separated-tokens.txt +0 -26
  104. package/resources/buddy-creator/assets/licenses/stringify-entities.txt +0 -26
  105. package/resources/buddy-creator/assets/licenses/style-to-js.txt +0 -26
  106. package/resources/buddy-creator/assets/licenses/style-to-object.txt +0 -26
  107. package/resources/buddy-creator/assets/licenses/trim-lines.txt +0 -26
  108. package/resources/buddy-creator/assets/licenses/trough.txt +0 -25
  109. package/resources/buddy-creator/assets/licenses/types--debug.txt +0 -25
  110. package/resources/buddy-creator/assets/licenses/types--estree-jsx.txt +0 -25
  111. package/resources/buddy-creator/assets/licenses/types--estree.txt +0 -25
  112. package/resources/buddy-creator/assets/licenses/types--hast.txt +0 -25
  113. package/resources/buddy-creator/assets/licenses/types--mdast.txt +0 -25
  114. package/resources/buddy-creator/assets/licenses/types--ms.txt +0 -25
  115. package/resources/buddy-creator/assets/licenses/types--unist.txt +0 -25
  116. package/resources/buddy-creator/assets/licenses/ungap--structured-clone.txt +0 -19
  117. package/resources/buddy-creator/assets/licenses/unified.txt +0 -25
  118. package/resources/buddy-creator/assets/licenses/unist-util-is.txt +0 -26
  119. package/resources/buddy-creator/assets/licenses/unist-util-position.txt +0 -26
  120. package/resources/buddy-creator/assets/licenses/unist-util-stringify-position.txt +0 -26
  121. package/resources/buddy-creator/assets/licenses/unist-util-visit-parents.txt +0 -26
  122. package/resources/buddy-creator/assets/licenses/unist-util-visit.txt +0 -26
  123. package/resources/buddy-creator/assets/licenses/vfile-message.txt +0 -26
  124. package/resources/buddy-creator/assets/licenses/vfile.txt +0 -25
  125. package/resources/buddy-creator/assets/licenses/zwitch.txt +0 -26
  126. package/resources/buddy-creator/assets/preview/assets/index-B5VmkoSx.js +0 -39
  127. package/resources/buddy-creator/assets/preview/assets/index-DWKP6b-3.css +0 -4
  128. package/resources/buddy-creator/assets/preview/brand-logo.png +0 -0
  129. package/resources/buddy-creator/assets/preview/brand.css +0 -100
  130. package/resources/buddy-creator/assets/preview/index.html +0 -7
  131. package/resources/buddy-creator/assets/preview/reader.css +0 -165
  132. package/resources/buddy-creator/assets/preview/reader.js +0 -135
  133. package/resources/buddy-creator/assets/preview/widgets.css +0 -1
  134. package/resources/buddy-creator/assets/preview/widgets.js +0 -168
  135. package/resources/buddy-creator/assets/widget-reference/conversation.png +0 -0
  136. package/resources/buddy-creator/assets/widget-reference/expanded.png +0 -0
  137. package/resources/buddy-creator/assets/widget-v2/app.js +0 -62
  138. package/resources/buddy-creator/assets/widget-v2/style.css +0 -1
  139. package/resources/buddy-creator/assets/widget-v3/app.js +0 -65
  140. package/resources/buddy-creator/assets/widget-v3/style.css +0 -103
  141. package/resources/buddy-creator/assets/widget-v4/app.js +0 -66
  142. package/resources/buddy-creator/assets/widget-v4/style.css +0 -187
  143. package/resources/buddy-creator/references/artifact-schema.md +0 -70
  144. package/resources/buddy-creator/references/catalog.json +0 -401
  145. package/resources/buddy-creator/references/definition.md +0 -24
  146. package/resources/buddy-creator/references/dialogue-examples.md +0 -133
  147. package/resources/buddy-creator/references/host-guide.md +0 -219
  148. package/resources/buddy-creator/references/interview.md +0 -235
  149. package/resources/buddy-creator/references/knowledge.md +0 -40
  150. package/resources/buddy-creator/references/methods.md +0 -77
  151. package/resources/buddy-creator/references/opening.md +0 -14
  152. package/resources/buddy-creator/references/preview-panel.md +0 -66
  153. package/resources/buddy-creator/references/recovery.md +0 -46
  154. package/resources/buddy-creator/references/service.md +0 -76
  155. package/resources/buddy-creator/references/widgets-protocol.md +0 -83
  156. package/resources/buddy-creator/references/widgets.md +0 -99
  157. package/resources/buddy-creator/scripts/buddy.py +0 -108
  158. package/resources/buddy-creator/scripts/buddy_client.py +0 -67
  159. package/resources/buddy-creator/scripts/buddy_core.py +0 -865
  160. package/resources/buddy-creator/scripts/completion.py +0 -296
  161. package/resources/buddy-creator/scripts/interview.py +0 -215
  162. package/resources/buddy-creator/scripts/preview.py +0 -617
  163. package/resources/buddy-creator/scripts/preview_panel.py +0 -80
  164. package/resources/buddy-creator/scripts/sources.py +0 -239
  165. package/resources/buddy-creator/scripts/widget_render.py +0 -66
  166. package/resources/buddy-creator/scripts/widget_render_v1.py +0 -176
  167. package/resources/buddy-creator/scripts/widget_render_v2.py +0 -98
  168. package/resources/buddy-creator/scripts/widget_render_v3.py +0 -86
  169. package/resources/buddy-creator/scripts/widget_render_v4.py +0 -121
  170. package/resources/buddy-creator/scripts/widgets.py +0 -227
  171. package/resources/buddy-creator/version.json +0 -8
  172. package/resources/buddy-creator.manifest.json +0 -791
  173. package/resources/dada-object-avatar/SKILL.md +0 -37
  174. package/resources/dada-object-avatar/agents/openai.yaml +0 -4
  175. package/resources/dada-object-avatar/assets/examples/cat.png +0 -0
  176. package/resources/dada-object-avatar/assets/examples/cooking.png +0 -0
  177. package/resources/dada-object-avatar/assets/examples/divination.png +0 -0
  178. package/resources/dada-object-avatar/assets/examples/doctor.png +0 -0
  179. package/resources/dada-object-avatar/assets/examples/relationship.png +0 -0
  180. package/resources/dada-object-avatar/assets/examples/work.png +0 -0
  181. package/resources/dada-object-avatar/assets/preview.png +0 -0
  182. package/resources/dada-object-avatar/references/evaluation-rubric.md +0 -22
  183. package/resources/dada-object-avatar/references/examples.json +0 -8
  184. package/resources/dada-object-avatar/references/prompt-template.md +0 -27
  185. package/resources/dada-object-avatar/references/style-system.md +0 -54
  186. package/resources/dada-object-avatar/references/subject-design.md +0 -23
  187. package/resources/dada-object-avatar/references/training-guide.md +0 -14
  188. package/resources/dada-object-avatar/references/training-log.jsonl +0 -0
  189. package/resources/dada-object-avatar/references/training-record.schema.json +0 -20
  190. package/resources/dada-object-avatar/scripts/choose_gaze.py +0 -36
  191. package/resources/dada-object-avatar/scripts/record_example.py +0 -22
  192. package/resources/dada-object-avatar/scripts/validate_png.py +0 -52
  193. package/resources/dada-object-avatar.manifest.json +0 -85
@@ -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.#state.phase === "ready") return Promise.resolve(this.#state);
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.#record({ channel: "dev", type: source, summary: text2.slice(0, 8224) });
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 === "image" && client.widgetImage) result = await client.widgetImage(id, mediaId);
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)) return accepted;
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
- writeHeaders(response);
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: "failed" });
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.#active || this.#sending) {
1494
- throw Object.assign(new Error("\u4E0A\u4E00\u8F6E\u56DE\u590D\u5C1A\u672A\u7ED3\u675F"), {
1495
- code: "TURN_IN_PROGRESS",
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: "\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u5B8C\u6210\u540E\u518D\u53D1\u9001"
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 = receipt.shouldReply ? Object.freeze({
1534
- runId,
1535
- messageTimestamp: item.timestamp,
1536
- observedReplying: false
1537
- }) : void 0;
1538
- this.#latest = Object.freeze({ runId, status: receipt.shouldReply ? "pending" : "completed" });
1539
- this.#streaming = void 0;
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
- const state = await this.state({ signal: options.signal });
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);