mixdog 0.9.156 → 0.9.158

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 (191) hide show
  1. package/README.md +30 -13
  2. package/package.json +6 -8
  3. package/scripts/build-ffmpeg-runtime.sh +141 -0
  4. package/scripts/build-runtime-linux.sh +7 -0
  5. package/scripts/build-runtime-macos.sh +7 -0
  6. package/scripts/generate-voice-runtime-manifest.mjs +70 -0
  7. package/scripts/lib/embedding-model-bench-core.mjs +353 -0
  8. package/scripts/lib/stage-postgres-runtime-windows.ps1 +235 -0
  9. package/scripts/native-tool-download.mjs +6 -7
  10. package/scripts/prepare-native-assets.mjs +13 -33
  11. package/scripts/prune-desktop-runtime.mjs +304 -0
  12. package/scripts/prune-embedding-runtime.mjs +19 -0
  13. package/scripts/run-office-live-tests.mjs +17 -21
  14. package/scripts/smoke-runtime-negative.sh +3 -2
  15. package/scripts/sync-voice-runtime-manifest.mjs +1 -0
  16. package/scripts/verify-release-assets.mjs +0 -63
  17. package/scripts/verify-voice-runtime-release.mjs +26 -8
  18. package/scripts/voice-runtime-config.json +2 -1
  19. package/src/app.mjs +0 -1
  20. package/src/headless-command.mjs +1 -2
  21. package/src/headless-exec.mjs +2 -5
  22. package/src/help.mjs +2 -1
  23. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +40 -15
  24. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +234 -0
  25. package/src/runtime/agent/orchestrator/providers/cursor-wire-interactions.mjs +80 -0
  26. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +75 -1
  27. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +234 -93
  28. package/src/runtime/agent/orchestrator/providers/lib/anthropic-replay-blocks.mjs +98 -0
  29. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +14 -7
  30. package/src/runtime/agent/orchestrator/providers/model-catalog-projection.mjs +160 -0
  31. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +14 -8
  32. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +19 -7
  33. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +13 -1
  34. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +1 -28
  35. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +30 -2
  36. package/src/runtime/agent/orchestrator/session/context-utils.mjs +94 -277
  37. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +97 -6
  38. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +19 -5
  39. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +5 -7
  40. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -0
  41. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +48 -15
  42. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +203 -0
  43. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +15 -2
  44. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +29 -7
  45. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +17 -2
  46. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +0 -24
  47. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +98 -1
  48. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +23 -3
  49. package/src/runtime/agent/orchestrator/session/thinking-replay-recovery.mjs +113 -0
  50. package/src/runtime/agent/orchestrator/session/token-estimate.mjs +130 -0
  51. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +49 -3
  52. package/src/runtime/agent/orchestrator/tools/builtin/lib/glob-static-prefix.mjs +121 -0
  53. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-pattern-fanout.mjs +17 -22
  54. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +1 -1
  55. package/src/runtime/agent/orchestrator/tools/builtin/local-search-telemetry.mjs +11 -0
  56. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +29 -5
  57. package/src/runtime/agent/orchestrator/tools/builtin/search-admission.mjs +33 -0
  58. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +6 -14
  59. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +9 -0
  60. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +57 -7
  61. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
  62. package/src/runtime/browser-bridge/action-schema.mjs +227 -30
  63. package/src/runtime/browser-bridge/browser-action-contract.d.mts +4 -0
  64. package/src/runtime/browser-bridge/browser-action-contract.mjs +25 -0
  65. package/src/runtime/browser-bridge/client.mjs +119 -35
  66. package/src/runtime/browser-bridge/tool-defs.mjs +40 -21
  67. package/src/runtime/channels/data/voice-runtime-manifest.json +35 -35
  68. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +17 -6
  69. package/src/runtime/computer-bridge/action-schema.mjs +108 -21
  70. package/src/runtime/computer-bridge/client.mjs +55 -9
  71. package/src/runtime/computer-bridge/tool-defs.mjs +7 -1
  72. package/src/runtime/memory/data/runtime-manifest.json +17 -17
  73. package/src/runtime/memory/index.mjs +43 -11
  74. package/src/runtime/memory/lib/embedding-cache-retention.mjs +55 -0
  75. package/src/runtime/memory/lib/embedding-model-cache-compression.mjs +50 -0
  76. package/src/runtime/memory/lib/embedding-model-config.mjs +16 -12
  77. package/src/runtime/memory/lib/embedding-provider.mjs +9 -1
  78. package/src/runtime/memory/lib/embedding-reindex.mjs +54 -0
  79. package/src/runtime/memory/lib/embedding-worker.mjs +18 -5
  80. package/src/runtime/memory/lib/http-router.mjs +10 -14
  81. package/src/runtime/memory/lib/light-ko-morph.mjs +88 -0
  82. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +5 -3
  83. package/src/runtime/memory/lib/memory-cycle3.mjs +5 -5
  84. package/src/runtime/memory/lib/memory-embed.mjs +12 -30
  85. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -167
  86. package/src/runtime/memory/lib/memory-text-utils.mjs +14 -56
  87. package/src/runtime/memory/lib/query-handlers.mjs +32 -39
  88. package/src/runtime/memory/lib/recall-embedding-readiness.mjs +78 -0
  89. package/src/runtime/memory/lib/recall-format.mjs +6 -2
  90. package/src/runtime/memory/lib/recall-fusion.mjs +53 -0
  91. package/src/runtime/memory/lib/recall-scoring.mjs +2 -140
  92. package/src/runtime/memory/lib/runtime-fetcher.mjs +16 -6
  93. package/src/runtime/memory/lib/trace-mode.mjs +58 -0
  94. package/src/runtime/memory/lib/trace-store.mjs +75 -43
  95. package/src/runtime/office/assurance-benchmark.mjs +12 -0
  96. package/src/runtime/office/assurance.mjs +45 -5
  97. package/src/runtime/office/benchmark.mjs +6 -1
  98. package/src/runtime/office/capabilities.mjs +19 -13
  99. package/src/runtime/office/composition-system.mjs +33 -0
  100. package/src/runtime/office/content-model.mjs +0 -1
  101. package/src/runtime/office/design-docx-components.mjs +264 -0
  102. package/src/runtime/office/design-docx.mjs +203 -0
  103. package/src/runtime/office/design-library-core.mjs +252 -0
  104. package/src/runtime/office/design-library-pack.mjs +374 -0
  105. package/src/runtime/office/design-library.mjs +26 -1268
  106. package/src/runtime/office/design-pptx-executive.mjs +335 -0
  107. package/src/runtime/office/design-pptx-plan.mjs +977 -0
  108. package/src/runtime/office/design-pptx-primitives.mjs +87 -0
  109. package/src/runtime/office/design-pptx-stack.mjs +50 -0
  110. package/src/runtime/office/design-pptx.mjs +776 -0
  111. package/src/runtime/office/design-review.mjs +373 -0
  112. package/src/runtime/office/design-system.mjs +53 -1988
  113. package/src/runtime/office/design-template-index.mjs +266 -0
  114. package/src/runtime/office/design-template-inspect.mjs +434 -0
  115. package/src/runtime/office/design-tokens.mjs +431 -0
  116. package/src/runtime/office/design-xlsx-components.mjs +171 -0
  117. package/src/runtime/office/design-xlsx.mjs +364 -0
  118. package/src/runtime/office/document-preview.mjs +139 -0
  119. package/src/runtime/office/image-layout.mjs +81 -0
  120. package/src/runtime/office/index.mjs +14 -2191
  121. package/src/runtime/office/office-actions.mjs +940 -0
  122. package/src/runtime/office/office-com-host.ps1 +616 -94
  123. package/src/runtime/office/office-com-session-host.ps1 +89 -13
  124. package/src/runtime/office/office-core.mjs +270 -0
  125. package/src/runtime/office/office-documents.mjs +103 -0
  126. package/src/runtime/office/office-sessions.mjs +465 -0
  127. package/src/runtime/office/office-transactions.mjs +432 -0
  128. package/src/runtime/office/pdf-analysis.mjs +57 -0
  129. package/src/runtime/office/pdf-render.mjs +4 -1
  130. package/src/runtime/office/polish-benchmark.mjs +63 -15
  131. package/src/runtime/office/portable-cells.mjs +271 -0
  132. package/src/runtime/office/portable-docx-parts.mjs +326 -0
  133. package/src/runtime/office/portable-docx-xml.mjs +258 -0
  134. package/src/runtime/office/portable-docx.mjs +755 -0
  135. package/src/runtime/office/portable-ooxml.mjs +21 -6057
  136. package/src/runtime/office/portable-opc.mjs +350 -0
  137. package/src/runtime/office/portable-pivot.mjs +229 -0
  138. package/src/runtime/office/portable-pptx-chart.mjs +101 -0
  139. package/src/runtime/office/portable-pptx-charts.mjs +292 -0
  140. package/src/runtime/office/portable-pptx-core.mjs +326 -0
  141. package/src/runtime/office/portable-pptx-deck.mjs +314 -0
  142. package/src/runtime/office/portable-pptx-package.mjs +439 -0
  143. package/src/runtime/office/portable-pptx-shapes.mjs +633 -0
  144. package/src/runtime/office/portable-pptx.mjs +66 -0
  145. package/src/runtime/office/portable-sheet-parts.mjs +152 -0
  146. package/src/runtime/office/portable-sheet-xml.mjs +320 -0
  147. package/src/runtime/office/portable-slide-shapes.mjs +14 -5
  148. package/src/runtime/office/portable-snapshot.mjs +528 -0
  149. package/src/runtime/office/portable-soffice.mjs +293 -0
  150. package/src/runtime/office/portable-validation.mjs +753 -0
  151. package/src/runtime/office/portable-xlsx.mjs +848 -0
  152. package/src/runtime/office/portable-xml.mjs +234 -0
  153. package/src/runtime/office/quality-live-benchmark.mjs +119 -16
  154. package/src/runtime/office/quality-pipeline.mjs +0 -5
  155. package/src/runtime/office/snapshot-contract.mjs +190 -0
  156. package/src/runtime/office/text-metrics.mjs +101 -2
  157. package/src/runtime/office/tool-defs.mjs +6 -2
  158. package/src/runtime/shared/bridge-tool-args.mjs +42 -0
  159. package/src/runtime/shared/heap-cap.mjs +56 -0
  160. package/src/runtime/shared/idle-gc.mjs +150 -0
  161. package/src/runtime/shared/native-tool-paths.mjs +0 -1
  162. package/src/runtime/shared/tool-workload-gates.mjs +12 -0
  163. package/src/session-runtime/builtin-features.mjs +105 -0
  164. package/src/session-runtime/config-lifecycle.mjs +6 -1
  165. package/src/session-runtime/context-status.mjs +17 -7
  166. package/src/session-runtime/goal-runtime.mjs +38 -13
  167. package/src/session-runtime/prewarm.mjs +0 -6
  168. package/src/session-runtime/runtime-core.mjs +30 -14
  169. package/src/session-runtime/session-lifecycle.mjs +2 -0
  170. package/src/session-runtime/settings-api.mjs +49 -2
  171. package/src/session-runtime/tool-profile.mjs +57 -0
  172. package/src/session-runtime/tool-surface.mjs +19 -3
  173. package/src/standalone/channel-worker.mjs +3 -1
  174. package/src/standalone/daemon.mjs +28 -4
  175. package/src/standalone/memory-runtime-proxy.mjs +2 -1
  176. package/src/standalone/session-client.mjs +5 -0
  177. package/src/standalone/session-protocol.mjs +2 -0
  178. package/src/standalone/session-runtime-host.mjs +2 -28
  179. package/src/standalone/session-runtime-worker.mjs +1 -2
  180. package/src/tui/dist/index.mjs +6 -12
  181. package/src/tui/lib/voice-setup.mjs +13 -20
  182. package/src/tui/session/context-state.mjs +7 -1
  183. package/src/tui/session/session-api-ext.mjs +10 -5
  184. package/src/tui/session/session-api.mjs +18 -0
  185. package/scripts/build-token-addon.mjs +0 -32
  186. package/src/runtime/agent/orchestrator/session/token-bpe.mjs +0 -42
  187. package/src/runtime/agent/orchestrator/session/token-native-worker.mjs +0 -35
  188. package/src/runtime/agent/orchestrator/session/token-native.mjs +0 -288
  189. package/src/runtime/agent/orchestrator/tools/token-addon-fetcher.mjs +0 -195
  190. package/src/runtime/agent/orchestrator/tools/token-manifest.json +0 -26
  191. package/src/runtime/memory/lib/ko-morph.mjs +0 -313
