@mulmoclaude/mulmoscript-plugin 0.1.0 → 0.2.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.
@@ -0,0 +1,13 @@
1
+ //#region src/core/contract.ts
2
+ /** Plugin pubsub event name the host publishes generation events on
3
+ * (full channel: `plugin:<scope>:generation`). */
4
+ var GENERATION_EVENT = "generation";
5
+ //#endregion
6
+ Object.defineProperty(exports, "GENERATION_EVENT", {
7
+ enumerable: true,
8
+ get: function() {
9
+ return GENERATION_EVENT;
10
+ }
11
+ });
12
+
13
+ //# sourceMappingURL=contract-DxKVCRQk.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-DxKVCRQk.cjs","names":[],"sources":["../src/core/contract.ts"],"sourcesContent":["// Host-agnostic dispatch envelope for the presentMulmoScript View. The Vue\n// View is decoupled from any one host's REST surface: it calls\n// `useRuntime().dispatch({ kind, … })`, the host routes that to its\n// mulmoScript dispatch handler, and every response is an `{ ok: … }`\n// envelope so failures travel as data (no HTTP-status coupling, no\n// \"dispatch failed (500)\" prefixes in user-facing errors).\n//\n// Long-running generation (movie / PDF) is a single long-held dispatch that\n// resolves when the pipeline finishes; per-beat progress arrives on the\n// plugin pubsub channel (`GENERATION_EVENT`) instead of an SSE stream, which\n// also covers generations started elsewhere (background autoGenerateMovie,\n// another tab, the agent).\n\n/** One in-flight or per-beat generation notice, published on the plugin\n * pubsub `generation` channel and returned by the `pendingGenerations`\n * snapshot. Value strings mirror @mulmobridge/protocol's GENERATION_KINDS\n * so MulmoClaude's host bridge maps 1:1 without a lookup table. */\nexport interface MulmoScriptGenerationEvent {\n kind: \"beatImage\" | \"beatAudio\" | \"characterImage\" | \"movie\" | \"pdf\";\n /** Wire `stories/…` path of the script the generation belongs to. */\n filePath: string;\n /** beatIndex (as string) for beat*, character key for characterImage, \"\" for movie/pdf. */\n key: string;\n /** false = started, true = finished (reload the asset off disk). */\n done: boolean;\n /** Only set on done=true when the work failed. */\n error?: string;\n}\n\n/** Plugin pubsub event name the host publishes generation events on\n * (full channel: `plugin:<scope>:generation`). */\nexport const GENERATION_EVENT = \"generation\";\n\ninterface BeatRef {\n filePath: string;\n beatIndex: number;\n}\n\ninterface CharacterRef {\n filePath: string;\n key: string;\n}\n\n/** Session tag for hosts that surface per-session generation indicators\n * (MulmoClaude's sidebar). Optional everywhere; hosts without sessions\n * ignore it. */\ninterface SessionTag {\n chatSessionId?: string;\n}\n\nexport type MulmoScriptDispatchArgs =\n | ({ kind: \"save\" } & { filePath?: string; script?: unknown; filename?: string })\n | { kind: \"updateBeat\"; filePath: string; beatIndex: number; beat: unknown }\n | { kind: \"updateScript\"; filePath: string; script: unknown }\n | ({ kind: \"beatImage\" } & BeatRef)\n | ({ kind: \"beatAudio\" } & BeatRef)\n | ({ kind: \"beatMovie\" } & BeatRef)\n | ({ kind: \"renderBeat\" } & BeatRef & SessionTag & { force?: boolean })\n | ({ kind: \"generateBeatAudio\" } & BeatRef & SessionTag & { force?: boolean })\n | ({ kind: \"uploadBeatImage\" } & BeatRef & { imageData: string })\n | ({ kind: \"characterImage\" } & CharacterRef)\n | ({ kind: \"renderCharacter\" } & CharacterRef & SessionTag & { force?: boolean })\n | ({ kind: \"uploadCharacterImage\" } & CharacterRef & { imageData: string })\n | ({ kind: \"movieStatus\" } & { filePath: string })\n | ({ kind: \"pdfStatus\" } & { filePath: string })\n | ({ kind: \"generateMovie\" } & { filePath: string } & SessionTag)\n | ({ kind: \"generatePdf\" } & { filePath: string } & SessionTag)\n | { kind: \"pendingGenerations\"; filePath: string };\n\nexport type MulmoScriptDispatchKind = MulmoScriptDispatchArgs[\"kind\"];\n\n/** Failure half of every dispatch response. `code` mirrors the phase-1\n * outcome codes so a host can log/telemetry on it; the View only reads\n * `error`. */\nexport interface DispatchFailure {\n ok: false;\n code?: \"bad_request\" | \"not_found\" | \"server_error\";\n error: string;\n}\n\nexport type DispatchEnvelope<T> = ({ ok: true } & T) | DispatchFailure;\n\n/** Maps a dispatch `kind` to its success payload so the View's transport\n * can call `dispatch` without casts at every site. */\nexport interface MulmoScriptDispatchResult {\n save: { script: Record<string, unknown>; filePath: string; message: string };\n updateBeat: Record<string, never>;\n updateScript: Record<string, never>;\n beatImage: { image: string | null };\n beatAudio: { audio: string | null };\n beatMovie: { moviePath: string | null };\n renderBeat: { image: string };\n generateBeatAudio: { audio: string };\n uploadBeatImage: { image: string };\n characterImage: { image: string | null };\n renderCharacter: { image: string };\n uploadCharacterImage: { image: string };\n movieStatus: { moviePath: string | null };\n pdfStatus: { pdfPath: string | null };\n generateMovie: { moviePath: string };\n generatePdf: { pdfPath: string };\n pendingGenerations: { pending: MulmoScriptGenerationEvent[] };\n}\n"],"mappings":";;;AA+BA,IAAa,mBAAmB"}
@@ -0,0 +1,8 @@
1
+ //#region src/core/contract.ts
2
+ /** Plugin pubsub event name the host publishes generation events on
3
+ * (full channel: `plugin:<scope>:generation`). */
4
+ var GENERATION_EVENT = "generation";
5
+ //#endregion
6
+ export { GENERATION_EVENT as t };
7
+
8
+ //# sourceMappingURL=contract-vY0niHkh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-vY0niHkh.js","names":[],"sources":["../src/core/contract.ts"],"sourcesContent":["// Host-agnostic dispatch envelope for the presentMulmoScript View. The Vue\n// View is decoupled from any one host's REST surface: it calls\n// `useRuntime().dispatch({ kind, … })`, the host routes that to its\n// mulmoScript dispatch handler, and every response is an `{ ok: … }`\n// envelope so failures travel as data (no HTTP-status coupling, no\n// \"dispatch failed (500)\" prefixes in user-facing errors).\n//\n// Long-running generation (movie / PDF) is a single long-held dispatch that\n// resolves when the pipeline finishes; per-beat progress arrives on the\n// plugin pubsub channel (`GENERATION_EVENT`) instead of an SSE stream, which\n// also covers generations started elsewhere (background autoGenerateMovie,\n// another tab, the agent).\n\n/** One in-flight or per-beat generation notice, published on the plugin\n * pubsub `generation` channel and returned by the `pendingGenerations`\n * snapshot. Value strings mirror @mulmobridge/protocol's GENERATION_KINDS\n * so MulmoClaude's host bridge maps 1:1 without a lookup table. */\nexport interface MulmoScriptGenerationEvent {\n kind: \"beatImage\" | \"beatAudio\" | \"characterImage\" | \"movie\" | \"pdf\";\n /** Wire `stories/…` path of the script the generation belongs to. */\n filePath: string;\n /** beatIndex (as string) for beat*, character key for characterImage, \"\" for movie/pdf. */\n key: string;\n /** false = started, true = finished (reload the asset off disk). */\n done: boolean;\n /** Only set on done=true when the work failed. */\n error?: string;\n}\n\n/** Plugin pubsub event name the host publishes generation events on\n * (full channel: `plugin:<scope>:generation`). */\nexport const GENERATION_EVENT = \"generation\";\n\ninterface BeatRef {\n filePath: string;\n beatIndex: number;\n}\n\ninterface CharacterRef {\n filePath: string;\n key: string;\n}\n\n/** Session tag for hosts that surface per-session generation indicators\n * (MulmoClaude's sidebar). Optional everywhere; hosts without sessions\n * ignore it. */\ninterface SessionTag {\n chatSessionId?: string;\n}\n\nexport type MulmoScriptDispatchArgs =\n | ({ kind: \"save\" } & { filePath?: string; script?: unknown; filename?: string })\n | { kind: \"updateBeat\"; filePath: string; beatIndex: number; beat: unknown }\n | { kind: \"updateScript\"; filePath: string; script: unknown }\n | ({ kind: \"beatImage\" } & BeatRef)\n | ({ kind: \"beatAudio\" } & BeatRef)\n | ({ kind: \"beatMovie\" } & BeatRef)\n | ({ kind: \"renderBeat\" } & BeatRef & SessionTag & { force?: boolean })\n | ({ kind: \"generateBeatAudio\" } & BeatRef & SessionTag & { force?: boolean })\n | ({ kind: \"uploadBeatImage\" } & BeatRef & { imageData: string })\n | ({ kind: \"characterImage\" } & CharacterRef)\n | ({ kind: \"renderCharacter\" } & CharacterRef & SessionTag & { force?: boolean })\n | ({ kind: \"uploadCharacterImage\" } & CharacterRef & { imageData: string })\n | ({ kind: \"movieStatus\" } & { filePath: string })\n | ({ kind: \"pdfStatus\" } & { filePath: string })\n | ({ kind: \"generateMovie\" } & { filePath: string } & SessionTag)\n | ({ kind: \"generatePdf\" } & { filePath: string } & SessionTag)\n | { kind: \"pendingGenerations\"; filePath: string };\n\nexport type MulmoScriptDispatchKind = MulmoScriptDispatchArgs[\"kind\"];\n\n/** Failure half of every dispatch response. `code` mirrors the phase-1\n * outcome codes so a host can log/telemetry on it; the View only reads\n * `error`. */\nexport interface DispatchFailure {\n ok: false;\n code?: \"bad_request\" | \"not_found\" | \"server_error\";\n error: string;\n}\n\nexport type DispatchEnvelope<T> = ({ ok: true } & T) | DispatchFailure;\n\n/** Maps a dispatch `kind` to its success payload so the View's transport\n * can call `dispatch` without casts at every site. */\nexport interface MulmoScriptDispatchResult {\n save: { script: Record<string, unknown>; filePath: string; message: string };\n updateBeat: Record<string, never>;\n updateScript: Record<string, never>;\n beatImage: { image: string | null };\n beatAudio: { audio: string | null };\n beatMovie: { moviePath: string | null };\n renderBeat: { image: string };\n generateBeatAudio: { audio: string };\n uploadBeatImage: { image: string };\n characterImage: { image: string | null };\n renderCharacter: { image: string };\n uploadCharacterImage: { image: string };\n movieStatus: { moviePath: string | null };\n pdfStatus: { pdfPath: string | null };\n generateMovie: { moviePath: string };\n generatePdf: { pdfPath: string };\n pendingGenerations: { pending: MulmoScriptGenerationEvent[] };\n}\n"],"mappings":";;;AA+BA,IAAa,mBAAmB"}
@@ -0,0 +1,10 @@
1
+ import type { MulmoScriptServerOps } from "./ops";
2
+ export type MulmoScriptDispatchHandler = (args: Record<string, unknown>) => Promise<unknown>;
3
+ /**
4
+ * Build the kind router over an ops instance. The save / reopen / update
5
+ * kinds run the phase-1 core executes against the backend's artifacts
6
+ * FileOps, guarded by the instance's realpath containment
7
+ * (`guardStoryWirePath`) — the core's own guard is lexical.
8
+ */
9
+ export declare function createMulmoScriptDispatchHandler(ops: MulmoScriptServerOps): MulmoScriptDispatchHandler;
10
+ //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/server/dispatch.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAqElD,MAAM,MAAM,0BAA0B,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7F;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,GAAG,EAAE,oBAAoB,GAAG,0BAA0B,CAuFtG"}
@@ -0,0 +1,7 @@
1
+ export type { GenerateOpArgs, MovieGenerationResult, MovieProgressEvent, MulmoScriptServerBackend, MulmoScriptServerLog, OpFailure, OpResult, PdfGenerationResult, } from "./types";
2
+ export { buildContext, buildBeatIdIndex, createMulmoScriptServerOps, PDF_MODE, PDF_SIZE, type MulmoScriptServerOps, type RunStoryOpDeps, type RunStoryOpOptions, type StoryContext, } from "./ops";
3
+ export { createMulmoScriptDispatchHandler, type MulmoScriptDispatchHandler } from "./dispatch";
4
+ export { withMulmoErrorCapture, enableGraphAIErrorCapture, composeMulmoErrorMessage, describeMulmoCause } from "./mulmoErrorCapture";
5
+ export { GENERATION_EVENT, type MulmoScriptGenerationEvent } from "../core/contract";
6
+ export { executeMulmoScriptSave, executeUpdateBeat, executeUpdateScript, type MulmoScriptFailure } from "../core/plugin";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAMA,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,SAAS,EACT,QAAQ,EACR,mBAAmB,GACpB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,0BAA0B,EAC1B,QAAQ,EACR,QAAQ,EACR,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,gCAAgC,EAAE,KAAK,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAC/F,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACrI,OAAO,EAAE,gBAAgB,EAAE,KAAK,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { MulmoScriptServerLog } from "./types";
2
+ /** Route captured GraphAI errors into the host logger. Set once by
3
+ * `createMulmoScriptServerOps`; the GraphAILogger sink is global, so the
4
+ * last-configured host logger wins (one ops instance per process). */
5
+ export declare function setMulmoErrorCaptureLogger(log: MulmoScriptServerLog | null): void;
6
+ /**
7
+ * Re-enable GraphAI's error level (everything else stays silenced) and
8
+ * route it into the host logger + the per-operation capture store.
9
+ * Call after every `setGraphAILogger(false)` — that helper disables all
10
+ * levels including error. Idempotent.
11
+ */
12
+ export declare function enableGraphAIErrorCapture(): void;
13
+ /** Render mulmocast's structured error `cause` as "field=value" pairs. */
14
+ export declare function describeMulmoCause(err: unknown): string | null;
15
+ /**
16
+ * Compose the enriched message for a failed mulmocast operation:
17
+ * mulmocast's own message, then its structured cause, then the
18
+ * captured underlying provider error(s). Deduped — GraphAI retries
19
+ * log the same error more than once.
20
+ */
21
+ export declare function composeMulmoErrorMessage(err: unknown, captured: readonly string[]): string;
22
+ /**
23
+ * Run a mulmocast operation, capturing GraphAI error logs emitted while
24
+ * it executes. On failure, rethrows with the captured provider error(s)
25
+ * appended to the message (original error kept as `cause`). Uses
26
+ * AsyncLocalStorage so concurrent operations don't cross-attribute.
27
+ */
28
+ export declare function withMulmoErrorCapture<T>(operation: () => Promise<T>): Promise<T>;
29
+ //# sourceMappingURL=mulmoErrorCapture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mulmoErrorCapture.d.ts","sourceRoot":"","sources":["../../src/server/mulmoErrorCapture.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAMpD;;uEAEuE;AACvE,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAEjF;AAYD;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAUhD;AAOD,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQ9D;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAI1F;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQtF"}
@@ -0,0 +1,101 @@
1
+ import type { MulmoBeat, MulmoStudioContext } from "@mulmocast/types";
2
+ import type { MulmoScriptGenerationEvent } from "../core/contract";
3
+ import type { GenerateOpArgs, MovieGenerationResult, MovieProgressEvent, MulmoScriptServerBackend, OpFailure, OpResult, PdfGenerationResult } from "./types";
4
+ type GenerationKind = MulmoScriptGenerationEvent["kind"];
5
+ export declare const PDF_MODE: "slide";
6
+ export declare const PDF_SIZE: "a4";
7
+ export declare function buildContext(absoluteFilePath: string, force?: boolean): Promise<MulmoStudioContext | null | undefined>;
8
+ export type StoryContext = NonNullable<Awaited<ReturnType<typeof buildContext>>>;
9
+ export interface RunStoryOpDeps {
10
+ resolveStory?: (filePath: string) => {
11
+ ok: true;
12
+ absolutePath: string;
13
+ } | OpFailure;
14
+ buildContext?: (absoluteFilePath: string, force?: boolean) => Promise<StoryContext | undefined>;
15
+ }
16
+ export interface RunStoryOpOptions<T> {
17
+ force?: boolean;
18
+ /**
19
+ * Op-specific tag included in the failure log so dashboards can
20
+ * distinguish which op is failing (e.g. `"generate-beat-audio"`).
21
+ * Falls back to a generic `"op failed"` entry when omitted.
22
+ */
23
+ operation?: string;
24
+ /**
25
+ * Soft-fail override for `buildContext` returning undefined. Some
26
+ * ops (e.g. `beatAudio`) historically returned a 200 `{ audio: null }`
27
+ * in that case so the frontend can silently retry. If provided, this
28
+ * callback returns the fallback result instead of the default
29
+ * server_error "Failed to initialize mulmo context".
30
+ */
31
+ onContextMissing?: () => OpResult<T>;
32
+ }
33
+ export declare function buildBeatIdIndex(beats: MulmoBeat[]): Map<string, number>;
34
+ /**
35
+ * Build the per-host mulmoScript server ops instance. One instance per
36
+ * process — it owns the in-flight movie/PDF dedup sets and the
37
+ * generation-state tracker, and binds the injected host backend.
38
+ */
39
+ export declare function createMulmoScriptServerOps(backend: MulmoScriptServerBackend): {
40
+ backend: MulmoScriptServerBackend;
41
+ toStoryRef: (absolutePath: string) => string;
42
+ resolveStory: (filePath: string) => {
43
+ ok: true;
44
+ absolutePath: string;
45
+ } | OpFailure;
46
+ guardStoryWirePath: (filePath: unknown) => OpFailure | null;
47
+ ffmpegGuard: () => OpFailure | null;
48
+ runStoryOp: <T>(filePath: string, options: RunStoryOpOptions<T>, handler: (ctx: {
49
+ absoluteFilePath: string;
50
+ context: StoryContext;
51
+ }) => Promise<OpResult<T>>, deps?: RunStoryOpDeps) => Promise<OpResult<T>>;
52
+ publishGeneration: (chatSessionId: string | undefined, kind: GenerationKind, filePath: string, key: string, finished: boolean, error?: string) => void;
53
+ pendingGenerations: (filePath: string) => MulmoScriptGenerationEvent[];
54
+ beatImageOp: (filePath: string, beatIndex: number) => Promise<OpResult<{
55
+ image: string | null;
56
+ }>>;
57
+ beatAudioOp: (filePath: string, beatIndex: number) => Promise<OpResult<{
58
+ audio: string | null;
59
+ }>>;
60
+ beatMovieOp: (filePath: string, beatIndex: number) => Promise<OpResult<{
61
+ moviePath: string | null;
62
+ }>>;
63
+ characterImageOp: (filePath: string, key: string) => Promise<OpResult<{
64
+ image: string | null;
65
+ }>>;
66
+ movieStatusOp: (filePath: string) => Promise<OpResult<{
67
+ moviePath: string | null;
68
+ }>>;
69
+ pdfStatusOp: (filePath: string) => Promise<OpResult<{
70
+ pdfPath: string | null;
71
+ }>>;
72
+ renderBeatOp: (args: Required<Pick<GenerateOpArgs, "filePath" | "beatIndex">> & GenerateOpArgs) => Promise<OpResult<{
73
+ image: string;
74
+ }>>;
75
+ generateBeatAudioOp: (args: Required<Pick<GenerateOpArgs, "filePath" | "beatIndex">> & GenerateOpArgs) => Promise<OpResult<{
76
+ audio: string;
77
+ }>>;
78
+ renderCharacterOp: (args: Required<Pick<GenerateOpArgs, "filePath" | "key">> & GenerateOpArgs) => Promise<OpResult<{
79
+ image: string;
80
+ }>>;
81
+ uploadBeatImageOp: (filePath: string, beatIndex: number, imageData: string) => Promise<OpResult<{
82
+ image: string;
83
+ }>>;
84
+ uploadCharacterImageOp: (filePath: string, key: string, imageData: string) => Promise<OpResult<{
85
+ image: string;
86
+ }>>;
87
+ inFlightMovies: Set<string>;
88
+ inFlightPdfs: Set<string>;
89
+ runMovieGeneration: (absoluteFilePath: string, onProgressEvent: (event: MovieProgressEvent) => void) => Promise<MovieGenerationResult>;
90
+ runPdfGeneration: (context: StoryContext, onImageBeatDone: (beatIndex: number) => void) => Promise<PdfGenerationResult>;
91
+ generateMovieOp: (filePath: string, chatSessionId: string | undefined) => Promise<OpResult<{
92
+ moviePath: string;
93
+ }>>;
94
+ generatePdfOp: (filePath: string, chatSessionId: string | undefined) => Promise<OpResult<{
95
+ pdfPath: string;
96
+ }>>;
97
+ triggerAutoBackgroundMovie: (absoluteFilePath: string, wireFilePath: string, chatSessionId: string | undefined) => void;
98
+ };
99
+ export type MulmoScriptServerOps = ReturnType<typeof createMulmoScriptServerOps>;
100
+ export {};
101
+ //# sourceMappingURL=ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/server/ops.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare function errorText(err: unknown): string;
2
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
3
+ export declare function stripDataUri(dataUri: string): string;
4
+ /** Realpath-based containment: resolve `relPath` against the ROOT's
5
+ * realpath and require the target's realpath to stay inside it. Returns
6
+ * null on ENOENT or traversal (symlink escapes included). */
7
+ export declare function resolveWithinRoot(rootReal: string, relPath: string): string | null;
8
+ export declare function fileToDataUri(filePath: string, mimeType: string): Promise<string>;
9
+ //# sourceMappingURL=support.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support.d.ts","sourceRoot":"","sources":["../../src/server/support.ts"],"names":[],"mappings":"AAUA,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAQ9C;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;8DAE8D;AAC9D,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAalF;AAID,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGvF"}
@@ -0,0 +1,74 @@
1
+ import type { FileOps } from "gui-chat-protocol";
2
+ import type { MulmoScriptGenerationEvent } from "../core/contract";
3
+ export interface OpFailure {
4
+ ok: false;
5
+ /** REST adapter mapping: bad_request→400, not_found→404,
6
+ * unavailable→503, server_error→500. */
7
+ code: "bad_request" | "not_found" | "server_error" | "unavailable";
8
+ error: string;
9
+ }
10
+ export type OpResult<T> = ({
11
+ ok: true;
12
+ } & T) | OpFailure;
13
+ export interface GenerateOpArgs {
14
+ filePath: string;
15
+ beatIndex?: number;
16
+ key?: string;
17
+ force?: boolean;
18
+ chatSessionId?: string;
19
+ }
20
+ export type MovieGenerationResult = {
21
+ ok: true;
22
+ outputPath: string;
23
+ } | {
24
+ ok: false;
25
+ error: string;
26
+ };
27
+ export type PdfGenerationResult = {
28
+ ok: true;
29
+ outputPath: string;
30
+ } | {
31
+ ok: false;
32
+ error: string;
33
+ };
34
+ export interface MovieProgressEvent {
35
+ kind: "image" | "audio";
36
+ beatIndex: number;
37
+ }
38
+ /** Host logger; every entry is already namespaced to mulmoScript by the
39
+ * package, so hosts just bind their own prefix/transport. */
40
+ export interface MulmoScriptServerLog {
41
+ info: (message: string, data?: Record<string, unknown>) => void;
42
+ warn: (message: string, data?: Record<string, unknown>) => void;
43
+ error: (message: string, data?: Record<string, unknown>) => void;
44
+ }
45
+ /**
46
+ * Host capabilities the server ops run against. Only genuinely
47
+ * host-specific transport lives here — the mulmocast orchestration, path
48
+ * containment, and generation-state tracking are all in-package.
49
+ */
50
+ export interface MulmoScriptServerBackend {
51
+ /** Absolute path of the stories directory (`<workspace>/artifacts/stories`).
52
+ * May not exist yet — the ops lazily create + realpath it. */
53
+ storiesDir: string;
54
+ /** Shared artifacts FileOps (rooted at `<workspace>/artifacts`) for the
55
+ * save / reopen / update dispatch kinds (phase-1 core executes). */
56
+ artifacts: FileOps;
57
+ /** Atomic file write (tmp alongside destination + rename; parent dirs
58
+ * created). Hosts inject their hardened implementation. */
59
+ writeFileAtomic: (absolutePath: string, data: string | Uint8Array) => Promise<void>;
60
+ /** ffmpeg availability probe. `false` blocks render/movie/PDF ops with a
61
+ * clear message; `true`/`undefined` proceeds (a boot probe may not have
62
+ * completed yet — never block on the startup window). */
63
+ isFfmpegAvailable?: () => boolean | undefined;
64
+ /**
65
+ * Generation fan-out (session channels, UI pubsub). Called on EDGE
66
+ * transitions only — first start / last finish of concurrent same-key
67
+ * runs — plus the finish-only per-beat pulses from the movie/PDF
68
+ * pipelines. `chatSessionId` is undefined for callers outside a chat
69
+ * session. The package keeps the in-flight snapshot itself.
70
+ */
71
+ onGenerationEvent?: (chatSessionId: string | undefined, event: MulmoScriptGenerationEvent) => void;
72
+ log?: MulmoScriptServerLog;
73
+ }
74
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAEnE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,KAAK,CAAC;IACV;6CACyC;IACzC,IAAI,EAAE,aAAa,GAAG,WAAW,GAAG,cAAc,GAAG,aAAa,CAAC;IACnE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,qBAAqB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACpG,MAAM,MAAM,mBAAmB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;8DAC8D;AAC9D,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAClE;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC;mEAC+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB;yEACqE;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB;gEAC4D;IAC5D,eAAe,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpF;;8DAE0D;IAC1D,iBAAiB,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC9C;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACnG,GAAG,CAAC,EAAE,oBAAoB,CAAC;CAC5B"}