workstate-bootstrap 0.5.2__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 (31) hide show
  1. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/CHANGELOG.md +60 -2
  2. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/PKG-INFO +10 -9
  3. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/README.md +7 -7
  4. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/pyproject.toml +8 -2
  5. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/__init__.py +1 -1
  6. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/cli.py +51 -11
  7. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/install.py +605 -126
  8. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/mcp_sync.py +3 -0
  9. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/subcommands.py +77 -44
  10. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_bootstrap_install_rehearsal.py +4 -4
  11. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_install.py +412 -54
  12. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_cli.py +57 -0
  13. workstate_bootstrap-0.7.0/tests/test_package_source.py +196 -0
  14. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_render_seam.py +1 -1
  15. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_subcommands.py +142 -26
  16. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/.gitignore +0 -0
  17. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/src/workstate_bootstrap/__main__.py +0 -0
  18. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/__init__.py +0 -0
  19. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_cli_profile.py +0 -0
  20. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_doctor_repair_sync.py +0 -0
  21. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_ensure_hooks_path_make.py +0 -0
  22. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_install_manifest_walker.py +0 -0
  23. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_install_profile_all_lifecycle.py +0 -0
  24. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_install_profiles.py +0 -0
  25. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_manifest_build.py +0 -0
  26. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_e2e.py +0 -0
  27. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_malformed.py +0 -0
  28. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_prune.py +0 -0
  29. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_mcp_sync_unit.py +0 -0
  30. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_package_metadata.py +0 -0
  31. {workstate_bootstrap-0.5.2 → workstate_bootstrap-0.7.0}/tests/test_root_visible_task_plans.py +0 -0
@@ -2,6 +2,64 @@
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
+
37
+ ## [0.6.0] — 2026-05-30
38
+
39
+ ### Changed
40
+
41
+ - **MCP server identity cutover (implementation note Slice B).** Default managed servers
42
+ register under the canonical `workstate-handoff-mcp` /
43
+ `workstate-orchestrator-mcp` names. `LEGACY_MCP_SERVER_RENAMES` +
44
+ `_legacy_prune_for()` dedup and forward-rewrite a stale `agent-*-mcp`
45
+ registration across all three config surfaces (`.mcp.json`,
46
+ `.vscode/mcp.json`, `.codex/config.toml`) so a re-install collapses the
47
+ duplicate to one canonical entry — fixing the "MCP servers not loading"
48
+ symptom caused by deep-merge preserving both old and new entries.
49
+ - **Default managed server pins bumped** to `mcp-workstate-handoff@0.12.0` and
50
+ `mcp-workstate-orchestrator@0.5.0`. `workstate-protocol` floor raised to
51
+ `>=0.1.6`.
52
+
53
+ ### Added
54
+
55
+ - **Runtime path migration `.workstate/` → `.workstate/` and
56
+ `docs/workstate/` → `docs/workstate/` (implementation note Slice D).**
57
+ `migrate_runtime_paths()` / `plan_runtime_path_migration()` run on
58
+ `install`/`update`: idempotent, archive-backed (a both-present collision
59
+ moves the legacy tree aside rather than overwriting), dry-run-capable, and
60
+ routed through the shared `workstate_protocol.paths` constants. `doctor`
61
+ flags a surviving legacy tree as `legacy_runtime_path`.
62
+
5
63
  ## [0.5.2] — 2026-05-20
6
64
 
7
65
  ### Changed
@@ -19,7 +77,7 @@
19
77
  When a consumer was installed pre-v0.2.0 (legacy root layout
20
78
  `<clone>/<surface>`) and the layout subsequently moved into
21
79
  `<clone>/packages/workstate-system/<surface>`, the target-side
22
- `scripts/hooks -> ../.agentic/remote/scripts/hooks` symlink survived
80
+ `scripts/hooks -> ../.workstate/remote/scripts/hooks` symlink survived
23
81
  every subsequent `workstate-bootstrap install` because the pre-fix
24
82
  `points_into_clone` check still passed lexically for the broken
25
83
  resolved path. `_materialize_surfaces` now classifies each existing
@@ -151,7 +209,7 @@
151
209
  post-checkout / pre-commit / pre-push hooks `exec`) is materialized
152
210
  alongside them. Without the helper, every branch-naming gate
153
211
  silently no-ops. The shared surface itself is unchanged
154
- (`scripts/hooks` is symlinked from `.agentic/remote`); the new
212
+ (`scripts/hooks` is symlinked from `.workstate/remote`); the new
155
213
  assertion catches a future regression where the upstream package
156
214
  drops the helper.
157
215
  - **Manifest renamed: `.workstate-overlay.json` → `.workstate-bootstrap.json`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workstate-bootstrap
3
- Version: 0.5.2
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.4
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'
@@ -117,20 +118,20 @@ installer implementation in
117
118
  | ------------------------------------ | ---------- | ----------- |
118
119
  | `scripts/hooks/` | shared | symlink |
119
120
  | `.github/hooks/` | shared | symlink |
120
- | `docs/agentic/contracts/` | shared | symlink |
121
- | `docs/agentic/rules/` | shared | symlink |
121
+ | `docs/workstate/contracts/` | shared | symlink |
122
+ | `docs/workstate/rules/` | shared | symlink |
122
123
  | `Makefile.d/` non-excluded children | shared | carved dir |
123
124
  | `scripts/workstate/` non-excluded children | shared | carved dir |
124
125
  | `.github/prompts/` | generated | real dir |
125
- | `.agentic/generated/plugins/workstate-system/base/` | generated | real dir |
126
- | `.agentic/generated/plugins/workstate-system/effective/` | generated | real dir |
126
+ | `.workstate/generated/plugins/workstate-system/base/` | generated | real dir |
127
+ | `.workstate/generated/plugins/workstate-system/effective/` | generated | real dir |
127
128
  | `.mcp.json` | generated | real file |
