@wenathlan/saddle 1.8.17 → 2.0.2
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/Dockerfile +1339 -0
- package/README.md +68 -22
- package/alternatives.ts +1218 -0
- package/biome.json +153 -0
- package/boards.json +1517 -0
- package/compute.ts +3144 -0
- package/cores.json +1801 -0
- package/dist/acquisition.d.ts +359 -0
- package/dist/acquisition.d.ts.map +1 -0
- package/dist/acquisition.js +629 -0
- package/dist/acquisition.js.map +1 -0
- package/dist/alternatives.d.ts +509 -0
- package/dist/alternatives.d.ts.map +1 -0
- package/dist/alternatives.js +951 -0
- package/dist/alternatives.js.map +1 -0
- package/dist/automation.d.ts +426 -0
- package/dist/automation.d.ts.map +1 -0
- package/dist/automation.js +561 -0
- package/dist/automation.js.map +1 -0
- package/dist/browser.d.ts +562 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +1057 -0
- package/dist/browser.js.map +1 -0
- package/dist/capacitor.config.d.ts +13 -0
- package/dist/capacitor.config.d.ts.map +1 -0
- package/dist/capacitor.config.js +26 -0
- package/dist/capacitor.config.js.map +1 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +111 -0
- package/dist/cli.js.map +1 -0
- package/dist/communication.d.ts +192 -0
- package/dist/communication.d.ts.map +1 -0
- package/dist/communication.js +418 -0
- package/dist/communication.js.map +1 -0
- package/dist/compute.d.ts +1161 -0
- package/dist/compute.d.ts.map +1 -0
- package/dist/compute.js +2273 -0
- package/dist/compute.js.map +1 -0
- package/dist/distribution.d.ts +529 -0
- package/dist/distribution.d.ts.map +1 -0
- package/dist/distribution.js +811 -0
- package/dist/distribution.js.map +1 -0
- package/dist/execution.d.ts +530 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +761 -0
- package/dist/execution.js.map +1 -0
- package/dist/format.d.ts +19 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +60 -0
- package/dist/format.js.map +1 -0
- package/dist/foundation.d.ts +176 -0
- package/dist/foundation.d.ts.map +1 -0
- package/dist/foundation.js +309 -0
- package/dist/foundation.js.map +1 -0
- package/dist/index.d.ts +733 -122
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1018 -122
- package/dist/index.js.map +1 -1
- package/dist/integration.d.ts +236 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +236 -0
- package/dist/integration.js.map +1 -0
- package/dist/intelligence.d.ts +94 -0
- package/dist/intelligence.d.ts.map +1 -0
- package/dist/intelligence.js +145 -0
- package/dist/intelligence.js.map +1 -0
- package/dist/isolation.d.ts +129 -0
- package/dist/isolation.d.ts.map +1 -0
- package/dist/isolation.js +96 -0
- package/dist/isolation.js.map +1 -0
- package/dist/media.d.ts +344 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +986 -0
- package/dist/media.js.map +1 -0
- package/dist/modes.d.ts +359 -0
- package/dist/modes.d.ts.map +1 -0
- package/dist/modes.js +134 -0
- package/dist/modes.js.map +1 -0
- package/dist/{library/public.d.ts → operations.d.ts} +15 -1
- package/dist/operations.d.ts.map +1 -0
- package/dist/{library/public.js → operations.js} +18 -7
- package/dist/operations.js.map +1 -0
- package/dist/orchestrator.d.ts +1339 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +4308 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/performance.d.ts +416 -0
- package/dist/performance.d.ts.map +1 -0
- package/dist/performance.js +827 -0
- package/dist/performance.js.map +1 -0
- package/dist/quantum.d.ts +810 -0
- package/dist/quantum.d.ts.map +1 -0
- package/dist/quantum.js +2073 -0
- package/dist/quantum.js.map +1 -0
- package/dist/render.d.ts +381 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +1073 -0
- package/dist/render.js.map +1 -0
- package/dist/scheduler.d.ts +596 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +1259 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/security.d.ts +501 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +1170 -0
- package/dist/security.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/{server/node.js → server.js} +16 -2
- package/dist/server.js.map +1 -0
- package/dist/tiers.d.ts +1002 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +2165 -0
- package/dist/tiers.js.map +1 -0
- package/dist/virtual.d.ts +641 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +1285 -0
- package/dist/virtual.js.map +1 -0
- package/dist/virtualcpu.d.ts +316 -0
- package/dist/virtualcpu.d.ts.map +1 -0
- package/dist/virtualcpu.js +1180 -0
- package/dist/virtualcpu.js.map +1 -0
- package/dist/virtualgpu.d.ts +345 -0
- package/dist/virtualgpu.d.ts.map +1 -0
- package/dist/virtualgpu.js +1000 -0
- package/dist/virtualgpu.js.map +1 -0
- package/dist/virtualization.d.ts +607 -0
- package/dist/virtualization.d.ts.map +1 -0
- package/dist/virtualization.js +1187 -0
- package/dist/virtualization.js.map +1 -0
- package/dist/virtualmemory.d.ts +818 -0
- package/dist/virtualmemory.d.ts.map +1 -0
- package/dist/virtualmemory.js +1796 -0
- package/dist/virtualmemory.js.map +1 -0
- package/dist/webscrape.d.ts +720 -0
- package/dist/webscrape.d.ts.map +1 -0
- package/dist/webscrape.js +2697 -0
- package/dist/webscrape.js.map +1 -0
- package/docker.config +769 -0
- package/docs/CONVERSA.txt +1523 -0
- package/docs/alternatives.md +499 -0
- package/docs/architecture-1.8.19.md +76 -0
- package/docs/architecture-1.8.19.mmd +33 -0
- package/docs/architecture-1.8.19.png +0 -0
- package/docs/architecture.md +355 -0
- package/docs/artifactavailability.md +6 -0
- package/docs/brancharchive-2026-08-18.md +18 -0
- package/docs/browser.md +7 -0
- package/docs/consolidation.md +70 -0
- package/docs/e2ugh-engine.md +528 -0
- package/{dist/examples/localjob.js → docs/example-localjob.ts} +3 -3
- package/{dist/examples/publicapi.js → docs/example-publicapi.ts} +2 -2
- package/docs/hardware.md +342 -0
- package/docs/optimization.md +126 -0
- package/docs/performance.md +499 -0
- package/docs/planning.1.8.18.md +94 -0
- package/docs/planning.1.8.19.md +49 -0
- package/docs/releasenotes-1.8.17.md +6 -0
- package/docs/releasenotes-1.8.18.md +32 -0
- package/docs/releasenotes-1.8.19.md +35 -0
- package/docs/research-1.8.18-isolation.md +43 -0
- package/docs/research-1.8.19-virtual-browser.md +27 -0
- package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
- package/docs/security.md +454 -0
- package/docs/todo-1.8.16.md +56 -1
- package/docs/todo-1.8.18.md +164 -0
- package/docs/todo-1.8.19.md +241 -0
- package/docs/viability.md +777 -0
- package/docs/virtualization.md +335 -0
- package/docs/web-duplicatecleanup.md +9 -0
- package/docs/web-ideas.md +106 -0
- package/docs/workflowimprovements-2026-08-19.md +70 -0
- package/gpumonitor.cpp +1543 -0
- package/gpus.json +2408 -0
- package/index.ts +1478 -0
- package/media.ts +1337 -0
- package/mttg.config +1549 -0
- package/orchestrator.ts +5462 -0
- package/package.json +304 -55
- package/passage.config +1331 -0
- package/performance.ts +1049 -0
- package/processors.json +2217 -0
- package/qemu.config +1062 -0
- package/qemubridge.py +1340 -0
- package/quantum.ts +2393 -0
- package/render.ts +1325 -0
- package/scheduler.ts +1600 -0
- package/security.ts +1449 -0
- package/tiers.ts +2871 -0
- package/tsconfig.json +29 -0
- package/virtualcpu.ts +1273 -0
- package/virtualgpu.ts +1181 -0
- package/virtualhardware.c +1011 -0
- package/virtualhardware.json +739 -0
- package/virtualization.ts +1628 -0
- package/virtualizationcore.cpp +4635 -0
- package/virtualmemory.ts +2303 -0
- package/vm.config.json +1910 -0
- package/{extension → web/extension}/manifest.json +1 -1
- package/web/readme.md +382 -0
- package/web/tsconfig.json +25 -0
- package/dist/adapters/forge.d.ts +0 -17
- package/dist/adapters/forge.d.ts.map +0 -1
- package/dist/adapters/forge.js +0 -19
- package/dist/adapters/forge.js.map +0 -1
- package/dist/adapters/forgejo.d.ts +0 -49
- package/dist/adapters/forgejo.d.ts.map +0 -1
- package/dist/adapters/forgejo.js +0 -8
- package/dist/adapters/forgejo.js.map +0 -1
- package/dist/adapters/github.d.ts +0 -12
- package/dist/adapters/github.d.ts.map +0 -1
- package/dist/adapters/github.js +0 -20
- package/dist/adapters/github.js.map +0 -1
- package/dist/adapters/gitlab.d.ts +0 -17
- package/dist/adapters/gitlab.d.ts.map +0 -1
- package/dist/adapters/gitlab.js +0 -10
- package/dist/adapters/gitlab.js.map +0 -1
- package/dist/adapters/huggingface.d.ts +0 -17
- package/dist/adapters/huggingface.d.ts.map +0 -1
- package/dist/adapters/huggingface.js +0 -6
- package/dist/adapters/huggingface.js.map +0 -1
- package/dist/adapters/socket.d.ts +0 -11
- package/dist/adapters/socket.d.ts.map +0 -1
- package/dist/adapters/socket.js +0 -17
- package/dist/adapters/socket.js.map +0 -1
- package/dist/adapters/transport.d.ts +0 -7
- package/dist/adapters/transport.d.ts.map +0 -1
- package/dist/adapters/transport.js +0 -36
- package/dist/adapters/transport.js.map +0 -1
- package/dist/ai/chunk.d.ts +0 -2
- package/dist/ai/chunk.d.ts.map +0 -1
- package/dist/ai/chunk.js +0 -36
- package/dist/ai/chunk.js.map +0 -1
- package/dist/ai/llmstxt.d.ts +0 -6
- package/dist/ai/llmstxt.d.ts.map +0 -1
- package/dist/ai/llmstxt.js +0 -12
- package/dist/ai/llmstxt.js.map +0 -1
- package/dist/ai/provenance.d.ts +0 -22
- package/dist/ai/provenance.d.ts.map +0 -1
- package/dist/ai/provenance.js +0 -25
- package/dist/ai/provenance.js.map +0 -1
- package/dist/ai/rag.d.ts +0 -26
- package/dist/ai/rag.d.ts.map +0 -1
- package/dist/ai/rag.js +0 -22
- package/dist/ai/rag.js.map +0 -1
- package/dist/ai/tokens.d.ts +0 -15
- package/dist/ai/tokens.d.ts.map +0 -1
- package/dist/ai/tokens.js +0 -9
- package/dist/ai/tokens.js.map +0 -1
- package/dist/api/auth.d.ts +0 -16
- package/dist/api/auth.d.ts.map +0 -1
- package/dist/api/auth.js +0 -19
- package/dist/api/auth.js.map +0 -1
- package/dist/api/contracts.d.ts +0 -28
- package/dist/api/contracts.d.ts.map +0 -1
- package/dist/api/contracts.js +0 -14
- package/dist/api/contracts.js.map +0 -1
- package/dist/api/control.d.ts +0 -10
- package/dist/api/control.d.ts.map +0 -1
- package/dist/api/control.js +0 -35
- package/dist/api/control.js.map +0 -1
- package/dist/api/http.d.ts +0 -7
- package/dist/api/http.d.ts.map +0 -1
- package/dist/api/http.js +0 -12
- package/dist/api/http.js.map +0 -1
- package/dist/api/rate.d.ts +0 -28
- package/dist/api/rate.d.ts.map +0 -1
- package/dist/api/rate.js +0 -36
- package/dist/api/rate.js.map +0 -1
- package/dist/api/security.d.ts +0 -12
- package/dist/api/security.d.ts.map +0 -1
- package/dist/api/security.js +0 -56
- package/dist/api/security.js.map +0 -1
- package/dist/api/service.d.ts +0 -5
- package/dist/api/service.d.ts.map +0 -1
- package/dist/api/service.js +0 -70
- package/dist/api/service.js.map +0 -1
- package/dist/apps/registry.d.ts +0 -33
- package/dist/apps/registry.d.ts.map +0 -1
- package/dist/apps/registry.js +0 -24
- package/dist/apps/registry.js.map +0 -1
- package/dist/binary/archive.d.ts +0 -27
- package/dist/binary/archive.d.ts.map +0 -1
- package/dist/binary/archive.js +0 -46
- package/dist/binary/archive.js.map +0 -1
- package/dist/binary/build.d.ts +0 -29
- package/dist/binary/build.d.ts.map +0 -1
- package/dist/binary/build.js +0 -17
- package/dist/binary/build.js.map +0 -1
- package/dist/binary/transform.d.ts +0 -70
- package/dist/binary/transform.d.ts.map +0 -1
- package/dist/binary/transform.js +0 -105
- package/dist/binary/transform.js.map +0 -1
- package/dist/bot/adapter.d.ts +0 -5
- package/dist/bot/adapter.d.ts.map +0 -1
- package/dist/bot/adapter.js +0 -11
- package/dist/bot/adapter.js.map +0 -1
- package/dist/bot/bot.d.ts +0 -28
- package/dist/bot/bot.d.ts.map +0 -1
- package/dist/bot/bot.js +0 -52
- package/dist/bot/bot.js.map +0 -1
- package/dist/bot/commands.d.ts +0 -8
- package/dist/bot/commands.d.ts.map +0 -1
- package/dist/bot/commands.js +0 -19
- package/dist/bot/commands.js.map +0 -1
- package/dist/bot/permissions.d.ts +0 -13
- package/dist/bot/permissions.d.ts.map +0 -1
- package/dist/bot/permissions.js +0 -16
- package/dist/bot/permissions.js.map +0 -1
- package/dist/browser/actions.d.ts +0 -33
- package/dist/browser/actions.d.ts.map +0 -1
- package/dist/browser/actions.js +0 -44
- package/dist/browser/actions.js.map +0 -1
- package/dist/browser/agent.d.ts +0 -21
- package/dist/browser/agent.d.ts.map +0 -1
- package/dist/browser/agent.js +0 -13
- package/dist/browser/agent.js.map +0 -1
- package/dist/browser/context.d.ts +0 -43
- package/dist/browser/context.d.ts.map +0 -1
- package/dist/browser/context.js +0 -54
- package/dist/browser/context.js.map +0 -1
- package/dist/browser/fingerprint.d.ts +0 -4
- package/dist/browser/fingerprint.d.ts.map +0 -1
- package/dist/browser/fingerprint.js +0 -12
- package/dist/browser/fingerprint.js.map +0 -1
- package/dist/browser/index.d.ts +0 -11
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/index.js +0 -11
- package/dist/browser/index.js.map +0 -1
- package/dist/browser/playwright.d.ts +0 -11
- package/dist/browser/playwright.d.ts.map +0 -1
- package/dist/browser/playwright.js +0 -24
- package/dist/browser/playwright.js.map +0 -1
- package/dist/browser/recorder.d.ts +0 -21
- package/dist/browser/recorder.d.ts.map +0 -1
- package/dist/browser/recorder.js +0 -58
- package/dist/browser/recorder.js.map +0 -1
- package/dist/browser/session.d.ts +0 -14
- package/dist/browser/session.d.ts.map +0 -1
- package/dist/browser/session.js +0 -21
- package/dist/browser/session.js.map +0 -1
- package/dist/browser/snapshot.d.ts +0 -69
- package/dist/browser/snapshot.d.ts.map +0 -1
- package/dist/browser/snapshot.js +0 -133
- package/dist/browser/snapshot.js.map +0 -1
- package/dist/captcha/contract.d.ts +0 -35
- package/dist/captcha/contract.d.ts.map +0 -1
- package/dist/captcha/contract.js +0 -17
- package/dist/captcha/contract.js.map +0 -1
- package/dist/captcha/evidence.d.ts +0 -10
- package/dist/captcha/evidence.d.ts.map +0 -1
- package/dist/captcha/evidence.js +0 -9
- package/dist/captcha/evidence.js.map +0 -1
- package/dist/captcha/guard.d.ts +0 -23
- package/dist/captcha/guard.d.ts.map +0 -1
- package/dist/captcha/guard.js +0 -12
- package/dist/captcha/guard.js.map +0 -1
- package/dist/cli/main.d.ts +0 -4
- package/dist/cli/main.d.ts.map +0 -1
- package/dist/cli/main.js +0 -46
- package/dist/cli/main.js.map +0 -1
- package/dist/core/errors.d.ts +0 -84
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/errors.js +0 -54
- package/dist/core/errors.js.map +0 -1
- package/dist/core/events.d.ts +0 -9
- package/dist/core/events.d.ts.map +0 -1
- package/dist/core/events.js +0 -21
- package/dist/core/events.js.map +0 -1
- package/dist/core/hash.d.ts +0 -10
- package/dist/core/hash.d.ts.map +0 -1
- package/dist/core/hash.js +0 -82
- package/dist/core/hash.js.map +0 -1
- package/dist/core/ids.d.ts +0 -10
- package/dist/core/ids.d.ts.map +0 -1
- package/dist/core/ids.js +0 -15
- package/dist/core/ids.js.map +0 -1
- package/dist/delivery/manifest.d.ts +0 -35
- package/dist/delivery/manifest.d.ts.map +0 -1
- package/dist/delivery/manifest.js +0 -68
- package/dist/delivery/manifest.js.map +0 -1
- package/dist/deploy/index.d.ts +0 -6
- package/dist/deploy/index.d.ts.map +0 -1
- package/dist/deploy/index.js +0 -6
- package/dist/deploy/index.js.map +0 -1
- package/dist/dispatch/resumable.d.ts +0 -102
- package/dist/dispatch/resumable.d.ts.map +0 -1
- package/dist/dispatch/resumable.js +0 -64
- package/dist/dispatch/resumable.js.map +0 -1
- package/dist/dispatch/workflow.d.ts +0 -6
- package/dist/dispatch/workflow.d.ts.map +0 -1
- package/dist/dispatch/workflow.js +0 -37
- package/dist/dispatch/workflow.js.map +0 -1
- package/dist/domain/artifacts.d.ts +0 -12
- package/dist/domain/artifacts.d.ts.map +0 -1
- package/dist/domain/artifacts.js +0 -14
- package/dist/domain/artifacts.js.map +0 -1
- package/dist/domain/jobs.d.ts +0 -12
- package/dist/domain/jobs.d.ts.map +0 -1
- package/dist/domain/jobs.js +0 -20
- package/dist/domain/jobs.js.map +0 -1
- package/dist/domain/providers.d.ts +0 -10
- package/dist/domain/providers.d.ts.map +0 -1
- package/dist/domain/providers.js +0 -8
- package/dist/domain/providers.js.map +0 -1
- package/dist/domain/runtime.d.ts +0 -14
- package/dist/domain/runtime.d.ts.map +0 -1
- package/dist/domain/runtime.js +0 -10
- package/dist/domain/runtime.js.map +0 -1
- package/dist/domain/sessions.d.ts +0 -12
- package/dist/domain/sessions.d.ts.map +0 -1
- package/dist/domain/sessions.js +0 -57
- package/dist/domain/sessions.js.map +0 -1
- package/dist/examples/localjob.d.ts +0 -2
- package/dist/examples/localjob.d.ts.map +0 -1
- package/dist/examples/localjob.js.map +0 -1
- package/dist/examples/publicapi.d.ts +0 -2
- package/dist/examples/publicapi.d.ts.map +0 -1
- package/dist/examples/publicapi.js.map +0 -1
- package/dist/extension/build.d.ts +0 -9
- package/dist/extension/build.d.ts.map +0 -1
- package/dist/extension/build.js +0 -85
- package/dist/extension/build.js.map +0 -1
- package/dist/extension/content.d.ts +0 -6
- package/dist/extension/content.d.ts.map +0 -1
- package/dist/extension/content.js +0 -135
- package/dist/extension/content.js.map +0 -1
- package/dist/extension/index.d.ts +0 -7
- package/dist/extension/index.d.ts.map +0 -1
- package/dist/extension/index.js +0 -7
- package/dist/extension/index.js.map +0 -1
- package/dist/extension/pagebridge.d.ts +0 -6
- package/dist/extension/pagebridge.d.ts.map +0 -1
- package/dist/extension/pagebridge.js +0 -42
- package/dist/extension/pagebridge.js.map +0 -1
- package/dist/extension/permissions.d.ts +0 -26
- package/dist/extension/permissions.d.ts.map +0 -1
- package/dist/extension/permissions.js +0 -28
- package/dist/extension/permissions.js.map +0 -1
- package/dist/extension/popup.d.ts +0 -5
- package/dist/extension/popup.d.ts.map +0 -1
- package/dist/extension/popup.js +0 -26
- package/dist/extension/popup.js.map +0 -1
- package/dist/extension/protocol.d.ts +0 -58
- package/dist/extension/protocol.d.ts.map +0 -1
- package/dist/extension/protocol.js +0 -101
- package/dist/extension/protocol.js.map +0 -1
- package/dist/extension/serviceworker.d.ts +0 -25
- package/dist/extension/serviceworker.d.ts.map +0 -1
- package/dist/extension/serviceworker.js +0 -102
- package/dist/extension/serviceworker.js.map +0 -1
- package/dist/extension/worker.d.ts +0 -28
- package/dist/extension/worker.d.ts.map +0 -1
- package/dist/extension/worker.js +0 -22
- package/dist/extension/worker.js.map +0 -1
- package/dist/format/check.d.ts +0 -8
- package/dist/format/check.d.ts.map +0 -1
- package/dist/format/check.js +0 -38
- package/dist/format/check.js.map +0 -1
- package/dist/library/public.d.ts.map +0 -1
- package/dist/library/public.js.map +0 -1
- package/dist/mcp/browser.d.ts +0 -9
- package/dist/mcp/browser.d.ts.map +0 -1
- package/dist/mcp/browser.js +0 -13
- package/dist/mcp/browser.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -35
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -40
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/transport.d.ts +0 -7
- package/dist/mcp/transport.d.ts.map +0 -1
- package/dist/mcp/transport.js +0 -17
- package/dist/mcp/transport.js.map +0 -1
- package/dist/memory/bridge.d.ts +0 -14
- package/dist/memory/bridge.d.ts.map +0 -1
- package/dist/memory/bridge.js +0 -16
- package/dist/memory/bridge.js.map +0 -1
- package/dist/memory/engine.d.ts +0 -38
- package/dist/memory/engine.d.ts.map +0 -1
- package/dist/memory/engine.js +0 -109
- package/dist/memory/engine.js.map +0 -1
- package/dist/memory/modes.d.ts +0 -43
- package/dist/memory/modes.d.ts.map +0 -1
- package/dist/memory/modes.js +0 -66
- package/dist/memory/modes.js.map +0 -1
- package/dist/memory/objects.d.ts +0 -21
- package/dist/memory/objects.d.ts.map +0 -1
- package/dist/memory/objects.js +0 -20
- package/dist/memory/objects.js.map +0 -1
- package/dist/memory/planner.d.ts +0 -66
- package/dist/memory/planner.d.ts.map +0 -1
- package/dist/memory/planner.js +0 -108
- package/dist/memory/planner.js.map +0 -1
- package/dist/memory/targets.d.ts +0 -78
- package/dist/memory/targets.d.ts.map +0 -1
- package/dist/memory/targets.js +0 -29
- package/dist/memory/targets.js.map +0 -1
- package/dist/memory/transforms.d.ts +0 -19
- package/dist/memory/transforms.d.ts.map +0 -1
- package/dist/memory/transforms.js +0 -14
- package/dist/memory/transforms.js.map +0 -1
- package/dist/modes/matrix.d.ts +0 -23
- package/dist/modes/matrix.d.ts.map +0 -1
- package/dist/modes/matrix.js +0 -18
- package/dist/modes/matrix.js.map +0 -1
- package/dist/modes/modes.d.ts +0 -33
- package/dist/modes/modes.d.ts.map +0 -1
- package/dist/modes/modes.js +0 -15
- package/dist/modes/modes.js.map +0 -1
- package/dist/modes/resolve.d.ts +0 -96
- package/dist/modes/resolve.d.ts.map +0 -1
- package/dist/modes/resolve.js +0 -48
- package/dist/modes/resolve.js.map +0 -1
- package/dist/observability/metrics.d.ts +0 -14
- package/dist/observability/metrics.d.ts.map +0 -1
- package/dist/observability/metrics.js +0 -18
- package/dist/observability/metrics.js.map +0 -1
- package/dist/packager/manifest.d.ts +0 -66
- package/dist/packager/manifest.d.ts.map +0 -1
- package/dist/packager/manifest.js +0 -94
- package/dist/packager/manifest.js.map +0 -1
- package/dist/packager/publish.d.ts +0 -51
- package/dist/packager/publish.d.ts.map +0 -1
- package/dist/packager/publish.js +0 -18
- package/dist/packager/publish.js.map +0 -1
- package/dist/packager/targetcli.d.ts +0 -7
- package/dist/packager/targetcli.d.ts.map +0 -1
- package/dist/packager/targetcli.js +0 -22
- package/dist/packager/targetcli.js.map +0 -1
- package/dist/persistence/adapter.d.ts +0 -5
- package/dist/persistence/adapter.d.ts.map +0 -1
- package/dist/persistence/adapter.js +0 -11
- package/dist/persistence/adapter.js.map +0 -1
- package/dist/persistence/drizzle.d.ts +0 -2
- package/dist/persistence/drizzle.d.ts.map +0 -1
- package/dist/persistence/drizzle.js +0 -12
- package/dist/persistence/drizzle.js.map +0 -1
- package/dist/persistence/memory.d.ts +0 -2
- package/dist/persistence/memory.d.ts.map +0 -1
- package/dist/persistence/memory.js +0 -27
- package/dist/persistence/memory.js.map +0 -1
- package/dist/persistence/migrations.d.ts +0 -19
- package/dist/persistence/migrations.d.ts.map +0 -1
- package/dist/persistence/migrations.js +0 -13
- package/dist/persistence/migrations.js.map +0 -1
- package/dist/persistence/prisma.d.ts +0 -2
- package/dist/persistence/prisma.d.ts.map +0 -1
- package/dist/persistence/prisma.js +0 -25
- package/dist/persistence/prisma.js.map +0 -1
- package/dist/persistence/schema.d.ts +0 -63
- package/dist/persistence/schema.d.ts.map +0 -1
- package/dist/persistence/schema.js +0 -28
- package/dist/persistence/schema.js.map +0 -1
- package/dist/persistence/sql.d.ts +0 -3
- package/dist/persistence/sql.d.ts.map +0 -1
- package/dist/persistence/sql.js +0 -37
- package/dist/persistence/sql.js.map +0 -1
- package/dist/protocol/blocks.d.ts +0 -10
- package/dist/protocol/blocks.d.ts.map +0 -1
- package/dist/protocol/blocks.js +0 -26
- package/dist/protocol/blocks.js.map +0 -1
- package/dist/protocol/json.d.ts +0 -6
- package/dist/protocol/json.d.ts.map +0 -1
- package/dist/protocol/json.js +0 -6
- package/dist/protocol/json.js.map +0 -1
- package/dist/protocol/ndjson.d.ts +0 -3
- package/dist/protocol/ndjson.d.ts.map +0 -1
- package/dist/protocol/ndjson.js +0 -20
- package/dist/protocol/ndjson.js.map +0 -1
- package/dist/protocol/sse.d.ts +0 -7
- package/dist/protocol/sse.d.ts.map +0 -1
- package/dist/protocol/sse.js +0 -25
- package/dist/protocol/sse.js.map +0 -1
- package/dist/proxy/pool.d.ts +0 -9
- package/dist/proxy/pool.d.ts.map +0 -1
- package/dist/proxy/pool.js +0 -27
- package/dist/proxy/pool.js.map +0 -1
- package/dist/queue/idempotency.d.ts +0 -10
- package/dist/queue/idempotency.d.ts.map +0 -1
- package/dist/queue/idempotency.js +0 -13
- package/dist/queue/idempotency.js.map +0 -1
- package/dist/queue/persistent.d.ts +0 -14
- package/dist/queue/persistent.d.ts.map +0 -1
- package/dist/queue/persistent.js +0 -66
- package/dist/queue/persistent.js.map +0 -1
- package/dist/queue/queue.d.ts +0 -7
- package/dist/queue/queue.d.ts.map +0 -1
- package/dist/queue/queue.js +0 -55
- package/dist/queue/queue.js.map +0 -1
- package/dist/queue/saga.d.ts +0 -5
- package/dist/queue/saga.d.ts.map +0 -1
- package/dist/queue/saga.js +0 -20
- package/dist/queue/saga.js.map +0 -1
- package/dist/release/assets.d.ts +0 -144
- package/dist/release/assets.d.ts.map +0 -1
- package/dist/release/assets.js +0 -157
- package/dist/release/assets.js.map +0 -1
- package/dist/release/evidence.d.ts +0 -92
- package/dist/release/evidence.d.ts.map +0 -1
- package/dist/release/evidence.js +0 -148
- package/dist/release/evidence.js.map +0 -1
- package/dist/release/verify.d.ts +0 -12
- package/dist/release/verify.d.ts.map +0 -1
- package/dist/release/verify.js +0 -112
- package/dist/release/verify.js.map +0 -1
- package/dist/runners/chain.d.ts +0 -125
- package/dist/runners/chain.d.ts.map +0 -1
- package/dist/runners/chain.js +0 -95
- package/dist/runners/chain.js.map +0 -1
- package/dist/runners/health.d.ts +0 -36
- package/dist/runners/health.d.ts.map +0 -1
- package/dist/runners/health.js +0 -26
- package/dist/runners/health.js.map +0 -1
- package/dist/runners/heartbeat.d.ts +0 -23
- package/dist/runners/heartbeat.d.ts.map +0 -1
- package/dist/runners/heartbeat.js +0 -29
- package/dist/runners/heartbeat.js.map +0 -1
- package/dist/runners/inprocess.d.ts +0 -17
- package/dist/runners/inprocess.d.ts.map +0 -1
- package/dist/runners/inprocess.js +0 -20
- package/dist/runners/inprocess.js.map +0 -1
- package/dist/runners/scheduler.d.ts +0 -5
- package/dist/runners/scheduler.d.ts.map +0 -1
- package/dist/runners/scheduler.js +0 -19
- package/dist/runners/scheduler.js.map +0 -1
- package/dist/runtime/abort.d.ts +0 -8
- package/dist/runtime/abort.d.ts.map +0 -1
- package/dist/runtime/abort.js +0 -13
- package/dist/runtime/abort.js.map +0 -1
- package/dist/runtime/compatibility.d.ts +0 -37
- package/dist/runtime/compatibility.d.ts.map +0 -1
- package/dist/runtime/compatibility.js +0 -10
- package/dist/runtime/compatibility.js.map +0 -1
- package/dist/runtime/detect.d.ts +0 -13
- package/dist/runtime/detect.d.ts.map +0 -1
- package/dist/runtime/detect.js +0 -18
- package/dist/runtime/detect.js.map +0 -1
- package/dist/runtime/engine.d.ts +0 -20
- package/dist/runtime/engine.d.ts.map +0 -1
- package/dist/runtime/engine.js +0 -61
- package/dist/runtime/engine.js.map +0 -1
- package/dist/runtime/retry.d.ts +0 -19
- package/dist/runtime/retry.d.ts.map +0 -1
- package/dist/runtime/retry.js +0 -54
- package/dist/runtime/retry.js.map +0 -1
- package/dist/runtime/worker.d.ts +0 -10
- package/dist/runtime/worker.d.ts.map +0 -1
- package/dist/runtime/worker.js +0 -25
- package/dist/runtime/worker.js.map +0 -1
- package/dist/scrape/cache.d.ts +0 -45
- package/dist/scrape/cache.d.ts.map +0 -1
- package/dist/scrape/cache.js +0 -45
- package/dist/scrape/cache.js.map +0 -1
- package/dist/scrape/crawl.d.ts +0 -47
- package/dist/scrape/crawl.d.ts.map +0 -1
- package/dist/scrape/crawl.js +0 -114
- package/dist/scrape/crawl.js.map +0 -1
- package/dist/scrape/extract.d.ts +0 -63
- package/dist/scrape/extract.d.ts.map +0 -1
- package/dist/scrape/extract.js +0 -47
- package/dist/scrape/extract.js.map +0 -1
- package/dist/scrape/normalize.d.ts +0 -52
- package/dist/scrape/normalize.d.ts.map +0 -1
- package/dist/scrape/normalize.js +0 -102
- package/dist/scrape/normalize.js.map +0 -1
- package/dist/scrape/robots.d.ts +0 -37
- package/dist/scrape/robots.d.ts.map +0 -1
- package/dist/scrape/robots.js +0 -71
- package/dist/scrape/robots.js.map +0 -1
- package/dist/scrape/schema.d.ts +0 -23
- package/dist/scrape/schema.d.ts.map +0 -1
- package/dist/scrape/schema.js +0 -92
- package/dist/scrape/schema.js.map +0 -1
- package/dist/scrape/scraper.d.ts +0 -6
- package/dist/scrape/scraper.d.ts.map +0 -1
- package/dist/scrape/scraper.js +0 -46
- package/dist/scrape/scraper.js.map +0 -1
- package/dist/scrape/semantic.d.ts +0 -25
- package/dist/scrape/semantic.d.ts.map +0 -1
- package/dist/scrape/semantic.js +0 -27
- package/dist/scrape/semantic.js.map +0 -1
- package/dist/server/node.d.ts +0 -7
- package/dist/server/node.d.ts.map +0 -1
- package/dist/server/node.js.map +0 -1
- package/dist/sessions/file.d.ts +0 -25
- package/dist/sessions/file.d.ts.map +0 -1
- package/dist/sessions/file.js +0 -13
- package/dist/sessions/file.js.map +0 -1
- package/dist/sessions/replay.d.ts +0 -9
- package/dist/sessions/replay.d.ts.map +0 -1
- package/dist/sessions/replay.js +0 -70
- package/dist/sessions/replay.js.map +0 -1
- package/dist/sessions/store.d.ts +0 -25
- package/dist/sessions/store.d.ts.map +0 -1
- package/dist/sessions/store.js +0 -13
- package/dist/sessions/store.js.map +0 -1
- package/dist/storage/adapter.d.ts +0 -5
- package/dist/storage/adapter.d.ts.map +0 -1
- package/dist/storage/adapter.js +0 -11
- package/dist/storage/adapter.js.map +0 -1
- package/dist/storage/cache.d.ts +0 -23
- package/dist/storage/cache.d.ts.map +0 -1
- package/dist/storage/cache.js +0 -79
- package/dist/storage/cache.js.map +0 -1
- package/dist/storage/checksum.d.ts +0 -3
- package/dist/storage/checksum.d.ts.map +0 -1
- package/dist/storage/checksum.js +0 -19
- package/dist/storage/checksum.js.map +0 -1
- package/dist/storage/chunked.d.ts +0 -21
- package/dist/storage/chunked.d.ts.map +0 -1
- package/dist/storage/chunked.js +0 -67
- package/dist/storage/chunked.js.map +0 -1
- package/dist/storage/content.d.ts +0 -24
- package/dist/storage/content.d.ts.map +0 -1
- package/dist/storage/content.js +0 -44
- package/dist/storage/content.js.map +0 -1
- package/dist/storage/filehosting.d.ts +0 -2
- package/dist/storage/filehosting.d.ts.map +0 -1
- package/dist/storage/filehosting.js +0 -24
- package/dist/storage/filehosting.js.map +0 -1
- package/dist/storage/githubcontents.d.ts +0 -2
- package/dist/storage/githubcontents.d.ts.map +0 -1
- package/dist/storage/githubcontents.js +0 -29
- package/dist/storage/githubcontents.js.map +0 -1
- package/dist/storage/index.d.ts +0 -12
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js +0 -12
- package/dist/storage/index.js.map +0 -1
- package/dist/storage/local.d.ts +0 -2
- package/dist/storage/local.d.ts.map +0 -1
- package/dist/storage/local.js +0 -72
- package/dist/storage/local.js.map +0 -1
- package/dist/storage/memory.d.ts +0 -6
- package/dist/storage/memory.d.ts.map +0 -1
- package/dist/storage/memory.js +0 -36
- package/dist/storage/memory.js.map +0 -1
- package/dist/storage/pool.d.ts +0 -95
- package/dist/storage/pool.d.ts.map +0 -1
- package/dist/storage/pool.js +0 -202
- package/dist/storage/pool.js.map +0 -1
- package/dist/storage/s3compatible.d.ts +0 -3
- package/dist/storage/s3compatible.d.ts.map +0 -1
- package/dist/storage/s3compatible.js +0 -70
- package/dist/storage/s3compatible.js.map +0 -1
- package/dist/storage/sync.d.ts +0 -47
- package/dist/storage/sync.d.ts.map +0 -1
- package/dist/storage/sync.js +0 -75
- package/dist/storage/sync.js.map +0 -1
- package/dist/surfaces/adapters.d.ts +0 -97
- package/dist/surfaces/adapters.d.ts.map +0 -1
- package/dist/surfaces/adapters.js +0 -50
- package/dist/surfaces/adapters.js.map +0 -1
- package/dist/surfaces/controls.d.ts +0 -18
- package/dist/surfaces/controls.d.ts.map +0 -1
- package/dist/surfaces/controls.js +0 -45
- package/dist/surfaces/controls.js.map +0 -1
- package/dist/surfaces/manifest.d.ts +0 -68
- package/dist/surfaces/manifest.d.ts.map +0 -1
- package/dist/surfaces/manifest.js +0 -42
- package/dist/surfaces/manifest.js.map +0 -1
- package/dist/surfaces/n8n.d.ts +0 -25
- package/dist/surfaces/n8n.d.ts.map +0 -1
- package/dist/surfaces/n8n.js +0 -31
- package/dist/surfaces/n8n.js.map +0 -1
- package/dist/surfaces/operations.d.ts +0 -32
- package/dist/surfaces/operations.d.ts.map +0 -1
- package/dist/surfaces/operations.js +0 -53
- package/dist/surfaces/operations.js.map +0 -1
- package/dist/surfaces/requirements.d.ts +0 -29
- package/dist/surfaces/requirements.d.ts.map +0 -1
- package/dist/surfaces/requirements.js +0 -50
- package/dist/surfaces/requirements.js.map +0 -1
- package/dist/surfaces/targets.d.ts +0 -196
- package/dist/surfaces/targets.d.ts.map +0 -1
- package/dist/surfaces/targets.js +0 -27
- package/dist/surfaces/targets.js.map +0 -1
- package/dist/webhook/delivery.d.ts +0 -18
- package/dist/webhook/delivery.d.ts.map +0 -1
- package/dist/webhook/delivery.js +0 -36
- package/dist/webhook/delivery.js.map +0 -1
- package/dist/webhook/receiver.d.ts +0 -26
- package/dist/webhook/receiver.d.ts.map +0 -1
- package/dist/webhook/receiver.js +0 -24
- package/dist/webhook/receiver.js.map +0 -1
- package/dist/webhook/signature.d.ts +0 -3
- package/dist/webhook/signature.d.ts.map +0 -1
- package/dist/webhook/signature.js +0 -7
- package/dist/webhook/signature.js.map +0 -1
- package/dist/workflow/manifest.d.ts +0 -22
- package/dist/workflow/manifest.d.ts.map +0 -1
- package/dist/workflow/manifest.js +0 -21
- package/dist/workflow/manifest.js.map +0 -1
- package/dist/workflow/registry.d.ts +0 -7
- package/dist/workflow/registry.d.ts.map +0 -1
- package/dist/workflow/registry.js +0 -18
- package/dist/workflow/registry.js.map +0 -1
- package/dist/workflow/templates.d.ts +0 -6
- package/dist/workflow/templates.d.ts.map +0 -1
- package/dist/workflow/templates.js +0 -18
- package/dist/workflow/templates.js.map +0 -1
- package/dist/workflow/triggers.d.ts +0 -64
- package/dist/workflow/triggers.d.ts.map +0 -1
- package/dist/workflow/triggers.js +0 -99
- package/dist/workflow/triggers.js.map +0 -1
- package/docs/logs/.gitkeep +0 -0
- package/docs/plans/00.index.md +0 -50
- package/docs/plans/01.architecture.md +0 -86
- package/docs/plans/02.research.computer.use.md +0 -58
- package/docs/plans/03.research.captcha.bypass.md +0 -68
- package/docs/plans/04.research.sandbox.ai.md +0 -52
- package/docs/plans/05.capture.platform.md +0 -57
- package/docs/plans/06.dependencies.md +0 -97
- package/docs/plans/07.captcha.test.page.md +0 -41
- package/docs/plans/08.production.infra.md +0 -70
- package/docs/plans/09.database.schema.md +0 -121
- package/docs/plans/10.cloudinary.storage.md +0 -57
- package/docs/plans/11.movement.logs.json.md +0 -72
- package/docs/plans/12.research.atlas.agent.browser.md +0 -79
- package/docs/plans/13.research.anti.detection.md +0 -898
- package/docs/plans/14.research.proxy.md +0 -1495
- package/docs/plans/15.research.retry.rate.limit.md +0 -1958
- package/docs/plans/16.research.crawling.md +0 -1417
- package/docs/plans/17.research.caching.md +0 -1610
- package/docs/plans/18.research.content.extraction.md +0 -1952
- package/docs/plans/19.research.errors.events.md +0 -1523
- package/docs/plans/20.research.zod.validation.md +0 -1350
- package/docs/plans/21.research.batch.concurrency.md +0 -1888
- package/docs/plans/22.research.universal.runtime.md +0 -944
- package/docs/plans/23.research.ai.integration.md +0 -1465
- package/docs/plans/24.research.memory.persistence.md +0 -1979
- package/docs/plans/25.research.server.api.md +0 -342
- package/docs/plans/26.research.compilation.md +0 -249
- package/docs/plans/27.research.html.parsing.md +0 -251
- package/docs/plans/28.action.plan.md +0 -50
- package/docs/plans/29.api.reference.md +0 -174
- package/docs/plans/30.architecture.plan.md +0 -94
- package/docs/plans/31.auditoria.dados.md +0 -163
- package/docs/plans/32.bots.automacao.computacional.md +0 -214
- package/docs/plans/33.bots.codigo.revisao.md +0 -220
- package/docs/plans/34.bots.seguranca.cicd.md +0 -366
- package/docs/plans/35.comparativo.concorrencia.md +0 -464
- package/docs/plans/36.computational.memory.md +0 -340
- package/docs/plans/37.deploystrategy.md +0 -394
- package/docs/plans/38.flow.md +0 -155
- package/docs/plans/39.multi.platform.bot.md +0 -252
- package/docs/plans/40.npm.publish.md +0 -250
- package/docs/plans/41.o.que.falta.md +0 -407
- package/docs/plans/42.pesquisa.concorrencia.md +0 -721
- package/docs/plans/43.plan.universal.architecture.md +0 -496
- package/docs/plans/44.reference.md +0 -100
- package/docs/plans/45.robotarchitecture.md +0 -237
- package/docs/plans/46.scdnintegration.md +0 -284
- package/docs/plans/47.multiforge.readme.md +0 -129
- package/docs/plans/48.theory.v4.repo.os.md +0 -152
- package/docs/plans/49.third.party.infra.md +0 -12
- package/docs/plans/50.file.as.compute.md +0 -39
- package/docs/plans/51.architecture.virtual.processor.md +0 -80
- package/docs/plans/52.manifesto.v8.md +0 -11
- package/docs/plans/58.cdn.list.md +0 -23
- package/docs/plans/59.sql.frameworks.md +0 -33
- package/docs/plans/60.sql.thirdparty.md +0 -26
- package/docs/plans/61.objective.multiforge.md +0 -63
- package/docs/plans/62.huggingface.upload.md +0 -26
- package/docs/plans/63.kaggle.upload.md +0 -24
- package/docs/plans/64.npm.storage.md +0 -30
- package/docs/plans/65.rclone.terabox.md +0 -32
- package/docs/plans/66.buckets.and.models.todo.md +0 -14
- package/docs/plans/67.database.todo.md +0 -13
- package/docs/plans/68.deploy.packages.todo.md +0 -12
- package/docs/plans/69.report.human.operator.md +0 -133
- package/docs/plans/70.report.brain2qwerty.ems.md +0 -135
- package/docs/plans/71.report.hd.infinito.vram.md +0 -155
- package/docs/plans/72.plan.hd.infinito.node.md +0 -146
- package/docs/plans/73.plan.scifi.repos.md +0 -125
- package/docs/plans/74.000.manifesto.v8.flat.2..md +0 -11
- package/docs/plans/README.md +0 -489
- package/docs/plans/aggregate_platforms.mjs +0 -146
- package/docs/plans/examplesession.json +0 -36
- package/docs/plans/missing-facts.md +0 -192
- package/docs/plans/models.md +0 -64
- package/docs/plans/organize.cjs +0 -270
- package/docs/plans/platforms.md +0 -2887
- package/docs/plans/sites.md +0 -31322
- package/docs/sources/farm.py +0 -117
- package/docs/sources/html/saddle1.html +0 -132
- package/docs/sources/html/saddle2.html +0 -157
- package/docs/sources/html/saddle3.html +0 -119
- package/docs/sources/html/saddle4.html +0 -144
- package/docs/sources/html/saddle5.html +0 -72
- package/docs/sources/html/saddle6.html +0 -171
- package/docs/sources/html/saddle7.html +0 -236
- package/docs/sources/saddle.ts +0 -74
- package/docs/sources/schema.prisma +0 -88
- package/docs/sources/script.sh +0 -64
- package/docs/sources/workflows.yml +0 -458
- package/docs/talks1/_body.txt +0 -14
- package/docs/talks1/_index.md +0 -15
- package/docs/talks1/_screenshot.png +0 -0
- package/docs/talks1/assistant-01.md +0 -5
- package/docs/talks1/assistant-02.md +0 -5
- package/docs/talks1/assistant-03.md +0 -531
- package/docs/talks1/assistant-04.md +0 -26
- package/docs/talks1/assistant-05.md +0 -774
- package/docs/talks1/assistant-06.md +0 -1718
- package/docs/talks1/scrape-share.cjs +0 -185
- package/docs/talks1/scrape-share.ts +0 -183
- package/docs/talks1/user-01.md +0 -3
- package/docs/talks1/user-02.md +0 -3
- package/docs/talks1/user-03.md +0 -88
- package/docs/talks1/user-04.md +0 -3
- package/docs/talks1/user-05.md +0 -3
- package/docs/talks1/user-06.md +0 -88
- package/docs/talks1/user-07.md +0 -88
- package/docs/talks2/_body.txt +0 -14
- package/docs/talks2/_index.md +0 -16
- package/docs/talks2/_screenshot.png +0 -0
- package/docs/talks2/assistant-01.md +0 -5
- package/docs/talks2/assistant-02.md +0 -5
- package/docs/talks2/assistant-03.md +0 -424
- package/docs/talks2/assistant-04.md +0 -598
- package/docs/talks2/assistant-05.md +0 -1280
- package/docs/talks2/assistant-06.md +0 -1227
- package/docs/talks2/assistant-07.md +0 -1252
- package/docs/talks2/user-01.md +0 -3
- package/docs/talks2/user-02.md +0 -3
- package/docs/talks2/user-03.md +0 -88
- package/docs/talks2/user-04.md +0 -88
- package/docs/talks2/user-05.md +0 -88
- package/docs/talks2/user-06.md +0 -88
- package/docs/talks2/user-07.md +0 -3
- package/docs/talks3/_body.txt +0 -467
- package/docs/talks3/_index.md +0 -10
- package/docs/talks3/_screenshot.png +0 -0
- package/docs/talks3/assistant-01.md +0 -417
- package/docs/talks3/assistant-02.md +0 -417
- package/docs/talks3/assistant-03.md +0 -29
- package/docs/talks3/assistant-04.md +0 -727
- package/docs/talks3/user-01.md +0 -88
- package/docs/talks3/user-02.md +0 -88
- package/docs/talks3/user-03.md +0 -3
- package/docs/talks3/user-04.md +0 -3
- package/docs/talks4/_body.txt +0 -14
- package/docs/talks4/_index.md +0 -12
- package/docs/talks4/_screenshot.png +0 -0
- package/docs/talks4/assistant-01.md +0 -5
- package/docs/talks4/assistant-02.md +0 -5
- package/docs/talks4/assistant-03.md +0 -35
- package/docs/talks4/assistant-04.md +0 -512
- package/docs/talks4/assistant-05.md +0 -599
- package/docs/talks4/user-01.md +0 -3
- package/docs/talks4/user-02.md +0 -3
- package/docs/talks4/user-03.md +0 -88
- package/docs/talks4/user-04.md +0 -88
- package/docs/talks4/user-05.md +0 -7
- package/docs/talks5/_body.txt +0 -14
- package/docs/talks5/_index.md +0 -13
- package/docs/talks5/_screenshot.png +0 -0
- package/docs/talks5/assistant-01.md +0 -5
- package/docs/talks5/assistant-02.md +0 -5
- package/docs/talks5/assistant-03.md +0 -690
- package/docs/talks5/assistant-04.md +0 -758
- package/docs/talks5/assistant-05.md +0 -974
- package/docs/talks5/user-01.md +0 -3
- package/docs/talks5/user-02.md +0 -3
- package/docs/talks5/user-03.md +0 -105
- package/docs/talks5/user-04.md +0 -105
- package/docs/talks5/user-05.md +0 -63
- package/docs/talks5/user-06.md +0 -105
- package/docs/talks6/_body.txt +0 -14
- package/docs/talks6/_index.md +0 -9
- package/docs/talks6/_screenshot.png +0 -0
- package/docs/talks6/assistant-01.md +0 -5
- package/docs/talks6/assistant-02.md +0 -5
- package/docs/talks6/assistant-03.md +0 -1499
- package/docs/talks6/user-01.md +0 -3
- package/docs/talks6/user-02.md +0 -3
- package/docs/talks6/user-03.md +0 -88
- package/docs/talks6/user-04.md +0 -88
- package/docs/talks7/_body.txt +0 -14
- package/docs/talks7/_index.md +0 -10
- package/docs/talks7/_screenshot.png +0 -0
- package/docs/talks7/assistant-01.md +0 -5
- package/docs/talks7/assistant-02.md +0 -5
- package/docs/talks7/assistant-03.md +0 -523
- package/docs/talks7/assistant-04.md +0 -617
- package/docs/talks7/user-01.md +0 -3
- package/docs/talks7/user-02.md +0 -3
- package/docs/talks7/user-03.md +0 -105
- package/docs/talks7/user-04.md +0 -67
- package/docs/talks8/conversa1.txt +0 -1322
- package/docs/talks8/conversa2.txt +0 -237
- package/docs/talks9/Beyond the Obvious_ 50 Plataformas Auto-Hospedadas de Forja de C/303/263digo para Al/303/251m de Gitea e GitLab.md" +0 -174
- package/docs/talks9/De NPM a Multi-Linguagem_ Uma Arquitetura T/303/251cnica para a Execu/303/247/303/243o Integrada de C/303/263digo no Ecossistema Node.js.md" +0 -59
- package/docs/talks9/De NPM a VMs Virtuais_ Uma An/303/241lise Arquitet/303/264nica para a Realiza/303/247/303/243o do Ciclo de Vida do Projeto SADDLE.md" +0 -91
- package/docs/talks9/Mapeamento da Engrenagem Computacional_ Uma Arquitetura para Execu/303/247/303/243o Isolada e Persist/303/252ncia em Ambientes Distribu/303/255dos.md" +0 -116
- package/docs/talks9/O Cen/303/241rio Pr/303/241tico do SADDLE_ Uma An/303/241lise de Viabilidade e Modelo de Ciclo de Vida Integrado.md" +0 -128
- package/docs/talks9/README (2).md +0 -489
- package/docs/talks9/README.md +0 -198
- package/docs/talks9/Viabilidade do Saddle_ Uma An/303/241lise T/303/251cnica da Transforma/303/247/303/243o de Armazenamento Remoto em Mem/303/263ria Computacional.md" +0 -80
- package/docs/talks9/conversa.txt +0 -544
- package/docs/talks9/other (2).md +0 -39
- package/docs/talks9/other.md +0 -57
- package/docs/talks9/outro.txt +0 -24
- /package/{extension/README.md → docs/extension.md} +0 -0
package/Dockerfile
ADDED
|
@@ -0,0 +1,1339 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
# saddle v2.0.0 grand merge — THE ONE CONTAINER FILE.
|
|
3
|
+
#
|
|
4
|
+
# this Dockerfile carries BOTH container surfaces of the merged repository:
|
|
5
|
+
# 1. the saddle virtual-hardware engine image (the five stages below:
|
|
6
|
+
# builder, python-bridge, qemu, qemu-runtime, runtime) — the default
|
|
7
|
+
# build target, published as ghcr.io/wenathlan/saddle:vhe-<version>
|
|
8
|
+
# across three profiles and four architectures;
|
|
9
|
+
# 2. the saddle node-engine image (the saddle-build and saddle-runtime
|
|
10
|
+
# stages at the end of this file, folded from the former
|
|
11
|
+
# dockerfile.saddle) — an explicit build target
|
|
12
|
+
# (`docker build --target saddle-runtime .`), the node 26 storage and
|
|
13
|
+
# compute service published as ghcr.io/wenathlan/saddle:<version>.
|
|
14
|
+
#
|
|
15
|
+
# saddle v2 (grand merge) - virtual hardware engine, multi-stage, multi-arch image.
|
|
16
|
+
#
|
|
17
|
+
# the five stages mirror the stages section of docker.config
|
|
18
|
+
# (multi-stage-cache-optimized strategy, parallel-friendly):
|
|
19
|
+
# builder toolchain stage on ubuntu:24.04. installs LLVM 18
|
|
20
|
+
# (from the noble archive, not apt.llvm.org which is
|
|
21
|
+
# unreachable from GHA runners), builds mesa 26.2.1
|
|
22
|
+
# (llvmpipe + lavapipe; rusticl is off until
|
|
23
|
+
# LLVMSPIRVLib >= 22.1 is packaged), installs node
|
|
24
|
+
# 26.7.0 from nodesource, and compiles the native sources
|
|
25
|
+
# DIRECTLY with gcc-14/g++-14 (no cmake anywhere: the libs
|
|
26
|
+
# are single translation units documented in their own
|
|
27
|
+
# headers): libs/virtualhardware.c (LD_PRELOAD spoofing
|
|
28
|
+
# core), libs/gpumonitor.cpp (nvml/cuda shim suite in
|
|
29
|
+
# four build modes) and libs/virtualizationcore.cpp
|
|
30
|
+
# (kvm/vfio/qmp core with an executable selftest), all
|
|
31
|
+
# with -O3 -flto. it also bakes the /etc/virtual hardware
|
|
32
|
+
# profile per the VHE_PROFILE_* build-args (max: EPYC 9965
|
|
33
|
+
# 192c/384t 1TiB, balanced: Threadripper Pro 9995WX
|
|
34
|
+
# 96c/192t 512GiB, lite: Ryzen 9 9950X3D 16c/32t 128GiB).
|
|
35
|
+
# python-bridge python:3.14.7-slim carrying qemubridge.py. the bridge is
|
|
36
|
+
# stdlib-only (asyncio/json/argparse), so the stage runs a
|
|
37
|
+
# py_compile syntax gate and no pip install at all.
|
|
38
|
+
# qemu QEMU 11.1.0 compiled from download.qemu.org with the
|
|
39
|
+
# x86_64-softmmu target for TCG/MTTCG guest execution;
|
|
40
|
+
# build arg QEMU_FROM_SOURCE=0 falls back to the distro
|
|
41
|
+
# qemu-system-x86 package when a source build is not
|
|
42
|
+
# viable on the host.
|
|
43
|
+
# qemu-runtime the qemu stage plus OVMF firmware, pciutils, kmod and
|
|
44
|
+
# tini (the docker.config "qemuRuntime" role: the guest
|
|
45
|
+
# runner consumed by the vheqemu docker run recipe).
|
|
46
|
+
# runtime ubuntu:24.04 final image: mesa 26.2.1 stack, node
|
|
47
|
+
# 26.7.0, Xvfb, vulkan-tools, clinfo, mesa-utils,
|
|
48
|
+
# python3, the compiled spoofing artifacts, the python
|
|
49
|
+
# bridge and the engine sources under /engine. default
|
|
50
|
+
# build target (docker build / the engine docker run
|
|
51
|
+
# recipe below).
|
|
52
|
+
#
|
|
53
|
+
# platforms: linux/amd64, linux/arm64, linux/ppc64le and linux/s390x
|
|
54
|
+
# through buildx --platform (the four-arch registry surface); every
|
|
55
|
+
# stage compiles for the portable baseline of its target architecture
|
|
56
|
+
# by default (x86-64 / armv8-a / power8 / z196, resolved from
|
|
57
|
+
# TARGETARCH) so the layers stay valid on every host and every
|
|
58
|
+
# gha-cached runner cpu; pass --build-arg VHE_MARCH=native for
|
|
59
|
+
# host-tuned local builds, or an explicit -march value when
|
|
60
|
+
# cross-building for a known deployment target.
|
|
61
|
+
#
|
|
62
|
+
# profiles: the three profiles (max, balanced, lite) are all built for
|
|
63
|
+
# all four architectures; each profile carries a distinct virtual CPU
|
|
64
|
+
# identity (model name, vcpus, threads, ram) baked into /etc/virtual.
|
|
65
|
+
#
|
|
66
|
+
# the one container file (the gateway 1.1.5 standard): the compose stack
|
|
67
|
+
# and the entrypoint bootstrap are MERGED INTO this file -
|
|
68
|
+
# docker-compose.yml and entrypoint.sh are deleted from the tree; every
|
|
69
|
+
# orchestration setting they carried is expressed here (the ENV defaults,
|
|
70
|
+
# EXPOSE, VOLUME, HEALTHCHECK, USER, the OCI labels, the entrypoint script
|
|
71
|
+
# embedded as a heredoc COPY) plus the hardened docker run recipes below
|
|
72
|
+
# documenting every flag of the former services (init reaps zombies as
|
|
73
|
+
# pid 1, cap-drop ALL + no-new-privileges harden the container, unlimited
|
|
74
|
+
# swap, 2g shm, 15s stop grace, 50m x 5 json-file logs, restart
|
|
75
|
+
# unless-stopped, the tmpfs scratch and the named volumes). Containerfile
|
|
76
|
+
# is the same format under the OCI name - Dockerfile is the universally
|
|
77
|
+
# compatible spelling, so it is the one file the repository keeps.
|
|
78
|
+
#
|
|
79
|
+
# the docker run recipes (one per former compose service; pick any free
|
|
80
|
+
# host port in 30000-60000 - nothing below is a fixed address):
|
|
81
|
+
#
|
|
82
|
+
# vhe (the engine service, default target):
|
|
83
|
+
# docker run -d --name saddle-engine \
|
|
84
|
+
# --restart unless-stopped --init \
|
|
85
|
+
# --cap-drop ALL --security-opt no-new-privileges:true \
|
|
86
|
+
# --ulimit nofile=65536:65536 \
|
|
87
|
+
# --memory-swap -1 --shm-size 2g --stop-timeout 15 \
|
|
88
|
+
# --log-driver json-file --log-opt max-size=50m --log-opt max-file=5 \
|
|
89
|
+
# --tmpfs /tmp:size=512m,mode=1777 --tmpfs /run/vhe:size=64m,mode=0755 \
|
|
90
|
+
# --tmpfs /cache/mesa_shader_cache:size=20g,uid=10000,gid=10000,mode=1777 \
|
|
91
|
+
# -v vmdata:/data/vmdata -v webdata:/data/web \
|
|
92
|
+
# -v ./vm.config.json:/engine/vm.config.json:ro \
|
|
93
|
+
# -e PORT=8080 -e NODE_ENV=production -p 31280:8080 \
|
|
94
|
+
# ghcr.io/wenathlan/saddle:vhe-2.0.2
|
|
95
|
+
#
|
|
96
|
+
# vheqemu (the guest runner; build it first with
|
|
97
|
+
# docker build --target qemu-runtime -t saddle/qemu:11.1.0 . because the
|
|
98
|
+
# published registry image is the runtime target):
|
|
99
|
+
# docker run -d --name saddle-qemu \
|
|
100
|
+
# --restart unless-stopped --init \
|
|
101
|
+
# --security-opt no-new-privileges:true \
|
|
102
|
+
# --ulimit nofile=65536:65536 \
|
|
103
|
+
# --memory-swap -1 --shm-size 2g --stop-timeout 15 \
|
|
104
|
+
# --log-driver json-file --log-opt max-size=50m --log-opt max-file=5 \
|
|
105
|
+
# -v ./qemu:/qemu:ro -v qemu-kernel:/opt/kernels:ro \
|
|
106
|
+
# -v qemudata:/data/qemudata -v ovmfvars:/data/ovmfvars \
|
|
107
|
+
# -v ./qemu.config:/engine/qemu.config:ro \
|
|
108
|
+
# -p 31281:31281 -it \
|
|
109
|
+
# saddle/qemu:11.1.0 \
|
|
110
|
+
# -accel tcg,thread=multi,tb-size=1024 -cpu EPYC-v5 \
|
|
111
|
+
# -smp 192,sockets=1,cores=192,threads=2,maxcpus=384 \
|
|
112
|
+
# -m 131072 -machine q35 -nodefaults -no-reboot -nographic \
|
|
113
|
+
# -serial mon:stdio -monitor none \
|
|
114
|
+
# -kernel /qemu/vmlinuz -initrd /qemu/initrd.img \
|
|
115
|
+
# -append "console=ttyS0 panic=-1"
|
|
116
|
+
#
|
|
117
|
+
# vhegpu (the fake gpu sidecar, same engine image):
|
|
118
|
+
# docker run -d --name saddle-gpu \
|
|
119
|
+
# --restart unless-stopped --init \
|
|
120
|
+
# --cap-drop ALL --security-opt no-new-privileges:true \
|
|
121
|
+
# --ulimit nofile=65536:65536 \
|
|
122
|
+
# --memory-swap -1 --shm-size 2g --stop-timeout 15 \
|
|
123
|
+
# --log-driver json-file --log-opt max-size=50m --log-opt max-file=5 \
|
|
124
|
+
# -v gpudata:/data/gpudata -v ./gpus.json:/engine/gpus.json:ro \
|
|
125
|
+
# -e VHE_GPU_PROFILE=b200 -e VHE_GPUS=8 -e VHE_MIG=1 \
|
|
126
|
+
# -e VHE_SMI_DRIVER=575.57.08 -e VHE_SMI_CUDA=12.9 \
|
|
127
|
+
# -e VHE_SMI_INTERVAL=30 -e VHE_SKIP_XVFB=1 -e VHE_SKIP_VALIDATE=1 \
|
|
128
|
+
# ghcr.io/wenathlan/saddle:vhe-2.0.2 /bin/bash -c '
|
|
129
|
+
# while true; do
|
|
130
|
+
# /usr/local/bin/nvidia-smi "$VHE_GPU_PROFILE" "$VHE_GPUS" || true
|
|
131
|
+
# sleep "$VHE_SMI_INTERVAL"
|
|
132
|
+
# done
|
|
133
|
+
# '
|
|
134
|
+
#
|
|
135
|
+
# qemubridge (the python QMP bridge, same engine image):
|
|
136
|
+
# docker run -d --name saddle-bridge \
|
|
137
|
+
# --restart unless-stopped --init \
|
|
138
|
+
# --security-opt no-new-privileges:true \
|
|
139
|
+
# --ulimit nofile=65536:65536 \
|
|
140
|
+
# --memory-swap -1 --shm-size 2g --stop-timeout 15 \
|
|
141
|
+
# --log-driver json-file --log-opt max-size=50m --log-opt max-file=5 \
|
|
142
|
+
# -v qemudata:/data/qemudata \
|
|
143
|
+
# -v ./qemubridge.py:/engine/qemubridge.py:ro \
|
|
144
|
+
# -e QMP_SOCKET=/run/vhe/vm.qmp -e PYTHONUNBUFFERED=1 \
|
|
145
|
+
# ghcr.io/wenathlan/saddle:vhe-2.0.2 \
|
|
146
|
+
# python3 /engine/qemubridge.py --socket /run/vhe/vm.qmp status
|
|
147
|
+
#
|
|
148
|
+
# saddle-node (the node-engine service, the former compose.yml
|
|
149
|
+
# service folded here; build it with
|
|
150
|
+
# docker build --target saddle-runtime -t saddle:<version> .):
|
|
151
|
+
# docker run -d --name saddle-node \
|
|
152
|
+
# --restart unless-stopped --init --read-only \
|
|
153
|
+
# --cap-drop ALL --security-opt no-new-privileges:true \
|
|
154
|
+
# --pids-limit 512 --network none \
|
|
155
|
+
# --ulimit nofile=65536:65536 \
|
|
156
|
+
# --log-driver json-file --log-opt max-size=50m --log-opt max-file=5 \
|
|
157
|
+
# --tmpfs /tmp:size=2g,mode=1777 \
|
|
158
|
+
# -e SADDLE_MEMORY_ENGINE=ram -e SBOT_PLATFORM= -e SBOT_CDN_URL= \
|
|
159
|
+
# ghcr.io/wenathlan/saddle:2.0.2 \
|
|
160
|
+
# node dist/cli.js plan
|
|
161
|
+
#
|
|
162
|
+
# observability (the former prometheus scraper of the full profile)
|
|
163
|
+
# runs from its own upstream image (prom/prometheus:v3.4.1) with
|
|
164
|
+
# --config.file and a 15d retention - the one container file this
|
|
165
|
+
# repository keeps covers only what it builds.
|
|
166
|
+
#
|
|
167
|
+
# no port is published by the image itself; the recipes above publish
|
|
168
|
+
# host 31280 -> container 8080 for the engine and 31281 for the qemu
|
|
169
|
+
# guest runner, and a bare `docker run` without -e PORT leaves the
|
|
170
|
+
# embedded entrypoint picking a random port in 30000-60000 (the same
|
|
171
|
+
# range the recipes draw their host ports from). nothing in the stack
|
|
172
|
+
# ever binds a hardcoded address.
|
|
173
|
+
|
|
174
|
+
# Base image contract (the gateway family policy): tags only, never a
|
|
175
|
+
# @sha256: digest. A single digest cannot serve the four-architecture
|
|
176
|
+
# matrix this image ships (the registry resolves the tag per platform),
|
|
177
|
+
# and a digest written here would be a hardcoded hash - the checksums
|
|
178
|
+
# that exist are generated by the GitHub runners and published as
|
|
179
|
+
# release assets (SHA256SUMS), never written into the sources.
|
|
180
|
+
ARG UBUNTU="ubuntu:24.04"
|
|
181
|
+
# maximum virtual hardware profile baked at build time (workflow override
|
|
182
|
+
# friendly): the top catalog cpu (EPYC 9965, 192 cores / 384 threads), the
|
|
183
|
+
# catalog maximum memory plan (1024 GiB), the top gpu profile (B200) and
|
|
184
|
+
# eight virtual adapters. every value is spoofed software identity: no
|
|
185
|
+
# physical hardware is touched, probed or required.
|
|
186
|
+
ARG VHE_PROFILE_CPU="epyc9965"
|
|
187
|
+
ARG VHE_PROFILE_VCPUS="192"
|
|
188
|
+
ARG VHE_PROFILE_THREADS="384"
|
|
189
|
+
ARG VHE_PROFILE_RAM_GB="1024"
|
|
190
|
+
ARG VHE_PROFILE_GPU="b200"
|
|
191
|
+
ARG VHE_PROFILE_GPUS="8"
|
|
192
|
+
ARG PYTHON_BASE="python:3.14.7-slim"
|
|
193
|
+
ARG LLVM_VERSION="18"
|
|
194
|
+
ARG NODE_VERSION="26.7.0"
|
|
195
|
+
ARG MESA_VERSION="26.2.1"
|
|
196
|
+
ARG QEMU_VERSION="11.1.0"
|
|
197
|
+
|
|
198
|
+
# ---------------------------------------------------------------------------
|
|
199
|
+
# stage 1: builder
|
|
200
|
+
# ---------------------------------------------------------------------------
|
|
201
|
+
FROM ${UBUNTU} AS builder
|
|
202
|
+
ARG TARGETPLATFORM
|
|
203
|
+
ARG TARGETARCH
|
|
204
|
+
ARG BUILDARCH
|
|
205
|
+
ARG LLVM_VERSION
|
|
206
|
+
ARG NODE_VERSION
|
|
207
|
+
ARG MESA_VERSION
|
|
208
|
+
# empty = portable baseline resolved from TARGETARCH at the compile step
|
|
209
|
+
# (x86-64 / armv8-a); "native" is the opt-in for host-tuned local builds.
|
|
210
|
+
ARG VHE_MARCH=""
|
|
211
|
+
# NOTE: the VHE_PROFILE_* build-args are deliberately NOT declared in the
|
|
212
|
+
# builder stage. The builder compiles mesa/node/native shims which are
|
|
213
|
+
# profile-independent; keeping the profile args out of the builder means
|
|
214
|
+
# the buildx registry cache is shared across max/balanced/lite for each
|
|
215
|
+
# architecture (the profile identity is baked in the runtime stage below).
|
|
216
|
+
|
|
217
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
218
|
+
|
|
219
|
+
# toolchain: gcc-14 (speaks c++26 for the shim suite) and the LLVM 18
|
|
220
|
+
# toolchain from the Ubuntu noble archive (which mesa 26.2.1 requires
|
|
221
|
+
# '>= 18.0.0'). The previous build pulled LLVM 22 from apt.llvm.org but
|
|
222
|
+
# that host is unreachable from GitHub Actions runners (curl exit 7,
|
|
223
|
+
# 8 retries all failed in 0 ms); the Ubuntu distro LLVM 18.1.x is served
|
|
224
|
+
# from archive.ubuntu.com which the runner can always reach. Rusticl is
|
|
225
|
+
# disabled (see the mesa block below) so no clang/libclc/libllvmspirvlib
|
|
226
|
+
# are needed; the native sources compile with g++-14.
|
|
227
|
+
RUN set -eux; \
|
|
228
|
+
# the Ubuntu arm64/ppc64el/s390x ports mirror (ports.ubuntu.com)
|
|
229
|
+
# intermittently serves either a Packages.gz whose size differs from
|
|
230
|
+
# the Release file while it is mid-sync ("File has unexpected size
|
|
231
|
+
# ... Mirror sync in progress?") OR a Release index that references
|
|
232
|
+
# .deb files already removed from the pool directory (404 Not Found
|
|
233
|
+
# on apt-get install). Retrying just apt-get update is not enough:
|
|
234
|
+
# the update can succeed on a stale index whose pool files are gone.
|
|
235
|
+
# The retry must cover BOTH apt-get update AND apt-get install so a
|
|
236
|
+
# 404 on install re-fetches a fresh index that references the new
|
|
237
|
+
# package versions. The stale list cache is cleared between retries.
|
|
238
|
+
apt_update_tries=5; \
|
|
239
|
+
while [ "$apt_update_tries" -gt 0 ]; do \
|
|
240
|
+
if apt-get update && apt-get install -y --no-install-recommends \
|
|
241
|
+
ca-certificates curl gnupg xz-utils bzip2 git \
|
|
242
|
+
python3 python3-pip python3-setuptools python3-wheel \
|
|
243
|
+
python3-mako python3-yaml python3-ply \
|
|
244
|
+
pkg-config bison flex ninja-build meson \
|
|
245
|
+
build-essential gcc-14 g++-14 \
|
|
246
|
+
"llvm-${LLVM_VERSION}-dev" "llvm-${LLVM_VERSION}-tools" \
|
|
247
|
+
libdrm-dev libexpat1-dev zlib1g-dev libzstd-dev \
|
|
248
|
+
libx11-dev libxext-dev libxfixes-dev libxxf86vm-dev libxrandr-dev \
|
|
249
|
+
libxcb1-dev libxcb-glx0-dev libxcb-dri2-0-dev libxcb-dri3-dev \
|
|
250
|
+
libxcb-present-dev libxcb-sync-dev libxcb-shm0-dev \
|
|
251
|
+
libxcb-randr0-dev libxcb-xfixes0-dev libx11-xcb-dev libxshmfence-dev \
|
|
252
|
+
libelf-dev libedit-dev libglvnd-dev \
|
|
253
|
+
glslang-tools spirv-tools; then break; fi; \
|
|
254
|
+
apt_update_tries=$((apt_update_tries - 1)); \
|
|
255
|
+
echo "apt-get update/install failed (mirror sync?), $apt_update_tries retries left"; \
|
|
256
|
+
sleep 10; \
|
|
257
|
+
rm -rf /var/lib/apt/lists/*; \
|
|
258
|
+
done; \
|
|
259
|
+
test "$apt_update_tries" -gt 0; \
|
|
260
|
+
ln -sf "/usr/bin/llvm-config-${LLVM_VERSION}" /usr/local/bin/llvm-config; \
|
|
261
|
+
ln -sf /usr/bin/gcc-14 /usr/local/bin/gcc; \
|
|
262
|
+
ln -sf /usr/bin/g++-14 /usr/local/bin/g++; \
|
|
263
|
+
# mesa 26.2.1 requires meson >= 1.4.0 (mesa.build:9); Ubuntu 24.04 noble
|
|
264
|
+
# ships meson 1.3.2 which is too old. meson installs from its exact
|
|
265
|
+
# version-pinned wheel URL: the artifact identity is the 1.12.0 release
|
|
266
|
+
# path on files.pythonhosted.org (a registry URL, the same class of
|
|
267
|
+
# contract npm ci uses through the lockfile). No hardcoded digest in
|
|
268
|
+
# this file: the maintainer supply-chain policy for this family is the
|
|
269
|
+
# version-tagged artifact (the Scorecard PinnedDependencies findings
|
|
270
|
+
# are dismissed per that policy) and the checksums that exist are
|
|
271
|
+
# generated on the GitHub runners at release time (see the SHA256SUMS
|
|
272
|
+
# asset of the Release workflow), never written into the sources.
|
|
273
|
+
curl -fsSL --retry 5 --retry-all-errors \
|
|
274
|
+
-o /tmp/meson-1.12.0-py3-none-any.whl \
|
|
275
|
+
"https://files.pythonhosted.org/packages/07/68/b0117422eb0a46d9d8d9e328f0c5b5c835179bfc058688bca35c90c89eba/meson-1.12.0-py3-none-any.whl"; \
|
|
276
|
+
pip3 install --break-system-packages --no-cache-dir \
|
|
277
|
+
/tmp/meson-1.12.0-py3-none-any.whl; \
|
|
278
|
+
rm -f /tmp/meson-1.12.0-py3-none-any.whl; \
|
|
279
|
+
meson --version
|
|
280
|
+
|
|
281
|
+
# NOTE: the rust toolchain step was removed because rusticl is disabled
|
|
282
|
+
# (LLVMSPIRVLib >= 22.1 not packaged for LLVM 22; see the mesa block below).
|
|
283
|
+
# Rusticl was the only mesa component that needed rustc + bindgen-cli; with
|
|
284
|
+
# it off, the build is rust-free.
|
|
285
|
+
|
|
286
|
+
# node 26.7.0 (current line, v8 14.6, temporal api, NODE_MODULE_VERSION 147).
|
|
287
|
+
# amd64 and arm64 install the pinned nodesource deb; ppc64le (any arch the
|
|
288
|
+
# nodesource apt repo does not carry) falls back to the official nodejs.org
|
|
289
|
+
# binary tarball, extracted straight into /usr so bin/node, include/node and
|
|
290
|
+
# lib/node_modules land exactly where the nodesource package (and the runtime
|
|
291
|
+
# stage COPY --from=builder directives) expect them. the node headers
|
|
292
|
+
# (/usr/include/node) are required by the ADDON build mode of gpumonitor.cpp.
|
|
293
|
+
RUN set -eux; \
|
|
294
|
+
nodesrc_ok="1"; \
|
|
295
|
+
case "${TARGETARCH}" in ppc64le|s390x|riscv64|loongarch64) nodesrc_ok="0" ;; esac; \
|
|
296
|
+
if [ "$nodesrc_ok" = "1" ]; then \
|
|
297
|
+
# the version-line setup script (setup_26.x) is the nodesource
|
|
298
|
+
# distribution contract: no hardcoded digest in this file. The
|
|
299
|
+
# script tracks the whole 26.x line (a frozen hash would
|
|
300
|
+
# false-negative on every upstream refresh), the apt repository
|
|
301
|
+
# it configures carries its own release signing, and the exact
|
|
302
|
+
# node build is pinned by the "nodejs=${NODE_VERSION}-1nodesource1"
|
|
303
|
+
# package below. Checksums for released artifacts are generated on
|
|
304
|
+
# the GitHub runners (SHA256SUMS release asset), never hardcoded.
|
|
305
|
+
curl -fsSL -o /tmp/nodesource-setup.sh https://deb.nodesource.com/setup_26.x; \
|
|
306
|
+
bash /tmp/nodesource-setup.sh; \
|
|
307
|
+
rm -f /tmp/nodesource-setup.sh; \
|
|
308
|
+
apt-get install -y --no-install-recommends \
|
|
309
|
+
"nodejs=${NODE_VERSION}-1nodesource1" \
|
|
310
|
+
|| apt-get install -y --no-install-recommends nodejs; \
|
|
311
|
+
else \
|
|
312
|
+
tarball="node-v${NODE_VERSION}-linux-${TARGETARCH}.tar.xz"; \
|
|
313
|
+
curl -fsSL --retry 5 --retry-all-errors -o "/tmp/${tarball}" \
|
|
314
|
+
"https://nodejs.org/dist/v${NODE_VERSION}/${tarball}"; \
|
|
315
|
+
tar -xJf "/tmp/${tarball}" -C /usr --strip-components=1; \
|
|
316
|
+
rm -f "/tmp/${tarball}"; \
|
|
317
|
+
fi; \
|
|
318
|
+
node --version; npm --version; \
|
|
319
|
+
# upgrade the bundled npm to the line the engines field documents
|
|
320
|
+
# (nodesource node 26.7.0 ships npm 11.19.0) and surgically refresh
|
|
321
|
+
# the four nested dependencies whose bundled versions carry the CVEs
|
|
322
|
+
# the trivy release gate rejects (brace-expansion CVE-2026-14257 /
|
|
323
|
+
# CVE-2026-69152, ip-address CVE-2026-69192 / CVE-2026-54272 /
|
|
324
|
+
# CVE-2026-69198, tar CVE-2026-73566, undici CVE-2026-16728 /
|
|
325
|
+
# CVE-2026-16729 / CVE-2026-15157). published npm tarballs freeze
|
|
326
|
+
# their bundled node_modules at publish time, so the swap alone
|
|
327
|
+
# still ships brace-expansion 5.0.7; each fixed release is packed
|
|
328
|
+
# separately and extracted over the nested path, then asserted: the
|
|
329
|
+
# runtime stage copies /usr/lib/node_modules verbatim and the gate
|
|
330
|
+
# scans exactly that path.
|
|
331
|
+
newnpm=$(npm pack "npm@12.0.2" --pack-destination /tmp 2>/dev/null | tail -n1); \
|
|
332
|
+
case "${newnpm}" in /*) ;; *) newnpm="/tmp/${newnpm}";; esac; \
|
|
333
|
+
test -f "${newnpm}"; \
|
|
334
|
+
rm -rf /usr/lib/node_modules/npm; \
|
|
335
|
+
mkdir -p /usr/lib/node_modules/npm; \
|
|
336
|
+
tar -xzf "${newnpm}" -C /usr/lib/node_modules/npm --strip-components=1; \
|
|
337
|
+
rm -f "${newnpm}"; \
|
|
338
|
+
hash -r; \
|
|
339
|
+
npm --version; \
|
|
340
|
+
test -f /usr/include/node/node_api.h; \
|
|
341
|
+
fixdep() { \
|
|
342
|
+
fname="$1"; fwant="$2"; \
|
|
343
|
+
ftgz=$(npm pack "$fname@$fwant" --pack-destination /tmp 2>/dev/null | tail -n1); \
|
|
344
|
+
case "$ftgz" in /*) ;; *) ftgz="/tmp/$ftgz";; esac; \
|
|
345
|
+
test -f "$ftgz"; \
|
|
346
|
+
fdest="/usr/lib/node_modules/npm/node_modules/$fname"; \
|
|
347
|
+
rm -rf "$fdest"; \
|
|
348
|
+
mkdir -p "$fdest"; \
|
|
349
|
+
tar -xzf "$ftgz" -C "$fdest" --strip-components=1; \
|
|
350
|
+
rm -f "$ftgz"; \
|
|
351
|
+
fgot=$(node -p "require('/usr/lib/node_modules/npm/node_modules/$fname/package.json').version"); \
|
|
352
|
+
if [ "$fgot" != "$fwant" ]; then \
|
|
353
|
+
echo "npm tree $fname is $fgot, expected $fwant" >&2; \
|
|
354
|
+
exit 1; \
|
|
355
|
+
fi; \
|
|
356
|
+
echo "npm tree $fname $fgot"; \
|
|
357
|
+
}; \
|
|
358
|
+
fixdep brace-expansion 5.0.9; \
|
|
359
|
+
fixdep ip-address 10.3.1; \
|
|
360
|
+
fixdep tar 7.5.21; \
|
|
361
|
+
fixdep undici 6.28.0; \
|
|
362
|
+
rm -rf /root/.npm 2>/dev/null || true
|
|
363
|
+
|
|
364
|
+
# mesa 26.2.1 from source (the "build" arm of the PPA-or-build policy):
|
|
365
|
+
# llvmpipe (OpenGL 4.6 core, 161/161 extensions), lavapipe (Vulkan 1.4
|
|
366
|
+
# software ICD, lvp_icd.<arch>.json). Rusticl (OpenCL 3.1) is DISABLED
|
|
367
|
+
# because mesa 26.2.1 requires LLVMSPIRVLib >= 22.1 (the
|
|
368
|
+
# SPIRV-LLVM-Translator for LLVM 22), and apt.llvm.org does not yet ship
|
|
369
|
+
# libllvmspirvlib-22-dev (the latest available is libllvmspirvlib-19-dev
|
|
370
|
+
# at version 19.1.0.0, which is too old). Building SPIRV-LLVM-Translator
|
|
371
|
+
# from source would add ~10 min to the build; the OpenCL validation is
|
|
372
|
+
# deferred until the package lands upstream. video codecs and extra
|
|
373
|
+
# tools stay off to keep the build lean; platforms=x11 only because the
|
|
374
|
+
# engine renders headless through Xvfb GLX.
|
|
375
|
+
#
|
|
376
|
+
# Download strategy: GHA runners cannot reliably reach mesa.freedesktop.org
|
|
377
|
+
# or archive.mesa3d.org (curl exit 28 on connect observed across multiple
|
|
378
|
+
# Build workflow runs). The canonical upstream tarball has been mirrored
|
|
379
|
+
# to a GitHub release asset under the mesa-cache-26.2.1 tag in this repo,
|
|
380
|
+
# which is served from githubusercontent.com (always reachable from GHA).
|
|
381
|
+
# The build tries the GitHub release first, then falls back through the
|
|
382
|
+
# freedesktop.org canonical URL and the archive.mesa3d.org mirror (the
|
|
383
|
+
# final redirect target) so local builds without GitHub access still
|
|
384
|
+
# work.
|
|
385
|
+
#
|
|
386
|
+
# Verification contract (no hardcoded hashes, the gateway family policy):
|
|
387
|
+
# the sha256 of the tarball is NEVER written in this file. GitHub computes
|
|
388
|
+
# the digest of every release asset at upload time; the publish workflows
|
|
389
|
+
# resolve that digest at build time and pass it as the MESA_SHA256
|
|
390
|
+
# build-arg, so every GitHub build verifies the tarball before it lands
|
|
391
|
+
# in a layer. Local builds without the build-arg fetch the SHA256SUMS
|
|
392
|
+
# asset of the mesa-cache release when reachable and verify against it;
|
|
393
|
+
# a fully offline local build proceeds with a visible warning.
|
|
394
|
+
ARG MESA_SHA256=""
|
|
395
|
+
RUN set -eux; \
|
|
396
|
+
curl_opts="-fL --retry 5 --retry-all-errors --retry-delay 5 \
|
|
397
|
+
--connect-timeout 30 --max-time 900"; \
|
|
398
|
+
tarball="mesa-${MESA_VERSION}.tar.xz"; \
|
|
399
|
+
repo="${GITHUB_REPOSITORY:-wenathlan/saddle}"; \
|
|
400
|
+
github_release="https://github.com/${repo}/releases/download/mesa-cache-${MESA_VERSION}/${tarball}"; \
|
|
401
|
+
sums_url="https://github.com/${repo}/releases/download/mesa-cache-${MESA_VERSION}/SHA256SUMS"; \
|
|
402
|
+
upstream="https://mesa.freedesktop.org/archive/${tarball}"; \
|
|
403
|
+
mirror="https://archive.mesa3d.org/${tarball}"; \
|
|
404
|
+
rm -f "${tarball}" SHA256SUMS; \
|
|
405
|
+
curl ${curl_opts} -C - -o "${tarball}" "${github_release}" \
|
|
406
|
+
|| curl ${curl_opts} -C - -o "${tarball}" "${upstream}" \
|
|
407
|
+
|| curl ${curl_opts} -C - -o "${tarball}" "${mirror}"; \
|
|
408
|
+
if [ -n "${MESA_SHA256}" ]; then \
|
|
409
|
+
echo "${MESA_SHA256} ${tarball}" | sha256sum -c -; \
|
|
410
|
+
elif curl -fsSL --retry 3 --connect-timeout 15 -o SHA256SUMS "${sums_url}" \
|
|
411
|
+
&& grep -q " ${tarball}\$" SHA256SUMS; then \
|
|
412
|
+
sha256sum -c --ignore-missing SHA256SUMS; \
|
|
413
|
+
rm -f SHA256SUMS; \
|
|
414
|
+
else \
|
|
415
|
+
echo "WARNING: MESA_SHA256 build-arg empty and no SHA256SUMS asset reachable; ${tarball} digest verification skipped (offline local build)" >&2; \
|
|
416
|
+
rm -f SHA256SUMS; \
|
|
417
|
+
fi; \
|
|
418
|
+
echo "mesa ${MESA_VERSION} tarball ready"; \
|
|
419
|
+
tar xf "${tarball}"; \
|
|
420
|
+
meson setup /tmp/mesa-build "mesa-${MESA_VERSION}" \
|
|
421
|
+
--buildtype release \
|
|
422
|
+
-Dprefix=/usr \
|
|
423
|
+
-Dsysconfdir=/etc \
|
|
424
|
+
-Dplatforms=x11 \
|
|
425
|
+
-Dglx=dri \
|
|
426
|
+
-Degl=enabled \
|
|
427
|
+
-Dshared-glapi=enabled \
|
|
428
|
+
-Dllvm=enabled \
|
|
429
|
+
-Dgallium-drivers=llvmpipe \
|
|
430
|
+
-Dvulkan-drivers=swrast \
|
|
431
|
+
-Dgallium-rusticl=false \
|
|
432
|
+
-Dvideo-codecs=[] \
|
|
433
|
+
-Dtools=[] \
|
|
434
|
+
-Dvalgrind=disabled \
|
|
435
|
+
-Dlibunwind=disabled \
|
|
436
|
+
-Dlmsensors=disabled \
|
|
437
|
+
-Dzstd=enabled; \
|
|
438
|
+
ninja -C /tmp/mesa-build; \
|
|
439
|
+
DESTDIR=/staging ninja -C /tmp/mesa-build install; \
|
|
440
|
+
# Ensure /staging/etc exists even when rusticl is off (no OpenCL ICD
|
|
441
|
+
# installed); the runtime stage COPY --from=builder /staging/etc /etc/
|
|
442
|
+
# would fail the buildx cache checksum without this.
|
|
443
|
+
mkdir -p /staging/etc; \
|
|
444
|
+
find /staging -name '*.so*' | head -20
|
|
445
|
+
|
|
446
|
+
# the native sources, compiled directly per the build headers of each file
|
|
447
|
+
# (no cmake, no build system beyond the compiler): the spoofing core and
|
|
448
|
+
# the shim suite with -O3 -march -flto as mandated for the engine. the
|
|
449
|
+
# c++26 build first tries `import std;` and falls back to -DVHE_NO_MODULES
|
|
450
|
+
# when the toolchain ships no std module (libstdc++-14 on noble ships
|
|
451
|
+
# without one). virtualizationcore.cpp additionally builds its selftest
|
|
452
|
+
# binary and runs it: the stage fails if a single assert trips.
|
|
453
|
+
WORKDIR /src
|
|
454
|
+
COPY virtualhardware.c gpumonitor.cpp virtualizationcore.cpp /src/libs/
|
|
455
|
+
RUN set -eux; \
|
|
456
|
+
# portable baseline per architecture, with the ARCH FLAG the compiler
|
|
457
|
+
# family actually accepts: x86 and arm speak -march; the ppc64le gcc
|
|
458
|
+
# port rejects '-march=power8' ('did you mean -mcpu=power8?') so that
|
|
459
|
+
# architecture selects the -mcpu spelling; s390x accepts -march=z196.
|
|
460
|
+
archflag="-march"; \
|
|
461
|
+
case "${TARGETARCH}" in \
|
|
462
|
+
arm64|aarch64) march="armv8-a" ;; \
|
|
463
|
+
ppc64le) march="power8"; archflag="-mcpu" ;; \
|
|
464
|
+
s390x) march="z196" ;; \
|
|
465
|
+
*) march="x86-64" ;; \
|
|
466
|
+
esac; \
|
|
467
|
+
if [ -n "${VHE_MARCH}" ]; then march="${VHE_MARCH}"; archflag="-march"; fi; \
|
|
468
|
+
echo "building native shims with ${archflag}=${march}"; \
|
|
469
|
+
mkdir -p /out/usr/local/lib /out/usr/local/bin /out/engine/native /out/etc/virtual; \
|
|
470
|
+
gcc-14 -std=c11 -O3 "$archflag=$march" -flto -funswitch-loops \
|
|
471
|
+
-shared -fPIC -pthread -ldl \
|
|
472
|
+
/src/libs/virtualhardware.c -o /out/usr/local/lib/libvirtualhardware.so; \
|
|
473
|
+
build_cpp() { \
|
|
474
|
+
g++-14 -std=c++2c -O3 "$archflag=$march" -flto \
|
|
475
|
+
-DVHE_NO_MODULES "$@"; \
|
|
476
|
+
}; \
|
|
477
|
+
build_cpp -shared -fPIC -ldl -DVHE_BUILD_PRELOAD \
|
|
478
|
+
/src/libs/gpumonitor.cpp \
|
|
479
|
+
-o /out/usr/local/lib/libvirtualhardware_gpu.so; \
|
|
480
|
+
build_cpp -DVHE_BUILD_CLI /src/libs/gpumonitor.cpp \
|
|
481
|
+
-o /out/usr/local/bin/nvidia-smi; \
|
|
482
|
+
build_cpp -DVHE_BUILD_FORGE /src/libs/gpumonitor.cpp \
|
|
483
|
+
-o /out/usr/local/bin/aetherforge; \
|
|
484
|
+
build_cpp -shared -fPIC -DVHE_BUILD_ADDON \
|
|
485
|
+
-DNODE_GYP_MODULE_NAME=vhe_gpu -I/usr/include/node \
|
|
486
|
+
/src/libs/gpumonitor.cpp -o /out/engine/native/vhe_gpu.node; \
|
|
487
|
+
build_cpp -shared -fPIC -pthread \
|
|
488
|
+
/src/libs/virtualizationcore.cpp \
|
|
489
|
+
-o /out/usr/local/lib/libvirtualizationcore.so; \
|
|
490
|
+
build_cpp -DVHE_VIRT_SELFTEST /src/libs/virtualizationcore.cpp \
|
|
491
|
+
-o /tmp/virtualizationcore_selftest; \
|
|
492
|
+
/tmp/virtualizationcore_selftest; \
|
|
493
|
+
ls -la /out/usr/local/lib /out/usr/local/bin /out/engine/native; \
|
|
494
|
+
/out/usr/local/bin/nvidia-smi a100 1 | head -3; \
|
|
495
|
+
/out/usr/local/bin/aetherforge --smp 16 --mttg 64 --mem 64 | head -3
|
|
496
|
+
|
|
497
|
+
# the nvidia-ml and libcuda soname symlinks make pynvml, gpustat and
|
|
498
|
+
# dlopen("libnvidia-ml.so.1") consumers resolve to the shim without any
|
|
499
|
+
# LD_PRELOAD cooperation (rick-hsu/nvml-unified-shim deployment pattern).
|
|
500
|
+
RUN set -eux; \
|
|
501
|
+
ln -s libvirtualhardware_gpu.so /out/usr/local/lib/libnvidia-ml.so.1; \
|
|
502
|
+
ln -s libvirtualhardware_gpu.so /out/usr/local/lib/libcuda.so.1; \
|
|
503
|
+
ln -s libvirtualhardware_gpu.so /out/usr/local/lib/libnvidia-ml.so; \
|
|
504
|
+
ln -s libvirtualhardware_gpu.so /out/usr/local/lib/libcuda.so
|
|
505
|
+
|
|
506
|
+
# /etc/virtual holds only the profile-independent kernel identity
|
|
507
|
+
# files (version/uptime/loadavg) here; the profile-specific cpuinfo
|
|
508
|
+
# and meminfo are baked in the runtime stage so the builder layers
|
|
509
|
+
# stay profile-independent (buildx cache shared across max/balanced/lite).
|
|
510
|
+
RUN mkdir -p /out/etc/virtual
|
|
511
|
+
|
|
512
|
+
COPY <<'EOF' /out/etc/virtual/version
|
|
513
|
+
Linux version 6.18.0-vhe (vhe-builder@vhe) (clang version 19.1.0) #1 SMP VHE PREEMPT_DYNAMIC 2026-08-22
|
|
514
|
+
EOF
|
|
515
|
+
|
|
516
|
+
COPY <<'EOF' /out/etc/virtual/uptime
|
|
517
|
+
3600.00 2700.00
|
|
518
|
+
EOF
|
|
519
|
+
|
|
520
|
+
COPY <<'EOF' /out/etc/virtual/loadavg
|
|
521
|
+
3.84 3.12 2.98 12/768 28471
|
|
522
|
+
EOF
|
|
523
|
+
|
|
524
|
+
# ---------------------------------------------------------------------------
|
|
525
|
+
# stage 2: python-bridge (qemubridge.py carrier)
|
|
526
|
+
# ---------------------------------------------------------------------------
|
|
527
|
+
FROM ${PYTHON_BASE} AS python-bridge
|
|
528
|
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
529
|
+
PYTHONUNBUFFERED=1
|
|
530
|
+
|
|
531
|
+
# qemubridge.py is stdlib-only (asyncio, json, argparse, pathlib): the v2
|
|
532
|
+
# merge dropped the pip dependencies of the older saddle bridge stages
|
|
533
|
+
# (qemu-bridge/cffi wheels) because the bridge talks raw QMP over a unix
|
|
534
|
+
# socket without any native binding. the py_compile run is the syntax gate
|
|
535
|
+
# (error catcher: a bridge that does not compile fails the image build).
|
|
536
|
+
COPY qemubridge.py /bridge/qemubridge.py
|
|
537
|
+
RUN set -eux; \
|
|
538
|
+
python3 -m py_compile /bridge/qemubridge.py; \
|
|
539
|
+
python3 /bridge/qemubridge.py --help >/dev/null; \
|
|
540
|
+
python3 -c "import ast, sys; ast.parse(open('/bridge/qemubridge.py').read()); print('qemubridge ast ok')"
|
|
541
|
+
|
|
542
|
+
# ---------------------------------------------------------------------------
|
|
543
|
+
# stage 3: qemu (TCG/MTTCG engine, the vheqemu docker run recipe base)
|
|
544
|
+
# ---------------------------------------------------------------------------
|
|
545
|
+
FROM ${UBUNTU} AS qemu
|
|
546
|
+
ARG QEMU_VERSION
|
|
547
|
+
ARG QEMU_FROM_SOURCE="1"
|
|
548
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
549
|
+
|
|
550
|
+
# qemu 11.1.0 (released 2026-08-12) with the x86_64 system emulator only;
|
|
551
|
+
# KVM is auto-detected at runtime but the engine targets TCG with MTTCG
|
|
552
|
+
# (-accel tcg,thread=multi,tb-size=1024 -cpu EPYC-v5) because CI hosts and
|
|
553
|
+
# nested containers expose no /dev/kvm. when QEMU_FROM_SOURCE=0 (source
|
|
554
|
+
# build not viable, for example a constrained builder), the stage installs
|
|
555
|
+
# the distro qemu-system-x86 package instead; version drift is then the
|
|
556
|
+
# operator's tradeoff and is recorded in the image labels.
|
|
557
|
+
RUN set -eux; \
|
|
558
|
+
# mirror sync race: same retry loop as the builder stage, covering
|
|
559
|
+
# BOTH apt-get update AND apt-get install together so a 404 on install
|
|
560
|
+
# (stale Release index referencing .deb files already removed from the
|
|
561
|
+
# pool) re-fetches a fresh index and retries the install.
|
|
562
|
+
apt_update_tries=5; \
|
|
563
|
+
while [ "$apt_update_tries" -gt 0 ]; do \
|
|
564
|
+
if apt-get update && apt-get install -y --no-install-recommends \
|
|
565
|
+
ca-certificates curl xz-utils bzip2 \
|
|
566
|
+
build-essential ninja-build meson python3 python3-venv \
|
|
567
|
+
libglib2.0-dev libpixman-1-dev zlib1g-dev flex bison; then break; fi; \
|
|
568
|
+
apt_update_tries=$((apt_update_tries - 1)); \
|
|
569
|
+
echo "apt-get update/install failed (mirror sync?), $apt_update_tries retries left"; \
|
|
570
|
+
sleep 10; \
|
|
571
|
+
rm -rf /var/lib/apt/lists/*; \
|
|
572
|
+
done; \
|
|
573
|
+
test "$apt_update_tries" -gt 0; \
|
|
574
|
+
if [ "${QEMU_FROM_SOURCE}" = "1" ]; then \
|
|
575
|
+
curl -fsSLO "https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz"; \
|
|
576
|
+
tar xf "qemu-${QEMU_VERSION}.tar.xz"; \
|
|
577
|
+
cd "qemu-${QEMU_VERSION}"; \
|
|
578
|
+
./configure \
|
|
579
|
+
--target-list=x86_64-softmmu \
|
|
580
|
+
--disable-docs \
|
|
581
|
+
--disable-werror \
|
|
582
|
+
--disable-sdl \
|
|
583
|
+
--disable-gtk \
|
|
584
|
+
--disable-curl \
|
|
585
|
+
--disable-spice \
|
|
586
|
+
--disable-opengl; \
|
|
587
|
+
ninja -C build; \
|
|
588
|
+
ninja -C build install; \
|
|
589
|
+
qemu-system-x86_64 --version; \
|
|
590
|
+
cd /; rm -rf "/qemu-${QEMU_VERSION}"*; \
|
|
591
|
+
else \
|
|
592
|
+
apt-get install -y --no-install-recommends \
|
|
593
|
+
qemu-system-x86 qemu-utils; \
|
|
594
|
+
qemu-system-x86_64 --version; \
|
|
595
|
+
fi; \
|
|
596
|
+
apt-get purge -y --auto-remove \
|
|
597
|
+
build-essential ninja-build meson python3-venv flex bison \
|
|
598
|
+
libglib2.0-dev libpixman-1-dev zlib1g-dev \
|
|
599
|
+
|| true; \
|
|
600
|
+
apt-get clean; rm -rf /var/lib/apt/lists/*
|
|
601
|
+
|
|
602
|
+
ENTRYPOINT ["qemu-system-x86_64"]
|
|
603
|
+
|
|
604
|
+
# ---------------------------------------------------------------------------
|
|
605
|
+
# stage 4: qemu-runtime (guest runner: qemu + OVMF + pciutils + tini)
|
|
606
|
+
# ---------------------------------------------------------------------------
|
|
607
|
+
FROM qemu AS qemu-runtime
|
|
608
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
609
|
+
|
|
610
|
+
# the docker.config qemuRuntime role: QEMU system (already provided by
|
|
611
|
+
# the parent stage, either the 11.1.0 source build or the distro
|
|
612
|
+
# fallback), OVMF firmware, PCI utilities, curl for health probes, kmod
|
|
613
|
+
# for module loading and tini as pid 1 so guest processes are reaped when
|
|
614
|
+
# the guest runner restarts. when the parent used the source build the
|
|
615
|
+
# distro qemu packages stay absent; when it used the apt fallback the
|
|
616
|
+
# ovmf/pciutils set still installs identically.
|
|
617
|
+
RUN set -eux; \
|
|
618
|
+
# mirror sync race: same retry loop as the builder and qemu stages,
|
|
619
|
+
# covering BOTH apt-get update AND apt-get install together.
|
|
620
|
+
apt_update_tries=5; \
|
|
621
|
+
while [ "$apt_update_tries" -gt 0 ]; do \
|
|
622
|
+
if apt-get update && apt-get install -y --no-install-recommends \
|
|
623
|
+
ovmf pciutils curl kmod tini; then break; fi; \
|
|
624
|
+
apt_update_tries=$((apt_update_tries - 1)); \
|
|
625
|
+
echo "apt-get update/install failed (mirror sync?), $apt_update_tries retries left"; \
|
|
626
|
+
sleep 10; \
|
|
627
|
+
rm -rf /var/lib/apt/lists/*; \
|
|
628
|
+
done; \
|
|
629
|
+
test "$apt_update_tries" -gt 0; \
|
|
630
|
+
mkdir -p /usr/share/OVMF /var/log/vhe /run/vhe; \
|
|
631
|
+
ls -lh /usr/share/OVMF/OVMF_CODE.fd || true; \
|
|
632
|
+
apt-get clean; rm -rf /var/lib/apt/lists/*
|
|
633
|
+
|
|
634
|
+
ENTRYPOINT ["/usr/bin/tini", "--", "qemu-system-x86_64"]
|
|
635
|
+
|
|
636
|
+
# ---------------------------------------------------------------------------
|
|
637
|
+
# stage 5: runtime (final, default target, the vhe/vhegpu docker run recipes)
|
|
638
|
+
# ---------------------------------------------------------------------------
|
|
639
|
+
FROM ${UBUNTU} AS runtime
|
|
640
|
+
ARG TARGETARCH
|
|
641
|
+
ARG NODE_VERSION
|
|
642
|
+
ARG VHE_UID=10000
|
|
643
|
+
ARG VHE_GID=10000
|
|
644
|
+
ARG VHE_PROFILE_CPU
|
|
645
|
+
ARG VHE_PROFILE_VCPUS
|
|
646
|
+
ARG VHE_PROFILE_THREADS
|
|
647
|
+
ARG VHE_PROFILE_RAM_GB
|
|
648
|
+
ARG VHE_PROFILE_GPU
|
|
649
|
+
ARG VHE_PROFILE_GPUS
|
|
650
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
651
|
+
|
|
652
|
+
# runtime packages: Xvfb for the headless GLX display, x11-utils/xdpyinfo
|
|
653
|
+
# for the readiness probe, vulkan-tools (vulkaninfo), clinfo for the
|
|
654
|
+
# rusticl report, mesa-utils (glxinfo/es2_info), the ocl-icd loader for
|
|
655
|
+
# rusticl, python3 for the qmp bridge, procps for free/top inside the
|
|
656
|
+
# sandbox, and the shared libraries the mesa staging links against.
|
|
657
|
+
#
|
|
658
|
+
# The LLVM 18 runtime (libLLVM-18.so.1, which llvmpipe and lavapipe link
|
|
659
|
+
# against) is COPIED from the builder stage below instead of installed
|
|
660
|
+
# separately: the builder already has the full llvm-18-dev toolchain
|
|
661
|
+
# installed from the Ubuntu noble archive, so copying the lib tree is
|
|
662
|
+
# both faster (no apt round-trip) and keeps the runtime stage on the
|
|
663
|
+
# same LLVM version the mesa build linked against.
|
|
664
|
+
RUN set -eux; \
|
|
665
|
+
# mirror sync race: same retry loop as the builder and qemu stages,
|
|
666
|
+
# covering BOTH apt-get update AND apt-get install together so a 404
|
|
667
|
+
# on install (stale Release index referencing .deb files already
|
|
668
|
+
# removed from the pool) re-fetches a fresh index and retries.
|
|
669
|
+
# (this is the leg that failed on ppc64le in 1.2.12 and on s390x in
|
|
670
|
+
# 1.2.13 before this retry covered the install step too).
|
|
671
|
+
#
|
|
672
|
+
# base-image CVE closure: apt-get install only guarantees the listed
|
|
673
|
+
# packages - the ubuntu:24.04 base layer arrives with whatever system
|
|
674
|
+
# packages its digest carried (and a BuildKit registry cache hit can
|
|
675
|
+
# replay an even older layer chain), so perl-base, util-linux,
|
|
676
|
+
# ncurses, coreutils & friends can lag behind the published security
|
|
677
|
+
# fixes even right after a fresh build. The upgrade step pulls every
|
|
678
|
+
# installed base package to the latest security update resolved by
|
|
679
|
+
# the fresh index above (never installs new packages, never removes
|
|
680
|
+
# any - same-version upgrades only), and Always-Include-Phased-Updates
|
|
681
|
+
# skips Ubuntu's gradual phasing so CI builds are deterministic.
|
|
682
|
+
apt_update_tries=5; \
|
|
683
|
+
while [ "$apt_update_tries" -gt 0 ]; do \
|
|
684
|
+
if apt-get update && apt-get install -y --no-install-recommends \
|
|
685
|
+
ca-certificates curl gnupg bash procps \
|
|
686
|
+
xvfb x11-utils xauth x11-xserver-utils \
|
|
687
|
+
mesa-utils vulkan-tools clinfo ocl-icd-libopencl1 \
|
|
688
|
+
python3 \
|
|
689
|
+
libdrm2 libexpat1 zlib1g libzstd1 libedit2 libatomic1 \
|
|
690
|
+
libx11-6 libxext6 libxfixes3 libxxf86vm1 libxshmfence1 \
|
|
691
|
+
libxcb1 libwayland-client0 libwayland-egl1 libelf1 \
|
|
692
|
+
libglib2.0-0t64 libpixman-1-0 \
|
|
693
|
+
&& apt-get -o APT::Get::Always-Include-Phased-Updates=true \
|
|
694
|
+
upgrade -y; then break; fi; \
|
|
695
|
+
apt_update_tries=$((apt_update_tries - 1)); \
|
|
696
|
+
echo "apt-get update/install/upgrade failed (mirror sync?), $apt_update_tries retries left"; \
|
|
697
|
+
sleep 10; \
|
|
698
|
+
rm -rf /var/lib/apt/lists/*; \
|
|
699
|
+
done; \
|
|
700
|
+
test "$apt_update_tries" -gt 0; \
|
|
701
|
+
apt-get clean; rm -rf /var/lib/apt/lists/*
|
|
702
|
+
|
|
703
|
+
# LLVM 18 runtime: copy the entire llvm-18 install tree from the builder
|
|
704
|
+
# (libLLVM-18.so.1 + the llvm-18 runtime libraries that llvmpipe and
|
|
705
|
+
# lavapipe link against). The ldconfig step later in this stage adds
|
|
706
|
+
# /usr/lib/llvm-18/lib to the search path so the loader picks them up.
|
|
707
|
+
COPY --from=builder /usr/lib/llvm-18/ /usr/lib/llvm-18/
|
|
708
|
+
|
|
709
|
+
# mesa 26.2.1 from the staging root: dri drivers, the lavapipe vulkan ICD
|
|
710
|
+
# json (lvp_icd.<arch>.json), the rusticl opencl ICD under /etc/OpenCL and
|
|
711
|
+
# the shared glapi.
|
|
712
|
+
COPY --from=builder /staging/usr /usr/
|
|
713
|
+
COPY --from=builder /staging/etc /etc/
|
|
714
|
+
# node 26.7.0 carried over from the builder, including headers so native
|
|
715
|
+
# addons (vhe_gpu.node and downstream user addons) rebuild without a second
|
|
716
|
+
# nodesource round-trip.
|
|
717
|
+
COPY --from=builder /usr/bin/node /usr/bin/node
|
|
718
|
+
COPY --from=builder /usr/bin/npm /usr/bin/npm
|
|
719
|
+
COPY --from=builder /usr/bin/npx /usr/bin/npx
|
|
720
|
+
COPY --from=builder /usr/lib/node_modules /usr/lib/node_modules
|
|
721
|
+
COPY --from=builder /usr/include/node /usr/include/node
|
|
722
|
+
# the spoofing artifacts: preload core, gpu shim with the nvidia soname
|
|
723
|
+
# symlinks, the fake nvidia-smi binary, the aetherforge control plane, the
|
|
724
|
+
# virtualization core shared library, the napi addon and the baked
|
|
725
|
+
# /etc/virtual profile.
|
|
726
|
+
COPY --from=builder /out/usr/local/lib /usr/local/lib/
|
|
727
|
+
COPY --from=builder /out/usr/local/bin/nvidia-smi /usr/local/bin/nvidia-smi
|
|
728
|
+
COPY --from=builder /out/usr/local/bin/aetherforge /usr/local/bin/aetherforge
|
|
729
|
+
COPY --from=builder /out/engine /engine
|
|
730
|
+
COPY --from=builder /out/etc/virtual /etc/virtual
|
|
731
|
+
|
|
732
|
+
# /etc/virtual cpuinfo + meminfo baked per profile here in the runtime
|
|
733
|
+
# stage (the builder is profile-independent so its layers share the buildx
|
|
734
|
+
# cache across max/balanced/lite; the profile identity is baked here).
|
|
735
|
+
# cpuinfo model name, processor count and thread count per profile
|
|
736
|
+
# (max: AMD EPYC 9965 192c/384t, balanced: AMD Ryzen Threadripper
|
|
737
|
+
# Pro 9995WX 96c/192t, lite: AMD Ryzen 9 9950X3D 16c/32t); cpu
|
|
738
|
+
# family/model/stepping and address sizes match each identity
|
|
739
|
+
# (the desktop ryzen drops la57 and reports 46/48-bit addressing).
|
|
740
|
+
# meminfo static snapshot scaled to the profile memory plan (max 1 TiB,
|
|
741
|
+
# balanced 512 GiB, lite 128 GiB); the preload core regenerates
|
|
742
|
+
# a dynamic copy per process by default (fakemem pattern from
|
|
743
|
+
# VHE_TOTALRAM_GB), so this file is the VHE_MEMINFO_MODE=static
|
|
744
|
+
# source of truth and the fallback. VmallocTotal (the 64-bit
|
|
745
|
+
# address space) and Hugepagesize (the fixed 2 MiB huge page) stay
|
|
746
|
+
# constant regardless of the profile memory plan.
|
|
747
|
+
COPY <<'EOF' /tmp/meminfo-template
|
|
748
|
+
MemTotal: 1073741824 kB
|
|
749
|
+
MemFree: 33554432 kB
|
|
750
|
+
MemAvailable: 94673704 kB
|
|
751
|
+
Buffers: 8388608 kB
|
|
752
|
+
Cached: 58720256 kB
|
|
753
|
+
SwapCached: 0 kB
|
|
754
|
+
Active: 33554432 kB
|
|
755
|
+
Inactive: 16777216 kB
|
|
756
|
+
Active(anon): 20971520 kB
|
|
757
|
+
Inactive(anon): 4194304 kB
|
|
758
|
+
Active(file): 12582912 kB
|
|
759
|
+
Inactive(file): 12582912 kB
|
|
760
|
+
Unevictable: 0 kB
|
|
761
|
+
Mlocked: 0 kB
|
|
762
|
+
SwapTotal: 67108864 kB
|
|
763
|
+
SwapFree: 67108864 kB
|
|
764
|
+
Zswap: 0 kB
|
|
765
|
+
Zswapped: 0 kB
|
|
766
|
+
Dirty: 262144 kB
|
|
767
|
+
Writeback: 0 kB
|
|
768
|
+
AnonPages: 20971520 kB
|
|
769
|
+
Mapped: 4194304 kB
|
|
770
|
+
Shmem: 1048576 kB
|
|
771
|
+
KReclaimable: 2097152 kB
|
|
772
|
+
Slab: 4194304 kB
|
|
773
|
+
SReclaimable: 2097152 kB
|
|
774
|
+
SUnreclaim: 2097152 kB
|
|
775
|
+
KernelStack: 65536 kB
|
|
776
|
+
PageTables: 32768 kB
|
|
777
|
+
NFS_Unstable: 0 kB
|
|
778
|
+
Bounce: 0 kB
|
|
779
|
+
WritebackTmp: 0 kB
|
|
780
|
+
CommitLimit: 134217728 kB
|
|
781
|
+
Committed_AS: 33554432 kB
|
|
782
|
+
VmallocTotal: 34359738367 kB
|
|
783
|
+
VmallocUsed: 1048576 kB
|
|
784
|
+
VmallocChunk: 0 kB
|
|
785
|
+
Percpu: 65536 kB
|
|
786
|
+
HardwareCorrupted: 0 kB
|
|
787
|
+
AnonHugePages: 0 kB
|
|
788
|
+
ShmemHugePages: 0 kB
|
|
789
|
+
FileHugePages: 0 kB
|
|
790
|
+
HugePages_Total: 0
|
|
791
|
+
HugePages_Free: 0
|
|
792
|
+
HugePages_Rsvd: 0
|
|
793
|
+
HugePages_Surp: 0
|
|
794
|
+
Hugepagesize: 2048 kB
|
|
795
|
+
Hugetlb: 0 kB
|
|
796
|
+
DirectMap4k: 2097152 kB
|
|
797
|
+
DirectMap2M: 62914560 kB
|
|
798
|
+
DirectMap1G: 67108864 kB
|
|
799
|
+
EOF
|
|
800
|
+
|
|
801
|
+
RUN set -eux; \
|
|
802
|
+
: > /etc/virtual/cpuinfo; \
|
|
803
|
+
case "${VHE_PROFILE_CPU}" in \
|
|
804
|
+
epyc9965) \
|
|
805
|
+
cpuname="AMD EPYC 9965"; \
|
|
806
|
+
cpufamily="26"; cpumodel="96"; cpustepping="2"; \
|
|
807
|
+
addr="52 bits physical, 57 bits virtual"; la57="1" ;; \
|
|
808
|
+
threadripperpro9995wx) \
|
|
809
|
+
cpuname="AMD Ryzen Threadripper Pro 9995WX"; \
|
|
810
|
+
cpufamily="26"; cpumodel="96"; cpustepping="2"; \
|
|
811
|
+
addr="52 bits physical, 57 bits virtual"; la57="1" ;; \
|
|
812
|
+
ryzen9950x3d) \
|
|
813
|
+
cpuname="AMD Ryzen 9 9950X3D"; \
|
|
814
|
+
cpufamily="25"; cpumodel="97"; cpustepping="2"; \
|
|
815
|
+
addr="46 bits physical, 48 bits virtual"; la57="0" ;; \
|
|
816
|
+
*) \
|
|
817
|
+
echo "unknown VHE_PROFILE_CPU=${VHE_PROFILE_CPU}; expected epyc9965, threadripperpro9995wx or ryzen9950x3d" >&2; \
|
|
818
|
+
exit 1 ;; \
|
|
819
|
+
esac; \
|
|
820
|
+
vcpus="${VHE_PROFILE_VCPUS}"; \
|
|
821
|
+
threads="${VHE_PROFILE_THREADS}"; \
|
|
822
|
+
ram_gb="${VHE_PROFILE_RAM_GB}"; \
|
|
823
|
+
modelname="${cpuname} ${vcpus}-Core Processor"; \
|
|
824
|
+
FLAGS='fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good amd_lbr vnnm nonstop_tsc cpuid extd_apicid amd_dcm aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 invpcid_single hw_pstate ssbd mba perfmon_v2 ibrs ibpb stibp vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid movdiri movdir64b fsrm md_clear serialize tsxldtrk avx512_fp16'; \
|
|
825
|
+
if [ "$la57" = "1" ]; then FLAGS="${FLAGS} la57"; fi; \
|
|
826
|
+
for i in $(seq 0 $((vcpus - 1))); do \
|
|
827
|
+
{ \
|
|
828
|
+
printf 'processor\t: %d\n' "$i"; \
|
|
829
|
+
printf 'vendor_id\t: AuthenticAMD\n'; \
|
|
830
|
+
printf 'cpu family\t: %s\n' "$cpufamily"; \
|
|
831
|
+
printf 'model\t\t: %s\n' "$cpumodel"; \
|
|
832
|
+
printf 'model name\t: %s\n' "$modelname"; \
|
|
833
|
+
printf 'stepping\t: %s\n' "$cpustepping"; \
|
|
834
|
+
printf 'microcode\t: 0x1100140\n'; \
|
|
835
|
+
printf 'cpu MHz\t\t: 2250.000\n'; \
|
|
836
|
+
printf 'cache size\t: 512 KB\n'; \
|
|
837
|
+
printf 'physical id\t: 0\n'; \
|
|
838
|
+
printf 'siblings\t: %s\n' "$threads"; \
|
|
839
|
+
printf 'core id\t\t: %d\n' "$((i % vcpus))"; \
|
|
840
|
+
printf 'cpu cores\t: %s\n' "$vcpus"; \
|
|
841
|
+
printf 'apicid\t\t: %d\n' "$i"; \
|
|
842
|
+
printf 'initial apicid\t: %d\n' "$i"; \
|
|
843
|
+
printf 'fpu\t\t: yes\n'; \
|
|
844
|
+
printf 'fpu_exception\t: yes\n'; \
|
|
845
|
+
printf 'cpuid level\t: 16\n'; \
|
|
846
|
+
printf 'wp\t\t: yes\n'; \
|
|
847
|
+
printf 'flags\t\t: %s\n' "$FLAGS"; \
|
|
848
|
+
printf 'bugs\t\t: sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass srso\n'; \
|
|
849
|
+
printf 'bogomips\t: 4500.00\n'; \
|
|
850
|
+
printf 'TLB size\t: 3584 4K pages\n'; \
|
|
851
|
+
printf 'clflush size\t: 64\n'; \
|
|
852
|
+
printf 'cache_alignment\t: 64\n'; \
|
|
853
|
+
printf 'address sizes\t: %s\n' "$addr"; \
|
|
854
|
+
printf 'power management: ts ttp tm hwpstate cpb eff_freq_ro [13] [16]\n'; \
|
|
855
|
+
} >> /etc/virtual/cpuinfo; \
|
|
856
|
+
done; \
|
|
857
|
+
grep -c '^processor' /etc/virtual/cpuinfo | grep -qx "$vcpus"; \
|
|
858
|
+
total_kb=$((ram_gb * 1024 * 1024)); \
|
|
859
|
+
awk -v total="$total_kb" 'function scale(line, a, n, i, out, key) { n = split(line, a, " "); if (n >= 2 && a[n] == "kB" && (a[n-1]+0) > 0) { key = a[1]; if (key != "VmallocTotal:" && key != "Hugepagesize:") { a[n-1] = int((a[n-1]+0) * total / 1073741824); } } out = a[1]; for (i = 2; i <= n; i++) out = out " " a[i]; return out; } { print scale($0) }' /tmp/meminfo-template > /etc/virtual/meminfo; \
|
|
860
|
+
rm -f /tmp/meminfo-template; \
|
|
861
|
+
grep -E "^MemTotal: +${total_kb} kB" /etc/virtual/meminfo; \
|
|
862
|
+
echo "baked /etc/virtual: ${modelname} (${vcpus}c/${threads}t), MemTotal ${total_kb} kB (${ram_gb} GiB plan)"
|
|
863
|
+
# the python bridge from its dedicated stage.
|
|
864
|
+
COPY --from=python-bridge /bridge/qemubridge.py /engine/qemubridge.py
|
|
865
|
+
|
|
866
|
+
# the engine sources and the specification files consumed at runtime
|
|
867
|
+
# (docker.config "final" stage copies the whole tree; the flat layout
|
|
868
|
+
# keeps that a single COPY layer).
|
|
869
|
+
COPY *.ts package.json tsconfig.json biome.json jsdom.d.ts /engine/
|
|
870
|
+
COPY processors.json gpus.json cores.json boards.json vm.config.json virtualhardware.json /engine/
|
|
871
|
+
COPY qemu.config mttg.config passage.config docker.config /engine/
|
|
872
|
+
|
|
873
|
+
# the web node ships inside the main container: the mesh edition (auth,
|
|
874
|
+
# sqlite database, dashboard and the browser sandbox pages) runs from the
|
|
875
|
+
# same image, so one container serves the engine AND the web surface.
|
|
876
|
+
# run it with: docker run ghcr.io/wenathlan/saddle node /engine/web/server.js
|
|
877
|
+
COPY web /engine/web
|
|
878
|
+
|
|
879
|
+
RUN set -eux; \
|
|
880
|
+
chmod 0755 /usr/local/bin/nvidia-smi /usr/local/bin/aetherforge; \
|
|
881
|
+
chmod 0644 /etc/virtual/*; \
|
|
882
|
+
printf '/usr/lib/llvm-18/lib\n/usr/local/lib\n' > /etc/ld.so.conf.d/vhe.conf; \
|
|
883
|
+
mkdir -p /etc/OpenCL/vendors; \
|
|
884
|
+
case "${TARGETARCH}" in \
|
|
885
|
+
arm64|aarch64) ln -sf lvp_icd.aarch64.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
|
|
886
|
+
ppc64le) ln -sf lvp_icd.ppc64le.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
|
|
887
|
+
s390x) ln -sf lvp_icd.s390x.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
|
|
888
|
+
*) ln -sf lvp_icd.x86_64.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
|
|
889
|
+
esac; \
|
|
890
|
+
ldconfig; \
|
|
891
|
+
node --version; \
|
|
892
|
+
python3 -m py_compile /engine/qemubridge.py; \
|
|
893
|
+
nvidia-smi b200 1 | head -2; \
|
|
894
|
+
ldconfig -p | grep -E 'libGL|lvp|rusticl|libLLVM-18' | head -5
|
|
895
|
+
|
|
896
|
+
# entrypoint: starts Xvfb on :99, validates the GL/Vulkan/OpenCL stack
|
|
897
|
+
# and execs the engine command. the bootstrap is EMBEDDED HERE (the one
|
|
898
|
+
# container file standard - the repository keeps no separate
|
|
899
|
+
# entrypoint.sh): the heredoc COPY below writes the script verbatim
|
|
900
|
+
# into the image and the quoted delimiter keeps every shell expansion
|
|
901
|
+
# literal, so the file is the exact former entrypoint.sh.
|
|
902
|
+
COPY <<'ENTRYPOINT_SCRIPT_EOF' /entrypoint.sh
|
|
903
|
+
#!/usr/bin/env bash
|
|
904
|
+
#
|
|
905
|
+
# entrypoint.sh - runtime bootstrap for the saddle virtual hardware
|
|
906
|
+
# engine image.
|
|
907
|
+
#
|
|
908
|
+
# responsibilities, in order:
|
|
909
|
+
# 0. print the engine banner, pin the MTTCG mode for downstream
|
|
910
|
+
# consumers, export the gallium/mesa environment overrides that are
|
|
911
|
+
# unique to the headless software stack, and report the firecracker
|
|
912
|
+
# warm-pool readiness note (the microvm runtime shares this image).
|
|
913
|
+
# 1. start Xvfb on display :99 with the validated headless-GLX recipe
|
|
914
|
+
# (Xvfb(1): -ac disables access control, -screen 0 1920x1080x24
|
|
915
|
+
# defines the framebuffer, -nolisten tcp closes the network surface,
|
|
916
|
+
# +extension GLX +render enable the GLX and RENDER extensions the
|
|
917
|
+
# mesa llvmpipe driver expects, -noreset keeps the server alive
|
|
918
|
+
# after the last client disconnects) and wait for readiness with
|
|
919
|
+
# xdpyinfo.
|
|
920
|
+
# 2. verify the LD_PRELOAD spoofing core is installed and loadable
|
|
921
|
+
# (global /etc/ld.so.preload from the dolos deployment pattern).
|
|
922
|
+
# 3. run the hardware validation heads: glxinfo (OpenGL renderer must
|
|
923
|
+
# be llvmpipe), vulkaninfo --summary (lavapipe ICD) and clinfo
|
|
924
|
+
# (rusticl reporting a gpu device on OpenCL 3.1); failures log
|
|
925
|
+
# warnings unless VHE_STRICT=1 turns them fatal.
|
|
926
|
+
# 4. allocate a random listening port in 30000-60000 when VHE_PORT/PORT
|
|
927
|
+
# is unset (shuf with a /dev/urandom fallback), so no host port is
|
|
928
|
+
# ever hardcoded across the engine.
|
|
929
|
+
# 5. exec "$@" so the engine becomes pid 1 and receives signals
|
|
930
|
+
# directly.
|
|
931
|
+
#
|
|
932
|
+
# environment knobs (all optional):
|
|
933
|
+
# VHE_DISPLAY x display number, default 99
|
|
934
|
+
# VHE_SCREEN screen geometry, default 1920x1080x24
|
|
935
|
+
# VHE_XVFB_WAIT max seconds waiting for the display, default 30
|
|
936
|
+
# VHE_SKIP_XVFB 1 skips display startup entirely (pure compute)
|
|
937
|
+
# VHE_SKIP_PRELOAD 1 skips the spoofing core check
|
|
938
|
+
# VHE_SKIP_VALIDATE 1 skips the glxinfo/vulkaninfo/clinfo probes
|
|
939
|
+
# VHE_STRICT 1 turns validation failures into entrypoint failures
|
|
940
|
+
# VHE_PORT / PORT fixed port; otherwise one is drawn from 30000-60000
|
|
941
|
+
# VHE_DEBUG 1 prints every decision to stderr
|
|
942
|
+
#
|
|
943
|
+
# the script never exits on validation warnings: the engine degrades to
|
|
944
|
+
# whatever hardware surface is actually functional, mirroring the
|
|
945
|
+
# defensive fallback chain of libvirtualhardware.so itself.
|
|
946
|
+
|
|
947
|
+
set -Eeuo pipefail
|
|
948
|
+
|
|
949
|
+
# ---------------------------------------------------------------- logging --
|
|
950
|
+
|
|
951
|
+
log() { printf '[saddle-entrypoint] %s\n' "$*" >&2; }
|
|
952
|
+
dbg() { [[ "${VHE_DEBUG:-0}" == "1" ]] && printf '[saddle-entrypoint:debug] %s\n' "$*" >&2 || true; }
|
|
953
|
+
warn() { printf '[saddle-entrypoint:warn] %s\n' "$*" >&2; }
|
|
954
|
+
die() { printf '[saddle-entrypoint:fatal] %s\n' "$*" >&2; exit 1; }
|
|
955
|
+
|
|
956
|
+
# ------------------------------------------------------------- variables --
|
|
957
|
+
|
|
958
|
+
vdisplaynum="${VHE_DISPLAY:-99}"
|
|
959
|
+
vdisplayid=":${vdisplaynum}"
|
|
960
|
+
screengeom="${VHE_SCREEN:-1920x1080x24}"
|
|
961
|
+
xvfbwait="${VHE_XVFB_WAIT:-30}"
|
|
962
|
+
xvfbpid=""
|
|
963
|
+
portvalue=""
|
|
964
|
+
|
|
965
|
+
cleanup() {
|
|
966
|
+
if [[ -n "${xvfbpid}" ]] && kill -0 "${xvfbpid}" 2>/dev/null; then
|
|
967
|
+
log "stopping Xvfb (pid ${xvfbpid})"
|
|
968
|
+
kill -TERM "${xvfbpid}" 2>/dev/null || true
|
|
969
|
+
wait "${xvfbpid}" 2>/dev/null || true
|
|
970
|
+
fi
|
|
971
|
+
}
|
|
972
|
+
trap cleanup EXIT
|
|
973
|
+
trap 'die "interrupted"' INT TERM
|
|
974
|
+
|
|
975
|
+
requirebin() {
|
|
976
|
+
command -v "$1" >/dev/null 2>&1 || die "required binary '$1' not found in PATH"
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
# ------------------------------------------- 0. banner and env overrides --
|
|
980
|
+
|
|
981
|
+
# report the baked profile identity (read from /etc/virtual so the banner
|
|
982
|
+
# matches the profile the image was built for: max/balanced/lite). Single
|
|
983
|
+
# awk process with an early exit per file (no sed|head pipeline: under
|
|
984
|
+
# set -o pipefail, head exiting after the first match would SIGPIPE sed on
|
|
985
|
+
# the large max/balanced cpuinfo and abort the entrypoint).
|
|
986
|
+
vhe_model="$(awk '/^model name/ { sub(/^[[:space:]]*model name[[:space:]]*:[[:space:]]*/, ""); print; exit }' /etc/virtual/cpuinfo 2>/dev/null)"
|
|
987
|
+
vhe_ram="$(awk '/^MemTotal/ { print $2; exit }' /etc/virtual/meminfo 2>/dev/null || true)"
|
|
988
|
+
case "${vhe_ram}" in *[!0-9]*) vhe_ram="" ;; esac
|
|
989
|
+
if [ -n "${vhe_model}" ] && [ -n "${vhe_ram}" ]; then
|
|
990
|
+
vhe_ram_gb=$(( vhe_ram / 1024 / 1024 ))
|
|
991
|
+
log "saddle virtual hardware engine (${vhe_model}, ${vhe_ram_gb} GiB, mesa 26.2.1)"
|
|
992
|
+
else
|
|
993
|
+
log "saddle virtual hardware engine (mesa 26.2.1)"
|
|
994
|
+
fi
|
|
995
|
+
log "docker contract: memory-swap=-1 shm-size=2g tmpfs shader cache 20G, Xvfb ${vdisplayid}"
|
|
996
|
+
|
|
997
|
+
# MTTCG is the default execution mode for the qemu layer of this stack:
|
|
998
|
+
# one host thread per vCPU, selected by -accel tcg,thread=multi. the flag
|
|
999
|
+
# is exported so child orchestrators (qemubridge.py, the aetherforge
|
|
1000
|
+
# control plane) observe a consistent default without re-deriving it.
|
|
1001
|
+
export QEMU_MTTCG="${QEMU_MTTCG:-1}"
|
|
1002
|
+
|
|
1003
|
+
# gallium/mesa overrides: keep the software rasterizer pinned even when
|
|
1004
|
+
# the base image environment is overridden by the operator, and expose
|
|
1005
|
+
# the avx-512 cpu caps list the llvmpipe JIT keys on. these lines are the
|
|
1006
|
+
# deployment counterpart of the ENV block baked in the Dockerfile.
|
|
1007
|
+
export LP_NATIVE_VECTOR_WIDTH="${LP_NATIVE_VECTOR_WIDTH:-512}"
|
|
1008
|
+
export LP_NUM_THREADS="${LP_NUM_THREADS:-0}"
|
|
1009
|
+
export GALLIUM_DRIVER="${GALLIUM_DRIVER:-llvmpipe}"
|
|
1010
|
+
export MESA_GL_VERSION_OVERRIDE="${MESA_GL_VERSION_OVERRIDE:-4.6}"
|
|
1011
|
+
export GALLIUM_OVERRIDE_CPU_CAPS="${GALLIUM_OVERRIDE_CPU_CAPS:-avx512f,avx512bw,avx512cd,avx512dq,avx512vl,avx512vnni,avx512_bf16}"
|
|
1012
|
+
export LD_PRELOAD="/usr/local/lib/libvirtualhardware.so${LD_PRELOAD:+:${LD_PRELOAD}}"
|
|
1013
|
+
|
|
1014
|
+
# the microvm runtime shares this image: the firecracker warm pool boots
|
|
1015
|
+
# in 125 ms (150 boots/s, 3-5 ms restore from a snapshot) and needs no
|
|
1016
|
+
# additional daemon here - the note keeps operators from expecting one.
|
|
1017
|
+
dbg "firecracker warm pool ready (125 ms boot, 3-5 ms restore)"
|
|
1018
|
+
|
|
1019
|
+
# ------------------------------------------------------ 1. display setup --
|
|
1020
|
+
|
|
1021
|
+
if [[ "${VHE_SKIP_XVFB:-0}" == "1" ]]; then
|
|
1022
|
+
log "VHE_SKIP_XVFB=1, skipping display startup"
|
|
1023
|
+
else
|
|
1024
|
+
requirebin Xvfb
|
|
1025
|
+
requirebin xdpyinfo
|
|
1026
|
+
|
|
1027
|
+
if xdpyinfo -display "${vdisplayid}" >/dev/null 2>&1; then
|
|
1028
|
+
log "display ${vdisplayid} already answering, reusing it"
|
|
1029
|
+
else
|
|
1030
|
+
log "starting Xvfb on ${vdisplayid} (${screengeom})"
|
|
1031
|
+
Xvfb "${vdisplayid}" \
|
|
1032
|
+
-ac \
|
|
1033
|
+
-screen 0 "${screengeom}" \
|
|
1034
|
+
-nolisten tcp \
|
|
1035
|
+
+extension GLX \
|
|
1036
|
+
+render \
|
|
1037
|
+
-noreset &
|
|
1038
|
+
xvfbpid=$!
|
|
1039
|
+
|
|
1040
|
+
waited=0
|
|
1041
|
+
until xdpyinfo -display "${vdisplayid}" >/dev/null 2>&1; do
|
|
1042
|
+
if ! kill -0 "${xvfbpid}" 2>/dev/null; then
|
|
1043
|
+
die "Xvfb died during startup"
|
|
1044
|
+
fi
|
|
1045
|
+
if [[ "${waited}" -ge "${xvfbwait}" ]]; then
|
|
1046
|
+
die "Xvfb not ready after ${xvfbwait}s on ${vdisplayid}"
|
|
1047
|
+
fi
|
|
1048
|
+
waited=$((waited + 1))
|
|
1049
|
+
sleep 1
|
|
1050
|
+
done
|
|
1051
|
+
log "Xvfb ready on ${vdisplayid} after ${waited}s (pid ${xvfbpid})"
|
|
1052
|
+
fi
|
|
1053
|
+
export DISPLAY="${vdisplayid}"
|
|
1054
|
+
fi
|
|
1055
|
+
|
|
1056
|
+
# ------------------------------------------------- 2. preload core check --
|
|
1057
|
+
|
|
1058
|
+
if [[ "${VHE_SKIP_PRELOAD:-0}" != "1" ]]; then
|
|
1059
|
+
preloadlib="/usr/local/lib/libvirtualhardware.so"
|
|
1060
|
+
if [[ ! -r "${preloadlib}" ]]; then
|
|
1061
|
+
die "spoofing core ${preloadlib} missing from the image"
|
|
1062
|
+
fi
|
|
1063
|
+
if ! LD_PRELOAD="${preloadlib}" /bin/true 2>/dev/null; then
|
|
1064
|
+
die "spoofing core ${preloadlib} is not loadable in this environment"
|
|
1065
|
+
fi
|
|
1066
|
+
if [[ -f /etc/ld.so.preload ]] && grep -q 'libvirtualhardware' /etc/ld.so.preload; then
|
|
1067
|
+
dbg "/etc/ld.so.preload carries the core (dolos global install)"
|
|
1068
|
+
else
|
|
1069
|
+
warn "/etc/ld.so.preload does not list libvirtualhardware.so; per-process spoofing only"
|
|
1070
|
+
fi
|
|
1071
|
+
if [[ -r /etc/virtual/cpuinfo ]]; then
|
|
1072
|
+
dbg "virtual cpuinfo present ($(grep -c '^processor' /etc/virtual/cpuinfo) processors)"
|
|
1073
|
+
else
|
|
1074
|
+
warn "/etc/virtual/cpuinfo missing; cpu reads fall through to the real host"
|
|
1075
|
+
fi
|
|
1076
|
+
if [[ -r /etc/virtual/meminfo ]]; then
|
|
1077
|
+
dbg "virtual meminfo present: $(head -1 /etc/virtual/meminfo)"
|
|
1078
|
+
else
|
|
1079
|
+
warn "/etc/virtual/meminfo missing; memory reads fall through to the real host"
|
|
1080
|
+
fi
|
|
1081
|
+
fi
|
|
1082
|
+
|
|
1083
|
+
# ------------------------------------------------- 3. stack validation --
|
|
1084
|
+
|
|
1085
|
+
if [[ "${VHE_SKIP_VALIDATE:-0}" != "1" ]]; then
|
|
1086
|
+
validationfailed=0
|
|
1087
|
+
|
|
1088
|
+
if command -v glxinfo >/dev/null 2>&1; then
|
|
1089
|
+
if renderer="$(glxinfo -B 2>/dev/null | sed -n 's/^OpenGL renderer string: //p' | head -1)"; then
|
|
1090
|
+
if [[ -n "${renderer}" ]]; then
|
|
1091
|
+
log "glxinfo: ${renderer}"
|
|
1092
|
+
if [[ "${renderer}" != *llvmpipe* ]]; then
|
|
1093
|
+
warn "OpenGL renderer is not llvmpipe: ${renderer}"
|
|
1094
|
+
fi
|
|
1095
|
+
fi
|
|
1096
|
+
else
|
|
1097
|
+
warn "glxinfo failed on display ${DISPLAY:-unset}"
|
|
1098
|
+
validationfailed=1
|
|
1099
|
+
fi
|
|
1100
|
+
else
|
|
1101
|
+
warn "glxinfo not available (mesa-utils missing), skipping GL probe"
|
|
1102
|
+
fi
|
|
1103
|
+
|
|
1104
|
+
if command -v vulkaninfo >/dev/null 2>&1; then
|
|
1105
|
+
if api="$(VULKANINFO_LOADER_DEBUG="" vulkaninfo --summary 2>/dev/null | sed -n 's/^.*apiVersion.*: *//p' | head -1)"; then
|
|
1106
|
+
log "vulkaninfo: api ${api:-reported} through ${VK_DRIVER_FILES:-default ICD search}"
|
|
1107
|
+
else
|
|
1108
|
+
warn "vulkaninfo --summary failed (check VK_DRIVER_FILES=${VK_DRIVER_FILES:-unset})"
|
|
1109
|
+
validationfailed=1
|
|
1110
|
+
fi
|
|
1111
|
+
else
|
|
1112
|
+
warn "vulkaninfo not available (vulkan-tools missing), skipping Vulkan probe"
|
|
1113
|
+
fi
|
|
1114
|
+
|
|
1115
|
+
if command -v clinfo >/dev/null 2>&1; then
|
|
1116
|
+
clhead="$(clinfo 2>/dev/null | grep -E 'Platform Name|Device Type|OpenCL C Version' | head -3 || true)"
|
|
1117
|
+
if [[ -n "${clhead}" ]]; then
|
|
1118
|
+
log "clinfo: $(echo "${clhead}" | tr '\n' ' ')"
|
|
1119
|
+
else
|
|
1120
|
+
warn "clinfo produced no platform report (rusticl ICD not reachable)"
|
|
1121
|
+
validationfailed=1
|
|
1122
|
+
fi
|
|
1123
|
+
else
|
|
1124
|
+
warn "clinfo not available, skipping OpenCL probe"
|
|
1125
|
+
fi
|
|
1126
|
+
|
|
1127
|
+
if command -v nvidia-smi >/dev/null 2>&1; then
|
|
1128
|
+
log "nvidia-smi virtual identity: $(nvidia-smi "${VHE_GPU_PROFILE:-a100}" 1 2>/dev/null | sed -n '2p' | cut -c1-60)..."
|
|
1129
|
+
else
|
|
1130
|
+
warn "virtual nvidia-smi adapter not on PATH"
|
|
1131
|
+
fi
|
|
1132
|
+
|
|
1133
|
+
if [[ "${validationfailed}" != "0" && "${VHE_STRICT:-0}" == "1" ]]; then
|
|
1134
|
+
die "VHE_STRICT=1 and the validation reported failures"
|
|
1135
|
+
fi
|
|
1136
|
+
fi
|
|
1137
|
+
|
|
1138
|
+
# --------------------------------------------------- 4. port allocation --
|
|
1139
|
+
|
|
1140
|
+
if [[ -z "${VHE_PORT:-}" && -z "${PORT:-}" ]]; then
|
|
1141
|
+
if command -v shuf >/dev/null 2>&1; then
|
|
1142
|
+
portvalue="$(shuf -i 30000-60000 -n 1)"
|
|
1143
|
+
elif [[ -r /dev/urandom ]]; then
|
|
1144
|
+
# deterministic fallback: urandom bytes scaled into the 30000-60000 range
|
|
1145
|
+
portvalue="$(( 30000 + ($(od -An -N2 -tu2 /dev/urandom | tr -d ' ') % 30001) ))"
|
|
1146
|
+
else
|
|
1147
|
+
portvalue="$(( 30000 + (RANDOM % 30001) ))"
|
|
1148
|
+
fi
|
|
1149
|
+
log "no port configured, allocated random port ${portvalue} (range 30000-60000)"
|
|
1150
|
+
elif [[ -n "${VHE_PORT:-}" ]]; then
|
|
1151
|
+
portvalue="${VHE_PORT}"
|
|
1152
|
+
log "using VHE_PORT=${portvalue}"
|
|
1153
|
+
else
|
|
1154
|
+
portvalue="${PORT}"
|
|
1155
|
+
log "using PORT=${portvalue}"
|
|
1156
|
+
fi
|
|
1157
|
+
export PORT="${portvalue}"
|
|
1158
|
+
export VHE_PORT="${portvalue}"
|
|
1159
|
+
|
|
1160
|
+
# ----------------------------------------------------------- 5. exec app --
|
|
1161
|
+
|
|
1162
|
+
log "environment ready: display=${DISPLAY:-none} port=${portvalue} profile=${VHE_GPU_PROFILE:-a100} gpus=${VHE_GPUS:-8} ram=${VHE_TOTALRAM_GB:-128}GiB cpus=${VHE_CPUS:-192} mttcg=${QEMU_MTTCG}"
|
|
1163
|
+
|
|
1164
|
+
if [[ $# -eq 0 ]]; then
|
|
1165
|
+
log "no command supplied, keeping the sandbox alive (exec /bin/bash)"
|
|
1166
|
+
set -- /bin/bash
|
|
1167
|
+
fi
|
|
1168
|
+
|
|
1169
|
+
# exec replaces this shell: Xvfb keeps running as an orphan supervised by
|
|
1170
|
+
# the container init (docker --init / compose init: true), and the engine
|
|
1171
|
+
# receives signals directly as the foreground process.
|
|
1172
|
+
exec "$@"
|
|
1173
|
+
ENTRYPOINT_SCRIPT_EOF
|
|
1174
|
+
RUN chmod 0755 /entrypoint.sh
|
|
1175
|
+
|
|
1176
|
+
# environment: software GL stack pinning (llvmpipe), GL 4.6 spoof, AVX-512
|
|
1177
|
+
# vector width for the gallivm JIT, single-threaded rasterization by
|
|
1178
|
+
# default to avoid container oversubscription (raise LP_NUM_THREADS to the
|
|
1179
|
+
# vCPU count for throughput), the gallium cpu caps override list, lavapipe
|
|
1180
|
+
# as the only vulkan ICD (VK_DRIVER_FILES; VK_ICD_FILENAMES is deprecated),
|
|
1181
|
+
# rusticl on llvmpipe reporting a gpu device on OpenCL 3.1, display :99 for
|
|
1182
|
+
# Xvfb, plus the default virtual profile knobs consumed by
|
|
1183
|
+
# libvirtualhardware and the former compose service settings merged
|
|
1184
|
+
# here (the web node database SADDLE_DB the recipes bind their webdata
|
|
1185
|
+
# volume at, and NODE_ENV).
|
|
1186
|
+
ENV LIBGL_ALWAYS_SOFTWARE="true" \
|
|
1187
|
+
GALLIUM_DRIVER="llvmpipe" \
|
|
1188
|
+
MESA_GL_VERSION_OVERRIDE="4.6" \
|
|
1189
|
+
MESA_GLSL_VERSION_OVERRIDE="460" \
|
|
1190
|
+
GALLIUM_OVERRIDE_CPU_CAPS="avx512f,avx512bw,avx512cd,avx512dq,avx512vl,avx512vnni,avx512_bf16" \
|
|
1191
|
+
LP_NATIVE_VECTOR_WIDTH="512" \
|
|
1192
|
+
LP_NUM_THREADS="0" \
|
|
1193
|
+
VK_DRIVER_FILES="/usr/share/vulkan/icd.d/lvp_icd.json" \
|
|
1194
|
+
RUSTICL_ENABLE="llvmpipe" \
|
|
1195
|
+
RUSTICL_DEVICE_TYPE="gpu" \
|
|
1196
|
+
RUSTICL_CL_VERSION="3.1" \
|
|
1197
|
+
MESA_SHADER_CACHE_DIR="/cache/mesa_shader_cache" \
|
|
1198
|
+
MESA_SHADER_CACHE_MAX_SIZE="20G" \
|
|
1199
|
+
DISPLAY=":99" \
|
|
1200
|
+
VHE_TOTALRAM_GB="${VHE_PROFILE_RAM_GB}" \
|
|
1201
|
+
VHE_CPUS="${VHE_PROFILE_VCPUS}" \
|
|
1202
|
+
VHE_KERNEL_RELEASE="6.18.0-vhe" \
|
|
1203
|
+
VHE_GPU_PROFILE="${VHE_PROFILE_GPU}" \
|
|
1204
|
+
VHE_GPUS="${VHE_PROFILE_GPUS}" \
|
|
1205
|
+
VHE_MEMINFO_REFRESH="5" \
|
|
1206
|
+
SADDLE_DB="/data/web/saddle.db" \
|
|
1207
|
+
NODE_ENV="production" \
|
|
1208
|
+
PATH="/engine/native:${PATH}"
|
|
1209
|
+
|
|
1210
|
+
# non-root runtime identity; uid/gid 10000 avoids collisions with host
|
|
1211
|
+
# accounts on bind mounts and matches the volume and tmpfs ownership
|
|
1212
|
+
# (the former compose shader-cache volume carried uid=10000,gid=10000).
|
|
1213
|
+
RUN set -eux; \
|
|
1214
|
+
groupadd --gid "${VHE_GID}" vhe; \
|
|
1215
|
+
useradd --uid "${VHE_UID}" --gid "${VHE_GID}" --create-home \
|
|
1216
|
+
--shell /bin/bash vhe; \
|
|
1217
|
+
mkdir -p /engine /cache/mesa_shader_cache /data/vmdata /data/web; \
|
|
1218
|
+
chown -R vhe:vhe /engine /cache /data; \
|
|
1219
|
+
chmod 0777 /cache/mesa_shader_cache
|
|
1220
|
+
|
|
1221
|
+
# global preload installation, written last so no image-build step after
|
|
1222
|
+
# this point runs under the interposer (dolos deployment pattern); setuid
|
|
1223
|
+
# binaries ignore /etc/ld.so.preload by loader design.
|
|
1224
|
+
RUN set -eux; \
|
|
1225
|
+
echo /usr/local/lib/libvirtualhardware.so > /etc/ld.so.preload; \
|
|
1226
|
+
cat /proc/meminfo | head -1; \
|
|
1227
|
+
free -m | head -2 || true
|
|
1228
|
+
|
|
1229
|
+
# healthcheck: the X display answers xdpyinfo and the virtual meminfo is in
|
|
1230
|
+
# place; start-period covers the Xvfb + shader-cache warmup. start-interval
|
|
1231
|
+
# probes every 5s during the grace window (compose 5.5.0 / docker 29.7.2
|
|
1232
|
+
# support the field).
|
|
1233
|
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --start-interval=5s --retries=3 \
|
|
1234
|
+
CMD xdpyinfo -display :99 >/dev/null 2>&1 \
|
|
1235
|
+
&& grep -q 'MemTotal' /etc/virtual/meminfo \
|
|
1236
|
+
|| exit 1
|
|
1237
|
+
|
|
1238
|
+
# OCI labels for registry introspection.
|
|
1239
|
+
LABEL org.opencontainers.image.title="saddle virtual-hardware engine (the grand merge)" \
|
|
1240
|
+
org.opencontainers.image.description="100% software virtual hardware: per-profile CPU/memory spoofing via LD_PRELOAD (max/balanced/lite), mesa 26.2.1 llvmpipe/lavapipe/rusticl, QEMU 11.1.0 TCG/MTTCG, virtual nvidia-smi adapter + NVML/CUDA shims, node 26.7.0, python bridge" \
|
|
1241
|
+
org.opencontainers.image.version="2.0.2" \
|
|
1242
|
+
org.opencontainers.image.licenses="MIT" \
|
|
1243
|
+
org.opencontainers.image.source="https://github.com/wenathlan/saddle" \
|
|
1244
|
+
org.opencontainers.image.documentation="https://github.com/wenathlan/saddle/blob/main/README.md" \
|
|
1245
|
+
org.opencontainers.image.created="2026-08-23T00:00:00Z"
|
|
1246
|
+
|
|
1247
|
+
WORKDIR /engine
|
|
1248
|
+
USER vhe
|
|
1249
|
+
STOPSIGNAL SIGTERM
|
|
1250
|
+
|
|
1251
|
+
# EXPOSE 8080: the engine service port of the docker run recipe above
|
|
1252
|
+
# (the former compose VHE_ENGINE_PORT default, published as 31280:8080).
|
|
1253
|
+
# a bare docker run without -e PORT leaves the embedded entrypoint
|
|
1254
|
+
# picking a random port in 30000-60000, so nothing here hardcodes a
|
|
1255
|
+
# bind - EXPOSE documents the recipe.
|
|
1256
|
+
EXPOSE 8080
|
|
1257
|
+
|
|
1258
|
+
# the state surface of the docker run recipes (the former compose named
|
|
1259
|
+
# volumes): /data carries vmdata (virtual machine images, bridge plans)
|
|
1260
|
+
# and webdata (the web node sqlite SADDLE_DB points at);
|
|
1261
|
+
# /cache/mesa_shader_cache keeps the JIT'd llvmpipe/lavapipe shaders
|
|
1262
|
+
# off the overlay filesystem (the recipe mounts a 20g tmpfs there).
|
|
1263
|
+
# without an explicit -v docker provisions anonymous volumes at these
|
|
1264
|
+
# paths so the state never lives in the container layer.
|
|
1265
|
+
VOLUME /data /cache/mesa_shader_cache
|
|
1266
|
+
|
|
1267
|
+
# the embedded bootstrap (the heredoc COPY above) starts Xvfb on :99,
|
|
1268
|
+
# validates the GL/Vulkan/OpenCL stack and execs the engine command as
|
|
1269
|
+
# pid 1.
|
|
1270
|
+
ENTRYPOINT ["/entrypoint.sh"]
|
|
1271
|
+
|
|
1272
|
+
# ══════════════════════════════════════════════════════════════════════
|
|
1273
|
+
# saddle node-engine stages — the storage/compute node service of the
|
|
1274
|
+
# grand merge (folded verbatim from the former dockerfile.saddle: the
|
|
1275
|
+
# hardened npm pinning survives; the build outputs dist/<domain>.js after
|
|
1276
|
+
# the flat consolidation). build explicitly:
|
|
1277
|
+
# docker build --target saddle-runtime -t saddle:<version> .
|
|
1278
|
+
# ══════════════════════════════════════════════════════════════════════
|
|
1279
|
+
|
|
1280
|
+
FROM node:26.8.1-bookworm-slim AS saddle-build
|
|
1281
|
+
|
|
1282
|
+
ARG SADDLE_VERSION
|
|
1283
|
+
WORKDIR /app
|
|
1284
|
+
|
|
1285
|
+
ENV NPM_CONFIG_LEGACY_PEER_DEPS=true
|
|
1286
|
+
|
|
1287
|
+
COPY package.json package-lock.json ./
|
|
1288
|
+
RUN npm ci --ignore-scripts --legacy-peer-deps
|
|
1289
|
+
COPY . .
|
|
1290
|
+
RUN npm run build:engine \
|
|
1291
|
+
&& node --check dist/cli.js
|
|
1292
|
+
|
|
1293
|
+
FROM node:26.8.1-bookworm-slim AS saddle-runtime
|
|
1294
|
+
|
|
1295
|
+
ARG SADDLE_VERSION
|
|
1296
|
+
LABEL org.opencontainers.image.title="Saddle" \
|
|
1297
|
+
org.opencontainers.image.description="Storage-backed browser and compute engine (the grand-merge node service)" \
|
|
1298
|
+
org.opencontainers.image.source="https://github.com/wenathlan/saddle" \
|
|
1299
|
+
org.opencontainers.image.version="$SADDLE_VERSION"
|
|
1300
|
+
|
|
1301
|
+
WORKDIR /app
|
|
1302
|
+
|
|
1303
|
+
# the service ENV surface of the former compose.yml (folded here so the
|
|
1304
|
+
# one container file carries the whole container context: memory engine
|
|
1305
|
+
# tier selection, the sbot platform tag and the sbot cdn url override)
|
|
1306
|
+
ENV NODE_ENV=production \
|
|
1307
|
+
NPM_CONFIG_LEGACY_PEER_DEPS=true \
|
|
1308
|
+
SADDLE_MEMORY_ENGINE=ram \
|
|
1309
|
+
SBOT_PLATFORM="" \
|
|
1310
|
+
SBOT_CDN_URL=""
|
|
1311
|
+
|
|
1312
|
+
COPY --from=saddle-build /app/package.json /app/package-lock.json ./
|
|
1313
|
+
RUN apt-get update \
|
|
1314
|
+
&& apt-get upgrade -y \
|
|
1315
|
+
&& rm -rf /var/lib/apt/lists/* \
|
|
1316
|
+
&& npm install --global npm@12.0.2 \
|
|
1317
|
+
&& tempdir="$(mktemp -d)" \
|
|
1318
|
+
&& npm pack brace-expansion@5.0.9 ip-address@10.3.1 --pack-destination "$tempdir" \
|
|
1319
|
+
&& mkdir -p /usr/local/lib/node_modules/npm/node_modules/brace-expansion /usr/local/lib/node_modules/npm/node_modules/ip-address \
|
|
1320
|
+
&& tar -xzf "$tempdir/brace-expansion-5.0.9.tgz" --strip-components=1 -C /usr/local/lib/node_modules/npm/node_modules/brace-expansion \
|
|
1321
|
+
&& tar -xzf "$tempdir/ip-address-10.3.1.tgz" --strip-components=1 -C /usr/local/lib/node_modules/npm/node_modules/ip-address \
|
|
1322
|
+
&& rm -rf "$tempdir" \
|
|
1323
|
+
&& npm ci --omit=dev --ignore-scripts --legacy-peer-deps \
|
|
1324
|
+
# prune the vendored build toolchains of optional native deps: the
|
|
1325
|
+
# cpu-features cmake sources ship nested Dockerfiles (build CI of
|
|
1326
|
+
# the dependency) that the trivy misconfig scanner flags (DS-0002
|
|
1327
|
+
# USER, DS-0029 no-install-recommends) inside the shipped image.
|
|
1328
|
+
# With --ignore-scripts the binding never builds and the package
|
|
1329
|
+
# degrades to a no-op at runtime - the sources are dead weight.
|
|
1330
|
+
&& rm -rf node_modules/cpu-features/deps \
|
|
1331
|
+
&& find node_modules -type f -name Dockerfile -delete
|
|
1332
|
+
COPY --from=saddle-build /app/dist ./dist
|
|
1333
|
+
|
|
1334
|
+
USER node
|
|
1335
|
+
|
|
1336
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 CMD ["node", "dist/cli.js", "help"]
|
|
1337
|
+
|
|
1338
|
+
ENTRYPOINT ["node", "dist/cli.js"]
|
|
1339
|
+
CMD ["help"]
|