daspkg
July 16, 2026 · View on GitHub
Package manager for daslang. Installs, updates, builds, and manages daslang modules from git repositories or a central package index.
Quick start
# run daspkg
daslang utils/daspkg/main.das -- <command> [args...]
# install a package by name (from the index)
daslang utils/daspkg/main.das -- install daspkg-test-pure
# install a package by URL
daslang utils/daspkg/main.das -- install github.com/borisbat/daspkg-test-pure
# install a specific version
daslang utils/daspkg/main.das -- install github.com/borisbat/daspkg-test-versions@1.0
# install all dependencies listed in .das_package
daslang utils/daspkg/main.das -- install
# install globally (shared across projects)
daslang utils/daspkg/main.das -- install --global dasImgui
Commands
| Command | Description |
|---|---|
install <url|name|path>[@version] | Install a package from git, index, or local path |
install (no args) | Install all dependencies from .das_package |
remove <name> | Remove an installed package |
update [name] | Re-install at pinned version (re-clone, rebuild) |
upgrade [name] | Upgrade to latest version |
list | List installed packages |
search <query> | Search the package index |
build | Build all C/C++ packages (cmake) |
check | Verify installed packages are present |
doctor | Check environment (git, cmake, gh) |
release [--out <dir>] [--tune-fast] | Bundle project as a redistributable standalone; tuning defaults to 20/80, with an opt-in quick 4/8/20 pass |
introduce [url] | Submit a package to the index via PR |
withdraw <name> | Remove a package from the index via PR |
All package commands accept --global / -g to operate on global modules.
Options
| Flag | Description |
|---|---|
--root <path> | Project root (default: current directory) |
--force | Force reinstall (overrides duplicate/version checks) |
--global, -g | Operate on global modules in {das_root}/modules/ |
--color / --no-color | Enable/disable ANSI colored output |
--verbose, -v | Print debug details (git commands, resolve steps) |
--json | Machine-readable JSON output (search, list, check) |
--branch <name>, -b <name> | Install from a git branch (e.g. master) instead of a tag |
--out <path> | Output directory for release (default: current directory) |
--tune-fast | During release, tune with progressive 4/8-round screening and a 20-round cap instead of the default 20/80 budget |
Global modules
Large packages (e.g. dasImgui) can be installed globally — once under {das_root}/modules/ — shared across all projects using that SDK. Avoids redundant clones and builds.
daspkg install --global dasImgui # install to das_root/modules/
daspkg list --global # list global packages
daspkg update --global dasImgui # re-install at pinned version
daspkg remove --global dasImgui # remove globally
- Local install auto-uses global:
daspkg install foochecks the global lock file first. If compatible, records a reference instead of cloning. - Version mismatch: errors with a suggestion. Use
--forceto install locally, or--globalto update the global copy. - Shadow detection: if a module exists both locally and globally, the local version wins (warning printed). Removing the local copy falls back to global.
- CMake: global packages with native builds get a
.daspkg_standalonemarker so the main CMake skips them during auto-discovery.
.das_package manifest
Executable daslang script declaring metadata, version resolution, dependencies, and build info.
options gen2
require daslib/daspkg
[export]
def package() {
package_name("mymodule")
package_author("username")
package_description("What this module does")
package_source("github.com/user/mymodule")
package_license("MIT")
package_tag("networking")
package_min_sdk("0.4")
}
[export]
def resolve(sdk_version, version : string) {
if (version == "" || version == "latest") {
download_tag("v2.0")
} else {
download_tag("v{version}")
}
// alternatives: download_branch("main"), download_redirect("github.com/other/repo", "v3.0")
}
[export]
def dependencies(version : string) {
require_package("github.com/user/dep-a", ">=1.0")
require_package("github.com/user/dep-b")
}
[export]
def build() {
cmake_build() // or: custom_build("make all"), or: no_build()
}
[export]
def release() {
release_main("main.das")
release_include("assets/**") // release-owned; refreshed every time
release_include_if_missing("app.toml") // user-owned after initialization
}
Use release_include_if_missing for editable deployment files. They are copied only when absent,
excluded from .daspkg_release.manifest, and preserved even when upgrading from an older manifest
that previously treated the same path as release-owned.
All functions except package() are optional. A repo without .das_package gets a "dumb clone" — no version resolution, no deps, no build.
Install flow
- Shallow-clone from default branch
- Run
.das_packageresolve()→ checkout resolved tag/branch (or re-clone on redirect) - Move to
modules/<name>/ - Record in
daspkg.lock - Install transitive dependencies
- Auto-build if
.das_packagehasbuild()
Project layout
my_project/
main.das
.das_package # project manifest (lists dependencies)
daspkg.lock # installed packages, versions, sources
modules/
<package_name>/
.das_module # provided by package author
.das_package # package manifest
_build/ # cmake build directory (if C++ package)
*.shared_module # built C++ output (if applicable)
.daspkg_cache/ # index cache (gitignored)
.daspkg_tmp/ # temp dir during install (gitignored)
{das_root}/ # daScript SDK root (for global modules)
modules/
.daspkg_global.lock # global lock file
<global_package>/
.daspkg_standalone # marker: built by daspkg, skip in CMake
Lock file (daspkg.lock)
{
"sdk_version": "",
"packages": [
{
"name": "mymodule",
"source": "github.com/user/mymodule",
"version": "1.0",
"tag": "v1.0",
"branch": "",
"root": true,
"local": false,
"global": false
}
]
}
- root —
trueif user-installed,falseif transitive dependency - tag/branch — resolved git ref
- local — installed from local path
- global — resolved from global install (no local copy)
The global lock file ({das_root}/modules/.daspkg_global.lock) uses the same format.
Architecture
| File | Description |
|---|---|
main.das | CLI entry point — parses args, dispatches to commands |
commands.das | Command implementations: install, remove, update, upgrade, build, check, doctor |
index.das | Package index: fetch, search, introduce, withdraw |
lockfile.das | LockFile / PackageEntry structs, JSON serialization |
package_runner.das | In-process .das_package compiler — compiles, simulates, extracts metadata |
utils.das | Shared utilities: run_cmd, force_rmdir, path helpers |
daslib/daspkg.das | API module that .das_package scripts require |
The package runner compiles .das_package scripts in-process using compile_file + simulate + invoke_in_context. It calls exported functions and reads state from daslib/daspkg module globals via get_context_global_variable.
Tests
| File | Count | Type |
|---|---|---|
test_daspkg.das | 151 | Unit tests (local operations, parsing, lock file, package_runner) |
test_daspkg_git.das | 70 | Integration tests (git clone, version resolve, index, global modules) |
# unit tests — fast, no network
daslang dastest/dastest.das -- --test utils/daspkg/test_daspkg.das
# integration tests — requires network
daslang dastest/dastest.das -- --test utils/daspkg/test_daspkg_git.das
Test repositories (GitHub)
| Repository | Purpose |
|---|---|
borisbat/daspkg-test-pure | Pure daslang module |
borisbat/daspkg-test-versions | Module with version tags (v1.0, v2.0) |
borisbat/daspkg-test-deps | Module with transitive dependency |
borisbat/daspkg-index | Central package index |
Design rationale
Why git-based (like Go modules)?
- Packages are git repositories — no centralized registry server to maintain
- Version = git tag.
resolve()maps version requests to tags. - Index is a curated JSON file in a git repo. Authors add via PR (
daspkg introduce).
Why executable manifests?
- Authors can put version-conditional logic in
resolve()anddependencies() - Same pattern as
.das_module— familiar to daslang authors - daspkg provides registration functions via
daslib/daspkg;.das_packagejust calls them
Why per-project by default?
- Game projects need reproducible builds —
modules/is self-contained - Global install (
--global) for large shared modules (dasImgui, etc.) - Runtime already scans both
das_root/modules/and projectmodules/
Version model
- Package version — semver, resolved via
.das_packageresolve() - SDK version —
resolve()receives it, can return different tags per SDK - Dependency constraints — operators
>=,>,<=,<,=, comma AND:">=1.0,<2.0" - Diamond deps — first installed wins (single
requirenamespace). Manual upgrade with--force.
Transport
- Only external dependency:
gitCLI. No HTTP library needed. - Shallow clones (
--depth 1) for speed. - Local installs: filesystem copy, no git.
Requirements
- git — required for all remote operations
- cmake — required for building C/C++ packages
- gh (GitHub CLI) — optional, only for
introduce/withdraw
Run daspkg doctor to check your environment.