chore: save the refactor mess

This commit is contained in:
Guillaume ARM 2026-06-16 22:16:58 +02:00
parent aa6ddd3bfd
commit afcddbd81b
75 changed files with 81 additions and 47 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
.env .env
node_modules/ node_modules/
dist/ dist/
.stage

View File

@ -60,3 +60,7 @@ ignore = {
} }
max_line_length = false max_line_length = false
-- .stage/ holds generated flat copies of per-package sources for the CraftOS-PC
-- harness; lint the originals under packages/, not the copies.
exclude_files = { ".stage" }

View File

@ -4,6 +4,7 @@
import 'just/deps.just' import 'just/deps.just'
import 'just/install.just' import 'just/install.just'
import 'just/npm.just' import 'just/npm.just'
import 'just/stage.just'
import 'just/craftos.just' import 'just/craftos.just'
import 'just/opencode.just' import 'just/opencode.just'
import 'just/sandbox.just' import 'just/sandbox.just'

View File

@ -185,7 +185,9 @@ for _, desc in ipairs(resolved) do
seenFile[filePath] = true; seenFile[filePath] = true;
allFiles[#allFiles + 1] = filePath; allFiles[#allFiles + 1] = filePath;
fs.delete(filePath); fs.delete(filePath);
shell.execute('wget', REPO_BASE .. filePath, filePath); -- Sources live under packages/<pkg>/ in the repo but install flat, so
-- fetch from the package path and write to the flat destination.
shell.execute('wget', REPO_BASE .. 'packages/' .. desc.name .. '/' .. filePath, filePath);
end end
end end
for _, srv in ipairs(desc.autostart or {}) do for _, srv in ipairs(desc.autostart or {}) do

View File

@ -116,7 +116,7 @@ check-packages *args: check-jq
old_version="$(git show "$last_desc_commit:$desc" | jq -r '.version // empty')" old_version="$(git show "$last_desc_commit:$desc" | jq -r '.version // empty')"
files=() files=()
while IFS= read -r file; do files+=("$file"); done < <(jq -r '.files[]?' "$desc") while IFS= read -r file; do files+=("packages/$name/$file"); done < <(jq -r '.files[]?' "$desc")
if [ "${#files[@]}" -gt 0 ] && ! git diff --quiet "$last_desc_commit" -- "${files[@]}"; then if [ "${#files[@]}" -gt 0 ] && ! git diff --quiet "$last_desc_commit" -- "${files[@]}"; then
if ! semver_gt "$desc_version" "$old_version"; then if ! semver_gt "$desc_version" "$old_version"; then
if [ "$fix" -eq 1 ]; then if [ "$fix" -eq 1 ]; then

View File

@ -3,7 +3,7 @@
# Launch the TrapOS dev environment in CraftOS-PC with repo-local data # Launch the TrapOS dev environment in CraftOS-PC with repo-local data
# (.craftos/) and read-only repo mounts. See ADR-0005. # (.craftos/) and read-only repo mounts. See ADR-0005.
[positional-arguments] [positional-arguments]
trapos *args: check-install trapos *args: check-install stage
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
repo='{{justfile_directory()}}' repo='{{justfile_directory()}}'
@ -13,8 +13,8 @@ trapos *args: check-install
fi fi
argv+=(--mount-ro "/trapos=$repo") argv+=(--mount-ro "/trapos=$repo")
for dir in apis programs servers startup tests; do for dir in apis programs servers startup tests; do
if [ -d "$repo/$dir" ]; then if [ -d "$repo/.stage/$dir" ]; then
argv+=(--mount-ro "/$dir=$repo/$dir") argv+=(--mount-ro "/$dir=$repo/.stage/$dir")
fi fi
done done
exec craftos "${argv[@]}" "$@" exec craftos "${argv[@]}" "$@"
@ -38,7 +38,7 @@ craftos *args: check-install
# shuts the machine down after normal completion or Lua errors, while the host # shuts the machine down after normal completion or Lua errors, while the host
# watchdog catches snippets that block before reaching shutdown. # watchdog catches snippets that block before reaching shutdown.
[positional-arguments] [positional-arguments]
trapos-exec code: trapos-exec code: stage
#!/usr/bin/env bash #!/usr/bin/env bash
set -uo pipefail set -uo pipefail
repo='{{justfile_directory()}}' repo='{{justfile_directory()}}'
@ -79,7 +79,7 @@ trapos-exec code:
printf '%s\n' 'status.close()' printf '%s\n' 'status.close()'
printf '%s\n' 'os.shutdown()' printf '%s\n' 'os.shutdown()'
} > "$runner" } > "$runner"
mount_arg=(--mount-ro "/trapos=$repo" --mount-ro "/apis=$repo/apis" --mount-ro "/programs=$repo/programs" --mount-ro "/servers=$repo/servers" --mount-ro "/startup=$repo/startup" --mount-ro "/tests=$repo/tests" --mount-ro "/headless=$stage_dir") mount_arg=(--mount-ro "/trapos=$repo" --mount-ro "/apis=$repo/.stage/apis" --mount-ro "/programs=$repo/.stage/programs" --mount-ro "/servers=$repo/.stage/servers" --mount-ro "/startup=$repo/.stage/startup" --mount-ro "/tests=$repo/.stage/tests" --mount-ro "/headless=$stage_dir")
craftos --directory "$data_dir" --headless "${rom_arg[@]}" "${mount_arg[@]}" --exec "shell.run('/headless/exec.lua')" >"$tmp" 2>&1 & craftos --directory "$data_dir" --headless "${rom_arg[@]}" "${mount_arg[@]}" --exec "shell.run('/headless/exec.lua')" >"$tmp" 2>&1 &
pid="$!" pid="$!"
( sleep "$timeout_seconds"; kill -TERM "$pid" >/dev/null 2>&1 ) & ( sleep "$timeout_seconds"; kill -TERM "$pid" >/dev/null 2>&1 ) &