package/README.md CHANGED
@@ -45,31 +45,35 @@ workflow setup.
45
45
 
46
46
  Terminal-Bench 2.1 — same model, same 89 tasks, same official verifier, with
47
47
  only the harness changed. Against the native CLI of each model family, Mixdog
48
- scores higher while spending less to get there.
48
+ delivers the same results at the same speed — on a fraction of the context,
49
+ for far less cost.
49
50
 
50
51
  ### GPT-5.6 Sol xhigh — Mixdog vs Codex CLI
51
52
 
52
53
  ![Terminal-Bench 2.1: Mixdog with GPT-5.6 Sol xhigh versus Codex CLI](https://raw.githubusercontent.com/tribgames/mixdog/main/benchmarks/terminal-bench-2.1/tb21-sol-vs-codex.svg)
53
54
 
54
- - **86.5%** (385/445) vs Codex CLI's **84.3%** (75/89)
55
- - **42%** lower priced cost$0.641 vs $1.096 per trial
56
- - **45%** smaller median final context18.5k vs 33.5k tokens
57
- - **1.11×** faster — 339s vs 378s per trial
55
+ - **39%** lower priced cost $0.476 vs $0.782 per trial
56
+ - **46%** smaller median final context 18.5k vs 34.3k tokens
57
+ - **86.5%** (385/445) vs Codex CLI's **86.1%** (383/445) full `k=5` on both
58
+ sides, pass@5 **96.6%** vs 95.5%
59
+ - Matched speed — 415s vs 437s wall time per trial
58
60
 
59
61
  ### Claude Opus 5 — Mixdog vs Claude Code
60
62
 
61
63
  ![Terminal-Bench 2.1: Mixdog with Claude Opus 5 versus Claude Code](https://raw.githubusercontent.com/tribgames/mixdog/main/benchmarks/terminal-bench-2.1/tb21-opus-vs-claude-code.svg)
62
64
 
63
- - **79/89** vs Claude Code's **77/89**
64
65
  - **19%** lower priced cost — $104.29 vs $129.21 per run
65
66
  - **28%** smaller median final context — 27.6k vs 38.2k tokens
66
- - **1.15×** faster
67
+ - **79/89** vs Claude Code's **77/89**
68
+ - **1.16×** faster — 610s vs 708s wall time per trial
67
69
 
68
- Every run uses the official Harbor verifier, fast mode off, a 272k context
69
- window, and zero retries. The Mixdog Sol run follows the protocol the official
70
- Terminal-Bench leaderboard requires all 89 tasks repeated five times (`k=5`,
71
- 445 trials); the Codex CLI baseline and both Opus-side runs are single passes
72
- (`k=1`, 89 trials each).
70
+ Every run uses the official Harbor verifier, fast mode off, and a 272k context
71
+ window; task failures and agent timeouts are never retried. The Sol comparison
72
+ follows the protocol the official Terminal-Bench leaderboard requires on both
73
+ sides all 89 tasks repeated five times (`k=5`, 445 trials each); the
74
+ Opus-side runs are single passes (`k=1`, 89 trials each). Speed is the full
75
+ trial wall clock, and cost values both sides at the same current API list
76
+ rates.
73
77
 
74
78
  The leaderboard is not accepting community submissions, so every run here ships
75
79
  its raw artifacts instead — Harbor verdicts, official verifier output, pinned
@@ -88,6 +92,13 @@ the harness, presets, and metric scripts that recompute each number above:
88
92
  MCP, skills, hooks, and plugins.
89
93
  - **Local memory** — semantic and lexical recall with project-scoped context
90
94
  and multilingual retrieval.
95
+ - **Browser Use** — a logged-in Chromium pane the agent can drive: tabs,
96
+ forms, downloads, and snapshots, with one-time Chrome profile import
97
+ including cookies and passwords.
98
+ - **Computer Use** — agent control of the Windows desktop through screen
99
+ capture, accessibility, OCR, and a strict guarded input contract.
100
+ - **Office documents** — author and edit Word, Excel, and PowerPoint files
101
+ with model-authored design plans, charts, and assurance-checked output.
91
102
  - **Encrypted remote access** — pair the installable web app with Desktop and
92
103
  use Mixdog from a browser or phone over authenticated E2EE.
93
104
  - **Desktop coding app** — agent panes, Monaco editor, Git, terminals, file
@@ -202,14 +213,20 @@ Mixdog Desktop runs the same agent runtime as the CLI:
202
213
  - Git staging, commits, branches, and generated commit messages
203
214
  - File explorer with previews, thumbnails, search, and drag-and-drop
204
215
  - Integrated terminal tabs using the local system shell
216
+ - Browser Use pane with agent control and Chromium profile import
217
+ - Computer Use on Windows with guarded native input
218
+ - Office document authoring with rendered previews
205
219
  - Image and video generation Studio with a persistent local gallery
206
220
  - Visual workflow, agent, schedule, and webhook editors
207
221
  - Voice dictation with an optional local transcription runtime
222
+ - Extensions hub with guided setup for Git, Memory, Browser Use, Computer
223
+ Use, Office, and voice
208
224
  - Provider setup, usage, git identity, and remote pairing settings
209
225
 
210
226
  The paired remote web app is installable on desktop and mobile browsers. It
211
227
  uses an authenticated end-to-end encrypted connection before session state,
212
- terminal data, files, or operation requests cross the relay.
228
+ terminal data, files, or operation requests cross the relay, and adds mobile
229
+ share-target intake, push notifications, and remote Browser Use.
213
230
 
214
231
  For desktop development:
215
232
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixdog",
3
- "version": "0.9.156",
3
+ "version": "0.9.158",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone mixdog coding-agent CLI/TUI workspace.",
@@ -54,7 +54,7 @@
54
54
  "smoke:all": "npm run smoke && npm run smoke:boot && npm run smoke:patch && npm run smoke:compact",
55
55
  "smoke:boot": "node scripts/boot-smoke.mjs",
56
56
  "smoke:compact": "node scripts/compact-smoke.mjs",
57
- "test:compact": "node --test scripts/suite-compact-test.mjs",
57
+ "test:compact": "node --test scripts/suite-compact-test.mjs src/runtime/agent/orchestrator/session/token-estimate.test.mjs",
58
58
  "test:markdown": "node --test scripts/markdown-surface-test.mjs",
59
59
  "smoke:loop": "node scripts/smoke-loop.mjs",
60
60
  "smoke:loop:final": "node scripts/smoke-loop-report.mjs --require-complete --min-elapsed 5h --min-iterations 400 --max-gap 60s --max-smoke-ms 10000 --max-avg-smoke-ms 8500 --max-step-ms smoke.mjs=4000 --max-step-ms boot-smoke.mjs=8000 --max-rss-mb 140 --max-rss-growth-mb 50",
@@ -72,7 +72,7 @@
72
72
  "test:session-transport": "node --test scripts/session-transport-test.mjs scripts/daemon-bootstrap-test.mjs src/runtime/shared/child-spawn-remote.test.mjs src/standalone/session-runtime-agent-control-client.test.mjs src/standalone/session-runtime-dispatch-cancel.test.mjs src/standalone/session-runtime-host-factory.test.mjs src/standalone/session-runtime-inline-host.test.mjs src/standalone/session-runtime-provider-cooldown.test.mjs src/standalone/session-runtime-shard-host.test.mjs src/standalone/session-runtime-shard-router.test.mjs",
73
73
  "test:session": "node --test scripts/runtime-turn-contract-test.mjs scripts/session-save-fault-store-test.mjs scripts/turn-review-revert-test.mjs src/runtime/shared/tool-surface.test.mjs src/runtime/bridge-clients.test.mjs",
74
74
  "test:quick": "npm run test:session && npm run test:session-transport && npm run test:desktop-main --prefix apps/desktop",
75
- "test:office": "node --test src/runtime/office/office-runtime.test.mjs src/runtime/office/office-assurance.test.mjs src/runtime/office/portable-authoring.test.mjs && npm run test:office-approval --prefix apps/desktop",
75
+ "test:office": "node --test scripts/run-office-live-tests.test.mjs src/runtime/office/office-runtime.test.mjs src/runtime/office/office-assurance.test.mjs src/runtime/office/portable-authoring.test.mjs src/runtime/office/slide-quality.test.mjs && npm run test:office-approval --prefix apps/desktop",
76
76
  "test:office:live": "node scripts/run-office-live-tests.mjs",
77
77
  "test:media": "node --test src/runtime/media/store.test.mjs src/runtime/media/renditions.test.mjs src/runtime/media/adapters/codex-image.test.mjs",
78
78
  "failures": "node scripts/tool-failures.mjs",
@@ -125,7 +125,7 @@
125
125
  "dependencies": {
126
126
  "@anthropic-ai/sdk": "^0.105.0",
127
127
  "@google/generative-ai": "^0.24.1",
128
- "@huggingface/transformers": "^3.8.1",
128
+ "@huggingface/transformers": "^4.2.0",
129
129
  "@modelcontextprotocol/sdk": "^1.29.0",
130
130
  "@mozilla/readability": "^0.6.0",
131
131
  "@napi-rs/canvas": "^1.0.8",
@@ -136,10 +136,9 @@
136
136
  "ink": "^7.1.0",
137
137
  "jsdom": "^27.0.0",
138
138
  "jszip": "^3.10.1",
139
- "kiwi-nlp": "^0.21.0",
140
139
  "marked": "^14.1.4",
141
140
  "node-cron": "^4.5.0",
142
- "onnxruntime-node": "1.23.2",
141
+ "onnxruntime-node": "1.29.0",
143
142
  "openai": "^6.44.0",
144
143
  "pdf-lib": "^1.17.1",
145
144
  "pdfjs-dist": "^6.2.108",
@@ -150,7 +149,6 @@
150
149
  "string-width": "^8.2.1",
151
150
  "strip-ansi": "^7.2.0",
152
151
  "tesseract.js": "^7.0.0",
153
- "tiktoken": "^1.0.22",
154
152
  "undici": "^8.5.0",
155
153
  "unpdf": "^1.8.0",
156
154
  "wrap-ansi": "^10.0.0",
@@ -160,7 +158,7 @@
160
158
  },
161
159
  "overrides": {
162
160
  "onnxruntime-node": {
163
- ".": "1.23.2",
161
+ ".": "1.29.0",
164
162
  "global-agent": "^4.1.3"
165
163
  },
166
164
  "sharp": "^0.35.3"
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ FFMPEG_VERSION="${FFMPEG_VERSION:-6.1.1}"
5
+ TARGET_OS="${TARGET_OS:?TARGET_OS is required}"
6
+ TARGET_ARCH="${TARGET_ARCH:?TARGET_ARCH is required}"
7
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
8
+ BUILD_DIR="$ROOT_DIR/build/ffmpeg-runtime-${TARGET_OS}-${TARGET_ARCH}"
9
+ SOURCE_DIR="$BUILD_DIR/ffmpeg-${FFMPEG_VERSION}"
10
+ DIST_DIR="$ROOT_DIR/dist"
11
+
12
+ rm -rf "$BUILD_DIR"
13
+ mkdir -p "$BUILD_DIR" "$DIST_DIR"
14
+
15
+ echo "==> Downloading FFmpeg n${FFMPEG_VERSION}"
16
+ curl -fsSL --retry 3 \
17
+ "https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.xz" \
18
+ -o "$BUILD_DIR/ffmpeg.tar.xz"
19
+ tar -xJf "$BUILD_DIR/ffmpeg.tar.xz" -C "$BUILD_DIR"
20
+
21
+ CONFIGURE_FLAGS=(
22
+ --disable-everything
23
+ --disable-autodetect
24
+ --disable-debug
25
+ --disable-doc
26
+ --disable-network
27
+ --disable-shared
28
+ --enable-static
29
+ --enable-small
30
+ --enable-ffmpeg
31
+ --enable-avcodec
32
+ --enable-avfilter
33
+ --enable-avformat
34
+ --enable-swresample
35
+ --enable-protocol=file,pipe
36
+ --enable-demuxer=aac,ac3,aiff,amr,ape,asf,au,avi,caf,flac,flv,matroska,mov,mp3,mpegts,ogg,wav,wv
37
+ --enable-decoder=aac,aac_fixed,ac3,alac,amrnb,amrwb,ape,eac3,flac,mp1,mp1float,mp2,mp2float,mp3,mp3float,opus,pcm_alaw,pcm_f32be,pcm_f32le,pcm_f64be,pcm_f64le,pcm_mulaw,pcm_s16be,pcm_s16le,pcm_s24be,pcm_s24le,pcm_s32be,pcm_s32le,pcm_s8,pcm_u16be,pcm_u16le,pcm_u24be,pcm_u24le,pcm_u32be,pcm_u32le,pcm_u8,vorbis,wavpack,wmav1,wmav2,wmapro
38
+ --enable-encoder=pcm_s16le
39
+ --enable-parser=aac,aac_latm,ac3,flac,mpegaudio,opus,vorbis
40
+ --enable-filter=aformat,anull,aresample
41
+ --enable-muxer=wav
42
+ )
43
+
44
+ EXE_NAME=ffmpeg
45
+ STRIP_COMMAND=strip
46
+ if [[ "$TARGET_OS" == "win32" ]]; then
47
+ CONFIGURE_FLAGS+=(
48
+ --target-os=mingw32
49
+ --arch=x86_64
50
+ --cc=gcc
51
+ --ar=ar
52
+ --ranlib=ranlib
53
+ --nm=nm
54
+ --strip=strip
55
+ --extra-ldflags=-static
56
+ )
57
+ EXE_NAME=ffmpeg.exe
58
+ elif [[ "$TARGET_OS" == "darwin" ]]; then
59
+ STRIP_COMMAND="strip -x"
60
+ fi
61
+
62
+ echo "==> Configuring minimal audio-transcode runtime"
63
+ pushd "$SOURCE_DIR" >/dev/null
64
+ ./configure "${CONFIGURE_FLAGS[@]}"
65
+ make -j"$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.logicalcpu)"
66
+ popd >/dev/null
67
+
68
+ RUNTIME_EXE="$SOURCE_DIR/ffmpeg"
69
+ if [[ "$TARGET_OS" == "win32" ]]; then
70
+ RUNTIME_EXE="$SOURCE_DIR/ffmpeg.exe"
71
+ fi
72
+ if [[ ! -f "$RUNTIME_EXE" ]]; then
73
+ echo "FFmpeg build did not produce $RUNTIME_EXE" >&2
74
+ exit 1
75
+ fi
76
+
77
+ read -r -a STRIP_PARTS <<< "$STRIP_COMMAND"
78
+ "${STRIP_PARTS[@]}" "$RUNTIME_EXE"
79
+
80
+ echo "==> Smoke testing WAV normalization"
81
+ PYTHON_COMMAND=
82
+ for candidate in python3 python; do
83
+ if command -v "$candidate" >/dev/null 2>&1; then
84
+ PYTHON_COMMAND="$candidate"
85
+ break
86
+ fi
87
+ done
88
+ if [[ -z "$PYTHON_COMMAND" ]]; then
89
+ echo "Python 3 is required for the FFmpeg runtime smoke test" >&2
90
+ exit 1
91
+ fi
92
+
93
+ "$PYTHON_COMMAND" - "$BUILD_DIR/input.wav" <<'PY'
94
+ import math
95
+ import struct
96
+ import sys
97
+ import wave
98
+
99
+ with wave.open(sys.argv[1], "wb") as wav:
100
+ wav.setnchannels(2)
101
+ wav.setsampwidth(2)
102
+ wav.setframerate(48000)
103
+ frames = bytearray()
104
+ for index in range(4800):
105
+ sample = int(math.sin(index * 2 * math.pi * 440 / 48000) * 12000)
106
+ frames.extend(struct.pack("<hh", sample, sample))
107
+ wav.writeframes(frames)
108
+ PY
109
+ "$RUNTIME_EXE" -hide_banner -loglevel error \
110
+ -i "$BUILD_DIR/input.wav" -ar 16000 -ac 1 -threads 1 -y "$BUILD_DIR/output.wav"
111
+ "$PYTHON_COMMAND" - "$BUILD_DIR/output.wav" <<'PY'
112
+ import sys
113
+ import wave
114
+
115
+ with wave.open(sys.argv[1], "rb") as wav:
116
+ assert wav.getframerate() == 16000
117
+ assert wav.getnchannels() == 1
118
+ assert wav.getnframes() > 0
119
+ PY
120
+
121
+ RUNTIME_BYTES="$(wc -c < "$RUNTIME_EXE" | tr -d ' ')"
122
+ if (( RUNTIME_BYTES > 26214400 )); then
123
+ echo "Minimal FFmpeg exceeds 25 MiB: $RUNTIME_BYTES bytes" >&2
124
+ exit 1
125
+ fi
126
+
127
+ ASSET_NAME="ffmpeg-${TARGET_OS}-${TARGET_ARCH}.gz"
128
+ gzip -9 -n -c "$RUNTIME_EXE" > "$DIST_DIR/$ASSET_NAME"
129
+ ASSET_BYTES="$(wc -c < "$DIST_DIR/$ASSET_NAME" | tr -d ' ')"
130
+ if (( ASSET_BYTES > 15728640 )); then
131
+ echo "Compressed FFmpeg exceeds 15 MiB: $ASSET_BYTES bytes" >&2
132
+ exit 1
133
+ fi
134
+
135
+ if command -v sha256sum >/dev/null 2>&1; then
136
+ (cd "$DIST_DIR" && sha256sum "$ASSET_NAME" > "$ASSET_NAME.sha256")
137
+ else
138
+ (cd "$DIST_DIR" && shasum -a 256 "$ASSET_NAME" > "$ASSET_NAME.sha256")
139
+ fi
140
+
141
+ echo "Built $DIST_DIR/$ASSET_NAME ($RUNTIME_BYTES bytes raw, $ASSET_BYTES bytes compressed)"
@@ -78,6 +78,7 @@ else
78
78
  make -j"$(nproc)"
79
79
  make install
80
80
  make -C contrib/pgcrypto install
81
+ make -C contrib/pg_trgm install
81
82
  fi
82
83
 
83
84
  PG_CONFIG="$STAGE_DIR/bin/pg_config"
@@ -255,6 +256,10 @@ for attempt in 1 2 3; do
255
256
  echo " vector extension version: $EXTV"
256
257
  echo " distance query result: $DIST"
257
258
  [[ "$EXTV" == "$PGVECTOR_VERSION" ]] || { echo "FAIL: extversion=$EXTV expected=$PGVECTOR_VERSION"; exit 1; }
259
+ "${RUN_AS[@]}" "$RUNTIME_DIR/bin/psql" -h 127.0.0.1 -p "$SMOKE_PORT" -U postgres -d postgres -c "CREATE EXTENSION pg_trgm;" > /dev/null
260
+ SIM="$("${RUN_AS[@]}" "$RUNTIME_DIR/bin/psql" -h 127.0.0.1 -p "$SMOKE_PORT" -U postgres -d postgres -tAc "SELECT similarity('mixdog','mixdig') > 0;")"
261
+ echo " pg_trgm similarity probe: $SIM"
262
+ [[ "$SIM" == "t" ]] || { echo "FAIL: pg_trgm similarity=$SIM"; exit 1; }
258
263
  "${RUN_AS[@]}" "$RUNTIME_DIR/bin/pg_ctl" -D "$SMOKE_DATA" -m fast stop > /dev/null
259
264
  )
260
265
  attempt_rc=$?
@@ -323,6 +328,8 @@ for attempt in 1 2 3; do
323
328
  "$EXTRACT_DIR/bin/psql" -h 127.0.0.1 -p "$EXTRACT_PORT" -U postgres -d postgres -tAc \
324
329
  "SELECT extversion FROM pg_extension WHERE extname='vector';")"
325
330
  [[ "$EXTV2" == "$PGVECTOR_VERSION" ]] || { echo "FAIL: extracted-smoke extversion=$EXTV2"; exit 1; }
331
+ "${RUN_AS[@]}" env -i HOME="$EXTRACT_DIR" PATH="/usr/bin:/bin" \
332
+ "$EXTRACT_DIR/bin/psql" -h 127.0.0.1 -p "$EXTRACT_PORT" -U postgres -d postgres -c "CREATE EXTENSION pg_trgm;" > /dev/null
326
333
  "${RUN_AS[@]}" env -i HOME="$EXTRACT_DIR" PATH="/usr/bin:/bin" \
327
334
  "$EXTRACT_DIR/bin/pg_ctl" -D "$EXTRACT_DATA" -m fast stop > /dev/null
328
335
  )
