@mulmoclaude/mulmoscript-plugin 4.1.0 → 4.3.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/dist/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as pluginCore, d as errorMessage, f as TOOL_DEFINITION, p as TOOL_NAME } from "./plugin-CXhOP_xU.js";
1
+ import { a as pluginCore, d as errorMessage, f as TOOL_DEFINITION, p as TOOL_NAME } from "./plugin-CAhxJ5WM.js";
2
2
  import { n as SCRIPT_CHANGED_EVENT, r as shouldReloadForScriptChange, t as GENERATION_EVENT } from "./contract-CIt1ZAtt.js";
3
3
  import { mulmoBeatSchema, mulmoScriptSchema } from "@mulmocast/types";
4
4
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineAsyncComponent, defineComponent, inject, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, reactive, ref, renderList, toDisplayString, unref, vModelText, vShow, watch, withDirectives, withModifiers } from "vue";
@@ -200,6 +200,22 @@ function clearReactiveRecords(...records) {
200
200
  Object.keys(record).forEach((key) => Reflect.deleteProperty(record, key));
201
201
  });
202
202
  }
203
+ /**
204
+ * Whether a `focusout` means focus actually LEFT `container`, rather than moving between two
205
+ * fields inside it.
206
+ *
207
+ * The distinction decides whether pending edits are written: treating every focusout as a
208
+ * departure would write on each hop between inputs, and treating none as one would let the user
209
+ * walk away with the last keystroke unsaved.
210
+ *
211
+ * `null` is focus going nowhere the document can name — clicking the page chrome, or the window
212
+ * losing focus. That counts as leaving: the editor is no longer where the typing goes.
213
+ */
214
+ function focusLeftContainer(container, movedTo) {
215
+ if (!container) return false;
216
+ if (!(movedTo instanceof Node)) return true;
217
+ return !container.contains(movedTo);
218
+ }
203
219
  //#endregion
204
220
  //#region src/vue/transport.ts
