lean-runtime 2.6.0__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.0 → lean_runtime-2.6.2}/CHANGELOG.md +26 -0
- {lean_runtime-2.6.0/lean_runtime.egg-info → lean_runtime-2.6.2}/PKG-INFO +9 -1
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/README.md +8 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/cli.md +15 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/getting-started.md +19 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/local-projects.md +30 -8
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/cli.py +30 -7
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/project_sharing.py +77 -5
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/runtime.py +149 -34
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/shared_projects.py +123 -15
- {lean_runtime-2.6.0 → lean_runtime-2.6.2/lean_runtime.egg-info}/PKG-INFO +9 -1
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/pyproject.toml +1 -1
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_cli.py +8 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_programs.py +1 -1
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_projects.py +189 -6
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/LICENSE +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/MANIFEST.in +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/environments.toml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/core-v4.32.2.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/leancert-v4.30.0.5.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/leancert-v4.31.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/leancert-v4.32.2.4.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/leancert-v4.33.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/mathlib-v4.30.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/mathlib-v4.31.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/mathlib-v4.32.2.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/catalog/locks/mathlib-v4.33.0.lock.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/compatibility/README.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/compatibility/mathlib-4.32.2.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/compatibility/mathlib-4.32.2.toml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/compatibility/mathlib-4.33.0.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/compatibility/mathlib-4.33.0.toml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/architecture.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/captures.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/case-study-v1.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/development.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/environments.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/index.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/portable-copies.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/project-publishing.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/python-api.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/ready-programs.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/standalone-files.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/trust-and-limitations.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/docs/v1-precision.md +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/examples/mathlib.toml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/__init__.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/__main__.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/_git.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/_paths.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/backends.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/bundles.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/capsules.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/comparison.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/console.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/decisions.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/diagnostics.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/__init__.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/analyzer.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/api.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/candidate.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/catalog.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/catalog_build.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/catalog_cli.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/catalog_manifest.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/data/catalog.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/defaults.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/engine.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/errors.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/module_inventory.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/planner.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/policy.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/probe.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/py.typed +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/result.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/schema_resources.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/schemas/catalog-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/schemas/plan-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/discovery/schemas/result-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/environments.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/errors.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/events.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/facade.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/frontmatter.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/health.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/lake.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/lockfiles.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/locking.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/matrix.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/models.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/oci.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/packs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/policies.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/profiling.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/programs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/projects.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/publisher_verification.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/py.typed +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/references.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/resolver.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/run_cli.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/schema_resources.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/serialization.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/specs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/store.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/timings.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/toolchain_oci.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/toolchain_slim.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/toolchains.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/verification.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime/wire.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime.egg-info/SOURCES.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime.egg-info/dependency_links.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime.egg-info/entry_points.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime.egg-info/requires.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/lean_runtime.egg-info/top_level.txt +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/mkdocs.yml +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/schemas/cleanup-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/schemas/comparison-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/schemas/execution-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/schemas/inspect-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/schemas/matrix-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/schemas/profile-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/schemas/verify-v1.schema.json +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/scripts/announcement_gate.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/scripts/registry_preflight.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/scripts/run_compatibility.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/scripts/run_v1_case_study.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/scripts/smoke_wheel.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/setup.cfg +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/conftest.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/discovery/e2e/test_real_discovery.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/discovery/test_analyzer.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/discovery/test_catalog.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/discovery/test_catalog_build.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/discovery/test_discovery_schema_resources.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/discovery/test_engine.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/discovery/test_planner.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/discovery/test_policy.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_backend.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_bundles.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_capsules.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_console.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_diagnostics.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_environment_integration.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_events_health.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_facade.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_frontmatter.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_git.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_interactive.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_lockfiles.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_models.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_multifile.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_packs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_paths.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_prebuilt_policy.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_project_publish.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_references.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_run_cli.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_runtime.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_schema_resources.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_schemas.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_signatures.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_specs.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_store.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_toolchain_oci.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_toolchain_slim.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_toolchains.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_v1_precision.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_verification_inventory.py +0 -0
- {lean_runtime-2.6.0 → lean_runtime-2.6.2}/tests/test_verification_probe.py +0 -0
|
@@ -2,6 +2,32 @@
|
|
|
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
|
+
|
|
18
|
+
## 2.6.1 - 2026-08-14
|
|
19
|
+
|
|
20
|
+
- Allow `lean-runtime init .` at an otherwise empty Git repository root while
|
|
21
|
+
preserving its original `.git` directory or worktree file, HEAD, and index.
|
|
22
|
+
Planning and execution now share target validation, so `init --plan` rejects
|
|
23
|
+
unsupported existing contents before reporting an acquisition-ready plan.
|
|
24
|
+
- Add `init --name NAME` for repository directories whose filesystem spelling
|
|
25
|
+
should not determine the Lake package and Lean root module name. Repeating
|
|
26
|
+
the same named initialization is idempotent; a conflicting name is rejected.
|
|
27
|
+
- Make `init --plan --offline` and `update --plan --offline` genuinely
|
|
28
|
+
network-free. Plans now report explicit blockers and return a failing status
|
|
29
|
+
when an exact local graph or required full toolchain is unavailable.
|
|
30
|
+
|
|
5
31
|
## 2.6.0 - 2026-08-14
|
|
6
32
|
|
|
7
33
|
- 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.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
|
|
@@ -209,6 +209,14 @@ 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
|
+
An existing target directory remains the same live directory, so `init .` does
|
|
217
|
+
not invalidate the invoking shell's working directory.
|
|
218
|
+
When the directory spelling is not the intended Lean module capitalization,
|
|
219
|
+
set it explicitly, for example `lean-runtime init . --name IntegralFramework`.
|
|
212
220
|
|
|
213
221
|
One-shot helpers are available when setup reuse is unnecessary:
|
|
214
222
|
|
|
@@ -173,6 +173,14 @@ 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
|
+
An existing target directory remains the same live directory, so `init .` does
|
|
181
|
+
not invalidate the invoking shell's working directory.
|
|
182
|
+
When the directory spelling is not the intended Lean module capitalization,
|
|
183
|
+
set it explicitly, for example `lean-runtime init . --name IntegralFramework`.
|
|
176
184
|
|
|
177
185
|
One-shot helpers are available when setup reuse is unnecessary:
|
|
178
186
|
|
|
@@ -176,6 +176,21 @@ 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.
|
|
184
|
+
|
|
185
|
+
A new `init` target may be absent, empty, or an otherwise empty Git root, with
|
|
186
|
+
an optional existing `AGENTS.md`. Git metadata and the custom guide are
|
|
187
|
+
preserved. Planning rejects any other existing contents using the same
|
|
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.
|
|
191
|
+
`--name NAME` overrides the inferred Lake package/root module name for a new
|
|
192
|
+
project, which is useful when a lowercase repository name needs internal
|
|
193
|
+
capitalization such as `IntegralFramework`.
|
|
179
194
|
|
|
180
195
|
Add supporting source files with repeatable `--include` options:
|
|
181
196
|
|
|
@@ -37,10 +37,29 @@ 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
|
+
If the target already exists, initialization keeps that directory inode alive;
|
|
52
|
+
the shell that runs `lean-runtime init .` can immediately continue using it.
|
|
53
|
+
The directory name normally supplies the Lake package/root module name. Override
|
|
54
|
+
it when capitalization matters, for example:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
lean-runtime init . --name IntegralFramework
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The same command can be rerun safely after initialization; a different name is
|
|
61
|
+
rejected rather than silently renaming an existing project.
|
|
62
|
+
|
|
44
63
|
Dependency upgrades are explicit:
|
|
45
64
|
|
|
46
65
|
```bash
|
|
@@ -61,11 +61,23 @@ 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—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.
|
|
78
|
+
Use `--name NAME` when creating inside a lowercase or otherwise differently
|
|
79
|
+
named repository and the Lean root module needs an explicit spelling.
|
|
80
|
+
|
|
69
81
|
For an existing pinned project, `lean-runtime init .` adopts its current
|
|
70
82
|
manifest without changing versions. Register a collection once with
|
|
71
83
|
`lean-runtime scan ~/research`; future exact matches are preferred over
|
|
@@ -96,13 +108,15 @@ lean-runtime attach ~/research --recursive
|
|
|
96
108
|
lean-runtime attach ~/research --recursive --execute
|
|
97
109
|
```
|
|
98
110
|
|
|
99
|
-
The preview groups exact graphs
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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.
|
|
106
120
|
|
|
107
121
|
The project itself remains portable. To return to independent package copies:
|
|
108
122
|
|
|
@@ -141,12 +155,20 @@ their artifacts.
|
|
|
141
155
|
|
|
142
156
|
The first shared build imports a clean, revision-matching local dependency copy
|
|
143
157
|
when one exists, using copy-on-write filesystem clones where supported. Missing
|
|
144
|
-
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
|
|
145
161
|
deletes the old `.lake/packages`; only an explicit `attach --execute` replaces
|
|
146
162
|
those generated copies after verification. `lean-runtime storage` reports
|
|
147
163
|
shared project package usage; automatic cleanup of those packages is not yet
|
|
148
164
|
implemented.
|
|
149
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
|
+
|
|
150
172
|
This mode requires a manifest and never runs `lake update`, so it cannot silently
|
|
151
173
|
change dependency revisions. It also reuses an existing local Git object database
|
|
152
174
|
when that database contains another requested revision, avoiding redundant Git
|
|
@@ -7,12 +7,13 @@ 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
|
|
|
13
14
|
from .console import styler_for
|
|
14
15
|
from .environments import ExecutionCapture
|
|
15
|
-
from .errors import LeanRuntimeError, MaterializationError, ResolutionError
|
|
16
|
+
from .errors import LeanRuntimeError, MaterializationError, ProjectError, ResolutionError
|
|
16
17
|
from .events import RuntimeEvent
|
|
17
18
|
from .lake import ROOT_MODULE
|
|
18
19
|
from .lockfiles import EnvironmentLock
|
|
@@ -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:
|
|
@@ -184,7 +188,8 @@ def _render_init_plan(plan: ProjectInitPlan) -> None:
|
|
|
184
188
|
print(f"Exact dependencies: {len(plan.packages)} package(s); versions unchanged")
|
|
185
189
|
return
|
|
186
190
|
context = f"Mathlib {plan.mathlib_version}" if plan.mathlib_version else "core Lean"
|
|
187
|
-
|
|
191
|
+
name = plan.project_name or plan.root.name
|
|
192
|
+
print(f"Create {name} in {plan.root} · {context} · {plan.toolchain}")
|
|
188
193
|
if not plan.toolchain_installed:
|
|
189
194
|
print("Full Lake toolchain: download required (size not published by Elan)")
|
|
190
195
|
if plan.seed_root is not None:
|
|
@@ -194,6 +199,8 @@ def _render_init_plan(plan: ProjectInitPlan) -> None:
|
|
|
194
199
|
print(f"Download: {format_byte_size(plan.download_bytes)}")
|
|
195
200
|
else:
|
|
196
201
|
print("Download: unknown (no compatible published artifact could be priced)")
|
|
202
|
+
for blocker in plan.blockers:
|
|
203
|
+
print(f"Blocker: {blocker}")
|
|
197
204
|
|
|
198
205
|
|
|
199
206
|
def _render_update_plan(plan: ProjectUpdatePlan) -> None:
|
|
@@ -277,6 +284,11 @@ def _add_policy(parser: argparse.ArgumentParser, *, timeout: float = 120) -> Non
|
|
|
277
284
|
|
|
278
285
|
def parser() -> argparse.ArgumentParser:
|
|
279
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
|
+
)
|
|
280
292
|
root.add_argument("--home", help="runtime store root")
|
|
281
293
|
root.add_argument("--quiet", action="store_true", help="suppress progress events")
|
|
282
294
|
root.add_argument("--verbose", action="store_true", help="show detailed decisions and checks")
|
|
@@ -538,6 +550,7 @@ def parser() -> argparse.ArgumentParser:
|
|
|
538
550
|
"init", help="create a latest-Mathlib project or adopt an existing Lake project"
|
|
539
551
|
)
|
|
540
552
|
init.add_argument("path", type=Path, nargs="?", default=Path("."))
|
|
553
|
+
init.add_argument("--name", help="explicit Lake package and root module name")
|
|
541
554
|
init_context = init.add_mutually_exclusive_group()
|
|
542
555
|
init_context.add_argument(
|
|
543
556
|
"--mathlib",
|
|
@@ -666,6 +679,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
666
679
|
if args.command == "init":
|
|
667
680
|
init_plan = runtime.plan_project_init(
|
|
668
681
|
args.path,
|
|
682
|
+
name=args.name,
|
|
669
683
|
mathlib=args.mathlib,
|
|
670
684
|
toolchain=args.toolchain,
|
|
671
685
|
seed_from=args.seed_from,
|
|
@@ -675,11 +689,16 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
675
689
|
_json(init_plan.to_dict())
|
|
676
690
|
else:
|
|
677
691
|
_render_init_plan(init_plan)
|
|
678
|
-
return 0
|
|
692
|
+
return 0 if init_plan.ready else 1
|
|
693
|
+
if not init_plan.ready:
|
|
694
|
+
raise ProjectError(
|
|
695
|
+
"project cannot be initialized:\n- " + "\n- ".join(init_plan.blockers)
|
|
696
|
+
)
|
|
679
697
|
if not args.json:
|
|
680
698
|
_render_init_plan(init_plan)
|
|
681
699
|
init_result = runtime.init_project(
|
|
682
700
|
args.path,
|
|
701
|
+
name=args.name,
|
|
683
702
|
mathlib=args.mathlib,
|
|
684
703
|
toolchain=args.toolchain,
|
|
685
704
|
agents=args.agents,
|
|
@@ -737,7 +756,11 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
737
756
|
_render_adoption_plan(adoption_plan)
|
|
738
757
|
print("No changes made. Re-run with --execute to adopt shared packages.")
|
|
739
758
|
return 0 if adoption_plan.blocked == 0 else 1
|
|
740
|
-
adoption_result = runtime.attach_projects(
|
|
759
|
+
adoption_result = runtime.attach_projects(
|
|
760
|
+
args.path,
|
|
761
|
+
recursive=args.recursive,
|
|
762
|
+
plan=adoption_plan,
|
|
763
|
+
)
|
|
741
764
|
if args.json:
|
|
742
765
|
_json(adoption_result.to_dict())
|
|
743
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
|
|
|
@@ -232,6 +247,12 @@ class ProjectInitPlan:
|
|
|
232
247
|
download_bytes_complete: bool
|
|
233
248
|
already_attached: bool = False
|
|
234
249
|
toolchain_installed: bool = False
|
|
250
|
+
project_name: str | None = None
|
|
251
|
+
blockers: tuple[str, ...] = ()
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
def ready(self) -> bool:
|
|
255
|
+
return not self.blockers
|
|
235
256
|
|
|
236
257
|
def to_dict(self) -> dict[str, Any]:
|
|
237
258
|
return {
|
|
@@ -245,6 +266,9 @@ class ProjectInitPlan:
|
|
|
245
266
|
"download_bytes_complete": self.download_bytes_complete,
|
|
246
267
|
"already_attached": self.already_attached,
|
|
247
268
|
"toolchain_installed": self.toolchain_installed,
|
|
269
|
+
"project_name": self.project_name,
|
|
270
|
+
"ready": self.ready,
|
|
271
|
+
"blockers": list(self.blockers),
|
|
248
272
|
}
|
|
249
273
|
|
|
250
274
|
|
|
@@ -393,10 +417,16 @@ def inspect_adoption(root: Path) -> ProjectAdoption:
|
|
|
393
417
|
)
|
|
394
418
|
|
|
395
419
|
|
|
396
|
-
def plan_adoption(
|
|
420
|
+
def plan_adoption(
|
|
421
|
+
path: Path,
|
|
422
|
+
*,
|
|
423
|
+
recursive: bool,
|
|
424
|
+
shared: SharedProjectManager | None = None,
|
|
425
|
+
) -> AdoptionPlan:
|
|
397
426
|
roots = discover_shareable_projects(path, recursive=recursive)
|
|
398
427
|
projects = tuple(inspect_adoption(root) for root in roots)
|
|
399
428
|
groups: dict[str, int] = {}
|
|
429
|
+
reused_groups: set[str] = set()
|
|
400
430
|
for project in projects:
|
|
401
431
|
if not project.ready or project.attached:
|
|
402
432
|
continue
|
|
@@ -408,6 +438,15 @@ def plan_adoption(path: Path, *, recursive: bool) -> AdoptionPlan:
|
|
|
408
438
|
str(entry["name"]): _entry_identity(identity_entry)
|
|
409
439
|
for entry, identity_entry in zip(entries, identity_entries, strict=True)
|
|
410
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
|
+
)
|
|
411
450
|
package_dir = _packages_directory(context)
|
|
412
451
|
for entry in entries:
|
|
413
452
|
if entry["type"] != "git":
|
|
@@ -416,23 +455,30 @@ def plan_adoption(path: Path, *, recursive: bool) -> AdoptionPlan:
|
|
|
416
455
|
local_bytes = _tree_bytes(local)
|
|
417
456
|
subdir = entry.get("subDir")
|
|
418
457
|
source_package = local / subdir if isinstance(subdir, str) and subdir else local
|
|
419
|
-
|
|
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():
|
|
420
463
|
identity = _package_identity(
|
|
421
464
|
context=context,
|
|
422
465
|
entry=entry,
|
|
423
466
|
source_package=source_package,
|
|
424
467
|
effective_entries=effective_entries,
|
|
425
468
|
)
|
|
469
|
+
key = sha256_id("project_package", identity)
|
|
426
470
|
else:
|
|
427
471
|
identity = {
|
|
428
472
|
"toolchain": context.toolchain,
|
|
429
473
|
"manifest": manifest,
|
|
430
474
|
"package": entry,
|
|
431
475
|
}
|
|
432
|
-
|
|
476
|
+
key = sha256_id("project_adoption_estimate", identity)
|
|
433
477
|
groups[key] = max(groups.get(key, 0), local_bytes)
|
|
434
478
|
current = sum(project.dependency_bytes for project in projects if not project.attached)
|
|
435
|
-
|
|
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)
|
|
436
482
|
|
|
437
483
|
|
|
438
484
|
def plan_detachment(root: Path) -> DetachmentPlan:
|
|
@@ -490,6 +536,12 @@ class ProjectAdopter:
|
|
|
490
536
|
seed_packages=seed_packages,
|
|
491
537
|
seed_package_paths=seed_package_paths,
|
|
492
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
|
+
)
|
|
493
545
|
probe(workspace.overrides_file)
|
|
494
546
|
manifest_packages = _manifest_packages(context)
|
|
495
547
|
override_value = json.loads(workspace.overrides_file.read_text(encoding="utf-8"))
|
|
@@ -516,6 +568,13 @@ class ProjectAdopter:
|
|
|
516
568
|
marker = lake_dir / ATTACHMENT_RECORD
|
|
517
569
|
config = context.root / PROJECT_CONFIG
|
|
518
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
|
+
)
|
|
519
578
|
for entry in manifest_packages:
|
|
520
579
|
if entry["type"] != "git":
|
|
521
580
|
continue
|
|
@@ -535,6 +594,12 @@ class ProjectAdopter:
|
|
|
535
594
|
packages_dir.replace(backup)
|
|
536
595
|
staging.replace(packages_dir)
|
|
537
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
|
+
)
|
|
538
603
|
probe(None)
|
|
539
604
|
record = {
|
|
540
605
|
"schema": ATTACHMENT_SCHEMA,
|
|
@@ -547,6 +612,13 @@ class ProjectAdopter:
|
|
|
547
612
|
write_json_atomic(marker, record)
|
|
548
613
|
config.write_text(_CONFIG_CONTENT, encoding="utf-8")
|
|
549
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
|
+
)
|
|
550
622
|
except BaseException:
|
|
551
623
|
_remove_path(staging)
|
|
552
624
|
if swapped:
|