@pinepaper.studio/mcp-server 1.6.8 → 1.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.de.md +1 -1
  2. package/README.es.md +1 -1
  3. package/README.fr.md +1 -1
  4. package/README.hi.md +1 -1
  5. package/README.ja.md +1 -1
  6. package/README.ko.md +1 -1
  7. package/README.md +89 -4
  8. package/README.pt-BR.md +1 -1
  9. package/README.zh-CN.md +1 -1
  10. package/dist/browser/index.d.ts +1 -1
  11. package/dist/browser/index.d.ts.map +1 -1
  12. package/dist/browser/index.js +1 -1
  13. package/dist/browser/index.js.map +1 -1
  14. package/dist/browser/puppeteer-controller.d.ts +86 -2
  15. package/dist/browser/puppeteer-controller.d.ts.map +1 -1
  16. package/dist/browser/puppeteer-controller.js +143 -60
  17. package/dist/browser/puppeteer-controller.js.map +1 -1
  18. package/dist/cli.js +12 -0
  19. package/dist/cli.js.map +1 -1
  20. package/dist/design/design-systems.d.ts +105 -7
  21. package/dist/design/design-systems.d.ts.map +1 -1
  22. package/dist/design/design-systems.js +210 -16
  23. package/dist/design/design-systems.js.map +1 -1
  24. package/dist/tools/definitions.d.ts.map +1 -1
  25. package/dist/tools/definitions.js +63 -3
  26. package/dist/tools/definitions.js.map +1 -1
  27. package/dist/tools/engine-methods.d.ts.map +1 -1
  28. package/dist/tools/engine-methods.js +2 -0
  29. package/dist/tools/engine-methods.js.map +1 -1
  30. package/dist/tools/handlers.d.ts.map +1 -1
  31. package/dist/tools/handlers.js +212 -8
  32. package/dist/tools/handlers.js.map +1 -1
  33. package/dist/tools/minimal-descriptions.d.ts.map +1 -1
  34. package/dist/tools/minimal-descriptions.js +2 -1
  35. package/dist/tools/minimal-descriptions.js.map +1 -1
  36. package/dist/tools/toolkits.d.ts.map +1 -1
  37. package/dist/tools/toolkits.js +1 -0
  38. package/dist/tools/toolkits.js.map +1 -1
  39. package/dist/types/code-generator.d.ts +10 -0
  40. package/dist/types/code-generator.d.ts.map +1 -1
  41. package/dist/types/code-generator.js +75 -8
  42. package/dist/types/code-generator.js.map +1 -1
  43. package/dist/types/schemas.d.ts +75 -35
  44. package/dist/types/schemas.d.ts.map +1 -1
  45. package/dist/types/schemas.js +43 -3
  46. package/dist/types/schemas.js.map +1 -1
  47. package/manifest.json +5 -1
  48. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"engine-methods.d.ts","sourceRoot":"","sources":["../../src/tools/engine-methods.ts"],"names":[],"mappings":"AAUA;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAsMpD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAcpD,CAAC"}