205
221
  var GENERATION_EVENT_KINDS = /* @__PURE__ */ new Set([
@@ -1305,118 +1321,113 @@ var _hoisted_10 = { class: "flex-1 min-w-0" };
1305
1321
  var _hoisted_11 = { class: "font-medium" };
1306
1322
  var _hoisted_12 = { class: "break-words whitespace-pre-wrap mt-0.5" };
1307
1323
  var _hoisted_13 = ["disabled"];
1308
- var _hoisted_14 = {
1309
- key: 2,
1310
- class: "flex-1 overflow-hidden",
1311
- "data-testid": "mulmo-script-deck-editor"
1312
- };
1313
- var _hoisted_15 = { class: "flex gap-3 items-stretch" };
1314
- var _hoisted_16 = [
1324
+ var _hoisted_14 = { class: "flex gap-3 items-stretch" };
1325
+ var _hoisted_15 = [
1315
1326
  "onDragover",
1316
1327
  "onDragleave",
1317
1328
  "onDrop"
1318
1329
  ];
1319
- var _hoisted_17 = ["data-testid"];
1320
- var _hoisted_18 = ["src", "data-testid"];
1321
- var _hoisted_19 = [
1330
+ var _hoisted_16 = ["data-testid"];
1331
+ var _hoisted_17 = ["src", "data-testid"];
1332
+ var _hoisted_18 = [
1322
1333
  "title",
1323
1334
  "aria-label",
1324
1335
  "data-testid",
1325
1336
  "onClick"
1326
1337
  ];
1327
- var _hoisted_20 = [
1338
+ var _hoisted_19 = [
1328
1339
  "src",
1329
1340
  "alt",
1330
1341
  "onClick"
1331
1342
  ];
1332
- var _hoisted_21 = [
1343
+ var _hoisted_20 = [
1333
1344
  "title",
1334
1345
  "aria-label",
1335
1346
  "data-testid",
1336
1347
  "onClick"
1337
1348
  ];
1338
- var _hoisted_22 = {
1349
+ var _hoisted_21 = {
1339
1350
  key: 0,
1340
1351
  class: "animate-spin w-5 h-5",
1341
1352
  viewBox: "0 0 24 24",
1342
1353
  fill: "none"
1343
1354
  };
1344
- var _hoisted_23 = {
1355
+ var _hoisted_22 = {
1345
1356
  key: 1,
1346
1357
  class: "material-icons text-3xl"
1347
1358
  };
1348
- var _hoisted_24 = ["disabled", "onClick"];
1349
- var _hoisted_25 = {
1359
+ var _hoisted_23 = ["disabled", "onClick"];
1360
+ var _hoisted_24 = {
1350
1361
  key: 3,
1351
1362
  class: "w-full aspect-video flex flex-col items-center justify-center gap-1 p-2"
1352
1363
  };
1353
- var _hoisted_26 = { class: "text-xs text-green-500" };
1354
- var _hoisted_27 = {
1364
+ var _hoisted_25 = { class: "text-xs text-green-500" };
1365
+ var _hoisted_26 = {
1355
1366
  key: 1,
1356
1367
  class: "text-xs text-red-400 text-center"
1357
1368
  };
1358
- var _hoisted_28 = {
1369
+ var _hoisted_27 = {
1359
1370
  key: 0,
1360
1371
  class: "text-xs text-gray-400 text-center italic leading-relaxed px-1"
1361
1372
  };
1362
- var _hoisted_29 = {
1373
+ var _hoisted_28 = {
1363
1374
  key: 1,
1364
1375
  class: "text-xs text-gray-300"
1365
1376
  };
1366
- var _hoisted_30 = {
1377
+ var _hoisted_29 = {
1367
1378
  key: 2,
1368
1379
  class: "absolute inset-0 flex items-center justify-center bg-blue-50/80 pointer-events-none"
1369
1380
  };
1370
- var _hoisted_31 = { class: "text-xs text-blue-500 font-medium" };
1371
- var _hoisted_32 = {
1381
+ var _hoisted_30 = { class: "text-xs text-blue-500 font-medium" };
1382
+ var _hoisted_31 = {
1372
1383
  key: 3,
1373
1384
  class: "absolute bottom-0 inset-x-0 text-center text-xs text-gray-400 bg-white/70 py-0.5 pointer-events-none"
1374
1385
  };
1375
- var _hoisted_33 = ["onClick"];
1376
- var _hoisted_34 = { class: "flex flex-col flex-1 min-w-0 px-2 py-1.5" };
1377
- var _hoisted_35 = { class: "text-sm text-gray-800 leading-relaxed" };
1378
- var _hoisted_36 = { class: "flex justify-between mt-auto pt-1" };
1379
- var _hoisted_37 = { class: "flex items-center gap-1" };
1380
- var _hoisted_38 = {
1386
+ var _hoisted_32 = ["onClick"];
1387
+ var _hoisted_33 = { class: "flex flex-col flex-1 min-w-0 px-2 py-1.5" };
1388
+ var _hoisted_34 = { class: "text-sm text-gray-800 leading-relaxed" };
1389
+ var _hoisted_35 = { class: "flex justify-between mt-auto pt-1" };
1390
+ var _hoisted_36 = { class: "flex items-center gap-1" };
1391
+ var _hoisted_37 = {
1381
1392
  key: 0,
1382
1393
  class: "animate-spin w-3 h-3 text-green-400",
1383
1394
  viewBox: "0 0 24 24",
1384
1395
  fill: "none"
1385
1396
  };
1386
- var _hoisted_39 = ["onClick"];
1387
- var _hoisted_40 = ["title"];
1388
- var _hoisted_41 = ["disabled", "onClick"];
1389
- var _hoisted_42 = ["onClick"];
1390
- var _hoisted_43 = [
1397
+ var _hoisted_38 = ["onClick"];
1398
+ var _hoisted_39 = ["title"];
1399
+ var _hoisted_40 = ["disabled", "onClick"];
1400
+ var _hoisted_41 = ["onClick"];
1401
+ var _hoisted_42 = [
1391
1402
  "title",
1392
1403
  "data-testid",
1393
1404
  "onClick"
1394
1405
  ];
1395
- var _hoisted_44 = {
1406
+ var _hoisted_43 = {
1396
1407
  key: 0,
1397
1408
  class: "border-t border-gray-100"
1398
1409
  };
1399
- var _hoisted_45 = ["onUpdate:modelValue", "data-testid"];
1400
- var _hoisted_46 = { class: "flex items-center justify-end gap-2 px-2 pb-2" };
1401
- var _hoisted_47 = {
1410
+ var _hoisted_44 = ["onUpdate:modelValue", "data-testid"];
1411
+ var _hoisted_45 = { class: "flex items-center justify-end gap-2 px-2 pb-2" };
1412
+ var _hoisted_46 = {
1402
1413
  key: 0,
1403
1414
  class: "text-xs text-red-600",
1404
1415
  role: "alert"
1405
1416
  };
1406
- var _hoisted_48 = [
1417
+ var _hoisted_47 = [
1407
1418
  "disabled",
1408
1419
  "data-testid",
1409
1420
  "onClick"
1410
1421
  ];
1411
- var _hoisted_49 = {
1422
+ var _hoisted_48 = {
1412
1423
  key: 0,
1413
1424
  class: "flex items-center justify-center h-32 text-gray-400 text-sm"
1414
1425
  };
1415
- var _hoisted_50 = { class: "bottom-bar-wrapper" };
1416
- var _hoisted_51 = { class: "editor-actions" };
1417
- var _hoisted_52 = ["disabled"];
1418
- var _hoisted_53 = ["title"];
1419
- var _hoisted_54 = { class: "material-icons" };
1426
+ var _hoisted_49 = { class: "bottom-bar-wrapper" };
1427
+ var _hoisted_50 = { class: "editor-actions" };
1428
+ var _hoisted_51 = ["disabled"];
1429
+ var _hoisted_52 = ["title"];
1430
+ var _hoisted_53 = { class: "material-icons" };
1420
1431
  var SILENT_BEAT_DEFAULT_SEC = 3;
1421
1432
  var MS_PER_SECOND = 1e3;
1422
1433
  var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -1598,6 +1609,18 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
1598
1609
  function onDeckBeatsUpdate(beats) {
1599
1610
  onDeckUpdate(withBeats(deckScriptInput.value, beats));
1600
1611
  }
1612
+ /**
1613
+ * Leaving the editor writes whatever is still in the debounce.
1614
+ *
1615
+ * Asking the agent to change the script means moving focus out of here first, so this lands
1616
+ * ahead of every request without the host having to announce one — MulmoTerminal's agent is a
1617
+ * terminal, and there is no "sent" event to hook. The debounce is short enough that it has
1618
+ * usually fired already; this closes the case where it has not, which would otherwise have the
1619
+ * agent read a file missing the last thing the user typed.
1620
+ */
1621
+ function onDeckFocusOut(event) {
1622
+ if (focusLeftContainer(event.currentTarget instanceof Node ? event.currentTarget : null, event.relatedTarget)) flushPendingDeckSave();
1623
+ }
1601
1624
  onBeforeUnmount(() => {
1602
1625
  flushPendingDeckSave();
1603
1626
  resetBeatMovies();
@@ -2075,10 +2098,15 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2075
2098
  "onCharDrop",
2076
2099
  "onRenderCharacter"
2077
2100
  ])) : createCommentVNode("", true),
2078
- unref(isDeck) ? (openBlock(), createElementBlock("div", _hoisted_14, [createVNode(unref(BeatListEditor), {
2101
+ unref(isDeck) ? (openBlock(), createElementBlock("div", {
2102
+ key: 2,
2103
+ class: "flex-1 overflow-hidden",
2104
+ "data-testid": "mulmo-script-deck-editor",
2105
+ onFocusout: onDeckFocusOut
2106
+ }, [createVNode(unref(BeatListEditor), {
2079
2107
  beats: deckBeats.value,
2080
2108
  "onUpdate:beats": onDeckBeatsUpdate
2081
- }, null, 8, ["beats"])])) : (openBlock(), createElementBlock("div", {
2109
+ }, null, 8, ["beats"])], 32)) : (openBlock(), createElementBlock("div", {
2082
2110
  key: 3,
2083
2111
  ref_key: "beatListEl",
2084
2112
  ref: beatListEl,
@@ -2087,7 +2115,7 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2087
2115
  return openBlock(), createElementBlock("div", {
2088
2116
  key: index,
2089
2117
  class: "rounded-lg border border-gray-200 overflow-hidden"
2090
- }, [createElementVNode("div", _hoisted_15, [createElementVNode("div", {
2118
+ }, [createElementVNode("div", _hoisted_14, [createElementVNode("div", {
2091
2119
  class: normalizeClass(["relative shrink-0 w-[45%] overflow-hidden bg-gray-50 transition-colors", beatDragOver[index] ? "bg-blue-50" : ""]),
2092
2120
  onDragover: ($event) => onBeatDragOver($event, index),
2093
2121
  onDragleave: ($event) => onBeatDragLeave(index),
@@ -2096,27 +2124,27 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2096
2124
  createElementVNode("div", {
2097
2125
  class: "absolute top-1.5 left-1.5 z-10 px-1.5 py-0.5 rounded bg-black/55 text-white text-xs font-medium leading-none pointer-events-none",
2098
2126
  "data-testid": `mulmo-script-beat-number-${index}`
2099
- }, toDisplayString(index + 1), 9, _hoisted_17),
2127
+ }, toDisplayString(index + 1), 9, _hoisted_16),
2100
2128
  unref(beatMovieOpen)[index] && unref(beatMovieUrls)[index] ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("video", {
2101
2129
  src: unref(beatMovieUrls)[index],
2102
2130
  class: "w-full object-contain",
2103
2131
  controls: "",
2104
2132
  autoplay: "",
2105
2133
  "data-testid": `mulmo-script-beat-movie-player-${index}`
2106
- }, null, 8, _hoisted_18), createElementVNode("button", {
2134
+ }, null, 8, _hoisted_17), createElementVNode("button", {
2107
2135
  class: "absolute top-1.5 right-1.5 flex items-center justify-center w-6 h-6 rounded border border-gray-400 text-gray-600 bg-white hover:bg-gray-50",
2108
2136
  title: unref(m).close,
2109
2137
  "aria-label": unref(m).close,
2110
2138
  "data-testid": `mulmo-script-beat-movie-close-${index}`,
2111
2139
  onClick: withModifiers(($event) => unref(closeBeatMovie)(index), ["stop"])
2112
- }, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_19)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
2140
+ }, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_18)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
2113
2141
  renderedImages[index] ? (openBlock(), createElementBlock("img", {
2114
2142
  key: 0,
2115
2143
  src: renderedImages[index],
2116
2144
  class: "w-full object-contain cursor-zoom-in",
2117
2145
  alt: `Beat ${index + 1}`,
2118
2146
  onClick: ($event) => openLightbox(index)
2119
- }, null, 8, _hoisted_20)) : createCommentVNode("", true),
2147
+ }, null, 8, _hoisted_19)) : createCommentVNode("", true),
2120
2148
  renderedImages[index] && unref(beatMovies)[index] && canFetchMedia.value ? (openBlock(), createElementBlock("button", {
2121
2149
  key: 1,
2122
2150
  class: "absolute inset-0 m-auto w-12 h-12 flex items-center justify-center rounded-full bg-black/50 text-white hover:bg-black/70",
@@ -2124,7 +2152,7 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2124
2152
  "aria-label": unref(m).play,
2125
2153
  "data-testid": `mulmo-script-beat-movie-play-${index}`,
2126
2154
  onClick: withModifiers(($event) => unref(playBeatMovie)(index), ["stop"])
2127
- }, [unref(beatMovieLoading)[index] ? (openBlock(), createElementBlock("svg", _hoisted_22, [..._cache[5] || (_cache[5] = [createElementVNode("circle", {
2155
+ }, [unref(beatMovieLoading)[index] ? (openBlock(), createElementBlock("svg", _hoisted_21, [..._cache[5] || (_cache[5] = [createElementVNode("circle", {
2128
2156
  class: "opacity-25",
2129
2157
  cx: "12",
2130
2158
  cy: "12",
@@ -2135,13 +2163,13 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2135
2163
  class: "opacity-75",
2136
2164
  fill: "currentColor",
2137
2165
  d: "M4 12a8 8 0 018-8v8H4z"
2138
- }, null, -1)])])) : (openBlock(), createElementBlock("span", _hoisted_23, "play_arrow"))], 8, _hoisted_21)) : createCommentVNode("", true),
2166
+ }, null, -1)])])) : (openBlock(), createElementBlock("span", _hoisted_22, "play_arrow"))], 8, _hoisted_20)) : createCommentVNode("", true),
2139
2167
  renderedImages[index] && renderState[index] !== "rendering" ? (openBlock(), createElementBlock("button", {
2140
2168
  key: 2,
2141
2169
  class: "absolute top-1.5 right-1.5 flex items-center gap-1 px-2 py-0.5 text-xs rounded border border-gray-400 text-gray-600 bg-white hover:bg-gray-50 disabled:opacity-60 disabled:cursor-not-allowed",
2142
2170
  disabled: unref(movieGenerating),
2143
2171
  onClick: withModifiers(($event) => regenerateBeat(index), ["stop"])
2144
- }, " ↺ ", 8, _hoisted_24)) : !renderedImages[index] ? (openBlock(), createElementBlock("div", _hoisted_25, [renderState[index] === "rendering" || unref(movieGenerating) && !renderedImages[index] && effectiveBeat$1(index).imagePrompt ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[6] || (_cache[6] = createElementVNode("svg", {
2172
+ }, " ↺ ", 8, _hoisted_23)) : !renderedImages[index] ? (openBlock(), createElementBlock("div", _hoisted_24, [renderState[index] === "rendering" || unref(movieGenerating) && !renderedImages[index] && effectiveBeat$1(index).imagePrompt ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[6] || (_cache[6] = createElementVNode("svg", {
2145
2173
  class: "animate-spin w-4 h-4 text-green-400",
2146
2174
  viewBox: "0 0 24 24",
2147
2175
  fill: "none"
@@ -2156,15 +2184,15 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2156
2184
  class: "opacity-75",
2157
2185
  fill: "currentColor",
2158
2186
  d: "M4 12a8 8 0 018-8v8H4z"
2159
- })], -1)), createElementVNode("span", _hoisted_26, toDisplayString(unref(m).rendering), 1)], 64)) : renderState[index] === "error" ? (openBlock(), createElementBlock("span", _hoisted_27, toDisplayString(renderErrors[index]), 1)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [effectiveBeat$1(index).imagePrompt ? (openBlock(), createElementBlock("span", _hoisted_28, toDisplayString(effectiveBeat$1(index).imagePrompt), 1)) : (openBlock(), createElementBlock("span", _hoisted_29, toDisplayString(beat.image?.type ?? "—"), 1))], 64))])) : createCommentVNode("", true)
2187
+ })], -1)), createElementVNode("span", _hoisted_25, toDisplayString(unref(m).rendering), 1)], 64)) : renderState[index] === "error" ? (openBlock(), createElementBlock("span", _hoisted_26, toDisplayString(renderErrors[index]), 1)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [effectiveBeat$1(index).imagePrompt ? (openBlock(), createElementBlock("span", _hoisted_27, toDisplayString(effectiveBeat$1(index).imagePrompt), 1)) : (openBlock(), createElementBlock("span", _hoisted_28, toDisplayString(beat.image?.type ?? "—"), 1))], 64))])) : createCommentVNode("", true)
2160
2188
  ], 64)),
2161
- beatDragOver[index] ? (openBlock(), createElementBlock("div", _hoisted_30, [createElementVNode("span", _hoisted_31, toDisplayString(unref(m).drop), 1)])) : !renderedImages[index] && renderState[index] !== "rendering" ? (openBlock(), createElementBlock("div", _hoisted_32, toDisplayString(unref(m).orDropImage), 1)) : createCommentVNode("", true),
2189
+ beatDragOver[index] ? (openBlock(), createElementBlock("div", _hoisted_29, [createElementVNode("span", _hoisted_30, toDisplayString(unref(m).drop), 1)])) : !renderedImages[index] && renderState[index] !== "rendering" ? (openBlock(), createElementBlock("div", _hoisted_31, toDisplayString(unref(m).orDropImage), 1)) : createCommentVNode("", true),
2162
2190
  !renderedImages[index] && renderState[index] !== "rendering" && !unref(movieGenerating) && !unref(isBeatImageReference)(effectiveBeat$1(index)) ? (openBlock(), createElementBlock("button", {
2163
2191
  key: 4,
2164
2192
  class: "absolute top-1.5 right-1.5 flex items-center gap-1 px-2 py-0.5 text-xs rounded border border-blue-400 text-blue-600 bg-white hover:bg-blue-50",
2165
2193
  onClick: ($event) => renderBeat(index)
2166
- }, toDisplayString(unref(m).generate), 9, _hoisted_33)) : createCommentVNode("", true)
2167
- ], 42, _hoisted_16), createElementVNode("div", _hoisted_34, [createElementVNode("span", _hoisted_35, toDisplayString(effectiveBeat$1(index).text), 1), createElementVNode("div", _hoisted_36, [createElementVNode("div", _hoisted_37, [audioState[index] === "generating" || unref(movieGenerating) && !beatAudios[index] && effectiveBeat$1(index).text ? (openBlock(), createElementBlock("svg", _hoisted_38, [..._cache[7] || (_cache[7] = [createElementVNode("circle", {
2194
+ }, toDisplayString(unref(m).generate), 9, _hoisted_32)) : createCommentVNode("", true)
2195
+ ], 42, _hoisted_15), createElementVNode("div", _hoisted_33, [createElementVNode("span", _hoisted_34, toDisplayString(effectiveBeat$1(index).text), 1), createElementVNode("div", _hoisted_35, [createElementVNode("div", _hoisted_36, [audioState[index] === "generating" || unref(movieGenerating) && !beatAudios[index] && effectiveBeat$1(index).text ? (openBlock(), createElementBlock("svg", _hoisted_37, [..._cache[7] || (_cache[7] = [createElementVNode("circle", {
2168
2196
  class: "opacity-25",
2169
2197
  cx: "12",
2170
2198
  cy: "12",
@@ -2179,19 +2207,19 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2179
2207
  key: 1,
2180
2208
  class: normalizeClass(["text-xs px-2 py-0.5 rounded border", playingAudio.value?.index === index ? "border-red-400 text-red-600 hover:bg-red-50" : "border-green-400 text-green-600 hover:bg-green-50"]),
2181
2209
  onClick: ($event) => playAudio(index)
2182
- }, toDisplayString(playingAudio.value?.index === index ? unref(m).stop : unref(m).play), 11, _hoisted_39)) : audioErrors[index] ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createElementVNode("span", {
2210
+ }, toDisplayString(playingAudio.value?.index === index ? unref(m).stop : unref(m).play), 11, _hoisted_38)) : audioErrors[index] ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createElementVNode("span", {
2183
2211
  class: "text-xs text-red-400 truncate min-w-0 max-w-[20rem]",
2184
2212
  title: audioErrors[index]
2185
- }, toDisplayString(unref(m).errPrefix) + " " + toDisplayString(audioErrors[index]), 9, _hoisted_40), effectiveBeat$1(index).text ? (openBlock(), createElementBlock("button", {
2213
+ }, toDisplayString(unref(m).errPrefix) + " " + toDisplayString(audioErrors[index]), 9, _hoisted_39), effectiveBeat$1(index).text ? (openBlock(), createElementBlock("button", {
2186
2214
  key: 0,
2187
2215
  class: "text-xs px-2 py-0.5 rounded border border-gray-300 text-gray-500 hover:bg-gray-50 disabled:opacity-50",
2188
2216
  disabled: unref(movieGenerating),
2189
2217
  onClick: ($event) => generateAudio(index)
2190
- }, " ↺ ", 8, _hoisted_41)) : createCommentVNode("", true)], 64)) : effectiveBeat$1(index).text ? (openBlock(), createElementBlock("button", {
2218
+ }, " ↺ ", 8, _hoisted_40)) : createCommentVNode("", true)], 64)) : effectiveBeat$1(index).text ? (openBlock(), createElementBlock("button", {
2191
2219
  key: 3,
2192
2220
  class: "text-xs px-2 py-0.5 rounded border border-gray-300 text-gray-500 hover:bg-gray-50",
2193
2221
  onClick: ($event) => generateAudio(index)
2194
- }, toDisplayString(unref(m).generateAudio), 9, _hoisted_42)) : createCommentVNode("", true)]), createElementVNode("button", {
2222
+ }, toDisplayString(unref(m).generateAudio), 9, _hoisted_41)) : createCommentVNode("", true)]), createElementVNode("button", {
2195
2223
  class: "text-gray-400 hover:text-gray-600",
2196
2224
  title: sourceOpen[index] ? "Hide source" : "Show source",
2197
2225
  "data-testid": `mulmo-script-beat-source-toggle-${index}`,
@@ -2205,20 +2233,20 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2205
2233
  "stroke-width": "2",
2206
2234
  "stroke-linecap": "round",
2207
2235
  "stroke-linejoin": "round"
2208
- }, [createElementVNode("polyline", { points: "16 18 22 12 16 6" }), createElementVNode("polyline", { points: "8 6 2 12 8 18" })], -1)])], 8, _hoisted_43)])])]), sourceOpen[index] ? (openBlock(), createElementBlock("div", _hoisted_44, [withDirectives(createElementVNode("textarea", {
2236
+ }, [createElementVNode("polyline", { points: "16 18 22 12 16 6" }), createElementVNode("polyline", { points: "8 6 2 12 8 18" })], -1)])], 8, _hoisted_42)])])]), sourceOpen[index] ? (openBlock(), createElementBlock("div", _hoisted_43, [withDirectives(createElementVNode("textarea", {
2209
2237
  "onUpdate:modelValue": ($event) => sourceText[index] = $event,
2210
2238
  class: normalizeClass(["w-full text-xs text-gray-600 bg-gray-50 p-2 font-mono resize-none", isValidBeat$1(index) ? "outline-none" : "outline outline-2 outline-red-400"]),
2211
2239
  rows: "8",
2212
2240
  spellcheck: "false",
2213
2241
  "data-testid": `mulmo-script-beat-source-textarea-${index}`
2214
- }, null, 10, _hoisted_45), [[vModelText, sourceText[index]]]), createElementVNode("div", _hoisted_46, [beatSaveErrors[index] ? (openBlock(), createElementBlock("span", _hoisted_47, toDisplayString(beatSaveErrors[index].kind === "invalidJson" ? unref(m).saveErrorInvalidJson(beatSaveErrors[index].error) : unref(m).saveErrorSaveFailed(beatSaveErrors[index].error)), 1)) : createCommentVNode("", true), createElementVNode("button", {
2242
+ }, null, 10, _hoisted_44), [[vModelText, sourceText[index]]]), createElementVNode("div", _hoisted_45, [beatSaveErrors[index] ? (openBlock(), createElementBlock("span", _hoisted_46, toDisplayString(beatSaveErrors[index].kind === "invalidJson" ? unref(m).saveErrorInvalidJson(beatSaveErrors[index].error) : unref(m).saveErrorSaveFailed(beatSaveErrors[index].error)), 1)) : createCommentVNode("", true), createElementVNode("button", {
2215
2243
  class: normalizeClass(["px-2 py-1 text-xs rounded border", isValidBeat$1(index) && !beatSaving[index] ? "border-blue-400 text-blue-600 hover:bg-blue-50 cursor-pointer" : "border-gray-200 text-gray-300 cursor-not-allowed"]),
2216
2244
  disabled: !isValidBeat$1(index) || !!beatSaving[index],
2217
2245
  "data-testid": `mulmo-script-beat-update-button-${index}`,
2218
2246
  onClick: ($event) => updateBeat(index)
2219
- }, toDisplayString(beatSaving[index] ? unref(m).saving : unref(m).update), 11, _hoisted_48)])])) : createCommentVNode("", true)]);
2220
- }), 128)), beats.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_49, toDisplayString(unref(m).noBeats), 1)) : createCommentVNode("", true)], 512)),
2221
- createElementVNode("div", _hoisted_50, [createElementVNode("details", {
2247
+ }, toDisplayString(beatSaving[index] ? unref(m).saving : unref(m).update), 11, _hoisted_47)])])) : createCommentVNode("", true)]);
2248
+ }), 128)), beats.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_48, toDisplayString(unref(m).noBeats), 1)) : createCommentVNode("", true)], 512)),
2249
+ createElementVNode("div", _hoisted_49, [createElementVNode("details", {
2222
2250
  ref_key: "sourceDetails",
2223
2251
  ref: sourceDetails,
2224
2252
  class: "script-source",
@@ -2230,11 +2258,11 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2230
2258
  class: normalizeClass(["script-editor", { "script-editor-invalid": sourceChanged.value && !sourceValid.value }]),
2231
2259
  spellcheck: "false"
2232
2260
  }, null, 2), [[vModelText, editableSource.value]]),
2233
- createElementVNode("div", _hoisted_51, [createElementVNode("button", {
2261
+ createElementVNode("div", _hoisted_50, [createElementVNode("button", {
2234
2262
  class: "apply-btn",
2235
2263
  disabled: !sourceChanged.value || !sourceValid.value,
2236
2264
  onClick: applySource
2237
- }, toDisplayString(unref(m).applyChanges), 9, _hoisted_52), createElementVNode("button", {
2265
+ }, toDisplayString(unref(m).applyChanges), 9, _hoisted_51), createElementVNode("button", {
2238
2266
  class: "cancel-btn",
2239
2267
  onClick: cancelSourceEdit
2240
2268
  }, toDisplayString(unref(m).cancel), 1)])
@@ -2242,7 +2270,7 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
2242
2270
  class: "copy-btn",
2243
2271
  title: unref(copied) ? "Copied!" : "Copy",
2244
2272
  onClick: copyText
2245
- }, [createElementVNode("span", _hoisted_54, toDisplayString(unref(copied) ? "check" : "content_copy"), 1)], 8, _hoisted_53), [[vShow, !editing.value]])]),
2273
+ }, [createElementVNode("span", _hoisted_53, toDisplayString(unref(copied) ? "check" : "content_copy"), 1)], 8, _hoisted_52), [[vShow, !editing.value]])]),
2246
2274
  lightbox.value ? (openBlock(), createBlock(BeatLightbox_default, {
2247
2275
  key: 4,
2248
2276
  lightbox: lightbox.value,
@@ -2280,7 +2308,7 @@ var _plugin_vue_export_helper_default = (sfc, props) => {
2280
2308
  };
2281
2309
  //#endregion
2282
2310
  //#region src/vue/View.vue
2283
- var View_default = /*#__PURE__*/ _plugin_vue_export_helper_default(View_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-87bf6e4c"]]);
2311
+ var View_default = /*#__PURE__*/ _plugin_vue_export_helper_default(View_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-d78be72d"]]);
2284
2312
  //#endregion
2285
2313
  //#region src/vue/Preview.vue?vue&type=script&setup=true&lang.ts
2286
2314
  var _hoisted_1 = {
@@ -2321,6 +2349,6 @@ var plugin = {
2321
2349
  };
2322
2350
  var vue_default = { plugin };
2323
2351
  //#endregion
2324
- export { GENERATION_EVENT, MULMOSCRIPT_HOST_ADAPTER_KEY, Preview_default as Preview, TOOL_DEFINITION, TOOL_NAME, View_default as View, vue_default as default, plugin, useHostAdapter, useMulmoScriptTransport };
2352
+ export { GENERATION_EVENT, MULMOSCRIPT_HOST_ADAPTER_KEY, Preview_default as Preview, SCRIPT_CHANGED_EVENT, TOOL_DEFINITION, TOOL_NAME, View_default as View, vue_default as default, plugin, useHostAdapter, useMulmoScriptTransport };
2325
2353
 
2326
2354
  //# sourceMappingURL=vue.js.map