@grifhinz/logics-manager 2.0.2 → 2.0.5

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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/AlexAgo83/logics-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/AlexAgo83/logics-manager/actions/workflows/ci.yml)
4
4
  [![License](https://img.shields.io/github/license/AlexAgo83/logics-manager)](LICENSE)
5
- ![Version](https://img.shields.io/badge/version-v2.0.2-4C8BF5)
5
+ ![Version](https://img.shields.io/badge/version-v2.0.5-4C8BF5)
6
6
  ![VS Code](https://img.shields.io/badge/VS%20Code-1.86.0-007ACC?logo=visualstudiocode&logoColor=white)
7
7
  ![TypeScript](https://img.shields.io/badge/TypeScript-5.3.3-3178C6?logo=typescript&logoColor=white)
8
8
  ![Vitest](https://img.shields.io/badge/Vitest-2.1.8-6E9F18?logo=vitest&logoColor=white)
@@ -35,6 +35,9 @@ Install the npm package with:
35
35
  npm install -g @grifhinz/logics-manager
36
36
  ```
37
37
 
38
+ To update that CLI later, run `logics-manager self-update`.
39
+ The command uses `pip` when the Python package is installed and falls back to `npm` for the global npm package.
40
+
38
41
  For the editor client, build and install the VSIX:
39
42
 
40
43
  ```bash
@@ -163,7 +166,7 @@ Windows notes:
163
166
 
164
167
  ### Install from Marketplace
165
168
 
166
- https://marketplace.visualstudio.com/items?itemName=cdx-logics.logics-manager
169
+ https://marketplace.visualstudio.com/items?itemName=cdx-logics.cdx-logics-vscode
167
170
 
168
171
  ### Install from VSIX (recommended for users)
169
172
 
@@ -267,7 +270,7 @@ Contract:
267
270
  - `Environment` can also surface direct remediation actions when the plugin detects a stale runtime, an incomplete bootstrap, a missing global publication, or missing environment placeholders.
268
271
  - `Environment` now uses a clearer hierarchy with summary, recommended actions, current status, and technical details, plus hybrid assist runtime state, backend availability, degraded reasons, Claude-bridge presence, and the shared Windows-safe runtime entrypoint.
269
272
  - `Check Environment` can be promoted into `Recommended` when the current repo state actually warrants operator attention.
270
- - repo-local refresh now watches `logics/**/*`, `logics.yaml`, and supported `.claude/` bridge files; external global runtime state still requires an explicit refresh because it lives outside the workspace.
273
+ - repo-local refresh now watches `logics/**/*`, `logics.yaml`, and `.git/HEAD`; external global runtime state still requires an explicit refresh because it lives outside the workspace.
271
274
  - `Launch Codex` starts Codex using the globally published Logics runtime when the shared runtime is healthy.
272
275
  - `AI Runtime Status` probes the shared `logics.py flow assist runtime-status` surface and reports ready providers, flagged providers, cooldown or credential issues, and bounded backend provenance.
273
276
  - `AI Provider Insights` opens a dedicated plugin panel backed by `logics.py flow assist roi-report`, with provider mix, execution-path breakdowns, derived rates, estimated ROI proxies, and recent audit drill-down over the shared runtime output.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.2
1
+ 2.0.5
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import argparse
4
4
  import json
5
+ import os
5
6
  from collections import Counter
6
7
  from datetime import datetime, timedelta, timezone
7
8
  import re
@@ -13,6 +14,7 @@ from typing import Any
13
14
  from .config import ConfigError, find_repo_root, load_repo_config
14
15
  from .doctor import doctor_payload
15
16
  from .lint import lint_payload
17
+ from .termstyle import colorize_help
16
18
 
17
19
 
18
20
  DEFAULT_HYBRID_AUDIT_LOG = "logics/.cache/hybrid_assist_audit.jsonl"
@@ -20,6 +22,7 @@ DEFAULT_HYBRID_MEASUREMENT_LOG = "logics/.cache/hybrid_assist_measurements.jsonl
20
22
  DEFAULT_HYBRID_ROI_RECENT_LIMIT = 8
21
23
  DEFAULT_HYBRID_ROI_WINDOW_DAYS = 14
22
24
  DEFAULT_ESTIMATED_REMOTE_TOKENS_PER_LOCAL_RUN = 1200
25
+ HELP_FLAGS = ("-h", "--help")
23
26
 
24
27
 
25
28
  CLAUDE_BRIDGE_VARIANTS: tuple[dict[str, object], ...] = (
@@ -1283,7 +1286,7 @@ def build_parser() -> argparse.ArgumentParser:
1283
1286
 
1284
1287
  claude_bridges = sub.add_parser(
1285
1288
  "claude-bridges",
1286
- help="Render the canonical Claude bridge files and prompts derived from the integrated runtime.",
1289
+ help="Render the canonical Claude runtime publication manifest and prompts derived from the integrated runtime.",
1287
1290
  )
1288
1291
  claude_bridges.add_argument("--format", choices=("text", "json"), default="text")
1289
1292
  claude_bridges.add_argument("--dry-run", action="store_true")
@@ -1346,10 +1349,375 @@ def build_parser() -> argparse.ArgumentParser:
1346
1349
  return parser
1347
1350
 
1348
1351
 
1349
- def _claude_bridge_status(repo_root: Path) -> dict[str, object]:
1352
+ def _build_help() -> str:
1353
+ return "\n".join(
1354
+ [
1355
+ "Logics Assist CLI",
1356
+ "Inspect runtime signals and build context bundles.",
1357
+ "",
1358
+ "Usage:",
1359
+ " logics-manager assist <command> [args...]",
1360
+ "",
1361
+ "Runtime and diagnostics:",
1362
+ " runtime-status",
1363
+ " Report local assist runtime readiness.",
1364
+ " Flags: --backend, --model-profile, --model, --ollama-host, --timeout, --format {text,json}, --out, --dry-run",
1365
+ " diff-risk",
1366
+ " Classify the current git diff using deterministic heuristics.",
1367
+ " Flags: --format {text,json}, --dry-run",
1368
+ " commit-plan",
1369
+ " Draft a minimal commit plan from the current git diff.",
1370
+ " Flags: --format {text,json}, --dry-run",
1371
+ " changed-surface-summary",
1372
+ " Summarize the current changed repository surface.",
1373
+ " Flags: --format {text,json}, --dry-run",
1374
+ "",
1375
+ "Review and governance:",
1376
+ " doc-consistency",
1377
+ " Review workflow docs for consistency issues without mutating them.",
1378
+ " Flags: --format {text,json}, --dry-run",
1379
+ " review-checklist",
1380
+ " Generate a bounded review checklist for the current change surface.",
1381
+ " Flags: --format {text,json}, --dry-run",
1382
+ " validation-checklist",
1383
+ " Generate a deterministic validation checklist from the current change surface.",
1384
+ " Flags: --format {text,json}, --dry-run",
1385
+ " validation-summary",
1386
+ " Summarize lint, doctor, and validation impact signals.",
1387
+ " Flags: --format {text,json}, --dry-run",
1388
+ " test-impact-summary",
1389
+ " Summarize the likely test impact of the current change surface.",
1390
+ " Flags: --format {text,json}, --dry-run",
1391
+ " roi-report",
1392
+ " Summarize hybrid assist ROI from local audit and measurement logs.",
1393
+ " Flags: --audit-log, --measurement-log, --recent-limit, --window-days, --format {text,json}, --out, --dry-run",
1394
+ "",
1395
+ "Context and prompts:",
1396
+ " claude-bridges",
1397
+ " Render the canonical Claude runtime publication manifest and prompts.",
1398
+ " Flags: --format {text,json}, --dry-run",
1399
+ " context <flow_name> [ref]",
1400
+ " Build a shared assist context bundle for a flow.",
1401
+ " Flags: --context-mode {summary-only,diff-first,full}, --profile {tiny,normal,deep}, --include-graph, --include-registry, --include-doctor, --format {text,json}, --out, --dry-run",
1402
+ " claude-instructions",
1403
+ " Render the canonical assistant instructions derived from the integrated runtime.",
1404
+ " Flags: --format {text,json}, --dry-run",
1405
+ " next-step [ref]",
1406
+ " Suggest the next bounded Logics step for a target doc.",
1407
+ " Flags: --format {text,json}, --dry-run",
1408
+ " request-draft",
1409
+ " Draft a bounded request doc from an intent.",
1410
+ " Flags: --intent, --format {text,json}, --execution-mode {suggestion-only,execute}, --dry-run",
1411
+ " spec-first-pass <ref>",
1412
+ " Draft a first-pass spec outline from a backlog item.",
1413
+ " Flags: --format {text,json}, --execution-mode {suggestion-only,execute}, --dry-run",
1414
+ " backlog-groom <ref>",
1415
+ " Draft a bounded backlog proposal from a request doc.",
1416
+ " Flags: --format {text,json}, --execution-mode {suggestion-only,execute}, --dry-run",
1417
+ " closure-summary [ref]",
1418
+ " Summarize a delivered request, backlog item, or task.",
1419
+ " Flags: --format {text,json}, --dry-run",
1420
+ "",
1421
+ "Examples:",
1422
+ " logics-manager assist runtime-status --format json",
1423
+ " logics-manager assist context request req_001_my_request --profile deep",
1424
+ " logics-manager assist request-draft --intent \"Improve onboarding\"",
1425
+ ]
1426
+ )
1427
+
1428
+
1429
+ def _build_command_help(command: str) -> str:
1430
+ if command == "runtime-status":
1431
+ return "\n".join(
1432
+ [
1433
+ "Logics Assist Runtime Status",
1434
+ "Report local assist runtime readiness.",
1435
+ "",
1436
+ "Usage:",
1437
+ " logics-manager assist runtime-status [args...]",
1438
+ "",
1439
+ "Flags:",
1440
+ " --backend",
1441
+ " --model-profile",
1442
+ " --model",
1443
+ " --ollama-host",
1444
+ " --timeout",
1445
+ " --format {text,json}",
1446
+ " --out",
1447
+ " --dry-run",
1448
+ ]
1449
+ )
1450
+ if command == "context":
1451
+ return "\n".join(
1452
+ [
1453
+ "Logics Assist Context",
1454
+ "Build a shared assist context bundle for a flow.",
1455
+ "",
1456
+ "Usage:",
1457
+ " logics-manager assist context <flow_name> [ref] [args...]",
1458
+ "",
1459
+ "Flags:",
1460
+ " --context-mode {summary-only,diff-first,full}",
1461
+ " --profile {tiny,normal,deep}",
1462
+ " --include-graph",
1463
+ " --include-registry",
1464
+ " --include-doctor",
1465
+ " --format {text,json}",
1466
+ " --out",
1467
+ " --dry-run",
1468
+ ]
1469
+ )
1470
+ if command == "request-draft":
1471
+ return "\n".join(
1472
+ [
1473
+ "Logics Assist Request Draft",
1474
+ "Draft a bounded request doc from an intent.",
1475
+ "",
1476
+ "Usage:",
1477
+ " logics-manager assist request-draft [args...]",
1478
+ "",
1479
+ "Flags:",
1480
+ " --intent",
1481
+ " --format {text,json}",
1482
+ " --execution-mode {suggestion-only,execute}",
1483
+ " --dry-run",
1484
+ ]
1485
+ )
1486
+ if command == "spec-first-pass":
1487
+ return "\n".join(
1488
+ [
1489
+ "Logics Assist Spec First Pass",
1490
+ "Draft a first-pass spec outline from a backlog item.",
1491
+ "",
1492
+ "Usage:",
1493
+ " logics-manager assist spec-first-pass <ref> [args...]",
1494
+ "",
1495
+ "Flags:",
1496
+ " --format {text,json}",
1497
+ " --execution-mode {suggestion-only,execute}",
1498
+ " --dry-run",
1499
+ ]
1500
+ )
1501
+ if command == "backlog-groom":
1502
+ return "\n".join(
1503
+ [
1504
+ "Logics Assist Backlog Groom",
1505
+ "Draft a bounded backlog proposal from a request doc.",
1506
+ "",
1507
+ "Usage:",
1508
+ " logics-manager assist backlog-groom <ref> [args...]",
1509
+ "",
1510
+ "Flags:",
1511
+ " --format {text,json}",
1512
+ " --execution-mode {suggestion-only,execute}",
1513
+ " --dry-run",
1514
+ ]
1515
+ )
1516
+ if command == "closure-summary":
1517
+ return "\n".join(
1518
+ [
1519
+ "Logics Assist Closure Summary",
1520
+ "Summarize a delivered request, backlog item, or task.",
1521
+ "",
1522
+ "Usage:",
1523
+ " logics-manager assist closure-summary [ref] [args...]",
1524
+ "",
1525
+ "Flags:",
1526
+ " --format {text,json}",
1527
+ " --dry-run",
1528
+ ]
1529
+ )
1530
+ if command == "roi-report":
1531
+ return "\n".join(
1532
+ [
1533
+ "Logics Assist ROI Report",
1534
+ "Summarize hybrid assist ROI from local audit and measurement logs.",
1535
+ "",
1536
+ "Usage:",
1537
+ " logics-manager assist roi-report [args...]",
1538
+ "",
1539
+ "Flags:",
1540
+ " --audit-log",
1541
+ " --measurement-log",
1542
+ " --recent-limit",
1543
+ " --window-days",
1544
+ " --format {text,json}",
1545
+ " --out",
1546
+ " --dry-run",
1547
+ ]
1548
+ )
1549
+ if command == "diff-risk":
1550
+ return "\n".join(
1551
+ [
1552
+ "Logics Assist Diff Risk",
1553
+ "Classify the current git diff using deterministic heuristics.",
1554
+ "",
1555
+ "Usage:",
1556
+ " logics-manager assist diff-risk [args...]",
1557
+ "",
1558
+ "Flags:",
1559
+ " --format {text,json}",
1560
+ " --dry-run",
1561
+ ]
1562
+ )
1563
+ if command == "commit-plan":
1564
+ return "\n".join(
1565
+ [
1566
+ "Logics Assist Commit Plan",
1567
+ "Draft a minimal commit plan from the current git diff.",
1568
+ "",
1569
+ "Usage:",
1570
+ " logics-manager assist commit-plan [args...]",
1571
+ "",
1572
+ "Flags:",
1573
+ " --format {text,json}",
1574
+ " --dry-run",
1575
+ ]
1576
+ )
1577
+ if command == "changed-surface-summary":
1578
+ return "\n".join(
1579
+ [
1580
+ "Logics Assist Changed Surface Summary",
1581
+ "Summarize the current changed repository surface.",
1582
+ "",
1583
+ "Usage:",
1584
+ " logics-manager assist changed-surface-summary [args...]",
1585
+ "",
1586
+ "Flags:",
1587
+ " --format {text,json}",
1588
+ " --dry-run",
1589
+ ]
1590
+ )
1591
+ if command == "doc-consistency":
1592
+ return "\n".join(
1593
+ [
1594
+ "Logics Assist Doc Consistency",
1595
+ "Review workflow docs for consistency issues without mutating them.",
1596
+ "",
1597
+ "Usage:",
1598
+ " logics-manager assist doc-consistency [args...]",
1599
+ "",
1600
+ "Flags:",
1601
+ " --format {text,json}",
1602
+ " --dry-run",
1603
+ ]
1604
+ )
1605
+ if command == "review-checklist":
1606
+ return "\n".join(
1607
+ [
1608
+ "Logics Assist Review Checklist",
1609
+ "Generate a bounded review checklist for the current change surface.",
1610
+ "",
1611
+ "Usage:",
1612
+ " logics-manager assist review-checklist [args...]",
1613
+ "",
1614
+ "Flags:",
1615
+ " --format {text,json}",
1616
+ " --dry-run",
1617
+ ]
1618
+ )
1619
+ if command == "validation-checklist":
1620
+ return "\n".join(
1621
+ [
1622
+ "Logics Assist Validation Checklist",
1623
+ "Generate a deterministic validation checklist from the current change surface.",
1624
+ "",
1625
+ "Usage:",
1626
+ " logics-manager assist validation-checklist [args...]",
1627
+ "",
1628
+ "Flags:",
1629
+ " --format {text,json}",
1630
+ " --dry-run",
1631
+ ]
1632
+ )
1633
+ if command == "validation-summary":
1634
+ return "\n".join(
1635
+ [
1636
+ "Logics Assist Validation Summary",
1637
+ "Summarize lint, doctor, and validation impact signals.",
1638
+ "",
1639
+ "Usage:",
1640
+ " logics-manager assist validation-summary [args...]",
1641
+ "",
1642
+ "Flags:",
1643
+ " --format {text,json}",
1644
+ " --dry-run",
1645
+ ]
1646
+ )
1647
+ if command == "test-impact-summary":
1648
+ return "\n".join(
1649
+ [
1650
+ "Logics Assist Test Impact Summary",
1651
+ "Summarize the likely test impact of the current change surface.",
1652
+ "",
1653
+ "Usage:",
1654
+ " logics-manager assist test-impact-summary [args...]",
1655
+ "",
1656
+ "Flags:",
1657
+ " --format {text,json}",
1658
+ " --dry-run",
1659
+ ]
1660
+ )
1661
+ if command == "claude-bridges":
1662
+ return "\n".join(
1663
+ [
1664
+ "Logics Assist Claude Bridges",
1665
+ "Render the canonical Claude runtime publication manifest and prompts.",
1666
+ "",
1667
+ "Usage:",
1668
+ " logics-manager assist claude-bridges [args...]",
1669
+ "",
1670
+ "Flags:",
1671
+ " --format {text,json}",
1672
+ " --dry-run",
1673
+ ]
1674
+ )
1675
+ if command == "claude-instructions":
1676
+ return "\n".join(
1677
+ [
1678
+ "Logics Assist Claude Instructions",
1679
+ "Render the canonical assistant instructions derived from the integrated runtime.",
1680
+ "",
1681
+ "Usage:",
1682
+ " logics-manager assist claude-instructions [args...]",
1683
+ "",
1684
+ "Flags:",
1685
+ " --format {text,json}",
1686
+ " --dry-run",
1687
+ ]
1688
+ )
1689
+ if command == "next-step":
1690
+ return "\n".join(
1691
+ [
1692
+ "Logics Assist Next Step",
1693
+ "Suggest the next bounded Logics step for a target doc.",
1694
+ "",
1695
+ "Usage:",
1696
+ " logics-manager assist next-step [ref] [args...]",
1697
+ "",
1698
+ "Flags:",
1699
+ " --format {text,json}",
1700
+ " --dry-run",
1701
+ ]
1702
+ )
1703
+ return _build_help()
1704
+
1705
+
1706
+ def _print_help(text: str) -> None:
1707
+ print(colorize_help(text))
1708
+
1709
+
1710
+ def _get_global_claude_home() -> Path:
1711
+ return Path(os.environ.get("LOGICS_CLAUDE_GLOBAL_HOME") or (Path.home() / ".claude")).resolve()
1712
+
1713
+
1714
+ def _claude_bridge_status(_repo_root: Path) -> dict[str, object]:
1715
+ global_home = _get_global_claude_home()
1350
1716
  detected_variants: list[str] = []
1351
1717
  for variant in CLAUDE_BRIDGE_VARIANTS:
1352
- if (repo_root / variant["command_path"]).is_file() and (repo_root / variant["agent_path"]).is_file():
1718
+ command_path = global_home / str(variant["command_path"]).replace(".claude/", "")
1719
+ agent_path = global_home / str(variant["agent_path"]).replace(".claude/", "")
1720
+ if command_path.is_file() and agent_path.is_file():
1353
1721
  detected_variants.append(variant["id"])
1354
1722
  return {
1355
1723
  "available": bool(detected_variants),
@@ -1368,7 +1736,7 @@ def _render_claude_bridge_lines(variant: dict[str, object], prompt: str) -> tupl
1368
1736
  command_lines = [
1369
1737
  f"# {title}",
1370
1738
  "",
1371
- f"Use the repository-local {title.lower()} bridge for this project.",
1739
+ f"Use the published global {title.lower()} bridge for this project.",
1372
1740
  "",
1373
1741
  "Primary prompt:",
1374
1742
  prompt,
@@ -1377,7 +1745,7 @@ def _render_claude_bridge_lines(variant: dict[str, object], prompt: str) -> tupl
1377
1745
  agent_lines = [
1378
1746
  f"# {title} Agent",
1379
1747
  "",
1380
- f"Use the repository-local {title.lower()} agent for this project.",
1748
+ f"Use the published global {title.lower()} agent for this project.",
1381
1749
  "",
1382
1750
  "Default prompt:",
1383
1751
  prompt,
@@ -1433,8 +1801,8 @@ def _build_claude_instructions(repo_root: Path) -> dict[str, object]:
1433
1801
  "- `python3 -m logics_manager lint --require-status`",
1434
1802
  "- `python3 -m logics_manager audit --legacy-cutoff-version 1.1.0 --group-by-doc`",
1435
1803
  "",
1436
- "Repository-local Claude bridge files and assistant instructions are generated from the integrated runtime.",
1437
- "Do not edit `.claude/` bridge files by hand unless you are deliberately repairing a generated artifact.",
1804
+ "Claude runtime artifacts are generated outside the repository from the integrated runtime.",
1805
+ "Do not edit generated runtime artifacts by hand unless you are deliberately repairing a generated artifact.",
1438
1806
  "",
1439
1807
  "Do not edit indicator lines or workflow links by hand.",
1440
1808
  "",
@@ -1454,8 +1822,8 @@ def _select_backend(requested_backend: str | None, bridge_status: dict[str, obje
1454
1822
  if requested_backend and requested_backend != "auto":
1455
1823
  return requested_backend, []
1456
1824
  if bridge_status.get("available"):
1457
- return "codex", ["claude bridge files detected"]
1458
- return "deterministic", ["no bridge files detected"]
1825
+ return "codex", ["global Claude runtime published"]
1826
+ return "deterministic", ["no global Claude runtime published"]
1459
1827
 
1460
1828
 
1461
1829
  def cmd_claude_bridges(args: argparse.Namespace) -> dict[str, object]:
@@ -1953,9 +2321,9 @@ def cmd_runtime_status(args: argparse.Namespace) -> dict[str, object]:
1953
2321
  print(f"- selected backend: {selected_backend}")
1954
2322
  print(f"- model profile: {default_profile}")
1955
2323
  print(f"- model: {resolved_model}")
1956
- print(f"- bridge available: {'yes' if bridge_status['available'] else 'no'}")
2324
+ print(f"- global Claude runtime available: {'yes' if bridge_status['available'] else 'no'}")
1957
2325
  if bridge_status["preferred_variant"]:
1958
- print(f"- bridge variant: {bridge_status['preferred_variant']}")
2326
+ print(f"- runtime variant: {bridge_status['preferred_variant']}")
1959
2327
  return payload
1960
2328
 
1961
2329
 
@@ -2200,11 +2568,17 @@ def cmd_context(args: argparse.Namespace) -> dict[str, object]:
2200
2568
  print(f"- ref: {args.ref or '<flow-default>'}")
2201
2569
  print(f"- mode: {context_mode}")
2202
2570
  print(f"- profile: {profile}")
2203
- print(f"- bridge available: {'yes' if bridge_status['available'] else 'no'}")
2571
+ print(f"- global Claude runtime available: {'yes' if bridge_status['available'] else 'no'}")
2204
2572
  return payload
2205
2573
 
2206
2574
 
2207
2575
  def main(argv: list[str]) -> int:
2576
+ if not argv or argv[0] in HELP_FLAGS:
2577
+ _print_help(_build_help())
2578
+ return 0
2579
+ if argv[0] in {"runtime-status", "context", "request-draft", "spec-first-pass", "backlog-groom", "closure-summary", "roi-report", "diff-risk", "commit-plan", "changed-surface-summary", "doc-consistency", "review-checklist", "validation-checklist", "validation-summary", "test-impact-summary", "claude-bridges", "claude-instructions", "next-step"} and len(argv) > 1 and argv[1] in HELP_FLAGS:
2580
+ _print_help(_build_command_help(argv[0]))
2581
+ return 0
2208
2582
  parser = build_parser()
2209
2583
  args = parser.parse_args(argv)
2210
2584
  payload = args.func(args)
@@ -1,9 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ import shutil
4
5
  from pathlib import Path
5
6
 
6
- from .assist import _build_claude_bridge_manifest, _build_claude_instructions
7
+ from .assist import _build_claude_instructions
7
8
 
8
9
 
9
10
  WORKFLOW_DIRS: tuple[str, ...] = ("request", "backlog", "tasks", "specs", "product", "architecture", "external", ".cache")
@@ -13,14 +14,34 @@ def _workflow_directories(repo_root: Path) -> list[Path]:
13
14
  return [repo_root / "logics" / name for name in WORKFLOW_DIRS]
14
15
 
15
16
 
17
+ def _legacy_runtime_paths(repo_root: Path) -> list[Path]:
18
+ return [repo_root / ".claude", repo_root / "logics" / "skills"]
19
+
20
+
21
+ def _remove_legacy_runtime_paths(repo_root: Path, *, check: bool) -> list[str]:
22
+ removed_paths: list[str] = []
23
+ for target in _legacy_runtime_paths(repo_root):
24
+ if not target.exists():
25
+ continue
26
+ removed_paths.append(target.relative_to(repo_root).as_posix() + ("/" if target.is_dir() else ""))
27
+ if not check:
28
+ if target.is_dir():
29
+ shutil.rmtree(target)
30
+ else:
31
+ target.unlink()
32
+ return removed_paths
33
+
34
+
16
35
  def bootstrap_payload(repo_root: Path, *, check: bool) -> dict[str, object]:
17
36
  logics_root = repo_root / "logics"
18
- bridge_manifest = _build_claude_bridge_manifest(repo_root)
19
37
  instructions_manifest = _build_claude_instructions(repo_root)
20
38
  directory_actions: list[dict[str, object]] = []
21
39
  created_paths: list[str] = []
40
+ removed_paths: list[str] = []
22
41
  missing_paths: list[str] = []
23
42
 
43
+ removed_paths.extend(_remove_legacy_runtime_paths(repo_root, check=check))
44
+
24
45
  if not logics_root.exists():
25
46
  missing_paths.append("logics/")
26
47
  elif not logics_root.is_dir():
@@ -71,24 +92,6 @@ def bootstrap_payload(repo_root: Path, *, check: bool) -> dict[str, object]:
71
92
  instructions_path.write_text(instructions_content, encoding="utf-8")
72
93
  created_paths.append("logics/instructions.md")
73
94
 
74
- for bridge in bridge_manifest["bridges"]:
75
- for rel_path, content in (
76
- (str(bridge["command_path"]), str(bridge["command_content"])),
77
- (str(bridge["agent_path"]), str(bridge["agent_content"])),
78
- ):
79
- bridge_path = repo_root / rel_path
80
- if bridge_path.exists():
81
- try:
82
- if bridge_path.read_text(encoding="utf-8") == content:
83
- continue
84
- except Exception:
85
- pass
86
- missing_paths.append(rel_path)
87
- if not check:
88
- bridge_path.parent.mkdir(parents=True, exist_ok=True)
89
- bridge_path.write_text(content, encoding="utf-8")
90
- created_paths.append(rel_path)
91
-
92
95
  ok = not missing_paths if check else True
93
96
  return {
94
97
  "command": "bootstrap",
@@ -97,8 +100,8 @@ def bootstrap_payload(repo_root: Path, *, check: bool) -> dict[str, object]:
97
100
  "ok": ok,
98
101
  "missing_paths": missing_paths,
99
102
  "created_paths": created_paths,
103
+ "removed_paths": removed_paths,
100
104
  "directory_actions": directory_actions,
101
- "claude_bridge_count": bridge_manifest["bridge_count"],
102
105
  "claude_instruction_line_count": instructions_manifest["line_count"],
103
106
  }
104
107
 
@@ -114,6 +117,10 @@ def render_bootstrap(payload: dict[str, object], *, output_format: str) -> str:
114
117
  lines.append(f"- missing: {path}")
115
118
  return "\n".join(lines)
116
119
  lines = ["Bootstrap: OK"]
120
+ if payload.get("removed_paths"):
121
+ lines.append("- removed:")
122
+ for path in payload["removed_paths"]:
123
+ lines.append(f" - {path}")
117
124
  if payload["created_paths"]:
118
125
  lines.append("- created:")
119
126
  for path in payload["created_paths"]: