@mengine/medeo-tool 1.0.1-alpha.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/index.mjs ADDED
@@ -0,0 +1,568 @@
1
+ import { i as renderCompactProjection, n as collectAffectedPartIds, r as renderPreview, t as EditSandboxSession } from "./script-session-B8fc9Ccb.mjs";
2
+ import { MengineDocSession, MengineHttpClient, ValidationError, createPlainMemoryAdapter, replayJournal } from "@mengine/medeo-client";
3
+ import { Worker } from "node:worker_threads";
4
+ import { randomUUID } from "node:crypto";
5
+ //#region src/sandbox/node-host.ts
6
+ const DEFAULT_TIMEOUT_MS = 2e3;
7
+ const DEFAULT_MEMORY_MB = 256;
8
+ /**
9
+ * Source runs load the checked-in TypeScript worker; packed runs load the
10
+ * sibling JavaScript chunk emitted as a second package entry. Keeping this
11
+ * branch explicit avoids shipping a `dist/*.ts` URL in the npm artifact.
12
+ */
13
+ function sourceSibling(fileName) {
14
+ const selfUrl = new URL(import.meta.url);
15
+ const extension = selfUrl.pathname.endsWith(".ts") ? "ts" : "mjs";
16
+ return new URL(`./${fileName}.${extension}`, selfUrl);
17
+ }
18
+ /** Run `script` against a forked document snapshot; always resolves (never rejects). */
19
+ function runEditScript(options) {
20
+ let scriptStartedAt = performance.now();
21
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
22
+ const memoryLimitMb = options.memoryLimitMb ?? DEFAULT_MEMORY_MB;
23
+ const workerEntryUrl = options.workerEntryUrl ?? sourceSibling("worker-entry");
24
+ const resolveRegisterUrl = sourceSibling("node-esm-resolve-register");
25
+ const ops = [];
26
+ const logs = [];
27
+ return new Promise((resolve) => {
28
+ let settled = false;
29
+ let timedOut = false;
30
+ let timer;
31
+ const worker = new Worker(workerEntryUrl, {
32
+ workerData: {
33
+ document: options.document,
34
+ script: options.script,
35
+ inputs: options.inputs,
36
+ idLabel: options.idLabel
37
+ },
38
+ execArgv: resolveRegisterUrl.pathname.endsWith(".ts") ? [
39
+ "--experimental-transform-types",
40
+ "--disable-warning=ExperimentalWarning",
41
+ `--import=${resolveRegisterUrl.href}`
42
+ ] : [],
43
+ resourceLimits: { maxOldGenerationSizeMb: memoryLimitMb }
44
+ });
45
+ /** Start wall-clock timeout only after worker signals script is about to run. */
46
+ const armTimeout = () => {
47
+ if (settled || timer != null) return;
48
+ timer = setTimeout(() => {
49
+ timedOut = true;
50
+ worker.terminate();
51
+ finish({
52
+ ok: false,
53
+ phase: "timeout",
54
+ error: { message: `edit script exceeded timeout of ${timeoutMs}ms` },
55
+ partial: {
56
+ ops: ops.slice(),
57
+ logs: logs.slice()
58
+ }
59
+ });
60
+ }, timeoutMs);
61
+ };
62
+ const finish = (result) => {
63
+ if (settled) return;
64
+ settled = true;
65
+ if (timer != null) clearTimeout(timer);
66
+ worker.terminate();
67
+ if (result.ok) resolve({
68
+ ...result,
69
+ durationMs: performance.now() - scriptStartedAt
70
+ });
71
+ else resolve(result);
72
+ };
73
+ worker.on("message", (message) => {
74
+ if (settled) return;
75
+ if (message.t === "ready") {
76
+ scriptStartedAt = performance.now();
77
+ armTimeout();
78
+ return;
79
+ }
80
+ if (message.t === "entry") {
81
+ ops.push(message.entry);
82
+ return;
83
+ }
84
+ if (message.t === "log") {
85
+ logs.push(message.line);
86
+ return;
87
+ }
88
+ if (message.t === "truncate") {
89
+ ops.length = Math.max(0, Math.min(message.index, ops.length));
90
+ return;
91
+ }
92
+ if (message.t === "done") {
93
+ if (message.opsCount !== ops.length) {
94
+ finish({
95
+ ok: false,
96
+ phase: "runtime",
97
+ error: { message: `opsCount mismatch: worker reported ${message.opsCount}, host collected ${ops.length}` },
98
+ partial: {
99
+ ops: ops.slice(),
100
+ logs: logs.slice()
101
+ }
102
+ });
103
+ return;
104
+ }
105
+ finish({
106
+ ok: true,
107
+ plan: {
108
+ doc_id: options.document.meta.draft_id ?? "",
109
+ base_version: options.baseVersion,
110
+ ops: ops.slice(),
111
+ preview: message.preview,
112
+ logs: logs.slice()
113
+ },
114
+ durationMs: 0
115
+ });
116
+ return;
117
+ }
118
+ if (message.t === "fail") finish({
119
+ ok: false,
120
+ phase: message.phase,
121
+ error: message.error,
122
+ partial: {
123
+ ops: ops.slice(),
124
+ logs: logs.slice()
125
+ }
126
+ });
127
+ });
128
+ worker.on("error", (error) => {
129
+ if (settled) return;
130
+ const text = error.message ?? String(error);
131
+ finish({
132
+ ok: false,
133
+ phase: /memory limit/i.test(text) ? "memory" : "runtime",
134
+ error: {
135
+ message: text,
136
+ stack: error.stack
137
+ },
138
+ partial: {
139
+ ops: ops.slice(),
140
+ logs: logs.slice()
141
+ }
142
+ });
143
+ });
144
+ worker.on("exit", (code) => {
145
+ if (settled) return;
146
+ if (timedOut) return;
147
+ finish({
148
+ ok: false,
149
+ phase: "runtime",
150
+ error: { message: `worker exited with code ${code ?? "null"} before completion` },
151
+ partial: {
152
+ ops: ops.slice(),
153
+ logs: logs.slice()
154
+ }
155
+ });
156
+ });
157
+ });
158
+ }
159
+ //#endregion
160
+ //#region src/prompt.ts
161
+ const MEDEO_TOOL_DESCRIPTION = `
162
+ Edit a Medeo video document through a deterministic, side-effect-free JavaScript sandbox.
163
+
164
+ Operations:
165
+ - snapshot: return the compact timeline projection and opaque base version.
166
+ - run-edit-script: execute JavaScript against a forked snapshot. Inspect timeline.*, compute coordinates, and call edit.* methods in one script. The sandbox has no network, storage, clock, or generation access. Pass materialized asset/speech facts through inputs. A successful run returns preview, logs, base_version, and plan_id — not the full op journal.
167
+ - commit-plan: replay a cached plan_id into the live MengineDocSession through SemanticEditor. Use validation=version for all-or-nothing commit, or preflight to localize an op conflict after concurrent edits.
168
+
169
+ Default flow: snapshot → run-edit-script with auto_commit=false → inspect preview → commit-plan. Use auto_commit=true only for low-risk edits when the host does not need user confirmation. On version mismatch, rerun snapshot and the script; never try to patch a rejected journal by hand.
170
+ `.trim();
171
+ //#endregion
172
+ //#region src/schema.ts
173
+ const MEDEO_TOOL_NAME = "medeo";
174
+ /**
175
+ * JSON Schema for the host-facing three-op `medeo` tool surface.
176
+ *
177
+ * The schema intentionally does not return or accept the full op journal:
178
+ * journals stay in the tool process and are referenced by `plan_id`. This keeps
179
+ * large intermediate products out of model context while preserving the exact
180
+ * journal used for commit.
181
+ */
182
+ const MEDEO_TOOL_PARAMETERS = {
183
+ type: "object",
184
+ required: ["op", "doc_id"],
185
+ additionalProperties: false,
186
+ properties: {
187
+ op: {
188
+ type: "string",
189
+ enum: [
190
+ "snapshot",
191
+ "run-edit-script",
192
+ "commit-plan"
193
+ ],
194
+ description: "Which Medeo document operation to run."
195
+ },
196
+ doc_id: {
197
+ type: "string",
198
+ minLength: 1,
199
+ description: "Medeo document id. Copy it from the host context; never invent it."
200
+ },
201
+ script: {
202
+ type: "string",
203
+ minLength: 1,
204
+ description: "JavaScript body for run-edit-script. It receives edit, timeline, checkpoint, rollbackTo, inputs, and console; perform all calculations in the script."
205
+ },
206
+ inputs: {
207
+ type: "object",
208
+ description: "Pre-materialized, side-effect-free values passed into the script. Generation and network IO must happen in the host before this call."
209
+ },
210
+ timeout_ms: {
211
+ type: "integer",
212
+ minimum: 1,
213
+ description: "Maximum script wall-clock time after worker startup (default 2000)."
214
+ },
215
+ memory_limit_mb: {
216
+ type: "integer",
217
+ minimum: 16,
218
+ description: "Worker old-generation memory ceiling in MB (default 256)."
219
+ },
220
+ auto_commit: {
221
+ type: "boolean",
222
+ description: "Commit the returned plan immediately after the sandbox succeeds. Default false: return preview plus plan_id for explicit commit."
223
+ },
224
+ plan_id: {
225
+ type: "string",
226
+ minLength: 1,
227
+ description: "Plan id returned by run-edit-script; required by commit-plan."
228
+ },
229
+ validation: {
230
+ type: "string",
231
+ enum: ["version", "preflight"],
232
+ description: "commit-plan mode: version rejects any concurrent change; preflight revalidates each op against the current snapshot."
233
+ }
234
+ },
235
+ oneOf: [
236
+ {
237
+ required: ["op", "doc_id"],
238
+ properties: {
239
+ op: { const: "snapshot" },
240
+ doc_id: { $ref: "#/properties/doc_id" }
241
+ },
242
+ additionalProperties: false
243
+ },
244
+ {
245
+ required: [
246
+ "op",
247
+ "doc_id",
248
+ "script"
249
+ ],
250
+ properties: {
251
+ op: { const: "run-edit-script" },
252
+ doc_id: { $ref: "#/properties/doc_id" },
253
+ script: { $ref: "#/properties/script" },
254
+ inputs: { $ref: "#/properties/inputs" },
255
+ timeout_ms: { $ref: "#/properties/timeout_ms" },
256
+ memory_limit_mb: { $ref: "#/properties/memory_limit_mb" },
257
+ auto_commit: { $ref: "#/properties/auto_commit" }
258
+ },
259
+ additionalProperties: false
260
+ },
261
+ {
262
+ required: [
263
+ "op",
264
+ "doc_id",
265
+ "plan_id"
266
+ ],
267
+ properties: {
268
+ op: { const: "commit-plan" },
269
+ doc_id: { $ref: "#/properties/doc_id" },
270
+ plan_id: { $ref: "#/properties/plan_id" },
271
+ validation: { $ref: "#/properties/validation" }
272
+ },
273
+ additionalProperties: false
274
+ }
275
+ ]
276
+ };
277
+ //#endregion
278
+ //#region src/session/commit-plan.ts
279
+ /**
280
+ * Replay a sandbox journal into a live session through its document adapter
281
+ * (SemanticEditor → Loro → mengine-server).
282
+ *
283
+ * - Default / `{ validation: 'version' }`: if `session.version()` ≠
284
+ * `plan.base_version`, reject with zero writes.
285
+ * - `{ validation: 'preflight' }`: skip the version gate; revalidate each op
286
+ * against a PlainMemoryAdapter seeded from the current live snapshot, then
287
+ * replay for real. A SchemaValidator failure becomes `op_conflict` with the
288
+ * failing entry's index. Journal integrity errors (unrecorded/unconsumed
289
+ * ids) still propagate as throws in both modes.
290
+ */
291
+ async function commitPlan(session, plan, options) {
292
+ if (options?.validation === "preflight") return commitPlanPreflight(session, plan);
293
+ const actual = session.version();
294
+ if (actual !== plan.base_version) return {
295
+ kind: "rejected",
296
+ reason: "version_mismatch",
297
+ expected: plan.base_version,
298
+ actual
299
+ };
300
+ await replayJournal(session.documentAdapter, plan.ops);
301
+ return {
302
+ kind: "committed",
303
+ ops_applied: plan.ops.length
304
+ };
305
+ }
306
+ /**
307
+ * Phase-2 path: scratch revalidation then real replay. Each entry is driven
308
+ * through `replayJournal` alone so a ValidationError maps to a stable index;
309
+ * integrity throws are not wrapped.
310
+ */
311
+ async function commitPlanPreflight(session, plan) {
312
+ const scratch = createPlainMemoryAdapter(session.snapshot());
313
+ for (let index = 0; index < plan.ops.length; index++) {
314
+ const entry = plan.ops[index];
315
+ if (entry == null) continue;
316
+ try {
317
+ await replayJournal(scratch, [entry]);
318
+ } catch (error) {
319
+ if (error instanceof ValidationError) return opConflict(index, entry.kind, error.message);
320
+ throw error;
321
+ }
322
+ }
323
+ for (let index = 0; index < plan.ops.length; index++) {
324
+ const entry = plan.ops[index];
325
+ if (entry == null) continue;
326
+ try {
327
+ await replayJournal(session.documentAdapter, [entry]);
328
+ } catch (error) {
329
+ if (error instanceof ValidationError) return opConflict(index, entry.kind, `real replay: ${error.message}`);
330
+ throw error;
331
+ }
332
+ }
333
+ return {
334
+ kind: "committed",
335
+ ops_applied: plan.ops.length
336
+ };
337
+ }
338
+ function opConflict(index, op_kind, message) {
339
+ return {
340
+ kind: "rejected",
341
+ reason: "op_conflict",
342
+ index,
343
+ op_kind,
344
+ message
345
+ };
346
+ }
347
+ //#endregion
348
+ //#region src/host-tool.ts
349
+ const DEFAULT_MAX_PLANS = 16;
350
+ function isRecord(value) {
351
+ return value !== null && typeof value === "object" && !Array.isArray(value);
352
+ }
353
+ function optionalContext(value, docId) {
354
+ if (value === void 0) return void 0;
355
+ return typeof value === "function" ? value(docId) : value;
356
+ }
357
+ function requiredContext(value, docId, field) {
358
+ const resolved = optionalContext(value, docId)?.trim();
359
+ if (resolved == null || resolved.length === 0) throw new Error(`${field} must resolve to a non-empty string for doc ${docId}`);
360
+ return resolved;
361
+ }
362
+ function parseInput(value) {
363
+ if (!isRecord(value)) throw new Error("input must be an object");
364
+ const op = value.op;
365
+ const docId = value.doc_id;
366
+ if (typeof op !== "string") throw new Error("op must be a string");
367
+ if (typeof docId !== "string" || docId.trim().length === 0) throw new Error("doc_id must be a non-empty string");
368
+ if (op === "snapshot") return {
369
+ op,
370
+ doc_id: docId
371
+ };
372
+ if (op === "run-edit-script") {
373
+ if (typeof value.script !== "string" || value.script.length === 0) throw new Error("script must be a non-empty string");
374
+ if (value.inputs !== void 0 && !isRecord(value.inputs)) throw new Error("inputs must be an object");
375
+ const timeoutMs = value.timeout_ms;
376
+ if (timeoutMs !== void 0 && (typeof timeoutMs !== "number" || !Number.isInteger(timeoutMs) || timeoutMs <= 0)) throw new Error("timeout_ms must be a positive integer");
377
+ const memoryLimitMb = value.memory_limit_mb;
378
+ if (memoryLimitMb !== void 0 && (typeof memoryLimitMb !== "number" || !Number.isInteger(memoryLimitMb) || memoryLimitMb < 16)) throw new Error("memory_limit_mb must be an integer >= 16");
379
+ if (value.auto_commit !== void 0 && typeof value.auto_commit !== "boolean") throw new Error("auto_commit must be a boolean");
380
+ return {
381
+ op,
382
+ doc_id: docId,
383
+ script: value.script,
384
+ ...value.inputs !== void 0 ? { inputs: value.inputs } : {},
385
+ ...timeoutMs !== void 0 ? { timeout_ms: timeoutMs } : {},
386
+ ...memoryLimitMb !== void 0 ? { memory_limit_mb: memoryLimitMb } : {},
387
+ ...value.auto_commit !== void 0 ? { auto_commit: value.auto_commit } : {}
388
+ };
389
+ }
390
+ if (op === "commit-plan") {
391
+ if (typeof value.plan_id !== "string" || value.plan_id.length === 0) throw new Error("plan_id must be a non-empty string");
392
+ if (value.validation !== void 0 && value.validation !== "version" && value.validation !== "preflight") throw new Error("validation must be \"version\" or \"preflight\"");
393
+ return {
394
+ op,
395
+ doc_id: docId,
396
+ plan_id: value.plan_id,
397
+ ...value.validation !== void 0 ? { validation: value.validation } : {}
398
+ };
399
+ }
400
+ throw new Error(`unknown op: ${op}`);
401
+ }
402
+ /**
403
+ * Create the self-contained Medeo LLM tool.
404
+ *
405
+ * The package owns session construction, compact projection, sandbox execution,
406
+ * plan caching, commit, and shutdown. The host supplies only environment facts:
407
+ * HTTP origin, credentials, fetch implementation, and a stable peer id.
408
+ */
409
+ function createMedeoTool(options) {
410
+ const sessions = /* @__PURE__ */ new Map();
411
+ const plans = /* @__PURE__ */ new Map();
412
+ const maxPlans = options.maxPlans ?? DEFAULT_MAX_PLANS;
413
+ let closed = false;
414
+ async function getSession(docId) {
415
+ if (closed) throw new Error("medeo tool is closed");
416
+ const existing = sessions.get(docId);
417
+ if (existing != null) return await existing;
418
+ const created = (async () => {
419
+ const client = new MengineHttpClient({
420
+ docId,
421
+ httpOrigin: requiredContext(options.httpOrigin, docId, "httpOrigin"),
422
+ ...options.authToken !== void 0 ? { authToken: () => optionalContext(options.authToken, docId) } : {},
423
+ ...options.userId !== void 0 ? { userId: () => optionalContext(options.userId, docId) } : {},
424
+ ...options.fetchImpl !== void 0 ? { fetchImpl: options.fetchImpl } : {}
425
+ });
426
+ const peerId = optionalContext(options.peerId, docId);
427
+ const session = new MengineDocSession({
428
+ docId,
429
+ client,
430
+ ...peerId !== void 0 ? { peerId } : {},
431
+ ...options.sseReconnectDelayMs !== void 0 ? { sseReconnectDelayMs: options.sseReconnectDelayMs } : {}
432
+ });
433
+ try {
434
+ await session.start();
435
+ return session;
436
+ } catch (error) {
437
+ session.destroy();
438
+ throw error;
439
+ }
440
+ })();
441
+ sessions.set(docId, created);
442
+ try {
443
+ return await created;
444
+ } catch (error) {
445
+ if (sessions.get(docId) === created) sessions.delete(docId);
446
+ throw error;
447
+ }
448
+ }
449
+ function rememberPlan(docId, plan) {
450
+ const planId = randomUUID();
451
+ plans.set(planId, {
452
+ docId,
453
+ plan
454
+ });
455
+ while (plans.size > maxPlans) {
456
+ const oldest = plans.keys().next().value;
457
+ if (oldest === void 0) break;
458
+ plans.delete(oldest);
459
+ }
460
+ return planId;
461
+ }
462
+ async function snapshot(input) {
463
+ const session = await getSession(input.doc_id);
464
+ const document = session.snapshot();
465
+ return {
466
+ ok: true,
467
+ op: "snapshot",
468
+ doc_id: input.doc_id,
469
+ version: session.version(),
470
+ preview: renderCompactProjection(document)
471
+ };
472
+ }
473
+ async function run(input) {
474
+ const session = await getSession(input.doc_id);
475
+ const document = session.snapshot();
476
+ const baseVersion = session.version();
477
+ const result = await runEditScript({
478
+ document,
479
+ baseVersion,
480
+ script: input.script,
481
+ ...input.inputs !== void 0 ? { inputs: input.inputs } : {},
482
+ timeoutMs: input.timeout_ms ?? options.sandbox?.timeoutMs,
483
+ memoryLimitMb: input.memory_limit_mb ?? options.sandbox?.memoryLimitMb
484
+ });
485
+ if (!result.ok) return {
486
+ ok: false,
487
+ op: "run-edit-script",
488
+ doc_id: input.doc_id,
489
+ phase: result.phase,
490
+ error: result.error,
491
+ partial: {
492
+ ops_count: result.partial.ops.length,
493
+ logs: result.partial.logs
494
+ }
495
+ };
496
+ const planId = rememberPlan(input.doc_id, result.plan);
497
+ const base = {
498
+ ok: true,
499
+ op: "run-edit-script",
500
+ doc_id: input.doc_id,
501
+ plan_id: planId,
502
+ base_version: baseVersion,
503
+ ops_count: result.plan.ops.length,
504
+ preview: result.plan.preview,
505
+ logs: result.plan.logs,
506
+ duration_ms: result.durationMs
507
+ };
508
+ if (input.auto_commit !== true) return base;
509
+ const commit = await commitPlan(session, result.plan);
510
+ return {
511
+ ...base,
512
+ committed: commit.kind === "committed",
513
+ commit_result: commit
514
+ };
515
+ }
516
+ async function commit(input) {
517
+ const cached = plans.get(input.plan_id);
518
+ if (cached == null || cached.docId !== input.doc_id) throw new Error(`plan_id ${input.plan_id} is not available for doc ${input.doc_id}`);
519
+ const session = await getSession(input.doc_id);
520
+ const commitOptions = input.validation === void 0 ? void 0 : { validation: input.validation };
521
+ const result = await commitPlan(session, cached.plan, commitOptions);
522
+ return {
523
+ ok: true,
524
+ op: "commit-plan",
525
+ doc_id: input.doc_id,
526
+ plan_id: input.plan_id,
527
+ committed: result.kind === "committed",
528
+ result
529
+ };
530
+ }
531
+ return {
532
+ name: MEDEO_TOOL_NAME,
533
+ description: MEDEO_TOOL_DESCRIPTION,
534
+ parameters: MEDEO_TOOL_PARAMETERS,
535
+ async handle(input) {
536
+ try {
537
+ const parsed = parseInput(input);
538
+ if (parsed.op === "snapshot") return await snapshot(parsed);
539
+ if (parsed.op === "run-edit-script") return await run(parsed);
540
+ return await commit(parsed);
541
+ } catch (error) {
542
+ return {
543
+ ok: false,
544
+ op: isRecord(input) && typeof input.op === "string" ? input.op : "snapshot",
545
+ error: error instanceof Error ? error.message : String(error)
546
+ };
547
+ }
548
+ },
549
+ async close() {
550
+ closed = true;
551
+ const opening = [...sessions.values()];
552
+ sessions.clear();
553
+ plans.clear();
554
+ const errors = [];
555
+ for (const sessionPromise of opening) try {
556
+ (await sessionPromise).destroy();
557
+ } catch (error) {
558
+ errors.push(error);
559
+ }
560
+ if (errors.length === 1) throw errors[0];
561
+ if (errors.length > 1) throw new AggregateError(errors, "failed to close medeo tool sessions");
562
+ }
563
+ };
564
+ }
565
+ //#endregion
566
+ export { EditSandboxSession, MEDEO_TOOL_DESCRIPTION, MEDEO_TOOL_NAME, MEDEO_TOOL_PARAMETERS, collectAffectedPartIds, commitPlan, createMedeoTool, renderCompactProjection, renderPreview, runEditScript };
567
+
568
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/sandbox/node-host.ts","../src/prompt.ts","../src/schema.ts","../src/session/commit-plan.ts","../src/host-tool.ts"],"sourcesContent":["/// <reference types=\"node\" />\n\nimport { Worker } from 'node:worker_threads';\n\nimport type { JournalEntry, VideoDocument } from '@mengine/medeo-client';\n\nimport type { ChangePlan } from './script-session.ts';\n\n/**\n * Host API for running an agent edit script in an isolated Node worker.\n *\n * Requires Node.js >= 24.15 (engines) so the worker can load TypeScript via\n * `--experimental-transform-types`. Do not inherit `process.execArgv` — vitest\n * injects loaders that break worker boot.\n */\n\nexport interface RunEditScriptOptions {\n document: VideoDocument;\n baseVersion: string;\n script: string;\n inputs?: Record<string, unknown>;\n /** Deterministic id mint label for tests; omit to use the default ULID factory. */\n idLabel?: string;\n /** Hard wall-clock timeout; default 2000 ms. */\n timeoutMs?: number;\n /** V8 old-generation ceiling for the worker; default 256 MB. */\n memoryLimitMb?: number;\n /** Override worker module URL (defaults to sibling `worker-entry.ts`). */\n workerEntryUrl?: URL;\n}\n\nexport type EditScriptResult =\n | {\n ok: true;\n plan: ChangePlan;\n /** Script execution time after worker readiness; excludes cold start. */\n durationMs: number;\n }\n | {\n ok: false;\n phase: 'parse' | 'runtime' | 'timeout' | 'memory';\n error: { message: string; line?: number; column?: number; stack?: string };\n partial: { ops: readonly JournalEntry[]; logs: string[] };\n };\n\ntype WorkerMessage =\n | { t: 'ready' }\n | { t: 'entry'; entry: JournalEntry }\n | { t: 'log'; line: string }\n | { t: 'truncate'; index: number }\n | { t: 'done'; preview: string; opsCount: number }\n | {\n t: 'fail';\n phase: 'parse' | 'runtime';\n error: { message: string; line?: number; column?: number; stack?: string };\n };\n\nconst DEFAULT_TIMEOUT_MS = 2000;\nconst DEFAULT_MEMORY_MB = 256;\n\n/**\n * Source runs load the checked-in TypeScript worker; packed runs load the\n * sibling JavaScript chunk emitted as a second package entry. Keeping this\n * branch explicit avoids shipping a `dist/*.ts` URL in the npm artifact.\n */\nfunction sourceSibling(fileName: string): URL {\n const selfUrl = new URL(import.meta.url);\n const extension = selfUrl.pathname.endsWith('.ts') ? 'ts' : 'mjs';\n return new URL(`./${fileName}.${extension}`, selfUrl);\n}\n\n/** Run `script` against a forked document snapshot; always resolves (never rejects). */\nexport function runEditScript(options: RunEditScriptOptions): Promise<EditScriptResult> {\n // Set when the worker has loaded its bundle and is about to invoke the script.\n // Keep this clock separate from worker boot so success timing matches the\n // timeout boundary and excludes cold-start/module-loading cost.\n let scriptStartedAt = performance.now();\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const memoryLimitMb = options.memoryLimitMb ?? DEFAULT_MEMORY_MB;\n const workerEntryUrl = options.workerEntryUrl ?? sourceSibling('worker-entry');\n const resolveRegisterUrl = sourceSibling('node-esm-resolve-register');\n\n const ops: JournalEntry[] = [];\n const logs: string[] = [];\n\n return new Promise<EditScriptResult>((resolve) => {\n let settled = false;\n let timedOut = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const worker = new Worker(workerEntryUrl, {\n workerData: {\n document: options.document,\n script: options.script,\n inputs: options.inputs,\n idLabel: options.idLabel,\n },\n // Explicit argv only — never inherit process.execArgv (vitest loaders).\n // Source workers need TypeScript transform plus the resolver hook for\n // workspace packages that still use extensionless directory imports.\n // Packed JavaScript workers already contain those dependencies.\n execArgv: resolveRegisterUrl.pathname.endsWith('.ts')\n ? [\n '--experimental-transform-types',\n '--disable-warning=ExperimentalWarning',\n `--import=${resolveRegisterUrl.href}`,\n ]\n : [],\n resourceLimits: { maxOldGenerationSizeMb: memoryLimitMb },\n });\n\n /** Start wall-clock timeout only after worker signals script is about to run. */\n const armTimeout = (): void => {\n if (settled || timer != null) return;\n timer = setTimeout(() => {\n timedOut = true;\n void worker.terminate();\n finish({\n ok: false,\n phase: 'timeout',\n error: { message: `edit script exceeded timeout of ${timeoutMs}ms` },\n partial: { ops: ops.slice(), logs: logs.slice() },\n });\n }, timeoutMs);\n };\n\n const finish = (result: EditScriptResult): void => {\n if (settled) return;\n settled = true;\n if (timer != null) clearTimeout(timer);\n void worker.terminate();\n if (result.ok) {\n resolve({ ...result, durationMs: performance.now() - scriptStartedAt });\n } else {\n resolve(result);\n }\n };\n\n worker.on('message', (message: WorkerMessage) => {\n if (settled) return;\n if (message.t === 'ready') {\n scriptStartedAt = performance.now();\n armTimeout();\n return;\n }\n if (message.t === 'entry') {\n ops.push(message.entry);\n return;\n }\n if (message.t === 'log') {\n logs.push(message.line);\n return;\n }\n if (message.t === 'truncate') {\n ops.length = Math.max(0, Math.min(message.index, ops.length));\n return;\n }\n if (message.t === 'done') {\n if (message.opsCount !== ops.length) {\n finish({\n ok: false,\n phase: 'runtime',\n error: {\n message: `opsCount mismatch: worker reported ${message.opsCount}, host collected ${ops.length}`,\n },\n partial: { ops: ops.slice(), logs: logs.slice() },\n });\n return;\n }\n finish({\n ok: true,\n plan: {\n doc_id: options.document.meta.draft_id ?? '',\n base_version: options.baseVersion,\n ops: ops.slice(),\n preview: message.preview,\n logs: logs.slice(),\n },\n durationMs: 0,\n });\n return;\n }\n if (message.t === 'fail') {\n finish({\n ok: false,\n phase: message.phase,\n error: message.error,\n partial: { ops: ops.slice(), logs: logs.slice() },\n });\n }\n });\n\n worker.on('error', (error: Error) => {\n if (settled) return;\n const text = error.message ?? String(error);\n const phase = /memory limit/i.test(text) ? 'memory' : 'runtime';\n finish({\n ok: false,\n phase,\n error: { message: text, stack: error.stack },\n partial: { ops: ops.slice(), logs: logs.slice() },\n });\n });\n\n worker.on('exit', (code: number) => {\n if (settled) return;\n if (timedOut) return;\n finish({\n ok: false,\n phase: 'runtime',\n error: { message: `worker exited with code ${code ?? 'null'} before completion` },\n partial: { ops: ops.slice(), logs: logs.slice() },\n });\n });\n });\n}\n","export const MEDEO_TOOL_DESCRIPTION = `\nEdit a Medeo video document through a deterministic, side-effect-free JavaScript sandbox.\n\nOperations:\n- snapshot: return the compact timeline projection and opaque base version.\n- run-edit-script: execute JavaScript against a forked snapshot. Inspect timeline.*, compute coordinates, and call edit.* methods in one script. The sandbox has no network, storage, clock, or generation access. Pass materialized asset/speech facts through inputs. A successful run returns preview, logs, base_version, and plan_id — not the full op journal.\n- commit-plan: replay a cached plan_id into the live MengineDocSession through SemanticEditor. Use validation=version for all-or-nothing commit, or preflight to localize an op conflict after concurrent edits.\n\nDefault flow: snapshot → run-edit-script with auto_commit=false → inspect preview → commit-plan. Use auto_commit=true only for low-risk edits when the host does not need user confirmation. On version mismatch, rerun snapshot and the script; never try to patch a rejected journal by hand.\n`.trim();\n","export const MEDEO_TOOL_NAME = 'medeo';\n\nexport type MedeoToolOp = 'snapshot' | 'run-edit-script' | 'commit-plan';\n\n/**\n * JSON Schema for the host-facing three-op `medeo` tool surface.\n *\n * The schema intentionally does not return or accept the full op journal:\n * journals stay in the tool process and are referenced by `plan_id`. This keeps\n * large intermediate products out of model context while preserving the exact\n * journal used for commit.\n */\nexport const MEDEO_TOOL_PARAMETERS = {\n type: 'object',\n required: ['op', 'doc_id'],\n additionalProperties: false,\n properties: {\n op: {\n type: 'string',\n enum: ['snapshot', 'run-edit-script', 'commit-plan'],\n description: 'Which Medeo document operation to run.',\n },\n doc_id: {\n type: 'string',\n minLength: 1,\n description: 'Medeo document id. Copy it from the host context; never invent it.',\n },\n script: {\n type: 'string',\n minLength: 1,\n description:\n 'JavaScript body for run-edit-script. It receives edit, timeline, checkpoint, rollbackTo, inputs, and console; perform all calculations in the script.',\n },\n inputs: {\n type: 'object',\n description:\n 'Pre-materialized, side-effect-free values passed into the script. Generation and network IO must happen in the host before this call.',\n },\n timeout_ms: {\n type: 'integer',\n minimum: 1,\n description: 'Maximum script wall-clock time after worker startup (default 2000).',\n },\n memory_limit_mb: {\n type: 'integer',\n minimum: 16,\n description: 'Worker old-generation memory ceiling in MB (default 256).',\n },\n auto_commit: {\n type: 'boolean',\n description:\n 'Commit the returned plan immediately after the sandbox succeeds. Default false: return preview plus plan_id for explicit commit.',\n },\n plan_id: {\n type: 'string',\n minLength: 1,\n description: 'Plan id returned by run-edit-script; required by commit-plan.',\n },\n validation: {\n type: 'string',\n enum: ['version', 'preflight'],\n description:\n 'commit-plan mode: version rejects any concurrent change; preflight revalidates each op against the current snapshot.',\n },\n },\n oneOf: [\n {\n required: ['op', 'doc_id'],\n properties: {\n op: { const: 'snapshot' },\n doc_id: { $ref: '#/properties/doc_id' },\n },\n additionalProperties: false,\n },\n {\n required: ['op', 'doc_id', 'script'],\n properties: {\n op: { const: 'run-edit-script' },\n doc_id: { $ref: '#/properties/doc_id' },\n script: { $ref: '#/properties/script' },\n inputs: { $ref: '#/properties/inputs' },\n timeout_ms: { $ref: '#/properties/timeout_ms' },\n memory_limit_mb: { $ref: '#/properties/memory_limit_mb' },\n auto_commit: { $ref: '#/properties/auto_commit' },\n },\n additionalProperties: false,\n },\n {\n required: ['op', 'doc_id', 'plan_id'],\n properties: {\n op: { const: 'commit-plan' },\n doc_id: { $ref: '#/properties/doc_id' },\n plan_id: { $ref: '#/properties/plan_id' },\n validation: { $ref: '#/properties/validation' },\n },\n additionalProperties: false,\n },\n ],\n} as const;\n","import {\n createPlainMemoryAdapter,\n replayJournal,\n ValidationError,\n type JournalEntry,\n type MengineDocSession,\n type SemanticOpName,\n} from '@mengine/medeo-client';\n\n/**\n * A sandbox journal plus the opaque version token taken at fork time.\n * `commitPlan` rejects the whole plan when the live session has moved on\n * (phase-1 version gate), or localizes a business conflict to a journal\n * entry under `{ validation: 'preflight' }`.\n */\nexport interface CommitPlan {\n /** `session.version()` at the moment the sandbox was forked. */\n base_version: string;\n ops: readonly JournalEntry[];\n}\n\nexport type CommitPlanResult =\n | { kind: 'committed'; ops_applied: number }\n | { kind: 'rejected'; reason: 'version_mismatch'; expected: string; actual: string }\n | {\n kind: 'rejected';\n reason: 'op_conflict';\n /** Failing entry index in the journal — agent rerun anchor. */\n index: number;\n op_kind: SemanticOpName;\n /** Validator message, passed through verbatim (never a raw Error). */\n message: string;\n };\n\nexport interface CommitPlanOptions {\n /** `'version'` (default, phase-1 hard gate) | `'preflight'` (phase-2 per-op revalidation). */\n validation?: 'version' | 'preflight';\n}\n\n/**\n * Replay a sandbox journal into a live session through its document adapter\n * (SemanticEditor → Loro → mengine-server).\n *\n * - Default / `{ validation: 'version' }`: if `session.version()` ≠\n * `plan.base_version`, reject with zero writes.\n * - `{ validation: 'preflight' }`: skip the version gate; revalidate each op\n * against a PlainMemoryAdapter seeded from the current live snapshot, then\n * replay for real. A SchemaValidator failure becomes `op_conflict` with the\n * failing entry's index. Journal integrity errors (unrecorded/unconsumed\n * ids) still propagate as throws in both modes.\n */\nexport async function commitPlan(\n session: MengineDocSession,\n plan: CommitPlan,\n options?: CommitPlanOptions,\n): Promise<CommitPlanResult> {\n if (options?.validation === 'preflight') {\n return commitPlanPreflight(session, plan);\n }\n\n const actual = session.version();\n if (actual !== plan.base_version) {\n return {\n kind: 'rejected',\n reason: 'version_mismatch',\n expected: plan.base_version,\n actual,\n };\n }\n\n await replayJournal(session.documentAdapter, plan.ops);\n return { kind: 'committed', ops_applied: plan.ops.length };\n}\n\n/**\n * Phase-2 path: scratch revalidation then real replay. Each entry is driven\n * through `replayJournal` alone so a ValidationError maps to a stable index;\n * integrity throws are not wrapped.\n */\nasync function commitPlanPreflight(session: MengineDocSession, plan: CommitPlan): Promise<CommitPlanResult> {\n const scratch = createPlainMemoryAdapter(session.snapshot());\n\n for (let index = 0; index < plan.ops.length; index++) {\n const entry = plan.ops[index];\n if (entry == null) continue;\n try {\n await replayJournal(scratch, [entry]);\n } catch (error) {\n if (error instanceof ValidationError) {\n return opConflict(index, entry.kind, error.message);\n }\n throw error;\n }\n }\n\n // Real replay: optimistic window may still collide; wrap ValidationError the\n // same way. Prior entries in this loop have already been written.\n for (let index = 0; index < plan.ops.length; index++) {\n const entry = plan.ops[index];\n if (entry == null) continue;\n try {\n await replayJournal(session.documentAdapter, [entry]);\n } catch (error) {\n if (error instanceof ValidationError) {\n return opConflict(index, entry.kind, `real replay: ${error.message}`);\n }\n throw error;\n }\n }\n\n return { kind: 'committed', ops_applied: plan.ops.length };\n}\n\nfunction opConflict(index: number, op_kind: SemanticOpName, message: string): CommitPlanResult {\n return { kind: 'rejected', reason: 'op_conflict', index, op_kind, message };\n}\n","import { randomUUID } from 'node:crypto';\n\nimport {\n MengineDocSession,\n MengineHttpClient,\n type MengineDocSessionOptions,\n type VideoDocument,\n} from '@mengine/medeo-client';\n\nimport { renderCompactProjection } from './document/compact-projection.ts';\nimport { MEDEO_TOOL_DESCRIPTION } from './prompt.ts';\nimport { runEditScript } from './sandbox/node-host.ts';\nimport type { ChangePlan } from './sandbox/script-session.ts';\nimport { MEDEO_TOOL_NAME, MEDEO_TOOL_PARAMETERS, type MedeoToolOp } from './schema.ts';\nimport { commitPlan, type CommitPlanOptions, type CommitPlanResult } from './session/commit-plan.ts';\n\ntype ContextualValue<T> = T | ((docId: string) => T | undefined);\n\nexport interface CreateMedeoToolOptions {\n /**\n * Mengine HTTP origin for a document. The host owns environment routing\n * (local/stg/prd/lane) and may return a different origin per document.\n * Sessions cache by doc id, so the origin must remain stable for that doc.\n */\n httpOrigin: ContextualValue<string>;\n /** Optional bearer token, evaluated for each HTTP request. */\n authToken?: ContextualValue<string>;\n /** Optional end-user id header, evaluated for each HTTP request. */\n userId?: ContextualValue<string>;\n /** Stable agent peer id. Supply a host-scoped value so audit provenance is durable. */\n peerId?: ContextualValue<string>;\n fetchImpl?: typeof fetch;\n sseReconnectDelayMs?: number;\n /** Defaults passed to runEditScript; each call may override them. */\n sandbox?: { timeoutMs?: number; memoryLimitMb?: number };\n /** Maximum cached plans; oldest plans are evicted (default 16). */\n maxPlans?: number;\n}\n\nexport type MedeoToolInput =\n | { op: 'snapshot'; doc_id: string }\n | {\n op: 'run-edit-script';\n doc_id: string;\n script: string;\n inputs?: Record<string, unknown>;\n timeout_ms?: number;\n memory_limit_mb?: number;\n auto_commit?: boolean;\n }\n | {\n op: 'commit-plan';\n doc_id: string;\n plan_id: string;\n validation?: 'version' | 'preflight';\n };\n\nexport type MedeoToolResult =\n | { ok: true; op: 'snapshot'; doc_id: string; version: string; preview: string }\n | {\n ok: true;\n op: 'run-edit-script';\n doc_id: string;\n plan_id: string;\n base_version: string;\n ops_count: number;\n preview: string;\n logs: string[];\n duration_ms: number;\n committed?: boolean;\n commit_result?: CommitPlanResult;\n }\n | {\n ok: false;\n op: 'run-edit-script';\n doc_id: string;\n phase: 'parse' | 'runtime' | 'timeout' | 'memory';\n error: { message: string; line?: number; column?: number; stack?: string };\n partial: { ops_count: number; logs: string[] };\n }\n | {\n ok: true;\n op: 'commit-plan';\n doc_id: string;\n plan_id: string;\n committed: boolean;\n result: CommitPlanResult;\n }\n | { ok: false; op: MedeoToolOp; error: string };\n\nexport interface MedeoTool {\n name: typeof MEDEO_TOOL_NAME;\n description: typeof MEDEO_TOOL_DESCRIPTION;\n parameters: typeof MEDEO_TOOL_PARAMETERS;\n handle(input: unknown): Promise<MedeoToolResult>;\n close(): Promise<void>;\n}\n\ninterface CachedPlan {\n docId: string;\n plan: ChangePlan;\n}\n\nconst DEFAULT_MAX_PLANS = 16;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction optionalContext<T>(value: ContextualValue<T> | undefined, docId: string): T | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'function' ? (value as (id: string) => T | undefined)(docId) : value;\n}\n\nfunction requiredContext(value: ContextualValue<string>, docId: string, field: string): string {\n const resolved = optionalContext(value, docId)?.trim();\n if (resolved == null || resolved.length === 0) {\n throw new Error(`${field} must resolve to a non-empty string for doc ${docId}`);\n }\n return resolved;\n}\n\nfunction parseInput(value: unknown): MedeoToolInput {\n if (!isRecord(value)) throw new Error('input must be an object');\n const op = value.op;\n const docId = value.doc_id;\n if (typeof op !== 'string') throw new Error('op must be a string');\n if (typeof docId !== 'string' || docId.trim().length === 0) throw new Error('doc_id must be a non-empty string');\n\n if (op === 'snapshot') return { op, doc_id: docId };\n\n if (op === 'run-edit-script') {\n if (typeof value.script !== 'string' || value.script.length === 0) {\n throw new Error('script must be a non-empty string');\n }\n if (value.inputs !== undefined && !isRecord(value.inputs)) {\n throw new Error('inputs must be an object');\n }\n const timeoutMs = value.timeout_ms;\n if (timeoutMs !== undefined && (typeof timeoutMs !== 'number' || !Number.isInteger(timeoutMs) || timeoutMs <= 0)) {\n throw new Error('timeout_ms must be a positive integer');\n }\n const memoryLimitMb = value.memory_limit_mb;\n if (\n memoryLimitMb !== undefined &&\n (typeof memoryLimitMb !== 'number' || !Number.isInteger(memoryLimitMb) || memoryLimitMb < 16)\n ) {\n throw new Error('memory_limit_mb must be an integer >= 16');\n }\n if (value.auto_commit !== undefined && typeof value.auto_commit !== 'boolean') {\n throw new Error('auto_commit must be a boolean');\n }\n return {\n op,\n doc_id: docId,\n script: value.script,\n ...(value.inputs !== undefined ? { inputs: value.inputs } : {}),\n ...(timeoutMs !== undefined ? { timeout_ms: timeoutMs } : {}),\n ...(memoryLimitMb !== undefined ? { memory_limit_mb: memoryLimitMb } : {}),\n ...(value.auto_commit !== undefined ? { auto_commit: value.auto_commit } : {}),\n };\n }\n\n if (op === 'commit-plan') {\n if (typeof value.plan_id !== 'string' || value.plan_id.length === 0) {\n throw new Error('plan_id must be a non-empty string');\n }\n if (value.validation !== undefined && value.validation !== 'version' && value.validation !== 'preflight') {\n throw new Error('validation must be \"version\" or \"preflight\"');\n }\n return {\n op,\n doc_id: docId,\n plan_id: value.plan_id,\n ...(value.validation !== undefined ? { validation: value.validation } : {}),\n };\n }\n\n throw new Error(`unknown op: ${op}`);\n}\n\n/**\n * Create the self-contained Medeo LLM tool.\n *\n * The package owns session construction, compact projection, sandbox execution,\n * plan caching, commit, and shutdown. The host supplies only environment facts:\n * HTTP origin, credentials, fetch implementation, and a stable peer id.\n */\nexport function createMedeoTool(options: CreateMedeoToolOptions): MedeoTool {\n const sessions = new Map<string, Promise<MengineDocSession>>();\n const plans = new Map<string, CachedPlan>();\n const maxPlans = options.maxPlans ?? DEFAULT_MAX_PLANS;\n let closed = false;\n\n async function getSession(docId: string): Promise<MengineDocSession> {\n if (closed) throw new Error('medeo tool is closed');\n const existing = sessions.get(docId);\n if (existing != null) return await existing;\n\n const created = (async () => {\n const client = new MengineHttpClient({\n docId,\n httpOrigin: requiredContext(options.httpOrigin, docId, 'httpOrigin'),\n ...(options.authToken !== undefined ? { authToken: () => optionalContext(options.authToken, docId) } : {}),\n ...(options.userId !== undefined ? { userId: () => optionalContext(options.userId, docId) } : {}),\n ...(options.fetchImpl !== undefined ? { fetchImpl: options.fetchImpl } : {}),\n });\n const peerId = optionalContext(options.peerId, docId);\n const session = new MengineDocSession({\n docId,\n client,\n ...(peerId !== undefined ? { peerId: peerId as MengineDocSessionOptions['peerId'] } : {}),\n ...(options.sseReconnectDelayMs !== undefined ? { sseReconnectDelayMs: options.sseReconnectDelayMs } : {}),\n });\n try {\n await session.start();\n return session;\n } catch (error) {\n session.destroy();\n throw error;\n }\n })();\n\n sessions.set(docId, created);\n try {\n return await created;\n } catch (error) {\n if (sessions.get(docId) === created) sessions.delete(docId);\n throw error;\n }\n }\n\n function rememberPlan(docId: string, plan: ChangePlan): string {\n const planId = randomUUID();\n plans.set(planId, { docId, plan });\n while (plans.size > maxPlans) {\n const oldest = plans.keys().next().value;\n if (oldest === undefined) break;\n plans.delete(oldest);\n }\n return planId;\n }\n\n async function snapshot(input: Extract<MedeoToolInput, { op: 'snapshot' }>): Promise<MedeoToolResult> {\n const session = await getSession(input.doc_id);\n const document = session.snapshot();\n return {\n ok: true,\n op: 'snapshot',\n doc_id: input.doc_id,\n version: session.version(),\n preview: renderCompactProjection(document),\n };\n }\n\n async function run(input: Extract<MedeoToolInput, { op: 'run-edit-script' }>): Promise<MedeoToolResult> {\n const session = await getSession(input.doc_id);\n const document: VideoDocument = session.snapshot();\n const baseVersion = session.version();\n const result = await runEditScript({\n document,\n baseVersion,\n script: input.script,\n ...(input.inputs !== undefined ? { inputs: input.inputs } : {}),\n timeoutMs: input.timeout_ms ?? options.sandbox?.timeoutMs,\n memoryLimitMb: input.memory_limit_mb ?? options.sandbox?.memoryLimitMb,\n });\n\n if (!result.ok) {\n return {\n ok: false,\n op: 'run-edit-script',\n doc_id: input.doc_id,\n phase: result.phase,\n error: result.error,\n partial: { ops_count: result.partial.ops.length, logs: result.partial.logs },\n };\n }\n\n const planId = rememberPlan(input.doc_id, result.plan);\n const base = {\n ok: true as const,\n op: 'run-edit-script' as const,\n doc_id: input.doc_id,\n plan_id: planId,\n base_version: baseVersion,\n ops_count: result.plan.ops.length,\n preview: result.plan.preview,\n logs: result.plan.logs,\n duration_ms: result.durationMs,\n };\n if (input.auto_commit !== true) return base;\n\n const commit = await commitPlan(session, result.plan);\n return { ...base, committed: commit.kind === 'committed', commit_result: commit };\n }\n\n async function commit(input: Extract<MedeoToolInput, { op: 'commit-plan' }>): Promise<MedeoToolResult> {\n const cached = plans.get(input.plan_id);\n if (cached == null || cached.docId !== input.doc_id) {\n throw new Error(`plan_id ${input.plan_id} is not available for doc ${input.doc_id}`);\n }\n const session = await getSession(input.doc_id);\n const commitOptions: CommitPlanOptions | undefined =\n input.validation === undefined ? undefined : { validation: input.validation };\n const result = await commitPlan(session, cached.plan, commitOptions);\n return {\n ok: true,\n op: 'commit-plan',\n doc_id: input.doc_id,\n plan_id: input.plan_id,\n committed: result.kind === 'committed',\n result,\n };\n }\n\n return {\n name: MEDEO_TOOL_NAME,\n description: MEDEO_TOOL_DESCRIPTION,\n parameters: MEDEO_TOOL_PARAMETERS,\n async handle(input: unknown): Promise<MedeoToolResult> {\n try {\n const parsed = parseInput(input);\n if (parsed.op === 'snapshot') return await snapshot(parsed);\n if (parsed.op === 'run-edit-script') return await run(parsed);\n return await commit(parsed);\n } catch (error) {\n const op = isRecord(input) && typeof input.op === 'string' ? (input.op as MedeoToolOp) : 'snapshot';\n return {\n ok: false,\n op,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n },\n async close(): Promise<void> {\n closed = true;\n const opening = [...sessions.values()];\n sessions.clear();\n plans.clear();\n const errors: unknown[] = [];\n for (const sessionPromise of opening) {\n try {\n const session = await sessionPromise;\n session.destroy();\n } catch (error) {\n errors.push(error);\n }\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'failed to close medeo tool sessions');\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,14 @@
1
+ import { register } from "node:module";
2
+ //#region src/sandbox/node-esm-resolve-register.ts
3
+ /**
4
+ * Register the Node ESM resolve hook that lets `--experimental-transform-types`
5
+ * workers load workspace packages whose source still uses extensionless /
6
+ * directory-relative imports (vite resolves those; bare Node does not).
7
+ *
8
+ * Loaded via worker `execArgv --import` from `node-host.ts`.
9
+ */
10
+ register(new URL("./node-esm-resolve-hooks.ts", import.meta.url));
11
+ //#endregion
12
+ export {};
13
+
14
+ //# sourceMappingURL=node-esm-resolve-register.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-esm-resolve-register.mjs","names":[],"sources":["../src/sandbox/node-esm-resolve-register.ts"],"sourcesContent":["/**\n * Register the Node ESM resolve hook that lets `--experimental-transform-types`\n * workers load workspace packages whose source still uses extensionless /\n * directory-relative imports (vite resolves those; bare Node does not).\n *\n * Loaded via worker `execArgv --import` from `node-host.ts`.\n */\nimport { register } from 'node:module';\n\nregister(new URL('./node-esm-resolve-hooks.ts', import.meta.url));\n"],"mappings":";;;;;;;;;AASA,SAAS,IAAI,IAAI,+BAA+B,OAAO,KAAK,GAAG,CAAC"}