@@ -73,6 +73,7 @@ else
73
73
  make -j"$(sysctl -n hw.logicalcpu)"
74
74
  make install
75
75
  make -C contrib/pgcrypto install
76
+ make -C contrib/pg_trgm install
76
77
  fi
77
78
 
78
79
  PG_CONFIG="$STAGE_DIR/bin/pg_config"
@@ -165,6 +166,10 @@ DIST="$("$RUNTIME_DIR/bin/psql" -h 127.0.0.1 -p "$SMOKE_PORT" -U postgres -d pos
165
166
  echo " vector extension version: $EXTV"
166
167
  echo " distance query result: $DIST"
167
168
  [[ "$EXTV" == "$PGVECTOR_VERSION" ]] || { echo "FAIL: extversion=$EXTV expected=$PGVECTOR_VERSION"; exit 1; }
169
+ "$RUNTIME_DIR/bin/psql" -h 127.0.0.1 -p "$SMOKE_PORT" -U postgres -d postgres -c "CREATE EXTENSION pg_trgm;" > /dev/null
170
+ SIM="$("$RUNTIME_DIR/bin/psql" -h 127.0.0.1 -p "$SMOKE_PORT" -U postgres -d postgres -tAc "SELECT similarity('mixdog','mixdig') > 0;")"
171
+ echo " pg_trgm similarity probe: $SIM"
172
+ [[ "$SIM" == "t" ]] || { echo "FAIL: pg_trgm similarity=$SIM"; exit 1; }
168
173
  "$RUNTIME_DIR/bin/pg_ctl" -D "$SMOKE_DATA" -m fast stop > /dev/null
