workstate-bootstrap 0.6.0__tar.gz → 0.7.0__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.
Files changed (39) hide show
  1. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/CHANGELOG.md +52 -20
  2. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/PKG-INFO +3 -2
  3. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/pyproject.toml +8 -2
  4. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/cli.py +53 -13
  5. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/install.py +526 -243
  6. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/mcp_sync.py +2 -4
  7. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/subcommands.py +79 -83
  8. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_bootstrap_install_rehearsal.py +15 -15
  9. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_cli_profile.py +5 -5
  10. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_doctor_repair_sync.py +3 -3
  11. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_ensure_hooks_path_make.py +1 -1
  12. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_install.py +343 -30
  13. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_install_manifest_walker.py +2 -2
  14. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_install_profile_all_lifecycle.py +2 -2
  15. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_install_profiles.py +5 -5
  16. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_manifest_build.py +1 -1
  17. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_cli.py +59 -2
  18. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_e2e.py +2 -2
  19. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_malformed.py +1 -1
  20. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_prune.py +1 -1
  21. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_unit.py +1 -1
  22. workstate_bootstrap-0.7.0/tests/test_package_source.py +196 -0
  23. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_render_seam.py +1 -1
  24. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_root_visible_task_plans.py +2 -2
  25. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_subcommands.py +123 -7
  26. workstate_bootstrap-0.6.0/docs/tasks/AHMCP-48-skills-imply-lifecycle-hoist-task-plan.md +0 -263
  27. workstate_bootstrap-0.6.0/docs/tasks/AHMCP-49-managed-server-versions-constant-task-plan.md +0 -186
  28. workstate_bootstrap-0.6.0/docs/tasks/AHMCP-50-mcp-sync-config-only-subcommand-task-plan.md +0 -246
  29. workstate_bootstrap-0.6.0/docs/tasks/AHMCP-56-cross-harness-install-manifest-task-plan.md +0 -355
  30. workstate_bootstrap-0.6.0/docs/tasks/AHMCP-57-stale-symlink-repoint-task-plan.md +0 -274
  31. workstate_bootstrap-0.6.0/tests/test_mcp_legacy_rename.py +0 -375
  32. workstate_bootstrap-0.6.0/tests/test_runtime_path_migration.py +0 -269
  33. workstate_bootstrap-0.6.0/uv.lock +0 -1754
  34. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/.gitignore +0 -0
  35. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/README.md +0 -0
  36. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/__init__.py +0 -0
  37. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/__main__.py +0 -0
  38. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/__init__.py +0 -0
  39. {workstate_bootstrap-0.6.0 → workstate_bootstrap-0.7.0}/tests/test_package_metadata.py +0 -0
@@ -2,11 +2,43 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## [0.7.0] — 2026-06-01
6
+
7
+ ### Added
8
+
9
+ - **Package-source overlay delivery (WS-PKG-DELIVERY-01).** `install` /
10
+ `update` can resolve the harness overlay from an installed
11
+ `workstate-system` distribution (`source_kind="package"`) instead of a git
12
+ clone, writing a `package`-kind `BootstrapManifest`. `update` / `repair`
13
+ reject a package-source manifest with a clear error rather than
14
+ dereferencing a `remote_url` that package manifests do not carry.
15
+
16
+ ### Changed
17
+
18
+ - **MCP launch decoupled from resolution (implementation note Theme A,
19
+ WS-MCP-LAUNCH-01).** Generated serve commands now use `uv run --no-sync`
20
+ and the server venvs are pre-built at install time
21
+ (`_presync_local_mcp_envs`), eliminating the cold-start re-sync race that
22
+ overran the harness's 30s MCP connection timeout and registered zero tools.
23
+ The `--no-sync` invariant is enforced at the shared render seam
24
+ (`_canonicalize_managed_servers`), so `install` / `update` / `repair` /
25
+ `mcp-sync` all rewrite an older launcher; the earlier preserve-path
26
+ `_normalize_local_mcp_server_specs` patch is retired.
27
+
28
+ ### Removed
29
+
30
+ - **Runtime-path migration shim retired (implementation note Slice D cutover complete).**
31
+ The legacy-runtime-tree migration helpers (`migrate_runtime_paths()`,
32
+ `plan_runtime_path_migration()`) and the `legacy_runtime_path` `doctor` check
33
+ are removed. `.workstate/` / `docs/workstate/` are the sole runtime paths with
34
+ no backward compatibility — a consumer still carrying the pre-rebrand runtime
35
+ tree must reinstall cleanly.
36
+
5
37
  ## [0.6.0] — 2026-05-30