View File

@ -46,4 +46,4 @@ npm-test-integration-trap-sandbox:
npm run test:integration --prefix tools/trap-sandbox/ npm run test:integration --prefix tools/trap-sandbox/
# Build generated artifacts. # Build generated artifacts.
build: npm-build build: npm-build stage

22
just/stage.just Normal file
View File

@ -0,0 +1,22 @@
# Assemble the flat mount roots the CraftOS-PC harness expects from the
# per-package sources. Lua loads its deps by absolute mount path (require
# '/apis/x') and ccpm installs files flat, but sources now live under
# packages/<pkg>/{apis,programs,servers,startup,tests}. This merges them back
# into a gitignored .stage/ that the dev/test recipes mount as /apis, /programs,
# /servers, /startup, /tests. Regenerated on every run so it always reflects the
# working tree.
stage:
#!/usr/bin/env bash
set -euo pipefail
repo='{{justfile_directory()}}'
cd "$repo"
stage="$repo/.stage"
rm -rf "$stage"
for dir in apis programs servers startup tests; do
for pkgdir in packages/*/"$dir"; do
[ -d "$pkgdir" ] || continue
mkdir -p "$stage/$dir"
cp -R "$pkgdir/." "$stage/$dir/"
done
done
printf '%s\n' 'OK: staged .stage/ from packages/'

View File

@ -16,7 +16,7 @@ test-integration: e2e test-timeout
# Run CraftOS-PC headless integration tests. Pass `--pretty` for grouped output. # Run CraftOS-PC headless integration tests. Pass `--pretty` for grouped output.
[positional-arguments] [positional-arguments]
_craftos-test *args: _craftos-test *args: stage
#!/usr/bin/env bash #!/usr/bin/env bash
set -uo pipefail set -uo pipefail
@ -58,7 +58,7 @@ _craftos-test *args:
rom_arg=(--rom /Applications/CraftOS-PC.app/Contents/Resources) rom_arg=(--rom /Applications/CraftOS-PC.app/Contents/Resources)
fi fi
repo='{{justfile_directory()}}' repo='{{justfile_directory()}}'
mount_arg=(--mount-ro "/trapos=$repo" --mount-ro "/apis=$repo/apis" --mount-ro "/programs=$repo/programs" --mount-ro "/startup=$repo/startup" --mount-ro "/tests=$repo/tests") mount_arg=(--mount-ro "/trapos=$repo" --mount-ro "/apis=$repo/.stage/apis" --mount-ro "/programs=$repo/.stage/programs" --mount-ro "/startup=$repo/.stage/startup" --mount-ro "/tests=$repo/.stage/tests")
tmp="$(mktemp)" tmp="$(mktemp)"
data_dir="$(mktemp -d)" data_dir="$(mktemp -d)"
output_path="$data_dir/computer/0/trapos-test-output" output_path="$data_dir/computer/0/trapos-test-output"
@ -94,7 +94,7 @@ _craftos-test *args:
# caught it. `expect` is "lua" (libtest cancels the case) or "shell" (the shell # caught it. `expect` is "lua" (libtest cancels the case) or "shell" (the shell
# watchdog kills the whole process). Not part of `ci`/`test`: these exercise the # watchdog kills the whole process). Not part of `ci`/`test`: these exercise the
# failure paths on purpose. # failure paths on purpose.
_timeout-fixture script shell_timeout extra_flag expect: check-install _timeout-fixture script shell_timeout extra_flag expect: check-install stage
#!/usr/bin/env bash #!/usr/bin/env bash
set -uo pipefail set -uo pipefail
repo='{{justfile_directory()}}' repo='{{justfile_directory()}}'
@ -103,7 +103,7 @@ _timeout-fixture script shell_timeout extra_flag expect: check-install
if [ "$(uname -s)" = "Darwin" ]; then if [ "$(uname -s)" = "Darwin" ]; then
rom_arg="--rom /Applications/CraftOS-PC.app/Contents/Resources" rom_arg="--rom /Applications/CraftOS-PC.app/Contents/Resources"
fi fi
mount_arg="--mount-ro /apis=$repo/apis --mount-ro /programs=$repo/programs --mount-ro /tests=$repo/tests" mount_arg="--mount-ro /apis=$repo/.stage/apis --mount-ro /programs=$repo/.stage/programs --mount-ro /tests=$repo/.stage/tests"
tmp="$(mktemp)" tmp="$(mktemp)"
data_dir="$(mktemp -d)" data_dir="$(mktemp -d)"
output_path="$data_dir/computer/0/trapos-test-output" output_path="$data_dir/computer/0/trapos-test-output"

View File

@ -1,6 +1,6 @@
{ {
"name": "TrapOS", "name": "TrapOS",
"version": "0.11.3", "version": "0.11.4",
"branch": "master", "branch": "master",
"packages": [ "packages": [
"trapos" "trapos"

View File

@ -1,13 +1,13 @@
{ {
"packages": { "packages": {
"trapos-core": "0.9.0", "trapos-core": "0.9.1",
"trapos-test": "0.2.1", "trapos-test": "0.2.2",
"trapos-boot": "0.4.0", "trapos-boot": "0.4.1",
"trapos-net": "0.3.0", "trapos-net": "0.3.1",
"trapos-ui": "0.2.2", "trapos-ui": "0.2.3",
"trapos-ai": "0.7.0", "trapos-ai": "0.7.1",
"trapos-sandbox": "0.3.3", "trapos-sandbox": "0.3.4",
"trapos-sandbox-legacy": "0.3.0", "trapos-sandbox-legacy": "0.3.1",
"trapos": "0.11.3" "trapos": "0.11.4"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos-ai", "name": "trapos-ai",
"version": "0.7.0", "version": "0.7.1",
"description": "TrapOS AI client for opencode serve", "description": "TrapOS AI client for opencode serve",
"dependencies": ["trapos-core"], "dependencies": ["trapos-core"],
"files": [ "files": [

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos-boot", "name": "trapos-boot",
"version": "0.4.0", "version": "0.4.1",
"description": "TrapOS boot: startup MOTD and autostart server launcher", "description": "TrapOS boot: startup MOTD and autostart server launcher",
"dependencies": ["trapos-core"], "dependencies": ["trapos-core"],
"files": [ "files": [

View File

@ -243,8 +243,11 @@ local function createCcpm(opts)
return api.registryBaseUrl(registry) .. 'packages/index.json'; return api.registryBaseUrl(registry) .. 'packages/index.json';
end end
function api.fileUrl(registry, filePath) -- Sources live under packages/<pkg>/ in the repo but install flat (the
return api.registryBaseUrl(registry) .. filePath; -- `filePath` from ccpm.json is the install destination), so the fetch URL
-- gains the package prefix while the install target stays flat.
function api.fileUrl(registry, pkg, filePath)
return api.registryBaseUrl(registry) .. 'packages/' .. pkg .. '/' .. filePath;
end end
-- ---------- HTTP ---------- -- ---------- HTTP ----------
@ -420,8 +423,8 @@ local function createCcpm(opts)
cleanupEmptyGeneratedDirs(); cleanupEmptyGeneratedDirs();
end end
function api.downloadFile(registry, filePath) function api.downloadFile(registry, pkg, filePath)
local body = httpGetBody(api.fileUrl(registry, filePath)); local body = httpGetBody(api.fileUrl(registry, pkg, filePath));
if not body then if not body then
return false, 'failed to download ' .. filePath; return false, 'failed to download ' .. filePath;
end end
@ -461,7 +464,7 @@ local function createCcpm(opts)
log('install ' .. item.name .. ' v' .. tostring(item.desc.version or '?')); log('install ' .. item.name .. ' v' .. tostring(item.desc.version or '?'));
for _, filePath in ipairs(item.desc.files or {}) do for _, filePath in ipairs(item.desc.files or {}) do
log(' ' .. filePath); log(' ' .. filePath);
local ok, derr = api.downloadFile(item.registry, filePath); local ok, derr = api.downloadFile(item.registry, item.name, filePath);
if not ok then return false, derr; end if not ok then return false, derr; end
end end
local previous = lock.packages[item.name]; local previous = lock.packages[item.name];

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos-core", "name": "trapos-core",
"version": "0.9.0", "version": "0.9.1",
"description": "TrapOS base: package manager, event loop, upgrade and event tools", "description": "TrapOS base: package manager, event loop, upgrade and event tools",
"dependencies": [], "dependencies": [],
"files": [ "files": [

View File

@ -154,8 +154,8 @@ testlib.test("install downloads files and records the lock", function()
dependencies = { "trapos-core" }, dependencies = { "trapos-core" },
files = { "apis/net.lua" }, files = { "apis/net.lua" },
}), }),
[base .. "apis/eventloop.lua"] = "eventloop-body", [base .. "packages/trapos-core/apis/eventloop.lua"] = "eventloop-body",
[base .. "apis/net.lua"] = "net-body", [base .. "packages/trapos-net/apis/net.lua"] = "net-body",
} }
local sd, root = freshDirs() local sd, root = freshDirs()
local ccpm = createCcpm({ stateDir = sd, installRoot = root, http = fakeHttp(routes) }) local ccpm = createCcpm({ stateDir = sd, installRoot = root, http = fakeHttp(routes) })
@ -194,8 +194,8 @@ testlib.test("install downloads files from a gitea registry", function()
dependencies = { "trapos-core" }, dependencies = { "trapos-core" },
files = { "apis/net.lua" }, files = { "apis/net.lua" },
}), }),
[base .. "apis/eventloop.lua"] = "eventloop-body", [base .. "packages/trapos-core/apis/eventloop.lua"] = "eventloop-body",
[base .. "apis/net.lua"] = "net-body", [base .. "packages/trapos-net/apis/net.lua"] = "net-body",
} }
local sd, root = freshDirs() local sd, root = freshDirs()
local ccpm = createCcpm({ stateDir = sd, installRoot = root, http = fakeHttp(routes) }) local ccpm = createCcpm({ stateDir = sd, installRoot = root, http = fakeHttp(routes) })
@ -237,8 +237,8 @@ testlib.test("installing trapos writes aggregated os state", function()
files = { "apis/net.lua" }, files = { "apis/net.lua" },
autostart = { "servers/ping-server" }, autostart = { "servers/ping-server" },
}), }),
[base .. "programs/ccpm.lua"] = "ccpm-body", [base .. "packages/trapos-core/programs/ccpm.lua"] = "ccpm-body",
[base .. "apis/net.lua"] = "net-body", [base .. "packages/trapos-net/apis/net.lua"] = "net-body",
} }
local sd, root = freshDirs() local sd, root = freshDirs()
local ccpm = createCcpm({ stateDir = sd, installRoot = root, http = fakeHttp(routes) }) local ccpm = createCcpm({ stateDir = sd, installRoot = root, http = fakeHttp(routes) })
@ -354,7 +354,7 @@ testlib.test("upgrade reinstalls outdated packages from cache", function()
dependencies = {}, dependencies = {},
files = { "programs/foo.lua" }, files = { "programs/foo.lua" },
}), }),
[base .. "programs/foo.lua"] = "foo-v2", [base .. "packages/foo/programs/foo.lua"] = "foo-v2",
} }
local sd, root = freshDirs() local sd, root = freshDirs()
local ccpm = createCcpm({ stateDir = sd, installRoot = root, http = fakeHttp(routes) }) local ccpm = createCcpm({ stateDir = sd, installRoot = root, http = fakeHttp(routes) })

View File

@ -36,7 +36,7 @@ local function runPostinstall(settingsLib)
end, end,
}, { __index = _G }); }, { __index = _G });
local chunk, loadErr = loadfile('/trapos/programs/trapos-postinstall.lua', 't', env); local chunk, loadErr = loadfile('/programs/trapos-postinstall.lua', 't', env);
if not chunk then error(loadErr, 0); end if not chunk then error(loadErr, 0); end
local ok, err = pcall(chunk); local ok, err = pcall(chunk);
if not ok then error(err, 0); end if not ok then error(err, 0); end

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos-net", "name": "trapos-net",
"version": "0.3.0", "version": "0.3.1",
"description": "TrapOS networking: service-name bus, router, ping", "description": "TrapOS networking: service-name bus, router, ping",
"dependencies": ["trapos-core"], "dependencies": ["trapos-core"],
"files": [ "files": [

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos-sandbox-legacy", "name": "trapos-sandbox-legacy",
"version": "0.3.0", "version": "0.3.1",
"description": "[legacy] TrapOS sandbox programs for ccpm experiments and Lua learning", "description": "[legacy] TrapOS sandbox programs for ccpm experiments and Lua learning",
"dependencies": ["trapos-core"], "dependencies": ["trapos-core"],
"files": [ "files": [

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos-sandbox", "name": "trapos-sandbox",
"version": "0.3.3", "version": "0.3.4",
"description": "TrapOS sandbox gateway client: WS daemon (servers/sandbox) + sandbox command + MCP exec/write server", "description": "TrapOS sandbox gateway client: WS daemon (servers/sandbox) + sandbox command + MCP exec/write server",
"dependencies": ["trapos-core"], "dependencies": ["trapos-core"],
"files": [ "files": [

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos-test", "name": "trapos-test",
"version": "0.2.1", "version": "0.2.2",
"description": "TrapOS test framework and CraftOS-PC suite runner", "description": "TrapOS test framework and CraftOS-PC suite runner",
"dependencies": ["trapos-core"], "dependencies": ["trapos-core"],
"files": [ "files": [

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos-ui", "name": "trapos-ui",
"version": "0.2.2", "version": "0.2.3",
"description": "TrapOS terminal UI toolkit and demo", "description": "TrapOS terminal UI toolkit and demo",
"dependencies": ["trapos-core"], "dependencies": ["trapos-core"],
"files": [ "files": [

View File

@ -1,6 +1,6 @@
{ {
"name": "trapos", "name": "trapos",
"version": "0.11.3", "version": "0.11.4",
"description": "TrapOS full install meta-package", "description": "TrapOS full install meta-package",
"dependencies": [ "dependencies": [
"trapos-boot", "trapos-boot",

View File

@ -54,8 +54,8 @@ local function installRoutes()
dependencies = {}, dependencies = {},
files = { 'apis/libccpm.lua', 'programs/ccpm.lua' }, files = { 'apis/libccpm.lua', 'programs/ccpm.lua' },
}), }),
[INSTALL_BASE .. 'apis/libccpm.lua'] = 'libccpm-body', [INSTALL_BASE .. 'packages/trapos-core/apis/libccpm.lua'] = 'libccpm-body',
[INSTALL_BASE .. 'programs/ccpm.lua'] = 'ccpm-body', [INSTALL_BASE .. 'packages/trapos-core/programs/ccpm.lua'] = 'ccpm-body',
}; };
end end

View File

@ -83,7 +83,7 @@ testlib.test('package descriptors are internally consistent', function()
local files = {}; local files = {};
for _, filePath in ipairs(desc.files) do for _, filePath in ipairs(desc.files) do
files[filePath] = true; files[filePath] = true;
testlib.assertTrue(fs.exists('/trapos/' .. filePath), name .. ' missing shipped file ' .. filePath); testlib.assertTrue(fs.exists(PACKAGES_DIR .. '/' .. name .. '/' .. filePath), name .. ' missing shipped file ' .. filePath);
end end
for _, autostart in ipairs(desc.autostart) do for _, autostart in ipairs(desc.autostart) do