@otto-assistant/bridge 0.4.92

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 (483) hide show
  1. package/bin.js +2 -0
  2. package/dist/agent-model.e2e.test.js +755 -0
  3. package/dist/ai-tool-to-genai.js +233 -0
  4. package/dist/ai-tool-to-genai.test.js +267 -0
  5. package/dist/ai-tool.js +6 -0
  6. package/dist/anthropic-auth-plugin.js +728 -0
  7. package/dist/anthropic-auth-plugin.test.js +125 -0
  8. package/dist/anthropic-auth-state.js +231 -0
  9. package/dist/bin.js +90 -0
  10. package/dist/channel-management.js +227 -0
  11. package/dist/cli-parsing.test.js +137 -0
  12. package/dist/cli-send-thread.e2e.test.js +356 -0
  13. package/dist/cli.js +3276 -0
  14. package/dist/commands/abort.js +65 -0
  15. package/dist/commands/action-buttons.js +245 -0
  16. package/dist/commands/add-project.js +113 -0
  17. package/dist/commands/agent.js +335 -0
  18. package/dist/commands/ask-question.js +274 -0
  19. package/dist/commands/btw.js +116 -0
  20. package/dist/commands/compact.js +120 -0
  21. package/dist/commands/context-usage.js +140 -0
  22. package/dist/commands/create-new-project.js +130 -0
  23. package/dist/commands/diff.js +63 -0
  24. package/dist/commands/file-upload.js +275 -0
  25. package/dist/commands/fork.js +220 -0
  26. package/dist/commands/gemini-apikey.js +70 -0
  27. package/dist/commands/login.js +885 -0
  28. package/dist/commands/mcp.js +239 -0
  29. package/dist/commands/memory-snapshot.js +24 -0
  30. package/dist/commands/mention-mode.js +44 -0
  31. package/dist/commands/merge-worktree.js +159 -0
  32. package/dist/commands/model-variant.js +364 -0
  33. package/dist/commands/model.js +776 -0
  34. package/dist/commands/new-worktree.js +366 -0
  35. package/dist/commands/paginated-select.js +57 -0
  36. package/dist/commands/permissions.js +274 -0
  37. package/dist/commands/queue.js +206 -0
  38. package/dist/commands/remove-project.js +115 -0
  39. package/dist/commands/restart-opencode-server.js +127 -0
  40. package/dist/commands/resume.js +149 -0
  41. package/dist/commands/run-command.js +79 -0
  42. package/dist/commands/screenshare.js +303 -0
  43. package/dist/commands/screenshare.test.js +20 -0
  44. package/dist/commands/session-id.js +78 -0
  45. package/dist/commands/session.js +176 -0
  46. package/dist/commands/share.js +80 -0
  47. package/dist/commands/tasks.js +205 -0
  48. package/dist/commands/types.js +2 -0
  49. package/dist/commands/undo-redo.js +305 -0
  50. package/dist/commands/unset-model.js +138 -0
  51. package/dist/commands/upgrade.js +42 -0
  52. package/dist/commands/user-command.js +155 -0
  53. package/dist/commands/verbosity.js +125 -0
  54. package/dist/commands/worktree-settings.js +43 -0
  55. package/dist/commands/worktrees.js +410 -0
  56. package/dist/condense-memory.js +33 -0
  57. package/dist/config.js +94 -0
  58. package/dist/context-awareness-plugin.js +363 -0
  59. package/dist/context-awareness-plugin.test.js +124 -0
  60. package/dist/critique-utils.js +95 -0
  61. package/dist/database.js +1310 -0
  62. package/dist/db.js +251 -0
  63. package/dist/db.test.js +138 -0
  64. package/dist/debounce-timeout.js +28 -0
  65. package/dist/debounced-process-flush.js +77 -0
  66. package/dist/discord-bot.js +1008 -0
  67. package/dist/discord-command-registration.js +524 -0
  68. package/dist/discord-urls.js +81 -0
  69. package/dist/discord-utils.js +591 -0
  70. package/dist/discord-utils.test.js +134 -0
  71. package/dist/errors.js +157 -0
  72. package/dist/escape-backticks.test.js +429 -0
  73. package/dist/event-stream-real-capture.e2e.test.js +533 -0
  74. package/dist/eventsource-parser.test.js +327 -0
  75. package/dist/exec-async.js +26 -0
  76. package/dist/external-opencode-sync.js +480 -0
  77. package/dist/format-tables.js +302 -0
  78. package/dist/format-tables.test.js +308 -0
  79. package/dist/forum-sync/config.js +79 -0
  80. package/dist/forum-sync/discord-operations.js +154 -0
  81. package/dist/forum-sync/index.js +5 -0
  82. package/dist/forum-sync/markdown.js +113 -0
  83. package/dist/forum-sync/sync-to-discord.js +417 -0
  84. package/dist/forum-sync/sync-to-files.js +190 -0
  85. package/dist/forum-sync/types.js +53 -0
  86. package/dist/forum-sync/watchers.js +307 -0
  87. package/dist/gateway-proxy-reconnect.e2e.test.js +394 -0
  88. package/dist/gateway-proxy.e2e.test.js +483 -0
  89. package/dist/genai-worker-wrapper.js +111 -0
  90. package/dist/genai-worker.js +311 -0
  91. package/dist/genai.js +232 -0
  92. package/dist/generated/browser.js +17 -0
  93. package/dist/generated/client.js +37 -0
  94. package/dist/generated/commonInputTypes.js +10 -0
  95. package/dist/generated/enums.js +52 -0
  96. package/dist/generated/internal/class.js +49 -0
  97. package/dist/generated/internal/prismaNamespace.js +253 -0
  98. package/dist/generated/internal/prismaNamespaceBrowser.js +223 -0
  99. package/dist/generated/models/bot_api_keys.js +1 -0
  100. package/dist/generated/models/bot_tokens.js +1 -0
  101. package/dist/generated/models/channel_agents.js +1 -0
  102. package/dist/generated/models/channel_directories.js +1 -0
  103. package/dist/generated/models/channel_mention_mode.js +1 -0
  104. package/dist/generated/models/channel_models.js +1 -0
  105. package/dist/generated/models/channel_verbosity.js +1 -0
  106. package/dist/generated/models/channel_worktrees.js +1 -0
  107. package/dist/generated/models/forum_sync_configs.js +1 -0
  108. package/dist/generated/models/global_models.js +1 -0
  109. package/dist/generated/models/ipc_requests.js +1 -0
  110. package/dist/generated/models/part_messages.js +1 -0
  111. package/dist/generated/models/scheduled_tasks.js +1 -0
  112. package/dist/generated/models/session_agents.js +1 -0
  113. package/dist/generated/models/session_events.js +1 -0
  114. package/dist/generated/models/session_models.js +1 -0
  115. package/dist/generated/models/session_start_sources.js +1 -0
  116. package/dist/generated/models/thread_sessions.js +1 -0
  117. package/dist/generated/models/thread_worktrees.js +1 -0
  118. package/dist/generated/models.js +1 -0
  119. package/dist/heap-monitor.js +122 -0
  120. package/dist/hrana-server.js +263 -0
  121. package/dist/hrana-server.test.js +370 -0
  122. package/dist/html-actions.js +123 -0
  123. package/dist/html-actions.test.js +70 -0
  124. package/dist/html-components.js +117 -0
  125. package/dist/html-components.test.js +34 -0
  126. package/dist/image-optimizer-plugin.js +153 -0
  127. package/dist/image-utils.js +112 -0
  128. package/dist/interaction-handler.js +397 -0
  129. package/dist/ipc-polling.js +252 -0
  130. package/dist/ipc-tools-plugin.js +193 -0
  131. package/dist/kimaki-digital-twin.e2e.test.js +161 -0
  132. package/dist/kimaki-opencode-plugin-loading.e2e.test.js +87 -0
  133. package/dist/kimaki-opencode-plugin.js +17 -0
  134. package/dist/kimaki-opencode-plugin.test.js +98 -0
  135. package/dist/limit-heading-depth.js +25 -0
  136. package/dist/limit-heading-depth.test.js +105 -0
  137. package/dist/logger.js +165 -0
  138. package/dist/markdown.js +342 -0
  139. package/dist/markdown.test.js +257 -0
  140. package/dist/message-finish-field.e2e.test.js +165 -0
  141. package/dist/message-formatting.js +413 -0
  142. package/dist/message-formatting.test.js +73 -0
  143. package/dist/message-preprocessing.js +330 -0
  144. package/dist/onboarding-tutorial.js +172 -0
  145. package/dist/onboarding-welcome.js +37 -0
  146. package/dist/openai-realtime.js +224 -0
  147. package/dist/opencode-command-detection.js +65 -0
  148. package/dist/opencode-command-detection.test.js +240 -0
  149. package/dist/opencode-command.js +129 -0
  150. package/dist/opencode-command.test.js +48 -0
  151. package/dist/opencode-interrupt-plugin.js +361 -0
  152. package/dist/opencode-interrupt-plugin.test.js +458 -0
  153. package/dist/opencode.js +861 -0
  154. package/dist/otto/branding.js +22 -0
  155. package/dist/otto/index.js +21 -0
  156. package/dist/parse-permission-rules.test.js +117 -0
  157. package/dist/patch-text-parser.js +97 -0
  158. package/dist/plugin-logger.js +59 -0
  159. package/dist/privacy-sanitizer.js +105 -0
  160. package/dist/queue-advanced-abort.e2e.test.js +293 -0
  161. package/dist/queue-advanced-action-buttons.e2e.test.js +206 -0
  162. package/dist/queue-advanced-e2e-setup.js +786 -0
  163. package/dist/queue-advanced-footer.e2e.test.js +472 -0
  164. package/dist/queue-advanced-model-switch.e2e.test.js +299 -0
  165. package/dist/queue-advanced-permissions-typing.e2e.test.js +180 -0
  166. package/dist/queue-advanced-question.e2e.test.js +261 -0
  167. package/dist/queue-advanced-typing-interrupt.e2e.test.js +114 -0
  168. package/dist/queue-advanced-typing.e2e.test.js +153 -0
  169. package/dist/queue-drain-after-interactive-ui.e2e.test.js +119 -0
  170. package/dist/queue-interrupt-drain.e2e.test.js +135 -0
  171. package/dist/queue-question-select-drain.e2e.test.js +120 -0
  172. package/dist/runtime-idle-sweeper.js +52 -0
  173. package/dist/runtime-lifecycle.e2e.test.js +508 -0
  174. package/dist/sentry.js +23 -0
  175. package/dist/session-handler/agent-utils.js +67 -0
  176. package/dist/session-handler/event-stream-state.js +420 -0
  177. package/dist/session-handler/event-stream-state.test.js +563 -0
  178. package/dist/session-handler/model-utils.js +124 -0
  179. package/dist/session-handler/opencode-session-event-log.js +94 -0
  180. package/dist/session-handler/thread-runtime-state.js +104 -0
  181. package/dist/session-handler/thread-session-runtime.js +3258 -0
  182. package/dist/session-handler.js +9 -0
  183. package/dist/session-search.js +100 -0
  184. package/dist/session-search.test.js +40 -0
  185. package/dist/session-title-rename.test.js +80 -0
  186. package/dist/startup-service.js +153 -0
  187. package/dist/startup-time.e2e.test.js +296 -0
  188. package/dist/store.js +17 -0
  189. package/dist/system-message.js +613 -0
  190. package/dist/system-message.test.js +602 -0
  191. package/dist/task-runner.js +295 -0
  192. package/dist/task-schedule.js +209 -0
  193. package/dist/task-schedule.test.js +71 -0
  194. package/dist/test-utils.js +299 -0
  195. package/dist/thinking-utils.js +35 -0
  196. package/dist/thread-message-queue.e2e.test.js +999 -0
  197. package/dist/tools.js +357 -0
  198. package/dist/undo-redo.e2e.test.js +161 -0
  199. package/dist/unnest-code-blocks.js +146 -0
  200. package/dist/unnest-code-blocks.test.js +673 -0
  201. package/dist/upgrade.js +114 -0
  202. package/dist/utils.js +144 -0
  203. package/dist/voice-attachment.js +34 -0
  204. package/dist/voice-handler.js +646 -0
  205. package/dist/voice-message.e2e.test.js +1021 -0
  206. package/dist/voice.js +447 -0
  207. package/dist/voice.test.js +235 -0
  208. package/dist/wait-session.js +94 -0
  209. package/dist/websockify.js +69 -0
  210. package/dist/worker-types.js +4 -0
  211. package/dist/worktree-lifecycle.e2e.test.js +308 -0
  212. package/dist/worktree-utils.js +3 -0
  213. package/dist/worktrees.js +929 -0
  214. package/dist/worktrees.test.js +189 -0
  215. package/dist/xml.js +92 -0
  216. package/dist/xml.test.js +32 -0
  217. package/package.json +98 -0
  218. package/schema.prisma +295 -0
  219. package/skills/batch/SKILL.md +87 -0
  220. package/skills/critique/SKILL.md +112 -0
  221. package/skills/egaki/SKILL.md +100 -0
  222. package/skills/errore/SKILL.md +647 -0
  223. package/skills/event-sourcing-state/SKILL.md +252 -0
  224. package/skills/gitchamber/SKILL.md +93 -0
  225. package/skills/goke/SKILL.md +644 -0
  226. package/skills/jitter/EDITOR.md +219 -0
  227. package/skills/jitter/EXPORT-INTERNALS.md +309 -0
  228. package/skills/jitter/SKILL.md +158 -0
  229. package/skills/jitter/jitter-clipboard.json +1042 -0
  230. package/skills/jitter/package.json +14 -0
  231. package/skills/jitter/tsconfig.json +15 -0
  232. package/skills/jitter/utils/actions.ts +212 -0
  233. package/skills/jitter/utils/export.ts +114 -0
  234. package/skills/jitter/utils/index.ts +141 -0
  235. package/skills/jitter/utils/snapshot.ts +154 -0
  236. package/skills/jitter/utils/traverse.ts +246 -0
  237. package/skills/jitter/utils/types.ts +279 -0
  238. package/skills/jitter/utils/wait.ts +133 -0
  239. package/skills/lintcn/SKILL.md +873 -0
  240. package/skills/new-skill/SKILL.md +211 -0
  241. package/skills/npm-package/SKILL.md +239 -0
  242. package/skills/playwriter/SKILL.md +35 -0
  243. package/skills/proxyman/SKILL.md +215 -0
  244. package/skills/security-review/SKILL.md +208 -0
  245. package/skills/simplify/SKILL.md +58 -0
  246. package/skills/spiceflow/SKILL.md +14 -0
  247. package/skills/termcast/SKILL.md +945 -0
  248. package/skills/tuistory/SKILL.md +250 -0
  249. package/skills/usecomputer/SKILL.md +264 -0
  250. package/skills/x-articles/SKILL.md +554 -0
  251. package/skills/zele/SKILL.md +112 -0
  252. package/skills/zustand-centralized-state/SKILL.md +1004 -0
  253. package/src/agent-model.e2e.test.ts +976 -0
  254. package/src/ai-tool-to-genai.test.ts +296 -0
  255. package/src/ai-tool-to-genai.ts +283 -0
  256. package/src/ai-tool.ts +39 -0
  257. package/src/anthropic-auth-plugin.test.ts +159 -0
  258. package/src/anthropic-auth-plugin.ts +861 -0
  259. package/src/anthropic-auth-state.ts +282 -0
  260. package/src/bin.ts +111 -0
  261. package/src/channel-management.ts +334 -0
  262. package/src/cli-parsing.test.ts +195 -0
  263. package/src/cli-send-thread.e2e.test.ts +464 -0
  264. package/src/cli.ts +4581 -0
  265. package/src/commands/abort.ts +89 -0
  266. package/src/commands/action-buttons.ts +364 -0
  267. package/src/commands/add-project.ts +149 -0
  268. package/src/commands/agent.ts +473 -0
  269. package/src/commands/ask-question.ts +390 -0
  270. package/src/commands/btw.ts +164 -0
  271. package/src/commands/compact.ts +157 -0
  272. package/src/commands/context-usage.ts +199 -0
  273. package/src/commands/create-new-project.ts +190 -0
  274. package/src/commands/diff.ts +91 -0
  275. package/src/commands/file-upload.ts +389 -0
  276. package/src/commands/fork.ts +321 -0
  277. package/src/commands/gemini-apikey.ts +104 -0
  278. package/src/commands/login.ts +1173 -0
  279. package/src/commands/mcp.ts +307 -0
  280. package/src/commands/memory-snapshot.ts +30 -0
  281. package/src/commands/mention-mode.ts +68 -0
  282. package/src/commands/merge-worktree.ts +223 -0
  283. package/src/commands/model-variant.ts +483 -0
  284. package/src/commands/model.ts +1053 -0
  285. package/src/commands/new-worktree.ts +510 -0
  286. package/src/commands/paginated-select.ts +81 -0
  287. package/src/commands/permissions.ts +397 -0
  288. package/src/commands/queue.ts +271 -0
  289. package/src/commands/remove-project.ts +155 -0
  290. package/src/commands/restart-opencode-server.ts +162 -0
  291. package/src/commands/resume.ts +230 -0
  292. package/src/commands/run-command.ts +123 -0
  293. package/src/commands/screenshare.test.ts +30 -0
  294. package/src/commands/screenshare.ts +366 -0
  295. package/src/commands/session-id.ts +109 -0
  296. package/src/commands/session.ts +227 -0
  297. package/src/commands/share.ts +106 -0
  298. package/src/commands/tasks.ts +293 -0
  299. package/src/commands/types.ts +25 -0
  300. package/src/commands/undo-redo.ts +386 -0
  301. package/src/commands/unset-model.ts +173 -0
  302. package/src/commands/upgrade.ts +52 -0
  303. package/src/commands/user-command.ts +198 -0
  304. package/src/commands/verbosity.ts +173 -0
  305. package/src/commands/worktree-settings.ts +70 -0
  306. package/src/commands/worktrees.ts +552 -0
  307. package/src/condense-memory.ts +36 -0
  308. package/src/config.ts +111 -0
  309. package/src/context-awareness-plugin.test.ts +142 -0
  310. package/src/context-awareness-plugin.ts +510 -0
  311. package/src/critique-utils.ts +139 -0
  312. package/src/database.ts +1876 -0
  313. package/src/db.test.ts +162 -0
  314. package/src/db.ts +286 -0
  315. package/src/debounce-timeout.ts +43 -0
  316. package/src/debounced-process-flush.ts +104 -0
  317. package/src/discord-bot.ts +1330 -0
  318. package/src/discord-command-registration.ts +693 -0
  319. package/src/discord-urls.ts +88 -0
  320. package/src/discord-utils.test.ts +153 -0
  321. package/src/discord-utils.ts +800 -0
  322. package/src/errors.ts +201 -0
  323. package/src/escape-backticks.test.ts +469 -0
  324. package/src/event-stream-real-capture.e2e.test.ts +692 -0
  325. package/src/eventsource-parser.test.ts +351 -0
  326. package/src/exec-async.ts +35 -0
  327. package/src/external-opencode-sync.ts +685 -0
  328. package/src/format-tables.test.ts +335 -0
  329. package/src/format-tables.ts +445 -0
  330. package/src/forum-sync/config.ts +92 -0
  331. package/src/forum-sync/discord-operations.ts +241 -0
  332. package/src/forum-sync/index.ts +9 -0
  333. package/src/forum-sync/markdown.ts +172 -0
  334. package/src/forum-sync/sync-to-discord.ts +595 -0
  335. package/src/forum-sync/sync-to-files.ts +294 -0
  336. package/src/forum-sync/types.ts +175 -0
  337. package/src/forum-sync/watchers.ts +454 -0
  338. package/src/gateway-proxy-reconnect.e2e.test.ts +523 -0
  339. package/src/gateway-proxy.e2e.test.ts +640 -0
  340. package/src/genai-worker-wrapper.ts +164 -0
  341. package/src/genai-worker.ts +386 -0
  342. package/src/genai.ts +321 -0
  343. package/src/generated/browser.ts +114 -0
  344. package/src/generated/client.ts +138 -0
  345. package/src/generated/commonInputTypes.ts +736 -0
  346. package/src/generated/enums.ts +88 -0
  347. package/src/generated/internal/class.ts +384 -0
  348. package/src/generated/internal/prismaNamespace.ts +2386 -0
  349. package/src/generated/internal/prismaNamespaceBrowser.ts +326 -0
  350. package/src/generated/models/bot_api_keys.ts +1288 -0
  351. package/src/generated/models/bot_tokens.ts +1656 -0
  352. package/src/generated/models/channel_agents.ts +1256 -0
  353. package/src/generated/models/channel_directories.ts +1859 -0
  354. package/src/generated/models/channel_mention_mode.ts +1300 -0
  355. package/src/generated/models/channel_models.ts +1288 -0
  356. package/src/generated/models/channel_verbosity.ts +1228 -0
  357. package/src/generated/models/channel_worktrees.ts +1300 -0
  358. package/src/generated/models/forum_sync_configs.ts +1452 -0
  359. package/src/generated/models/global_models.ts +1288 -0
  360. package/src/generated/models/ipc_requests.ts +1485 -0
  361. package/src/generated/models/part_messages.ts +1302 -0
  362. package/src/generated/models/scheduled_tasks.ts +2320 -0
  363. package/src/generated/models/session_agents.ts +1086 -0
  364. package/src/generated/models/session_events.ts +1439 -0
  365. package/src/generated/models/session_models.ts +1114 -0
  366. package/src/generated/models/session_start_sources.ts +1408 -0
  367. package/src/generated/models/thread_sessions.ts +1781 -0
  368. package/src/generated/models/thread_worktrees.ts +1356 -0
  369. package/src/generated/models.ts +30 -0
  370. package/src/heap-monitor.ts +152 -0
  371. package/src/hrana-server.test.ts +434 -0
  372. package/src/hrana-server.ts +314 -0
  373. package/src/html-actions.test.ts +87 -0
  374. package/src/html-actions.ts +174 -0
  375. package/src/html-components.test.ts +38 -0
  376. package/src/html-components.ts +181 -0
  377. package/src/image-optimizer-plugin.ts +194 -0
  378. package/src/image-utils.ts +149 -0
  379. package/src/interaction-handler.ts +576 -0
  380. package/src/ipc-polling.ts +326 -0
  381. package/src/ipc-tools-plugin.ts +236 -0
  382. package/src/kimaki-digital-twin.e2e.test.ts +199 -0
  383. package/src/kimaki-opencode-plugin-loading.e2e.test.ts +109 -0
  384. package/src/kimaki-opencode-plugin.test.ts +108 -0
  385. package/src/kimaki-opencode-plugin.ts +18 -0
  386. package/src/limit-heading-depth.test.ts +116 -0
  387. package/src/limit-heading-depth.ts +26 -0
  388. package/src/logger.ts +208 -0
  389. package/src/markdown.test.ts +308 -0
  390. package/src/markdown.ts +410 -0
  391. package/src/message-finish-field.e2e.test.ts +192 -0
  392. package/src/message-formatting.test.ts +81 -0
  393. package/src/message-formatting.ts +533 -0
  394. package/src/message-preprocessing.ts +455 -0
  395. package/src/onboarding-tutorial.ts +176 -0
  396. package/src/onboarding-welcome.ts +49 -0
  397. package/src/openai-realtime.ts +358 -0
  398. package/src/opencode-command-detection.test.ts +307 -0
  399. package/src/opencode-command-detection.ts +76 -0
  400. package/src/opencode-command.test.ts +70 -0
  401. package/src/opencode-command.ts +188 -0
  402. package/src/opencode-interrupt-plugin.test.ts +677 -0
  403. package/src/opencode-interrupt-plugin.ts +477 -0
  404. package/src/opencode.ts +1110 -0
  405. package/src/otto/branding.ts +23 -0
  406. package/src/otto/index.ts +22 -0
  407. package/src/parse-permission-rules.test.ts +127 -0
  408. package/src/patch-text-parser.ts +107 -0
  409. package/src/plugin-logger.ts +68 -0
  410. package/src/privacy-sanitizer.ts +142 -0
  411. package/src/queue-advanced-abort.e2e.test.ts +382 -0
  412. package/src/queue-advanced-action-buttons.e2e.test.ts +268 -0
  413. package/src/queue-advanced-e2e-setup.ts +873 -0
  414. package/src/queue-advanced-footer.e2e.test.ts +576 -0
  415. package/src/queue-advanced-model-switch.e2e.test.ts +383 -0
  416. package/src/queue-advanced-permissions-typing.e2e.test.ts +245 -0
  417. package/src/queue-advanced-question.e2e.test.ts +316 -0
  418. package/src/queue-advanced-typing-interrupt.e2e.test.ts +146 -0
  419. package/src/queue-advanced-typing.e2e.test.ts +199 -0
  420. package/src/queue-drain-after-interactive-ui.e2e.test.ts +151 -0
  421. package/src/queue-interrupt-drain.e2e.test.ts +166 -0
  422. package/src/queue-question-select-drain.e2e.test.ts +152 -0
  423. package/src/runtime-idle-sweeper.ts +76 -0
  424. package/src/runtime-lifecycle.e2e.test.ts +641 -0
  425. package/src/schema.sql +173 -0
  426. package/src/sentry.ts +26 -0
  427. package/src/session-handler/agent-utils.ts +97 -0
  428. package/src/session-handler/event-stream-fixtures/real-session-action-buttons.jsonl +45 -0
  429. package/src/session-handler/event-stream-fixtures/real-session-footer-suppressed-on-pre-idle-interrupt.jsonl +40 -0
  430. package/src/session-handler/event-stream-fixtures/real-session-permission-external-file.jsonl +23 -0
  431. package/src/session-handler/event-stream-fixtures/real-session-task-normal.jsonl +22 -0
  432. package/src/session-handler/event-stream-fixtures/real-session-task-three-parallel-sleeps.jsonl +277 -0
  433. package/src/session-handler/event-stream-fixtures/real-session-task-user-interruption.jsonl +46 -0
  434. package/src/session-handler/event-stream-fixtures/session-abort-after-idle-race.jsonl +21 -0
  435. package/src/session-handler/event-stream-fixtures/session-concurrent-messages-serialized.jsonl +56 -0
  436. package/src/session-handler/event-stream-fixtures/session-explicit-abort.jsonl +44 -0
  437. package/src/session-handler/event-stream-fixtures/session-normal-completion.jsonl +29 -0
  438. package/src/session-handler/event-stream-fixtures/session-tool-call-noisy-stream.jsonl +29 -0
  439. package/src/session-handler/event-stream-fixtures/session-two-completions-same-session.jsonl +50 -0
  440. package/src/session-handler/event-stream-fixtures/session-user-interruption.jsonl +59 -0
  441. package/src/session-handler/event-stream-fixtures/session-voice-queued-followup.jsonl +52 -0
  442. package/src/session-handler/event-stream-state.test.ts +645 -0
  443. package/src/session-handler/event-stream-state.ts +608 -0
  444. package/src/session-handler/model-utils.ts +183 -0
  445. package/src/session-handler/opencode-session-event-log.ts +130 -0
  446. package/src/session-handler/thread-runtime-state.ts +212 -0
  447. package/src/session-handler/thread-session-runtime.ts +4281 -0
  448. package/src/session-handler.ts +15 -0
  449. package/src/session-search.test.ts +50 -0
  450. package/src/session-search.ts +148 -0
  451. package/src/session-title-rename.test.ts +112 -0
  452. package/src/startup-service.ts +200 -0
  453. package/src/startup-time.e2e.test.ts +373 -0
  454. package/src/store.ts +122 -0
  455. package/src/system-message.test.ts +612 -0
  456. package/src/system-message.ts +723 -0
  457. package/src/task-runner.ts +421 -0
  458. package/src/task-schedule.test.ts +84 -0
  459. package/src/task-schedule.ts +311 -0
  460. package/src/test-utils.ts +435 -0
  461. package/src/thinking-utils.ts +61 -0
  462. package/src/thread-message-queue.e2e.test.ts +1219 -0
  463. package/src/tools.ts +430 -0
  464. package/src/undici.d.ts +12 -0
  465. package/src/undo-redo.e2e.test.ts +209 -0
  466. package/src/unnest-code-blocks.test.ts +713 -0
  467. package/src/unnest-code-blocks.ts +185 -0
  468. package/src/upgrade.ts +127 -0
  469. package/src/utils.ts +212 -0
  470. package/src/voice-attachment.ts +51 -0
  471. package/src/voice-handler.ts +908 -0
  472. package/src/voice-message.e2e.test.ts +1255 -0
  473. package/src/voice.test.ts +281 -0
  474. package/src/voice.ts +627 -0
  475. package/src/wait-session.ts +147 -0
  476. package/src/websockify.ts +101 -0
  477. package/src/worker-types.ts +64 -0
  478. package/src/worktree-lifecycle.e2e.test.ts +391 -0
  479. package/src/worktree-utils.ts +4 -0
  480. package/src/worktrees.test.ts +223 -0
  481. package/src/worktrees.ts +1294 -0
  482. package/src/xml.test.ts +38 -0
  483. package/src/xml.ts +121 -0