1
+ {"version":3,"file":"engine-methods.d.ts","sourceRoot":"","sources":["../../src/tools/engine-methods.ts"],"names":[],"mappings":"AAUA;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAwMpD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAcpD,CAAC"}
@@ -70,10 +70,12 @@ export const REQUIRED_ENGINE_METHODS = [
70
70
  'diffHistoryStates',
71
71
  'distillArticle',
72
72
  'dollyWorldCamera',
73
+ 'ensureHeavyModules',
73
74
  'estimateExportSize',
74
75
  'exportBVH',
75
76
  'exportDotLottie',
76
77
  'exportEngine.exportToStore',
78
+ 'exportEngine.listExports',
77
79
  'exportEngine.readExport',
78
80
  'exportEngine.releaseExport',
79
81
  'exportEngine.sceneHasAudio',
@@ -1 +1 @@
1
- {"version":3,"file":"engine-methods.js","sourceRoot":"","sources":["../../src/tools/engine-methods.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine-methods.js","sourceRoot":"","sources":["../../src/tools/engine-methods.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/tools/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,cAAc,EAA6B,MAAM,oCAAoC,CAAC;AA8I/F,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,0BAA0B,EAG3B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,YAAY,EAA0C,MAAM,uBAAuB,CAAC;AAgC7F;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAOlD;AAaD,eAAO,MAAM,mBAAmB,aAAgD,CAAC;AAGjF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGvD;AAiHD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,MAAM,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAOhD;AAMD,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,0BAA0B,CAAC;IAC/C,oEAAoE;IACpE,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,sEAAsE;IACtE,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAuFD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,OAAO,EACjB,OAAO,CAAC,EAAE,YAAY,GACrB,cAAc,CAwBhB;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CAqMzB;AAMD,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GACtC,MAAM,CASR;AAkFD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAkBzB"}
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/tools/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,cAAc,EAA6B,MAAM,oCAAoC,CAAC;AA+I/F,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,0BAA0B,EAG3B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,YAAY,EAA0C,MAAM,uBAAuB,CAAC;AAgC7F;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAOlD;AAaD,eAAO,MAAM,mBAAmB,aAAgD,CAAC;AAkCjF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGvD;AAsLD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,MAAM,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAOhD;AAMD,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,0BAA0B,CAAC;IAC/C,oEAAoE;IACpE,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,sEAAsE;IACtE,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAuFD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,OAAO,EACjB,OAAO,CAAC,EAAE,YAAY,GACrB,cAAc,CAwBhB;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CAqMzB;AAMD,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GACtC,MAAM,CASR;AAkFD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAkBzB"}
@@ -10,7 +10,7 @@ import { CreateItemInputSchema, ModifyItemInputSchema, DeleteItemInputSchema, Ad
10
10
  // Diagram schemas
11
11
  CreateDiagramShapeInputSchema, ConnectInputSchema, ConnectPortsInputSchema, AddPortsInputSchema, AutoLayoutInputSchema, GetDiagramShapesInputSchema, UpdateConnectorInputSchema, RemoveConnectorInputSchema, DiagramModeInputSchema,
12
12
  // Agent flow mode schemas
13
- AgentStartJobInputSchema, AgentEndJobInputSchema, AgentResetInputSchema, AgentBatchExecuteInputSchema, AgentExportInputSchema, AgentAnalyzeInputSchema,
13
+ AgentStartJobInputSchema, AgentEndJobInputSchema, AgentResetInputSchema, AgentBatchExecuteInputSchema, AgentExportInputSchema, ExportStoreInputSchema, AgentAnalyzeInputSchema,
14
14
  // Letter collage schemas
15
15
  CreateLetterCollageInputSchema, AnimateLetterCollageInputSchema,
16
16
  // Map schemas
@@ -84,6 +84,34 @@ function getExportDir() {
84
84
  // pasted into a response.
85
85
  export const ALWAYS_SAVE_FORMATS = new Set(['mp4', 'webm', 'gif', 'pdf', 'wav']);
86
86
  const SAVE_THRESHOLD_BYTES = 500_000; // ~500KB base64 ≈ 375KB decoded
87
+ /**
88
+ * Governor budget for the export run itself.
89
+ *
90
+ * FxTool's runGenerated defaults to a 10s async-tail timeout — right for a
91
+ * scene-building script that has no business running longer, and fatal for an
92
+ * export, which renders frame by frame and is capped at 600s of footage. The
93
+ * export died at ten seconds with a PP_TIMEOUT that read like a bug in the
94
+ * scene. This raises the budget rather than bypassing the governor, so the
95
+ * report, the item budget and the seeded PRNG all survive.
96
+ *
97
+ * PINEPAPER_EXPORT_TIMEOUT overrides it. The default matches the floor put on
98
+ * CDP's own per-call timeout (MIN_PROTOCOL_TIMEOUT_MS in
99
+ * puppeteer-controller.ts), so raising this past the default without also
100
+ * raising PINEPAPER_TIMEOUT just moves the execution to a protocol error —
101
+ * which is why that case says so out loud rather than failing obscurely later.
102
+ */
103
+ const EXPORT_GOVERNOR_DEFAULT_MS = 300_000;
104
+ function exportGovernorTimeoutMs() {
105
+ const raw = Number(process.env.PINEPAPER_EXPORT_TIMEOUT);
106
+ if (!Number.isFinite(raw) || raw <= 0)
107
+ return EXPORT_GOVERNOR_DEFAULT_MS;
108
+ const protocolFloor = Math.max(Number(process.env.PINEPAPER_TIMEOUT) || 0, EXPORT_GOVERNOR_DEFAULT_MS);
109
+ if (raw > protocolFloor) {
110
+ console.error(`[PinePaper] PINEPAPER_EXPORT_TIMEOUT=${raw}ms is above the browser's protocol timeout (${protocolFloor}ms) — ` +
111
+ 'raise PINEPAPER_TIMEOUT to match, or an export past that point fails as a protocol error rather than a governor timeout.');
112
+ }
113
+ return raw;
114
+ }
87
115
  export function getFileExtension(format) {
88
116
  const extMap = { mp4: 'mp4', webm: 'webm', gif: 'gif', pdf: 'pdf', png: 'png', svg: 'svg', wav: 'wav' };
89
117
  return extMap[format] || format;
@@ -122,6 +150,8 @@ async function saveExportToFile(data, format, platform) {
122
150
  * recoverable. `releaseExport` runs only once the whole file is written.
123
151
  */
124
152
  async function streamRetainedExportToFile(controller, retained, platform) {
153
+ // Reassigned once if the store corrects the size below.
154
+ let corrected = false;
125
155
  const exportDir = getExportDir();
126
156
  await mkdir(exportDir, { recursive: true });
127
157
  const ext = getFileExtension(retained.format);
@@ -139,18 +169,78 @@ async function streamRetainedExportToFile(controller, retained, platform) {
139
169
  await unlink(filePath);
140
170
  }
141
171
  catch { /* nothing written yet */ }
142
- return new Error(`${why} (export "${retained.exportId}" is still held in the studio, ${offset} of ${retained.size} bytes read; ` +
143
- `it can be paged again, and is released only once a whole file is written)`);
172
+ return new Error(
173
+ // The promise now names the call that keeps it. It was true before and
174
+ // unreachable: reading a held export mutates nothing, so "it can be paged
175
+ // again" was always correct and there was no door to page it through.
176
+ `${why} (export "${retained.exportId}" is still held in the studio, ${offset} of ${retained.size} bytes read; ` +
177
+ `page it out with pinepaper_export_store action 'save', exportId "${retained.exportId}" — reading is idempotent, ` +
178
+ 'so retrying costs nothing and the export is released only once a whole file is written. Do it BEFORE the next ' +
179
+ 'export: a new one evicts the oldest held bytes to make room)');
144
180
  };
181
+ // A READ THAT FAILS ON SIZE IS NOT A READ THAT FAILS.
182
+ //
183
+ // A 17 MB memphis chunk died on its FOURTH 4 MB read — three had already
184
+ // landed — with "Failed to write data to data pipe". That is CDP refusing to
185
+ // carry one oversized value across the bridge, not the store refusing to
186
+ // serve it: the render had succeeded and the bytes were sitting right there.
187
+ // The loop abandoned the whole export anyway, and the caller was left with an
188
+ // error that explained the bytes were still held and no way to go get them.
189
+ //
190
+ // So a transport failure halves the request and asks again, down to a floor,
191
+ // before giving up. The offset does not move, so a retry costs one re-read,
192
+ // never a corrupt file. A refusal from the STORE (evicted, out of range) is
193
+ // NOT retried — that answer will not change with a smaller window, and
194
+ // retrying it would only spend the caller's time to reach the same place.
195
+ const MIN_CHUNK_BYTES = 256 * 1024;
196
+ let window = chunkBytes;
145
197
  for (;;) {
146
- const code = codeGenerator.generateReadExportChunk(retained.exportId, offset, Math.min(chunkBytes, retained.size - offset));
198
+ const want = Math.min(window, retained.size - offset);
199
+ const code = codeGenerator.generateReadExportChunk(retained.exportId, offset, want);
200
+ // Deliberately governed at the default budget: a chunk read is a slice of a
201
+ // string already in memory. If one of these ever needs ten seconds, the
202
+ // store is wedged and a timeout is the correct answer, not a longer wait.
147
203
  const run = await controller.executeCode(code, false);
148
- if (!run.success)
149
- throw await abandon(`reading the export failed: ${run.error || 'unknown error'}`);
204
+ if (!run.success) {
205
+ if (want > MIN_CHUNK_BYTES) {
206
+ window = Math.max(MIN_CHUNK_BYTES, Math.floor(want / 2));
207
+ console.error(`[PinePaper] a ${want}-byte read of "${retained.exportId}" failed (${run.error || 'unknown error'}); `
208
+ + `retrying the same offset at ${window} bytes`);
209
+ continue;
210
+ }
211
+ throw await abandon(`reading the export failed even at the ${MIN_CHUNK_BYTES}-byte floor: ${run.error || 'unknown error'}`);
212
+ }
150
213
  const chunk = run.result;
151
214
  if (!chunk || chunk.ok !== true) {
215
+ // A RANGE REFUSAL IS A CORRECTION, and it carries the real size.
216
+ //
217
+ // readExport refuses an out-of-range read by name rather than clamping —
218
+ // deliberately, so a miscounting caller is told instead of handed a short
219
+ // chunk it treats as the tail, which surfaces later as a truncated video
220
+ // with nothing pointing back at the cause. The size this loop is working
221
+ // from came from the export result, and `save` works from a listing; when
222
+ // either disagrees with the file, the refusal is the authority. Take it
223
+ // ONCE — a second disagreement is not a miscount, it is a moving target.
224
+ // Only when it DISAGREES. Every range refusal quotes the real size,
225
+ // including the ones that are refusing for some other reason — so
226
+ // matching the number alone treated an eviction as a miscount, spent the
227
+ // one correction on a no-op re-read, and hid the actual reason for an
228
+ // iteration.
229
+ const stated = /\(size (\d+)\)/.exec(chunk?.reason ?? '');
230
+ if (stated && !corrected && Number(stated[1]) !== retained.size) {
231
+ corrected = true;
232
+ const was = retained.size;
233
+ retained = { ...retained, size: Number(stated[1]) };
234
+ console.error(`[PinePaper] the store reports "${retained.exportId}" as ${retained.size} bytes, not ${was}; `
235
+ + "taking the store's number and continuing");
236
+ continue;
237
+ }
152
238
  // An evicted id is its own failure: a later export reclaimed the space.
153
- // Re-exporting is the caller's decision, never this loop's.
239
+ // Re-exporting is the caller's decision, never this loop's. The engine
240
+ // records an eviction in browser storage so it survives a reload, but
241
+ // that storage is best-effort — a private window, cleared site data or
242
+ // storage switched off all fall back to memory-only. So `evicted` being
243
+ // ABSENT means unknown, never that the export was not there.
154
244
  throw await abandon(chunk?.evicted
155
245
  ? `the export was evicted mid-read: ${chunk.reason}`
156
246
  : `the studio refused the read: ${chunk?.reason || 'no reason given'}`);
@@ -2021,6 +2111,74 @@ You can now start creating new items on a clean canvas.`,
2021
2111
  }
2022
2112
  return batchResult;
2023
2113
  }
2114
+ case 'pinepaper_export_store': {
2115
+ const input = ExportStoreInputSchema.parse(args);
2116
+ const controller = options.browserController || getBrowserController();
2117
+ if (!controller.connected) {
2118
+ try {
2119
+ await controller.connect();
2120
+ }
2121
+ catch (connectError) {
2122
+ return errorResult(ErrorCodes.EXECUTION_ERROR, `the export store lives in the studio, and connecting to it failed: ${connectError instanceof Error ? connectError.message : 'unknown error'}`, {}, { toolName: 'pinepaper_export_store' });
2123
+ }
2124
+ }
2125
+ const held = await controller.executeCode(codeGenerator.generateListExports(), false);
2126
+ if (!held.success) {
2127
+ return errorResult(ErrorCodes.EXECUTION_ERROR, `listing the export store failed: ${held.error || 'unknown error'}`, {}, { toolName: 'pinepaper_export_store' });
2128
+ }
2129
+ const listing = held.result;
2130
+ if (!listing || listing.ok !== true) {
2131
+ return errorResult(ErrorCodes.EXECUTION_ERROR, listing?.reason || 'the studio did not answer with a listing', {}, { toolName: 'pinepaper_export_store' });
2132
+ }
2133
+ const exports = listing.exports ?? [];
2134
+ if (input.action === 'list') {
2135
+ return dataResult({
2136
+ exports,
2137
+ held: exports.length,
2138
+ heldBytes: exports.reduce((n, e) => n + (e.size || 0), 0),
2139
+ note: exports.length > 1
2140
+ ? 'A later export evicts the OLDEST held ones to make room. Save or release each before starting the next.'
2141
+ : undefined,
2142
+ });
2143
+ }
2144
+ // Both remaining actions name an id, and an id the store does not have
2145
+ // is the one thing worth saying carefully. The engine records an
2146
+ // eviction durably enough to survive a reload, so a read of that id
2147
+ // will usually say "evicted" — but the record is best-effort browser
2148
+ // storage and a listing cannot consult it at all. Absence of the id
2149
+ // here is therefore "gone, cause unknown", and stating one cause as
2150
+ // fact would be inventing the more interesting half of the answer.
2151
+ const entry = exports.find((e) => e.id === input.exportId);
2152
+ if (!entry) {
2153
+ return errorResult(ErrorCodes.INVALID_PARAMS, `the studio is not holding "${input.exportId}". It was released, evicted to make room for a later export, `
2154
+ + `or never existed here — a listing cannot tell which. `
2155
+ + `${exports.length ? `Held right now: ${exports.map((e) => e.id).join(', ')}.` : 'The store is empty.'}`, { exportId: input.exportId, held: exports.map((e) => e.id) }, { toolName: 'pinepaper_export_store' });
2156
+ }
2157
+ if (input.action === 'release') {
2158
+ const dropped = await controller.executeCode(codeGenerator.generateReleaseExport(entry.id), false);
2159
+ const outcome = dropped.result;
2160
+ if (!dropped.success || outcome?.ok !== true) {
2161
+ return errorResult(ErrorCodes.EXECUTION_ERROR, `releasing "${entry.id}" failed: ${dropped.error || outcome?.reason || 'unknown error'}`, { exportId: entry.id }, { toolName: 'pinepaper_export_store' });
2162
+ }
2163
+ return dataResult({ released: entry.id, freedBytes: entry.size });
2164
+ }
2165
+ // save: the same pager agent_export uses, pointed at an id instead of a
2166
+ // fresh render. Reading is idempotent, so a save that failed halfway
2167
+ // can simply be run again — there is no partial state to clean up here.
2168
+ try {
2169
+ const { filePath, fileSize, chunks } = await streamRetainedExportToFile(controller, { exportId: entry.id, size: entry.size, format: entry.format }, input.platform || 'recovered');
2170
+ return {
2171
+ content: [{
2172
+ type: 'text',
2173
+ text: `Export recovered from the studio's store:\n\nFile: ${filePath}\nFormat: ${entry.format}\n`
2174
+ + `Size: ${(fileSize / 1024).toFixed(1)} KB\nPaged out in ${chunks} chunk${chunks === 1 ? '' : 's'}, then released\n`,
2175
+ }],
2176
+ };
2177
+ }
2178
+ catch (streamError) {
2179
+ return errorResult(ErrorCodes.EXECUTION_ERROR, streamError instanceof Error ? streamError.message : 'paging the export out of the store failed', { exportId: entry.id, size: entry.size }, { toolName: 'pinepaper_export_store' });
2180
+ }
2181
+ }
2024
2182
  case 'pinepaper_agent_export': {
2025
2183
  const input = AgentExportInputSchema.parse(args);
2026
2184
  const code = codeGenerator.generateAgentExport(input);
@@ -2048,12 +2206,46 @@ You can now start creating new items on a clean canvas.`,
2048
2206
  if (!exportSessionManager.hasActiveJob()) {
2049
2207
  exportSessionManager.startJob({ name: 'auto_session', screenshotPolicy: 'on_complete' });
2050
2208
  }
2051
- const exportBrowserResult = await controller.executeCode(code, false);
2209
+ const exportBrowserResult = await controller.executeCode(code, false, {
2210
+ governorTimeoutMs: exportGovernorTimeoutMs(),
2211
+ });
2052
2212
  if (!exportBrowserResult.success) {
2053
2213
  const canvasState = await captureCanvasState(controller);
2054
2214
  return errorResult(ErrorCodes.EXECUTION_ERROR, exportBrowserResult.error || 'Export failed', { code }, { toolName: 'pinepaper_agent_export', canvasState: canvasState || undefined });
2055
2215
  }
2056
2216
  const exportResult = exportBrowserResult.result;
2217
+ // TWO VERDICTS, and only one of them was being read.
2218
+ //
2219
+ // `exportBrowserResult.success` says the CODE RAN. The export's own
2220
+ // verdict is `exportResult.success`, and every emitted branch that
2221
+ // cannot deliver returns `{ success: false, error }` — a studio without
2222
+ // the renderer, an encoder that died, a blob past the inline ceiling.
2223
+ // None of that was checked: the value fell through to the inline return
2224
+ // below, which reports a success and hands back a result object nobody
2225
+ // reads past the first line.
2226
+ //
2227
+ // Measured cost: a five-chunk video where two chunks came back
2228
+ // `success: false, error: "export failed: Failed to write data to data
2229
+ // pipe"` under an outer `"success": true`. The caller shipped a
2230
+ // three-chunk video believing it had five. A silent success is the one
2231
+ // failure mode this surface can never afford, because nothing
2232
+ // downstream has any reason to look again.
2233
+ if (exportResult && exportResult.success === false) {
2234
+ const canvasState = await captureCanvasState(controller);
2235
+ // A "data pipe" failure is the BROWSER TRANSPORT refusing to carry
2236
+ // the result back, not the encoder refusing to make it — the string
2237
+ // exists nowhere in the engine. So the render may well have finished
2238
+ // and the bytes may be sitting in the export store right now. Saying
2239
+ // so is the difference between recovering an export and re-rendering
2240
+ // one, and re-rendering is what evicts an earlier chunk's bytes.
2241
+ const looksLikeTransport = /data pipe/i.test(String(exportResult.error ?? ''));
2242
+ return errorResult(ErrorCodes.EXECUTION_ERROR, `export failed: ${exportResult.error || 'the studio reported failure without naming a reason'}`
2243
+ + (looksLikeTransport
2244
+ ? ' — that is the browser transport failing to carry the result back, not necessarily the render failing.'
2245
+ + " Call pinepaper_export_store action 'list' BEFORE re-rendering: the bytes may already be held, and a"
2246
+ + ' fresh export can evict an earlier one to make room.'
2247
+ : ''), { code, format: exportResult.format ?? input.format, result: exportResult }, { toolName: 'pinepaper_agent_export', canvasState: canvasState || undefined });
2248
+ }
2057
2249
  const format = exportResult?.format || input.format || 'png';
2058
2250
  const data = exportResult?.data;
2059
2251
  // RETAINED: the studio held the encoded file in its export store rather
@@ -2145,6 +2337,18 @@ You can now start creating new items on a clean canvas.`,
2145
2337
  }
2146
2338
  return dataResult(sys);
2147
2339
  }
2340
+ case 'list_motion': {
2341
+ // Curves and durations together, because a motion token is a shape
2342
+ // AND a length. The curves were published and the durations beside
2343
+ // them in the same store were not, so a caller could match a
2344
+ // system's easing and had to invent its timing.
2345
+ const easings = designSystems.listEasings(input.authoredOnly);
2346
+ const durations = designSystems.listDurations(input.authoredOnly);
2347
+ return dataResult({
2348
+ easings, durations,
2349
+ note: 'These are the licensed SYSTEMS\' motion scales. An aesthetic style (bauhaus_geometric, memphis_group) carries no upstream motion data — pair one of these with a style rather than expecting the style to name its own.',
2350
+ });
2351
+ }
2148
2352
  case 'list_easings':
2149
2353
  return dataResult({ easings: designSystems.listEasings(input.authoredOnly) });
2150
2354
  case 'list_styles':