From 379047d6c8394c380c6d4d97885cf5be57fc08cf Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 01:35:40 +0000 Subject: [PATCH 01/24] build: turn the repo into a turborepo monorepo with uv workspaces Move the runtime to packages/core and the CLI to packages/cli. The root holds a virtual uv workspace, the turbo config, and the root scripts. Every check, test, and build runs from the root through turbo. Pin bun, turbo, uv, ruff, and ty. Regenerate uv.lock with uv 0.12 and track it. Drop the root requirements.txt, which nothing read. --- .gitignore | 5 +- bun.lock | 27 ++++++ package.json | 23 +++++ {cli => packages/cli}/ARCHITECTURE.md | 0 {cli => packages/cli}/README.md | 0 .../cli/canyonos}/__init__.py | 0 {cli => packages/cli}/canyonos/build.py | 0 {cli => packages/cli}/canyonos/clean.py | 0 {cli => packages/cli}/canyonos/config.py | 0 {cli => packages/cli}/canyonos/constants.py | 0 .../cli}/canyonos/dashboard.compose.yml | 0 .../cli}/canyonos/dashboard_stack.py | 0 {cli => packages/cli}/canyonos/deploy.py | 0 {cli => packages/cli}/canyonos/doctor.py | 0 {cli => packages/cli}/canyonos/gc.py | 0 {cli => packages/cli}/canyonos/init.py | 0 {cli => packages/cli}/canyonos/logs.py | 0 {cli => packages/cli}/canyonos/new_app.py | 0 {cli => packages/cli}/canyonos/quit.py | 0 {cli => packages/cli}/canyonos/serve.py | 0 {cli => packages/cli}/canyonos/status.py | 0 {cli => packages/cli}/canyonos/stop.py | 0 {cli => packages/cli}/canyonos/sync.py | 0 {cli => packages/cli}/canyonos/test.py | 0 {cli => packages/cli}/canyonos/theme.py | 0 {cli => packages/cli}/canyonos/ui.py | 0 {cli => packages/cli}/canyonos/verify.py | 0 {cli => packages/cli}/cli.py | 0 {cli => packages/cli}/install.sh | 0 {cli => packages/cli}/pyproject.toml | 0 .../cli/utils}/__init__.py | 0 {cli => packages/cli}/utils/help_screen.py | 0 {cli => packages/cli}/utils/tui.py | 0 .dockerignore => packages/core/.dockerignore | 11 +-- {canyonos_core => packages/core}/Dockerfile | 0 .../core/canyonos_core}/FUTURE_SCHEMA.md | 0 .../canyonos_core}/OTLP_Exporter/DESIGN.md | 0 .../canyonos_core}/OTLP_Exporter/SCHEMA.md | 0 .../canyonos_core/OTLP_Exporter}/__init__.py | 0 .../canyonos_core}/OTLP_Exporter/convert.py | 0 .../core/canyonos_core}/OTLP_Exporter/db.py | 0 .../OTLP_Exporter/otel_exporter.py | 0 .../OTLP_Exporter/otel_queue.db | 0 .../core/canyonos_core}/README.md | 0 .../core/canyonos_core}/__init__.py | 0 .../core/canyonos_core}/cli.py | 0 .../canyonos_core}/controller/__init__.py | 0 .../controller/canyonos_context.py | 0 .../cloud_provider_logic/EC2/README.md | 0 .../cloud_provider_logic/EC2/_runtime.py | 0 .../cloud_provider_logic/Local/_runtime.py | 0 .../core/canyonos_core}/controller/deploy.py | 0 .../core/canyonos_core}/controller/future.py | 0 .../controller/global_controller.py | 0 .../controller/instance_manager.py | 0 .../controller/local_controller.py | 0 .../controller/local_controller_frontend.py | 0 .../controller/proto/global_controller.proto | 0 .../controller/proto/local_controler.proto | 0 .../controller/utils/__init__.py | 0 .../controller/utils/agent_specs.py | 0 .../controller/utils/aws_pricing_chart.db | Bin .../controller/utils/container_names.py | 0 .../controller/utils/env_file.py | 0 .../controller/utils/gpu_metrics.py | 0 .../controller/utils/grpc_options.py | 0 .../controller/utils/pricing.py | 0 .../controller/utils/process_supervisor.py | 0 .../controller/utils/redis_client.py | 0 .../controller/utils/redis_utils.py | 0 .../controller/utils/session_logging.py | 0 .../controller/utils/telemetry_logging.py | 0 .../core/canyonos_core}/llm_proxy/README.md | 0 .../core/canyonos_core}/llm_proxy/__init__.py | 0 .../core/canyonos_core}/llm_proxy/__main__.py | 0 .../core/canyonos_core}/llm_proxy/app.py | 0 .../core/canyonos_core}/llm_proxy/config.py | 0 .../core/canyonos_core}/llm_proxy/core.py | 0 .../core/canyonos_core}/llm_proxy/hooks.py | 0 .../llm_proxy/providers/__init__.py | 0 .../llm_proxy/providers/anthropic.py | 0 .../llm_proxy/providers/base.py | 0 .../llm_proxy/providers/bedrock.py | 0 .../llm_proxy/providers/openai.py | 0 .../core/canyonos_core}/llm_proxy/proxy.py | 0 .../canyonos_core}/llm_proxy/requirements.txt | 0 .../core/canyonos_core}/llm_proxy/stub.py | 0 .../core/canyonos_core}/server.py | 0 .../core/canyonos_core}/stub_generator.py | 0 packages/core/pyproject.toml | 38 ++++++++ pyproject.toml | 65 ++++---------- requirements.txt | 14 --- tests/test_otel_exporter_fanout.py | 4 +- turbo.json | 60 +++++++++++++ uv.lock | 83 ++++++++++++++---- 95 files changed, 244 insertions(+), 86 deletions(-) create mode 100644 bun.lock create mode 100644 package.json rename {cli => packages/cli}/ARCHITECTURE.md (100%) rename {cli => packages/cli}/README.md (100%) rename {canyonos_core/OTLP_Exporter => packages/cli/canyonos}/__init__.py (100%) rename {cli => packages/cli}/canyonos/build.py (100%) rename {cli => packages/cli}/canyonos/clean.py (100%) rename {cli => packages/cli}/canyonos/config.py (100%) rename {cli => packages/cli}/canyonos/constants.py (100%) rename {cli => packages/cli}/canyonos/dashboard.compose.yml (100%) rename {cli => packages/cli}/canyonos/dashboard_stack.py (100%) rename {cli => packages/cli}/canyonos/deploy.py (100%) rename {cli => packages/cli}/canyonos/doctor.py (100%) rename {cli => packages/cli}/canyonos/gc.py (100%) rename {cli => packages/cli}/canyonos/init.py (100%) rename {cli => packages/cli}/canyonos/logs.py (100%) rename {cli => packages/cli}/canyonos/new_app.py (100%) rename {cli => packages/cli}/canyonos/quit.py (100%) rename {cli => packages/cli}/canyonos/serve.py (100%) rename {cli => packages/cli}/canyonos/status.py (100%) rename {cli => packages/cli}/canyonos/stop.py (100%) rename {cli => packages/cli}/canyonos/sync.py (100%) rename {cli => packages/cli}/canyonos/test.py (100%) rename {cli => packages/cli}/canyonos/theme.py (100%) rename {cli => packages/cli}/canyonos/ui.py (100%) rename {cli => packages/cli}/canyonos/verify.py (100%) rename {cli => packages/cli}/cli.py (100%) rename {cli => packages/cli}/install.sh (100%) rename {cli => packages/cli}/pyproject.toml (100%) rename {cli/canyonos => packages/cli/utils}/__init__.py (100%) rename {cli => packages/cli}/utils/help_screen.py (100%) rename {cli => packages/cli}/utils/tui.py (100%) rename .dockerignore => packages/core/.dockerignore (61%) rename {canyonos_core => packages/core}/Dockerfile (100%) rename {canyonos_core => packages/core/canyonos_core}/FUTURE_SCHEMA.md (100%) rename {canyonos_core => packages/core/canyonos_core}/OTLP_Exporter/DESIGN.md (100%) rename {canyonos_core => packages/core/canyonos_core}/OTLP_Exporter/SCHEMA.md (100%) rename {cli/utils => packages/core/canyonos_core/OTLP_Exporter}/__init__.py (100%) rename {canyonos_core => packages/core/canyonos_core}/OTLP_Exporter/convert.py (100%) rename {canyonos_core => packages/core/canyonos_core}/OTLP_Exporter/db.py (100%) rename {canyonos_core => packages/core/canyonos_core}/OTLP_Exporter/otel_exporter.py (100%) rename {canyonos_core => packages/core/canyonos_core}/OTLP_Exporter/otel_queue.db (100%) rename {canyonos_core => packages/core/canyonos_core}/README.md (100%) rename {canyonos_core => packages/core/canyonos_core}/__init__.py (100%) rename {canyonos_core => packages/core/canyonos_core}/cli.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/__init__.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/canyonos_context.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/cloud_provider_logic/EC2/README.md (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/cloud_provider_logic/EC2/_runtime.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/cloud_provider_logic/Local/_runtime.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/deploy.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/future.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/global_controller.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/instance_manager.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/local_controller.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/local_controller_frontend.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/proto/global_controller.proto (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/proto/local_controler.proto (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/__init__.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/agent_specs.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/aws_pricing_chart.db (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/container_names.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/env_file.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/gpu_metrics.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/grpc_options.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/pricing.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/process_supervisor.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/redis_client.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/redis_utils.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/session_logging.py (100%) rename {canyonos_core => packages/core/canyonos_core}/controller/utils/telemetry_logging.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/README.md (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/__init__.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/__main__.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/app.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/config.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/core.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/hooks.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/providers/__init__.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/providers/anthropic.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/providers/base.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/providers/bedrock.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/providers/openai.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/proxy.py (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/requirements.txt (100%) rename {canyonos_core => packages/core/canyonos_core}/llm_proxy/stub.py (100%) rename {canyonos_core => packages/core/canyonos_core}/server.py (100%) rename {canyonos_core => packages/core/canyonos_core}/stub_generator.py (100%) create mode 100644 packages/core/pyproject.toml delete mode 100644 requirements.txt create mode 100644 turbo.json diff --git a/.gitignore b/.gitignore index cbb9e05e..abae86e0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,10 @@ build/ *.egg-info/ *.egg +# Node / Turborepo +node_modules/ +.turbo/ + # Virtual environments venv/ .venv/ @@ -44,7 +48,6 @@ docker_container/ !.env.example AWSCLIV2.pkg .python-version -uv.lock Agent Artifacts docs/ diff --git a/bun.lock b/bun.lock new file mode 100644 index 00000000..2326e146 --- /dev/null +++ b/bun.lock @@ -0,0 +1,27 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "canyoncodecore", + "devDependencies": { + "turbo": "2.10.13", + }, + }, + }, + "packages": { + "@turbo/darwin-64": ["@turbo/darwin-64@2.10.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-m5DBcpkxmcKpEJHHFUfqf9GLUjSmw3cDnBJM9nghPW3kjCNb5OyNKmzG7/yT5x5AwzOO+HMwKN+UI4iVKL87YA=="], + + "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.10.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vfKPvSuoY8BJGj8M8yN+a7aq1g+CejbEacDSDlJLDkSbPN3J/U1DbYAmPG8Ype5XvImI0SgfvUhIorNnFj67zw=="], + + "@turbo/linux-64": ["@turbo/linux-64@2.10.13", "", { "os": [ "linux", "android", ], "cpu": "x64" }, "sha512-Zp0N5M6j9iEjJtFLTA2L+52TLuYy0VbXT3zLZzfMeqqdKSUJ7pDo2pA1NhqjoQcF2dIsktZ8xZRW3pGI6T81fw=="], + + "@turbo/linux-arm64": ["@turbo/linux-arm64@2.10.13", "", { "os": [ "linux", "android", ], "cpu": "arm64" }, "sha512-M8XcfWdS2D4EP3wzd5ehUyCANucMIOsRE6gZuV0Mr2NIn+FpsUjXFCh7r9HY7GnNcjXH4tUnT76OsCDg2c0Fng=="], + + "@turbo/windows-64": ["@turbo/windows-64@2.10.13", "", { "os": "win32", "cpu": "x64" }, "sha512-QFd3KBMpBBCc31TbxMnxgdBivie8lxJXV8EqmanH8fg8l2e1BdCLWpZJbxk48VNvcF4LHUnwO0FJOq+veKN1cw=="], + + "@turbo/windows-arm64": ["@turbo/windows-arm64@2.10.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-rM+cFO1P8iAHXdasOdMyK9nDk0UGII7VEFLIA8+jwv/+rh48pnVBbF2OSjJDBOw57pxNLIOEDA0JyKcarTBcIw=="], + + "turbo": ["turbo@2.10.13", "", { "optionalDependencies": { "@turbo/darwin-64": "2.10.13", "@turbo/darwin-arm64": "2.10.13", "@turbo/linux-64": "2.10.13", "@turbo/linux-arm64": "2.10.13", "@turbo/windows-64": "2.10.13", "@turbo/windows-arm64": "2.10.13" }, "bin": { "turbo": "bin/turbo" } }, "sha512-69MkPbjk+G8oyC7pC2DeBk0rPdbLz51wuH5eAT0Q4BVJkzq/b1XM4kUUidsARbmDjwIELSJwd1ezITULY9kWNw=="], + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..ef4116a0 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "canyoncodecore", + "private": true, + "workspaces": [ + "apps/*", + "packages/*" + ], + "engines": { + "bun": ">=1.3.1" + }, + "packageManager": "bun@1.3.14", + "scripts": { + "lint": "turbo run lint", + "typecheck": "turbo run typecheck", + "check": "turbo run lint typecheck format:check", + "format": "turbo run format", + "test": "turbo run test", + "build": "turbo run build" + }, + "devDependencies": { + "turbo": "2.10.13" + } +} diff --git a/cli/ARCHITECTURE.md b/packages/cli/ARCHITECTURE.md similarity index 100% rename from cli/ARCHITECTURE.md rename to packages/cli/ARCHITECTURE.md diff --git a/cli/README.md b/packages/cli/README.md similarity index 100% rename from cli/README.md rename to packages/cli/README.md diff --git a/canyonos_core/OTLP_Exporter/__init__.py b/packages/cli/canyonos/__init__.py similarity index 100% rename from canyonos_core/OTLP_Exporter/__init__.py rename to packages/cli/canyonos/__init__.py diff --git a/cli/canyonos/build.py b/packages/cli/canyonos/build.py similarity index 100% rename from cli/canyonos/build.py rename to packages/cli/canyonos/build.py diff --git a/cli/canyonos/clean.py b/packages/cli/canyonos/clean.py similarity index 100% rename from cli/canyonos/clean.py rename to packages/cli/canyonos/clean.py diff --git a/cli/canyonos/config.py b/packages/cli/canyonos/config.py similarity index 100% rename from cli/canyonos/config.py rename to packages/cli/canyonos/config.py diff --git a/cli/canyonos/constants.py b/packages/cli/canyonos/constants.py similarity index 100% rename from cli/canyonos/constants.py rename to packages/cli/canyonos/constants.py diff --git a/cli/canyonos/dashboard.compose.yml b/packages/cli/canyonos/dashboard.compose.yml similarity index 100% rename from cli/canyonos/dashboard.compose.yml rename to packages/cli/canyonos/dashboard.compose.yml diff --git a/cli/canyonos/dashboard_stack.py b/packages/cli/canyonos/dashboard_stack.py similarity index 100% rename from cli/canyonos/dashboard_stack.py rename to packages/cli/canyonos/dashboard_stack.py diff --git a/cli/canyonos/deploy.py b/packages/cli/canyonos/deploy.py similarity index 100% rename from cli/canyonos/deploy.py rename to packages/cli/canyonos/deploy.py diff --git a/cli/canyonos/doctor.py b/packages/cli/canyonos/doctor.py similarity index 100% rename from cli/canyonos/doctor.py rename to packages/cli/canyonos/doctor.py diff --git a/cli/canyonos/gc.py b/packages/cli/canyonos/gc.py similarity index 100% rename from cli/canyonos/gc.py rename to packages/cli/canyonos/gc.py diff --git a/cli/canyonos/init.py b/packages/cli/canyonos/init.py similarity index 100% rename from cli/canyonos/init.py rename to packages/cli/canyonos/init.py diff --git a/cli/canyonos/logs.py b/packages/cli/canyonos/logs.py similarity index 100% rename from cli/canyonos/logs.py rename to packages/cli/canyonos/logs.py diff --git a/cli/canyonos/new_app.py b/packages/cli/canyonos/new_app.py similarity index 100% rename from cli/canyonos/new_app.py rename to packages/cli/canyonos/new_app.py diff --git a/cli/canyonos/quit.py b/packages/cli/canyonos/quit.py similarity index 100% rename from cli/canyonos/quit.py rename to packages/cli/canyonos/quit.py diff --git a/cli/canyonos/serve.py b/packages/cli/canyonos/serve.py similarity index 100% rename from cli/canyonos/serve.py rename to packages/cli/canyonos/serve.py diff --git a/cli/canyonos/status.py b/packages/cli/canyonos/status.py similarity index 100% rename from cli/canyonos/status.py rename to packages/cli/canyonos/status.py diff --git a/cli/canyonos/stop.py b/packages/cli/canyonos/stop.py similarity index 100% rename from cli/canyonos/stop.py rename to packages/cli/canyonos/stop.py diff --git a/cli/canyonos/sync.py b/packages/cli/canyonos/sync.py similarity index 100% rename from cli/canyonos/sync.py rename to packages/cli/canyonos/sync.py diff --git a/cli/canyonos/test.py b/packages/cli/canyonos/test.py similarity index 100% rename from cli/canyonos/test.py rename to packages/cli/canyonos/test.py diff --git a/cli/canyonos/theme.py b/packages/cli/canyonos/theme.py similarity index 100% rename from cli/canyonos/theme.py rename to packages/cli/canyonos/theme.py diff --git a/cli/canyonos/ui.py b/packages/cli/canyonos/ui.py similarity index 100% rename from cli/canyonos/ui.py rename to packages/cli/canyonos/ui.py diff --git a/cli/canyonos/verify.py b/packages/cli/canyonos/verify.py similarity index 100% rename from cli/canyonos/verify.py rename to packages/cli/canyonos/verify.py diff --git a/cli/cli.py b/packages/cli/cli.py similarity index 100% rename from cli/cli.py rename to packages/cli/cli.py diff --git a/cli/install.sh b/packages/cli/install.sh similarity index 100% rename from cli/install.sh rename to packages/cli/install.sh diff --git a/cli/pyproject.toml b/packages/cli/pyproject.toml similarity index 100% rename from cli/pyproject.toml rename to packages/cli/pyproject.toml diff --git a/cli/canyonos/__init__.py b/packages/cli/utils/__init__.py similarity index 100% rename from cli/canyonos/__init__.py rename to packages/cli/utils/__init__.py diff --git a/cli/utils/help_screen.py b/packages/cli/utils/help_screen.py similarity index 100% rename from cli/utils/help_screen.py rename to packages/cli/utils/help_screen.py diff --git a/cli/utils/tui.py b/packages/cli/utils/tui.py similarity index 100% rename from cli/utils/tui.py rename to packages/cli/utils/tui.py diff --git a/.dockerignore b/packages/core/.dockerignore similarity index 61% rename from .dockerignore rename to packages/core/.dockerignore index ab0acb8b..3e0bd8b3 100644 --- a/.dockerignore +++ b/packages/core/.dockerignore @@ -1,7 +1,4 @@ -.git -.omx .pytest_cache -.venv .env .env.* !.env.example @@ -15,8 +12,6 @@ __pycache__ ._* Thumbs.db .DS_Store -AWSCLIV2.pkg -docker_container -grpc_stubs -stubs -tests +node_modules +.turbo +dist diff --git a/canyonos_core/Dockerfile b/packages/core/Dockerfile similarity index 100% rename from canyonos_core/Dockerfile rename to packages/core/Dockerfile diff --git a/canyonos_core/FUTURE_SCHEMA.md b/packages/core/canyonos_core/FUTURE_SCHEMA.md similarity index 100% rename from canyonos_core/FUTURE_SCHEMA.md rename to packages/core/canyonos_core/FUTURE_SCHEMA.md diff --git a/canyonos_core/OTLP_Exporter/DESIGN.md b/packages/core/canyonos_core/OTLP_Exporter/DESIGN.md similarity index 100% rename from canyonos_core/OTLP_Exporter/DESIGN.md rename to packages/core/canyonos_core/OTLP_Exporter/DESIGN.md diff --git a/canyonos_core/OTLP_Exporter/SCHEMA.md b/packages/core/canyonos_core/OTLP_Exporter/SCHEMA.md similarity index 100% rename from canyonos_core/OTLP_Exporter/SCHEMA.md rename to packages/core/canyonos_core/OTLP_Exporter/SCHEMA.md diff --git a/cli/utils/__init__.py b/packages/core/canyonos_core/OTLP_Exporter/__init__.py similarity index 100% rename from cli/utils/__init__.py rename to packages/core/canyonos_core/OTLP_Exporter/__init__.py diff --git a/canyonos_core/OTLP_Exporter/convert.py b/packages/core/canyonos_core/OTLP_Exporter/convert.py similarity index 100% rename from canyonos_core/OTLP_Exporter/convert.py rename to packages/core/canyonos_core/OTLP_Exporter/convert.py diff --git a/canyonos_core/OTLP_Exporter/db.py b/packages/core/canyonos_core/OTLP_Exporter/db.py similarity index 100% rename from canyonos_core/OTLP_Exporter/db.py rename to packages/core/canyonos_core/OTLP_Exporter/db.py diff --git a/canyonos_core/OTLP_Exporter/otel_exporter.py b/packages/core/canyonos_core/OTLP_Exporter/otel_exporter.py similarity index 100% rename from canyonos_core/OTLP_Exporter/otel_exporter.py rename to packages/core/canyonos_core/OTLP_Exporter/otel_exporter.py diff --git a/canyonos_core/OTLP_Exporter/otel_queue.db b/packages/core/canyonos_core/OTLP_Exporter/otel_queue.db similarity index 100% rename from canyonos_core/OTLP_Exporter/otel_queue.db rename to packages/core/canyonos_core/OTLP_Exporter/otel_queue.db diff --git a/canyonos_core/README.md b/packages/core/canyonos_core/README.md similarity index 100% rename from canyonos_core/README.md rename to packages/core/canyonos_core/README.md diff --git a/canyonos_core/__init__.py b/packages/core/canyonos_core/__init__.py similarity index 100% rename from canyonos_core/__init__.py rename to packages/core/canyonos_core/__init__.py diff --git a/canyonos_core/cli.py b/packages/core/canyonos_core/cli.py similarity index 100% rename from canyonos_core/cli.py rename to packages/core/canyonos_core/cli.py diff --git a/canyonos_core/controller/__init__.py b/packages/core/canyonos_core/controller/__init__.py similarity index 100% rename from canyonos_core/controller/__init__.py rename to packages/core/canyonos_core/controller/__init__.py diff --git a/canyonos_core/controller/canyonos_context.py b/packages/core/canyonos_core/controller/canyonos_context.py similarity index 100% rename from canyonos_core/controller/canyonos_context.py rename to packages/core/canyonos_core/controller/canyonos_context.py diff --git a/canyonos_core/controller/cloud_provider_logic/EC2/README.md b/packages/core/canyonos_core/controller/cloud_provider_logic/EC2/README.md similarity index 100% rename from canyonos_core/controller/cloud_provider_logic/EC2/README.md rename to packages/core/canyonos_core/controller/cloud_provider_logic/EC2/README.md diff --git a/canyonos_core/controller/cloud_provider_logic/EC2/_runtime.py b/packages/core/canyonos_core/controller/cloud_provider_logic/EC2/_runtime.py similarity index 100% rename from canyonos_core/controller/cloud_provider_logic/EC2/_runtime.py rename to packages/core/canyonos_core/controller/cloud_provider_logic/EC2/_runtime.py diff --git a/canyonos_core/controller/cloud_provider_logic/Local/_runtime.py b/packages/core/canyonos_core/controller/cloud_provider_logic/Local/_runtime.py similarity index 100% rename from canyonos_core/controller/cloud_provider_logic/Local/_runtime.py rename to packages/core/canyonos_core/controller/cloud_provider_logic/Local/_runtime.py diff --git a/canyonos_core/controller/deploy.py b/packages/core/canyonos_core/controller/deploy.py similarity index 100% rename from canyonos_core/controller/deploy.py rename to packages/core/canyonos_core/controller/deploy.py diff --git a/canyonos_core/controller/future.py b/packages/core/canyonos_core/controller/future.py similarity index 100% rename from canyonos_core/controller/future.py rename to packages/core/canyonos_core/controller/future.py diff --git a/canyonos_core/controller/global_controller.py b/packages/core/canyonos_core/controller/global_controller.py similarity index 100% rename from canyonos_core/controller/global_controller.py rename to packages/core/canyonos_core/controller/global_controller.py diff --git a/canyonos_core/controller/instance_manager.py b/packages/core/canyonos_core/controller/instance_manager.py similarity index 100% rename from canyonos_core/controller/instance_manager.py rename to packages/core/canyonos_core/controller/instance_manager.py diff --git a/canyonos_core/controller/local_controller.py b/packages/core/canyonos_core/controller/local_controller.py similarity index 100% rename from canyonos_core/controller/local_controller.py rename to packages/core/canyonos_core/controller/local_controller.py diff --git a/canyonos_core/controller/local_controller_frontend.py b/packages/core/canyonos_core/controller/local_controller_frontend.py similarity index 100% rename from canyonos_core/controller/local_controller_frontend.py rename to packages/core/canyonos_core/controller/local_controller_frontend.py diff --git a/canyonos_core/controller/proto/global_controller.proto b/packages/core/canyonos_core/controller/proto/global_controller.proto similarity index 100% rename from canyonos_core/controller/proto/global_controller.proto rename to packages/core/canyonos_core/controller/proto/global_controller.proto diff --git a/canyonos_core/controller/proto/local_controler.proto b/packages/core/canyonos_core/controller/proto/local_controler.proto similarity index 100% rename from canyonos_core/controller/proto/local_controler.proto rename to packages/core/canyonos_core/controller/proto/local_controler.proto diff --git a/canyonos_core/controller/utils/__init__.py b/packages/core/canyonos_core/controller/utils/__init__.py similarity index 100% rename from canyonos_core/controller/utils/__init__.py rename to packages/core/canyonos_core/controller/utils/__init__.py diff --git a/canyonos_core/controller/utils/agent_specs.py b/packages/core/canyonos_core/controller/utils/agent_specs.py similarity index 100% rename from canyonos_core/controller/utils/agent_specs.py rename to packages/core/canyonos_core/controller/utils/agent_specs.py diff --git a/canyonos_core/controller/utils/aws_pricing_chart.db b/packages/core/canyonos_core/controller/utils/aws_pricing_chart.db similarity index 100% rename from canyonos_core/controller/utils/aws_pricing_chart.db rename to packages/core/canyonos_core/controller/utils/aws_pricing_chart.db diff --git a/canyonos_core/controller/utils/container_names.py b/packages/core/canyonos_core/controller/utils/container_names.py similarity index 100% rename from canyonos_core/controller/utils/container_names.py rename to packages/core/canyonos_core/controller/utils/container_names.py diff --git a/canyonos_core/controller/utils/env_file.py b/packages/core/canyonos_core/controller/utils/env_file.py similarity index 100% rename from canyonos_core/controller/utils/env_file.py rename to packages/core/canyonos_core/controller/utils/env_file.py diff --git a/canyonos_core/controller/utils/gpu_metrics.py b/packages/core/canyonos_core/controller/utils/gpu_metrics.py similarity index 100% rename from canyonos_core/controller/utils/gpu_metrics.py rename to packages/core/canyonos_core/controller/utils/gpu_metrics.py diff --git a/canyonos_core/controller/utils/grpc_options.py b/packages/core/canyonos_core/controller/utils/grpc_options.py similarity index 100% rename from canyonos_core/controller/utils/grpc_options.py rename to packages/core/canyonos_core/controller/utils/grpc_options.py diff --git a/canyonos_core/controller/utils/pricing.py b/packages/core/canyonos_core/controller/utils/pricing.py similarity index 100% rename from canyonos_core/controller/utils/pricing.py rename to packages/core/canyonos_core/controller/utils/pricing.py diff --git a/canyonos_core/controller/utils/process_supervisor.py b/packages/core/canyonos_core/controller/utils/process_supervisor.py similarity index 100% rename from canyonos_core/controller/utils/process_supervisor.py rename to packages/core/canyonos_core/controller/utils/process_supervisor.py diff --git a/canyonos_core/controller/utils/redis_client.py b/packages/core/canyonos_core/controller/utils/redis_client.py similarity index 100% rename from canyonos_core/controller/utils/redis_client.py rename to packages/core/canyonos_core/controller/utils/redis_client.py diff --git a/canyonos_core/controller/utils/redis_utils.py b/packages/core/canyonos_core/controller/utils/redis_utils.py similarity index 100% rename from canyonos_core/controller/utils/redis_utils.py rename to packages/core/canyonos_core/controller/utils/redis_utils.py diff --git a/canyonos_core/controller/utils/session_logging.py b/packages/core/canyonos_core/controller/utils/session_logging.py similarity index 100% rename from canyonos_core/controller/utils/session_logging.py rename to packages/core/canyonos_core/controller/utils/session_logging.py diff --git a/canyonos_core/controller/utils/telemetry_logging.py b/packages/core/canyonos_core/controller/utils/telemetry_logging.py similarity index 100% rename from canyonos_core/controller/utils/telemetry_logging.py rename to packages/core/canyonos_core/controller/utils/telemetry_logging.py diff --git a/canyonos_core/llm_proxy/README.md b/packages/core/canyonos_core/llm_proxy/README.md similarity index 100% rename from canyonos_core/llm_proxy/README.md rename to packages/core/canyonos_core/llm_proxy/README.md diff --git a/canyonos_core/llm_proxy/__init__.py b/packages/core/canyonos_core/llm_proxy/__init__.py similarity index 100% rename from canyonos_core/llm_proxy/__init__.py rename to packages/core/canyonos_core/llm_proxy/__init__.py diff --git a/canyonos_core/llm_proxy/__main__.py b/packages/core/canyonos_core/llm_proxy/__main__.py similarity index 100% rename from canyonos_core/llm_proxy/__main__.py rename to packages/core/canyonos_core/llm_proxy/__main__.py diff --git a/canyonos_core/llm_proxy/app.py b/packages/core/canyonos_core/llm_proxy/app.py similarity index 100% rename from canyonos_core/llm_proxy/app.py rename to packages/core/canyonos_core/llm_proxy/app.py diff --git a/canyonos_core/llm_proxy/config.py b/packages/core/canyonos_core/llm_proxy/config.py similarity index 100% rename from canyonos_core/llm_proxy/config.py rename to packages/core/canyonos_core/llm_proxy/config.py diff --git a/canyonos_core/llm_proxy/core.py b/packages/core/canyonos_core/llm_proxy/core.py similarity index 100% rename from canyonos_core/llm_proxy/core.py rename to packages/core/canyonos_core/llm_proxy/core.py diff --git a/canyonos_core/llm_proxy/hooks.py b/packages/core/canyonos_core/llm_proxy/hooks.py similarity index 100% rename from canyonos_core/llm_proxy/hooks.py rename to packages/core/canyonos_core/llm_proxy/hooks.py diff --git a/canyonos_core/llm_proxy/providers/__init__.py b/packages/core/canyonos_core/llm_proxy/providers/__init__.py similarity index 100% rename from canyonos_core/llm_proxy/providers/__init__.py rename to packages/core/canyonos_core/llm_proxy/providers/__init__.py diff --git a/canyonos_core/llm_proxy/providers/anthropic.py b/packages/core/canyonos_core/llm_proxy/providers/anthropic.py similarity index 100% rename from canyonos_core/llm_proxy/providers/anthropic.py rename to packages/core/canyonos_core/llm_proxy/providers/anthropic.py diff --git a/canyonos_core/llm_proxy/providers/base.py b/packages/core/canyonos_core/llm_proxy/providers/base.py similarity index 100% rename from canyonos_core/llm_proxy/providers/base.py rename to packages/core/canyonos_core/llm_proxy/providers/base.py diff --git a/canyonos_core/llm_proxy/providers/bedrock.py b/packages/core/canyonos_core/llm_proxy/providers/bedrock.py similarity index 100% rename from canyonos_core/llm_proxy/providers/bedrock.py rename to packages/core/canyonos_core/llm_proxy/providers/bedrock.py diff --git a/canyonos_core/llm_proxy/providers/openai.py b/packages/core/canyonos_core/llm_proxy/providers/openai.py similarity index 100% rename from canyonos_core/llm_proxy/providers/openai.py rename to packages/core/canyonos_core/llm_proxy/providers/openai.py diff --git a/canyonos_core/llm_proxy/proxy.py b/packages/core/canyonos_core/llm_proxy/proxy.py similarity index 100% rename from canyonos_core/llm_proxy/proxy.py rename to packages/core/canyonos_core/llm_proxy/proxy.py diff --git a/canyonos_core/llm_proxy/requirements.txt b/packages/core/canyonos_core/llm_proxy/requirements.txt similarity index 100% rename from canyonos_core/llm_proxy/requirements.txt rename to packages/core/canyonos_core/llm_proxy/requirements.txt diff --git a/canyonos_core/llm_proxy/stub.py b/packages/core/canyonos_core/llm_proxy/stub.py similarity index 100% rename from canyonos_core/llm_proxy/stub.py rename to packages/core/canyonos_core/llm_proxy/stub.py diff --git a/canyonos_core/server.py b/packages/core/canyonos_core/server.py similarity index 100% rename from canyonos_core/server.py rename to packages/core/canyonos_core/server.py diff --git a/canyonos_core/stub_generator.py b/packages/core/canyonos_core/stub_generator.py similarity index 100% rename from canyonos_core/stub_generator.py rename to packages/core/canyonos_core/stub_generator.py diff --git a/packages/core/pyproject.toml b/packages/core/pyproject.toml new file mode 100644 index 00000000..57c1e6de --- /dev/null +++ b/packages/core/pyproject.toml @@ -0,0 +1,38 @@ +[project] +name = "canyonos-core" +version = "0.1.0" +description = "Distributed agent orchestration framework (CanyonOS core runtime)" +requires-python = ">=3.10" +dependencies = [ + "boto3==1.43.91", + "grpcio==1.83.1", + "grpcio-tools==1.65.5", + "redis==8.1.0", + "sqlalchemy", + "psycopg[binary]", + "pyyaml==6.0.3", + "flask==3.1.3", + "requests==2.34.2", + "psutil==7.2.2", + "opentelemetry-api>=1.44.0", + "opentelemetry-sdk>=1.44.0", + "opentelemetry-exporter-otlp-proto-grpc>=1.44.0", + "opentelemetry-exporter-otlp-proto-http>=1.44.0", +] + +# Import-only: the core runtime ships no console script. The user-facing `canyonos` +# executable lives in the separate `packages/cli` distribution. In-container entrypoints +# are invoked as `python -m canyonos_core.server` / `.cli` / `.llm_proxy`. + +[build-system] +requires = ["setuptools>=64"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +include = ["canyonos_core*"] + +[tool.setuptools.package-data] +canyonos_core = [ + "controller/proto/*.proto", + "controller/utils/aws_pricing_chart.db", +] diff --git a/pyproject.toml b/pyproject.toml index 16753dc6..b38e5471 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,40 +1,23 @@ -[project] -name = "canyonos-core" -version = "0.1.0" -description = "Distributed agent orchestration framework (CanyonOS core runtime)" -requires-python = ">=3.10" -dependencies = [ - "boto3==1.43.91", - "grpcio==1.83.1", - "grpcio-tools==1.65.5", - "redis==8.1.0", - "sqlalchemy", - "psycopg[binary]", - "pyyaml==6.0.3", - "flask==3.1.3", - "requests==2.34.2", - "psutil==7.2.2", - "opentelemetry-api>=1.44.0", - "opentelemetry-sdk>=1.44.0", - "opentelemetry-exporter-otlp-proto-grpc>=1.44.0", - "opentelemetry-exporter-otlp-proto-http>=1.44.0", -] +[tool.turbo] +name = "canyonos-python" -# Import-only: the core runtime ships no console script. The user-facing `canyonos` -# executable lives in the separate `cli/` distribution. In-container entrypoints are -# invoked as `python -m canyonos_core.server` / `.cli` / `.llm_proxy`. +[tool.uv.workspace] +members = ["packages/*"] -[build-system] -requires = ["setuptools>=64"] -build-backend = "setuptools.build_meta" +[tool.uv] +required-version = ">=0.12.15" -[tool.setuptools.packages.find] -include = ["canyonos_core*"] +[tool.uv.sources] +canyonos-core = { workspace = true } +canyonos = { workspace = true } -[tool.setuptools.package-data] -canyonos_core = [ - "controller/proto/*.proto", - "controller/utils/aws_pricing_chart.db", +[dependency-groups] +dev = [ + "pytest>=9.1.1", + "ruff==0.16.7", + "ty==0.0.81", + "canyonos-core", + "canyonos", ] [tool.ruff] @@ -53,9 +36,9 @@ ignore = ["E402"] python = ".venv" [tool.ty.src] -include = ["canyonos_core"] +include = ["packages/core/canyonos_core"] exclude = [ - "canyonos_core/stub_generator.py", + "packages/core/canyonos_core/stub_generator.py", ] [tool.ty.analysis] @@ -76,15 +59,3 @@ allowed-unresolved-imports = [ "*_stub", "*_agent_stub", ] - -[dependency-groups] -dev = [ - "pytest>=9.1.1", - # The standalone user CLI (`canyonos`) lives in cli/. It is a DISTINCT - # distribution from this `canyonos-core` runtime, so there is no name - # collision; the root test suite imports it to cover CLI behavior. - "canyonos", -] - -[tool.uv.sources] -canyonos = { path = "cli", editable = true } diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index b0b4be29..00000000 --- a/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -boto3==1.43.91 -grpcio==1.83.1 -grpcio-tools==1.65.5 -redis==8.1.0 -pyyaml==6.0.3 -flask==3.1.3 -requests==2.34.2 -sqlalchemy -psycopg[binary] -psutil==7.2.2 -opentelemetry-api -opentelemetry-sdk -opentelemetry-exporter-otlp-proto-grpc -opentelemetry-exporter-otlp-proto-http diff --git a/tests/test_otel_exporter_fanout.py b/tests/test_otel_exporter_fanout.py index bbf13a2d..41f01be4 100644 --- a/tests/test_otel_exporter_fanout.py +++ b/tests/test_otel_exporter_fanout.py @@ -13,7 +13,9 @@ ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) # ``otel_exporter.py`` is also executed as a script from its own directory and # therefore imports ``convert`` and ``db`` as top-level modules. -sys.path.insert(0, os.path.join(ROOT, "canyonos_core", "OTLP_Exporter")) +sys.path.insert( + 0, os.path.join(ROOT, "packages", "core", "canyonos_core", "OTLP_Exporter") +) from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import ( # noqa: E402 ExportTraceServiceResponse, diff --git a/turbo.json b/turbo.json new file mode 100644 index 00000000..bb19ce92 --- /dev/null +++ b/turbo.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://turborepo.dev/schema.json", + "futureFlags": { + "experimentalPythonWorkspaces": true, + "experimentalTaskCommand": true + }, + "tasks": { + "build": { + "cache": true, + "outputs": [ + "dist/**" + ] + }, + "canyonos-python#lint": { + "command": [ + "uv", + "run", + "--active", + "--frozen", + "ruff", + "check", + "." + ] + }, + "canyonos-python#typecheck": { + "command": [ + "uv", + "run", + "--active", + "--frozen", + "ty", + "check" + ] + }, + "canyonos-python#format": { + "cache": false, + "command": [ + "uv", + "run", + "--active", + "--frozen", + "ruff", + "format", + "." + ] + }, + "canyonos-python#format:check": { + "command": [ + "uv", + "run", + "--active", + "--frozen", + "ruff", + "format", + "--check", + "." + ] + } + } +} diff --git a/uv.lock b/uv.lock index 2ee739b1..1592989c 100644 --- a/uv.lock +++ b/uv.lock @@ -7,6 +7,21 @@ resolution-markers = [ "python_full_version < '3.13'", ] +[manifest] +members = [ + "canyonos", + "canyonos-core", +] + +[manifest.dependency-groups] +dev = [ + { name = "canyonos", editable = "packages/cli" }, + { name = "canyonos-core", editable = "packages/core" }, + { name = "pytest", specifier = ">=9.1.1" }, + { name = "ruff", specifier = "==0.16.7" }, + { name = "ty", specifier = "==0.0.81" }, +] + [[package]] name = "async-timeout" version = "5.0.1" @@ -55,8 +70,8 @@ wheels = [ [[package]] name = "canyonos" -version = "0.1.717" -source = { editable = "cli" } +version = "0.1.721" +source = { editable = "packages/cli" } dependencies = [ { name = "pyfiglet" }, { name = "pyyaml" }, @@ -75,7 +90,7 @@ requires-dist = [ [[package]] name = "canyonos-core" version = "0.1.0" -source = { editable = "." } +source = { editable = "packages/core" } dependencies = [ { name = "boto3" }, { name = "flask" }, @@ -93,12 +108,6 @@ dependencies = [ { name = "sqlalchemy" }, ] -[package.dev-dependencies] -dev = [ - { name = "canyonos" }, - { name = "pytest" }, -] - [package.metadata] requires-dist = [ { name = "boto3", specifier = "==1.43.91" }, @@ -117,12 +126,6 @@ requires-dist = [ { name = "sqlalchemy" }, ] -[package.metadata.requires-dev] -dev = [ - { name = "canyonos", editable = "cli" }, - { name = "pytest", specifier = ">=9.1.1" }, -] - [[package]] name = "certifi" version = "2026.7.22" @@ -1079,6 +1082,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93", size = 118102, upload-time = "2026-01-02T16:50:29.201Z" }, ] +[[package]] +name = "ruff" +version = "0.16.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/bb/5a449b9162e49b139d72f61672bd3ac1d790221f796d3304e2241fff4c58/ruff-0.16.7.tar.gz", hash = "sha256:5f71d004ac1263b22fa39462ac5ae618a4b77d58981af2cc79bf79a29c12b1a6", size = 4924184, upload-time = "2026-09-10T18:04:06.336Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/b2/c80aeeb7f9e469c0d63a85d2f1ab6e1ebfbe10ea7a8d2438b7e09e3ff09e/ruff-0.16.7-py3-none-linux_armv6l.whl", hash = "sha256:727307773e7c7f9181d3ed3a2484186e56c1fa1874255911c74585eb2c7c19f9", size = 10048917, upload-time = "2026-09-10T18:03:30.28Z" }, + { url = "https://files.pythonhosted.org/packages/7b/96/20bb7bcae008004df52afcb7ac83432d4a467f2c17b672fe46d26be231c5/ruff-0.16.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9d61c258deabf58f34c67bd4bb4d939c7f2e6b5f0e59c1cdd1cf771b11cde929", size = 10242929, upload-time = "2026-09-10T18:03:32.706Z" }, + { url = "https://files.pythonhosted.org/packages/90/b2/f184b0d5abec02db69cfd7e49b688ae0237554528ca777136c613bf36bee/ruff-0.16.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7ab81118df8945e0193d0240712aa4496573595b75185c3636ed825592a0f728", size = 9847245, upload-time = "2026-09-10T18:03:34.509Z" }, + { url = "https://files.pythonhosted.org/packages/eb/2d/db1633a641866ed801e34cc6b60ef236c5e16f9b2124ab1d49cc24a5fe4f/ruff-0.16.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c196c968874fc8019da8e7163de7a1a370f111e2309b4b7dfea0fce950198d0", size = 9961780, upload-time = "2026-09-10T18:03:36.618Z" }, + { url = "https://files.pythonhosted.org/packages/4d/98/edea21e1a3e38dbbc3bf6bb068b863b3b06184cf8533a4c7dbbe208a89d5/ruff-0.16.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac8c3bd0a7e10ad31e6ce51e7a99f3cb772e69aecdd6b9ea7e99b362f62a62c0", size = 9866337, upload-time = "2026-09-10T18:03:38.805Z" }, + { url = "https://files.pythonhosted.org/packages/0b/11/a15e60d4c87b214646f116ca9d204475bf993ee1047459bc9a360fd4d6d1/ruff-0.16.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:398d3988edde000b5c75dc1b3f584708da9bc990de069c18909142580fec1af9", size = 10562512, upload-time = "2026-09-10T18:03:40.71Z" }, + { url = "https://files.pythonhosted.org/packages/29/42/eaff4c9b6d0c7cdf56df313a17e89ae854f5bbc0b0c8f9cce19be0ab7a8f/ruff-0.16.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce05b62b770a8217c4646a9c4139fca00efe8fe5d71f87df2b243ff20d4584d1", size = 11302938, upload-time = "2026-09-10T18:03:42.607Z" }, + { url = "https://files.pythonhosted.org/packages/5d/43/c75aa59a4ec181fe2ec06cab30e198c1c6d107229a9f008ae3a7c16cabd8/ruff-0.16.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af1b576fddb9d9ef2ececfb5fadcd6a624b25070ed85e3cfcfe449fc3ff6a7b9", size = 10840857, upload-time = "2026-09-10T18:03:44.604Z" }, + { url = "https://files.pythonhosted.org/packages/21/33/81f3da371942ea031105ba679d8d6e28ec1660ccd690a45f42d381161356/ruff-0.16.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce7f8f22df67c93ed96c717f9128eadb797144ac2bad475cf536f31d6100c55", size = 10370001, upload-time = "2026-09-10T18:03:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/fa/0b/6345fb4dbf6dd0ed1cfe5d18391dc9c3f59cc81622a7b0a65b84b3e730ba/ruff-0.16.7-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:06d0e93d04f392996435ebd600c153f65b47d73fbec2415aa99c5ee5756b3a5f", size = 10548735, upload-time = "2026-09-10T18:03:48.658Z" }, + { url = "https://files.pythonhosted.org/packages/3f/4d/c5576adf511f92a328e5569dda190ecdd430da51f1a649f3a4a2fd73e21e/ruff-0.16.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:142151a5e7b93c1b11111337142f89dd2fbfee92161225c99a97222f22e32656", size = 10108496, upload-time = "2026-09-10T18:03:50.563Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8c/667d83c16199a17a56adc6b0bd4c3beb5b767a2babcd16a56f76f9be7fd6/ruff-0.16.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e6651f97a342d8b35d54d8991544ca22169b86dc54111cb604666940c431b750", size = 9860136, upload-time = "2026-09-10T18:03:52.621Z" }, + { url = "https://files.pythonhosted.org/packages/99/75/78d401106731999a1dd20cc5a6961e37e1eb9397a3b589f73f3a5ce146a3/ruff-0.16.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ef140c6eb935fa9a84c9c607dfb2cb1b85843c192e79265b0c54f35f557ea8e5", size = 10286290, upload-time = "2026-09-10T18:03:55.207Z" }, + { url = "https://files.pythonhosted.org/packages/68/49/56f9c3a8b755df93a0ad318b2147bf4ef5dae9a7e5ec61c460109c67957f/ruff-0.16.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:53e39506a730fadeee0d998ed5946f30671f0db240c6c7c73bdabbe33604bb6f", size = 10745048, upload-time = "2026-09-10T18:03:57.299Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ea/7f9b938a63ece4bec677ad7f9f7fa02df3383db1949ed93a382441c09a87/ruff-0.16.7-py3-none-win32.whl", hash = "sha256:2ea3470fcebcbc5df2fb0c6f3b90333fa9084c534e0111c038fa4a6ab9f1c4b7", size = 10059082, upload-time = "2026-09-10T18:03:59.632Z" }, + { url = "https://files.pythonhosted.org/packages/39/11/480a6973a927aa653e1cead6a6416008640e03a99d05b34c0434b8c6c366/ruff-0.16.7-py3-none-win_amd64.whl", hash = "sha256:7ac26aca826e9e21d0f1cb25b54ac660760a9fdd094d3e4df9848232be98cfc6", size = 10593368, upload-time = "2026-09-10T18:04:01.999Z" }, + { url = "https://files.pythonhosted.org/packages/8b/4b/51327018d056f0dad2c2238f26d1fb0f53707a9d91b75dea6d1b3039f136/ruff-0.16.7-py3-none-win_arm64.whl", hash = "sha256:aab7f39e2c9df6c596216070f98eef1207b94f8516cca20c808826974971855b", size = 10412401, upload-time = "2026-09-10T18:04:04.098Z" }, +] + [[package]] name = "s3transfer" version = "0.19.2" @@ -1212,6 +1240,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, ] +[[package]] +name = "ty" +version = "0.0.81" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/61/b7/c9d736f48585f5a711ea47bb97a353d3771834f89481d747ea9687b74fa9/ty-0.0.81.tar.gz", hash = "sha256:ef721aa649bf41d665ba86e1ea726fd3feab6800e2c4887a062a704baf304ca8", size = 7225871, upload-time = "2026-09-15T02:05:29.536Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/70/649a5ec8fd6cc9dfa731c905523b19e677ad36dd9dcc4fcadfed8235507f/ty-0.0.81-py3-none-linux_armv6l.whl", hash = "sha256:8e9e3dd6edb1462633ddba2bf337d1c05023a5a13c2f315e445565c7ad43d247", size = 13679646, upload-time = "2026-09-15T02:04:51.436Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d0/3769b760918c3dde1bbaeee87422cd442fc550baadb5c8621e479b363282/ty-0.0.81-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:649c350873e4b3e937d856512ee57b8a345d80079cbead73a5308c2cdafe594c", size = 13211367, upload-time = "2026-09-15T02:04:54.18Z" }, + { url = "https://files.pythonhosted.org/packages/f8/5f/b8fe3ab7eee87bbf1f5ff1b65c55526a3f31a9604630bc9e7d84199bbac5/ty-0.0.81-py3-none-macosx_11_0_arm64.whl", hash = "sha256:480c78706ba78239f901d68cf1ba53e98b84aa51e19b9241daa0fb62fdecd2e2", size = 13084312, upload-time = "2026-09-15T02:04:56.133Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d8/ce22278014f14ae8205d2f9622696d39c623a0c9e80056c258bb89bb8322/ty-0.0.81-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cdbfa4b634b1d21542eedc11e424dedcc4871c2128d0d46b55b0089d3220492", size = 13127965, upload-time = "2026-09-15T02:04:58.306Z" }, + { url = "https://files.pythonhosted.org/packages/82/d0/4e75c61f6a241a0804f25117af4f91a5aaa4a48408b57f8d4c34d8a3d91e/ty-0.0.81-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f7a34743a21669d4f3d5fda98c36189cb4d9dceee1415a8a42d7426d55995db", size = 13432523, upload-time = "2026-09-15T02:05:00.471Z" }, + { url = "https://files.pythonhosted.org/packages/0b/02/e0b6b783418515c8ba40c13d5e333da9e0576a7a69582fc2b5831bb7d913/ty-0.0.81-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:742eab849947bc10b4c09810d37bd743afe9502e114b7bcfd6389f0ae3f425aa", size = 14211082, upload-time = "2026-09-15T02:05:02.455Z" }, + { url = "https://files.pythonhosted.org/packages/6b/af/85cb68d13ff617f2b213212d674e1266b933f2d051b63a1e5116e8ca0bfc/ty-0.0.81-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b4cef395eee7007449aa3fc3fc8dc6bc58fe7a8956d56db078569061741bf52", size = 14692204, upload-time = "2026-09-15T02:05:04.705Z" }, + { url = "https://files.pythonhosted.org/packages/24/c6/791891f3fa8fec91e9ec3e8c9d6774ab903297defe847a3e5d7e047360ad/ty-0.0.81-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80cf8c34973a1da2ec2a043efcba8f4c0a984d45210957a8ddd2c16f2b8f8e85", size = 14371010, upload-time = "2026-09-15T02:05:06.63Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b2/c9fba5b4ed7f63f26e83432fa2062ca04606b61dce7bbacc1238232af649/ty-0.0.81-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f37a8f66c444eea29f17adfe0664f42062520773f18031fd4913f28eb56d2966", size = 13758537, upload-time = "2026-09-15T02:05:08.722Z" }, + { url = "https://files.pythonhosted.org/packages/77/e6/09c41e96bbcbe53dd18c9a1a6dbd2e456b0d03b94440a4bd9bab55a4e19a/ty-0.0.81-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e8134cc03e84a27f409877b9b62053fd4aaac9c3ce0ce0fdace8b5ed58d78e04", size = 14280789, upload-time = "2026-09-15T02:05:10.719Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d1/87eb8e01fb17602cde5911cbadb9b11141a04f728dbda0a2a00243f337ca/ty-0.0.81-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fb6f269c5f14a07047e05cbf3d06dd9a64a048050f736afcf744a180a272f034", size = 13169638, upload-time = "2026-09-15T02:05:12.806Z" }, + { url = "https://files.pythonhosted.org/packages/94/3c/137ceb792858f408c48f20a066d12ee76108e5f28a13242720879c024172/ty-0.0.81-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:38355a5e6294ebd3cee616ed581d051963d61b293a1b3351c248747f73a45b74", size = 13449856, upload-time = "2026-09-15T02:05:15.505Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4a9b31fadfc80a2141f3862316eb31944843e01bc1f6533794291cce767e/ty-0.0.81-py3-none-musllinux_1_2_i686.whl", hash = "sha256:59a35e128a9831423aee19db804aa8a1358ee3ce615b3fc0dec20d40bfd0d733", size = 13675303, upload-time = "2026-09-15T02:05:17.537Z" }, + { url = "https://files.pythonhosted.org/packages/e3/16/dbcd2c10ab80b015a227110a4ec75314468b6720d800261098521df4eee9/ty-0.0.81-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f0f4219fbc068ea3414fa804c6bd57ef4229a11884ab9ca71cd8308072520aad", size = 14050298, upload-time = "2026-09-15T02:05:20.424Z" }, + { url = "https://files.pythonhosted.org/packages/95/ba/a70ced0c0c078ff09a3a80224d045c4267d07811dbaf125c749af5f72606/ty-0.0.81-py3-none-win32.whl", hash = "sha256:82ff952e64ba4c4da1c0c89723e326c768ae4f9ff20624dee04a51c3f4e4b96c", size = 12866650, upload-time = "2026-09-15T02:05:22.824Z" }, + { url = "https://files.pythonhosted.org/packages/3f/51/4b79453df93dfb9edecb1bd6cb04e772277d8c7260693165358a033b6ed1/ty-0.0.81-py3-none-win_amd64.whl", hash = "sha256:ef82788744da0b7f2a598e4e9776f9c5998df4eef7e2750ae3a5537e7c734b69", size = 13572976, upload-time = "2026-09-15T02:05:24.907Z" }, + { url = "https://files.pythonhosted.org/packages/0a/56/09594d55a0c49543eeac149c0dbc80b9b04409cc26ca48f1c1a9595c0916/ty-0.0.81-py3-none-win_arm64.whl", hash = "sha256:bdb1563990c5d3abfe5a09e7512733f302773ede6a5d3e4e5c6ad46393d8df4d", size = 13364408, upload-time = "2026-09-15T02:05:27.247Z" }, +] + [[package]] name = "typing-extensions" version = "4.16.0" From 95879aab61dc90951c4cddb7c5f3226d670528be Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 01:40:21 +0000 Subject: [PATCH 02/24] docs: point install and setup notes at the packages layout Add the repository layout and the root commands to the README. --- README.md | 35 ++++++++++++++++++- .../cloud_provider_logic/EC2/README.md | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d097c241..a63d7c8f 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Same deployment. Same managament. Same observability. Use any of the following package managers to install the canyonos CLI (curl, brew, uv, pip): ```bash -curl -fsSL https://raw.githubusercontent.com/CanyonCodeCoreAI/canyoncodecore/main/cli/install.sh | sh +curl -fsSL https://raw.githubusercontent.com/CanyonCodeCoreAI/canyoncodecore/main/packages/cli/install.sh | sh # OR brew tap CanyonCodeCoreAI/canyonos https://github.com/CanyonCodeCoreAI/canyoncodecore brew install canyonos @@ -72,6 +72,39 @@ canyonos doctor --- +## Development + +Work on CanyonOS from a checkout of this repository. It is a Turborepo monorepo with one uv workspace. + +``` +packages/core/ # canyonos-core, the runtime that ships in the container +packages/cli/ # canyonos, the user-facing CLI +tests/ # the test suite for both packages +examples/ # example projects you can build and deploy +``` + +Turborepo runs every task. uv holds one shared environment at the root, so one sync makes both packages editable. + +```bash +# Setup +bun install # Turborepo and the root scripts +uv sync # one shared Python environment at the root + +# Quality checks +bun run check # lint + typecheck + format check +bun run lint # ruff check +bun run typecheck # ty check +bun run format # ruff format + +# Test and build +bun run test # pytest +bun run build # wheel + sdist of both packages into dist/ +``` + +Run the CLI from the checkout with `uv run canyonos `. + +--- + ## Commands ### Essentials diff --git a/packages/core/canyonos_core/controller/cloud_provider_logic/EC2/README.md b/packages/core/canyonos_core/controller/cloud_provider_logic/EC2/README.md index ea9ee2b1..5472ec25 100644 --- a/packages/core/canyonos_core/controller/cloud_provider_logic/EC2/README.md +++ b/packages/core/canyonos_core/controller/cloud_provider_logic/EC2/README.md @@ -11,7 +11,7 @@ For global controller - Python 3.10+ - CanyonOS folder - pip requirements installed in env - - pip install -e . --break-system-packages + - pip install -e packages/core --break-system-packages - Private key labeled as ventis_ec2 inside ~/.ssh - Private key complementing local public key From cd49b32f621fa0fa2d68aca5f43a108c1f7d688c Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 01:42:14 +0000 Subject: [PATCH 03/24] ci: run checks and releases from the packages layout CI installs turbo and syncs the uv workspace, then runs the root check. The CLI release jobs build from the workspace root and refresh uv.lock with the version bump. The core image builds from packages/core. --- .github/workflows/ci.yml | 31 +++++++++++++++------------ .github/workflows/cli-release-tag.yml | 26 ++++++++++++++-------- .github/workflows/cli-release.yml | 20 ++++++++--------- .github/workflows/core-image.yml | 20 ++++++----------- 4 files changed, 50 insertions(+), 47 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 737849f4..8619b0f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,25 +18,28 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.14 + + - name: Install Turborepo + run: bun install --frozen-lockfile + - name: Set up uv uses: astral-sh/setup-uv@v5 with: + version: "0.12.15" enable-cache: true - - name: "Run Ruff: Lint" - run: uvx ruff@0.16.7 check . + # Turbo runs "uv run --frozen", so the workspace env must exist first. + - name: Sync the Python workspace + run: uv sync --locked - - name: "Run Ruff: Format Check" - run: uvx ruff@0.16.7 format --check . - - - name: "Install dependencies for Ty" - run: | - uv venv - uv pip install -e . - - - name: "Run Ty: Type Check" - run: uvx ty check + - name: Run lint, type check, and format check + run: bun run check # If you want to run this locally, install act and run "act pull_request" -# For fixing Ruff lint errors: uvx ruff@0.16.7 check --fix . -# For fixing Ruff formatting errors: uvx ruff@0.16.7 format . +# For the same checks without act: bun run check +# For reporting Ruff lint errors: bun run lint +# For fixing Ruff formatting errors: bun run format diff --git a/.github/workflows/cli-release-tag.yml b/.github/workflows/cli-release-tag.yml index 744a99c4..ce0df79d 100644 --- a/.github/workflows/cli-release-tag.yml +++ b/.github/workflows/cli-release-tag.yml @@ -4,7 +4,7 @@ on: push: branches: [main] paths: - - 'cli/**' + - 'packages/cli/**' permissions: contents: write @@ -19,22 +19,29 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Bump patch version in cli/pyproject.toml + - name: Set up uv + uses: astral-sh/setup-uv@v5 + with: + version: "0.12.15" + + - name: Bump patch version in packages/cli/pyproject.toml id: bump run: | - current=$(grep -m1 '^version = ' cli/pyproject.toml | sed -E 's/version = "(.*)"/\1/') + current=$(grep -m1 '^version = ' packages/cli/pyproject.toml | sed -E 's/version = "(.*)"/\1/') major=$(echo "$current" | cut -d. -f1) minor=$(echo "$current" | cut -d. -f2) patch=$(echo "$current" | cut -d. -f3) next="$major.$minor.$((patch + 1))" - sed -i "s/^version = \".*\"/version = \"$next\"/" cli/pyproject.toml + sed -i "s/^version = \".*\"/version = \"$next\"/" packages/cli/pyproject.toml + # uv.lock pins the member version; --locked and --frozen fail until it is refreshed. + uv lock echo "tag=cli-v$next" >> "$GITHUB_OUTPUT" - name: Commit version bump and push tag run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add cli/pyproject.toml + git add packages/cli/pyproject.toml uv.lock git commit -m "cli: bump version to ${{ steps.bump.outputs.tag }} [skip release]" git push origin HEAD:main git tag "${{ steps.bump.outputs.tag }}" @@ -59,15 +66,16 @@ jobs: - name: Set up uv uses: astral-sh/setup-uv@v5 + with: + version: "0.12.15" - name: Build sdist and wheel - working-directory: cli - run: uv build + run: uv build --package canyonos - name: Publish to PyPI - working-directory: cli env: UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - run: uv publish + # The workspace shares one dist/; this glob excludes the canyonos_core-* files. + run: uv publish 'dist/canyonos-*' # Calls cli-release.yml directly (a GITHUB_TOKEN tag push won't retrigger it); "[skip release]" is a defensive backstop against the same push looping. diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 5a5ff602..8f0bfb43 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -45,19 +45,19 @@ jobs: - name: Set up uv uses: astral-sh/setup-uv@v5 with: + version: "0.12.15" enable-cache: true - - name: Install project and Nuitka - working-directory: cli + # packages/cli has no env of its own: both commands target the workspace root .venv. + - name: Install workspace and Nuitka run: | - uv venv - uv pip install -e . + uv sync --locked uv pip install nuitka - name: Build standalone binary - working-directory: cli + working-directory: packages/cli run: | - uv run python -m nuitka \ + uv run --no-sync python -m nuitka \ --mode=onefile \ --output-filename=${{ matrix.asset }} \ --output-dir=dist \ @@ -70,14 +70,14 @@ jobs: uses: actions/upload-artifact@v4 with: name: ${{ matrix.asset }} - path: cli/dist/${{ matrix.asset }} + path: packages/cli/dist/${{ matrix.asset }} - name: Attach to GitHub release uses: softprops/action-gh-release@v2 with: tag_name: ${{ inputs.tag || github.ref_name }} - files: cli/dist/${{ matrix.asset }} + files: packages/cli/dist/${{ matrix.asset }} # Triggered by: pushing a "cli-v*" tag directly, running manually, or cli-release-tag.yml calling -# this workflow after it auto-tags a cli/pyproject.toml version bump on main. -# cli/install.sh downloads the matching asset for the latest "cli-v*" release. +# this workflow after it auto-tags a packages/cli/pyproject.toml version bump on main. +# packages/cli/install.sh downloads the matching asset for the latest "cli-v*" release. diff --git a/.github/workflows/core-image.yml b/.github/workflows/core-image.yml index 091ef6f0..70583591 100644 --- a/.github/workflows/core-image.yml +++ b/.github/workflows/core-image.yml @@ -6,20 +6,12 @@ on: # Paths are duplicated because Actions does not resolve YAML anchors. pull_request: paths: - - 'canyonos_core/**' - - 'pyproject.toml' - - 'requirements.txt' - - 'uv.lock' - - '.dockerignore' + - 'packages/core/**' - '.github/workflows/core-image.yml' push: branches: [main] paths: - - 'canyonos_core/**' - - 'pyproject.toml' - - 'requirements.txt' - - 'uv.lock' - - '.dockerignore' + - 'packages/core/**' - '.github/workflows/core-image.yml' workflow_dispatch: @@ -52,8 +44,8 @@ jobs: - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 with: - context: . - file: canyonos_core/Dockerfile + context: packages/core + file: packages/core/Dockerfile platforms: linux/amd64,linux/arm64 push: false cache-from: type=gha,scope=canyonos-core @@ -102,8 +94,8 @@ jobs: - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 with: - context: . - file: canyonos_core/Dockerfile + context: packages/core + file: packages/core/Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} From a1a280289dd01fdf6d1eb8de2e9bf32d60a2a603 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 01:42:14 +0000 Subject: [PATCH 04/24] build: keep egg-info out of the core image context --- packages/core/.dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/.dockerignore b/packages/core/.dockerignore index 3e0bd8b3..07c2d8af 100644 --- a/packages/core/.dockerignore +++ b/packages/core/.dockerignore @@ -15,3 +15,4 @@ Thumbs.db node_modules .turbo dist +*.egg-info From d344d87a06ae39e5e963bf296b050178d6363c8b Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 01:50:00 +0000 Subject: [PATCH 05/24] ci: sync only the CLI package for the nuitka build Fix the reason given for the CI sync step and drop the publish glob note. --- .github/workflows/ci.yml | 2 +- .github/workflows/cli-release-tag.yml | 1 - .github/workflows/cli-release.yml | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8619b0f2..75aca09d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: version: "0.12.15" enable-cache: true - # Turbo runs "uv run --frozen", so the workspace env must exist first. + # --locked fails the job when uv.lock is stale. - name: Sync the Python workspace run: uv sync --locked diff --git a/.github/workflows/cli-release-tag.yml b/.github/workflows/cli-release-tag.yml index ce0df79d..13a8f77c 100644 --- a/.github/workflows/cli-release-tag.yml +++ b/.github/workflows/cli-release-tag.yml @@ -75,7 +75,6 @@ jobs: - name: Publish to PyPI env: UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - # The workspace shares one dist/; this glob excludes the canyonos_core-* files. run: uv publish 'dist/canyonos-*' # Calls cli-release.yml directly (a GITHUB_TOKEN tag push won't retrigger it); "[skip release]" is a defensive backstop against the same push looping. diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 8f0bfb43..2762c95a 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -51,7 +51,7 @@ jobs: # packages/cli has no env of its own: both commands target the workspace root .venv. - name: Install workspace and Nuitka run: | - uv sync --locked + uv sync --locked --package canyonos uv pip install nuitka - name: Build standalone binary From e742f7f3a65724062a268453647d2ddcec9a013d Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 01:50:00 +0000 Subject: [PATCH 06/24] build: rely on turbo's own build outputs and ignore stray envs in the core context --- packages/core/.dockerignore | 2 ++ turbo.json | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/core/.dockerignore b/packages/core/.dockerignore index 07c2d8af..f5825f80 100644 --- a/packages/core/.dockerignore +++ b/packages/core/.dockerignore @@ -1,4 +1,6 @@ .pytest_cache +.venv +build .env .env.* !.env.example diff --git a/turbo.json b/turbo.json index bb19ce92..931336c1 100644 --- a/turbo.json +++ b/turbo.json @@ -6,10 +6,7 @@ }, "tasks": { "build": { - "cache": true, - "outputs": [ - "dist/**" - ] + "cache": true }, "canyonos-python#lint": { "command": [ From 274b72efb802aeca7ddc6c6938b6c152a2d0fa8c Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 01:50:00 +0000 Subject: [PATCH 07/24] docs: fix the moved path in the porting skill and split a README sentence --- .claude/skills/porting-to-canyonos/validate.py | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.claude/skills/porting-to-canyonos/validate.py b/.claude/skills/porting-to-canyonos/validate.py index 868ee811..7dd2562c 100755 --- a/.claude/skills/porting-to-canyonos/validate.py +++ b/.claude/skills/porting-to-canyonos/validate.py @@ -59,7 +59,7 @@ from validation.workflow import check_workflow DEFAULT_CONFIG_PATH = "config/global_controller.yaml" -# canyonos_core/cli.py SOURCE_DIR_NAME -- the duplicated application source. +# packages/core/canyonos_core/cli.py SOURCE_DIR_NAME -- the duplicated application source. SOURCE_DIR_NAME = "app" diff --git a/README.md b/README.md index a63d7c8f..78174730 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ tests/ # the test suite for both packages examples/ # example projects you can build and deploy ``` -Turborepo runs every task. uv holds one shared environment at the root, so one sync makes both packages editable. +Turborepo runs every task. uv holds one shared environment at the root. One sync makes both packages editable. ```bash # Setup From 3618d57547e09494d657f49970e8d5c92d0908c9 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 02:41:14 +0000 Subject: [PATCH 08/24] test: move tests into their packages and run them per package CLI tests live in packages/cli/tests and core tests in packages/core/tests. Each package declares pytest, so turbo runs one test task per package and a filter runs a single package. The root tests directory keeps the end-to-end harness with its own task. --- README.md | 3 ++- packages/cli/pyproject.toml | 5 +++++ .../cli/tests}/test_canyonos_deploy.py | 0 .../cli/tests}/test_canyonos_test.py | 0 .../cli/tests}/test_dashboard_stack.py | 0 .../cli/tests}/test_deploy_progress.py | 0 .../cli/tests}/test_gc_container_name.py | 0 packages/core/pyproject.toml | 5 +++++ .../core/tests}/test_canyonos_context.py | 0 {tests => packages/core/tests}/test_cli.py | 0 {tests => packages/core/tests}/test_deploy.py | 0 .../core/tests}/test_env_file_reserved_keys.py | 0 .../core/tests}/test_error_propagation.py | 0 {tests => packages/core/tests}/test_future.py | 0 .../tests}/test_global_controller_cleanup.py | 0 .../tests}/test_global_controller_identity.py | 0 .../tests}/test_global_controller_project_id.py | 0 .../test_global_controller_redis_reuse.py | 0 .../tests}/test_global_controller_reload.py | 0 .../test_global_controller_telemetry_skip.py | 0 .../core/tests}/test_gpu_metrics.py | 0 .../tests}/test_instance_manager_runtime.py | 0 .../tests}/test_llm_proxy_bedrock_streaming.py | 0 .../core/tests}/test_llm_proxy_streaming_e2e.py | 0 .../tests}/test_llm_proxy_usage_extraction.py | 0 .../tests}/test_local_controller_cleanup.py | 0 .../tests}/test_local_controller_metrics.py | 0 .../core/tests}/test_otel_exporter_fanout.py | 4 +--- .../core/tests}/test_otel_exporter_fields.py | 0 .../core/tests}/test_redis_utils.py | 0 .../core/tests}/test_runtime_ec2.py | 0 .../core/tests}/test_session_logging.py | 0 .../core/tests}/test_stub_generator.py | 0 .../core/tests}/test_telemetry_logging.py | 0 pyproject.toml | 1 - tests/README.md | 2 +- tests/run_tests.sh | 2 +- turbo.json | 13 +++++++++++++ uv.lock | 17 ++++++++++++++++- 39 files changed, 44 insertions(+), 8 deletions(-) rename {tests => packages/cli/tests}/test_canyonos_deploy.py (100%) rename {tests => packages/cli/tests}/test_canyonos_test.py (100%) rename {tests => packages/cli/tests}/test_dashboard_stack.py (100%) rename {tests => packages/cli/tests}/test_deploy_progress.py (100%) rename {tests => packages/cli/tests}/test_gc_container_name.py (100%) rename {tests => packages/core/tests}/test_canyonos_context.py (100%) rename {tests => packages/core/tests}/test_cli.py (100%) rename {tests => packages/core/tests}/test_deploy.py (100%) rename {tests => packages/core/tests}/test_env_file_reserved_keys.py (100%) rename {tests => packages/core/tests}/test_error_propagation.py (100%) rename {tests => packages/core/tests}/test_future.py (100%) rename {tests => packages/core/tests}/test_global_controller_cleanup.py (100%) rename {tests => packages/core/tests}/test_global_controller_identity.py (100%) rename {tests => packages/core/tests}/test_global_controller_project_id.py (100%) rename {tests => packages/core/tests}/test_global_controller_redis_reuse.py (100%) rename {tests => packages/core/tests}/test_global_controller_reload.py (100%) rename {tests => packages/core/tests}/test_global_controller_telemetry_skip.py (100%) rename {tests => packages/core/tests}/test_gpu_metrics.py (100%) rename {tests => packages/core/tests}/test_instance_manager_runtime.py (100%) rename {tests => packages/core/tests}/test_llm_proxy_bedrock_streaming.py (100%) rename {tests => packages/core/tests}/test_llm_proxy_streaming_e2e.py (100%) rename {tests => packages/core/tests}/test_llm_proxy_usage_extraction.py (100%) rename {tests => packages/core/tests}/test_local_controller_cleanup.py (100%) rename {tests => packages/core/tests}/test_local_controller_metrics.py (100%) rename {tests => packages/core/tests}/test_otel_exporter_fanout.py (99%) rename {tests => packages/core/tests}/test_otel_exporter_fields.py (100%) rename {tests => packages/core/tests}/test_redis_utils.py (100%) rename {tests => packages/core/tests}/test_runtime_ec2.py (100%) rename {tests => packages/core/tests}/test_session_logging.py (100%) rename {tests => packages/core/tests}/test_stub_generator.py (100%) rename {tests => packages/core/tests}/test_telemetry_logging.py (100%) diff --git a/README.md b/README.md index 78174730..3f749cb0 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ Work on CanyonOS from a checkout of this repository. It is a Turborepo monorepo ``` packages/core/ # canyonos-core, the runtime that ships in the container packages/cli/ # canyonos, the user-facing CLI -tests/ # the test suite for both packages +tests/ # the end-to-end harness (each package holds its own tests) examples/ # example projects you can build and deploy ``` @@ -98,6 +98,7 @@ bun run format # ruff format # Test and build bun run test # pytest +bun run test --filter= # one package: canyonos or canyonos-core bun run build # wheel + sdist of both packages into dist/ ``` diff --git a/packages/cli/pyproject.toml b/packages/cli/pyproject.toml index d43fe468..90d024a5 100644 --- a/packages/cli/pyproject.toml +++ b/packages/cli/pyproject.toml @@ -25,3 +25,8 @@ py-modules = ["cli"] [tool.setuptools.package-data] canyonos = ["dashboard.compose.yml"] + +[dependency-groups] +dev = [ + "pytest>=9.1.1", +] diff --git a/tests/test_canyonos_deploy.py b/packages/cli/tests/test_canyonos_deploy.py similarity index 100% rename from tests/test_canyonos_deploy.py rename to packages/cli/tests/test_canyonos_deploy.py diff --git a/tests/test_canyonos_test.py b/packages/cli/tests/test_canyonos_test.py similarity index 100% rename from tests/test_canyonos_test.py rename to packages/cli/tests/test_canyonos_test.py diff --git a/tests/test_dashboard_stack.py b/packages/cli/tests/test_dashboard_stack.py similarity index 100% rename from tests/test_dashboard_stack.py rename to packages/cli/tests/test_dashboard_stack.py diff --git a/tests/test_deploy_progress.py b/packages/cli/tests/test_deploy_progress.py similarity index 100% rename from tests/test_deploy_progress.py rename to packages/cli/tests/test_deploy_progress.py diff --git a/tests/test_gc_container_name.py b/packages/cli/tests/test_gc_container_name.py similarity index 100% rename from tests/test_gc_container_name.py rename to packages/cli/tests/test_gc_container_name.py diff --git a/packages/core/pyproject.toml b/packages/core/pyproject.toml index 57c1e6de..05235f45 100644 --- a/packages/core/pyproject.toml +++ b/packages/core/pyproject.toml @@ -36,3 +36,8 @@ canyonos_core = [ "controller/proto/*.proto", "controller/utils/aws_pricing_chart.db", ] + +[dependency-groups] +dev = [ + "pytest>=9.1.1", +] diff --git a/tests/test_canyonos_context.py b/packages/core/tests/test_canyonos_context.py similarity index 100% rename from tests/test_canyonos_context.py rename to packages/core/tests/test_canyonos_context.py diff --git a/tests/test_cli.py b/packages/core/tests/test_cli.py similarity index 100% rename from tests/test_cli.py rename to packages/core/tests/test_cli.py diff --git a/tests/test_deploy.py b/packages/core/tests/test_deploy.py similarity index 100% rename from tests/test_deploy.py rename to packages/core/tests/test_deploy.py diff --git a/tests/test_env_file_reserved_keys.py b/packages/core/tests/test_env_file_reserved_keys.py similarity index 100% rename from tests/test_env_file_reserved_keys.py rename to packages/core/tests/test_env_file_reserved_keys.py diff --git a/tests/test_error_propagation.py b/packages/core/tests/test_error_propagation.py similarity index 100% rename from tests/test_error_propagation.py rename to packages/core/tests/test_error_propagation.py diff --git a/tests/test_future.py b/packages/core/tests/test_future.py similarity index 100% rename from tests/test_future.py rename to packages/core/tests/test_future.py diff --git a/tests/test_global_controller_cleanup.py b/packages/core/tests/test_global_controller_cleanup.py similarity index 100% rename from tests/test_global_controller_cleanup.py rename to packages/core/tests/test_global_controller_cleanup.py diff --git a/tests/test_global_controller_identity.py b/packages/core/tests/test_global_controller_identity.py similarity index 100% rename from tests/test_global_controller_identity.py rename to packages/core/tests/test_global_controller_identity.py diff --git a/tests/test_global_controller_project_id.py b/packages/core/tests/test_global_controller_project_id.py similarity index 100% rename from tests/test_global_controller_project_id.py rename to packages/core/tests/test_global_controller_project_id.py diff --git a/tests/test_global_controller_redis_reuse.py b/packages/core/tests/test_global_controller_redis_reuse.py similarity index 100% rename from tests/test_global_controller_redis_reuse.py rename to packages/core/tests/test_global_controller_redis_reuse.py diff --git a/tests/test_global_controller_reload.py b/packages/core/tests/test_global_controller_reload.py similarity index 100% rename from tests/test_global_controller_reload.py rename to packages/core/tests/test_global_controller_reload.py diff --git a/tests/test_global_controller_telemetry_skip.py b/packages/core/tests/test_global_controller_telemetry_skip.py similarity index 100% rename from tests/test_global_controller_telemetry_skip.py rename to packages/core/tests/test_global_controller_telemetry_skip.py diff --git a/tests/test_gpu_metrics.py b/packages/core/tests/test_gpu_metrics.py similarity index 100% rename from tests/test_gpu_metrics.py rename to packages/core/tests/test_gpu_metrics.py diff --git a/tests/test_instance_manager_runtime.py b/packages/core/tests/test_instance_manager_runtime.py similarity index 100% rename from tests/test_instance_manager_runtime.py rename to packages/core/tests/test_instance_manager_runtime.py diff --git a/tests/test_llm_proxy_bedrock_streaming.py b/packages/core/tests/test_llm_proxy_bedrock_streaming.py similarity index 100% rename from tests/test_llm_proxy_bedrock_streaming.py rename to packages/core/tests/test_llm_proxy_bedrock_streaming.py diff --git a/tests/test_llm_proxy_streaming_e2e.py b/packages/core/tests/test_llm_proxy_streaming_e2e.py similarity index 100% rename from tests/test_llm_proxy_streaming_e2e.py rename to packages/core/tests/test_llm_proxy_streaming_e2e.py diff --git a/tests/test_llm_proxy_usage_extraction.py b/packages/core/tests/test_llm_proxy_usage_extraction.py similarity index 100% rename from tests/test_llm_proxy_usage_extraction.py rename to packages/core/tests/test_llm_proxy_usage_extraction.py diff --git a/tests/test_local_controller_cleanup.py b/packages/core/tests/test_local_controller_cleanup.py similarity index 100% rename from tests/test_local_controller_cleanup.py rename to packages/core/tests/test_local_controller_cleanup.py diff --git a/tests/test_local_controller_metrics.py b/packages/core/tests/test_local_controller_metrics.py similarity index 100% rename from tests/test_local_controller_metrics.py rename to packages/core/tests/test_local_controller_metrics.py diff --git a/tests/test_otel_exporter_fanout.py b/packages/core/tests/test_otel_exporter_fanout.py similarity index 99% rename from tests/test_otel_exporter_fanout.py rename to packages/core/tests/test_otel_exporter_fanout.py index 41f01be4..bbf13a2d 100644 --- a/tests/test_otel_exporter_fanout.py +++ b/packages/core/tests/test_otel_exporter_fanout.py @@ -13,9 +13,7 @@ ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) # ``otel_exporter.py`` is also executed as a script from its own directory and # therefore imports ``convert`` and ``db`` as top-level modules. -sys.path.insert( - 0, os.path.join(ROOT, "packages", "core", "canyonos_core", "OTLP_Exporter") -) +sys.path.insert(0, os.path.join(ROOT, "canyonos_core", "OTLP_Exporter")) from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import ( # noqa: E402 ExportTraceServiceResponse, diff --git a/tests/test_otel_exporter_fields.py b/packages/core/tests/test_otel_exporter_fields.py similarity index 100% rename from tests/test_otel_exporter_fields.py rename to packages/core/tests/test_otel_exporter_fields.py diff --git a/tests/test_redis_utils.py b/packages/core/tests/test_redis_utils.py similarity index 100% rename from tests/test_redis_utils.py rename to packages/core/tests/test_redis_utils.py diff --git a/tests/test_runtime_ec2.py b/packages/core/tests/test_runtime_ec2.py similarity index 100% rename from tests/test_runtime_ec2.py rename to packages/core/tests/test_runtime_ec2.py diff --git a/tests/test_session_logging.py b/packages/core/tests/test_session_logging.py similarity index 100% rename from tests/test_session_logging.py rename to packages/core/tests/test_session_logging.py diff --git a/tests/test_stub_generator.py b/packages/core/tests/test_stub_generator.py similarity index 100% rename from tests/test_stub_generator.py rename to packages/core/tests/test_stub_generator.py diff --git a/tests/test_telemetry_logging.py b/packages/core/tests/test_telemetry_logging.py similarity index 100% rename from tests/test_telemetry_logging.py rename to packages/core/tests/test_telemetry_logging.py diff --git a/pyproject.toml b/pyproject.toml index b38e5471..0307143d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,6 @@ canyonos = { workspace = true } [dependency-groups] dev = [ - "pytest>=9.1.1", "ruff==0.16.7", "ty==0.0.81", "canyonos-core", diff --git a/tests/README.md b/tests/README.md index 90b902af..e45b1f21 100644 --- a/tests/README.md +++ b/tests/README.md @@ -4,7 +4,7 @@ This directory contains an automated end-to-end testing suite for CanyonOS. It i ## 1. Automated Test Runner (`run_tests.sh`) This script automates the entire testing lifecycle by interacting with the `canyonos` CLI: -0. Runs a small pytest suite from this `tests/` directory. +0. Runs the package test suites and the tests in this `tests/` directory. 1. Scaffolds a new temporary project using `canyonos new-project`. 2. Compiles the project using `canyonos build`. 3. Launches the project using `canyonos deploy` in the background. diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 4eec785c..7a105861 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -8,7 +8,7 @@ echo "===========================================" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" echo ">> 0. Running small pytest suite..." -python3 -m pytest "$SCRIPT_DIR" +python3 -m pytest "$SCRIPT_DIR" "$SCRIPT_DIR/../packages" TEST_DIR="/tmp/canyonos_test_env_$$" PROJECT_NAME="canyonos_test" diff --git a/turbo.json b/turbo.json index 931336c1..b5ae471f 100644 --- a/turbo.json +++ b/turbo.json @@ -8,6 +8,19 @@ "build": { "cache": true }, + "canyonos-python#test": { + "command": [ + "uv", + "run", + "--active", + "--frozen", + "pytest", + "tests" + ], + "inputs": [ + "tests/**" + ] + }, "canyonos-python#lint": { "command": [ "uv", diff --git a/uv.lock b/uv.lock index 1592989c..4327050e 100644 --- a/uv.lock +++ b/uv.lock @@ -17,7 +17,6 @@ members = [ dev = [ { name = "canyonos", editable = "packages/cli" }, { name = "canyonos-core", editable = "packages/core" }, - { name = "pytest", specifier = ">=9.1.1" }, { name = "ruff", specifier = "==0.16.7" }, { name = "ty", specifier = "==0.0.81" }, ] @@ -79,6 +78,11 @@ dependencies = [ { name = "ruamel-yaml" }, ] +[package.dev-dependencies] +dev = [ + { name = "pytest" }, +] + [package.metadata] requires-dist = [ { name = "pyfiglet" }, @@ -87,6 +91,9 @@ requires-dist = [ { name = "ruamel-yaml" }, ] +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=9.1.1" }] + [[package]] name = "canyonos-core" version = "0.1.0" @@ -108,6 +115,11 @@ dependencies = [ { name = "sqlalchemy" }, ] +[package.dev-dependencies] +dev = [ + { name = "pytest" }, +] + [package.metadata] requires-dist = [ { name = "boto3", specifier = "==1.43.91" }, @@ -126,6 +138,9 @@ requires-dist = [ { name = "sqlalchemy" }, ] +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=9.1.1" }] + [[package]] name = "certifi" version = "2026.7.22" From f455f4d1796cf2ecba9fb06adb37acd9e6ee3230 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 02:42:40 +0000 Subject: [PATCH 09/24] test: compile the controller protos for the core test session The core runtime bare-imports the generated gRPC stubs, which only the container images provide. A conftest now compiles the protos into a gitignored build dir at session start, so the core suite collects and runs from a checkout. The fake stub modules in the exporter test are no longer needed. --- packages/core/tests/conftest.py | 30 +++++++++++++++++++ .../core/tests/test_otel_exporter_fanout.py | 14 --------- 2 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 packages/core/tests/conftest.py diff --git a/packages/core/tests/conftest.py b/packages/core/tests/conftest.py new file mode 100644 index 00000000..700b5c38 --- /dev/null +++ b/packages/core/tests/conftest.py @@ -0,0 +1,30 @@ +"""Compile the controller protos before collection. + +canyonos_core.controller bare-imports local_controler_pb2. The container +images put protoc's output on sys.path; a checkout has to generate it. +""" + +import subprocess +import sys +from pathlib import Path + +PACKAGE_ROOT = Path(__file__).resolve().parents[1] +PROTO_DIR = PACKAGE_ROOT / "canyonos_core" / "controller" / "proto" +STUB_DIR = PACKAGE_ROOT / "build" / "pb" + + +def pytest_configure(config): + STUB_DIR.mkdir(parents=True, exist_ok=True) + subprocess.run( + [ + sys.executable, + "-m", + "grpc_tools.protoc", + f"-I{PROTO_DIR}", + f"--python_out={STUB_DIR}", + f"--grpc_python_out={STUB_DIR}", + *sorted(str(p) for p in PROTO_DIR.glob("*.proto")), + ], + check=True, + ) + sys.path.insert(0, str(STUB_DIR)) diff --git a/packages/core/tests/test_otel_exporter_fanout.py b/packages/core/tests/test_otel_exporter_fanout.py index bbf13a2d..2fa09f0b 100644 --- a/packages/core/tests/test_otel_exporter_fanout.py +++ b/packages/core/tests/test_otel_exporter_fanout.py @@ -5,7 +5,6 @@ import sqlite3 import sys import tempfile -import types import unittest from unittest.mock import MagicMock, patch @@ -25,19 +24,6 @@ import otel_exporter # noqa: E402 -# The generated local-controller protobuf modules are build artifacts and are -# not present in a source checkout. The static config helper does not use them, -# so provide the tiny import-time surface needed to test it in isolation. -if "local_controler_pb2" not in sys.modules: - local_pb2 = types.ModuleType("local_controler_pb2") - local_pb2.JsonResponse = object - sys.modules["local_controler_pb2"] = local_pb2 -if "local_controler_pb2_grpc" not in sys.modules: - local_pb2_grpc = types.ModuleType("local_controler_pb2_grpc") - local_pb2_grpc.LocalControllerStub = object - sys.modules["local_controler_pb2_grpc"] = local_pb2_grpc - - class OTelExporterFanoutTests(unittest.TestCase): def setUp(self): self.db_file = tempfile.NamedTemporaryFile(suffix=".db", delete=False) From 5334f4be5512fdc953cd898fe27bb4c9f772570f Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 02:45:35 +0000 Subject: [PATCH 10/24] ci: pin the bun and uv setup actions to commit hashes --- .github/workflows/ci.yml | 4 ++-- .github/workflows/cli-release-tag.yml | 4 ++-- .github/workflows/cli-release.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75aca09d..90b3ad23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: 1.3.14 @@ -27,7 +27,7 @@ jobs: run: bun install --frozen-lockfile - name: Set up uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: version: "0.12.15" enable-cache: true diff --git a/.github/workflows/cli-release-tag.yml b/.github/workflows/cli-release-tag.yml index 13a8f77c..add6d099 100644 --- a/.github/workflows/cli-release-tag.yml +++ b/.github/workflows/cli-release-tag.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@v4 - name: Set up uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: version: "0.12.15" @@ -65,7 +65,7 @@ jobs: ref: ${{ needs.bump.outputs.tag }} - name: Set up uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: version: "0.12.15" diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 2762c95a..466560d4 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -43,7 +43,7 @@ jobs: ref: ${{ inputs.tag || github.ref }} - name: Set up uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: version: "0.12.15" enable-cache: true From 79c90eec0a2710f93f8dd19a136bd15b4299439e Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 02:51:36 +0000 Subject: [PATCH 11/24] ci: run the test suite with a cached turbo on every pull request CI now runs bun run test after the checks, keeps the turbo cache between runs with actions/cache, and triggers on every pull request and on pushes to main. --- .github/workflows/ci.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90b3ad23..f7192b24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,11 +1,18 @@ name: CI on: + # No branch filter, so a PR against another PR's branch runs too. pull_request: + push: branches: [ main ] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + + permissions: contents: read @@ -13,11 +20,21 @@ permissions: jobs: test: runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Checkout code uses: actions/checkout@v4 + # Tasks whose inputs did not change replay from this cache. + - name: Cache turbo task results + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo- + - name: Set up Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: @@ -39,7 +56,10 @@ jobs: - name: Run lint, type check, and format check run: bun run check + - name: Run tests + run: bun run test + # If you want to run this locally, install act and run "act pull_request" -# For the same checks without act: bun run check +# For the same checks without act: bun run check && bun run test # For reporting Ruff lint errors: bun run lint # For fixing Ruff formatting errors: bun run format From 315cc408f54b7cb224b8e7e35ae8696cb15c7e24 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 02:58:41 +0000 Subject: [PATCH 12/24] ci: build the CLI release through turbo and narrow the release trigger The release jobs build the wheel with bun run build and the binaries with a new build:binary turbo task. Nuitka is pinned through a release dependency group of the CLI package. Tests, docs, and the install script under packages/cli no longer start a release. --- .github/workflows/cli-release-tag.yml | 22 +++++++++++++++++--- .github/workflows/cli-release.yml | 29 +++++++++++++-------------- package.json | 3 ++- packages/cli/pyproject.toml | 3 +++ turbo.json | 17 ++++++++++++++++ uv.lock | 10 +++++++++ 6 files changed, 65 insertions(+), 19 deletions(-) diff --git a/.github/workflows/cli-release-tag.yml b/.github/workflows/cli-release-tag.yml index add6d099..e9320d7f 100644 --- a/.github/workflows/cli-release-tag.yml +++ b/.github/workflows/cli-release-tag.yml @@ -3,8 +3,12 @@ name: Tag CLI Release on: push: branches: [main] + # Only files that ship in the wheel or the binary cut a release. Negations must follow the positive pattern. paths: - 'packages/cli/**' + - '!packages/cli/tests/**' + - '!packages/cli/**.md' + - '!packages/cli/install.sh' permissions: contents: write @@ -23,6 +27,7 @@ jobs: uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: version: "0.12.15" + enable-cache: true - name: Bump patch version in packages/cli/pyproject.toml id: bump @@ -64,17 +69,28 @@ jobs: with: ref: ${{ needs.bump.outputs.tag }} + - name: Set up Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: 1.3.14 + + - name: Install Turborepo + run: bun install --frozen-lockfile + - name: Set up uv uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: version: "0.12.15" + enable-cache: true + # A release runner has no turbo cache, so this always runs uv build --package canyonos. - name: Build sdist and wheel - run: uv build --package canyonos + run: bun run build --filter=canyonos - name: Publish to PyPI env: UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - run: uv publish 'dist/canyonos-*' + run: uv publish --check-url https://pypi.org/simple/canyonos/ 'dist/canyonos-*' -# Calls cli-release.yml directly (a GITHUB_TOKEN tag push won't retrigger it); "[skip release]" is a defensive backstop against the same push looping. +# Calls cli-release.yml directly (a GITHUB_TOKEN tag push won't retrigger it). "[skip release]" keeps the bump commit, +# which edits packages/cli/pyproject.toml, from starting another bump. diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 466560d4..132d2c36 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -42,29 +42,28 @@ jobs: with: ref: ${{ inputs.tag || github.ref }} + - name: Set up Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: 1.3.14 + + - name: Install Turborepo + run: bun install --frozen-lockfile + - name: Set up uv uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: version: "0.12.15" enable-cache: true - # packages/cli has no env of its own: both commands target the workspace root .venv. - - name: Install workspace and Nuitka - run: | - uv sync --locked --package canyonos - uv pip install nuitka + # nuitka is in the non-default "release" group, so a plain uv sync skips it. + - name: Install the CLI and Nuitka + run: uv sync --locked --package canyonos --group release + # The task runs from packages/cli; arguments after "--" append to its command. + # Uncached on purpose: the task hash does not include the runner OS. - name: Build standalone binary - working-directory: packages/cli - run: | - uv run --no-sync python -m nuitka \ - --mode=onefile \ - --output-filename=${{ matrix.asset }} \ - --output-dir=dist \ - --include-data-file=canyonos/dashboard.compose.yml=canyonos/dashboard.compose.yml \ - --include-distribution-metadata=canyonos \ - --assume-yes-for-downloads \ - cli.py + run: bun run build:binary --filter=canyonos -- --output-filename=${{ matrix.asset }} - name: Upload build artifact uses: actions/upload-artifact@v4 diff --git a/package.json b/package.json index ef4116a0..4b8f565c 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "check": "turbo run lint typecheck format:check", "format": "turbo run format", "test": "turbo run test", - "build": "turbo run build" + "build": "turbo run build", + "build:binary": "turbo run build:binary" }, "devDependencies": { "turbo": "2.10.13" diff --git a/packages/cli/pyproject.toml b/packages/cli/pyproject.toml index 90d024a5..69baa90c 100644 --- a/packages/cli/pyproject.toml +++ b/packages/cli/pyproject.toml @@ -30,3 +30,6 @@ canyonos = ["dashboard.compose.yml"] dev = [ "pytest>=9.1.1", ] +release = [ + "nuitka", +] diff --git a/turbo.json b/turbo.json index b5ae471f..9446d72c 100644 --- a/turbo.json +++ b/turbo.json @@ -8,6 +8,23 @@ "build": { "cache": true }, + "canyonos#build:binary": { + "cache": false, + "command": [ + "uv", + "run", + "--no-sync", + "python", + "-m", + "nuitka", + "--mode=onefile", + "--output-dir=dist", + "--include-data-file=canyonos/dashboard.compose.yml=canyonos/dashboard.compose.yml", + "--include-distribution-metadata=canyonos", + "--assume-yes-for-downloads", + "cli.py" + ] + }, "canyonos-python#test": { "command": [ "uv", diff --git a/uv.lock b/uv.lock index 4327050e..346a2589 100644 --- a/uv.lock +++ b/uv.lock @@ -82,6 +82,9 @@ dependencies = [ dev = [ { name = "pytest" }, ] +release = [ + { name = "nuitka" }, +] [package.metadata] requires-dist = [ @@ -93,6 +96,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [{ name = "pytest", specifier = ">=9.1.1" }] +release = [{ name = "nuitka" }] [[package]] name = "canyonos-core" @@ -697,6 +701,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] +[[package]] +name = "nuitka" +version = "4.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/ce/38409fc853cc26d86ab71ccd53f7dfddbc7a84d4821b9b54db428b35779b/nuitka-4.2.1.tar.gz", hash = "sha256:815c6e571a7a6424af384fe9d95d4ba38f1634d39a5515e8094d7fbfa090cbcb", size = 4632551, upload-time = "2026-09-05T08:08:19.117Z" } + [[package]] name = "opentelemetry-api" version = "1.44.0" From 5c9567d6dec0a60e0010bc38703653f37e84fd73 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 03:11:51 +0000 Subject: [PATCH 13/24] test: hash the lock and skip bytecode for the root test task Keep the core tests out of the image build context. --- packages/core/.dockerignore | 1 + turbo.json | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/core/.dockerignore b/packages/core/.dockerignore index f5825f80..cc447a84 100644 --- a/packages/core/.dockerignore +++ b/packages/core/.dockerignore @@ -18,3 +18,4 @@ node_modules .turbo dist *.egg-info +tests diff --git a/turbo.json b/turbo.json index b5ae471f..e3514a2c 100644 --- a/turbo.json +++ b/turbo.json @@ -18,7 +18,10 @@ "tests" ], "inputs": [ - "tests/**" + "tests/**", + "!tests/**/__pycache__/**", + "pyproject.toml", + "uv.lock" ] }, "canyonos-python#lint": { From cde787147fb8b77cb7fee69167a50a7995790bab Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 03:11:58 +0000 Subject: [PATCH 14/24] test: declare grpcio-tools for the core tests and rebuild the stubs each session --- packages/core/pyproject.toml | 1 + packages/core/tests/conftest.py | 4 +++- uv.lock | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/core/pyproject.toml b/packages/core/pyproject.toml index 05235f45..99309e92 100644 --- a/packages/core/pyproject.toml +++ b/packages/core/pyproject.toml @@ -39,5 +39,6 @@ canyonos_core = [ [dependency-groups] dev = [ + "grpcio-tools", "pytest>=9.1.1", ] diff --git a/packages/core/tests/conftest.py b/packages/core/tests/conftest.py index 700b5c38..8febff18 100644 --- a/packages/core/tests/conftest.py +++ b/packages/core/tests/conftest.py @@ -4,6 +4,7 @@ images put protoc's output on sys.path; a checkout has to generate it. """ +import shutil import subprocess import sys from pathlib import Path @@ -14,7 +15,8 @@ def pytest_configure(config): - STUB_DIR.mkdir(parents=True, exist_ok=True) + shutil.rmtree(STUB_DIR, ignore_errors=True) + STUB_DIR.mkdir(parents=True) subprocess.run( [ sys.executable, diff --git a/uv.lock b/uv.lock index 4327050e..f308a057 100644 --- a/uv.lock +++ b/uv.lock @@ -117,6 +117,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "grpcio-tools" }, { name = "pytest" }, ] @@ -139,7 +140,10 @@ requires-dist = [ ] [package.metadata.requires-dev] -dev = [{ name = "pytest", specifier = ">=9.1.1" }] +dev = [ + { name = "grpcio-tools" }, + { name = "pytest", specifier = ">=9.1.1" }, +] [[package]] name = "certifi" From f815ef850bb904ab2c6d99b962eb34eebcf429ea Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 03:12:17 +0000 Subject: [PATCH 15/24] ci: drop a comment that restates the cache step --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7192b24..cf505a98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,6 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - # Tasks whose inputs did not change replay from this cache. - name: Cache turbo task results uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: From 40197146bf9de629f1da5564c0dba6cc3db2d259 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 03:12:19 +0000 Subject: [PATCH 16/24] ci: fix the publish check url, pin nuitka, and keep core tests from publishing the image uv appends the project name to the check url, so it must be the index root. Core test and doc changes no longer rebuild the runtime image. --- .github/workflows/cli-release-tag.yml | 3 +-- .github/workflows/cli-release.yml | 1 - .github/workflows/core-image.yml | 4 ++++ packages/cli/pyproject.toml | 2 +- uv.lock | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cli-release-tag.yml b/.github/workflows/cli-release-tag.yml index e9320d7f..fdbc2814 100644 --- a/.github/workflows/cli-release-tag.yml +++ b/.github/workflows/cli-release-tag.yml @@ -83,14 +83,13 @@ jobs: version: "0.12.15" enable-cache: true - # A release runner has no turbo cache, so this always runs uv build --package canyonos. - name: Build sdist and wheel run: bun run build --filter=canyonos - name: Publish to PyPI env: UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - run: uv publish --check-url https://pypi.org/simple/canyonos/ 'dist/canyonos-*' + run: uv publish --check-url https://pypi.org/simple/ 'dist/canyonos-*' # Calls cli-release.yml directly (a GITHUB_TOKEN tag push won't retrigger it). "[skip release]" keeps the bump commit, # which edits packages/cli/pyproject.toml, from starting another bump. diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 132d2c36..da41459f 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -61,7 +61,6 @@ jobs: run: uv sync --locked --package canyonos --group release # The task runs from packages/cli; arguments after "--" append to its command. - # Uncached on purpose: the task hash does not include the runner OS. - name: Build standalone binary run: bun run build:binary --filter=canyonos -- --output-filename=${{ matrix.asset }} diff --git a/.github/workflows/core-image.yml b/.github/workflows/core-image.yml index 70583591..f9cf37ac 100644 --- a/.github/workflows/core-image.yml +++ b/.github/workflows/core-image.yml @@ -7,11 +7,15 @@ on: pull_request: paths: - 'packages/core/**' + - '!packages/core/tests/**' + - '!packages/core/**.md' - '.github/workflows/core-image.yml' push: branches: [main] paths: - 'packages/core/**' + - '!packages/core/tests/**' + - '!packages/core/**.md' - '.github/workflows/core-image.yml' workflow_dispatch: diff --git a/packages/cli/pyproject.toml b/packages/cli/pyproject.toml index 69baa90c..dd99ff1b 100644 --- a/packages/cli/pyproject.toml +++ b/packages/cli/pyproject.toml @@ -31,5 +31,5 @@ dev = [ "pytest>=9.1.1", ] release = [ - "nuitka", + "nuitka==4.2.1", ] diff --git a/uv.lock b/uv.lock index 87e21c4d..2accfbfb 100644 --- a/uv.lock +++ b/uv.lock @@ -96,7 +96,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [{ name = "pytest", specifier = ">=9.1.1" }] -release = [{ name = "nuitka" }] +release = [{ name = "nuitka", specifier = "==4.2.1" }] [[package]] name = "canyonos-core" From 1d1b45b5abb82c7da5d4cbaa7d7f93f0bf2bf10b Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 12:15:15 +0000 Subject: [PATCH 17/24] build: drop the apps workspace glob until an app exists --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index ef4116a0..9fe845b7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "canyoncodecore", "private": true, "workspaces": [ - "apps/*", "packages/*" ], "engines": { From bd48b454e10f5b6df24d3366ae97c2e39db916a7 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 17:34:23 +0000 Subject: [PATCH 18/24] style: format the clean command test --- tests/test_clean.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_clean.py b/tests/test_clean.py index 5c4284d2..dad8d08c 100644 --- a/tests/test_clean.py +++ b/tests/test_clean.py @@ -69,7 +69,9 @@ def fake_run(argv, **_): calls.append(argv) if argv[:2] == ["docker", "images"]: return completed(argv, stdout="image-in-use\n") - return completed(argv, returncode=1, stderr="image is being used by running container") + return completed( + argv, returncode=1, stderr="image is being used by running container" + ) monkeypatch.chdir(tmp_path) monkeypatch.setattr(clean.subprocess, "run", fake_run) From 24158cb4eb2c1e43493636160678b47d9c7b054f Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 17:34:26 +0000 Subject: [PATCH 19/24] test: move the clean command test into the CLI package --- {tests => packages/cli/tests}/test_clean.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {tests => packages/cli/tests}/test_clean.py (100%) diff --git a/tests/test_clean.py b/packages/cli/tests/test_clean.py similarity index 100% rename from tests/test_clean.py rename to packages/cli/tests/test_clean.py From aab4c59a6b5c9a64cf2d1db62ef0e49d43530410 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 17:35:35 +0000 Subject: [PATCH 20/24] docs: drop the development section from the README --- README.md | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/README.md b/README.md index 78174730..53505430 100644 --- a/README.md +++ b/README.md @@ -72,39 +72,6 @@ canyonos doctor --- -## Development - -Work on CanyonOS from a checkout of this repository. It is a Turborepo monorepo with one uv workspace. - -``` -packages/core/ # canyonos-core, the runtime that ships in the container -packages/cli/ # canyonos, the user-facing CLI -tests/ # the test suite for both packages -examples/ # example projects you can build and deploy -``` - -Turborepo runs every task. uv holds one shared environment at the root. One sync makes both packages editable. - -```bash -# Setup -bun install # Turborepo and the root scripts -uv sync # one shared Python environment at the root - -# Quality checks -bun run check # lint + typecheck + format check -bun run lint # ruff check -bun run typecheck # ty check -bun run format # ruff format - -# Test and build -bun run test # pytest -bun run build # wheel + sdist of both packages into dist/ -``` - -Run the CLI from the checkout with `uv run canyonos `. - ---- - ## Commands ### Essentials From 64514459c19faaa249dd7a547b2993244038a1e7 Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Thu, 17 Sep 2026 17:37:14 +0000 Subject: [PATCH 21/24] build: name the root package canyonos --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9fe845b7..7d4ef3e6 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "canyoncodecore", + "name": "canyonos", "private": true, "workspaces": [ "packages/*" From d51ece1c7941c1c6a68651aa39e1e4e26c5f286f Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Fri, 18 Sep 2026 21:24:22 +0000 Subject: [PATCH 22/24] test(core): move the llm proxy and pricing tests into the package --- {tests => packages/core/tests}/test_llm_proxy_header_injection.py | 0 {tests => packages/core/tests}/test_llm_proxy_http_streaming.py | 0 {tests => packages/core/tests}/test_pricing_model_resolution.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {tests => packages/core/tests}/test_llm_proxy_header_injection.py (100%) rename {tests => packages/core/tests}/test_llm_proxy_http_streaming.py (100%) rename {tests => packages/core/tests}/test_pricing_model_resolution.py (100%) diff --git a/tests/test_llm_proxy_header_injection.py b/packages/core/tests/test_llm_proxy_header_injection.py similarity index 100% rename from tests/test_llm_proxy_header_injection.py rename to packages/core/tests/test_llm_proxy_header_injection.py diff --git a/tests/test_llm_proxy_http_streaming.py b/packages/core/tests/test_llm_proxy_http_streaming.py similarity index 100% rename from tests/test_llm_proxy_http_streaming.py rename to packages/core/tests/test_llm_proxy_http_streaming.py diff --git a/tests/test_pricing_model_resolution.py b/packages/core/tests/test_pricing_model_resolution.py similarity index 100% rename from tests/test_pricing_model_resolution.py rename to packages/core/tests/test_pricing_model_resolution.py From 3cf35fa969132eb5411a1df405591bb5bab01b2e Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Mon, 21 Sep 2026 12:18:00 +0000 Subject: [PATCH 23/24] build: hash the porting skill sources into the root test task --- turbo.json | 1 + 1 file changed, 1 insertion(+) diff --git a/turbo.json b/turbo.json index e3514a2c..c2bc97ab 100644 --- a/turbo.json +++ b/turbo.json @@ -20,6 +20,7 @@ "inputs": [ "tests/**", "!tests/**/__pycache__/**", + ".claude/skills/porting-to-canyonos/**", "pyproject.toml", "uv.lock" ] From 26899a5da54e629d472f590715048c36ee576a3c Mon Sep 17 00:00:00 2001 From: Felipe Augustos Date: Mon, 21 Sep 2026 18:24:56 +0000 Subject: [PATCH 24/24] ci(cli): publish to PyPI only after the binaries are attached --- .github/workflows/cli-release-tag.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cli-release-tag.yml b/.github/workflows/cli-release-tag.yml index fdbc2814..f84a08a0 100644 --- a/.github/workflows/cli-release-tag.yml +++ b/.github/workflows/cli-release-tag.yml @@ -60,8 +60,9 @@ jobs: with: tag: ${{ needs.bump.outputs.tag }} + # PyPI last: a version can never be re-uploaded, and the binaries can. publish-pypi: - needs: bump + needs: [bump, release] runs-on: ubuntu-latest steps: - name: Checkout code