@imgly/codesign-mcp 0.1.6 → 0.1.8

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 (448) hide show
  1. package/README.md +5 -10
  2. package/assets/docs/api/index.d.ts +9 -3
  3. package/assets/docs/guide/SKILL.md +2 -2
  4. package/assets/docs/guide/api/node/classes/creativeengine.md +13 -13
  5. package/assets/docs/guide/edit-image/transform/scale.md +1 -3
  6. package/assets/docs/guide/filters-and-effects/duotone.md +1 -1
  7. package/assets/docs/guide/get-started/bun.md +0 -2
  8. package/assets/docs/guide/get-started/deno.md +0 -1
  9. package/assets/docs/guide/get-started/vanilla.md +0 -2
  10. package/assets/docs/guide/import-media/default-assets.md +20 -24
  11. package/assets/docs/guide/plugins/print-ready-pdf.md +0 -2
  12. package/assets/docs/guide/serve-assets.md +80 -23
  13. package/assets/docs/handbook/SKILL.md +6 -7
  14. package/dist/assets/inline.generated.js +12 -12
  15. package/dist/assets/inline.generated.js.map +1 -1
  16. package/dist/cli/http.d.ts.map +1 -1
  17. package/dist/cli/http.js +29 -5
  18. package/dist/cli/http.js.map +1 -1
  19. package/dist/cli/stdio.d.ts.map +1 -1
  20. package/dist/cli/stdio.js +145 -48
  21. package/dist/cli/stdio.js.map +1 -1
  22. package/dist/cli/trial-license.generated.d.ts +1 -1
  23. package/dist/cli/trial-license.generated.js +1 -1
  24. package/dist/cli/trial-license.generated.js.map +1 -1
  25. package/dist/config.d.ts +17 -2
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +20 -1
  28. package/dist/config.js.map +1 -1
  29. package/dist/diagnostics/bundle.d.ts +3 -0
  30. package/dist/diagnostics/bundle.d.ts.map +1 -1
  31. package/dist/diagnostics/bundle.js +25 -22
  32. package/dist/diagnostics/bundle.js.map +1 -1
  33. package/dist/diagnostics/events.d.ts +6 -0
  34. package/dist/diagnostics/events.d.ts.map +1 -1
  35. package/dist/diagnostics/events.js.map +1 -1
  36. package/dist/diagnostics/prompt.d.ts +3 -0
  37. package/dist/diagnostics/prompt.d.ts.map +1 -0
  38. package/dist/diagnostics/prompt.js +21 -0
  39. package/dist/diagnostics/prompt.js.map +1 -0
  40. package/dist/diagnostics/router.d.ts +12 -0
  41. package/dist/diagnostics/router.d.ts.map +1 -0
  42. package/dist/diagnostics/router.js +64 -0
  43. package/dist/diagnostics/router.js.map +1 -0
  44. package/dist/diagnostics/spa-assets.generated.d.ts.map +1 -0
  45. package/dist/diagnostics/spa-assets.generated.js +1231 -0
  46. package/dist/diagnostics/spa-assets.generated.js.map +1 -0
  47. package/dist/diagnostics/status.d.ts +38 -0
  48. package/dist/diagnostics/status.d.ts.map +1 -0
  49. package/dist/diagnostics/status.js +53 -0
  50. package/dist/diagnostics/status.js.map +1 -0
  51. package/dist/diagnostics/summary.d.ts +48 -0
  52. package/dist/diagnostics/summary.d.ts.map +1 -0
  53. package/dist/diagnostics/summary.js +116 -0
  54. package/dist/diagnostics/summary.js.map +1 -0
  55. package/dist/diagnostics/tool.d.ts +16 -0
  56. package/dist/diagnostics/tool.d.ts.map +1 -0
  57. package/dist/diagnostics/tool.js +90 -0
  58. package/dist/diagnostics/tool.js.map +1 -0
  59. package/dist/engine/asset-sources.d.ts +8 -0
  60. package/dist/engine/asset-sources.d.ts.map +1 -1
  61. package/dist/engine/asset-sources.js +9 -2
  62. package/dist/engine/asset-sources.js.map +1 -1
  63. package/dist/engine/cesdk-adapter.d.ts +5 -1
  64. package/dist/engine/cesdk-adapter.d.ts.map +1 -1
  65. package/dist/engine/cesdk-adapter.js +8 -1
  66. package/dist/engine/cesdk-adapter.js.map +1 -1
  67. package/dist/engine/engine-capacity.d.ts +16 -0
  68. package/dist/engine/engine-capacity.d.ts.map +1 -0
  69. package/dist/engine/engine-capacity.js +48 -0
  70. package/dist/engine/engine-capacity.js.map +1 -0
  71. package/dist/engine/engine-slots.d.ts +48 -0
  72. package/dist/engine/engine-slots.d.ts.map +1 -0
  73. package/dist/engine/engine-slots.js +182 -0
  74. package/dist/engine/engine-slots.js.map +1 -0
  75. package/dist/engine/uri-resolver.js.map +1 -1
  76. package/dist/server.d.ts +25 -0
  77. package/dist/server.d.ts.map +1 -1
  78. package/dist/server.js +24 -4
  79. package/dist/server.js.map +1 -1
  80. package/dist/tools/engine.d.ts +92 -14
  81. package/dist/tools/engine.d.ts.map +1 -1
  82. package/dist/tools/engine.js +147 -20
  83. package/dist/tools/engine.js.map +1 -1
  84. package/dist/tools/export.d.ts.map +1 -1
  85. package/dist/tools/export.js +34 -4
  86. package/dist/tools/export.js.map +1 -1
  87. package/dist/tools/index.js +2 -2
  88. package/dist/tools/index.js.map +1 -1
  89. package/dist/tools/load.d.ts.map +1 -1
  90. package/dist/tools/load.js +26 -19
  91. package/dist/tools/load.js.map +1 -1
  92. package/dist/tools/preview.d.ts.map +1 -1
  93. package/dist/tools/preview.js +60 -40
  94. package/dist/tools/preview.js.map +1 -1
  95. package/dist/tools/{open-editor.d.ts → view.d.ts} +3 -3
  96. package/dist/tools/view.d.ts.map +1 -0
  97. package/dist/tools/{open-editor.js → view.js} +20 -18
  98. package/dist/tools/view.js.map +1 -0
  99. package/dist/viewer/listener.d.ts +2 -0
  100. package/dist/viewer/listener.d.ts.map +1 -1
  101. package/dist/viewer/listener.js +2 -0
  102. package/dist/viewer/listener.js.map +1 -1
  103. package/dist/viewer/presigned-r2-url-builder.d.ts +1 -1
  104. package/dist/viewer/presigned-r2-url-builder.js +1 -1
  105. package/dist/viewer/presigned-r2-url-builder.js.map +1 -1
  106. package/dist/viewer/router.d.ts.map +1 -1
  107. package/dist/viewer/router.js +8 -17
  108. package/dist/viewer/router.js.map +1 -1
  109. package/dist/viewer/session-mount.js.map +1 -1
  110. package/dist/viewer/spa-assets.generated.d.ts.map +1 -1
  111. package/dist/viewer/spa-assets.generated.js +750 -869
  112. package/dist/viewer/spa-assets.generated.js.map +1 -1
  113. package/dist/viewer/url-builder.d.ts +4 -3
  114. package/dist/viewer/url-builder.d.ts.map +1 -1
  115. package/dist/viewer/url-builder.js +4 -4
  116. package/dist/viewer/url-builder.js.map +1 -1
  117. package/package.json +7 -6
  118. package/dist/dashboard/router.d.ts +0 -3
  119. package/dist/dashboard/router.d.ts.map +0 -1
  120. package/dist/dashboard/router.js +0 -19
  121. package/dist/dashboard/router.js.map +0 -1
  122. package/dist/dashboard/spa-assets.generated.d.ts.map +0 -1
  123. package/dist/dashboard/spa-assets.generated.js +0 -220
  124. package/dist/dashboard/spa-assets.generated.js.map +0 -1
  125. package/dist/metrics/mount.d.ts +0 -11
  126. package/dist/metrics/mount.d.ts.map +0 -1
  127. package/dist/metrics/mount.js +0 -13
  128. package/dist/metrics/mount.js.map +0 -1
  129. package/dist/metrics/recorder.d.ts +0 -55
  130. package/dist/metrics/recorder.d.ts.map +0 -1
  131. package/dist/metrics/recorder.js +0 -97
  132. package/dist/metrics/recorder.js.map +0 -1
  133. package/dist/test/scripts/changelog-add.d.ts +0 -8
  134. package/dist/test/scripts/changelog-add.d.ts.map +0 -1
  135. package/dist/test/scripts/changelog-add.js +0 -50
  136. package/dist/test/scripts/changelog-add.js.map +0 -1
  137. package/dist/test/scripts/changelog-collate.d.ts +0 -38
  138. package/dist/test/scripts/changelog-collate.d.ts.map +0 -1
  139. package/dist/test/scripts/changelog-collate.js +0 -171
  140. package/dist/test/scripts/changelog-collate.js.map +0 -1
  141. package/dist/test/test/changelog.test.d.ts +0 -2
  142. package/dist/test/test/changelog.test.d.ts.map +0 -1
  143. package/dist/test/test/changelog.test.js +0 -293
  144. package/dist/test/test/changelog.test.js.map +0 -1
  145. package/dist/test/test/cli/dispatcher.test.d.ts +0 -2
  146. package/dist/test/test/cli/dispatcher.test.d.ts.map +0 -1
  147. package/dist/test/test/cli/dispatcher.test.js +0 -54
  148. package/dist/test/test/cli/dispatcher.test.js.map +0 -1
  149. package/dist/test/test/cli/redirect-console.test.d.ts +0 -2
  150. package/dist/test/test/cli/redirect-console.test.d.ts.map +0 -1
  151. package/dist/test/test/cli/redirect-console.test.js +0 -78
  152. package/dist/test/test/cli/redirect-console.test.js.map +0 -1
  153. package/dist/test/test/cli/resolve-license.test.d.ts +0 -2
  154. package/dist/test/test/cli/resolve-license.test.d.ts.map +0 -1
  155. package/dist/test/test/cli/resolve-license.test.js +0 -29
  156. package/dist/test/test/cli/resolve-license.test.js.map +0 -1
  157. package/dist/test/test/cli/stdio-diagnostics.test.d.ts +0 -2
  158. package/dist/test/test/cli/stdio-diagnostics.test.d.ts.map +0 -1
  159. package/dist/test/test/cli/stdio-diagnostics.test.js +0 -31
  160. package/dist/test/test/cli/stdio-diagnostics.test.js.map +0 -1
  161. package/dist/test/test/cli/stdio-license.test.d.ts +0 -2
  162. package/dist/test/test/cli/stdio-license.test.d.ts.map +0 -1
  163. package/dist/test/test/cli/stdio-license.test.js +0 -19
  164. package/dist/test/test/cli/stdio-license.test.js.map +0 -1
  165. package/dist/test/test/config.test.d.ts +0 -2
  166. package/dist/test/test/config.test.d.ts.map +0 -1
  167. package/dist/test/test/config.test.js +0 -95
  168. package/dist/test/test/config.test.js.map +0 -1
  169. package/dist/test/test/cross-ref.test.d.ts +0 -2
  170. package/dist/test/test/cross-ref.test.d.ts.map +0 -1
  171. package/dist/test/test/cross-ref.test.js +0 -39
  172. package/dist/test/test/cross-ref.test.js.map +0 -1
  173. package/dist/test/test/diagnostics/bundle.test.d.ts +0 -2
  174. package/dist/test/test/diagnostics/bundle.test.d.ts.map +0 -1
  175. package/dist/test/test/diagnostics/bundle.test.js +0 -53
  176. package/dist/test/test/diagnostics/bundle.test.js.map +0 -1
  177. package/dist/test/test/diagnostics/compose.test.d.ts +0 -2
  178. package/dist/test/test/diagnostics/compose.test.d.ts.map +0 -1
  179. package/dist/test/test/diagnostics/compose.test.js +0 -31
  180. package/dist/test/test/diagnostics/compose.test.js.map +0 -1
  181. package/dist/test/test/diagnostics/file-sink.test.d.ts +0 -2
  182. package/dist/test/test/diagnostics/file-sink.test.d.ts.map +0 -1
  183. package/dist/test/test/diagnostics/file-sink.test.js +0 -113
  184. package/dist/test/test/diagnostics/file-sink.test.js.map +0 -1
  185. package/dist/test/test/diagnostics/redact.test.d.ts +0 -2
  186. package/dist/test/test/diagnostics/redact.test.d.ts.map +0 -1
  187. package/dist/test/test/diagnostics/redact.test.js +0 -59
  188. package/dist/test/test/diagnostics/redact.test.js.map +0 -1
  189. package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts +0 -2
  190. package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts.map +0 -1
  191. package/dist/test/test/diagnostics/tool-call-adapter.test.js +0 -34
  192. package/dist/test/test/diagnostics/tool-call-adapter.test.js.map +0 -1
  193. package/dist/test/test/engine/asset-sources.test.d.ts +0 -2
  194. package/dist/test/test/engine/asset-sources.test.d.ts.map +0 -1
  195. package/dist/test/test/engine/asset-sources.test.js +0 -100
  196. package/dist/test/test/engine/asset-sources.test.js.map +0 -1
  197. package/dist/test/test/engine/cesdk-adapter.test.d.ts +0 -2
  198. package/dist/test/test/engine/cesdk-adapter.test.d.ts.map +0 -1
  199. package/dist/test/test/engine/cesdk-adapter.test.js +0 -32
  200. package/dist/test/test/engine/cesdk-adapter.test.js.map +0 -1
  201. package/dist/test/test/engine/mutex.test.d.ts +0 -2
  202. package/dist/test/test/engine/mutex.test.d.ts.map +0 -1
  203. package/dist/test/test/engine/mutex.test.js +0 -63
  204. package/dist/test/test/engine/mutex.test.js.map +0 -1
  205. package/dist/test/test/engine/session.test.d.ts +0 -2
  206. package/dist/test/test/engine/session.test.d.ts.map +0 -1
  207. package/dist/test/test/engine/session.test.js +0 -159
  208. package/dist/test/test/engine/session.test.js.map +0 -1
  209. package/dist/test/test/engine/unsplash-source.test.d.ts +0 -2
  210. package/dist/test/test/engine/unsplash-source.test.d.ts.map +0 -1
  211. package/dist/test/test/engine/unsplash-source.test.js +0 -129
  212. package/dist/test/test/engine/unsplash-source.test.js.map +0 -1
  213. package/dist/test/test/engine/uri-resolver.test.d.ts +0 -2
  214. package/dist/test/test/engine/uri-resolver.test.d.ts.map +0 -1
  215. package/dist/test/test/engine/uri-resolver.test.js +0 -38
  216. package/dist/test/test/engine/uri-resolver.test.js.map +0 -1
  217. package/dist/test/test/gateway/hosted-stub.test.d.ts +0 -2
  218. package/dist/test/test/gateway/hosted-stub.test.d.ts.map +0 -1
  219. package/dist/test/test/gateway/hosted-stub.test.js +0 -11
  220. package/dist/test/test/gateway/hosted-stub.test.js.map +0 -1
  221. package/dist/test/test/gateway/local.test.d.ts +0 -2
  222. package/dist/test/test/gateway/local.test.d.ts.map +0 -1
  223. package/dist/test/test/gateway/local.test.js +0 -29
  224. package/dist/test/test/gateway/local.test.js.map +0 -1
  225. package/dist/test/test/handbook-contract.test.d.ts +0 -2
  226. package/dist/test/test/handbook-contract.test.d.ts.map +0 -1
  227. package/dist/test/test/handbook-contract.test.js +0 -79
  228. package/dist/test/test/handbook-contract.test.js.map +0 -1
  229. package/dist/test/test/http/server.test.d.ts +0 -2
  230. package/dist/test/test/http/server.test.d.ts.map +0 -1
  231. package/dist/test/test/http/server.test.js +0 -338
  232. package/dist/test/test/http/server.test.js.map +0 -1
  233. package/dist/test/test/http/session-id-header.test.d.ts +0 -2
  234. package/dist/test/test/http/session-id-header.test.d.ts.map +0 -1
  235. package/dist/test/test/http/session-id-header.test.js +0 -76
  236. package/dist/test/test/http/session-id-header.test.js.map +0 -1
  237. package/dist/test/test/http/session-manager.test.d.ts +0 -2
  238. package/dist/test/test/http/session-manager.test.d.ts.map +0 -1
  239. package/dist/test/test/http/session-manager.test.js +0 -97
  240. package/dist/test/test/http/session-manager.test.js.map +0 -1
  241. package/dist/test/test/http/workspace-auth.test.d.ts +0 -2
  242. package/dist/test/test/http/workspace-auth.test.d.ts.map +0 -1
  243. package/dist/test/test/http/workspace-auth.test.js +0 -40
  244. package/dist/test/test/http/workspace-auth.test.js.map +0 -1
  245. package/dist/test/test/metrics/mount.test.d.ts +0 -2
  246. package/dist/test/test/metrics/mount.test.d.ts.map +0 -1
  247. package/dist/test/test/metrics/mount.test.js +0 -59
  248. package/dist/test/test/metrics/mount.test.js.map +0 -1
  249. package/dist/test/test/metrics/recorder.test.d.ts +0 -2
  250. package/dist/test/test/metrics/recorder.test.d.ts.map +0 -1
  251. package/dist/test/test/metrics/recorder.test.js +0 -118
  252. package/dist/test/test/metrics/recorder.test.js.map +0 -1
  253. package/dist/test/test/revisions/hash.test.d.ts +0 -2
  254. package/dist/test/test/revisions/hash.test.d.ts.map +0 -1
  255. package/dist/test/test/revisions/hash.test.js +0 -33
  256. package/dist/test/test/revisions/hash.test.js.map +0 -1
  257. package/dist/test/test/revisions/store.test.d.ts +0 -2
  258. package/dist/test/test/revisions/store.test.d.ts.map +0 -1
  259. package/dist/test/test/revisions/store.test.js +0 -315
  260. package/dist/test/test/revisions/store.test.js.map +0 -1
  261. package/dist/test/test/server.metrics.test.d.ts +0 -2
  262. package/dist/test/test/server.metrics.test.d.ts.map +0 -1
  263. package/dist/test/test/server.metrics.test.js +0 -87
  264. package/dist/test/test/server.metrics.test.js.map +0 -1
  265. package/dist/test/test/server.test.d.ts +0 -2
  266. package/dist/test/test/server.test.d.ts.map +0 -1
  267. package/dist/test/test/server.test.js +0 -146
  268. package/dist/test/test/server.test.js.map +0 -1
  269. package/dist/test/test/skill-tools.test.d.ts +0 -2
  270. package/dist/test/test/skill-tools.test.d.ts.map +0 -1
  271. package/dist/test/test/skill-tools.test.js +0 -84
  272. package/dist/test/test/skill-tools.test.js.map +0 -1
  273. package/dist/test/test/smoke.test.d.ts +0 -2
  274. package/dist/test/test/smoke.test.d.ts.map +0 -1
  275. package/dist/test/test/smoke.test.js +0 -8
  276. package/dist/test/test/smoke.test.js.map +0 -1
  277. package/dist/test/test/tools/asset-generate.test.d.ts +0 -2
  278. package/dist/test/test/tools/asset-generate.test.d.ts.map +0 -1
  279. package/dist/test/test/tools/asset-generate.test.js +0 -66
  280. package/dist/test/test/tools/asset-generate.test.js.map +0 -1
  281. package/dist/test/test/tools/asset-search.test.d.ts +0 -2
  282. package/dist/test/test/tools/asset-search.test.d.ts.map +0 -1
  283. package/dist/test/test/tools/asset-search.test.js +0 -121
  284. package/dist/test/test/tools/asset-search.test.js.map +0 -1
  285. package/dist/test/test/tools/edit-harness.d.ts +0 -14
  286. package/dist/test/test/tools/edit-harness.d.ts.map +0 -1
  287. package/dist/test/test/tools/edit-harness.js +0 -30
  288. package/dist/test/test/tools/edit-harness.js.map +0 -1
  289. package/dist/test/test/tools/edit.telemetry.test.d.ts +0 -2
  290. package/dist/test/test/tools/edit.telemetry.test.d.ts.map +0 -1
  291. package/dist/test/test/tools/edit.telemetry.test.js +0 -46
  292. package/dist/test/test/tools/edit.telemetry.test.js.map +0 -1
  293. package/dist/test/test/tools/edit.test.d.ts +0 -2
  294. package/dist/test/test/tools/edit.test.d.ts.map +0 -1
  295. package/dist/test/test/tools/edit.test.js +0 -267
  296. package/dist/test/test/tools/edit.test.js.map +0 -1
  297. package/dist/test/test/tools/export-harness.d.ts +0 -13
  298. package/dist/test/test/tools/export-harness.d.ts.map +0 -1
  299. package/dist/test/test/tools/export-harness.js +0 -27
  300. package/dist/test/test/tools/export-harness.js.map +0 -1
  301. package/dist/test/test/tools/export.telemetry.test.d.ts +0 -2
  302. package/dist/test/test/tools/export.telemetry.test.d.ts.map +0 -1
  303. package/dist/test/test/tools/export.telemetry.test.js +0 -65
  304. package/dist/test/test/tools/export.telemetry.test.js.map +0 -1
  305. package/dist/test/test/tools/export.test.d.ts +0 -2
  306. package/dist/test/test/tools/export.test.d.ts.map +0 -1
  307. package/dist/test/test/tools/export.test.js +0 -174
  308. package/dist/test/test/tools/export.test.js.map +0 -1
  309. package/dist/test/test/tools/history.test.d.ts +0 -2
  310. package/dist/test/test/tools/history.test.d.ts.map +0 -1
  311. package/dist/test/test/tools/history.test.js +0 -29
  312. package/dist/test/test/tools/history.test.js.map +0 -1
  313. package/dist/test/test/tools/import.test.d.ts +0 -2
  314. package/dist/test/test/tools/import.test.d.ts.map +0 -1
  315. package/dist/test/test/tools/import.test.js +0 -122
  316. package/dist/test/test/tools/import.test.js.map +0 -1
  317. package/dist/test/test/tools/index.test.d.ts +0 -2
  318. package/dist/test/test/tools/index.test.d.ts.map +0 -1
  319. package/dist/test/test/tools/index.test.js +0 -117
  320. package/dist/test/test/tools/index.test.js.map +0 -1
  321. package/dist/test/test/tools/inspect.test.d.ts +0 -2
  322. package/dist/test/test/tools/inspect.test.d.ts.map +0 -1
  323. package/dist/test/test/tools/inspect.test.js +0 -62
  324. package/dist/test/test/tools/inspect.test.js.map +0 -1
  325. package/dist/test/test/tools/list.test.d.ts +0 -2
  326. package/dist/test/test/tools/list.test.d.ts.map +0 -1
  327. package/dist/test/test/tools/list.test.js +0 -23
  328. package/dist/test/test/tools/list.test.js.map +0 -1
  329. package/dist/test/test/tools/load.integration.test.d.ts +0 -2
  330. package/dist/test/test/tools/load.integration.test.d.ts.map +0 -1
  331. package/dist/test/test/tools/load.integration.test.js +0 -165
  332. package/dist/test/test/tools/load.integration.test.js.map +0 -1
  333. package/dist/test/test/tools/load.test.d.ts +0 -2
  334. package/dist/test/test/tools/load.test.d.ts.map +0 -1
  335. package/dist/test/test/tools/load.test.js +0 -387
  336. package/dist/test/test/tools/load.test.js.map +0 -1
  337. package/dist/test/test/tools/metrics.test.d.ts +0 -2
  338. package/dist/test/test/tools/metrics.test.d.ts.map +0 -1
  339. package/dist/test/test/tools/metrics.test.js +0 -29
  340. package/dist/test/test/tools/metrics.test.js.map +0 -1
  341. package/dist/test/test/tools/open-editor.test.d.ts +0 -2
  342. package/dist/test/test/tools/open-editor.test.d.ts.map +0 -1
  343. package/dist/test/test/tools/open-editor.test.js +0 -53
  344. package/dist/test/test/tools/open-editor.test.js.map +0 -1
  345. package/dist/test/test/tools/preview-harness.d.ts +0 -9
  346. package/dist/test/test/tools/preview-harness.d.ts.map +0 -1
  347. package/dist/test/test/tools/preview-harness.js +0 -23
  348. package/dist/test/test/tools/preview-harness.js.map +0 -1
  349. package/dist/test/test/tools/preview.telemetry.test.d.ts +0 -2
  350. package/dist/test/test/tools/preview.telemetry.test.d.ts.map +0 -1
  351. package/dist/test/test/tools/preview.telemetry.test.js +0 -36
  352. package/dist/test/test/tools/preview.telemetry.test.js.map +0 -1
  353. package/dist/test/test/tools/preview.test.d.ts +0 -2
  354. package/dist/test/test/tools/preview.test.d.ts.map +0 -1
  355. package/dist/test/test/tools/preview.test.js +0 -75
  356. package/dist/test/test/tools/preview.test.js.map +0 -1
  357. package/dist/test/test/tools/rename.test.d.ts +0 -2
  358. package/dist/test/test/tools/rename.test.d.ts.map +0 -1
  359. package/dist/test/test/tools/rename.test.js +0 -16
  360. package/dist/test/test/tools/rename.test.js.map +0 -1
  361. package/dist/test/test/tools/save.test.d.ts +0 -2
  362. package/dist/test/test/tools/save.test.d.ts.map +0 -1
  363. package/dist/test/test/tools/save.test.js +0 -137
  364. package/dist/test/test/tools/save.test.js.map +0 -1
  365. package/dist/test/test/tools/schema-best-practices.d.ts +0 -13
  366. package/dist/test/test/tools/schema-best-practices.d.ts.map +0 -1
  367. package/dist/test/test/tools/schema-best-practices.js +0 -169
  368. package/dist/test/test/tools/schema-best-practices.js.map +0 -1
  369. package/dist/test/test/tools/schema-best-practices.test.d.ts +0 -3
  370. package/dist/test/test/tools/schema-best-practices.test.d.ts.map +0 -1
  371. package/dist/test/test/tools/schema-best-practices.test.js +0 -194
  372. package/dist/test/test/tools/schema-best-practices.test.js.map +0 -1
  373. package/dist/test/test/tools/spans.test.d.ts +0 -2
  374. package/dist/test/test/tools/spans.test.d.ts.map +0 -1
  375. package/dist/test/test/tools/spans.test.js +0 -84
  376. package/dist/test/test/tools/spans.test.js.map +0 -1
  377. package/dist/test/test/viewer/broadcaster.test.d.ts +0 -2
  378. package/dist/test/test/viewer/broadcaster.test.d.ts.map +0 -1
  379. package/dist/test/test/viewer/broadcaster.test.js +0 -53
  380. package/dist/test/test/viewer/broadcaster.test.js.map +0 -1
  381. package/dist/test/test/viewer/cesdk-cdn.test.d.ts +0 -2
  382. package/dist/test/test/viewer/cesdk-cdn.test.d.ts.map +0 -1
  383. package/dist/test/test/viewer/cesdk-cdn.test.js +0 -19
  384. package/dist/test/test/viewer/cesdk-cdn.test.js.map +0 -1
  385. package/dist/test/test/viewer/config-route.test.d.ts +0 -2
  386. package/dist/test/test/viewer/config-route.test.d.ts.map +0 -1
  387. package/dist/test/test/viewer/config-route.test.js +0 -28
  388. package/dist/test/test/viewer/config-route.test.js.map +0 -1
  389. package/dist/test/test/viewer/resource-route.test.d.ts +0 -2
  390. package/dist/test/test/viewer/resource-route.test.d.ts.map +0 -1
  391. package/dist/test/test/viewer/resource-route.test.js +0 -70
  392. package/dist/test/test/viewer/resource-route.test.js.map +0 -1
  393. package/dist/test/test/viewer/router.test.d.ts +0 -2
  394. package/dist/test/test/viewer/router.test.d.ts.map +0 -1
  395. package/dist/test/test/viewer/router.test.js +0 -227
  396. package/dist/test/test/viewer/router.test.js.map +0 -1
  397. package/dist/test/test/viewer/session-mount.test.d.ts +0 -2
  398. package/dist/test/test/viewer/session-mount.test.d.ts.map +0 -1
  399. package/dist/test/test/viewer/session-mount.test.js +0 -52
  400. package/dist/test/test/viewer/session-mount.test.js.map +0 -1
  401. package/dist/test/test/viewer/spa-version.test.d.ts +0 -2
  402. package/dist/test/test/viewer/spa-version.test.d.ts.map +0 -1
  403. package/dist/test/test/viewer/spa-version.test.js +0 -14
  404. package/dist/test/test/viewer/spa-version.test.js.map +0 -1
  405. package/dist/test/test/viewer/url-builder.test.d.ts +0 -2
  406. package/dist/test/test/viewer/url-builder.test.d.ts.map +0 -1
  407. package/dist/test/test/viewer/url-builder.test.js +0 -98
  408. package/dist/test/test/viewer/url-builder.test.js.map +0 -1
  409. package/dist/test/test/workspace/content-hash.test.d.ts +0 -2
  410. package/dist/test/test/workspace/content-hash.test.d.ts.map +0 -1
  411. package/dist/test/test/workspace/content-hash.test.js +0 -17
  412. package/dist/test/test/workspace/content-hash.test.js.map +0 -1
  413. package/dist/test/test/workspace/hosted-stub.test.d.ts +0 -2
  414. package/dist/test/test/workspace/hosted-stub.test.d.ts.map +0 -1
  415. package/dist/test/test/workspace/hosted-stub.test.js +0 -30
  416. package/dist/test/test/workspace/hosted-stub.test.js.map +0 -1
  417. package/dist/test/test/workspace/in-memory.test.d.ts +0 -2
  418. package/dist/test/test/workspace/in-memory.test.d.ts.map +0 -1
  419. package/dist/test/test/workspace/in-memory.test.js +0 -4
  420. package/dist/test/test/workspace/in-memory.test.js.map +0 -1
  421. package/dist/test/test/workspace/node-fs.test.d.ts +0 -2
  422. package/dist/test/test/workspace/node-fs.test.d.ts.map +0 -1
  423. package/dist/test/test/workspace/node-fs.test.js +0 -20
  424. package/dist/test/test/workspace/node-fs.test.js.map +0 -1
  425. package/dist/test/test/workspace/s3.test.d.ts +0 -2
  426. package/dist/test/test/workspace/s3.test.d.ts.map +0 -1
  427. package/dist/test/test/workspace/s3.test.js +0 -153
  428. package/dist/test/test/workspace/s3.test.js.map +0 -1
  429. package/dist/test/test/workspace/scoped.test.d.ts +0 -2
  430. package/dist/test/test/workspace/scoped.test.d.ts.map +0 -1
  431. package/dist/test/test/workspace/scoped.test.js +0 -59
  432. package/dist/test/test/workspace/scoped.test.js.map +0 -1
  433. package/dist/test/test/workspace/shared-contract.d.ts +0 -3
  434. package/dist/test/test/workspace/shared-contract.d.ts.map +0 -1
  435. package/dist/test/test/workspace/shared-contract.js +0 -92
  436. package/dist/test/test/workspace/shared-contract.js.map +0 -1
  437. package/dist/test/tsconfig.test.tsbuildinfo +0 -1
  438. package/dist/test/vitest.config.d.ts +0 -3
  439. package/dist/test/vitest.config.d.ts.map +0 -1
  440. package/dist/test/vitest.config.js +0 -8
  441. package/dist/test/vitest.config.js.map +0 -1
  442. package/dist/tools/metrics.d.ts +0 -11
  443. package/dist/tools/metrics.d.ts.map +0 -1
  444. package/dist/tools/metrics.js +0 -28
  445. package/dist/tools/metrics.js.map +0 -1
  446. package/dist/tools/open-editor.d.ts.map +0 -1
  447. package/dist/tools/open-editor.js.map +0 -1
  448. /package/dist/{dashboard → diagnostics}/spa-assets.generated.d.ts +0 -0