169
174
  trap - EXIT
170
175
  rm -rf "$SMOKE_DATA"
@@ -207,6 +212,8 @@ env -i HOME="$EXTRACT_DIR" PATH="/usr/bin:/bin" \
207
212
  "$EXTRACT_DIR/bin/psql" -h 127.0.0.1 -p "$EXTRACT_PORT" -U postgres -d postgres -c "CREATE EXTENSION vector;" > /dev/null
208
213
  EXTV2="$(env -i HOME="$EXTRACT_DIR" PATH="/usr/bin:/bin" "$EXTRACT_DIR/bin/psql" -h 127.0.0.1 -p "$EXTRACT_PORT" -U postgres -d postgres -tAc "SELECT extversion FROM pg_extension WHERE extname='vector';")"
209
214
  [[ "$EXTV2" == "$PGVECTOR_VERSION" ]] || { echo "FAIL: extracted-smoke extversion=$EXTV2"; exit 1; }
215
+ env -i HOME="$EXTRACT_DIR" PATH="/usr/bin:/bin" \
216
+ "$EXTRACT_DIR/bin/psql" -h 127.0.0.1 -p "$EXTRACT_PORT" -U postgres -d postgres -c "CREATE EXTENSION pg_trgm;" > /dev/null
210
217
  env -i HOME="$EXTRACT_DIR" PATH="/usr/bin:/bin" \
