@mulmoclaude/mulmoscript-plugin 3.1.0 → 4.1.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/contract-BhN3yKJC.cjs +36 -0
- package/dist/contract-BhN3yKJC.cjs.map +1 -0
- package/dist/contract-CIt1ZAtt.js +19 -0
- package/dist/contract-CIt1ZAtt.js.map +1 -0
- package/dist/core/contract.d.ts +24 -0
- package/dist/core/contract.d.ts.map +1 -1
- package/dist/server/dispatch.d.ts.map +1 -1
- package/dist/server/ops.d.ts +1 -0
- package/dist/server/ops.d.ts.map +1 -1
- package/dist/server/types.d.ts +6 -1
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server.cjs +18 -2
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +18 -2
- package/dist/server.js.map +1 -1
- package/dist/style.css +119 -19
- package/dist/vue/View.vue.d.ts.map +1 -1
- package/dist/vue/composables/useDeckEditor.d.ts +1 -0
- package/dist/vue/composables/useDeckEditor.d.ts.map +1 -1
- package/dist/vue/helpers.d.ts +2 -2
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/transport.d.ts +3 -0
- package/dist/vue/transport.d.ts.map +1 -1
- package/dist/vue/viewTypes.d.ts +1 -1
- package/dist/vue/viewTypes.d.ts.map +1 -1
- package/dist/vue.cjs +73 -14
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +73 -14
- package/dist/vue.js.map +1 -1
- package/package.json +4 -2
- package/dist/contract-DxKVCRQk.cjs +0 -13
- package/dist/contract-DxKVCRQk.cjs.map +0 -1
- package/dist/contract-vY0niHkh.js +0 -8
- package/dist/contract-vY0niHkh.js.map +0 -1
package/dist/vue.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { a as pluginCore, d as errorMessage, f as TOOL_DEFINITION, p as TOOL_NAME } from "./plugin-CXhOP_xU.js";
|
|
2
|
-
import { t as GENERATION_EVENT } from "./contract-
|
|
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";
|
|
5
|
+
import { beatsOf, withBeats } from "@mulmocast/beat-editor";
|
|
5
6
|
import { createUseT, useRuntime } from "gui-chat-protocol/vue";
|
|
6
7
|
//#region src/vue/support.ts
|
|
7
8
|
function isRecord(value) {
|
|
@@ -115,8 +116,8 @@ function isBeatImageReference(beat) {
|
|
|
115
116
|
return beat.image?.type === "beat";
|
|
116
117
|
}
|
|
117
118
|
/** Pure check: is every beat in the script a `slide`-typed beat?
|
|
118
|
-
* When true, the View mounts `@mulmocast/
|
|
119
|
-
* `
|
|
119
|
+
* When true, the View mounts `@mulmocast/beat-editor`'s
|
|
120
|
+
* `BeatListEditor` instead of the per-beat list UI (#1575).
|
|
120
121
|
* Empty / missing `beats[]` returns false — there's nothing to edit
|
|
121
122
|
* as a deck, fall through to the existing UI which renders an empty
|
|
122
123
|
* state. Mixed scripts (any non-`slide` beat) also return false; that
|
|
@@ -208,6 +209,15 @@ var GENERATION_EVENT_KINDS = /* @__PURE__ */ new Set([
|
|
|
208
209
|
"movie",
|
|
209
210
|
"pdf"
|
|
210
211
|
]);
|
|
212
|
+
function parseScriptChangedEvent(payload) {
|
|
213
|
+
if (!isRecord(payload)) return null;
|
|
214
|
+
const { filePath, origin } = payload;
|
|
215
|
+
if (typeof filePath !== "string") return null;
|
|
216
|
+
return {
|
|
217
|
+
filePath,
|
|
218
|
+
...typeof origin === "string" ? { origin } : {}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
211
221
|
function parseGenerationEvent(payload) {
|
|
212
222
|
if (!isRecord(payload)) return null;
|
|
213
223
|
const { kind, filePath, key, done, error } = payload;
|
|
@@ -254,9 +264,25 @@ function useMulmoScriptTransport() {
|
|
|
254
264
|
handler(event);
|
|
255
265
|
});
|
|
256
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* A write to this script landed — reload from disk.
|
|
269
|
+
*
|
|
270
|
+
* `ownOrigin` is this View's id. Its own writes echo back on the same channel, and acting
|
|
271
|
+
* on them would rebuild the element the caret is in on every keystroke, so they are dropped
|
|
272
|
+
* here. A write from the agent carries no origin and always reaches the handler.
|
|
273
|
+
*/
|
|
274
|
+
function onScriptChanged(filePath, ownOrigin, handler) {
|
|
275
|
+
return runtime.pubsub.subscribe(SCRIPT_CHANGED_EVENT, (payload) => {
|
|
276
|
+
const event = parseScriptChangedEvent(payload);
|
|
277
|
+
if (!event) return;
|
|
278
|
+
if (!shouldReloadForScriptChange(event, filePath(), ownOrigin)) return;
|
|
279
|
+
handler();
|
|
280
|
+
});
|
|
281
|
+
}
|
|
257
282
|
return {
|
|
258
283
|
call,
|
|
259
|
-
onGenerationEvent
|
|
284
|
+
onGenerationEvent,
|
|
285
|
+
onScriptChanged
|
|
260
286
|
};
|
|
261
287
|
}
|
|
262
288
|
//#endregion
|
|
@@ -550,6 +576,17 @@ function useCharacterImages({ api, filePath, chatSessionId, getImages }) {
|
|
|
550
576
|
//#endregion
|
|
551
577
|
//#region src/vue/composables/useDeckEditor.ts
|
|
552
578
|
var DECK_SAVE_DEBOUNCE_MS = 300;
|
|
579
|
+
/**
|
|
580
|
+
* Who this editor is, on the wire.
|
|
581
|
+
*
|
|
582
|
+
* Every write carries it so the server's "this script changed" broadcast can be told apart
|
|
583
|
+
* from someone else's. Without it a save would echo back and reload the editor mid-keystroke,
|
|
584
|
+
* rebuilding the element the caret sits in.
|
|
585
|
+
*
|
|
586
|
+
* Per module instance rather than per component: one View is mounted at a time, and a value
|
|
587
|
+
* that survives a remount keeps a save in flight from being mistaken for a foreign write.
|
|
588
|
+
*/
|
|
589
|
+
var EDITOR_ORIGIN = `deck-editor-${Math.random().toString(36).slice(2)}`;
|
|
553
590
|
function useDeckEditor({ api, filePath, effectiveScript, commitScript }) {
|
|
554
591
|
const isDeck = computed(() => isAllSlideDeck(effectiveScript.value));
|
|
555
592
|
const deckScriptInput = computed(() => effectiveScript.value);
|
|
@@ -569,7 +606,8 @@ function useDeckEditor({ api, filePath, effectiveScript, commitScript }) {
|
|
|
569
606
|
if (!next || !filePath.value) return;
|
|
570
607
|
const response = await api.call("updateScript", {
|
|
571
608
|
filePath: filePath.value,
|
|
572
|
-
script: next
|
|
609
|
+
script: next,
|
|
610
|
+
origin: EDITOR_ORIGIN
|
|
573
611
|
});
|
|
574
612
|
if (!response.ok) {
|
|
575
613
|
console.error("[presentMulmoScript] deck save failed:", response.error);
|
|
@@ -586,11 +624,25 @@ function useDeckEditor({ api, filePath, effectiveScript, commitScript }) {
|
|
|
586
624
|
flushDeckSave();
|
|
587
625
|
}
|
|
588
626
|
}
|
|
627
|
+
/**
|
|
628
|
+
* Reload when someone else writes this script — the agent, or another window.
|
|
629
|
+
*
|
|
630
|
+
* A pending local edit is flushed first rather than dropped: the user's keystrokes are the
|
|
631
|
+
* thing they would notice losing, and the write that triggered this has already landed, so
|
|
632
|
+
* flushing cannot clobber it out of order.
|
|
633
|
+
*/
|
|
634
|
+
function watchForeignWrites(reload) {
|
|
635
|
+
return api.onScriptChanged(() => filePath.value, EDITOR_ORIGIN, () => {
|
|
636
|
+
flushPendingDeckSave();
|
|
637
|
+
reload();
|
|
638
|
+
});
|
|
639
|
+
}
|
|
589
640
|
return {
|
|
590
641
|
isDeck,
|
|
591
642
|
deckScriptInput,
|
|
592
643
|
onDeckUpdate,
|
|
593
|
-
flushPendingDeckSave
|
|
644
|
+
flushPendingDeckSave,
|
|
645
|
+
watchForeignWrites
|
|
594
646
|
};
|
|
595
647
|
}
|
|
596
648
|
/** Reactive message bundle for the active host locale. The plugin carries its
|
|
@@ -1372,7 +1424,7 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
|
|
|
1372
1424
|
props: { selectedResult: {} },
|
|
1373
1425
|
emits: ["updateResult"],
|
|
1374
1426
|
setup(__props, { emit: __emit }) {
|
|
1375
|
-
const
|
|
1427
|
+
const BeatListEditor = defineAsyncComponent(() => import("@mulmocast/beat-editor").then((mod) => mod.BeatListEditor));
|
|
1376
1428
|
const api = useMulmoScriptTransport();
|
|
1377
1429
|
const adapter = useHostAdapter();
|
|
1378
1430
|
const canFetchMedia = computed(() => Boolean(adapter.fetchMediaBlob));
|
|
@@ -1533,16 +1585,24 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
|
|
|
1533
1585
|
}
|
|
1534
1586
|
});
|
|
1535
1587
|
}
|
|
1536
|
-
const { isDeck, deckScriptInput, onDeckUpdate, flushPendingDeckSave } = useDeckEditor({
|
|
1588
|
+
const { isDeck, deckScriptInput, onDeckUpdate, flushPendingDeckSave, watchForeignWrites } = useDeckEditor({
|
|
1537
1589
|
api,
|
|
1538
1590
|
filePath,
|
|
1539
1591
|
effectiveScript,
|
|
1540
1592
|
commitScript
|
|
1541
1593
|
});
|
|
1594
|
+
const unsubscribeForeignWrites = watchForeignWrites(() => {
|
|
1595
|
+
refreshScriptFromDisk();
|
|
1596
|
+
});
|
|
1597
|
+
const deckBeats = computed(() => beatsOf(deckScriptInput.value));
|
|
1598
|
+
function onDeckBeatsUpdate(beats) {
|
|
1599
|
+
onDeckUpdate(withBeats(deckScriptInput.value, beats));
|
|
1600
|
+
}
|
|
1542
1601
|
onBeforeUnmount(() => {
|
|
1543
1602
|
flushPendingDeckSave();
|
|
1544
1603
|
resetBeatMovies();
|
|
1545
1604
|
unsubscribeGenerationEvents();
|
|
1605
|
+
unsubscribeForeignWrites();
|
|
1546
1606
|
});
|
|
1547
1607
|
const loadedSource = ref("");
|
|
1548
1608
|
const sourceChanged = computed(() => editableSource.value !== loadedSource.value);
|
|
@@ -2015,11 +2075,10 @@ var View_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
|
|
|
2015
2075
|
"onCharDrop",
|
|
2016
2076
|
"onRenderCharacter"
|
|
2017
2077
|
])) : createCommentVNode("", true),
|
|
2018
|
-
unref(isDeck) ? (openBlock(), createElementBlock("div", _hoisted_14, [createVNode(unref(
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
}, null, 8, ["script", "onUpdate:script"])])) : (openBlock(), createElementBlock("div", {
|
|
2078
|
+
unref(isDeck) ? (openBlock(), createElementBlock("div", _hoisted_14, [createVNode(unref(BeatListEditor), {
|
|
2079
|
+
beats: deckBeats.value,
|
|
2080
|
+
"onUpdate:beats": onDeckBeatsUpdate
|
|
2081
|
+
}, null, 8, ["beats"])])) : (openBlock(), createElementBlock("div", {
|
|
2023
2082
|
key: 3,
|
|
2024
2083
|
ref_key: "beatListEl",
|
|
2025
2084
|
ref: beatListEl,
|
|
@@ -2221,7 +2280,7 @@ var _plugin_vue_export_helper_default = (sfc, props) => {
|
|
|
2221
2280
|
};
|
|
2222
2281
|
//#endregion
|
|
2223
2282
|
//#region src/vue/View.vue
|
|
2224
|
-
var View_default = /*#__PURE__*/ _plugin_vue_export_helper_default(View_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
2283
|
+
var View_default = /*#__PURE__*/ _plugin_vue_export_helper_default(View_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-87bf6e4c"]]);
|
|
2225
2284
|
//#endregion
|
|
2226
2285
|
//#region src/vue/Preview.vue?vue&type=script&setup=true&lang.ts
|
|
2227
2286
|
var _hoisted_1 = {
|