6
38
 
7
39
  ### Changed
8
40
 
9
- - **MCP server identity cutover (Plan 0013 Slice B).** Default managed servers
41
+ - **MCP server identity cutover (implementation note Slice B).** Default managed servers
10
42
  register under the canonical `workstate-handoff-mcp` /
11
43
  `workstate-orchestrator-mcp` names. `LEGACY_MCP_SERVER_RENAMES` +
12
44
  `_legacy_prune_for()` dedup and forward-rewrite a stale `agent-*-mcp`
@@ -20,8 +52,8 @@
20
52
 
21
53
  ### Added
22
54
 
23
- - **Runtime path migration `.agentic/` → `.workstate/` and
24
- `docs/agentic/` → `docs/workstate/` (Plan 0013 Slice D).**
55
+ - **Runtime path migration `.workstate/` → `.workstate/` and
56
+ `docs/workstate/` → `docs/workstate/` (implementation note Slice D).**
25
57
  `migrate_runtime_paths()` / `plan_runtime_path_migration()` run on
26
58
  `install`/`update`: idempotent, archive-backed (a both-present collision
27
59
  moves the legacy tree aside rather than overwriting), dry-run-capable, and
@@ -41,11 +73,11 @@
41
73
 
42
74
  ### Fixed
43
75
 
44
- - **AHMCP-57 — stale shared-surface symlinks now repointed on rerun.**
76
+ - **WORKSTATE-REF-57 — stale shared-surface symlinks now repointed on rerun.**
45
77
  When a consumer was installed pre-v0.2.0 (legacy root layout
46
78
  `<clone>/<surface>`) and the layout subsequently moved into
47
79
  `<clone>/packages/workstate-system/<surface>`, the target-side
48
- `scripts/hooks -> ../.agentic/remote/scripts/hooks` symlink survived
80
+ `scripts/hooks -> ../.workstate/remote/scripts/hooks` symlink survived
49
81
  every subsequent `workstate-bootstrap install` because the pre-fix
50
82
  `points_into_clone` check still passed lexically for the broken
51
83
  resolved path. `_materialize_surfaces` now classifies each existing
@@ -61,7 +93,7 @@
61
93
 
62
94
  ### Changed
63
95
 
64
- - **AHMCP-56 — cross-harness install manifest is now the single source of
96
+ - **WORKSTATE-REF-56 — cross-harness install manifest is now the single source of
65
97
  truth for hook adapter wiring.** `config/agent-workflows/portable_commands.json`
66
98
  schema v2 introduces a top-level `hooks[]` array; install dispatches
