fusion-cli 1.1.0__py3-none-any.whl

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 (46) hide show
  1. fusion/__init__.py +3 -0
  2. fusion/_skills/fusion-analyst/SKILL.md +50 -0
  3. fusion/_skills/fusion-analyst/references/assess.md +12 -0
  4. fusion/_skills/fusion-analyst/references/compare.md +12 -0
  5. fusion/_skills/fusion-analyst/references/export.md +18 -0
  6. fusion/_skills/fusion-analyst/references/fusion-conventions.md +149 -0
  7. fusion/_skills/fusion-analyst/references/report.md +13 -0
  8. fusion/_skills/fusion-analyst/scripts/export.py +64 -0
  9. fusion/_skills/fusion-intake/SKILL.md +128 -0
  10. fusion/_skills/fusion-intake/references/convert.md +104 -0
  11. fusion/_skills/fusion-intake/references/delivery.md +107 -0
  12. fusion/_skills/fusion-intake/references/fusion-conventions.md +149 -0
  13. fusion/_skills/fusion-intake/references/gate.md +107 -0
  14. fusion/_skills/fusion-intake/scripts/convert.py +836 -0
  15. fusion/_skills/fusion-intake/scripts/gate.py +267 -0
  16. fusion/_skills/fusion-librarian/SKILL.md +64 -0
  17. fusion/_skills/fusion-librarian/references/archive.md +21 -0
  18. fusion/_skills/fusion-librarian/references/create.md +14 -0
  19. fusion/_skills/fusion-librarian/references/cross-reference.md +45 -0
  20. fusion/_skills/fusion-librarian/references/fusion-conventions.md +149 -0
  21. fusion/_skills/fusion-librarian/references/promote.md +24 -0
  22. fusion/_skills/fusion-librarian/references/query.md +17 -0
  23. fusion/_skills/fusion-librarian/references/reflect.md +47 -0
  24. fusion/_skills/fusion-librarian/references/restructure.md +20 -0
  25. fusion/_skills/fusion-librarian/references/tag.md +13 -0
  26. fusion/_skills/fusion-librarian/scripts/link-repair.py +371 -0
  27. fusion/_skills/fusion-planner/SKILL.md +62 -0
  28. fusion/_skills/fusion-planner/references/close.md +12 -0
  29. fusion/_skills/fusion-planner/references/create-activity.md +38 -0
  30. fusion/_skills/fusion-planner/references/fusion-conventions.md +149 -0
  31. fusion/_skills/fusion-planner/references/horizon.md +20 -0
  32. fusion/bucket.py +77 -0
  33. fusion/checker.py +248 -0
  34. fusion/cli.py +406 -0
  35. fusion/document.py +155 -0
  36. fusion/hub.py +78 -0
  37. fusion/indexer.py +75 -0
  38. fusion/ledger.py +106 -0
  39. fusion/manifest.py +33 -0
  40. fusion/scaffold.py +120 -0
  41. fusion/setup.py +300 -0
  42. fusion/views.py +111 -0
  43. fusion_cli-1.1.0.dist-info/METADATA +67 -0
  44. fusion_cli-1.1.0.dist-info/RECORD +46 -0
  45. fusion_cli-1.1.0.dist-info/WHEEL +4 -0
  46. fusion_cli-1.1.0.dist-info/entry_points.txt +2 -0
