mixdog 0.9.147 → 0.9.149
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/package.json +23 -3
- package/scripts/build-voice-runtime-unix.sh +101 -0
- package/scripts/embedding-quality-probe.mjs +96 -0
- package/scripts/generate-voice-runtime-manifest.mjs +300 -0
- package/scripts/generate-voice-runtime-manifest.test.mjs +135 -0
- package/scripts/native-binary-arch.mjs +30 -13
- package/scripts/native-binary-arch.test.mjs +40 -4
- package/scripts/plan-voice-runtime-release.mjs +73 -0
- package/scripts/prepare-native-assets.mjs +50 -9
- package/scripts/prune-embedding-runtime.mjs +3 -3
- package/scripts/sync-voice-runtime-manifest.mjs +46 -0
- package/scripts/verify-release-assets.mjs +106 -6
- package/scripts/verify-voice-runtime-release.mjs +89 -0
- package/scripts/voice-runtime-config.json +52 -0
- package/src/app.mjs +42 -5
- package/src/headless-exec.mjs +58 -32
- package/src/headless-exec.test.mjs +74 -13
- package/src/rules/lead/01-general.md +2 -0
- package/src/rules/shared/10-tool-workflow.md +7 -4
- package/src/rules/shared/30-exploration.md +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +28 -9
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +6 -1
- package/src/runtime/agent/orchestrator/config.mjs +53 -18
- package/src/runtime/agent/orchestrator/mcp/cancellation.test.mjs +139 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +34 -5
- package/src/runtime/agent/orchestrator/mcp/client.mjs +94 -10
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +98 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.test.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +67 -16
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +4 -82
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +0 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +62 -121
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +48 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.test.mjs +215 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +44 -48
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +54 -31
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +56 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +34 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +61 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +61 -15
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +120 -1
- package/src/runtime/agent/orchestrator/providers/lib/env-utils.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/lib/stream-outcome.mjs +0 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +187 -84
- package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +32 -9
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +78 -33
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +21 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +36 -36
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +16 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +50 -213
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +135 -126
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +20 -11
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +112 -36
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +220 -50
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +112 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +130 -60
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +28 -10
- package/src/runtime/agent/orchestrator/providers/registry.mjs +122 -95
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +69 -3
- package/src/runtime/agent/orchestrator/providers/tool-stream-state.mjs +4 -22
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +7 -14
- package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/context-compaction-policy.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +27 -48
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +19 -14
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +9 -43
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +43 -5
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +15 -2
- package/src/runtime/agent/orchestrator/session/manager/pending-messages-persistence.test.mjs +325 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +599 -195
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +22 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +26 -16
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +23 -11
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +118 -3
- package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +332 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +38 -1
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +27 -6
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -20
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +291 -128
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -9
- package/src/runtime/agent/orchestrator/tools/builtin/edit-encoding-eol.test.mjs +224 -0
- package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +53 -3
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +255 -25
- package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +87 -0
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +132 -9
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-pattern-fanout.mjs +29 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool-integrity.test.mjs +14 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +180 -31
- package/src/runtime/agent/orchestrator/tools/builtin/local-search-telemetry.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +32 -5
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-health.test.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +10 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +38 -10
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +31 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +11 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-windows.mjs +22 -4
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +6 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +25 -24
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +152 -133
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +114 -42
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +129 -15
- package/src/runtime/agent/orchestrator/tools/code-graph/loose-file-target.test.mjs +72 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +7 -8
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +201 -19
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +26 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +10 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-search-scope.test.mjs +55 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +115 -25
- package/src/runtime/agent/orchestrator/tools/code-graph/text-span-mask.test.mjs +268 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +296 -46
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.test.mjs +104 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +136 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +127 -38
- package/src/runtime/agent/orchestrator/tools/patch/engine-contract-gate.test.mjs +661 -0
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +350 -9
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +418 -44
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +27 -3
- package/src/runtime/agent/orchestrator/tools/patch/patch-codec-eol.test.mjs +552 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +65 -15
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +284 -109
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +51 -21
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +44 -27
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
- package/src/runtime/attachments/store.mjs +11 -3
- package/src/runtime/channels/data/voice-runtime-manifest.json +46 -70
- package/src/runtime/channels/lib/event-queue.mjs +51 -41
- package/src/runtime/channels/lib/scheduler.mjs +23 -28
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -17
- package/src/runtime/channels/lib/voice-runtime-fetcher.test.mjs +17 -0
- package/src/runtime/channels/lib/webhook.mjs +39 -20
- package/src/runtime/channels/lib/whisper-server.mjs +46 -1
- package/src/runtime/channels/lib/worker-main.mjs +3 -1
- package/src/runtime/media/adapters/gemini-video.mjs +20 -4
- package/src/runtime/media/jobs.mjs +13 -0
- package/src/runtime/media/renditions.mjs +7 -1
- package/src/runtime/media/store.mjs +42 -22
- package/src/runtime/memory/index.mjs +4 -9
- package/src/runtime/memory/lib/agent-ipc.mjs +1 -6
- package/src/runtime/memory/lib/archive-security.test.mjs +21 -1
- package/src/runtime/memory/lib/core-memory-store.mjs +28 -50
- package/src/runtime/memory/lib/embedding-model-config.mjs +37 -1
- package/src/runtime/memory/lib/embedding-model-config.test.mjs +33 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +34 -12
- package/src/runtime/memory/lib/embedding-worker.mjs +37 -5
- package/src/runtime/memory/lib/ko-morph.mjs +46 -15
- package/src/runtime/memory/lib/memory-action-handlers.mjs +18 -1
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -18
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -18
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +98 -45
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +71 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.test.mjs +78 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +37 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
- package/src/runtime/memory/lib/memory-embedding-migration.test.mjs +50 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +9 -24
- package/src/runtime/memory/lib/memory.mjs +50 -12
- package/src/runtime/memory/lib/pg/process.mjs +1 -10
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -9
- package/src/runtime/memory/lib/query-handlers.mjs +2 -4
- package/src/runtime/memory/lib/session-ingest-runtime.mjs +2 -2
- package/src/runtime/shared/background-tasks.mjs +15 -0
- package/src/runtime/shared/background-tasks.test.mjs +78 -0
- package/src/runtime/shared/child-guardian.mjs +2 -10
- package/src/runtime/shared/pid-liveness.mjs +27 -0
- package/src/runtime/shared/pristine-execution-contract.json +0 -1
- package/src/runtime/shared/runtime-root.mjs +1 -11
- package/src/runtime/shared/service-discovery.mjs +1 -17
- package/src/runtime/shared/singleton-owner.mjs +1 -11
- package/src/runtime/shared/staged-update.mjs +2 -12
- package/src/runtime/shared/tool-status.mjs +5 -1
- package/src/runtime/shared/tool-surface.mjs +15 -7
- package/src/runtime/shared/turn-snapshot-store.mjs +168 -0
- package/src/runtime/shared/turn-snapshot.mjs +137 -13
- package/src/runtime/shared/turn-worktree-snapshot.mjs +110 -18
- package/src/runtime/shared/webhook-session-run.mjs +16 -2
- package/src/runtime/web-search/lib/http-fetch.mjs +34 -4
- package/src/runtime/web-search/lib/state.mjs +15 -15
- package/src/runtime/web-search/lib/web-tools.mjs +46 -5
- package/src/session-runtime/context-status.mjs +4 -12
- package/src/session-runtime/runtime-core.mjs +20 -1
- package/src/session-runtime/session-lifecycle.mjs +9 -0
- package/src/standalone/agent-dispatch-broker.mjs +33 -2
- package/src/standalone/agent-tool/job-task-reconcile.mjs +78 -0
- package/src/standalone/agent-tool/notify.mjs +3 -1
- package/src/standalone/agent-tool/spawn-flow.mjs +52 -70
- package/src/standalone/agent-tool/tag-registry.mjs +116 -33
- package/src/standalone/agent-tool/tool-def.mjs +2 -2
- package/src/standalone/agent-tool/worker-index.mjs +8 -11
- package/src/standalone/agent-tool/worker-rows.mjs +4 -1
- package/src/standalone/agent-tool.mjs +20 -55
- package/src/standalone/agent-watchdog-registry.mjs +28 -4
- package/src/standalone/channel-client.mjs +47 -15
- package/src/standalone/channel-transport.mjs +44 -25
- package/src/standalone/daemon.mjs +31 -2
- package/src/standalone/hook-bus/config.mjs +25 -9
- package/src/standalone/hook-bus/handlers.mjs +16 -52
- package/src/standalone/hook-bus.mjs +29 -23
- package/src/standalone/memory-runtime-proxy.mjs +1 -16
- package/src/standalone/session-client.mjs +86 -23
- package/src/standalone/session-protocol.mjs +0 -2
- package/src/standalone/session-runtime-host-health.test.mjs +5 -4
- package/src/standalone/session-runtime-host.mjs +101 -6
- package/src/standalone/session-runtime-record.mjs +1 -5
- package/src/standalone/session-runtime-worker.mjs +52 -57
- package/src/standalone/session-service.mjs +4 -1
- package/src/standalone/session-transport.mjs +56 -25
- package/src/tui/App.jsx +40 -49
- package/src/tui/app/app-view.jsx +14 -21
- package/src/tui/app/core-memory-picker.mjs +29 -16
- package/src/tui/app/create-app-pickers.mjs +15 -36
- package/src/tui/app/extension-pickers.mjs +60 -49
- package/src/tui/app/maintenance-pickers.mjs +100 -57
- package/src/tui/app/message-selector.mjs +6 -5
- package/src/tui/app/model-picker.mjs +30 -13
- package/src/tui/app/onboarding-steps.mjs +21 -12
- package/src/tui/app/panel-epoch.mjs +56 -0
- package/src/tui/app/panel-epoch.test.mjs +1009 -0
- package/src/tui/app/panel-surface.mjs +98 -0
- package/src/tui/app/project-picker.mjs +30 -29
- package/src/tui/app/prompt-submit.mjs +192 -97
- package/src/tui/app/prompt-submit.test.mjs +206 -0
- package/src/tui/app/provider-setup-picker.mjs +74 -43
- package/src/tui/app/resume-picker.mjs +11 -8
- package/src/tui/app/route-pickers.mjs +45 -28
- package/src/tui/app/settings-picker.mjs +69 -18
- package/src/tui/app/shell-layout.mjs +1 -3
- package/src/tui/app/slash-commands.mjs +0 -2
- package/src/tui/app/slash-dispatch.mjs +4 -2
- package/src/tui/app/text-entry-policy.mjs +25 -0
- package/src/tui/app/theme-effort-pickers.mjs +11 -16
- package/src/tui/app/usage-context-panels.mjs +21 -25
- package/src/tui/app/use-global-key-input.mjs +3 -2
- package/src/tui/app/use-prompt-draft-flow.mjs +6 -18
- package/src/tui/app/use-prompt-handlers.mjs +3 -2
- package/src/tui/app/use-welcome-prompt-hint.mjs +17 -3
- package/src/tui/components/Picker.jsx +1 -1
- package/src/tui/components/TextEntryPanel.jsx +7 -2
- package/src/tui/dist/index.mjs +652 -561
- package/src/tui/lib/voice-setup.mjs +1 -2
- package/src/tui/session/agent-job-feed.mjs +73 -11
- package/src/tui/session/session-api-ext.mjs +5 -6
- package/src/tui/session/session-api.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +15 -5
- package/src/tui/session/tui-steering-persist.mjs +33 -19
- package/src/tui/session/tui-steering-persist.test.mjs +104 -0
- package/src/tui/session-local.mjs +0 -22
- package/scripts/.tmp-coverage-report.mjs +0 -96
- package/src/runtime/agent/orchestrator/tools/builtin/shell-monitor.mjs +0 -57
- package/src/runtime/agent/orchestrator/tools/builtin/shell-monitor.test.mjs +0 -57
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import test from 'node:test'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
VOICE_RUNTIME_CONFIG,
|
|
6
|
+
VOICE_RUNTIME_TAG,
|
|
7
|
+
buildVoiceRuntimePlatforms,
|
|
8
|
+
fetchGithubRelease,
|
|
9
|
+
voiceRuntimeBuildHash,
|
|
10
|
+
} from './generate-voice-runtime-manifest.mjs'
|
|
11
|
+
import { mergeVoiceRuntimeManifest } from './sync-voice-runtime-manifest.mjs'
|
|
12
|
+
|
|
13
|
+
const names = VOICE_RUNTIME_CONFIG.platforms.map((platform) => platform.asset)
|
|
14
|
+
|
|
15
|
+
test('voice runtime release assets produce a complete fail-closed manifest', () => {
|
|
16
|
+
assert.equal(VOICE_RUNTIME_CONFIG.vulkanSdkVersion, '1.4.309.0')
|
|
17
|
+
const assets = names.map((name, index) => ({
|
|
18
|
+
name,
|
|
19
|
+
size: index + 1,
|
|
20
|
+
digest: `sha256:${String(index + 1).padStart(64, '0')}`,
|
|
21
|
+
browser_download_url: `https://github.com/tribgames/mixdog/releases/download/${VOICE_RUNTIME_TAG}/${name}`,
|
|
22
|
+
}))
|
|
23
|
+
const platforms = buildVoiceRuntimePlatforms(assets)
|
|
24
|
+
assert.equal(platforms['win32-x64'].variants[0].id, 'vulkan')
|
|
25
|
+
assert.equal(platforms['linux-x64'].variants[0].id, 'vulkan')
|
|
26
|
+
assert.equal(platforms['linux-arm64'].variants[0].id, 'vulkan')
|
|
27
|
+
assert.equal(platforms['darwin-arm64'].variants[0].id, 'metal')
|
|
28
|
+
assert.equal(platforms['darwin-x64'].variants[0].id, 'cpu')
|
|
29
|
+
assert.equal(platforms['win32-x64'].variants[0].executable, 'whisper-server.exe')
|
|
30
|
+
assert.deepEqual(
|
|
31
|
+
VOICE_RUNTIME_CONFIG.platforms
|
|
32
|
+
.filter((platform) => platform.os === 'linux')
|
|
33
|
+
.map((platform) => platform.runner),
|
|
34
|
+
['ubuntu-24.04', 'ubuntu-24.04-arm'],
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('voice runtime manifest generation rejects a partial release', () => {
|
|
39
|
+
assert.throws(() => buildVoiceRuntimePlatforms([]), /missing required asset/)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('voice runtime manifest generation rejects undeclared archives', () => {
|
|
43
|
+
assert.throws(
|
|
44
|
+
() => buildVoiceRuntimePlatforms([{
|
|
45
|
+
name: 'whisper-server-linux-riscv64-cpu.zip',
|
|
46
|
+
size: 1,
|
|
47
|
+
digest: `sha256:${'1'.padStart(64, '0')}`,
|
|
48
|
+
browser_download_url:
|
|
49
|
+
`https://github.com/tribgames/mixdog/releases/download/${VOICE_RUNTIME_TAG}/whisper-server-linux-riscv64-cpu.zip`,
|
|
50
|
+
}]),
|
|
51
|
+
/unexpected runtime asset/,
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('voice runtime manifest normalizes hidden draft asset URLs to the published tag', () => {
|
|
56
|
+
const assets = names.map((name, index) => ({
|
|
57
|
+
name,
|
|
58
|
+
size: index + 1,
|
|
59
|
+
digest: `sha256:${String(index + 1).padStart(64, '0')}`,
|
|
60
|
+
browser_download_url:
|
|
61
|
+
`https://github.com/tribgames/mixdog/releases/download/untagged-fixture/${name}`,
|
|
62
|
+
}))
|
|
63
|
+
const platforms = buildVoiceRuntimePlatforms(assets)
|
|
64
|
+
assert.equal(
|
|
65
|
+
platforms['win32-x64'].variants[0].url,
|
|
66
|
+
`https://github.com/tribgames/mixdog/releases/download/${VOICE_RUNTIME_TAG}/whisper-server-win32-x64-vulkan.zip`,
|
|
67
|
+
)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('voice runtime release lookup finds an authenticated untagged draft', async (t) => {
|
|
71
|
+
const originalFetch = globalThis.fetch
|
|
72
|
+
t.after(() => {
|
|
73
|
+
globalThis.fetch = originalFetch
|
|
74
|
+
})
|
|
75
|
+
const requests = []
|
|
76
|
+
globalThis.fetch = async (url) => {
|
|
77
|
+
requests.push(String(url))
|
|
78
|
+
if (String(url).includes('/releases/tags/')) {
|
|
79
|
+
return new Response(null, { status: 404 })
|
|
80
|
+
}
|
|
81
|
+
return Response.json([{
|
|
82
|
+
tag_name: VOICE_RUNTIME_TAG,
|
|
83
|
+
draft: true,
|
|
84
|
+
assets: [],
|
|
85
|
+
}])
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const release = await fetchGithubRelease(
|
|
89
|
+
'tribgames/mixdog',
|
|
90
|
+
VOICE_RUNTIME_TAG,
|
|
91
|
+
'fixture-token',
|
|
92
|
+
)
|
|
93
|
+
assert.equal(release.draft, true)
|
|
94
|
+
assert.equal(release.tag_name, VOICE_RUNTIME_TAG)
|
|
95
|
+
assert.equal(requests.length, 2)
|
|
96
|
+
assert.match(requests[1], /\/releases\?per_page=100&page=1$/)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('voice runtime build identity is stable and merge preserves model and ffmpeg metadata', async () => {
|
|
100
|
+
const buildHash = await voiceRuntimeBuildHash()
|
|
101
|
+
assert.match(buildHash, /^[a-f0-9]{64}$/)
|
|
102
|
+
const platforms = Object.fromEntries(VOICE_RUNTIME_CONFIG.platforms.map((platform, index) => [
|
|
103
|
+
platform.key,
|
|
104
|
+
{
|
|
105
|
+
variants: [{
|
|
106
|
+
id: platform.backend,
|
|
107
|
+
requires: null,
|
|
108
|
+
url: `https://github.com/tribgames/mixdog/releases/download/${VOICE_RUNTIME_TAG}/${platform.asset}`,
|
|
109
|
+
sha256: String(index + 1).padStart(64, '0'),
|
|
110
|
+
size: index + 1,
|
|
111
|
+
format: 'zip',
|
|
112
|
+
executable: platform.executable,
|
|
113
|
+
}],
|
|
114
|
+
},
|
|
115
|
+
]))
|
|
116
|
+
const current = {
|
|
117
|
+
version: '1.8.4',
|
|
118
|
+
source: 'old',
|
|
119
|
+
model: { id: 'standard' },
|
|
120
|
+
ffmpeg: { version: 'b6.1.1' },
|
|
121
|
+
platforms: {},
|
|
122
|
+
}
|
|
123
|
+
const released = {
|
|
124
|
+
...current,
|
|
125
|
+
version: VOICE_RUNTIME_CONFIG.runtimeVersion,
|
|
126
|
+
source: `ggml-org/whisper.cpp@${VOICE_RUNTIME_CONFIG.whisperCommit}`,
|
|
127
|
+
release_tag: VOICE_RUNTIME_TAG,
|
|
128
|
+
build_hash: buildHash,
|
|
129
|
+
platforms,
|
|
130
|
+
}
|
|
131
|
+
const merged = await mergeVoiceRuntimeManifest(current, released)
|
|
132
|
+
assert.strictEqual(merged.model, current.model)
|
|
133
|
+
assert.strictEqual(merged.ffmpeg, current.ffmpeg)
|
|
134
|
+
assert.deepEqual(merged.platforms, platforms)
|
|
135
|
+
})
|
|
@@ -23,9 +23,18 @@ const PE_MACHINE = new Map([[0x8664, 'x64'], [0xaa64, 'arm64'], [0x14c, 'ia32']]
|
|
|
23
23
|
function machOArch(buffer) {
|
|
24
24
|
if (buffer.length < 8) return null
|
|
25
25
|
const magic = buffer.readUInt32BE(0)
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
if (magic ===
|
|
26
|
+
// mach_header_64 is 32 bytes; mach_header is 28. Do not trust cputype until
|
|
27
|
+
// the full header extent is present.
|
|
28
|
+
if (magic === 0xfeedfacf || magic === 0xcffaedfe) {
|
|
29
|
+
if (buffer.length < 32) return null
|
|
30
|
+
const cpu = magic === 0xfeedfacf ? buffer.readUInt32BE(4) : buffer.readUInt32LE(4)
|
|
31
|
+
return MACHO_CPU.get(cpu) || null
|
|
32
|
+
}
|
|
33
|
+
if (magic === 0xfeedface || magic === 0xcefaedfe) {
|
|
34
|
+
if (buffer.length < 28) return null
|
|
35
|
+
const cpu = magic === 0xfeedface ? buffer.readUInt32BE(4) : buffer.readUInt32LE(4)
|
|
36
|
+
return MACHO_CPU.get(cpu) || null
|
|
37
|
+
}
|
|
29
38
|
return null
|
|
30
39
|
}
|
|
31
40
|
|
|
@@ -40,10 +49,10 @@ function machOFatArches(buffer) {
|
|
|
40
49
|
const count = buffer.readUInt32BE(4)
|
|
41
50
|
if (!count || count > 16) return null
|
|
42
51
|
const entrySize = wide ? 32 : 20
|
|
52
|
+
if (buffer.length < 8 + count * entrySize) return null
|
|
43
53
|
const arches = []
|
|
44
54
|
for (let index = 0; index < count; index += 1) {
|
|
45
55
|
const offset = 8 + index * entrySize
|
|
46
|
-
if (offset + 4 > buffer.length) return null
|
|
47
56
|
const arch = MACHO_CPU.get(buffer.readUInt32BE(offset))
|
|
48
57
|
if (arch) arches.push(arch)
|
|
49
58
|
}
|
|
@@ -51,17 +60,26 @@ function machOFatArches(buffer) {
|
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
function elfArch(buffer) {
|
|
54
|
-
if (buffer.length <
|
|
55
|
-
|
|
56
|
-
const
|
|
63
|
+
if (buffer.length < 16 || buffer.readUInt32BE(0) !== 0x7f454c46) return null
|
|
64
|
+
const eiClass = buffer[4]
|
|
65
|
+
const eiData = buffer[5]
|
|
66
|
+
if (eiData !== 1 && eiData !== 2) return null
|
|
67
|
+
const headerSize = eiClass === 1 ? 52 : eiClass === 2 ? 64 : 0
|
|
68
|
+
if (!headerSize || buffer.length < headerSize) return null
|
|
69
|
+
const littleEndian = eiData === 1
|
|
57
70
|
const machine = littleEndian ? buffer.readUInt16LE(18) : buffer.readUInt16BE(18)
|
|
58
|
-
|
|
71
|
+
const arch = ELF_MACHINE.get(machine)
|
|
72
|
+
if (!arch) return null
|
|
73
|
+
const expectedClass = arch === 'ia32' ? 1 : 2
|
|
74
|
+
if (eiClass !== expectedClass) return null
|
|
75
|
+
return arch
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
function peArch(buffer) {
|
|
62
79
|
if (buffer.length < 64 || buffer.readUInt16LE(0) !== 0x5a4d) return null
|
|
63
80
|
const headerOffset = buffer.readUInt32LE(60)
|
|
64
|
-
|
|
81
|
+
// IMAGE_NT_HEADERS starts at e_lfanew: 4-byte PE signature + 20-byte COFF header.
|
|
82
|
+
if (headerOffset < 64 || headerOffset + 24 > buffer.length) return null
|
|
65
83
|
if (buffer.readUInt32LE(headerOffset) !== 0x00004550) return null
|
|
66
84
|
return PE_MACHINE.get(buffer.readUInt16LE(headerOffset + 4)) || null
|
|
67
85
|
}
|
|
@@ -83,11 +101,10 @@ export function nativeBinaryArch(buffer) {
|
|
|
83
101
|
}
|
|
84
102
|
|
|
85
103
|
/**
|
|
86
|
-
* True when the artifact can run on `arch`.
|
|
87
|
-
*
|
|
88
|
-
* cannot parse would fail builds over unrelated payloads.
|
|
104
|
+
* True when the artifact can run on `arch`. Unknown, truncated, or unsupported
|
|
105
|
+
* headers answer false so a wrong-arch or unreadable object cannot publish.
|
|
89
106
|
*/
|
|
90
107
|
export function nativeBinaryRunsOn(buffer, arch) {
|
|
91
108
|
const arches = nativeBinaryArches(buffer)
|
|
92
|
-
return arches
|
|
109
|
+
return Array.isArray(arches) && arches.includes(arch)
|
|
93
110
|
}
|
|
@@ -28,9 +28,10 @@ function machOFat(cpus) {
|
|
|
28
28
|
return buffer
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function elf(machine) {
|
|
32
|
-
const buffer = Buffer.alloc(
|
|
31
|
+
function elf(machine, { eiClass = 2 } = {}) {
|
|
32
|
+
const buffer = Buffer.alloc(eiClass === 1 ? 52 : 64)
|
|
33
33
|
buffer.writeUInt32BE(0x7f454c46, 0)
|
|
34
|
+
buffer[4] = eiClass
|
|
34
35
|
buffer[5] = 1
|
|
35
36
|
buffer.writeUInt16LE(machine, 18)
|
|
36
37
|
return buffer
|
|
@@ -60,16 +61,51 @@ test('universal binaries report every slice they carry', () => {
|
|
|
60
61
|
test('ELF and PE headers are read too', () => {
|
|
61
62
|
assert.equal(nativeBinaryArch(elf(0x3e)), 'x64')
|
|
62
63
|
assert.equal(nativeBinaryArch(elf(0xb7)), 'arm64')
|
|
64
|
+
assert.equal(nativeBinaryArch(elf(0x03, { eiClass: 1 })), 'ia32')
|
|
63
65
|
assert.equal(nativeBinaryArch(pe(0x8664)), 'x64')
|
|
64
66
|
assert.equal(nativeBinaryArch(pe(0xaa64)), 'arm64')
|
|
65
67
|
})
|
|
66
68
|
|
|
69
|
+
test('ELF class must match the named machine', () => {
|
|
70
|
+
assert.equal(nativeBinaryArch(elf(0x3e, { eiClass: 1 })), null)
|
|
71
|
+
assert.equal(nativeBinaryRunsOn(elf(0x3e, { eiClass: 1 }), 'x64'), false)
|
|
72
|
+
assert.equal(nativeBinaryArch(elf(0xb7, { eiClass: 1 })), null)
|
|
73
|
+
assert.equal(nativeBinaryArch(elf(0x03)), null)
|
|
74
|
+
})
|
|
75
|
+
|
|
67
76
|
test('a foreign architecture is rejected for the target', () => {
|
|
68
77
|
assert.equal(nativeBinaryRunsOn(machO({ cpu: 0x0100000c }), 'x64'), false)
|
|
69
78
|
assert.equal(nativeBinaryRunsOn(elf(0x3e), 'arm64'), false)
|
|
70
79
|
})
|
|
71
80
|
|
|
72
|
-
test('
|
|
81
|
+
test('unknown, truncated, or unsupported headers are not architecture-compatible', () => {
|
|
73
82
|
assert.equal(nativeBinaryArches(Buffer.from('#!/bin/sh\nexec node "$0"\n')), null)
|
|
74
|
-
assert.equal(nativeBinaryRunsOn(Buffer.alloc(4), 'x64'),
|
|
83
|
+
assert.equal(nativeBinaryRunsOn(Buffer.alloc(4), 'x64'), false)
|
|
84
|
+
assert.equal(nativeBinaryRunsOn(Buffer.from('#!/bin/sh\n'), 'arm64'), false)
|
|
85
|
+
assert.equal(nativeBinaryRunsOn(elf(0xf3), 'x64'), false)
|
|
86
|
+
|
|
87
|
+
const truncatedMachO = Buffer.alloc(8)
|
|
88
|
+
truncatedMachO.writeUInt32BE(0xcffaedfe, 0)
|
|
89
|
+
truncatedMachO.writeUInt32LE(0x01000007, 4)
|
|
90
|
+
assert.equal(nativeBinaryRunsOn(truncatedMachO, 'x64'), false)
|
|
91
|
+
|
|
92
|
+
const truncatedElf = Buffer.alloc(20)
|
|
93
|
+
truncatedElf.writeUInt32BE(0x7f454c46, 0)
|
|
94
|
+
truncatedElf[4] = 1
|
|
95
|
+
truncatedElf[5] = 1
|
|
96
|
+
truncatedElf.writeUInt16LE(0x3e, 18)
|
|
97
|
+
assert.equal(nativeBinaryRunsOn(truncatedElf, 'x64'), false)
|
|
98
|
+
|
|
99
|
+
const truncatedPe = Buffer.alloc(70)
|
|
100
|
+
truncatedPe.writeUInt16LE(0x5a4d, 0)
|
|
101
|
+
truncatedPe.writeUInt32LE(64, 60)
|
|
102
|
+
truncatedPe.writeUInt32LE(0x00004550, 64)
|
|
103
|
+
truncatedPe.writeUInt16LE(0x8664, 68)
|
|
104
|
+
assert.equal(nativeBinaryRunsOn(truncatedPe, 'x64'), false)
|
|
105
|
+
|
|
106
|
+
const truncatedFat = Buffer.alloc(12)
|
|
107
|
+
truncatedFat.writeUInt32BE(0xcafebabe, 0)
|
|
108
|
+
truncatedFat.writeUInt32BE(1, 4)
|
|
109
|
+
truncatedFat.writeUInt32BE(0x01000007, 8)
|
|
110
|
+
assert.equal(nativeBinaryRunsOn(truncatedFat, 'x64'), false)
|
|
75
111
|
})
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { appendFileSync } from 'node:fs'
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
import { resolve } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
VOICE_RUNTIME_CONFIG,
|
|
7
|
+
VOICE_RUNTIME_TAG,
|
|
8
|
+
assertVoiceRuntimeManifestIdentity,
|
|
9
|
+
compareSemver,
|
|
10
|
+
downloadReleaseAsset,
|
|
11
|
+
fetchGithubRelease,
|
|
12
|
+
sameVoiceRuntimeIdentity,
|
|
13
|
+
} from './generate-voice-runtime-manifest.mjs'
|
|
14
|
+
|
|
15
|
+
async function main() {
|
|
16
|
+
const repository = String(process.env.GITHUB_REPOSITORY || 'tribgames/mixdog')
|
|
17
|
+
const requestedTag = String(process.env.INPUT_TAG || '').trim()
|
|
18
|
+
if (requestedTag && requestedTag !== VOICE_RUNTIME_TAG) {
|
|
19
|
+
throw new Error(`voice runtime tag must be ${VOICE_RUNTIME_TAG}, got ${requestedTag}`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const bundledPath = resolve('src/runtime/channels/data/voice-runtime-manifest.json')
|
|
23
|
+
const bundled = JSON.parse(await readFile(bundledPath, 'utf8'))
|
|
24
|
+
if (compareSemver(bundled.version, VOICE_RUNTIME_CONFIG.runtimeVersion) > 0) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`refusing voice runtime downgrade from ${bundled.version} to ${VOICE_RUNTIME_CONFIG.runtimeVersion}`,
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const release = await fetchGithubRelease(repository, VOICE_RUNTIME_TAG, process.env.GITHUB_TOKEN, {
|
|
31
|
+
allowMissing: true,
|
|
32
|
+
})
|
|
33
|
+
let buildNeeded = true
|
|
34
|
+
let syncNeeded = true
|
|
35
|
+
let releaseState = 'missing'
|
|
36
|
+
|
|
37
|
+
if (release?.draft) {
|
|
38
|
+
releaseState = 'draft'
|
|
39
|
+
} else if (release) {
|
|
40
|
+
releaseState = 'published'
|
|
41
|
+
if (release.prerelease) throw new Error(`${VOICE_RUNTIME_TAG} must not be a prerelease`)
|
|
42
|
+
const manifestAsset = release.assets?.find((asset) => asset.name === 'voice-runtime-manifest.json')
|
|
43
|
+
if (!manifestAsset) {
|
|
44
|
+
throw new Error(`published ${VOICE_RUNTIME_TAG} has no voice-runtime-manifest.json`)
|
|
45
|
+
}
|
|
46
|
+
const released = JSON.parse(
|
|
47
|
+
(await downloadReleaseAsset(manifestAsset, process.env.GITHUB_TOKEN)).toString('utf8'),
|
|
48
|
+
)
|
|
49
|
+
await assertVoiceRuntimeManifestIdentity(released, { repository })
|
|
50
|
+
buildNeeded = false
|
|
51
|
+
syncNeeded = !sameVoiceRuntimeIdentity(bundled, released)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const values = {
|
|
55
|
+
tag: VOICE_RUNTIME_TAG,
|
|
56
|
+
version: VOICE_RUNTIME_CONFIG.runtimeVersion,
|
|
57
|
+
commit: VOICE_RUNTIME_CONFIG.whisperCommit,
|
|
58
|
+
vulkan_sdk_version: VOICE_RUNTIME_CONFIG.vulkanSdkVersion,
|
|
59
|
+
matrix: JSON.stringify(VOICE_RUNTIME_CONFIG.platforms),
|
|
60
|
+
build_needed: String(buildNeeded),
|
|
61
|
+
sync_needed: String(syncNeeded),
|
|
62
|
+
}
|
|
63
|
+
const output = process.env.GITHUB_OUTPUT
|
|
64
|
+
if (output) {
|
|
65
|
+
for (const [key, value] of Object.entries(values)) appendFileSync(output, `${key}=${value}\n`)
|
|
66
|
+
}
|
|
67
|
+
console.log(JSON.stringify({ release_state: releaseState, ...values }, null, 2))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
main().catch((error) => {
|
|
71
|
+
console.error(error?.stack || error)
|
|
72
|
+
process.exitCode = 1
|
|
73
|
+
})
|
|
@@ -22,17 +22,40 @@ import { ensureTokenAddon } from '../src/runtime/agent/orchestrator/tools/token-
|
|
|
22
22
|
|
|
23
23
|
const DEFAULT_PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
24
24
|
|
|
25
|
+
export const NATIVE_ASSET_PLATFORMS = Object.freeze([
|
|
26
|
+
'darwin-arm64',
|
|
27
|
+
'darwin-x64',
|
|
28
|
+
'linux-arm64',
|
|
29
|
+
'linux-x64',
|
|
30
|
+
'win32-x64',
|
|
31
|
+
]);
|
|
32
|
+
|
|
25
33
|
export const REQUIRED_NATIVE_INSTALLERS = Object.freeze({
|
|
26
34
|
graph: ensureGraphBinary,
|
|
27
35
|
patch: ensurePatchBinary,
|
|
28
36
|
spawn: ensureSpawnBinary,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const OPTIONAL_NATIVE_INSTALLERS = Object.freeze({
|
|
29
40
|
token: ensureTokenAddon,
|
|
30
41
|
});
|
|
31
42
|
|
|
43
|
+
export function nativeAssetPlatformKey(platform = process.platform, arch = process.arch) {
|
|
44
|
+
return `${platform}-${arch}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
32
47
|
export async function prepareRequiredNativeAssets({
|
|
33
48
|
packageRoot = DEFAULT_PACKAGE_ROOT,
|
|
34
|
-
installers = REQUIRED_NATIVE_INSTALLERS,
|
|
49
|
+
installers = { ...REQUIRED_NATIVE_INSTALLERS, ...OPTIONAL_NATIVE_INSTALLERS },
|
|
50
|
+
platform = process.platform,
|
|
51
|
+
arch = process.arch,
|
|
35
52
|
} = {}) {
|
|
53
|
+
const platformKey = nativeAssetPlatformKey(platform, arch);
|
|
54
|
+
if (!NATIVE_ASSET_PLATFORMS.includes(platformKey)) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`native assets are not published for ${platformKey}; supported: ${NATIVE_ASSET_PLATFORMS.join(', ')}`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
36
59
|
const root = resolve(String(packageRoot || ''));
|
|
37
60
|
const target = packageNativeToolsDir(root);
|
|
38
61
|
const stagingRoot = await mkdtemp(join(root, '.native-tools-install-'));
|
|
@@ -40,24 +63,42 @@ export async function prepareRequiredNativeAssets({
|
|
|
40
63
|
const stagedToolsDir = join(stagingRoot, 'native-tools');
|
|
41
64
|
try {
|
|
42
65
|
await mkdir(stagedToolsDir, { recursive: true });
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
const install = installers[name];
|
|
66
|
+
const installOne = async (name, fileName, { optional }) => {
|
|
67
|
+
const install = installers[name];
|
|
46
68
|
if (typeof install !== 'function') {
|
|
69
|
+
if (optional) {
|
|
70
|
+
console.warn(`[native-assets] optional ${name} skipped: installer is invalid`);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
47
73
|
throw new Error(`native asset installer is invalid: ${name}`);
|
|
48
74
|
}
|
|
75
|
+
try {
|
|
49
76
|
const installedPath = await install(downloadDataDir);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
77
|
+
if (typeof installedPath !== 'string' || installedPath.length === 0) {
|
|
78
|
+
throw new Error(`native asset installer returned no path: ${name}`);
|
|
79
|
+
}
|
|
53
80
|
const destination = join(stagedToolsDir, fileName);
|
|
54
81
|
await copyFile(installedPath, destination);
|
|
55
82
|
if (process.platform !== 'win32' && name !== 'token') {
|
|
56
83
|
await chmod(destination, 0o755);
|
|
57
84
|
}
|
|
58
85
|
return [name, join(target, fileName)];
|
|
59
|
-
})
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (!optional) throw error;
|
|
88
|
+
console.warn(`[native-assets] optional ${name} skipped: ${error?.message || error}`);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const requiredEntries = await Promise.all(
|
|
93
|
+
Object.keys(REQUIRED_NATIVE_INSTALLERS).map((name) => (
|
|
94
|
+
installOne(name, NATIVE_TOOL_FILENAMES[name], { optional: false })
|
|
95
|
+
)),
|
|
60
96
|
);
|
|
97
|
+
const optionalEntries = [];
|
|
98
|
+
for (const name of Object.keys(OPTIONAL_NATIVE_INSTALLERS)) {
|
|
99
|
+
const entry = await installOne(name, NATIVE_TOOL_FILENAMES[name], { optional: true });
|
|
100
|
+
if (entry) optionalEntries.push(entry);
|
|
101
|
+
}
|
|
61
102
|
await rm(target, {
|
|
62
103
|
recursive: true,
|
|
63
104
|
force: true,
|
|
@@ -65,7 +106,7 @@ export async function prepareRequiredNativeAssets({
|
|
|
65
106
|
retryDelay: 100,
|
|
66
107
|
});
|
|
67
108
|
await rename(stagedToolsDir, target);
|
|
68
|
-
return Object.fromEntries(
|
|
109
|
+
return Object.fromEntries([...requiredEntries, ...optionalEntries]);
|
|
69
110
|
} finally {
|
|
70
111
|
// Antivirus and process scanners can briefly retain freshly copied .exe
|
|
71
112
|
// handles on Windows. Cleanup must not replace the installer's real error
|
|
@@ -99,7 +99,7 @@ export async function pruneEmbeddingRuntime(packageRoot, options = {}) {
|
|
|
99
99
|
)))).find(Boolean)
|
|
100
100
|
if (!ortRoot) throw new Error('Embedding runtime is incomplete: onnxruntime-node is unavailable')
|
|
101
101
|
|
|
102
|
-
const targetBinaryDir = join(ortRoot, 'bin', 'napi-
|
|
102
|
+
const targetBinaryDir = join(ortRoot, 'bin', 'napi-v6', target.platform, target.arch)
|
|
103
103
|
if (!(await exists(join(targetBinaryDir, 'onnxruntime_binding.node')))) {
|
|
104
104
|
throw new Error(`Embedding runtime is incomplete: missing ${target.key} ONNX binding`)
|
|
105
105
|
}
|
|
@@ -118,9 +118,9 @@ export async function pruneEmbeddingRuntime(packageRoot, options = {}) {
|
|
|
118
118
|
]))
|
|
119
119
|
|
|
120
120
|
// onnxruntime-node resolves exactly:
|
|
121
|
-
// bin/napi-
|
|
121
|
+
// bin/napi-v6/${process.platform}/${process.arch}/onnxruntime_binding.node.
|
|
122
122
|
// Keep one native payload and remove every foreign OS/architecture.
|
|
123
|
-
const napiRoot = join(ortRoot, 'bin', 'napi-
|
|
123
|
+
const napiRoot = join(ortRoot, 'bin', 'napi-v6')
|
|
124
124
|
await removeChildrenExcept(napiRoot, new Set([target.platform]))
|
|
125
125
|
await removeChildrenExcept(join(napiRoot, target.platform), new Set([target.arch]))
|
|
126
126
|
await removeChildrenExcept(ortRoot, new Set([
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { pathToFileURL } from 'node:url'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
assertVoiceRuntimeManifestIdentity,
|
|
7
|
+
compareSemver,
|
|
8
|
+
} from './generate-voice-runtime-manifest.mjs'
|
|
9
|
+
|
|
10
|
+
export async function mergeVoiceRuntimeManifest(current, released, options = {}) {
|
|
11
|
+
await assertVoiceRuntimeManifestIdentity(released, options)
|
|
12
|
+
if (compareSemver(current.version, released.version) > 0) {
|
|
13
|
+
throw new Error(`refusing voice runtime manifest downgrade from ${current.version} to ${released.version}`)
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
...current,
|
|
17
|
+
version: released.version,
|
|
18
|
+
source: released.source,
|
|
19
|
+
release_tag: released.release_tag,
|
|
20
|
+
build_hash: released.build_hash,
|
|
21
|
+
platforms: released.platforms,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function main() {
|
|
26
|
+
const releasedPath = resolve(process.argv[2] || 'dist/voice-runtime-manifest.json')
|
|
27
|
+
const bundledPath = resolve(
|
|
28
|
+
process.argv[3] || 'src/runtime/channels/data/voice-runtime-manifest.json',
|
|
29
|
+
)
|
|
30
|
+
const [released, current] = await Promise.all([
|
|
31
|
+
readFile(releasedPath, 'utf8').then(JSON.parse),
|
|
32
|
+
readFile(bundledPath, 'utf8').then(JSON.parse),
|
|
33
|
+
])
|
|
34
|
+
const repository = String(process.env.GITHUB_REPOSITORY || 'tribgames/mixdog')
|
|
35
|
+
const merged = await mergeVoiceRuntimeManifest(current, released, { repository })
|
|
36
|
+
await writeFile(bundledPath, `${JSON.stringify(merged, null, 2)}\n`)
|
|
37
|
+
console.log(`synchronized ${bundledPath} from ${releasedPath}`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const invokedPath = process.argv[1] ? pathToFileURL(resolve(process.argv[1])).href : ''
|
|
41
|
+
if (invokedPath === import.meta.url) {
|
|
42
|
+
main().catch((error) => {
|
|
43
|
+
console.error(error?.stack || error)
|
|
44
|
+
process.exitCode = 1
|
|
45
|
+
})
|
|
46
|
+
}
|