lean-runtime 2.6.0__tar.gz → 2.6.1__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.0 → lean_runtime-2.6.1}/CHANGELOG.md +13 -0
- {lean_runtime-2.6.0/lean_runtime.egg-info → lean_runtime-2.6.1}/PKG-INFO +7 -1
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/README.md +6 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/cli.md +8 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/getting-started.md +17 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/local-projects.md +10 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/cli.py +13 -3
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/project_sharing.py +9 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/runtime.py +114 -13
- {lean_runtime-2.6.0 → lean_runtime-2.6.1/lean_runtime.egg-info}/PKG-INFO +7 -1
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/pyproject.toml +1 -1
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_cli.py +1 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_programs.py +1 -1
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_projects.py +131 -6
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/LICENSE +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/MANIFEST.in +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/environments.toml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/core-v4.32.2.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/leancert-v4.30.0.5.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/leancert-v4.31.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/leancert-v4.32.2.4.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/leancert-v4.33.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/mathlib-v4.30.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/mathlib-v4.31.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/mathlib-v4.32.2.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/catalog/locks/mathlib-v4.33.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/compatibility/README.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/compatibility/mathlib-4.32.2.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/compatibility/mathlib-4.32.2.toml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/compatibility/mathlib-4.33.0.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/compatibility/mathlib-4.33.0.toml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/architecture.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/captures.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/case-study-v1.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/development.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/environments.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/index.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/portable-copies.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/project-publishing.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/python-api.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/ready-programs.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/standalone-files.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/trust-and-limitations.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/docs/v1-precision.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/examples/mathlib.toml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/__init__.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/__main__.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/_git.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/_paths.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/backends.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/bundles.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/capsules.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/comparison.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/console.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/decisions.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/diagnostics.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/__init__.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/analyzer.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/api.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/candidate.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/catalog.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/catalog_build.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/catalog_cli.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/catalog_manifest.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/data/catalog.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/defaults.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/engine.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/errors.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/module_inventory.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/planner.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/policy.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/probe.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/py.typed +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/result.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/schema_resources.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/schemas/catalog-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/schemas/plan-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/discovery/schemas/result-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/environments.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/errors.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/events.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/facade.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/frontmatter.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/health.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/lake.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/lockfiles.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/locking.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/matrix.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/models.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/oci.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/packs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/policies.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/profiling.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/programs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/projects.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/publisher_verification.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/py.typed +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/references.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/resolver.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/run_cli.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/schema_resources.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/serialization.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/shared_projects.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/specs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/store.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/timings.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/toolchain_oci.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/toolchain_slim.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/toolchains.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/verification.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime/wire.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime.egg-info/SOURCES.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime.egg-info/dependency_links.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime.egg-info/entry_points.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime.egg-info/requires.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/lean_runtime.egg-info/top_level.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/mkdocs.yml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/schemas/cleanup-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/schemas/comparison-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/schemas/execution-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/schemas/inspect-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/schemas/matrix-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/schemas/profile-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/schemas/verify-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/scripts/announcement_gate.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/scripts/registry_preflight.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/scripts/run_compatibility.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/scripts/run_v1_case_study.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/scripts/smoke_wheel.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/setup.cfg +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/conftest.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/discovery/e2e/test_real_discovery.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/discovery/test_analyzer.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/discovery/test_catalog.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/discovery/test_catalog_build.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/discovery/test_discovery_schema_resources.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/discovery/test_engine.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/discovery/test_planner.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/discovery/test_policy.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_backend.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_bundles.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_capsules.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_console.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_diagnostics.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_environment_integration.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_events_health.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_facade.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_frontmatter.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_git.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_interactive.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_lockfiles.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_models.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_multifile.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_packs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_paths.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_prebuilt_policy.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_project_publish.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_references.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_run_cli.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_runtime.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_schema_resources.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_schemas.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_signatures.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_specs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_store.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_toolchain_oci.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_toolchain_slim.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_toolchains.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_v1_precision.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_verification_inventory.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.1}/tests/test_verification_probe.py +0 -0
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 2.6.1 - 2026-08-14
|
|
6
|
+
|
|
7
|
+
- Allow `lean-runtime init .` at an otherwise empty Git repository root while
|
|
8
|
+
preserving its original `.git` directory or worktree file, HEAD, and index.
|
|
9
|
+
Planning and execution now share target validation, so `init --plan` rejects
|
|
10
|
+
unsupported existing contents before reporting an acquisition-ready plan.
|
|
11
|
+
- Add `init --name NAME` for repository directories whose filesystem spelling
|
|
12
|
+
should not determine the Lake package and Lean root module name. Repeating
|
|
13
|
+
the same named initialization is idempotent; a conflicting name is rejected.
|
|
14
|
+
- Make `init --plan --offline` and `update --plan --offline` genuinely
|
|
15
|
+
network-free. Plans now report explicit blockers and return a failing status
|
|
16
|
+
when an exact local graph or required full toolchain is unavailable.
|
|
17
|
+
|
|
5
18
|
## 2.6.0 - 2026-08-14
|
|
6
19
|
|
|
7
20
|
- Make the local-project path a four-command workflow: `init`, `check`,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lean-runtime
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.1
|
|
4
4
|
Summary: Run Lean 4 proofs from Python or standalone files
|
|
5
5
|
Author: Alejandro Radisic
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -209,6 +209,12 @@ lean-runtime init .
|
|
|
209
209
|
`init --plan` is side-effect free; `--max-download 500MiB` and `--offline`
|
|
210
210
|
enforce cold-start policy. Advanced bulk migration remains available through
|
|
211
211
|
`attach`, and `detach --execute` materializes an independent project again.
|
|
212
|
+
For a new project, the target may be absent, empty, or an otherwise empty Git
|
|
213
|
+
repository root; existing Git identity and index state are preserved. A custom
|
|
214
|
+
`AGENTS.md` is also allowed and retained. Other existing contents are rejected
|
|
215
|
+
before acquisition rather than overwritten.
|
|
216
|
+
When the directory spelling is not the intended Lean module capitalization,
|
|
217
|
+
set it explicitly, for example `lean-runtime init . --name IntegralFramework`.
|
|
212
218
|
|
|
213
219
|
One-shot helpers are available when setup reuse is unnecessary:
|
|
214
220
|
|
|
@@ -173,6 +173,12 @@ lean-runtime init .
|
|
|
173
173
|
`init --plan` is side-effect free; `--max-download 500MiB` and `--offline`
|
|
174
174
|
enforce cold-start policy. Advanced bulk migration remains available through
|
|
175
175
|
`attach`, and `detach --execute` materializes an independent project again.
|
|
176
|
+
For a new project, the target may be absent, empty, or an otherwise empty Git
|
|
177
|
+
repository root; existing Git identity and index state are preserved. A custom
|
|
178
|
+
`AGENTS.md` is also allowed and retained. Other existing contents are rejected
|
|
179
|
+
before acquisition rather than overwritten.
|
|
180
|
+
When the directory spelling is not the intended Lean module capitalization,
|
|
181
|
+
set it explicitly, for example `lean-runtime init . --name IntegralFramework`.
|
|
176
182
|
|
|
177
183
|
One-shot helpers are available when setup reuse is unnecessary:
|
|
178
184
|
|
|
@@ -177,6 +177,14 @@ 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
179
|
|
|
180
|
+
A new `init` target may be absent, empty, or an otherwise empty Git root, with
|
|
181
|
+
an optional existing `AGENTS.md`. Git metadata and the custom guide are
|
|
182
|
+
preserved. Planning rejects any other existing contents using the same
|
|
183
|
+
validation as execution.
|
|
184
|
+
`--name NAME` overrides the inferred Lake package/root module name for a new
|
|
185
|
+
project, which is useful when a lowercase repository name needs internal
|
|
186
|
+
capitalization such as `IntegralFramework`.
|
|
187
|
+
|
|
180
188
|
Add supporting source files with repeatable `--include` options:
|
|
181
189
|
|
|
182
190
|
```bash
|
|
@@ -37,10 +37,27 @@ Before doing any work, `init --plan` reports the exact release, local reuse, and
|
|
|
37
37
|
known download size. `--max-download 500MiB` refuses a larger transfer and
|
|
38
38
|
`--offline` requires a matching local graph. Initialization is transactional:
|
|
39
39
|
the target appears only after Lake and the shared dependency graph both verify.
|
|
40
|
+
Offline plans perform no registry lookup; they return a blocked plan and a
|
|
41
|
+
nonzero status when the required exact local graph is absent.
|
|
40
42
|
Project development requires one full Lake-capable Lean toolchain per Lean
|
|
41
43
|
version. When it is absent, the plan says its Elan download size is unknown;
|
|
42
44
|
`--offline` and `--max-download` fail closed instead of silently installing it.
|
|
43
45
|
|
|
46
|
+
The target may be a missing directory, an empty directory, or an otherwise
|
|
47
|
+
empty Git repository root. In the Git case, `init` preserves the existing HEAD,
|
|
48
|
+
index, remotes, and worktree metadata. It also preserves an existing
|
|
49
|
+
`AGENTS.md`; any other non-project contents are rejected by both `--plan` and
|
|
50
|
+
execution rather than overwritten.
|
|
51
|
+
The directory name normally supplies the Lake package/root module name. Override
|
|
52
|
+
it when capitalization matters, for example:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
lean-runtime init . --name IntegralFramework
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The same command can be rerun safely after initialization; a different name is
|
|
59
|
+
rejected rather than silently renaming an existing project.
|
|
60
|
+
|
|
44
61
|
Dependency upgrades are explicit:
|
|
45
62
|
|
|
46
63
|
```bash
|
|
@@ -61,11 +61,21 @@ Initialization acquires and verifies the exact graph before publishing the
|
|
|
61
61
|
target directory. Use `--plan` for a side-effect-free cost report, `--offline`
|
|
62
62
|
to require local data, `--max-download SIZE` to enforce a transfer ceiling, or
|
|
63
63
|
`--seed-from PROJECT` to name an exact local donor.
|
|
64
|
+
Offline planning never queries configured registries. A missing exact local
|
|
65
|
+
graph appears as a blocker and makes the planning command fail.
|
|
64
66
|
The plan separately reports whether the full Lake-capable toolchain is already
|
|
65
67
|
installed. Because Elan does not publish a preflight byte count, a missing full
|
|
66
68
|
toolchain is rejected under `--offline` or `--max-download` rather than silently
|
|
67
69
|
bypassing the policy.
|
|
68
70
|
|
|
71
|
+
An otherwise empty Git root is a valid new-project target. The original `.git`
|
|
72
|
+
directory—or `.git` worktree file—is transferred through the atomic publication
|
|
73
|
+
without changing HEAD, the index, or remotes. A pre-existing `AGENTS.md` is also
|
|
74
|
+
preserved. Other contents must be moved first or represented by an existing
|
|
75
|
+
pinned Lake project; the read-only plan enforces the same rule as execution.
|
|
76
|
+
Use `--name NAME` when creating inside a lowercase or otherwise differently
|
|
77
|
+
named repository and the Lean root module needs an explicit spelling.
|
|
78
|
+
|
|
69
79
|
For an existing pinned project, `lean-runtime init .` adopts its current
|
|
70
80
|
manifest without changing versions. Register a collection once with
|
|
71
81
|
`lean-runtime scan ~/research`; future exact matches are preferred over
|
|
@@ -12,7 +12,7 @@ from typing import Any
|
|
|
12
12
|
|
|
13
13
|
from .console import styler_for
|
|
14
14
|
from .environments import ExecutionCapture
|
|
15
|
-
from .errors import LeanRuntimeError, MaterializationError, ResolutionError
|
|
15
|
+
from .errors import LeanRuntimeError, MaterializationError, ProjectError, ResolutionError
|
|
16
16
|
from .events import RuntimeEvent
|
|
17
17
|
from .lake import ROOT_MODULE
|
|
18
18
|
from .lockfiles import EnvironmentLock
|
|
@@ -184,7 +184,8 @@ def _render_init_plan(plan: ProjectInitPlan) -> None:
|
|
|
184
184
|
print(f"Exact dependencies: {len(plan.packages)} package(s); versions unchanged")
|
|
185
185
|
return
|
|
186
186
|
context = f"Mathlib {plan.mathlib_version}" if plan.mathlib_version else "core Lean"
|
|
187
|
-
|
|
187
|
+
name = plan.project_name or plan.root.name
|
|
188
|
+
print(f"Create {name} in {plan.root} · {context} · {plan.toolchain}")
|
|
188
189
|
if not plan.toolchain_installed:
|
|
189
190
|
print("Full Lake toolchain: download required (size not published by Elan)")
|
|
190
191
|
if plan.seed_root is not None:
|
|
@@ -194,6 +195,8 @@ def _render_init_plan(plan: ProjectInitPlan) -> None:
|
|
|
194
195
|
print(f"Download: {format_byte_size(plan.download_bytes)}")
|
|
195
196
|
else:
|
|
196
197
|
print("Download: unknown (no compatible published artifact could be priced)")
|
|
198
|
+
for blocker in plan.blockers:
|
|
199
|
+
print(f"Blocker: {blocker}")
|
|
197
200
|
|
|
198
201
|
|
|
199
202
|
def _render_update_plan(plan: ProjectUpdatePlan) -> None:
|
|
@@ -538,6 +541,7 @@ def parser() -> argparse.ArgumentParser:
|
|
|
538
541
|
"init", help="create a latest-Mathlib project or adopt an existing Lake project"
|
|
539
542
|
)
|
|
540
543
|
init.add_argument("path", type=Path, nargs="?", default=Path("."))
|
|
544
|
+
init.add_argument("--name", help="explicit Lake package and root module name")
|
|
541
545
|
init_context = init.add_mutually_exclusive_group()
|
|
542
546
|
init_context.add_argument(
|
|
543
547
|
"--mathlib",
|
|
@@ -666,6 +670,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
666
670
|
if args.command == "init":
|
|
667
671
|
init_plan = runtime.plan_project_init(
|
|
668
672
|
args.path,
|
|
673
|
+
name=args.name,
|
|
669
674
|
mathlib=args.mathlib,
|
|
670
675
|
toolchain=args.toolchain,
|
|
671
676
|
seed_from=args.seed_from,
|
|
@@ -675,11 +680,16 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
675
680
|
_json(init_plan.to_dict())
|
|
676
681
|
else:
|
|
677
682
|
_render_init_plan(init_plan)
|
|
678
|
-
return 0
|
|
683
|
+
return 0 if init_plan.ready else 1
|
|
684
|
+
if not init_plan.ready:
|
|
685
|
+
raise ProjectError(
|
|
686
|
+
"project cannot be initialized:\n- " + "\n- ".join(init_plan.blockers)
|
|
687
|
+
)
|
|
679
688
|
if not args.json:
|
|
680
689
|
_render_init_plan(init_plan)
|
|
681
690
|
init_result = runtime.init_project(
|
|
682
691
|
args.path,
|
|
692
|
+
name=args.name,
|
|
683
693
|
mathlib=args.mathlib,
|
|
684
694
|
toolchain=args.toolchain,
|
|
685
695
|
agents=args.agents,
|
|
@@ -232,6 +232,12 @@ class ProjectInitPlan:
|
|
|
232
232
|
download_bytes_complete: bool
|
|
233
233
|
already_attached: bool = False
|
|
234
234
|
toolchain_installed: bool = False
|
|
235
|
+
project_name: str | None = None
|
|
236
|
+
blockers: tuple[str, ...] = ()
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def ready(self) -> bool:
|
|
240
|
+
return not self.blockers
|
|
235
241
|
|
|
236
242
|
def to_dict(self) -> dict[str, Any]:
|
|
237
243
|
return {
|
|
@@ -245,6 +251,9 @@ class ProjectInitPlan:
|
|
|
245
251
|
"download_bytes_complete": self.download_bytes_complete,
|
|
246
252
|
"already_attached": self.already_attached,
|
|
247
253
|
"toolchain_installed": self.toolchain_installed,
|
|
254
|
+
"project_name": self.project_name,
|
|
255
|
+
"ready": self.ready,
|
|
256
|
+
"blockers": list(self.blockers),
|
|
248
257
|
}
|
|
249
258
|
|
|
250
259
|
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
7
|
import subprocess
|
|
8
|
+
import sys
|
|
8
9
|
import tempfile
|
|
9
10
|
import threading
|
|
10
11
|
from collections.abc import Mapping, Sequence
|
|
@@ -14,6 +15,11 @@ from datetime import datetime, timezone
|
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
from typing import Any
|
|
16
17
|
|
|
18
|
+
if sys.version_info >= (3, 11):
|
|
19
|
+
import tomllib
|
|
20
|
+
else: # pragma: no cover - exercised by the Python 3.10 CI job
|
|
21
|
+
import tomli as tomllib
|
|
22
|
+
|
|
17
23
|
from ._paths import remove_tree
|
|
18
24
|
from .backends import Backend, LocalBackend
|
|
19
25
|
from .bundles import EnvironmentBundles, PortableCopyInfo
|
|
@@ -1302,6 +1308,18 @@ class Runtime:
|
|
|
1302
1308
|
)
|
|
1303
1309
|
self.toolchains.ensure(toolchain)
|
|
1304
1310
|
|
|
1311
|
+
def _project_toolchain_blockers(self, toolchain: str, *, installed: bool) -> tuple[str, ...]:
|
|
1312
|
+
if installed:
|
|
1313
|
+
return ()
|
|
1314
|
+
if self.availability == "local":
|
|
1315
|
+
return (f"offline setup requires the full {toolchain} toolchain locally",)
|
|
1316
|
+
if self.max_download_bytes is not None:
|
|
1317
|
+
return (
|
|
1318
|
+
"the full Lake-capable Lean toolchain is missing and its Elan download "
|
|
1319
|
+
"cannot be preflighted under --max-download",
|
|
1320
|
+
)
|
|
1321
|
+
return ()
|
|
1322
|
+
|
|
1305
1323
|
def plan_project_update(
|
|
1306
1324
|
self,
|
|
1307
1325
|
path: str | os.PathLike[str] = ".",
|
|
@@ -1370,16 +1388,24 @@ class Runtime:
|
|
|
1370
1388
|
download_bytes: int | None = 0
|
|
1371
1389
|
complete = True
|
|
1372
1390
|
if changed:
|
|
1391
|
+
blockers.extend(
|
|
1392
|
+
self._project_toolchain_blockers(latest.toolchain, installed=toolchain_installed)
|
|
1393
|
+
)
|
|
1373
1394
|
seeds, seed_root = self._project_seed_paths(
|
|
1374
1395
|
latest.toolchain,
|
|
1375
1396
|
latest_packages,
|
|
1376
1397
|
seed_from=Path(seed_from) if seed_from is not None else None,
|
|
1377
1398
|
)
|
|
1378
1399
|
if not seeds:
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1400
|
+
if self.availability == "local":
|
|
1401
|
+
download_bytes = None
|
|
1402
|
+
complete = False
|
|
1403
|
+
blockers.append("offline update has no exact local Mathlib dependency graph")
|
|
1404
|
+
else:
|
|
1405
|
+
acquisition = self.plan_exact(latest.lock, import_roots=("Mathlib",))
|
|
1406
|
+
raw_download = acquisition.get("download_bytes")
|
|
1407
|
+
download_bytes = raw_download if isinstance(raw_download, int) else None
|
|
1408
|
+
complete = acquisition.get("download_bytes_complete") is True
|
|
1383
1409
|
if not toolchain_installed:
|
|
1384
1410
|
download_bytes = None
|
|
1385
1411
|
complete = False
|
|
@@ -1564,10 +1590,29 @@ class Runtime:
|
|
|
1564
1590
|
return registered, root
|
|
1565
1591
|
return {}, None
|
|
1566
1592
|
|
|
1593
|
+
@staticmethod
|
|
1594
|
+
def _validate_new_project_target(target: Path) -> tuple[Path, ...]:
|
|
1595
|
+
"""Validate metadata that can be preserved around an atomic project init."""
|
|
1596
|
+
if not target.exists():
|
|
1597
|
+
return ()
|
|
1598
|
+
if not target.is_dir():
|
|
1599
|
+
raise ProjectError(f"initialization target is not a directory: {target}")
|
|
1600
|
+
entries = tuple(target.iterdir())
|
|
1601
|
+
allowed = {".git", "AGENTS.md"}
|
|
1602
|
+
unsupported = [entry for entry in entries if entry.name not in allowed]
|
|
1603
|
+
if unsupported:
|
|
1604
|
+
names = ", ".join(sorted(entry.name for entry in unsupported))
|
|
1605
|
+
raise ProjectError(
|
|
1606
|
+
f"initialization target is not empty: {target} ({names}); choose an empty "
|
|
1607
|
+
"directory or run `lean-runtime init .` inside an existing Lake project"
|
|
1608
|
+
)
|
|
1609
|
+
return entries
|
|
1610
|
+
|
|
1567
1611
|
def plan_project_init(
|
|
1568
1612
|
self,
|
|
1569
1613
|
path: str | os.PathLike[str] = ".",
|
|
1570
1614
|
*,
|
|
1615
|
+
name: str | None = None,
|
|
1571
1616
|
mathlib: str | None = "latest",
|
|
1572
1617
|
toolchain: str | None = None,
|
|
1573
1618
|
seed_from: str | os.PathLike[str] | None = None,
|
|
@@ -1575,12 +1620,30 @@ class Runtime:
|
|
|
1575
1620
|
"""Plan project creation or adoption without changing the target."""
|
|
1576
1621
|
target = Path(path).expanduser().resolve()
|
|
1577
1622
|
if (target / "lakefile.toml").is_file() or (target / "lakefile.lean").is_file():
|
|
1623
|
+
if name is not None:
|
|
1624
|
+
lakefile = target / "lakefile.toml"
|
|
1625
|
+
if not lakefile.is_file():
|
|
1626
|
+
raise ProjectError(
|
|
1627
|
+
"cannot verify --name for an existing lakefile.lean project; omit it"
|
|
1628
|
+
)
|
|
1629
|
+
try:
|
|
1630
|
+
with lakefile.open("rb") as stream:
|
|
1631
|
+
configured_name = tomllib.load(stream).get("name")
|
|
1632
|
+
except (OSError, tomllib.TOMLDecodeError) as exc:
|
|
1633
|
+
raise ProjectError(f"could not verify existing project --name: {exc}") from exc
|
|
1634
|
+
if configured_name != name:
|
|
1635
|
+
raise ProjectError(
|
|
1636
|
+
f"existing project is named {configured_name!r}, not {name!r}"
|
|
1637
|
+
)
|
|
1578
1638
|
adoption = self.plan_project_adoption(target).projects[0]
|
|
1579
1639
|
installed = (
|
|
1580
1640
|
self._toolchain_installed(adoption.toolchain)
|
|
1581
1641
|
if adoption.toolchain is not None
|
|
1582
1642
|
else False
|
|
1583
1643
|
)
|
|
1644
|
+
blockers = tuple(adoption.blockers) + self._project_toolchain_blockers(
|
|
1645
|
+
adoption.toolchain or "unknown", installed=installed
|
|
1646
|
+
)
|
|
1584
1647
|
return ProjectInitPlan(
|
|
1585
1648
|
target,
|
|
1586
1649
|
"adopt",
|
|
@@ -1592,7 +1655,17 @@ class Runtime:
|
|
|
1592
1655
|
True,
|
|
1593
1656
|
adoption.attached,
|
|
1594
1657
|
installed,
|
|
1658
|
+
None,
|
|
1659
|
+
blockers,
|
|
1595
1660
|
)
|
|
1661
|
+
self._validate_new_project_target(target)
|
|
1662
|
+
project_name = name or target.name
|
|
1663
|
+
if name is not None and (
|
|
1664
|
+
not name
|
|
1665
|
+
or not (name[0].isalpha() or name[0] == "_")
|
|
1666
|
+
or any(not (character.isalnum() or character == "_") for character in name)
|
|
1667
|
+
):
|
|
1668
|
+
raise ProjectError("project --name must be a Lean identifier")
|
|
1596
1669
|
selected = self._mathlib_catalog_entry(mathlib or "latest")
|
|
1597
1670
|
selected_toolchain = normalize_toolchain(toolchain or selected.toolchain)
|
|
1598
1671
|
if mathlib is not None and selected_toolchain != selected.toolchain:
|
|
@@ -1602,6 +1675,7 @@ class Runtime:
|
|
|
1602
1675
|
)
|
|
1603
1676
|
if mathlib is None:
|
|
1604
1677
|
installed = self._toolchain_installed(selected_toolchain)
|
|
1678
|
+
blockers = self._project_toolchain_blockers(selected_toolchain, installed=installed)
|
|
1605
1679
|
return ProjectInitPlan(
|
|
1606
1680
|
target,
|
|
1607
1681
|
"create",
|
|
@@ -1613,6 +1687,8 @@ class Runtime:
|
|
|
1613
1687
|
installed,
|
|
1614
1688
|
False,
|
|
1615
1689
|
installed,
|
|
1690
|
+
project_name,
|
|
1691
|
+
blockers,
|
|
1616
1692
|
)
|
|
1617
1693
|
selected_packages = selected.lock.manifest["packages"]
|
|
1618
1694
|
assert isinstance(selected_packages, list)
|
|
@@ -1621,15 +1697,25 @@ class Runtime:
|
|
|
1621
1697
|
selected_packages,
|
|
1622
1698
|
seed_from=Path(seed_from) if seed_from is not None else None,
|
|
1623
1699
|
)
|
|
1700
|
+
toolchain_installed = self._toolchain_installed(selected_toolchain)
|
|
1701
|
+
init_blockers = list(
|
|
1702
|
+
self._project_toolchain_blockers(
|
|
1703
|
+
selected_toolchain,
|
|
1704
|
+
installed=toolchain_installed,
|
|
1705
|
+
)
|
|
1706
|
+
)
|
|
1624
1707
|
if seed_paths:
|
|
1625
1708
|
download_bytes: int | None = 0
|
|
1626
1709
|
complete = True
|
|
1710
|
+
elif self.availability == "local":
|
|
1711
|
+
download_bytes = None
|
|
1712
|
+
complete = False
|
|
1713
|
+
init_blockers.append("offline setup has no exact local Mathlib dependency graph")
|
|
1627
1714
|
else:
|
|
1628
1715
|
acquisition = self.plan_exact(selected.lock, import_roots=("Mathlib",))
|
|
1629
1716
|
raw_download = acquisition.get("download_bytes")
|
|
1630
1717
|
download_bytes = raw_download if isinstance(raw_download, int) else None
|
|
1631
1718
|
complete = acquisition.get("download_bytes_complete") is True
|
|
1632
|
-
toolchain_installed = self._toolchain_installed(selected_toolchain)
|
|
1633
1719
|
if not toolchain_installed:
|
|
1634
1720
|
download_bytes = None
|
|
1635
1721
|
complete = False
|
|
@@ -1644,12 +1730,15 @@ class Runtime:
|
|
|
1644
1730
|
complete,
|
|
1645
1731
|
False,
|
|
1646
1732
|
toolchain_installed,
|
|
1733
|
+
project_name,
|
|
1734
|
+
tuple(init_blockers),
|
|
1647
1735
|
)
|
|
1648
1736
|
|
|
1649
1737
|
def init_project(
|
|
1650
1738
|
self,
|
|
1651
1739
|
path: str | os.PathLike[str] = ".",
|
|
1652
1740
|
*,
|
|
1741
|
+
name: str | None = None,
|
|
1653
1742
|
mathlib: str | None = "latest",
|
|
1654
1743
|
toolchain: str | None = None,
|
|
1655
1744
|
agents: bool = True,
|
|
@@ -1670,6 +1759,7 @@ class Runtime:
|
|
|
1670
1759
|
|
|
1671
1760
|
plan = self.plan_project_init(
|
|
1672
1761
|
target,
|
|
1762
|
+
name=name,
|
|
1673
1763
|
mathlib=mathlib,
|
|
1674
1764
|
toolchain=toolchain,
|
|
1675
1765
|
seed_from=seed_from,
|
|
@@ -1697,18 +1787,14 @@ class Runtime:
|
|
|
1697
1787
|
seed_packages = environment.workspace / str(raw_packages)
|
|
1698
1788
|
seed_package_paths = None
|
|
1699
1789
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
1700
|
-
existing_entries =
|
|
1701
|
-
unsupported = [entry for entry in existing_entries if entry.name != "AGENTS.md"]
|
|
1702
|
-
if unsupported:
|
|
1703
|
-
raise ProjectError(
|
|
1704
|
-
f"initialization target is not empty: {target}; use `lean-runtime init .` "
|
|
1705
|
-
"inside an existing Lake project to adopt it"
|
|
1706
|
-
)
|
|
1790
|
+
existing_entries = self._validate_new_project_target(target)
|
|
1707
1791
|
staging = Path(
|
|
1708
1792
|
tempfile.mkdtemp(prefix=f".{target.name}.lean-runtime-init-", dir=target.parent)
|
|
1709
1793
|
)
|
|
1710
1794
|
backup: Path | None = None
|
|
1711
1795
|
published = False
|
|
1796
|
+
original_git = next((entry for entry in existing_entries if entry.name == ".git"), None)
|
|
1797
|
+
git_transferred = False
|
|
1712
1798
|
try:
|
|
1713
1799
|
custom_agents = target / "AGENTS.md"
|
|
1714
1800
|
if custom_agents.is_file():
|
|
@@ -1719,7 +1805,7 @@ class Runtime:
|
|
|
1719
1805
|
"--offline",
|
|
1720
1806
|
f"--dir={staging}",
|
|
1721
1807
|
"init",
|
|
1722
|
-
target.name,
|
|
1808
|
+
plan.project_name or target.name,
|
|
1723
1809
|
"lib",
|
|
1724
1810
|
)
|
|
1725
1811
|
process = subprocess.run(
|
|
@@ -1798,6 +1884,14 @@ class Runtime:
|
|
|
1798
1884
|
agents_file = staging / "AGENTS.md"
|
|
1799
1885
|
if agents and not agents_file.exists():
|
|
1800
1886
|
agents_file.write_text(_DEFAULT_AGENTS_GUIDE, encoding="utf-8")
|
|
1887
|
+
if original_git is not None:
|
|
1888
|
+
generated_git = staging / ".git"
|
|
1889
|
+
if generated_git.is_dir() and not generated_git.is_symlink():
|
|
1890
|
+
remove_tree(generated_git)
|
|
1891
|
+
elif generated_git.exists() or generated_git.is_symlink():
|
|
1892
|
+
generated_git.unlink()
|
|
1893
|
+
original_git.replace(generated_git)
|
|
1894
|
+
git_transferred = True
|
|
1801
1895
|
if target.exists():
|
|
1802
1896
|
backup = target.parent / f".{target.name}.lean-runtime-backup-{os.getpid()}"
|
|
1803
1897
|
target.replace(backup)
|
|
@@ -1812,6 +1906,13 @@ class Runtime:
|
|
|
1812
1906
|
self.shared_projects.remember_project(context)
|
|
1813
1907
|
return replace(result.results[0], root=target)
|
|
1814
1908
|
except BaseException:
|
|
1909
|
+
if git_transferred:
|
|
1910
|
+
staged_git = (target if published else staging) / ".git"
|
|
1911
|
+
restore_root = backup if backup is not None and backup.exists() else target
|
|
1912
|
+
if staged_git.exists() or staged_git.is_symlink():
|
|
1913
|
+
restore_root.mkdir(parents=True, exist_ok=True)
|
|
1914
|
+
staged_git.replace(restore_root / ".git")
|
|
1915
|
+
git_transferred = False
|
|
1815
1916
|
if published:
|
|
1816
1917
|
if target.exists():
|
|
1817
1918
|
remove_tree(target)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lean-runtime
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.1
|
|
4
4
|
Summary: Run Lean 4 proofs from Python or standalone files
|
|
5
5
|
Author: Alejandro Radisic
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -209,6 +209,12 @@ lean-runtime init .
|
|
|
209
209
|
`init --plan` is side-effect free; `--max-download 500MiB` and `--offline`
|
|
210
210
|
enforce cold-start policy. Advanced bulk migration remains available through
|
|
211
211
|
`attach`, and `detach --execute` materializes an independent project again.
|
|
212
|
+
For a new project, the target may be absent, empty, or an otherwise empty Git
|
|
213
|
+
repository root; existing Git identity and index state are preserved. A custom
|
|
214
|
+
`AGENTS.md` is also allowed and retained. Other existing contents are rejected
|
|
215
|
+
before acquisition rather than overwritten.
|
|
216
|
+
When the directory spelling is not the intended Lean module capitalization,
|
|
217
|
+
set it explicitly, for example `lean-runtime init . --name IntegralFramework`.
|
|
212
218
|
|
|
213
219
|
One-shot helpers are available when setup reuse is unnecessary:
|
|
214
220
|
|
|
@@ -44,6 +44,7 @@ def test_project_sharing_commands_have_safe_defaults() -> None:
|
|
|
44
44
|
assert init.mathlib == "4.33.0"
|
|
45
45
|
assert init.agents
|
|
46
46
|
assert parser().parse_args(["init", "demo", "--core"]).mathlib is None
|
|
47
|
+
assert parser().parse_args(["init", ".", "--name", "DemoProject"]).name == "DemoProject"
|
|
47
48
|
assert not parser().parse_args(["init", "demo", "--no-agents"]).agents
|
|
48
49
|
attach = parser().parse_args(["attach", "projects", "--recursive"])
|
|
49
50
|
assert attach.recursive and not attach.execute
|
|
@@ -18,7 +18,7 @@ def _payload(root: Path) -> Path:
|
|
|
18
18
|
payload = root / "payload"
|
|
19
19
|
payload.mkdir()
|
|
20
20
|
executable = payload / "echo-bridge"
|
|
21
|
-
executable.write_text("#!/bin/sh\
|
|
21
|
+
executable.write_text("#!/bin/sh\nexec /bin/cat\n")
|
|
22
22
|
executable.chmod(0o755)
|
|
23
23
|
return payload
|
|
24
24
|
|