211
218
  "$EXTRACT_DIR/bin/pg_ctl" -D "$EXTRACT_DATA" -m fast stop > /dev/null
212
219
  trap - EXIT
@@ -10,6 +10,7 @@ const RELEASE_HASH_INPUTS = [
10
10
  new URL('../.github/workflows/build-voice-runtime.yml', import.meta.url),
11
11
  new URL('./build-voice-runtime-unix.sh', import.meta.url),
12
12
  new URL('./build-voice-runtime-windows.ps1', import.meta.url),
13
+ new URL('./build-ffmpeg-runtime.sh', import.meta.url),
13
14
  new URL('./generate-voice-runtime-manifest.mjs', import.meta.url),
14
15
  ]
15
16
 
@@ -21,6 +22,9 @@ function loadVoiceRuntimeConfig() {
21
22
  if (!/^[a-f0-9]{40}$/.test(config.whisperCommit || '')) {
22
23
  throw new Error('voice runtime config has an invalid whisperCommit')
23
24
  }
25
+ if (!/^\d+\.\d+\.\d+-mixdog\.\d+$/.test(config.ffmpegVersion || '')) {
26
+ throw new Error('voice runtime config has an invalid ffmpegVersion')
27
+ }
24
28
  if (!Array.isArray(config.platforms) || config.platforms.length === 0) {
25
29
  throw new Error('voice runtime config has no platforms')
26
30
  }
@@ -133,6 +137,38 @@ export function buildVoiceRuntimePlatforms(
133
137
  return platforms
134
138
  }
135
139
 
140
+ function ffmpegAssetName(spec) {
141
+ return `ffmpeg-${spec.os}-${spec.arch}.gz`
142
+ }
143
+
144
+ export function buildVoiceFfmpegPlatforms(
145
+ releaseAssets,
146
+ { repository = 'tribgames/mixdog', tag = VOICE_RUNTIME_TAG } = {},
147
+ ) {
148
+ const byName = new Map((releaseAssets || []).map((asset) => [asset.name, asset]))
149
+ const platforms = {}
150
+ for (const spec of VOICE_RUNTIME_CONFIG.platforms) {
151
+ const assetName = ffmpegAssetName(spec)
152
+ const asset = byName.get(assetName)
153
+ if (!asset) throw new Error(`release is missing required asset ${assetName}`)
154
+ if (!Number.isSafeInteger(asset.size) || asset.size <= 0) {
155
+ throw new Error(`release asset ${assetName} has invalid size`)
156
+ }
157
+ platforms[spec.key] = {
158
+ url: `https://github.com/${repository}/releases/download/${tag}/${assetName}`,
159
+ sha256: releaseAssetSha256(asset),
160
+ size: asset.size,
161
+ format: 'gz',
162
+ executable: spec.os === 'win32' ? 'ffmpeg.exe' : 'ffmpeg',
163
+ }
164
+ }
165
+ return {
166
+ version: VOICE_RUNTIME_CONFIG.ffmpegVersion,
167
+ source: 'FFmpeg n6.1.1 minimal audio-transcode build',
168
+ platforms,
169
+ }
170
+ }
171
+
136
172
  function githubHeaders(token, accept = 'application/vnd.github+json') {
137
173
  return {
138
174
  Accept: accept,
@@ -207,6 +243,7 @@ export function voiceRuntimeIdentity(manifest) {
207
243
  source: manifest?.source,
208
244
  release_tag: manifest?.release_tag,
209
245
  build_hash: manifest?.build_hash,
246
+ ffmpeg: manifest?.ffmpeg,
210
247
  platforms: manifest?.platforms,
211
248
  }
212
249
  }
@@ -258,6 +295,36 @@ export async function assertVoiceRuntimeManifestIdentity(
258
295
  throw new Error(`voice runtime manifest ${spec.key} does not match the release config`)
259
296
  }
260
297
  }
298
+ const expectedFfmpeg = buildVoiceFfmpegPlatforms(
299
+ VOICE_RUNTIME_CONFIG.platforms.map((spec, index) => ({
300
+ name: ffmpegAssetName(spec),
301
+ size: index + 1,
302
+ digest: `sha256:${String(index + 1).padStart(64, '0')}`,
303
+ })),
304
+ { repository, tag: VOICE_RUNTIME_TAG },
305
+ )
306
+ if (
307
+ manifest?.ffmpeg?.version !== expectedFfmpeg.version
308
+ || manifest?.ffmpeg?.source !== expectedFfmpeg.source
309
+ || JSON.stringify(Object.keys(manifest?.ffmpeg?.platforms || {}))
310
+ !== JSON.stringify(Object.keys(expectedFfmpeg.platforms))
311
+ ) {
312
+ throw new Error('voice runtime FFmpeg manifest does not match the release config')
313
+ }
314
+ for (const spec of VOICE_RUNTIME_CONFIG.platforms) {
315
+ const actual = manifest.ffmpeg.platforms[spec.key]
316
+ const expected = expectedFfmpeg.platforms[spec.key]
317
+ if (
318
+ actual?.url !== expected.url
319
+ || actual?.format !== expected.format
320
+ || actual?.executable !== expected.executable
321
+ || !/^[a-f0-9]{64}$/.test(actual?.sha256 || '')
322
+ || !Number.isSafeInteger(actual?.size)
323
+ || actual.size <= 0
324
+ ) {
325
+ throw new Error(`voice runtime FFmpeg ${spec.key} does not match the release config`)
326
+ }
327
+ }
261
328
  }