fusion/views.py ADDED
@@ -0,0 +1,111 @@
1
+ """fusion status / today / agenda — the composed day (design spec §5)."""
2
+ from __future__ import annotations
3
+
4
+ from collections import Counter
5
+ from dataclasses import asdict
6
+ from pathlib import Path
7
+
8
+ from . import bucket, hub, ledger
9
+ from .document import AURORAS
10
+
11
+
12
+ def filter_since(entries: list[ledger.Entry], since: str | None):
13
+ if not since:
14
+ return entries
15
+ if since == "last-reflection":
16
+ last = max(
17
+ (i for i, e in enumerate(entries) if e.verb == "reflected"),
18
+ default=None,
19
+ )
20
+ return entries if last is None else entries[last + 1 :]
21
+ return [e for e in entries if e.date >= since]
22
+
23
+
24
+ def status(root: Path, since: str | None = None) -> dict:
25
+ b = bucket.load(root)
26
+ auroras: Counter = Counter()
27
+ types: Counter = Counter()
28
+ activities: Counter = Counter()
29
+ total = 0
30
+ for zone, rel, doc in bucket.iter_documents(root):
31
+ total += 1
32
+ auroras[doc.aurora or "—"] += 1
33
+ types[doc.type or "—"] += 1
34
+ if zone == "activities":
35
+ activities[doc.status or "unset"] += 1
36
+ entries = filter_since(ledger.read(root), since)
37
+ return {
38
+ "bucket": b.name or root.name,
39
+ "documents": total,
40
+ "auroras": dict(sorted(auroras.items())),
41
+ "types": dict(sorted(types.items())),
42
+ "activities": dict(sorted(activities.items())),
43
+ "ledger": [asdict(e) for e in entries[-10:]],
44
+ }
45
+
46
+
47
+ def _hub_buckets():
48
+ """Yield (bucket_name, root) for every readable hub bucket — read means
49
+ a BUCKET.md exists, not that the bucket holds any documents yet."""
50
+ for entry in hub.load():
51
+ root = hub.resolve(entry)
52
+ if not (root / "BUCKET.md").is_file():
53
+ continue
54
+ b = bucket.load(root)
55
+ yield (b.name or entry.name), root
56
+
57
+
58
+ def _hub_documents():
59
+ """Yield (bucket_name, zone, rel, doc) across every readable hub bucket."""
60
+ for name, root in _hub_buckets():
61
+ for zone, rel, doc in bucket.iter_documents(root):
62
+ yield name, zone, rel, doc
63
+
64
+
65
+ def _item(name: str, zone: str, rel, doc, date=None) -> dict:
66
+ return {
67
+ "bucket": name,
68
+ "title": doc.title or rel.stem,
69
+ "path": f"{zone}/{rel.as_posix()}",
70
+ "type": doc.type,
71
+ "aurora": doc.aurora,
72
+ "status": doc.status,
73
+ "date": date,
74
+ }
75
+
76
+
77
+ def today() -> dict:
78
+ groups: dict[str, list] = {}
79
+ buckets: list[str] = []
80
+ for name, root in _hub_buckets():
81
+ buckets.append(name)
82
+ for zone, rel, doc in bucket.iter_documents(root):
83
+ if "archive" in rel.parts or doc.aurora == "archive":
84
+ continue
85
+ is_active_activity = zone == "activities" and doc.status == "active"
86
+ is_commitment = doc.aurora == "commitments"
87
+ if is_active_activity or is_commitment:
88
+ groups.setdefault(doc.aurora or "—", []).append(
89
+ _item(name, zone, rel, doc)
90
+ )
91
+ ordered = {a: groups[a] for a in AURORAS if a in groups}
92
+ for aurora, items in groups.items():
93
+ if aurora not in ordered:
94
+ ordered[aurora] = items
95
+ return {"buckets": buckets, "groups": ordered}
96
+
97
+
98
+ def agenda() -> dict:
99
+ dated: list[dict] = []
100
+ active: list[dict] = []
101
+ for name, zone, rel, doc in _hub_documents():
102
+ if "archive" in rel.parts or doc.aurora == "archive":
103
+ continue
104
+ fm = doc.frontmatter or {}
105
+ raw = fm.get("due") or fm.get("date")
106
+ if raw is not None:
107
+ dated.append(_item(name, zone, rel, doc, date=str(raw)[:10]))
108
+ elif zone == "activities" and doc.status == "active":
109
+ active.append(_item(name, zone, rel, doc))
110
+ dated.sort(key=lambda i: i["date"])
111
+ return {"dated": dated, "active": active}
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: fusion-cli
3
+ Version: 1.1.0
4
+ Summary: The Fusion reference CLI — the notary of the Fusion Convention.
5
+ Author: Bluewaves Boutique
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: pyyaml>=6.0
9
+ Description-Content-Type: text/markdown
10
+
11
+ # fusion — the notary of the Fusion Convention
12
+
13
+ The reference CLI. It records, checks, and composes; it never judges —
14
+ judgment belongs to the skill family. Buckets that follow
15
+ [the convention](../SPEC.md) are Fusion whether or not this tool ever
16
+ touches them.
17
+
18
+ ## Install
19
+
20
+ One line, installs the CLI and the four skills into every agent that
21
+ reads them:
22
+
23
+ ```sh
24
+ curl -fsSL https://raw.githubusercontent.com/bluewaves-creations/fusion/main/install.sh | sh
25
+ ```
26
+
27
+ Just the CLI, from PyPI:
28
+
29
+ ```sh
30
+ uv tool install fusion-cli
31
+ ```
32
+
33
+ From a clone:
34
+
35
+ ```sh
36
+ git clone https://github.com/bluewaves-creations/fusion.git
37
+ uv tool install ./fusion/cli
38
+ fusion --version
39
+ ```
40
+
41
+ ## The nine commands (there is no tenth)
42
+
43
+ | Command | Does |
44
+ |---|---|
45
+ | `fusion new <path>` | Scaffold a complete bucket + register it in the hub |
46
+ | `fusion hub` | List / register (`add <path>`) / retire (`remove <name>`) buckets |
47
+ | `fusion log <verb> <object>` | Append a ledger entry — the only writer. No args: read the ledger |
48
+ | `fusion index [path]` | Regenerate `INDEX.md` in `library/` and `activities/` |
49
+ | `fusion check [path]` | Audit a bucket against SPEC §11 — exit 1 on errors |
50
+ | `fusion status [path]` | One bucket at a glance |
51
+ | `fusion today` | The composed day, across every bucket in the hub |
52
+ | `fusion agenda` | The wider horizon — dated and active, across the hub |
53
+ | `fusion setup` | Install the skills into every detected agent — the installer's brain. `--remove` undoes it |
54
+
55
+ Every command takes `--json` (agents parse, never scrape). `log`, `new`,
56
+ and `index` take `--as <actor>`; the pen defaults to `FUSION_ACTOR`, then
57
+ the OS username. `status` and `log` take `--since <date|last-reflection>`.
58
+ `log` also takes `--bucket` (resolves the ledger; default: walk up from the current directory).
59
+ The hub lives at `~/.fusion/hub.md` (`FUSION_HUB` overrides).
60
+
61
+ ## Development
62
+
63
+ ```sh
64
+ cd cli
65
+ uv run pytest # the suite — golden tests run against ../examples/crazy-ones
66
+ uv run fusion check ../examples/crazy-ones
67
+ ```
@@ -0,0 +1,46 @@
1
+ fusion/__init__.py,sha256=llHMk8mEYtxolae7jRHA6InBi4s9_I63LdBprNYR12A,84
2
+ fusion/bucket.py,sha256=EZQH80Uu2VFetkcQPzzNreoCIJsg7rUbwze1FWmRYm4,2124
3
+ fusion/checker.py,sha256=W03XPxWorCqcvxz3oX2dt3Q7GzOHDgi1I0xWEJNUzRI,9462
4
+ fusion/cli.py,sha256=sHAJ4z1yOvdyM1vCqA-cu2nveZWK1xw2D_GvhzqJtq8,17205
5
+ fusion/document.py,sha256=Ajh-faFQLXgwVLibagdxIxwAjMI57CHKQbGsGNwNRNE,4813
6
+ fusion/hub.py,sha256=RgmXtlFqZ36C4rnP4D3syr8O6f3ZrKTIVQGYd_7EeNY,1974
7
+ fusion/indexer.py,sha256=SA9ZBOh4OSZ4lx2x33yUpPte82ZHGPpGtLvFfw6Yhj8,2694
8
+ fusion/ledger.py,sha256=oJNladLLRhA4zhyVTUOgzaaMy3o8nTjDgg3qza0uotw,3280
9
+ fusion/manifest.py,sha256=7UU5HlvTctoSpz9iqLlwJxYQLewXj7GJv3zdhIHoeyI,871
10
+ fusion/scaffold.py,sha256=Dzz5np91MUWCtS38l3dIY60IaXdPFKO2AfjxMsIV5CU,3607
11
+ fusion/setup.py,sha256=j_3nwgvtvxe-ZuIbQXrQWfI8MSoMLRycxV6x6Gp_99E,12771
12
+ fusion/views.py,sha256=hCdq1IjTisd-8drXkuoTmt680NHSBV3dyOaFERj0qes,3796
13
+ fusion/_skills/fusion-analyst/SKILL.md,sha256=T7XnaeylxdyniCcWtXZYEKvgzOZx_I-H2nmHvmX5HKI,2872
14
+ fusion/_skills/fusion-analyst/references/assess.md,sha256=6JKusH38m5uCXp0zRtFsVmiAMdmFL7vwA0jtlqYKGFs,624
15
+ fusion/_skills/fusion-analyst/references/compare.md,sha256=uBEIVC7fa-D6t_SCXNIGGI_dZAYtLIdQ9Ds-ivLizv8,626
16
+ fusion/_skills/fusion-analyst/references/export.md,sha256=CCcirWNSwkZ6GbDeVn1-tmVT7SbTvN9cfIqIQR_Fw6Q,747
17
+ fusion/_skills/fusion-analyst/references/fusion-conventions.md,sha256=dLqp_HFTnhUKl69CyeoEbNXjMy1lCOSfDgbWMVh-tfI,6216
18
+ fusion/_skills/fusion-analyst/references/report.md,sha256=kjsh5G9xaHAuEiotB74pLc_4bs5rYKilSPmJwA2Agbs,751
19
+ fusion/_skills/fusion-analyst/scripts/export.py,sha256=59HhpIfJqPikGUI2GFxrg1JIAQ2JYJnsZvP2sCi67oc,1959
20
+ fusion/_skills/fusion-intake/SKILL.md,sha256=-zhBmLkUgJRnM3DqXfhKc6LQdlvE_8QtWXOcIPhPAGQ,7557
21
+ fusion/_skills/fusion-intake/references/convert.md,sha256=yxEdUnvxVTmSX7wqyYhdRBL49ph3inOEswESVXeO3bY,4392
22
+ fusion/_skills/fusion-intake/references/delivery.md,sha256=r1qmVfq2sUhBqmW35sCEfjyH-C2NTE1RBPEMigXap14,5879
23
+ fusion/_skills/fusion-intake/references/fusion-conventions.md,sha256=dLqp_HFTnhUKl69CyeoEbNXjMy1lCOSfDgbWMVh-tfI,6216
24
+ fusion/_skills/fusion-intake/references/gate.md,sha256=bJ3cEnVXJGqGg8DmkjJakzzzILOlcpr7GZi392YZ-6A,5304
25
+ fusion/_skills/fusion-intake/scripts/convert.py,sha256=FcFQ-ibeWjkyujG-4IZQltUY072RzlFLH1XO7A3v18Q,34829
26
+ fusion/_skills/fusion-intake/scripts/gate.py,sha256=mn2pG2ldAS_h1Y6hrZdB-8QNHo8xYojGPDLsQ5Ja0aY,10002
27
+ fusion/_skills/fusion-librarian/SKILL.md,sha256=EsEaH5TIswQYkeNjO5Xb4Xj704VmcKiig9TGTB6bXuE,3706
28
+ fusion/_skills/fusion-librarian/references/archive.md,sha256=i4xITrqsjjC68aJq1ktsefzZYCChed6uFKuitJxAMy8,1088
29
+ fusion/_skills/fusion-librarian/references/create.md,sha256=cH-NSwPLXDsweQ4MFQLw_YEUwtjksFMa7lU3KqW-x4o,869
30
+ fusion/_skills/fusion-librarian/references/cross-reference.md,sha256=HhEs_j7SqaGgmAE2wJI64x3J8fcmL6uG9H4y8p3DcnI,2481
31
+ fusion/_skills/fusion-librarian/references/fusion-conventions.md,sha256=dLqp_HFTnhUKl69CyeoEbNXjMy1lCOSfDgbWMVh-tfI,6216
32
+ fusion/_skills/fusion-librarian/references/promote.md,sha256=x6qLJWqt6zBN3FgF9r5K65jjwE5h43qvM4e4R9wEuvE,1128
33
+ fusion/_skills/fusion-librarian/references/query.md,sha256=JmQHQfdktK6hFoC7x-ms5Xvj2oGluAiwuO_mpY4MbeQ,831
34
+ fusion/_skills/fusion-librarian/references/reflect.md,sha256=3lkmqhfOhJdZfKw_2vHwEf19Kp4DXZSBI4jyAf1C0WQ,1933
35
+ fusion/_skills/fusion-librarian/references/restructure.md,sha256=U_WtJzmo_uNfIZAN0inga0mtFhqQO1xIvT6VJ2EI1aE,1077
36
+ fusion/_skills/fusion-librarian/references/tag.md,sha256=E9M2Wec5PiGlMpEAF3Q3VbYYDo7O9kMA5ZPv22pbmSs,689
37
+ fusion/_skills/fusion-librarian/scripts/link-repair.py,sha256=q3_dDf-d1kJ852MzzPuxPFAWNlwYJMizbvRlFbG079w,15422
38
+ fusion/_skills/fusion-planner/SKILL.md,sha256=ljMMYpUkykzwpj8Gja-Kfd0QoZ--bSUWc_NRUJvUaro,3018
39
+ fusion/_skills/fusion-planner/references/close.md,sha256=ucKMR93bQazTE532mNqKJLTK0iMji3YzYuIMZfCr51s,709
40
+ fusion/_skills/fusion-planner/references/create-activity.md,sha256=RFIJStk1CCoUYLVBZUxaVz4-SgNRm7YGGesRup4aR-U,994
41
+ fusion/_skills/fusion-planner/references/fusion-conventions.md,sha256=dLqp_HFTnhUKl69CyeoEbNXjMy1lCOSfDgbWMVh-tfI,6216
42
+ fusion/_skills/fusion-planner/references/horizon.md,sha256=E3YchjopfxC-ERTyAxTj5hzmvEnFYd_teY8TScYcg2o,1096
43
+ fusion_cli-1.1.0.dist-info/METADATA,sha256=G1YNkkxeO0gEhxihsLQVwmRAQNfFQi6EUN55RhvHfG8,2289
44
+ fusion_cli-1.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
45
+ fusion_cli-1.1.0.dist-info/entry_points.txt,sha256=fVgiRsE5pSqmAqNKk9YQCJnpBW3A780OzNC-A4CjzqM,49
46
+ fusion_cli-1.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ fusion = fusion.cli:main_entry