128
129
  | `.vscode/mcp.json` | generated | real file |
129
130
  | `.codex/config.toml` | generated | real file |
130
131
  | `core.hooksPath` git config | generated | git config |
131
132
  | `.task-state/handoff.db` | runtime | sqlite |
132
133
  | `.task-state/exports/` | runtime | dir |
133
- | `.agentic/remote/` | bootstrap | git clone |
134
+ | `.workstate/remote/` | bootstrap | git clone |
134
135
  | `.workstate-bootstrap.json` | bootstrap | manifest |
135
136
 
136
137
  `.task-state/` is provisioned by the handoff server's `init-state`
@@ -161,13 +162,13 @@ regenerates it through `workstate-bootstrap install`.
161
162
  `install`, `update`, `doctor`, or `repair` for a non-default root;
162
163
  bootstrap records that path so later update/doctor/repair runs reuse
163
164
  it. Override-aware installs generate effective plugin trees under
164
- `.agentic/generated/plugins/workstate-system/effective/{claude,codex}`
165
+ `.workstate/generated/plugins/workstate-system/effective/{claude,codex}`
165
166
  and point marketplace pins at those generated trees.
166
167
  - `install` and `update` preserve plugin override files by default.
167
168
  `--reset-overrides` is the explicit destructive path; it removes only
168
169
  the resolved override root, refuses dirty git worktrees unless
169
170
  `--backup` is supplied, and archives backups under
170
- `.agentic/override-backups/<timestamp>/` before removal.
171
+ `.workstate/override-backups/<timestamp>/` before removal.
171
172
 
172
173
  ## Development
173
174
 
@@ -98,20 +98,20 @@ installer implementation in
98
98
  | ------------------------------------ | ---------- | ----------- |
99
99
  | `scripts/hooks/` | shared | symlink |
100
100
  | `.github/hooks/` | shared | symlink |
101
- | `docs/agentic/contracts/` | shared | symlink |
102
- | `docs/agentic/rules/` | shared | symlink |
101
+ | `docs/workstate/contracts/` | shared | symlink |
102
+ | `docs/workstate/rules/` | shared | symlink |
103
103
  | `Makefile.d/` non-excluded children | shared | carved dir |
104
104
  | `scripts/workstate/` non-excluded children | shared | carved dir |
105
105
  | `.github/prompts/` | generated | real dir |
106
- | `.agentic/generated/plugins/workstate-system/base/` | generated | real dir |
107
- | `.agentic/generated/plugins/workstate-system/effective/` | generated | real dir |
106
+ | `.workstate/generated/plugins/workstate-system/base/` | generated | real dir |
107
+ | `.workstate/generated/plugins/workstate-system/effective/` | generated | real dir |
108
108
  | `.mcp.json` | generated | real file |
109
109
  | `.vscode/mcp.json` | generated | real file |
110
110
  | `.codex/config.toml` | generated | real file |
111
111
  | `core.hooksPath` git config | generated | git config |
112
112
  | `.task-state/handoff.db` | runtime | sqlite |
113
113
  | `.task-state/exports/` | runtime | dir |
114
- | `.agentic/remote/` | bootstrap | git clone |
114
+ | `.workstate/remote/` | bootstrap | git clone |
115
115
  | `.workstate-bootstrap.json` | bootstrap | manifest |
116
116
 
117
117
  `.task-state/` is provisioned by the handoff server's `init-state`
@@ -142,13 +142,13 @@ regenerates it through `workstate-bootstrap install`.
142
142
  `install`, `update`, `doctor`, or `repair` for a non-default root;
143
143
  bootstrap records that path so later update/doctor/repair runs reuse
144
144
  it. Override-aware installs generate effective plugin trees under
145
- `.agentic/generated/plugins/workstate-system/effective/{claude,codex}`
145
+ `.workstate/generated/plugins/workstate-system/effective/{claude,codex}`
146
146
  and point marketplace pins at those generated trees.
147
147
  - `install` and `update` preserve plugin override files by default.
148
148
  `--reset-overrides` is the explicit destructive path; it removes only
149
149
  the resolved override root, refuses dirty git worktrees unless
150
150
  `--backup` is supplied, and archives backups under
151
- `.agentic/override-backups/<timestamp>/` before removal.
151
+ `.workstate/override-backups/<timestamp>/` before removal.
152
152
 
153
153
  ## Development
154
154
 
@@ -4,13 +4,18 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "workstate-bootstrap"
7
- version = "0.5.2"
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.4,<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"]
@@ -3,4 +3,4 @@
3
3
  from workstate_bootstrap.install import install
4
4
 
5
5
  __all__ = ["install"]
6
- __version__ = "0.5.2"
6
+ __version__ = "0.6.0"
@@ -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 (
@@ -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,
@@ -151,7 +183,7 @@ def _build_parser() -> argparse.ArgumentParser:
151
183
  "--backup",
152
184
  action="store_true",
153
185
  help=(
154
- "Archive plugin overrides under .agentic/override-backups/<timestamp>/ "
186
+ "Archive plugin overrides under .workstate/override-backups/<timestamp>/ "
155
187
  "before a reset-overrides removal."
156
188
  ),
157
189
  )
@@ -303,7 +335,7 @@ def _build_parser() -> argparse.ArgumentParser:
303
335
  "--backup",
304
336
  action="store_true",
305
337
  help=(
306
- "Archive plugin overrides under .agentic/override-backups/<timestamp>/ "
338
+ "Archive plugin overrides under .workstate/override-backups/<timestamp>/ "
307
339
  "before a reset-overrides removal."
308
340
  ),
309
341
  )
@@ -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