262
329
 
263
330
  async function main() {
@@ -269,11 +336,13 @@ async function main() {
269
336
  const manifestPath = resolve(process.argv[2] || 'src/runtime/channels/data/voice-runtime-manifest.json')
270
337
  const manifest = JSON.parse(await readFile(manifestPath, 'utf8'))
271
338
  let platforms
339
+ let ffmpeg
272
340
  let lastError
273
341
  for (let attempt = 1; attempt <= 5; attempt++) {
274
342
  try {
275
343
  const release = await fetchGithubRelease(repository, tag, process.env.GITHUB_TOKEN)
276
344
  platforms = buildVoiceRuntimePlatforms(release.assets, { repository, tag })
345
+ ffmpeg = buildVoiceFfmpegPlatforms(release.assets, { repository, tag })
277
346
  lastError = null
278
347
  break
279
348
  } catch (error) {
@@ -286,6 +355,7 @@ async function main() {
286
355
  manifest.source = `ggml-org/whisper.cpp@${VOICE_RUNTIME_COMMIT}`
287
356
  manifest.release_tag = tag
288
357
  manifest.build_hash = await voiceRuntimeBuildHash()
358
+ manifest.ffmpeg = ffmpeg
289
359
  manifest.platforms = platforms
290
360
  await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`)
291
361
  console.log(`updated ${manifestPath} from ${tag}`)