lean-runtime 2.6.1__tar.gz → 2.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/CHANGELOG.md +13 -0
- {lean_runtime-2.6.1/lean_runtime.egg-info → lean_runtime-2.6.2}/PKG-INFO +3 -1
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/README.md +2 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/cli.md +7 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/getting-started.md +2 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/local-projects.md +24 -12
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/cli.py +17 -4
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/project_sharing.py +68 -5
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/runtime.py +45 -31
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/shared_projects.py +123 -15
- {lean_runtime-2.6.1 → lean_runtime-2.6.2/lean_runtime.egg-info}/PKG-INFO +3 -1
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/pyproject.toml +1 -1
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_cli.py +7 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_projects.py +58 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/LICENSE +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/MANIFEST.in +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/environments.toml +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/core-v4.32.2.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/leancert-v4.30.0.5.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/leancert-v4.31.0.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/leancert-v4.32.2.4.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/leancert-v4.33.0.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/mathlib-v4.30.0.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/mathlib-v4.31.0.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/mathlib-v4.32.2.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/catalog/locks/mathlib-v4.33.0.lock.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/compatibility/README.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/compatibility/mathlib-4.32.2.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/compatibility/mathlib-4.32.2.toml +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/compatibility/mathlib-4.33.0.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/compatibility/mathlib-4.33.0.toml +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/architecture.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/captures.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/case-study-v1.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/development.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/environments.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/index.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/portable-copies.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/project-publishing.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/python-api.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/ready-programs.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/standalone-files.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/trust-and-limitations.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/docs/v1-precision.md +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/examples/mathlib.toml +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/__init__.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/__main__.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/_git.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/_paths.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/backends.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/bundles.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/capsules.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/comparison.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/console.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/decisions.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/diagnostics.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/__init__.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/analyzer.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/api.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/candidate.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/catalog.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/catalog_build.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/catalog_cli.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/catalog_manifest.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/data/catalog.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/defaults.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/engine.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/errors.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/module_inventory.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/planner.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/policy.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/probe.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/py.typed +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/result.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/schema_resources.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/schemas/catalog-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/schemas/plan-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/discovery/schemas/result-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/environments.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/errors.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/events.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/facade.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/frontmatter.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/health.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/lake.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/lockfiles.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/locking.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/matrix.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/models.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/oci.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/packs.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/policies.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/profiling.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/programs.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/projects.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/publisher_verification.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/py.typed +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/references.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/resolver.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/run_cli.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/schema_resources.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/serialization.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/specs.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/store.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/timings.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/toolchain_oci.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/toolchain_slim.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/toolchains.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/verification.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime/wire.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime.egg-info/SOURCES.txt +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime.egg-info/dependency_links.txt +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime.egg-info/entry_points.txt +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime.egg-info/requires.txt +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/lean_runtime.egg-info/top_level.txt +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/mkdocs.yml +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/schemas/cleanup-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/schemas/comparison-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/schemas/execution-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/schemas/inspect-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/schemas/matrix-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/schemas/profile-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/schemas/verify-v1.schema.json +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/scripts/announcement_gate.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/scripts/registry_preflight.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/scripts/run_compatibility.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/scripts/run_v1_case_study.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/scripts/smoke_wheel.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/setup.cfg +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/conftest.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/discovery/e2e/test_real_discovery.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/discovery/test_analyzer.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/discovery/test_catalog.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/discovery/test_catalog_build.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/discovery/test_discovery_schema_resources.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/discovery/test_engine.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/discovery/test_planner.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/discovery/test_policy.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_backend.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_bundles.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_capsules.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_console.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_diagnostics.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_environment_integration.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_events_health.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_facade.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_frontmatter.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_git.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_interactive.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_lockfiles.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_models.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_multifile.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_packs.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_paths.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_prebuilt_policy.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_programs.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_project_publish.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_references.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_run_cli.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_runtime.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_schema_resources.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_schemas.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_signatures.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_specs.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_store.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_toolchain_oci.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_toolchain_slim.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_toolchains.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_v1_precision.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_verification_inventory.py +0 -0
- {lean_runtime-2.6.1 → lean_runtime-2.6.2}/tests/test_verification_probe.py +0 -0
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 2.6.2 - 2026-08-14
|
|
6
|
+
|
|
7
|
+
- Keep an existing initialization target's directory inode alive, so running
|
|
8
|
+
`lean-runtime init .` no longer strands the invoking shell in an unlinked
|
|
9
|
+
working directory. Fully prepared staged children are published with rollback
|
|
10
|
+
while Git metadata, custom agent guidance, and index state remain in place.
|
|
11
|
+
- Make attachment plans distinguish checkout bytes removed, compatible shared
|
|
12
|
+
bytes already available, new shared bytes required, and estimated machine
|
|
13
|
+
recovery. Exact managed packages now bypass redundant source resolution when
|
|
14
|
+
their toolchain, platform, revision, and effective dependency closure match.
|
|
15
|
+
- Emit package-by-package shared-workspace resolution, reuse, and import events,
|
|
16
|
+
and add `lean-runtime --version`.
|
|
17
|
+
|
|
5
18
|
## 2.6.1 - 2026-08-14
|
|
6
19
|
|
|
7
20
|
- Allow `lean-runtime init .` at an otherwise empty Git repository root while
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lean-runtime
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.2
|
|
4
4
|
Summary: Run Lean 4 proofs from Python or standalone files
|
|
5
5
|
Author: Alejandro Radisic
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -213,6 +213,8 @@ For a new project, the target may be absent, empty, or an otherwise empty Git
|
|
|
213
213
|
repository root; existing Git identity and index state are preserved. A custom
|
|
214
214
|
`AGENTS.md` is also allowed and retained. Other existing contents are rejected
|
|
215
215
|
before acquisition rather than overwritten.
|
|
216
|
+
An existing target directory remains the same live directory, so `init .` does
|
|
217
|
+
not invalidate the invoking shell's working directory.
|
|
216
218
|
When the directory spelling is not the intended Lean module capitalization,
|
|
217
219
|
set it explicitly, for example `lean-runtime init . --name IntegralFramework`.
|
|
218
220
|
|
|
@@ -177,6 +177,8 @@ For a new project, the target may be absent, empty, or an otherwise empty Git
|
|
|
177
177
|
repository root; existing Git identity and index state are preserved. A custom
|
|
178
178
|
`AGENTS.md` is also allowed and retained. Other existing contents are rejected
|
|
179
179
|
before acquisition rather than overwritten.
|
|
180
|
+
An existing target directory remains the same live directory, so `init .` does
|
|
181
|
+
not invalidate the invoking shell's working directory.
|
|
180
182
|
When the directory spelling is not the intended Lean module capitalization,
|
|
181
183
|
set it explicitly, for example `lean-runtime init . --name IntegralFramework`.
|
|
182
184
|
|
|
@@ -176,11 +176,18 @@ recursive mode inventories a project tree, reports blockers and estimated disk
|
|
|
176
176
|
recovery, and adopts each valid project transactionally. `detach` is likewise a
|
|
177
177
|
preview unless `--execute` is present. Attached projects use shared mode by
|
|
178
178
|
default in `lean-runtime build`; detach before requesting `--local`.
|
|
179
|
+
The attachment preview separates bytes removed from each checkout, compatible
|
|
180
|
+
bytes already present in the shared store, new shared bytes that must be
|
|
181
|
+
imported, and estimated machine-level recovery. These quantities differ on a
|
|
182
|
+
first attachment because copy-on-write migration can shrink the repository
|
|
183
|
+
without immediately freeing the dependency blocks retained by the shared copy.
|
|
179
184
|
|
|
180
185
|
A new `init` target may be absent, empty, or an otherwise empty Git root, with
|
|
181
186
|
an optional existing `AGENTS.md`. Git metadata and the custom guide are
|
|
182
187
|
preserved. Planning rejects any other existing contents using the same
|
|
183
188
|
validation as execution.
|
|
189
|
+
Existing target directories are populated in place after staging verifies, so
|
|
190
|
+
`lean-runtime init .` keeps the caller's current working directory valid.
|
|
184
191
|
`--name NAME` overrides the inferred Lake package/root module name for a new
|
|
185
192
|
project, which is useful when a lowercase repository name needs internal
|
|
186
193
|
capitalization such as `IntegralFramework`.
|
|
@@ -48,6 +48,8 @@ empty Git repository root. In the Git case, `init` preserves the existing HEAD,
|
|
|
48
48
|
index, remotes, and worktree metadata. It also preserves an existing
|
|
49
49
|
`AGENTS.md`; any other non-project contents are rejected by both `--plan` and
|
|
50
50
|
execution rather than overwritten.
|
|
51
|
+
If the target already exists, initialization keeps that directory inode alive;
|
|
52
|
+
the shell that runs `lean-runtime init .` can immediately continue using it.
|
|
51
53
|
The directory name normally supplies the Lake package/root module name. Override
|
|
52
54
|
it when capitalization matters, for example:
|
|
53
55
|
|
|
@@ -69,10 +69,12 @@ toolchain is rejected under `--offline` or `--max-download` rather than silently
|
|
|
69
69
|
bypassing the policy.
|
|
70
70
|
|
|
71
71
|
An otherwise empty Git root is a valid new-project target. The original `.git`
|
|
72
|
-
directory—or `.git` worktree file—
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
directory—or `.git` worktree file—stays in place without changing HEAD, the
|
|
73
|
+
index, or remotes. The existing directory inode also stays live, so invoking
|
|
74
|
+
`lean-runtime init .` does not strand the shell in an unlinked working
|
|
75
|
+
directory. A pre-existing `AGENTS.md` is preserved. Other contents must be moved
|
|
76
|
+
first or represented by an existing pinned Lake project; the read-only plan
|
|
77
|
+
enforces the same rule as execution.
|
|
76
78
|
Use `--name NAME` when creating inside a lowercase or otherwise differently
|
|
77
79
|
named repository and the Lean root module needs an explicit spelling.
|
|
78
80
|
|
|
@@ -106,13 +108,15 @@ lean-runtime attach ~/research --recursive
|
|
|
106
108
|
lean-runtime attach ~/research --recursive --execute
|
|
107
109
|
```
|
|
108
110
|
|
|
109
|
-
The preview groups exact graphs
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
The preview groups exact graphs and separately reports checkout bytes removed,
|
|
112
|
+
compatible shared bytes already ready, new shared bytes required, and estimated
|
|
113
|
+
machine-level recovery. It also identifies missing local paths, dirty
|
|
114
|
+
dependencies, and revision mismatches. Execution continues through independent
|
|
115
|
+
projects while reporting per-project failures. It first prepares the exact
|
|
116
|
+
shared workspace and probes it through Lake. Only then does it atomically
|
|
117
|
+
replace `.lake/packages` with package links, probe the resulting project through
|
|
118
|
+
ordinary Lake, and discard the old generated copies. Any failure restores the
|
|
119
|
+
original package directory.
|
|
116
120
|
|
|
117
121
|
The project itself remains portable. To return to independent package copies:
|
|
118
122
|
|
|
@@ -151,12 +155,20 @@ their artifacts.
|
|
|
151
155
|
|
|
152
156
|
The first shared build imports a clean, revision-matching local dependency copy
|
|
153
157
|
when one exists, using copy-on-write filesystem clones where supported. Missing
|
|
154
|
-
sources are fetched at the exact manifest commit. A
|
|
158
|
+
sources are fetched at the exact manifest commit. A later project bypasses
|
|
159
|
+
source resolution when a managed package marker proves that its toolchain,
|
|
160
|
+
platform, revision, and effective dependency closure already match. A plain shared build never
|
|
155
161
|
deletes the old `.lake/packages`; only an explicit `attach --execute` replaces
|
|
156
162
|
those generated copies after verification. `lean-runtime storage` reports
|
|
157
163
|
shared project package usage; automatic cleanup of those packages is not yet
|
|
158
164
|
implemented.
|
|
159
165
|
|
|
166
|
+
Check capsules and mutable shared packages are intentionally separate storage
|
|
167
|
+
tiers. Capsules are source-free and trimmed for checking; ordinary Lake
|
|
168
|
+
development needs source-shaped packages and build metadata. A capsule can seed
|
|
169
|
+
compatible build artifacts while the exact source workspace is materialized,
|
|
170
|
+
but attached projects ultimately link to the mutable shared-project store.
|
|
171
|
+
|
|
160
172
|
This mode requires a manifest and never runs `lake update`, so it cannot silently
|
|
161
173
|
change dependency revisions. It also reuses an existing local Git object database
|
|
162
174
|
when that database contains another requested revision, avoiding redundant Git
|
|
@@ -7,6 +7,7 @@ import json
|
|
|
7
7
|
import sys
|
|
8
8
|
import time
|
|
9
9
|
from datetime import datetime
|
|
10
|
+
from importlib.metadata import version as distribution_version
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any
|
|
12
13
|
|
|
@@ -172,9 +173,12 @@ def _render_adoption_plan(plan: AdoptionPlan) -> None:
|
|
|
172
173
|
for warning in project.warnings:
|
|
173
174
|
print(f" note: {warning}")
|
|
174
175
|
print()
|
|
175
|
-
print(f"
|
|
176
|
-
print(f"
|
|
177
|
-
print(f"
|
|
176
|
+
print(f"Checkout bytes removed: {format_byte_size(plan.checkout_bytes_removed)}")
|
|
177
|
+
print(f"Shared bytes already ready:{format_byte_size(plan.shared_bytes_reused):>10}")
|
|
178
|
+
print(f"New shared bytes needed: {format_byte_size(plan.new_shared_bytes)}")
|
|
179
|
+
print(
|
|
180
|
+
f"Estimated machine recovery: {format_byte_size(plan.estimated_machine_reclaimable_bytes)}"
|
|
181
|
+
)
|
|
178
182
|
|
|
179
183
|
|
|
180
184
|
def _render_init_plan(plan: ProjectInitPlan) -> None:
|
|
@@ -280,6 +284,11 @@ def _add_policy(parser: argparse.ArgumentParser, *, timeout: float = 120) -> Non
|
|
|
280
284
|
|
|
281
285
|
def parser() -> argparse.ArgumentParser:
|
|
282
286
|
root = argparse.ArgumentParser(prog="lean-runtime")
|
|
287
|
+
root.add_argument(
|
|
288
|
+
"--version",
|
|
289
|
+
action="version",
|
|
290
|
+
version=f"%(prog)s {distribution_version('lean-runtime')}",
|
|
291
|
+
)
|
|
283
292
|
root.add_argument("--home", help="runtime store root")
|
|
284
293
|
root.add_argument("--quiet", action="store_true", help="suppress progress events")
|
|
285
294
|
root.add_argument("--verbose", action="store_true", help="show detailed decisions and checks")
|
|
@@ -747,7 +756,11 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
747
756
|
_render_adoption_plan(adoption_plan)
|
|
748
757
|
print("No changes made. Re-run with --execute to adopt shared packages.")
|
|
749
758
|
return 0 if adoption_plan.blocked == 0 else 1
|
|
750
|
-
adoption_result = runtime.attach_projects(
|
|
759
|
+
adoption_result = runtime.attach_projects(
|
|
760
|
+
args.path,
|
|
761
|
+
recursive=args.recursive,
|
|
762
|
+
plan=adoption_plan,
|
|
763
|
+
)
|
|
751
764
|
if args.json:
|
|
752
765
|
_json(adoption_result.to_dict())
|
|
753
766
|
else:
|
|
@@ -156,6 +156,8 @@ class AdoptionPlan:
|
|
|
156
156
|
recursive: bool
|
|
157
157
|
current_dependency_bytes: int
|
|
158
158
|
estimated_shared_bytes: int
|
|
159
|
+
shared_bytes_reused: int = 0
|
|
160
|
+
new_shared_bytes: int = 0
|
|
159
161
|
|
|
160
162
|
@property
|
|
161
163
|
def ready(self) -> int:
|
|
@@ -167,7 +169,16 @@ class AdoptionPlan:
|
|
|
167
169
|
|
|
168
170
|
@property
|
|
169
171
|
def estimated_reclaimable_bytes(self) -> int:
|
|
170
|
-
|
|
172
|
+
"""Compatibility alias for estimated machine-level recovery."""
|
|
173
|
+
return self.estimated_machine_reclaimable_bytes
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def checkout_bytes_removed(self) -> int:
|
|
177
|
+
return self.current_dependency_bytes
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def estimated_machine_reclaimable_bytes(self) -> int:
|
|
181
|
+
return max(0, self.current_dependency_bytes - self.new_shared_bytes)
|
|
171
182
|
|
|
172
183
|
def to_dict(self) -> dict[str, Any]:
|
|
173
184
|
return {
|
|
@@ -177,6 +188,10 @@ class AdoptionPlan:
|
|
|
177
188
|
"blocked": self.blocked,
|
|
178
189
|
"current_dependency_bytes": self.current_dependency_bytes,
|
|
179
190
|
"estimated_shared_bytes": self.estimated_shared_bytes,
|
|
191
|
+
"checkout_bytes_removed": self.checkout_bytes_removed,
|
|
192
|
+
"shared_bytes_reused": self.shared_bytes_reused,
|
|
193
|
+
"new_shared_bytes": self.new_shared_bytes,
|
|
194
|
+
"estimated_machine_reclaimable_bytes": (self.estimated_machine_reclaimable_bytes),
|
|
180
195
|
"estimated_reclaimable_bytes": self.estimated_reclaimable_bytes,
|
|
181
196
|
}
|
|
182
197
|
|
|
@@ -402,10 +417,16 @@ def inspect_adoption(root: Path) -> ProjectAdoption:
|
|
|
402
417
|
)
|
|
403
418
|
|
|
404
419
|
|
|
405
|
-
def plan_adoption(
|
|
420
|
+
def plan_adoption(
|
|
421
|
+
path: Path,
|
|
422
|
+
*,
|
|
423
|
+
recursive: bool,
|
|
424
|
+
shared: SharedProjectManager | None = None,
|
|
425
|
+
) -> AdoptionPlan:
|
|
406
426
|
roots = discover_shareable_projects(path, recursive=recursive)
|
|
407
427
|
projects = tuple(inspect_adoption(root) for root in roots)
|
|
408
428
|
groups: dict[str, int] = {}
|
|
429
|
+
reused_groups: set[str] = set()
|
|
409
430
|
for project in projects:
|
|
410
431
|
if not project.ready or project.attached:
|
|
411
432
|
continue
|
|
@@ -417,6 +438,15 @@ def plan_adoption(path: Path, *, recursive: bool) -> AdoptionPlan:
|
|
|
417
438
|
str(entry["name"]): _entry_identity(identity_entry)
|
|
418
439
|
for entry, identity_entry in zip(entries, identity_entries, strict=True)
|
|
419
440
|
}
|
|
441
|
+
reusable = (
|
|
442
|
+
shared.reusable_packages(
|
|
443
|
+
context,
|
|
444
|
+
entries,
|
|
445
|
+
effective_entries=effective_entries,
|
|
446
|
+
)
|
|
447
|
+
if shared is not None
|
|
448
|
+
else {}
|
|
449
|
+
)
|
|
420
450
|
package_dir = _packages_directory(context)
|
|
421
451
|
for entry in entries:
|
|
422
452
|
if entry["type"] != "git":
|
|
@@ -425,23 +455,30 @@ def plan_adoption(path: Path, *, recursive: bool) -> AdoptionPlan:
|
|
|
425
455
|
local_bytes = _tree_bytes(local)
|
|
426
456
|
subdir = entry.get("subDir")
|
|
427
457
|
source_package = local / subdir if isinstance(subdir, str) and subdir else local
|
|
428
|
-
|
|
458
|
+
reusable_package = reusable.get(str(entry["name"]))
|
|
459
|
+
if reusable_package is not None:
|
|
460
|
+
key = reusable_package.name
|
|
461
|
+
reused_groups.add(key)
|
|
462
|
+
elif _git_head(local) == entry.get("rev") and source_package.is_dir():
|
|
429
463
|
identity = _package_identity(
|
|
430
464
|
context=context,
|
|
431
465
|
entry=entry,
|
|
432
466
|
source_package=source_package,
|
|
433
467
|
effective_entries=effective_entries,
|
|
434
468
|
)
|
|
469
|
+
key = sha256_id("project_package", identity)
|
|
435
470
|
else:
|
|
436
471
|
identity = {
|
|
437
472
|
"toolchain": context.toolchain,
|
|
438
473
|
"manifest": manifest,
|
|
439
474
|
"package": entry,
|
|
440
475
|
}
|
|
441
|
-
|
|
476
|
+
key = sha256_id("project_adoption_estimate", identity)
|
|
442
477
|
groups[key] = max(groups.get(key, 0), local_bytes)
|
|
443
478
|
current = sum(project.dependency_bytes for project in projects if not project.attached)
|
|
444
|
-
|
|
479
|
+
reused = sum(size for key, size in groups.items() if key in reused_groups)
|
|
480
|
+
new = sum(size for key, size in groups.items() if key not in reused_groups)
|
|
481
|
+
return AdoptionPlan(projects, recursive, current, sum(groups.values()), reused, new)
|
|
445
482
|
|
|
446
483
|
|
|
447
484
|
def plan_detachment(root: Path) -> DetachmentPlan:
|
|
@@ -499,6 +536,12 @@ class ProjectAdopter:
|
|
|
499
536
|
seed_packages=seed_packages,
|
|
500
537
|
seed_package_paths=seed_package_paths,
|
|
501
538
|
)
|
|
539
|
+
self.shared.events.emit(
|
|
540
|
+
"project.attach.shared_probe_started",
|
|
541
|
+
f"Verifying shared graph for {context.root.name}",
|
|
542
|
+
phase="project-attach",
|
|
543
|
+
packages=len(workspace.package_ids),
|
|
544
|
+
)
|
|
502
545
|
probe(workspace.overrides_file)
|
|
503
546
|
manifest_packages = _manifest_packages(context)
|
|
504
547
|
override_value = json.loads(workspace.overrides_file.read_text(encoding="utf-8"))
|
|
@@ -525,6 +568,13 @@ class ProjectAdopter:
|
|
|
525
568
|
marker = lake_dir / ATTACHMENT_RECORD
|
|
526
569
|
config = context.root / PROJECT_CONFIG
|
|
527
570
|
try:
|
|
571
|
+
self.shared.events.emit(
|
|
572
|
+
"project.attach.swap_started",
|
|
573
|
+
f"Replacing local dependency copies for {context.root.name}",
|
|
574
|
+
phase="project-attach",
|
|
575
|
+
packages=len(workspace.package_ids),
|
|
576
|
+
checkout_bytes=reclaimed,
|
|
577
|
+
)
|
|
528
578
|
for entry in manifest_packages:
|
|
529
579
|
if entry["type"] != "git":
|
|
530
580
|
continue
|
|
@@ -544,6 +594,12 @@ class ProjectAdopter:
|
|
|
544
594
|
packages_dir.replace(backup)
|
|
545
595
|
staging.replace(packages_dir)
|
|
546
596
|
swapped = True
|
|
597
|
+
self.shared.events.emit(
|
|
598
|
+
"project.attach.attached_probe_started",
|
|
599
|
+
f"Verifying attached graph for {context.root.name}",
|
|
600
|
+
phase="project-attach",
|
|
601
|
+
packages=len(workspace.package_ids),
|
|
602
|
+
)
|
|
547
603
|
probe(None)
|
|
548
604
|
record = {
|
|
549
605
|
"schema": ATTACHMENT_SCHEMA,
|
|
@@ -556,6 +612,13 @@ class ProjectAdopter:
|
|
|
556
612
|
write_json_atomic(marker, record)
|
|
557
613
|
config.write_text(_CONFIG_CONTENT, encoding="utf-8")
|
|
558
614
|
_remove_path(backup)
|
|
615
|
+
self.shared.events.emit(
|
|
616
|
+
"project.attach.completed",
|
|
617
|
+
f"Attached shared dependencies for {context.root.name}",
|
|
618
|
+
phase="project-attach",
|
|
619
|
+
packages=len(workspace.package_ids),
|
|
620
|
+
checkout_bytes=reclaimed,
|
|
621
|
+
)
|
|
559
622
|
except BaseException:
|
|
560
623
|
_remove_path(staging)
|
|
561
624
|
if swapped:
|
|
@@ -1167,7 +1167,7 @@ class Runtime:
|
|
|
1167
1167
|
self, path: str | os.PathLike[str], *, recursive: bool = False
|
|
1168
1168
|
) -> AdoptionPlan:
|
|
1169
1169
|
"""Inspect one project or a tree without changing it."""
|
|
1170
|
-
return plan_adoption(Path(path), recursive=recursive)
|
|
1170
|
+
return plan_adoption(Path(path), recursive=recursive, shared=self.shared_projects)
|
|
1171
1171
|
|
|
1172
1172
|
def _probe_project_graph(
|
|
1173
1173
|
self,
|
|
@@ -1211,12 +1211,20 @@ class Runtime:
|
|
|
1211
1211
|
recursive: bool = False,
|
|
1212
1212
|
seed_packages: Path | None = None,
|
|
1213
1213
|
seed_package_paths: dict[str, Path] | None = None,
|
|
1214
|
+
plan: AdoptionPlan | None = None,
|
|
1214
1215
|
) -> AdoptionBatchResult:
|
|
1215
1216
|
"""Adopt exact shared dependencies after a read-only plan."""
|
|
1216
|
-
plan
|
|
1217
|
+
if plan is not None:
|
|
1218
|
+
requested_roots = discover_shareable_projects(Path(path), recursive=recursive)
|
|
1219
|
+
planned_roots = tuple(project.root for project in plan.projects)
|
|
1220
|
+
if requested_roots != planned_roots or plan.recursive != recursive:
|
|
1221
|
+
raise ProjectError("adoption plan does not match the requested project scope")
|
|
1222
|
+
selected_plan = plan
|
|
1223
|
+
else:
|
|
1224
|
+
selected_plan = self.plan_project_adoption(path, recursive=recursive)
|
|
1217
1225
|
results: list[AdoptionResult] = []
|
|
1218
1226
|
failures: list[tuple[Path, str]] = []
|
|
1219
|
-
for project in
|
|
1227
|
+
for project in selected_plan.projects:
|
|
1220
1228
|
if project.attached:
|
|
1221
1229
|
workspace_id = discover_project(project.root).provenance().workspace_id
|
|
1222
1230
|
results.append(
|
|
@@ -1242,15 +1250,15 @@ class Runtime:
|
|
|
1242
1250
|
self.project_adopter.attach(
|
|
1243
1251
|
context,
|
|
1244
1252
|
probe=probe,
|
|
1245
|
-
seed_packages=seed_packages if len(
|
|
1253
|
+
seed_packages=(seed_packages if len(selected_plan.projects) == 1 else None),
|
|
1246
1254
|
seed_package_paths=(
|
|
1247
|
-
seed_package_paths if len(
|
|
1255
|
+
seed_package_paths if len(selected_plan.projects) == 1 else None
|
|
1248
1256
|
),
|
|
1249
1257
|
)
|
|
1250
1258
|
)
|
|
1251
1259
|
except (OSError, ProjectError) as exc:
|
|
1252
1260
|
failures.append((project.root, str(exc)))
|
|
1253
|
-
return AdoptionBatchResult(
|
|
1261
|
+
return AdoptionBatchResult(selected_plan, tuple(results), tuple(failures))
|
|
1254
1262
|
|
|
1255
1263
|
def scan_projects(
|
|
1256
1264
|
self, path: str | os.PathLike[str], *, recursive: bool = True
|
|
@@ -1791,10 +1799,10 @@ class Runtime:
|
|
|
1791
1799
|
staging = Path(
|
|
1792
1800
|
tempfile.mkdtemp(prefix=f".{target.name}.lean-runtime-init-", dir=target.parent)
|
|
1793
1801
|
)
|
|
1794
|
-
backup: Path | None = None
|
|
1795
1802
|
published = False
|
|
1796
1803
|
original_git = next((entry for entry in existing_entries if entry.name == ".git"), None)
|
|
1797
|
-
|
|
1804
|
+
published_in_place = False
|
|
1805
|
+
published_entries: list[Path] = []
|
|
1798
1806
|
try:
|
|
1799
1807
|
custom_agents = target / "AGENTS.md"
|
|
1800
1808
|
if custom_agents.is_file():
|
|
@@ -1890,41 +1898,47 @@ class Runtime:
|
|
|
1890
1898
|
remove_tree(generated_git)
|
|
1891
1899
|
elif generated_git.exists() or generated_git.is_symlink():
|
|
1892
1900
|
generated_git.unlink()
|
|
1893
|
-
original_git.replace(generated_git)
|
|
1894
|
-
git_transferred = True
|
|
1895
1901
|
if target.exists():
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1902
|
+
# Keep an existing directory inode alive. Replacing the directory itself
|
|
1903
|
+
# leaves a shell that invoked `lean-runtime init .` inside an unlinked cwd.
|
|
1904
|
+
# Staging has already been fully initialized, attached, and probed, so only
|
|
1905
|
+
# its children need a small rollback-safe publication transaction here.
|
|
1906
|
+
published_in_place = True
|
|
1907
|
+
for entry in sorted(staging.iterdir(), key=lambda path: path.name):
|
|
1908
|
+
destination = target / entry.name
|
|
1909
|
+
if destination.exists() or destination.is_symlink():
|
|
1910
|
+
if entry.name == "AGENTS.md" and destination.is_file():
|
|
1911
|
+
if entry.is_symlink() or entry.is_file():
|
|
1912
|
+
entry.unlink()
|
|
1913
|
+
elif entry.exists():
|
|
1914
|
+
remove_tree(entry)
|
|
1915
|
+
continue
|
|
1916
|
+
raise ProjectError(
|
|
1917
|
+
f"initialization target changed while publishing: {destination}"
|
|
1918
|
+
)
|
|
1919
|
+
entry.replace(destination)
|
|
1920
|
+
published_entries.append(destination)
|
|
1921
|
+
else:
|
|
1922
|
+
staging.replace(target)
|
|
1899
1923
|
published = True
|
|
1900
|
-
if backup is not None:
|
|
1901
|
-
remove_tree(backup)
|
|
1902
|
-
backup = None
|
|
1903
1924
|
context = discover_project(target)
|
|
1904
1925
|
# Registry discovery is an optimization, not part of publishing the project.
|
|
1905
1926
|
with suppress(OSError, EnvironmentError):
|
|
1906
1927
|
self.shared_projects.remember_project(context)
|
|
1907
1928
|
return replace(result.results[0], root=target)
|
|
1908
1929
|
except BaseException:
|
|
1909
|
-
if
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
if target.exists():
|
|
1918
|
-
remove_tree(target)
|
|
1919
|
-
if backup is not None and backup.exists():
|
|
1920
|
-
backup.replace(target)
|
|
1921
|
-
backup = None
|
|
1930
|
+
if published_in_place:
|
|
1931
|
+
for entry in reversed(published_entries):
|
|
1932
|
+
if entry.is_symlink() or entry.is_file():
|
|
1933
|
+
entry.unlink()
|
|
1934
|
+
elif entry.exists():
|
|
1935
|
+
remove_tree(entry)
|
|
1936
|
+
elif published and target.exists():
|
|
1937
|
+
remove_tree(target)
|
|
1922
1938
|
raise
|
|
1923
1939
|
finally:
|
|
1924
1940
|
if staging.exists():
|
|
1925
1941
|
remove_tree(staging)
|
|
1926
|
-
if backup is not None and backup.exists():
|
|
1927
|
-
remove_tree(backup)
|
|
1928
1942
|
|
|
1929
1943
|
def project(
|
|
1930
1944
|
self,
|