67
99
  adapter rows through a manifest-driven walker (closed-set operation
@@ -99,17 +131,17 @@
99
131
 
100
132
  - **Bump default managed MCP server pins** to `mcp-workstate-handoff@0.11.1`
101
133
  and `mcp-workstate-orchestrator@0.4.5` so consumer repos pick up the
102
- AHMCP-54 (multi-active CURRENT_TASK projection, import/export
134
+ WORKSTATE-REF-54 (multi-active CURRENT_TASK projection, import/export
103
135
  malformed-payload rejection, target_branch/worktree_path/plan_path
104
- preservation) and AHMCP-55 (compaction env-var namespace
105
- consolidation under `AGENT_HANDOFF_COMPACTION_*` with `AHMCP_*` kept
136
+ preservation) and WORKSTATE-REF-55 (compaction env-var namespace
137
+ consolidation under `AGENT_HANDOFF_COMPACTION_*` with `WORKSTATE_*` kept
106
138
  as a deprecated alias) fixes by default.
107
139
 
108
140
  ## [0.4.1] — 2026-05-09
109
141
 
110
142
  ### Fixed
111
143
 
112
- - **`--profile all` now performs the lifecycle hoist** (AHMCP-48). The
144
+ - **`--profile all` now performs the lifecycle hoist** (WORKSTATE-REF-48). The
113
145
  legacy default profile shipped lifecycle-referencing skills
114
146
  (`branch-lifecycle`, `tdd`, `incremental-implementation`,
115
147
  `branch-review`, `handoff-lifecycle`) but did not install the
@@ -142,11 +174,11 @@
142
174
  ### Added
143
175
 
144
176
  - **Install profile contract: `--profile {minimal,lifecycle,all}`**
145
- (Plan 0009 / AHMCP-40 Slice 1.5.a). The CLI now accepts an explicit
177
+ (implementation note / WORKSTATE-REF-40 implementation note.5.a). The CLI now accepts an explicit
146
178
  install profile flag and honors it across the manifest layers, so
147
179
  consumer repos can pick a smaller hoist surface than the default.
148
- - **Hoist `Makefile.d/plans.mk` + `git-plan-cat.sh` stub** (Plan 0007 /
149
- AHMCP-38 Slice 0). Consumer repos installed via `workstate-bootstrap`
180
+ - **Hoist `Makefile.d/plans.mk` + `git-plan-cat.sh` stub** (implementation note /
181
+ WORKSTATE-REF-38 implementation note). Consumer repos installed via `workstate-bootstrap`
150
182
  pick up `make plan-show / plan-edit / plans-list / plan-register`
151
183
  out of the box; the targets shell out to `uvx mcp-workstate-handoff`
152
184
  under the hood.
@@ -160,14 +192,14 @@
160
192
 
161
193
  ## [0.3.1] — 2026-05-03
162
194
 
163
- - **Plan 0006 BR-01 — raise `workstate-protocol` lower bound to
195
+ - **implementation note BR-01 — raise `workstate-protocol` lower bound to
164
196
  `>=0.1.2,<0.2.0`.** Bootstrap's default install path invokes
165
197
  `uvx mcp-workstate-handoff`, which imports `workstate_protocol.branch_naming`
166
198
  at startup; the previous `>=0.1.0` floor let `uvx` resolve a protocol
167
199
  release missing the module, crashing init-state on a fresh install. A
168
200
  new packaging test (`tests/test_package_metadata.py`) pins the floor
169
201
  so the declaration cannot silently drift back below the contract.
170
- - **Plan 0006 Slice 5 — install rehearsal pins six-hook surface +
202
+ - **implementation note implementation note — install rehearsal pins six-hook surface +
171
203
  helper materialization.** `SHARED_GIT_HOOK_NAMES` now includes
172
204
  `pre-commit` (in addition to `post-checkout`, `post-commit`,
173
205
  `post-merge`, `post-rewrite`, `pre-push`); the install rehearsal
@@ -177,7 +209,7 @@
177
209
  post-checkout / pre-commit / pre-push hooks `exec`) is materialized
178
210
  alongside them. Without the helper, every branch-naming gate
179
211
  silently no-ops. The shared surface itself is unchanged
180
- (`scripts/hooks` is symlinked from `.agentic/remote`); the new
212
+ (`scripts/hooks` is symlinked from `.workstate/remote`); the new
181
213
  assertion catches a future regression where the upstream package
182
214
  drops the helper.
183
215
  - **Manifest renamed: `.workstate-overlay.json` → `.workstate-bootstrap.json`
@@ -195,7 +227,7 @@
195
227
  --workspace-root . serve-stdio` into `.mcp.json`,
196
228
  `.vscode/mcp.json`, and `.codex/config.toml`, so external clients
197
229
  start runnable MCP servers from a fresh install or update.
198
- - **`regenerate-task-views` harness hook contract dropped (Plan 0005).**
230
+ - **`regenerate-task-views` harness hook contract dropped (implementation note).**
199
231
  Bootstrap no longer materializes any Claude / VS Code / Codex hook
200
232
  wiring that invokes `regenerate-task-views`; `DASHBOARD.txt` is now
201
233
  auto-regenerated server-side inside `mcp-workstate-handoff` on every
@@ -208,7 +240,7 @@
208
240
 
209
241
  ## 0.3.0 — 2026-04-28
210
242
 
211
- - **Install-time state provisioning (Plan 0003).** `install` now runs
243
+ - **Install-time state provisioning (implementation note).** `install` now runs
212
244
  the handoff server's `init-state` after surface/config materialization
213
245
  but before `core.hooksPath` is set, so a fresh install ends with a
214
246
  schema-current `.task-state/handoff.db` and `.task-state/exports/`
@@ -232,7 +264,7 @@
232
264
  gated on `.mcp.json` being present in the manifest's `configs` array
233
265
  so config-only installs (`--no-mcp-servers`) do not produce
234
266
  false-positive drift.
235
- - **`switch_task` cold-start fix.** Plan 0003 Slice 1 (in
267
+ - **`switch_task` cold-start fix.** implementation note implementation note (in
236
268
  `mcp-workstate-handoff` 0.5.0+) drops `BranchMismatchError` from
237
269
  `switch_task`; the cold-start cycle (register task → `switch_task`
238
270
  → first content write) now completes from any branch. Branch
@@ -255,7 +287,7 @@
255
287
  `packages/workstate-system/` (the workstate monorepo layout) with
256
288
  fallback to the clone root for legacy hoisted overlays. Fixes
257
289
  `BootstrapManifestValidationError: required surface 'scripts/hooks' was
258
- not materialized` against monorepo refs at or after Plan 0002 step 1.
290
+ not materialized` against monorepo refs at or after implementation note step 1.
259
291
  - Rehearsal fixture (`fake_remote_with_generator`) now mirrors the real
260
292
  monorepo layout so this regression cannot return silently.
261
293
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workstate-bootstrap
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Bootstrap CLI that hoists the shared workstate-system surface into consumer repos.
5
5
  Project-URL: Homepage, https://github.com/darce/workstate
6
6
  Project-URL: Source, https://github.com/darce/workstate/tree/main/packages/workstate-bootstrap
@@ -11,7 +11,8 @@ License: Proprietary
11
11
  Requires-Python: >=3.11
12
12
  Requires-Dist: pyyaml>=6
13
13
  Requires-Dist: tomlkit>=0.13
14
- Requires-Dist: workstate-protocol<0.2.0,>=0.1.6
14
+ Requires-Dist: workstate-protocol<0.2.0,>=0.1.7
15
+ Requires-Dist: workstate-system<0.2.0,>=0.1.0
15
16
  Provides-Extra: dev
16
17
  Requires-Dist: mcp-workstate-handoff; (python_version >= '3.12') and extra == 'dev'
17
18
  Requires-Dist: pytest>=8; extra == 'dev'
@@ -4,13 +4,18 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "workstate-bootstrap"
7
- version = "0.6.0"
7
+ version = "0.7.0"
8
8
  description = "Bootstrap CLI that hoists the shared workstate-system surface into consumer repos."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
11
11
  license = { text = "Proprietary" }
12
12
  authors = [{ name = "darce" }]
13
- dependencies = ["tomlkit>=0.13", "pyyaml>=6", "workstate-protocol>=0.1.6,<0.2.0"]
13
+ dependencies = [
14
+ "tomlkit>=0.13",
15
+ "pyyaml>=6",
16
+ "workstate-protocol>=0.1.7,<0.2.0",
17
+ "workstate-system>=0.1.0,<0.2.0",
18
+ ]
14
19
 
15
20
  [project.scripts]
16
21
  workstate-bootstrap = "workstate_bootstrap.cli:main"
@@ -27,6 +32,7 @@ dev = ["pytest>=8", "mcp-workstate-handoff; python_version >= '3.12'"]
27
32
  [tool.uv.sources]
28
33
  mcp-workstate-handoff = { path = "../mcp-workstate-handoff", editable = true }
29
34
  workstate-protocol = { path = "../workstate-protocol", editable = true }
35
+ workstate-system = { path = "../workstate-system", editable = true }
30
36
 
31
37
  [tool.hatch.build.targets.wheel]
32
38
  packages = ["src/workstate_bootstrap"]
@@ -13,6 +13,7 @@ from workstate_bootstrap.install import (
13
13
  PROFILE_ALL,
14
14
  PROFILE_LIFECYCLE,
15
15
  PROFILE_MINIMAL,
16
+ _build_local_default_mcp_servers,
16
17
  install,
17
18
  )
18
19
  from workstate_bootstrap.mcp_sync import (
@@ -23,11 +24,11 @@ from workstate_bootstrap.mcp_sync import (
23
24
  )
24
25
  from workstate_bootstrap.subcommands import doctor, repair, status, update
25
26
 
26
- # Plan 0009: CLI default flips to ``minimal``. The library
27
+ # implementation note: CLI default flips to ``minimal``. The library
27
28
  # ``install()`` API keeps ``profile="all"`` for back-compat with
28
29
  # pre-Plan-0009 callers.
29
30
  INSTALL_PROFILE_CHOICES: tuple[str, ...] = (PROFILE_MINIMAL, PROFILE_LIFECYCLE, PROFILE_ALL)
30
- # AHMCP-56 Slice 3: flipped from PROFILE_MINIMAL back to PROFILE_ALL so
31
+ # WORKSTATE-REF-56 implementation note: flipped from PROFILE_MINIMAL back to PROFILE_ALL so
31
32
  # a no-argument ``workstate-bootstrap install`` materializes the full
32
33
  # surface set out of the box. ``--profile minimal`` and
33
34
  # ``--profile lifecycle`` remain opt-in for lean installs.
@@ -45,7 +46,7 @@ def _resolve_mcp_servers(
45
46
  - ``no_servers=True``: explicit opt-out → ``None`` (no config files written).
46
47
  - ``raw is None``: behavior depends on ``default_when_unset``. ``install``
47
48
  passes ``True`` so an unset flag falls back to :data:`DEFAULT_MCP_SERVERS`
48
- (Plan 0002 step 2a — single-command, no-hand-edits install). ``doctor`` /
49
+ (implementation note step 2a — single-command, no-hand-edits install). ``doctor`` /
49
50
  ``update`` / ``repair`` pass ``False`` so an unset flag means
50
51
  "don't check / refresh configs at all".
51
52
  - ``raw == "default"``: use :data:`DEFAULT_MCP_SERVERS`.
@@ -64,8 +65,29 @@ def _resolve_mcp_servers(
64
65
  return doc
65
66
 
66
67
 
68
+ def _resolve_managed_servers(
69
+ target: Path, raw: str | None
70
+ ) -> Mapping[str, Mapping[str, Any]] | None:
71
+ """Resolve ``--mcp-servers``, making ``default`` profile-aware.
72
+
73
+ On a ``git_overlay`` install with local MCP packages, ``default`` resolves
74
+ the LOCAL ``uv run --no-sync --project ...`` launchers (via
75
+ :func:`_build_local_default_mcp_servers`) instead of the uvx package map, so
76
+ ``mcp-sync`` and ``repair`` converge on the same launchers as
77
+ ``install``/``update`` and never silently downgrade a local install. Falls
78
+ back to the uvx map when no local packages are present. implementation note A1.
79
+ """
80
+ servers = _resolve_mcp_servers(raw)
81
+ if raw == "default":
82
+ local = _build_local_default_mcp_servers(target)
83
+ if local is not None:
84
+ return local
85
+ return servers
86
+
87
+
67
88
  DEFAULT_REMOTE_URL = "git@github.com:darce/workstate.git"
68
89
  DEFAULT_REMOTE_REF = "main"
90
+ INSTALL_SOURCE_CHOICES: tuple[str, ...] = ("git_overlay", "package")
69
91
 
70
92
 
71
93
  def _build_parser() -> argparse.ArgumentParser:
@@ -80,7 +102,7 @@ def _build_parser() -> argparse.ArgumentParser:
80
102
 
81
103
  p_install = sub.add_parser(
82
104
  "install",
83
- help="Clone the shared workstate-system remote and write the overlay manifest.",
105
+ help="Materialize the shared workstate-system overlay and write the manifest.",
84
106
  )
85
107
  p_install.add_argument(
86
108
  "--target",
@@ -98,6 +120,16 @@ def _build_parser() -> argparse.ArgumentParser:
98
120
  default=DEFAULT_REMOTE_REF,
99
121
  help=f"Tag or branch to check out (default: {DEFAULT_REMOTE_REF}).",
100
122
  )
123
+ p_install.add_argument(
124
+ "--source",
125
+ choices=INSTALL_SOURCE_CHOICES,
126
+ default="git_overlay",
127
+ help=(
128
+ "Overlay source. 'git_overlay' keeps the existing clone-backed "
129
+ "default; 'package' resolves payload data from the installed "
130
+ "workstate-system distribution."
131
+ ),
132
+ )
101
133
  p_install.add_argument(
102
134
  "--mcp-servers",
103
135
  default=None,
@@ -160,7 +192,7 @@ def _build_parser() -> argparse.ArgumentParser:
160
192
  choices=INSTALL_PROFILE_CHOICES,
161
193
  default=INSTALL_PROFILE_DEFAULT,
162
194
  help=(
163
- "Install profile. 'all' (default, AHMCP-56 Slice 3) materializes "
195
+ "Install profile. 'all' (default, WORKSTATE-REF-56 implementation note) materializes "
164
196
  "per-agent surfaces, runs the workflow generator, writes MCP "
165
197
  "config surfaces, and performs the lifecycle hoist. 'minimal' "
166
198
  "clones the remote, writes the manifest, and sets core.hooksPath "
@@ -439,6 +471,7 @@ def main(argv: list[str] | None = None) -> int:
439
471
  target=args.target,
440
472
  remote_url=args.remote_url,
441
473
  remote_ref=args.remote_ref,
474
+ source=args.source,
442
475
  mcp_servers=_resolve_mcp_servers(
443
476
  args.mcp_servers,
444
477
  no_servers=args.no_mcp_servers,
@@ -454,11 +487,18 @@ def main(argv: list[str] | None = None) -> int:
454
487
  install_codex_stop_hook=args.install_codex_stop_hook,
455
488
  install_vscode_stop_hook=args.install_vscode_stop_hook,
456
489
  )
457
- print(
458
- f"installed workstate-system overlay: "
459
- f"{args.remote_url}@{manifest['remote_sha']} -> {args.target}",
460
- file=sys.stdout,
461
- )
490
+ if manifest.get("source_kind") == "package":
491
+ print(
492
+ f"installed workstate-system overlay: "
493
+ f"workstate-system=={manifest['package_version']} -> {args.target}",
494
+ file=sys.stdout,
495
+ )
496
+ else:
497
+ print(
498
+ f"installed workstate-system overlay: "
499
+ f"{args.remote_url}@{manifest['remote_sha']} -> {args.target}",
500
+ file=sys.stdout,
501
+ )
462
502
  if isinstance(manifest.get("override_backup_path"), str):
463
503
  print(f"override backup: {manifest['override_backup_path']}", file=sys.stdout)
464
504
  if isinstance(manifest.get("state_backup_path"), str):
@@ -503,7 +543,7 @@ def main(argv: list[str] | None = None) -> int:
503
543
  backup_overrides=args.backup,
504
544
  enforce_required_surfaces=not args.no_enforce_required_surfaces,
505
545
  )
506
- except FileNotFoundError as exc:
546
+ except (FileNotFoundError, ValueError) as exc:
507
547
  print(str(exc), file=sys.stderr)
508
548
  return 1
509
549
  print(
@@ -520,7 +560,7 @@ def main(argv: list[str] | None = None) -> int:
520
560
  report = repair(
521
561
  target=args.target,
522
562
  force_dirty=args.force_dirty,
523
- mcp_servers=_resolve_mcp_servers(args.mcp_servers),
563
+ mcp_servers=_resolve_managed_servers(args.target, args.mcp_servers),
524
564
  plugin_overrides=args.plugin_overrides,
525
565
  )
526
566
  except FileNotFoundError as exc:
@@ -540,7 +580,7 @@ def main(argv: list[str] | None = None) -> int:
540
580
 
541
581
  if args.command == "mcp-sync":
542
582
  try:
543
- servers = _resolve_mcp_servers(args.mcp_servers)
583
+ servers = _resolve_managed_servers(args.target, args.mcp_servers)
544
584
  except (FileNotFoundError, json.JSONDecodeError) as exc:
545
585
  print(f"mcp-sync: --mcp-servers: {exc}", file=sys.stderr)
546
586
  return 2