@@ -1,46 +0,0 @@
1
- // packages/codesign-mcp/test/tools/edit.telemetry.test.ts
2
- import { describe, it, expect } from 'vitest';
3
- import { createEditTool } from '../../src/tools/edit.js';
4
- import { makeEditHarness } from './edit-harness.js';
5
- describe('edit telemetry', () => {
6
- it('records a successful tool_call report with ordered phase spans', async () => {
7
- const reports = [];
8
- const telemetry = { record: (r) => reports.push(r) };
9
- const tool = createEditTool({ ...makeEditHarness(), telemetry });
10
- const res = await tool.call({ parent: null, code: 'return undefined' });
11
- expect(res.isError).toBeUndefined();
12
- expect(reports).toHaveLength(1);
13
- const r = reports[0];
14
- expect(r.tool).toBe('edit');
15
- expect(r.succeeded).toBe(true);
16
- expect(r.revision).toBe('newrev');
17
- expect(r.spans.map((s) => s.phase)).toEqual(expect.arrayContaining([
18
- 'engine_scene_load',
19
- 'engine_execute',
20
- 'engine_scene_save',
21
- 'workspace_write'
22
- ]));
23
- const sum = r.spans.reduce((n, s) => n + s.ms, 0);
24
- expect(sum).toBeLessThanOrEqual(r.totalMs + 1); // Σspans ≤ totalMs (+float slack)
25
- });
26
- it('records succeeded=false with error when code throws', async () => {
27
- const reports = [];
28
- const tool = createEditTool({
29
- ...makeEditHarness(),
30
- telemetry: { record: (r) => reports.push(r) }
31
- });
32
- const res = await tool.call({
33
- parent: null,
34
- code: 'throw new Error("boom")'
35
- });
36
- expect(res.isError).toBe(true);
37
- expect(reports[0].succeeded).toBe(false);
38
- expect(reports[0].error?.message).toContain('boom');
39
- });
40
- it('does nothing observable when no telemetry is injected', async () => {
41
- const tool = createEditTool(makeEditHarness());
42
- const res = await tool.call({ parent: null, code: 'return undefined' });
43
- expect(res.isError).toBeUndefined();
44
- });
45
- });
46
- //# sourceMappingURL=edit.telemetry.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"edit.telemetry.test.js","sourceRoot":"","sources":["../../../../test/tools/edit.telemetry.test.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/codesign-mcp/test/tools/edit.telemetry.test.ts\nimport { describe, it, expect } from 'vitest';\nimport { createEditTool } from '../../src/tools/edit.js';\nimport type { ToolCallReport } from '../../src/tools/spans.js';\nimport { makeEditHarness } from './edit-harness.js';\n\ndescribe('edit telemetry', () => {\n it('records a successful tool_call report with ordered phase spans', async () => {\n const reports: ToolCallReport[] = [];\n const telemetry = { record: (r: ToolCallReport) => reports.push(r) };\n const tool = createEditTool({ ...makeEditHarness(), telemetry });\n\n const res = await tool.call({ parent: null, code: 'return undefined' });\n expect(res.isError).toBeUndefined();\n expect(reports).toHaveLength(1);\n const r = reports[0];\n expect(r.tool).toBe('edit');\n expect(r.succeeded).toBe(true);\n expect(r.revision).toBe('newrev');\n expect(r.spans.map((s) => s.phase)).toEqual(\n expect.arrayContaining([\n 'engine_scene_load',\n 'engine_execute',\n 'engine_scene_save',\n 'workspace_write'\n ])\n );\n const sum = r.spans.reduce((n, s) => n + s.ms, 0);\n expect(sum).toBeLessThanOrEqual(r.totalMs + 1); // Σspans ≤ totalMs (+float slack)\n });\n\n it('records succeeded=false with error when code throws', async () => {\n const reports: ToolCallReport[] = [];\n const tool = createEditTool({\n ...makeEditHarness(),\n telemetry: { record: (r) => reports.push(r) }\n });\n const res = await tool.call({\n parent: null,\n code: 'throw new Error(\"boom\")'\n });\n expect(res.isError).toBe(true);\n expect(reports[0].succeeded).toBe(false);\n expect(reports[0].error?.message).toContain('boom');\n });\n\n it('does nothing observable when no telemetry is injected', async () => {\n const tool = createEditTool(makeEditHarness());\n const res = await tool.call({ parent: null, code: 'return undefined' });\n expect(res.isError).toBeUndefined();\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=edit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"edit.test.d.ts","sourceRoot":"","sources":["../../../../test/tools/edit.test.ts"],"names":[],"mappings":""}
@@ -1,267 +0,0 @@
1
- // packages/codesign-mcp/test/tools/edit.test.ts
2
- import { describe, expect, it, vi } from 'vitest';
3
- import { Mutex } from '../../src/engine/mutex.js';
4
- import { EngineSession } from '../../src/engine/session.js';
5
- import { RevisionStore } from '../../src/revisions/store.js';
6
- import { createEditTool } from '../../src/tools/edit.js';
7
- import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
8
- const engineLock = new Mutex();
9
- function makeDeps() {
10
- const fs = new InMemoryWorkspaceFS();
11
- const store = new RevisionStore(fs);
12
- const fakeEngine = { _scene: '' };
13
- const adapter = {
14
- create: () => fakeEngine,
15
- reset: vi.fn(async () => {
16
- fakeEngine._scene = 'EMPTY';
17
- }),
18
- loadFromString: vi.fn(async (e, s) => {
19
- e._scene = s;
20
- }),
21
- saveToString: vi.fn(async (e) => e._scene)
22
- };
23
- const session = new EngineSession({ size: 1, adapter });
24
- const onLeafWritten = vi.fn();
25
- return { fs, store, session, adapter, onLeafWritten, fakeEngine };
26
- }
27
- describe('edit tool — happy path', () => {
28
- it('parent=null resets engine, writes a root revision, returns {revision, parent}', async () => {
29
- const { store, session, adapter, onLeafWritten } = makeDeps();
30
- const tool = createEditTool({ store, session, engineLock, onLeafWritten });
31
- // The user `code` is what mutates the engine — it runs AFTER reset/loadFromString
32
- // resets the slot. So we set _scene from inside the code string.
33
- const result = await tool.call({
34
- parent: null,
35
- code: "engine._scene = 'ENGINE_AFTER_USER_CODE'",
36
- title: 'Wedding card',
37
- note: 'blank canvas'
38
- });
39
- expect(adapter.reset).toHaveBeenCalledOnce();
40
- expect(result.isError).toBeFalsy();
41
- const part = result.content[0];
42
- const envelope = JSON.parse(part.text);
43
- expect(envelope.parent).toBeNull();
44
- expect(envelope.revision).toMatch(/^[0-9a-f]{12}$/);
45
- expect(onLeafWritten).toHaveBeenCalledWith({
46
- revision: envelope.revision,
47
- rootRevision: envelope.revision
48
- });
49
- const persisted = await store.read(envelope.revision);
50
- expect(persisted.meta.title).toBe('Wedding card');
51
- expect(persisted.scene).toBe('ENGINE_AFTER_USER_CODE');
52
- // The code that ran is persisted alongside the revision for `inspect`.
53
- expect(await store.readCode(envelope.revision)).toBe("engine._scene = 'ENGINE_AFTER_USER_CODE'");
54
- });
55
- it('parent=existing revision is a linear edit (no reload on warm slot)', async () => {
56
- const { store, session, adapter, onLeafWritten } = makeDeps();
57
- const tool = createEditTool({ store, session, engineLock, onLeafWritten });
58
- const first = await tool.call({
59
- parent: null,
60
- code: "engine._scene = 'SCENE_V1'",
61
- title: 'T'
62
- });
63
- const firstRev = JSON.parse(first.content[0].text).revision;
64
- adapter.loadFromString.mockClear();
65
- const second = await tool.call({
66
- parent: firstRev,
67
- code: "engine._scene = 'SCENE_V2'",
68
- note: 'tweak'
69
- });
70
- expect(adapter.loadFromString).not.toHaveBeenCalled(); // engine already at firstRev
71
- const secondRev = JSON.parse(second.content[0].text).revision;
72
- const persisted = await store.read(secondRev);
73
- expect(persisted.meta.parent).toBe(firstRev);
74
- expect(persisted.scene).toBe('SCENE_V2');
75
- });
76
- it('parent=older revision reloads engine and creates a fork', async () => {
77
- const { store, session, adapter, onLeafWritten } = makeDeps();
78
- const tool = createEditTool({ store, session, engineLock, onLeafWritten });
79
- const r1 = await tool.call({
80
- parent: null,
81
- code: "engine._scene = 'SCENE_V1'",
82
- title: 'T'
83
- });
84
- const rev1 = JSON.parse(r1.content[0].text).revision;
85
- const _r2 = await tool.call({
86
- parent: rev1,
87
- code: "engine._scene = 'SCENE_V2'"
88
- });
89
- // now rewind: parent = rev1
90
- adapter.loadFromString.mockClear();
91
- const r3 = await tool.call({
92
- parent: rev1,
93
- code: "engine._scene = 'SCENE_V3_FORK'"
94
- });
95
- expect(adapter.loadFromString).toHaveBeenCalledOnce(); // reloaded SCENE_V1
96
- const rev3 = JSON.parse(r3.content[0].text).revision;
97
- const persisted = await store.read(rev3);
98
- expect(persisted.meta.parent).toBe(rev1);
99
- expect(persisted.scene).toBe('SCENE_V3_FORK');
100
- });
101
- });
102
- describe('edit tool — safety + validation', () => {
103
- it('marks slot dirty when code throws; next edit pays one reload', async () => {
104
- const { store, session, adapter, onLeafWritten } = makeDeps();
105
- const tool = createEditTool({ store, session, engineLock, onLeafWritten });
106
- const r1 = await tool.call({
107
- parent: null,
108
- code: "engine._scene = 'SCENE_V1'",
109
- title: 'T'
110
- });
111
- const rev1 = JSON.parse(r1.content[0].text).revision;
112
- const bad = await tool.call({
113
- parent: rev1,
114
- code: "throw new Error('boom')"
115
- });
116
- expect(bad.isError).toBe(true);
117
- // Populate the session with the scene so we can re-acquire
118
- const rev = await store.read(rev1);
119
- await session.populate(rev1, rev.scene);
120
- const slot = await session.acquire(rev1);
121
- // After dirty + re-acquire, loadFromString must have been called.
122
- expect(adapter.loadFromString).toHaveBeenCalled();
123
- expect(slot.currentRevision).toBe(rev1);
124
- });
125
- it('returns isError when parent property is missing entirely', async () => {
126
- const { store, session } = makeDeps();
127
- const tool = createEditTool({ store, session, engineLock });
128
- const result = await tool.call({
129
- code: '// no parent'
130
- });
131
- expect(result.isError).toBe(true);
132
- expect(result.content[0].text).toMatch(/parent.*required/i);
133
- });
134
- it('returns isError when code is missing', async () => {
135
- const { store, session } = makeDeps();
136
- const tool = createEditTool({ store, session, engineLock });
137
- const result = await tool.call({ parent: null });
138
- expect(result.isError).toBe(true);
139
- expect(result.content[0].text).toMatch(/code.*required/i);
140
- });
141
- it('coerces the literal string "null" to a real null parent (new design root)', async () => {
142
- // Some LLMs / MCP clients emit the four-character string "null" instead of
143
- // the bare JSON null literal — a quoting slip, not a real revision id. The
144
- // tool coerces "null" → null rather than rejecting, so the slip never
145
- // blocks creating a new design root. (Stochastic, model-dependent.)
146
- const { store, session, adapter } = makeDeps();
147
- const tool = createEditTool({ store, session, engineLock });
148
- const result = await tool.call({
149
- parent: 'null',
150
- code: "engine._scene = 'X'"
151
- });
152
- expect(result.isError).toBeFalsy();
153
- expect(adapter.reset).toHaveBeenCalledOnce(); // treated as parent=null
154
- const envelope = JSON.parse(result.content[0].text);
155
- expect(envelope.parent).toBeNull();
156
- expect(envelope.revision).toMatch(/^[0-9a-f]{12}$/);
157
- });
158
- });
159
- describe('edit tool — per-leaf thumbnail', () => {
160
- it('calls renderThumbnail with the new revision id and persists the bytes', async () => {
161
- const fs = new InMemoryWorkspaceFS();
162
- const store = new RevisionStore(fs);
163
- const fakeEngine = { _scene: '' };
164
- const adapter = {
165
- create: () => fakeEngine,
166
- reset: vi.fn(async () => { }),
167
- loadFromString: vi.fn(async () => { }),
168
- saveToString: vi.fn(async () => fakeEngine._scene)
169
- };
170
- const session = new EngineSession({ size: 1, adapter });
171
- const renderThumbnail = vi.fn(async () => new Uint8Array([0x52, 0x49, 0x46, 0x46])); // "RIFF" — webp header
172
- const tool = createEditTool({
173
- store,
174
- session,
175
- engineLock,
176
- renderThumbnail,
177
- fs
178
- });
179
- const r = await tool.call({
180
- parent: null,
181
- code: "engine._scene = 'SCENE_V1'",
182
- title: 'T'
183
- });
184
- const rev = JSON.parse(r.content[0].text).revision;
185
- expect(renderThumbnail).toHaveBeenCalledWith(expect.objectContaining({ revision: rev }));
186
- const shard = rev.slice(0, 2);
187
- const rest = rev.slice(2);
188
- expect(await fs.exists(`exports/${shard}/${rest}/preview.webp`)).toBe(true);
189
- });
190
- it('does not fail the edit when renderThumbnail throws', async () => {
191
- const fs = new InMemoryWorkspaceFS();
192
- const store = new RevisionStore(fs);
193
- const fakeEngine = { _scene: '' };
194
- const adapter = {
195
- create: () => fakeEngine,
196
- reset: vi.fn(async () => { }),
197
- loadFromString: vi.fn(async () => { }),
198
- saveToString: vi.fn(async () => fakeEngine._scene)
199
- };
200
- const session = new EngineSession({ size: 1, adapter });
201
- const renderThumbnail = vi.fn(async () => {
202
- throw new Error('thumbnail render boom');
203
- });
204
- const tool = createEditTool({
205
- store,
206
- session,
207
- engineLock,
208
- renderThumbnail,
209
- fs
210
- });
211
- const r = await tool.call({
212
- parent: null,
213
- code: "engine._scene = 'S'",
214
- title: 'T'
215
- });
216
- expect(r.isError).toBeFalsy();
217
- });
218
- });
219
- describe('edit tool — concurrency', () => {
220
- it('two sessions sharing one engine do not corrupt each other under the lock', async () => {
221
- const fs = new InMemoryWorkspaceFS();
222
- const store = new RevisionStore(fs);
223
- // ONE shared engine — exactly the production wiring, where
224
- // ensureHeadlessEngine is a process singleton handed to every session.
225
- const sharedEngine = { _scene: '' };
226
- const makeAdapter = () => ({
227
- create: () => sharedEngine,
228
- reset: async () => {
229
- sharedEngine._scene = '';
230
- },
231
- loadFromString: async (e, s) => {
232
- e._scene = s;
233
- },
234
- saveToString: async (e) => e._scene
235
- });
236
- // Each MCP session owns its EngineSession (per-session slot state) but they
237
- // share the engine. ONE lock is shared across sessions — the invariant the
238
- // bootstrap upholds by creating the Mutex once, outside createSession.
239
- const lock = new Mutex();
240
- const sessionA = new EngineSession({ size: 1, adapter: makeAdapter() });
241
- const sessionB = new EngineSession({ size: 1, adapter: makeAdapter() });
242
- const toolA = createEditTool({
243
- store,
244
- session: sessionA,
245
- engineLock: lock
246
- });
247
- const toolB = createEditTool({
248
- store,
249
- session: sessionB,
250
- engineLock: lock
251
- });
252
- // Each edit stamps the shared engine, then awaits — the exact window where,
253
- // WITHOUT the lock, the other session would overwrite the engine before
254
- // saveToString reads it back (so revA would persist SCENE_B). The shared
255
- // lock serializes the two, so each revision keeps its own scene.
256
- const code = (mark) => `engine._scene = '${mark}'; await new Promise((r) => setTimeout(r, 10));`;
257
- const [resA, resB] = await Promise.all([
258
- toolA.call({ parent: null, code: code('SCENE_A'), title: 'A' }),
259
- toolB.call({ parent: null, code: code('SCENE_B'), title: 'B' })
260
- ]);
261
- const revA = JSON.parse(resA.content[0].text).revision;
262
- const revB = JSON.parse(resB.content[0].text).revision;
263
- expect((await store.read(revA)).scene).toBe('SCENE_A');
264
- expect((await store.read(revB)).scene).toBe('SCENE_B');
265
- });
266
- });
267
- //# sourceMappingURL=edit.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"edit.test.js","sourceRoot":"","sources":["../../../../test/tools/edit.test.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/codesign-mcp/test/tools/edit.test.ts\nimport { describe, expect, it, vi } from 'vitest';\nimport { Mutex } from '../../src/engine/mutex.js';\nimport { type EngineAdapter, EngineSession } from '../../src/engine/session.js';\nimport { RevisionStore } from '../../src/revisions/store.js';\nimport { createEditTool } from '../../src/tools/edit.js';\nimport { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';\n\nconst engineLock = new Mutex();\n\nfunction makeDeps() {\n const fs = new InMemoryWorkspaceFS();\n const store = new RevisionStore(fs);\n const fakeEngine = { _scene: '' };\n const adapter: EngineAdapter = {\n create: () => fakeEngine,\n reset: vi.fn(async () => {\n fakeEngine._scene = 'EMPTY';\n }),\n loadFromString: vi.fn(async (e, s) => {\n (e as typeof fakeEngine)._scene = s;\n }),\n saveToString: vi.fn(async (e) => (e as typeof fakeEngine)._scene)\n };\n const session = new EngineSession({ size: 1, adapter });\n const onLeafWritten = vi.fn();\n return { fs, store, session, adapter, onLeafWritten, fakeEngine };\n}\n\ndescribe('edit tool — happy path', () => {\n it('parent=null resets engine, writes a root revision, returns {revision, parent}', async () => {\n const { store, session, adapter, onLeafWritten } = makeDeps();\n const tool = createEditTool({ store, session, engineLock, onLeafWritten });\n // The user `code` is what mutates the engine — it runs AFTER reset/loadFromString\n // resets the slot. So we set _scene from inside the code string.\n const result = await tool.call({\n parent: null,\n code: \"engine._scene = 'ENGINE_AFTER_USER_CODE'\",\n title: 'Wedding card',\n note: 'blank canvas'\n });\n expect(adapter.reset).toHaveBeenCalledOnce();\n expect(result.isError).toBeFalsy();\n const part = result.content[0] as { type: 'text'; text: string };\n const envelope = JSON.parse(part.text) as {\n revision: string;\n parent: string | null;\n };\n expect(envelope.parent).toBeNull();\n expect(envelope.revision).toMatch(/^[0-9a-f]{12}$/);\n expect(onLeafWritten).toHaveBeenCalledWith({\n revision: envelope.revision,\n rootRevision: envelope.revision\n });\n\n const persisted = await store.read(envelope.revision);\n expect(persisted.meta.title).toBe('Wedding card');\n expect(persisted.scene).toBe('ENGINE_AFTER_USER_CODE');\n // The code that ran is persisted alongside the revision for `inspect`.\n expect(await store.readCode(envelope.revision)).toBe(\n \"engine._scene = 'ENGINE_AFTER_USER_CODE'\"\n );\n });\n\n it('parent=existing revision is a linear edit (no reload on warm slot)', async () => {\n const { store, session, adapter, onLeafWritten } = makeDeps();\n const tool = createEditTool({ store, session, engineLock, onLeafWritten });\n const first = await tool.call({\n parent: null,\n code: \"engine._scene = 'SCENE_V1'\",\n title: 'T'\n });\n const firstRev = JSON.parse(\n (first.content[0] as { text: string }).text\n ).revision;\n\n (adapter.loadFromString as ReturnType<typeof vi.fn>).mockClear();\n const second = await tool.call({\n parent: firstRev,\n code: \"engine._scene = 'SCENE_V2'\",\n note: 'tweak'\n });\n expect(adapter.loadFromString).not.toHaveBeenCalled(); // engine already at firstRev\n const secondRev = JSON.parse(\n (second.content[0] as { text: string }).text\n ).revision;\n const persisted = await store.read(secondRev);\n expect(persisted.meta.parent).toBe(firstRev);\n expect(persisted.scene).toBe('SCENE_V2');\n });\n\n it('parent=older revision reloads engine and creates a fork', async () => {\n const { store, session, adapter, onLeafWritten } = makeDeps();\n const tool = createEditTool({ store, session, engineLock, onLeafWritten });\n const r1 = await tool.call({\n parent: null,\n code: \"engine._scene = 'SCENE_V1'\",\n title: 'T'\n });\n const rev1 = JSON.parse((r1.content[0] as { text: string }).text).revision;\n const _r2 = await tool.call({\n parent: rev1,\n code: \"engine._scene = 'SCENE_V2'\"\n });\n // now rewind: parent = rev1\n (adapter.loadFromString as ReturnType<typeof vi.fn>).mockClear();\n const r3 = await tool.call({\n parent: rev1,\n code: \"engine._scene = 'SCENE_V3_FORK'\"\n });\n expect(adapter.loadFromString).toHaveBeenCalledOnce(); // reloaded SCENE_V1\n const rev3 = JSON.parse((r3.content[0] as { text: string }).text).revision;\n const persisted = await store.read(rev3);\n expect(persisted.meta.parent).toBe(rev1);\n expect(persisted.scene).toBe('SCENE_V3_FORK');\n });\n});\n\ndescribe('edit tool — safety + validation', () => {\n it('marks slot dirty when code throws; next edit pays one reload', async () => {\n const { store, session, adapter, onLeafWritten } = makeDeps();\n const tool = createEditTool({ store, session, engineLock, onLeafWritten });\n const r1 = await tool.call({\n parent: null,\n code: \"engine._scene = 'SCENE_V1'\",\n title: 'T'\n });\n const rev1 = JSON.parse((r1.content[0] as { text: string }).text).revision;\n\n const bad = await tool.call({\n parent: rev1,\n code: \"throw new Error('boom')\"\n });\n expect(bad.isError).toBe(true);\n\n // Populate the session with the scene so we can re-acquire\n const rev = await store.read(rev1);\n await session.populate(rev1, rev.scene);\n\n const slot = await session.acquire(rev1);\n // After dirty + re-acquire, loadFromString must have been called.\n expect(adapter.loadFromString).toHaveBeenCalled();\n expect(slot.currentRevision).toBe(rev1);\n });\n\n it('returns isError when parent property is missing entirely', async () => {\n const { store, session } = makeDeps();\n const tool = createEditTool({ store, session, engineLock });\n const result = await tool.call({\n code: '// no parent'\n } as unknown as Record<string, unknown>);\n expect(result.isError).toBe(true);\n expect((result.content[0] as { text: string }).text).toMatch(\n /parent.*required/i\n );\n });\n\n it('returns isError when code is missing', async () => {\n const { store, session } = makeDeps();\n const tool = createEditTool({ store, session, engineLock });\n const result = await tool.call({ parent: null } as unknown as Record<\n string,\n unknown\n >);\n expect(result.isError).toBe(true);\n expect((result.content[0] as { text: string }).text).toMatch(\n /code.*required/i\n );\n });\n\n it('coerces the literal string \"null\" to a real null parent (new design root)', async () => {\n // Some LLMs / MCP clients emit the four-character string \"null\" instead of\n // the bare JSON null literal — a quoting slip, not a real revision id. The\n // tool coerces \"null\" → null rather than rejecting, so the slip never\n // blocks creating a new design root. (Stochastic, model-dependent.)\n const { store, session, adapter } = makeDeps();\n const tool = createEditTool({ store, session, engineLock });\n const result = await tool.call({\n parent: 'null',\n code: \"engine._scene = 'X'\"\n });\n expect(result.isError).toBeFalsy();\n expect(adapter.reset).toHaveBeenCalledOnce(); // treated as parent=null\n const envelope = JSON.parse(\n (result.content[0] as { text: string }).text\n ) as { revision: string; parent: string | null };\n expect(envelope.parent).toBeNull();\n expect(envelope.revision).toMatch(/^[0-9a-f]{12}$/);\n });\n});\n\ndescribe('edit tool — per-leaf thumbnail', () => {\n it('calls renderThumbnail with the new revision id and persists the bytes', async () => {\n const fs = new InMemoryWorkspaceFS();\n const store = new RevisionStore(fs);\n const fakeEngine = { _scene: '' };\n const adapter: EngineAdapter = {\n create: () => fakeEngine,\n reset: vi.fn(async () => {}),\n loadFromString: vi.fn(async () => {}),\n saveToString: vi.fn(async () => fakeEngine._scene)\n };\n const session = new EngineSession({ size: 1, adapter });\n const renderThumbnail = vi.fn(\n async () => new Uint8Array([0x52, 0x49, 0x46, 0x46])\n ); // \"RIFF\" — webp header\n const tool = createEditTool({\n store,\n session,\n engineLock,\n renderThumbnail,\n fs\n });\n const r = await tool.call({\n parent: null,\n code: \"engine._scene = 'SCENE_V1'\",\n title: 'T'\n });\n const rev = JSON.parse((r.content[0] as { text: string }).text).revision;\n expect(renderThumbnail).toHaveBeenCalledWith(\n expect.objectContaining({ revision: rev })\n );\n const shard = rev.slice(0, 2);\n const rest = rev.slice(2);\n expect(await fs.exists(`exports/${shard}/${rest}/preview.webp`)).toBe(true);\n });\n\n it('does not fail the edit when renderThumbnail throws', async () => {\n const fs = new InMemoryWorkspaceFS();\n const store = new RevisionStore(fs);\n const fakeEngine = { _scene: '' };\n const adapter: EngineAdapter = {\n create: () => fakeEngine,\n reset: vi.fn(async () => {}),\n loadFromString: vi.fn(async () => {}),\n saveToString: vi.fn(async () => fakeEngine._scene)\n };\n const session = new EngineSession({ size: 1, adapter });\n const renderThumbnail = vi.fn(async () => {\n throw new Error('thumbnail render boom');\n });\n const tool = createEditTool({\n store,\n session,\n engineLock,\n renderThumbnail,\n fs\n });\n const r = await tool.call({\n parent: null,\n code: \"engine._scene = 'S'\",\n title: 'T'\n });\n expect(r.isError).toBeFalsy();\n });\n});\n\ndescribe('edit tool — concurrency', () => {\n it('two sessions sharing one engine do not corrupt each other under the lock', async () => {\n const fs = new InMemoryWorkspaceFS();\n const store = new RevisionStore(fs);\n // ONE shared engine — exactly the production wiring, where\n // ensureHeadlessEngine is a process singleton handed to every session.\n const sharedEngine = { _scene: '' };\n const makeAdapter = (): EngineAdapter => ({\n create: () => sharedEngine,\n reset: async () => {\n sharedEngine._scene = '';\n },\n loadFromString: async (e, s) => {\n (e as typeof sharedEngine)._scene = s;\n },\n saveToString: async (e) => (e as typeof sharedEngine)._scene\n });\n // Each MCP session owns its EngineSession (per-session slot state) but they\n // share the engine. ONE lock is shared across sessions — the invariant the\n // bootstrap upholds by creating the Mutex once, outside createSession.\n const lock = new Mutex();\n const sessionA = new EngineSession({ size: 1, adapter: makeAdapter() });\n const sessionB = new EngineSession({ size: 1, adapter: makeAdapter() });\n const toolA = createEditTool({\n store,\n session: sessionA,\n engineLock: lock\n });\n const toolB = createEditTool({\n store,\n session: sessionB,\n engineLock: lock\n });\n\n // Each edit stamps the shared engine, then awaits — the exact window where,\n // WITHOUT the lock, the other session would overwrite the engine before\n // saveToString reads it back (so revA would persist SCENE_B). The shared\n // lock serializes the two, so each revision keeps its own scene.\n const code = (mark: string) =>\n `engine._scene = '${mark}'; await new Promise((r) => setTimeout(r, 10));`;\n const [resA, resB] = await Promise.all([\n toolA.call({ parent: null, code: code('SCENE_A'), title: 'A' }),\n toolB.call({ parent: null, code: code('SCENE_B'), title: 'B' })\n ]);\n const revA = (\n JSON.parse((resA.content[0] as { text: string }).text) as {\n revision: string;\n }\n ).revision;\n const revB = (\n JSON.parse((resB.content[0] as { text: string }).text) as {\n revision: string;\n }\n ).revision;\n expect((await store.read(revA)).scene).toBe('SCENE_A');\n expect((await store.read(revB)).scene).toBe('SCENE_B');\n });\n});\n"]}
@@ -1,13 +0,0 @@
1
- import { Mutex } from '../../src/engine/mutex.js';
2
- import { EngineSession } from '../../src/engine/session.js';
3
- import { RevisionStore } from '../../src/revisions/store.js';
4
- import { LocalViewerUrlBuilder } from '../../src/viewer/url-builder.js';
5
- import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
6
- export declare function makeExportHarness(): {
7
- fs: InMemoryWorkspaceFS;
8
- store: RevisionStore;
9
- session: EngineSession<unknown>;
10
- engineLock: Mutex;
11
- urlBuilder: LocalViewerUrlBuilder;
12
- };
13
- //# sourceMappingURL=export-harness.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"export-harness.d.ts","sourceRoot":"","sources":["../../../../test/tools/export-harness.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAsB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE,wBAAgB,iBAAiB;;;;;;EAoBhC"}
@@ -1,27 +0,0 @@
1
- // Shared export-tool test harness — a plain module (no test registrations) so importing it never re-runs export.test.ts.
2
- import { Mutex } from '../../src/engine/mutex.js';
3
- import { EngineSession } from '../../src/engine/session.js';
4
- import { RevisionStore } from '../../src/revisions/store.js';
5
- import { LocalViewerUrlBuilder } from '../../src/viewer/url-builder.js';
6
- import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
7
- export function makeExportHarness() {
8
- const fs = new InMemoryWorkspaceFS();
9
- const store = new RevisionStore(fs);
10
- const fakeEngine = {
11
- block: {
12
- export: async (_id, _mime) => new Blob([new Uint8Array([0xff, 0xd8, 0xff, 0xe0])])
13
- }
14
- };
15
- const adapter = {
16
- create: () => fakeEngine,
17
- reset: async () => { },
18
- loadFromString: async () => { },
19
- saveToString: async () => ''
20
- };
21
- const session = new EngineSession({ size: 1, adapter });
22
- const urlBuilder = new LocalViewerUrlBuilder({
23
- base: 'http://127.0.0.1:9000'
24
- });
25
- return { fs, store, session, engineLock: new Mutex(), urlBuilder };
26
- }
27
- //# sourceMappingURL=export-harness.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"export-harness.js","sourceRoot":"","sources":["../../../../test/tools/export-harness.ts"],"names":[],"mappings":"AAAA,yHAAyH;AACzH,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAsB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,GAAG,IAAI,mBAAmB,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC;IACpC,MAAM,UAAU,GAAG;QACjB,KAAK,EAAE;YACL,MAAM,EAAE,KAAK,EAAE,GAAW,EAAE,KAAa,EAAE,EAAE,CAC3C,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;SACvD;KACF,CAAC;IACF,MAAM,OAAO,GAAkB;QAC7B,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU;QACxB,KAAK,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QACrB,cAAc,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QAC9B,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE;KAC7B,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,IAAI,qBAAqB,CAAC;QAC3C,IAAI,EAAE,uBAAuB;KAC9B,CAAC,CAAC;IACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC;AACrE,CAAC","sourcesContent":["// Shared export-tool test harness — a plain module (no test registrations) so importing it never re-runs export.test.ts.\nimport { Mutex } from '../../src/engine/mutex.js';\nimport { type EngineAdapter, EngineSession } from '../../src/engine/session.js';\nimport { RevisionStore } from '../../src/revisions/store.js';\nimport { LocalViewerUrlBuilder } from '../../src/viewer/url-builder.js';\nimport { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';\n\nexport function makeExportHarness() {\n const fs = new InMemoryWorkspaceFS();\n const store = new RevisionStore(fs);\n const fakeEngine = {\n block: {\n export: async (_id: number, _mime: string) =>\n new Blob([new Uint8Array([0xff, 0xd8, 0xff, 0xe0])])\n }\n };\n const adapter: EngineAdapter = {\n create: () => fakeEngine,\n reset: async () => {},\n loadFromString: async () => {},\n saveToString: async () => ''\n };\n const session = new EngineSession({ size: 1, adapter });\n const urlBuilder = new LocalViewerUrlBuilder({\n base: 'http://127.0.0.1:9000'\n });\n return { fs, store, session, engineLock: new Mutex(), urlBuilder };\n}\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=export.telemetry.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"export.telemetry.test.d.ts","sourceRoot":"","sources":["../../../../test/tools/export.telemetry.test.ts"],"names":[],"mappings":""}
@@ -1,65 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createExportTool } from '../../src/tools/export.js';
3
- import { makeExportHarness } from './export-harness.js';
4
- describe('export telemetry', () => {
5
- it('records workspace_read, engine_scene_load, engine_execute and workspace_write phases', async () => {
6
- const reports = [];
7
- const harness = makeExportHarness();
8
- const root = await harness.store.write({
9
- scene: 'SCENE_FOR_EXPORT',
10
- parent: null,
11
- title: 'T'
12
- });
13
- const tool = createExportTool({
14
- ...harness,
15
- telemetry: { record: (r) => reports.push(r) }
16
- });
17
- const res = await tool.call({
18
- target: 'image',
19
- format: 'png',
20
- revision: root.id,
21
- blockId: 1
22
- });
23
- expect(res.isError).toBeUndefined();
24
- expect(reports).toHaveLength(1);
25
- const r = reports[0];
26
- expect(r.tool).toBe('export');
27
- expect(r.succeeded).toBe(true);
28
- expect(r.revision).toBe(root.id);
29
- const phases = r.spans.map((s) => s.phase);
30
- expect(phases).toEqual(expect.arrayContaining([
31
- 'workspace_read',
32
- 'engine_scene_load',
33
- 'engine_execute',
34
- 'workspace_write'
35
- ]));
36
- expect(phases).not.toContain('engine_scene_save');
37
- });
38
- it('records succeeded=false when required args are missing', async () => {
39
- const reports = [];
40
- const tool = createExportTool({
41
- ...makeExportHarness(),
42
- telemetry: { record: (r) => reports.push(r) }
43
- });
44
- const res = await tool.call({});
45
- expect(res.isError).toBe(true);
46
- expect(reports[0].succeeded).toBe(false);
47
- });
48
- it('does nothing observable when no telemetry is injected', async () => {
49
- const harness = makeExportHarness();
50
- const root = await harness.store.write({
51
- scene: 'S',
52
- parent: null,
53
- title: 'T'
54
- });
55
- const tool = createExportTool(harness);
56
- const res = await tool.call({
57
- target: 'image',
58
- format: 'png',
59
- revision: root.id,
60
- blockId: 1
61
- });
62
- expect(res.isError).toBeUndefined();
63
- });
64
- });
65
- //# sourceMappingURL=export.telemetry.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"export.telemetry.test.js","sourceRoot":"","sources":["../../../../test/tools/export.telemetry.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { createExportTool } from '../../src/tools/export.js';\nimport type { ToolCallReport } from '../../src/tools/spans.js';\nimport { makeExportHarness } from './export-harness.js';\n\ndescribe('export telemetry', () => {\n it('records workspace_read, engine_scene_load, engine_execute and workspace_write phases', async () => {\n const reports: ToolCallReport[] = [];\n const harness = makeExportHarness();\n const root = await harness.store.write({\n scene: 'SCENE_FOR_EXPORT',\n parent: null,\n title: 'T'\n });\n const tool = createExportTool({\n ...harness,\n telemetry: { record: (r) => reports.push(r) }\n });\n const res = await tool.call({\n target: 'image',\n format: 'png',\n revision: root.id,\n blockId: 1\n });\n expect(res.isError).toBeUndefined();\n expect(reports).toHaveLength(1);\n const r = reports[0];\n expect(r.tool).toBe('export');\n expect(r.succeeded).toBe(true);\n expect(r.revision).toBe(root.id);\n const phases = r.spans.map((s) => s.phase);\n expect(phases).toEqual(\n expect.arrayContaining([\n 'workspace_read',\n 'engine_scene_load',\n 'engine_execute',\n 'workspace_write'\n ])\n );\n expect(phases).not.toContain('engine_scene_save');\n });\n\n it('records succeeded=false when required args are missing', async () => {\n const reports: ToolCallReport[] = [];\n const tool = createExportTool({\n ...makeExportHarness(),\n telemetry: { record: (r) => reports.push(r) }\n });\n const res = await tool.call({});\n expect(res.isError).toBe(true);\n expect(reports[0].succeeded).toBe(false);\n });\n\n it('does nothing observable when no telemetry is injected', async () => {\n const harness = makeExportHarness();\n const root = await harness.store.write({\n scene: 'S',\n parent: null,\n title: 'T'\n });\n const tool = createExportTool(harness);\n const res = await tool.call({\n target: 'image',\n format: 'png',\n revision: root.id,\n blockId: 1\n });\n expect(res.isError).toBeUndefined();\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=export.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"export.test.d.ts","sourceRoot":"","sources":["../../../../test/tools/export.test.ts"],"names":[],"mappings":""}