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.
- package/README.md +30 -13
- package/package.json +6 -8
- package/scripts/build-ffmpeg-runtime.sh +141 -0
- package/scripts/build-runtime-linux.sh +7 -0
- package/scripts/build-runtime-macos.sh +7 -0
- package/scripts/generate-voice-runtime-manifest.mjs +70 -0
- package/scripts/lib/embedding-model-bench-core.mjs +353 -0
- package/scripts/lib/stage-postgres-runtime-windows.ps1 +235 -0
- package/scripts/native-tool-download.mjs +6 -7
- package/scripts/prepare-native-assets.mjs +13 -33
- package/scripts/prune-desktop-runtime.mjs +304 -0
- package/scripts/prune-embedding-runtime.mjs +19 -0
- package/scripts/run-office-live-tests.mjs +17 -21
- package/scripts/smoke-runtime-negative.sh +3 -2
- package/scripts/sync-voice-runtime-manifest.mjs +1 -0
- package/scripts/verify-release-assets.mjs +0 -63
- package/scripts/verify-voice-runtime-release.mjs +26 -8
- package/scripts/voice-runtime-config.json +2 -1
- package/src/app.mjs +0 -1
- package/src/headless-command.mjs +1 -2
- package/src/headless-exec.mjs +2 -5
- package/src/help.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +40 -15
- package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +234 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-interactions.mjs +80 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +75 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +234 -93
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-replay-blocks.mjs +98 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/model-catalog-projection.mjs +160 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +14 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +19 -7
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +1 -28
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +30 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +94 -277
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +97 -6
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +19 -5
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +5 -7
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +48 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +203 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +15 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +29 -7
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +17 -2
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +0 -24
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +98 -1
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +23 -3
- package/src/runtime/agent/orchestrator/session/thinking-replay-recovery.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/token-estimate.mjs +130 -0
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +49 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/glob-static-prefix.mjs +121 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-pattern-fanout.mjs +17 -22
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/local-search-telemetry.mjs +11 -0
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +29 -5
- package/src/runtime/agent/orchestrator/tools/builtin/search-admission.mjs +33 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +6 -14
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +57 -7
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
- package/src/runtime/browser-bridge/action-schema.mjs +227 -30
- package/src/runtime/browser-bridge/browser-action-contract.d.mts +4 -0
- package/src/runtime/browser-bridge/browser-action-contract.mjs +25 -0
- package/src/runtime/browser-bridge/client.mjs +119 -35
- package/src/runtime/browser-bridge/tool-defs.mjs +40 -21
- package/src/runtime/channels/data/voice-runtime-manifest.json +35 -35
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +17 -6
- package/src/runtime/computer-bridge/action-schema.mjs +108 -21
- package/src/runtime/computer-bridge/client.mjs +55 -9
- package/src/runtime/computer-bridge/tool-defs.mjs +7 -1
- package/src/runtime/memory/data/runtime-manifest.json +17 -17
- package/src/runtime/memory/index.mjs +43 -11
- package/src/runtime/memory/lib/embedding-cache-retention.mjs +55 -0
- package/src/runtime/memory/lib/embedding-model-cache-compression.mjs +50 -0
- package/src/runtime/memory/lib/embedding-model-config.mjs +16 -12
- package/src/runtime/memory/lib/embedding-provider.mjs +9 -1
- package/src/runtime/memory/lib/embedding-reindex.mjs +54 -0
- package/src/runtime/memory/lib/embedding-worker.mjs +18 -5
- package/src/runtime/memory/lib/http-router.mjs +10 -14
- package/src/runtime/memory/lib/light-ko-morph.mjs +88 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +5 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +5 -5
- package/src/runtime/memory/lib/memory-embed.mjs +12 -30
- package/src/runtime/memory/lib/memory-recall-store.mjs +22 -167
- package/src/runtime/memory/lib/memory-text-utils.mjs +14 -56
- package/src/runtime/memory/lib/query-handlers.mjs +32 -39
- package/src/runtime/memory/lib/recall-embedding-readiness.mjs +78 -0
- package/src/runtime/memory/lib/recall-format.mjs +6 -2
- package/src/runtime/memory/lib/recall-fusion.mjs +53 -0
- package/src/runtime/memory/lib/recall-scoring.mjs +2 -140
- package/src/runtime/memory/lib/runtime-fetcher.mjs +16 -6
- package/src/runtime/memory/lib/trace-mode.mjs +58 -0
- package/src/runtime/memory/lib/trace-store.mjs +75 -43
- package/src/runtime/office/assurance-benchmark.mjs +12 -0
- package/src/runtime/office/assurance.mjs +45 -5
- package/src/runtime/office/benchmark.mjs +6 -1
- package/src/runtime/office/capabilities.mjs +19 -13
- package/src/runtime/office/composition-system.mjs +33 -0
- package/src/runtime/office/content-model.mjs +0 -1
- package/src/runtime/office/design-docx-components.mjs +264 -0
- package/src/runtime/office/design-docx.mjs +203 -0
- package/src/runtime/office/design-library-core.mjs +252 -0
- package/src/runtime/office/design-library-pack.mjs +374 -0
- package/src/runtime/office/design-library.mjs +26 -1268
- package/src/runtime/office/design-pptx-executive.mjs +335 -0
- package/src/runtime/office/design-pptx-plan.mjs +977 -0
- package/src/runtime/office/design-pptx-primitives.mjs +87 -0
- package/src/runtime/office/design-pptx-stack.mjs +50 -0
- package/src/runtime/office/design-pptx.mjs +776 -0
- package/src/runtime/office/design-review.mjs +373 -0
- package/src/runtime/office/design-system.mjs +53 -1988
- package/src/runtime/office/design-template-index.mjs +266 -0
- package/src/runtime/office/design-template-inspect.mjs +434 -0
- package/src/runtime/office/design-tokens.mjs +431 -0
- package/src/runtime/office/design-xlsx-components.mjs +171 -0
- package/src/runtime/office/design-xlsx.mjs +364 -0
- package/src/runtime/office/document-preview.mjs +139 -0
- package/src/runtime/office/image-layout.mjs +81 -0
- package/src/runtime/office/index.mjs +14 -2191
- package/src/runtime/office/office-actions.mjs +940 -0
- package/src/runtime/office/office-com-host.ps1 +616 -94
- package/src/runtime/office/office-com-session-host.ps1 +89 -13
- package/src/runtime/office/office-core.mjs +270 -0
- package/src/runtime/office/office-documents.mjs +103 -0
- package/src/runtime/office/office-sessions.mjs +465 -0
- package/src/runtime/office/office-transactions.mjs +432 -0
- package/src/runtime/office/pdf-analysis.mjs +57 -0
- package/src/runtime/office/pdf-render.mjs +4 -1
- package/src/runtime/office/polish-benchmark.mjs +63 -15
- package/src/runtime/office/portable-cells.mjs +271 -0
- package/src/runtime/office/portable-docx-parts.mjs +326 -0
- package/src/runtime/office/portable-docx-xml.mjs +258 -0
- package/src/runtime/office/portable-docx.mjs +755 -0
- package/src/runtime/office/portable-ooxml.mjs +21 -6057
- package/src/runtime/office/portable-opc.mjs +350 -0
- package/src/runtime/office/portable-pivot.mjs +229 -0
- package/src/runtime/office/portable-pptx-chart.mjs +101 -0
- package/src/runtime/office/portable-pptx-charts.mjs +292 -0
- package/src/runtime/office/portable-pptx-core.mjs +326 -0
- package/src/runtime/office/portable-pptx-deck.mjs +314 -0
- package/src/runtime/office/portable-pptx-package.mjs +439 -0
- package/src/runtime/office/portable-pptx-shapes.mjs +633 -0
- package/src/runtime/office/portable-pptx.mjs +66 -0
- package/src/runtime/office/portable-sheet-parts.mjs +152 -0
- package/src/runtime/office/portable-sheet-xml.mjs +320 -0
- package/src/runtime/office/portable-slide-shapes.mjs +14 -5
- package/src/runtime/office/portable-snapshot.mjs +528 -0
- package/src/runtime/office/portable-soffice.mjs +293 -0
- package/src/runtime/office/portable-validation.mjs +753 -0
- package/src/runtime/office/portable-xlsx.mjs +848 -0
- package/src/runtime/office/portable-xml.mjs +234 -0
- package/src/runtime/office/quality-live-benchmark.mjs +119 -16
- package/src/runtime/office/quality-pipeline.mjs +0 -5
- package/src/runtime/office/snapshot-contract.mjs +190 -0
- package/src/runtime/office/text-metrics.mjs +101 -2
- package/src/runtime/office/tool-defs.mjs +6 -2
- package/src/runtime/shared/bridge-tool-args.mjs +42 -0
- package/src/runtime/shared/heap-cap.mjs +56 -0
- package/src/runtime/shared/idle-gc.mjs +150 -0
- package/src/runtime/shared/native-tool-paths.mjs +0 -1
- package/src/runtime/shared/tool-workload-gates.mjs +12 -0
- package/src/session-runtime/builtin-features.mjs +105 -0
- package/src/session-runtime/config-lifecycle.mjs +6 -1
- package/src/session-runtime/context-status.mjs +17 -7
- package/src/session-runtime/goal-runtime.mjs +38 -13
- package/src/session-runtime/prewarm.mjs +0 -6
- package/src/session-runtime/runtime-core.mjs +30 -14
- package/src/session-runtime/session-lifecycle.mjs +2 -0
- package/src/session-runtime/settings-api.mjs +49 -2
- package/src/session-runtime/tool-profile.mjs +57 -0
- package/src/session-runtime/tool-surface.mjs +19 -3
- package/src/standalone/channel-worker.mjs +3 -1
- package/src/standalone/daemon.mjs +28 -4
- package/src/standalone/memory-runtime-proxy.mjs +2 -1
- package/src/standalone/session-client.mjs +5 -0
- package/src/standalone/session-protocol.mjs +2 -0
- package/src/standalone/session-runtime-host.mjs +2 -28
- package/src/standalone/session-runtime-worker.mjs +1 -2
- package/src/tui/dist/index.mjs +6 -12
- package/src/tui/lib/voice-setup.mjs +13 -20
- package/src/tui/session/context-state.mjs +7 -1
- package/src/tui/session/session-api-ext.mjs +10 -5
- package/src/tui/session/session-api.mjs +18 -0
- package/scripts/build-token-addon.mjs +0 -32
- package/src/runtime/agent/orchestrator/session/token-bpe.mjs +0 -42
- package/src/runtime/agent/orchestrator/session/token-native-worker.mjs +0 -35
- package/src/runtime/agent/orchestrator/session/token-native.mjs +0 -288
- package/src/runtime/agent/orchestrator/tools/token-addon-fetcher.mjs +0 -195
- package/src/runtime/agent/orchestrator/tools/token-manifest.json +0 -26
- 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
|
-
|
|
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
|

|
|
53
54
|
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
57
|
-
|
|
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
|

|
|
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
|
-
- **
|
|
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
|
|
70
|
-
Terminal-Bench leaderboard requires
|
|
71
|
-
|
|
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.
|
|
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": "^
|
|
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.
|
|
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.
|
|
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}`)
|