@@ -0,0 +1,219 @@
1
+ # Jitter Editor API Reference
2
+
3
+ Reference for `window.app` methods and layer types. For utilities, see SKILL.md and use `jitterUtils.*`.
4
+
5
+ ## App Instance Methods
6
+
7
+ ```javascript
8
+ // Playback
9
+ app.play()
10
+ app.stopPlayback()
11
+ app.moveCursor(timeInMs)
12
+
13
+ // Layer creation (opens picker or adds at cursor)
14
+ app.addArtboard()
15
+ app.addText('toolbar')
16
+ app.addRectShape('toolbar')
17
+ app.addEllipseShape('toolbar')
18
+ app.addMedia('toolbar')
19
+
20
+ // File operations
21
+ app.renameFile(newName)
22
+ app.deleteFile()
23
+ app.downloadProject()
24
+ app.scheduleSave()
25
+ ```
26
+
27
+ ## Dispatch Actions
28
+
29
+ Use `app.dispatchAction(action)` or `jitterUtils.*` helpers.
30
+
31
+ ### Core Actions
32
+
33
+ | Action Type | Purpose |
34
+ | ------------------- | ---------------------- |
35
+ | `updateObjWithUndo` | Update node properties |
36
+ | `addObjWithUndo` | Add new node |
37
+ | `removeObjWithUndo` | Remove nodes |
38
+ | `setSelection` | Select nodes |
39
+ | `emptySelection` | Clear selection |
40
+ | `undo` / `redo` | Undo/redo |
41
+ | `setCurrentTime` | Set playhead time |
42
+ | `zoomToSelection` | Zoom to selected |
43
+
44
+ ## Layer Types
45
+
46
+ ### Artboard
47
+
48
+ ```javascript
49
+ {
50
+ type: "artboard",
51
+ name: "16:9",
52
+ width: 1920,
53
+ height: 1080,
54
+ duration: 11000,
55
+ background: true,
56
+ fillColor: "#ffffff"
57
+ }
58
+ ```
59
+
60
+ ### Text
61
+
62
+ ```javascript
63
+ {
64
+ type: "text",
65
+ text: "Hello World",
66
+ fontSize: 48,
67
+ font: { name: "Poppins", type: "googlefont", weight: 600 },
68
+ fillColor: "#000000",
69
+ textAlign: "center", // "left" | "center" | "right"
70
+ verticalAlign: "middle"
71
+ }
72
+ ```
73
+
74
+ ### Image / SVG / Video / GIF
75
+
76
+ ```javascript
77
+ {
78
+ type: "image", // or "svg", "video", "gif"
79
+ url: "https://example.com/asset.jpg",
80
+ width: 400,
81
+ height: 300,
82
+ cornerRadius: 0
83
+ }
84
+ ```
85
+
86
+ ### Shapes
87
+
88
+ ```javascript
89
+ // Rectangle
90
+ { type: "rect", fillColor: "#3B82F6", cornerRadius: 8 }
91
+
92
+ // Ellipse
93
+ { type: "ellipse", fillColor: "#EF4444" }
94
+
95
+ // Star
96
+ { type: "star", fillColor: "#F59E0B", points: 5, innerRadius: 50 }
97
+ ```
98
+
99
+ ### Group
100
+
101
+ ```javascript
102
+ {
103
+ type: "layerGrp",
104
+ name: "Group Name",
105
+ clipsContent: false,
106
+ cornerRadius: 0
107
+ }
108
+ ```
109
+
110
+ ## Common Properties
111
+
112
+ All layers support:
113
+
114
+ | Property | Type | Description |
115
+ | ----------------- | ------- | ------------------- |
116
+ | `x`, `y` | number | Position |
117
+ | `width`, `height` | number | Size |
118
+ | `angle` | number | Rotation in degrees |
119
+ | `scale` | number | Scale factor |
120
+ | `opacity` | number | 0-100 |
121
+ | `shadowEnabled` | boolean | Drop shadow |
122
+ | `strokeEnabled` | boolean | Stroke/border |
123
+
124
+ ## Fill Colors
125
+
126
+ ```javascript
127
+ // Solid
128
+ fillColor: "#3B82F6"
129
+
130
+ // Linear gradient
131
+ fillColor: {
132
+ type: "GRADIENT_LINEAR",
133
+ stops: [
134
+ { id: "s1", position: 0, color: "#FF0000" },
135
+ { id: "s2", position: 1, color: "#0000FF" }
136
+ ],
137
+ transform: { angle: 0, sx: 1, tx: 0.5, ty: 0.5 }
138
+ }
139
+
140
+ // Radial gradient
141
+ fillColor: {
142
+ type: "GRADIENT_RADIAL",
143
+ stops: [...],
144
+ transform: { sx: 1, tx: 0.5, ty: 0.5 }
145
+ }
146
+ ```
147
+
148
+ ## Easing Presets
149
+
150
+ ```javascript
151
+ { name: "smooth:standard:v1", schema: "v1", config: { intensity: 50 } }
152
+ { name: "smooth:accelerate:v1", schema: "v1", config: { intensity: 50 } }
153
+ { name: "smooth:decelerate:v1", schema: "v1", config: { intensity: 50 } }
154
+ { name: "spring", schema: "v1", config: { stiffness: 100, damping: 10 } }
155
+ { name: "bounce", schema: "v1", config: { bounces: 3 } }
156
+ { name: "linear", schema: "v1", config: {} }
157
+ ```
158
+
159
+ ## Animation Types
160
+
161
+ ### Transform
162
+
163
+ `scale`, `move`, `rotate`, `opacity`
164
+
165
+ ### Enter/Exit
166
+
167
+ `fadeIn/Out`, `growIn/Out`, `shrinkIn/Out`, `slideIn/Out`, `spinIn/Out`, `blurIn/Out`, `textIn/Out`
168
+
169
+ ### Mask
170
+
171
+ `maskRevealIn/Out`, `maskSlideIn/Out`, `maskCenterIn/Out`
172
+
173
+ ### Media
174
+
175
+ `playVideo`, `playAudio`
176
+
177
+ ## Node Tree Structure
178
+
179
+ ```
180
+ Artboard (type: "artboard")
181
+ ├── LayersTree (type: "layersTree")
182
+ │ ├── LayerGrp (type: "layerGrp")
183
+ │ │ ├── Text (type: "text")
184
+ │ │ └── Image (type: "image")
185
+ │ └── SVG (type: "svg")
186
+ └── OperationsTree (type: "operationsTree")
187
+ └── OpGrp (type: "opGrp")
188
+ ├── Scale animation
189
+ └── FadeIn animation
190
+ ```
191
+
192
+ ## State Access
193
+
194
+ ```javascript
195
+ // Current selection
196
+ const state = app.props.observableEditorState.getSnapshot()
197
+ const selectedIds = state.selection.nodesIds
198
+
199
+ // Project config
200
+ const conf = app.props.observableImmutableConf.lastImmutableConf
201
+
202
+ // File metadata
203
+ const fileMeta = app.props.fileMeta
204
+ // { id, name, bucket, teamId }
205
+
206
+ // Subscribe to changes
207
+ const unsubscribe = app.props.observableImmutableConf.subscribe(() => {
208
+ // Config changed
209
+ })
210
+ ```
211
+
212
+ ## File Actions
213
+
214
+ ```javascript
215
+ await app.props.fileActions.duplicateFile(fileId) // Returns new ID
216
+ await app.props.fileActions.deleteFile(fileId)
217
+ await app.props.fileActions.renameFile(name)
218
+ await app.props.fileActions.saveFile()
219
+ ```
@@ -0,0 +1,309 @@
1
+ ---
2
+ title: Jitter Export Pipeline Internals
3
+ description: |
4
+ Reverse-engineered architecture of Jitter's export and rendering pipeline.
5
+ Covers the headless renderer page, scene graph format, network requests,
6
+ bundle structure, and feasibility of building a standalone local exporter.
7
+ prompt: |
8
+ Analyze the jitter skill. Try it in the playwriter. Then analyze the
9
+ JavaScript code that runs in the exporter page. Think about extracting
10
+ the JavaScript bundle to create a standalone local exporter for AI agents.
11
+ Examine network requests, download the bundle, see where the data for the
12
+ scene graph comes from and how we would override it.
13
+ Files read: @discord/skills/jitter/SKILL.md @discord/skills/jitter/EDITOR.md
14
+ @discord/skills/jitter/utils/export.ts @discord/skills/jitter/utils/wait.ts
15
+ @discord/skills/jitter/utils/types.ts @discord/skills/jitter/utils/traverse.ts
16
+ @discord/skills/jitter/utils/actions.ts
17
+ Used Playwriter to navigate to jitter.video, open a real project, inspect
18
+ window.app, download all JS chunks, and intercept network requests on the
19
+ /api/renderer/ page.
20
+ ---
21
+
22
+ # Jitter Export Pipeline Internals
23
+
24
+ ## Architecture Overview
25
+
26
+ Jitter is a **Gatsby (React) SPA**. Three pages are relevant to export:
27
+
28
+ | Page | Path | Role |
29
+ |------|------|------|
30
+ | Editor | `/file/?id=` | Interactive editor, stores scene graph in `window.app` |
31
+ | Export UI | `/export/` | Plan-limit checks, delegates to renderer |
32
+ | **API Renderer** | `/api/renderer/` | **Headless rendering engine** — the key page |
33
+
34
+ The API Renderer page renders **nothing visible** (`render() { return null }`).
35
+ It exists solely to be driven by an external process (Puppeteer/Playwright on
36
+ Jitter's servers) that calls `window.jitter.renderFrame(time)` in a loop.
37
+
38
+ ```
39
+ ┌─────────────────────────────────────────────────────────┐
40
+ │ Jitter's export backend (server-side Puppeteer) │
41
+ │ │
42
+ │ 1. Open /api/renderer/?file=X&artboardId=Y&width=... │
43
+ │ 2. Wait for jitterLoadEvent {name:"ready"} │
44
+ │ 3. Loop: window.jitter.renderFrame(t) → PNG string │
45
+ │ 4. Pipe PNGs to FFmpeg → MP4/WebM/GIF │
46
+ │ 5. Upload result to S3, return download link │
47
+ └─────────────────────────────────────────────────────────┘
48
+ ```
49
+
50
+ ## The API Renderer Page
51
+
52
+ **Source:** `component---src-pages-api-renderer-ts` (3KB, all logic delegated
53
+ to modules in `app.js`)
54
+
55
+ **URL params** (all required):
56
+
57
+ | Param | Type | Description |
58
+ |-------|------|-------------|
59
+ | `file` | string | Project/file ID |
60
+ | `bucket` | string | S3 bucket name (e.g. `snackthis-userdata`) |
61
+ | `artboardId` | string | Which artboard to render |
62
+ | `width` | number | Export width in px |
63
+ | `height` | number | Export height in px |
64
+ | `noBg` | boolean | Transparent background |
65
+ | `addWatermark` | boolean | Add Jitter watermark |
66
+ | `superSampling` | number | Render at higher res then downsample |
67
+ | `playbackDirection` | string | `normal`, `reverse`, or `boomerang` |
68
+ | `vfe` | string | Video fallback export (`on`/`off`) |
69
+
70
+ **Lifecycle:**
71
+
72
+ 1. Parses and Zod-validates URL params
73
+ 2. Loads project data: `GM(fileId, bucket)` — tries IndexedDB cache first,
74
+ then S3/CloudFront
75
+ 3. Finds the artboard in the loaded project
76
+ 4. Creates a **scene** object (resolves assets, builds render tree)
77
+ 5. Creates a **canvas renderer** (Canvas 2D, not WebGL)
78
+ 6. Sets `window.jitter`:
79
+ - `exportContext: { exportWidth, exportHeight, exportDuration }`
80
+ - `renderFrame(time)` → renders frame, returns `{ name: "frame", t, pngString, ...exportContext }`
81
+ - `wav` → audio data as number array (or undefined)
82
+ 7. Dispatches `CustomEvent("jitterLoadEvent", { detail: { name: "ready", ...exportContext } })`
83
+ 8. On error dispatches `{ name: "error", message }`
84
+
85
+ ## Scene Graph Format
86
+
87
+ The project configuration lives at
88
+ `window.app.props.observableImmutableConf.lastImmutableConf`.
89
+
90
+ Top-level structure:
91
+
92
+ ```json
93
+ {
94
+ "nodes": {},
95
+ "roots": [
96
+ {
97
+ "id": "artboard-id",
98
+ "item": {
99
+ "type": "artboard",
100
+ "width": 1080,
101
+ "height": 1080,
102
+ "duration": 8000,
103
+ "fillColor": "#ffffff",
104
+ "background": true
105
+ },
106
+ "children": [
107
+ { "id": "...", "item": { "type": "operationsTree" }, "children": [...] },
108
+ { "id": "...", "item": { "type": "layersTree" }, "children": [...] }
109
+ ]
110
+ }
111
+ ]
112
+ }
113
+ ```
114
+
115
+ ### Layer types
116
+
117
+ | Type | Key properties |
118
+ |------|---------------|
119
+ | `artboard` | `width`, `height`, `duration`, `fillColor`, `background` |
120
+ | `layersTree` | Container for visual layers |
121
+ | `operationsTree` | Container for animation operations |
122
+ | `opGrp` | Named animation step (e.g. "Step 1") |
123
+ | `layerGrp` | Visual group, `clipsContent`, `cornerRadius` |
124
+ | `image` | `url` (CloudFront), `width`, `height`, `cornerRadius` |
125
+ | `video` | `url`, `audioUrl`, `width`, `height` |
126
+ | `svg` | `url` |
127
+ | `gif` | `url` |
128
+ | `text` | `text`, `font`, `fontSize`, `fillColor`, `textAlign` |
129
+ | `rect` | `fillColor`, `cornerRadius`, `strokeColor` |
130
+ | `ellipse` | `fillColor` |
131
+ | `star` | `fillColor`, `points`, `innerRadius` |
132
+
133
+ All layers share: `x`, `y`, `width`, `height`, `angle`, `scale`, `opacity`,
134
+ `shadowEnabled`, `strokeEnabled`.
135
+
136
+ ### Animation operations
137
+
138
+ Operations live under `operationsTree > opGrp` nodes. Each operation targets
139
+ a layer by `targetId`:
140
+
141
+ ```json
142
+ {
143
+ "type": "move",
144
+ "targetId": "layer-id",
145
+ "startTime": 1000,
146
+ "endTime": 2000,
147
+ "toValue": { "moveX": -530, "moveY": 0 },
148
+ "easing": {
149
+ "name": "smooth:standard:v1",
150
+ "schema": "v1",
151
+ "config": { "intensity": 85 }
152
+ }
153
+ }
154
+ ```
155
+
156
+ Animation types: `move`, `scale`, `rotate`, `opacity`, `fadeIn/Out`,
157
+ `growIn/Out`, `shrinkIn/Out`, `slideIn/Out`, `spinIn/Out`, `blurIn/Out`,
158
+ `textIn/Out`, `maskRevealIn/Out`, `maskSlideIn/Out`, `maskCenterIn/Out`,
159
+ `playVideo`, `playAudio`.
160
+
161
+ ### Asset URLs
162
+
163
+ All media assets are served from CloudFront:
164
+
165
+ ```
166
+ https://d154zarmrcpu4a.cloudfront.net/{assetId}.png
167
+ https://d154zarmrcpu4a.cloudfront.net/{assetId}.mp4
168
+ ```
169
+
170
+ Project data (the conf JSON) is stored at:
171
+
172
+ ```
173
+ https://d2q1h0g8a6snwf.cloudfront.net/{encodedFileId}
174
+ ```
175
+
176
+ The `d2q1h0g8a6snwf` URL is for the `snackthis-userdata` bucket.
177
+ Other buckets use `(0,u.T8)(bucket, fileId)` to construct the URL.
178
+
179
+ ## Network Requests During Export
180
+
181
+ Requests made when the `/api/renderer/` page loads:
182
+
183
+ **Static assets (cached):**
184
+ - `webpack-runtime-*.js` (11KB)
185
+ - 6 shared chunks (~970KB total)
186
+ - `app.js` (3.0MB) — contains the entire renderer
187
+ - `api-renderer-*.js` (3KB)
188
+ - Page data JSONs from Gatsby
189
+
190
+ **Data fetches:**
191
+ - `backend2.jitter.video/get-user-infos` — user profile
192
+ - `backend2.jitter.video/get-subscription` — plan info
193
+ - `backend2.jitter.video/teams/get-all-subscriptions`
194
+ - `backend2.jitter.video/realtime/get-token` — WebSocket auth token
195
+
196
+ **Project data:** loaded from IndexedDB cache if the user recently visited the
197
+ editor, otherwise fetched from S3/CloudFront.
198
+
199
+ **No rendering API calls** — all rendering is 100% client-side on Canvas 2D.
200
+
201
+ ## JS Bundle Structure
202
+
203
+ | File | Size | Purpose |
204
+ |------|------|---------|
205
+ | `app-*.js` | **3.0MB** | Core: renderer, scene builder, all shared modules |
206
+ | `editor-page (file-*.js)` | 960KB | Editor UI (not needed for export) |
207
+ | `22016225-*.js` | 176KB | Shared chunk |
208
+ | `3caaf7ec-*.js` | 168KB | Shared chunk |
209
+ | `42b3359b-*.js` | 316KB | Shared chunk |
210
+ | `4fa16633-*.js` | 124KB | Shared chunk (canvas/WebGL refs) |
211
+ | `146c69ca-*.js` | 62KB | Shared chunk |
212
+ | `f27202df-*.js` | 116KB | Shared chunk |
213
+ | `api-renderer-*.js` | **3KB** | Glue: parse params → create scene → expose `window.jitter` |
214
+ | `webpack-runtime-*.js` | 11KB | Module loader |
215
+
216
+ Total for rendering: ~4.8MB of JavaScript.
217
+
218
+ ### Key webpack modules (inside app.js)
219
+
220
+ | Module ID | Export | Purpose |
221
+ |-----------|--------|---------|
222
+ | 65031 | `GM` (as `L`) | Project loader: IndexedDB → S3/CloudFront fallback |
223
+ | 82106 | `h` (as `b`) | Scene creation: conf → scene object with asset store |
224
+ | 89018 | `UH` (as `a`) | Renderer factory: scene → `{ canvas, renderFrame, duration }` |
225
+ | 66868 | `HX` (as `Z`) | Core frame render: `(scene, time, canvasCtx) → void` |
226
+ | 82755 | `eM` | Canvas to PNG string conversion |
227
+ | 44852 | `vS` | Artboard finder in project tree |
228
+ | 94533 | `Mj` | Audio track extraction |
229
+ | 61904 | `ev` | Canvas context creation at given dimensions |
230
+
231
+ ## Renderer Internals
232
+
233
+ The renderer factory (module 89018) creates a closure:
234
+
235
+ ```
236
+ function createRenderer(scene, width, height, superSampling, options):
237
+ canvas = createCanvasContext(width, height)
238
+ if superSampling > 1:
239
+ create chain of progressively smaller canvases for downscaling
240
+
241
+ return {
242
+ canvas: canvas.canvas,
243
+ duration: computeDuration(scene.duration, playbackDirection),
244
+ renderFrame: async (time) => {
245
+ adjustedTime = applyPlaybackDirection(time)
246
+ coreRender(scene, adjustedTime, canvas) // module 66868.HX
247
+ }
248
+ }
249
+ ```
250
+
251
+ Scene creation (module 82106) takes the raw conf and:
252
+ 1. Resolves the camera/viewport for the selected artboards
253
+ 2. Optionally applies imgix transforms for super-sampled images
254
+ 3. Optionally strips audio or backgrounds
255
+ 4. Loads all assets into an `assetStore` (Map of asset ID → loaded asset)
256
+ 5. Creates a `prepass` function (prepares frame) and `render` function (draws frame)
257
+
258
+ ## Standalone Local Exporter: Feasibility
259
+
260
+ ### What would be needed
261
+
262
+ ```
263
+ ┌──────────────────────────────────────────────────┐
264
+ │ Local index.html │
265
+ │ │
266
+ │ ┌─────────────┐ ┌──────────────────────────┐ │
267
+ │ │ Scene JSON │──▸│ Jitter Renderer Engine │ │
268
+ │ │ (uploaded) │ │ (extracted from app.js) │ │
269
+ │ └─────────────┘ │ scene → canvas → frames │ │
270
+ │ └───────────┬──────────────┘ │
271
+ │ ▼ │
272
+ │ ┌──────────────────────────┐ │
273
+ │ │ Frame capture + encode │ │
274
+ │ │ MediaRecorder/WebCodecs │ │
275
+ │ └───────────┬──────────────┘ │
276
+ │ ▼ │
277
+ │ ┌──────────────────────────┐ │
278
+ │ │ MP4/WebM output file │ │
279
+ │ └──────────────────────────┘ │
280
+ └──────────────────────────────────────────────────┘
281
+ ```
282
+
283
+ ### Assessment by component
284
+
285
+ | Component | Difficulty | Notes |
286
+ |-----------|-----------|-------|
287
+ | Bundle extraction | Hard | 3MB minified webpack bundle, ~15 transitive module deps |
288
+ | Project data override | Easy | Replace `GM()` loader with local JSON injection |
289
+ | Asset hosting | Easy | Download CloudFront assets, rewrite URLs or use service worker |
290
+ | Auth bypass | Easy | Mock `/get-user-infos`, `/get-subscription` — rendering is client-side |
291
+ | Video encoding | Medium | WebCodecs API, MediaRecorder, or FFmpeg.wasm |
292
+ | Legal/ToS compliance | **Blocker** | Extracting and redistributing Jitter's code likely violates ToS |
293
+
294
+ ### Practical alternatives
295
+
296
+ 1. **Use Playwright to drive `/api/renderer/` directly** — this is exactly
297
+ what Jitter's own backend does. Navigate, wait for ready event, call
298
+ `renderFrame()` in a loop, pipe frames to FFmpeg. No extraction needed.
299
+
300
+ 2. **Build a custom renderer** using the scene format as a spec. The JSON
301
+ format is well-understood. Libraries like `lottie-web`, `rive`, or a
302
+ custom Canvas 2D renderer could interpret the same format.
303
+
304
+ 3. **Use the editor + Playwriter skill** — the existing jitter skill already
305
+ supports: modify scene → generate export URL → navigate → download. This
306
+ works today.
307
+
308
+ 4. **Request an API/self-hosted tier from Jitter** — their architecture
309
+ already has an `api/renderer` page designed for programmatic use.
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: jitter
3
+ description: Control Jitter (jitter.video) for exporting animations, replacing assets, and modifying text programmatically via Playwriter.
4
+ ---
5
+
6
+ # Jitter Programmatic Control Skill
7
+
8
+ Control Jitter (jitter.video) for exporting animations, replacing assets, and modifying text.
9
+
10
+ ## Setup
11
+
12
+ Load utils before interacting with Jitter:
13
+
14
+ ```javascript
15
+ // Load once per page (before navigation or via addInitScript)
16
+ await page.addInitScript({ path: './skills/jitter/dist/jitter-utils.js' })
17
+
18
+ // Navigate to project
19
+ await page.goto('https://jitter.video/file/?id=YOUR_FILE_ID')
20
+
21
+ // Wait for app to be ready
22
+ await page.evaluate(() => jitterUtils.waitForApp())
23
+ ```
24
+
25
+ ## API Reference
26
+
27
+ ### Traversal
28
+
29
+ | Function | Description |
30
+ | ----------------------- | ---------------------------------- |
31
+ | `findNodeById(id)` | Find node by ID |
32
+ | `findAllMediaNodes()` | Get all images/SVGs/videos/GIFs |
33
+ | `findAllTextNodes()` | Get all text nodes |
34
+ | `getArtboards()` | Get all artboards with dimensions |
35
+ | `findNodesByType(type)` | Find nodes by layer type |
36
+ | `findNodesByName(name)` | Find nodes by name (partial match) |
37
+ | `flattenTree()` | Get all nodes as flat array |
38
+
39
+ ### Actions
40
+
41
+ | Function | Description |
42
+ | ------------------------------ | --------------------------- |
43
+ | `replaceAssetUrl(nodeId, url)` | Replace image/SVG/video URL |
44
+ | `replaceText(nodeId, text)` | Replace text content |
45
+ | `updateNode(nodeId, props)` | Update any node properties |
46
+ | `batchReplace(replacements)` | Batch update multiple nodes |
47
+ | `selectNodes(nodeIds)` | Select nodes by ID |
48
+ | `removeNodes(nodeIds)` | Remove nodes |
49
+ | `undo()` / `redo()` | Undo/redo actions |
50
+
51
+ ### Export
52
+
53
+ | Function | Description |
54
+ | ------------------------------------------- | -------------------------------- |
55
+ | `generateExportUrl(opts)` | Generate export URL with options |
56
+ | `generateExportUrlFromCurrentProject(opts)` | Export URL for current project |
57
+ | `parseJitterUrl(url)` | Parse file/node IDs from URL |
58
+ | `getFileMeta()` | Get current file metadata |
59
+
60
+ ### Snapshot & Restore
61
+
62
+ | Function | Description |
63
+ | -------------------------------------------------- | ----------------------------------------- |
64
+ | `createSnapshot(nodeIds)` | Save node states |
65
+ | `restoreFromSnapshot(snapshot)` | Restore saved states |
66
+ | `duplicateProject()` | Clone current project |
67
+ | `withTemporaryChanges(nodeIds, changes, callback)` | Apply temp changes, run callback, restore |
68
+
69
+ ### Waiting
70
+
71
+ | Function | Description |
72
+ | ------------------------------- | ---------------------- |
73
+ | `waitForApp(timeout?)` | Wait for app to load |
74
+ | `waitForSync(delay?)` | Wait for server sync |
75
+ | `waitForNode(nodeId, timeout?)` | Wait for node to exist |
76
+ | `isAppReady()` | Check if app is ready |
77
+
78
+ ## Examples
79
+
80
+ ### Replace Assets and Export
81
+
82
+ ```javascript
83
+ // Get all media nodes
84
+ const media = await page.evaluate(() => jitterUtils.findAllMediaNodes())
85
+
86
+ // Replace specific assets
87
+ await page.evaluate(() => {
88
+ jitterUtils.batchReplace([
89
+ { nodeId: 'abc123', data: { url: 'https://example.com/new-image.svg' } },
90
+ { nodeId: 'def456', data: { url: 'https://example.com/new-photo.jpg' } },
91
+ ])
92
+ })
93
+
94
+ // Wait for sync then export
95
+ await page.evaluate(() => jitterUtils.waitForSync())
96
+ const exportUrl = await page.evaluate(() =>
97
+ jitterUtils.generateExportUrlFromCurrentProject({ profile: 'lottie' }),
98
+ )
99
+ await page.goto(exportUrl)
100
+ ```
101
+
102
+ ### Export with Temporary Changes
103
+
104
+ ```javascript
105
+ await page.evaluate(async () => {
106
+ const nodeIds = ['node1', 'node2']
107
+ const changes = {
108
+ node1: { url: 'https://temp-asset.svg' },
109
+ node2: { text: 'Temporary Text' },
110
+ }
111
+
112
+ await jitterUtils.withTemporaryChanges(nodeIds, changes, async () => {
113
+ // Changes applied here, will be restored after
114
+ const url = jitterUtils.generateExportUrlFromCurrentProject()
115
+ // ... navigate to export URL and download
116
+ })
117
+ // Original values automatically restored
118
+ })
119
+ ```
120
+
121
+ ### Find and Update Text
122
+
123
+ ```javascript
124
+ const textNodes = await page.evaluate(() => jitterUtils.findAllTextNodes())
125
+ // [{ id, name, text, fontSize, fontFamily }, ...]
126
+
127
+ await page.evaluate(() => {
128
+ jitterUtils.replaceText('textNodeId', 'New headline')
129
+ })
130
+ ```
131
+
132
+ ## Export Profiles
133
+
134
+ | Profile | Output |
135
+ | ------------ | ------------------------------ |
136
+ | `lottie` | Lottie JSON (vector animation) |
137
+ | `mp4` | H.264 video |
138
+ | `gif` | Animated GIF |
139
+ | `webm` | WebM video |
140
+ | `prores4444` | ProRes 4444 (with alpha) |
141
+ | `pngs` | PNG sequence |
142
+
143
+ ## Lottie Export Limitations
144
+
145
+ - **NodeIds are NOT preserved** in exported Lottie - cannot map back to Jitter nodes
146
+ - **Text becomes shapes** - not editable Lottie text layers
147
+ - **Images are embedded** as base64, no external URLs
148
+ - **Videos** export as first frame only
149
+
150
+ **Workaround:** Always modify assets in Jitter before export using `replaceAssetUrl()`.
151
+
152
+ ## Tips
153
+
154
+ 1. **Wait for sync** after modifications before exporting (1-2 seconds)
155
+ 2. **Asset URLs** must be publicly accessible - Jitter fetches server-side
156
+ 3. All `*WithUndo` actions can be undone with Ctrl+Z
157
+ 4. Node IDs are stable and bookmarkable via `?nodeId=xxx`
158
+ 5. Export URLs require being logged in with project access