beacon-framework 1.2.0__tar.gz → 1.2.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.
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/PKG-INFO +1 -1
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/pyproject.toml +5 -1
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/__init__.py +1 -1
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/cli.py +19 -12
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/epic.py +2 -2
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/roadmap.py +74 -43
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/.gitignore +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/BEACON.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/LICENSE +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/README.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/pragmatic-principles.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/__main__.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/bullet.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/docs.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/doctor.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/installer.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/integrations/__init__.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/integrations/claude_code.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/integrations/release.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/language.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/manifest.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/beacon.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/help/commands.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/help/doctor.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/help/git-flow.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/help/phases.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/help/quickstart.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/CLAUDE.md.fragment +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/agents/beacon-reviewer.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/constitution.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/continue.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/implement.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/plan.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/prd.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/review.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/roadmap.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/seed.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/specify.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/status.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/beacon/tasks.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/design/diagram.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/design/evaluate.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/design/wardley.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/git/feature.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/git/pr.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/git/release.gitflow.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/git/release.trunk.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/commands/init.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/settings.json +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/skills/beacon-build/SKILL.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/skills/beacon-design/SKILL.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/skills/beacon-seed/SKILL.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/claude_code/skills/beacon-ship/SKILL.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/release/PUBLISHING.gitflow.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/release/PUBLISHING.trunk.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/release/psr_config.gitflow.toml +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/release/psr_config.trunk.toml +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/release/workflows/release.gitflow.yml +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/integrations/release/workflows/release.trunk.yml +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/languages/node.toml +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/languages/python.toml +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/.beacon/doctor.toml.example +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/ADRs/ADR-000-template.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/ADRs/README.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Background/00-problem-statement.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Background/01-final-architecture-document.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Roadmap/README.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Roadmap/archive/.gitkeep +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Roadmap/epics/.gitkeep +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Roadmap/epics/EPIC-TEMPLATE.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Roadmap/epics/archive/.gitkeep +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Work/README.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Work/analysis/.gitkeep +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Work/branches/.gitkeep +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Work/planning/.gitkeep +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/project-management/Work/sessions/.gitkeep +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/roadmap_template.html +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/user-facing-docs/README.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/user-facing-docs/explanation/index.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/user-facing-docs/how-to/index.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/user-facing-docs/reference/index.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/user-facing-docs/tutorials/getting-started.md +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/seed.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/upgrader.py +0 -0
- {beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/validate.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: beacon-framework
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: Light-touch, pragmatic, artifact-driven framework for AI-assisted software delivery
|
|
5
5
|
Project-URL: Repository, https://github.com/darth-veitcher/beacon
|
|
6
6
|
Author: darth-veitcher
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "beacon-framework"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.2"
|
|
8
8
|
description = "Light-touch, pragmatic, artifact-driven framework for AI-assisted software delivery"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -74,6 +74,8 @@ Repository = "https://github.com/darth-veitcher/beacon"
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
|
|
78
|
+
|
|
77
79
|
|
|
78
80
|
|
|
79
81
|
|
|
@@ -181,6 +183,8 @@ exclude_commit_patterns = ["^chore\\(release\\):"]
|
|
|
181
183
|
|
|
182
184
|
|
|
183
185
|
|
|
186
|
+
|
|
187
|
+
|
|
184
188
|
|
|
185
189
|
|
|
186
190
|
|
|
@@ -1281,9 +1281,10 @@ def roadmap_export(
|
|
|
1281
1281
|
Markdown document. Safe to commit alongside beacon.md; regenerate on demand or
|
|
1282
1282
|
wire into CI with ``beacon roadmap export``.
|
|
1283
1283
|
"""
|
|
1284
|
-
from beacon import roadmap as _roadmap
|
|
1285
1284
|
from datetime import date
|
|
1286
1285
|
|
|
1286
|
+
from beacon import roadmap as _roadmap
|
|
1287
|
+
|
|
1287
1288
|
root = _resolve_root(here, path)
|
|
1288
1289
|
if not (root / "project-management").is_dir():
|
|
1289
1290
|
console.print(f"[red]✗[/red] Not a BEACON project at [cyan]{root}[/cyan].")
|
|
@@ -1300,14 +1301,21 @@ def roadmap_export(
|
|
|
1300
1301
|
return
|
|
1301
1302
|
dest = output or (root / "ROADMAP.md")
|
|
1302
1303
|
dest.write_text(content, encoding="utf-8")
|
|
1303
|
-
console.print(
|
|
1304
|
-
f"[green]✓[/green] Roadmap exported → [cyan]{dest.relative_to(root)}[/cyan]"
|
|
1305
|
-
)
|
|
1304
|
+
console.print(f"[green]✓[/green] Roadmap exported → [cyan]{dest.relative_to(root)}[/cyan]")
|
|
1306
1305
|
if not data.epics:
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1306
|
+
if data.archived_epics and not include_done:
|
|
1307
|
+
n = len(data.archived_epics)
|
|
1308
|
+
plural = "s" if n > 1 else ""
|
|
1309
|
+
console.print(
|
|
1310
|
+
f"[dim] ({n} archived epic{plural}"
|
|
1311
|
+
" — run [/dim][dim cyan]beacon roadmap export --include-done"
|
|
1312
|
+
"[/dim cyan][dim] to include completed work)[/dim]"
|
|
1313
|
+
)
|
|
1314
|
+
elif not data.archived_epics:
|
|
1315
|
+
console.print(
|
|
1316
|
+
"[dim] (project-management/Roadmap/epics/ has no epics yet"
|
|
1317
|
+
" — run [/dim][dim cyan]beacon epic new <slug>[/dim cyan][dim])[/dim]"
|
|
1318
|
+
)
|
|
1311
1319
|
|
|
1312
1320
|
|
|
1313
1321
|
@roadmap_app.command("render")
|
|
@@ -1325,9 +1333,10 @@ def roadmap_render(
|
|
|
1325
1333
|
design system (dark, blueprint-grid, engineering-whitepaper aesthetic). Open
|
|
1326
1334
|
directly in a browser, screenshot into a slide deck, or host as a static page.
|
|
1327
1335
|
"""
|
|
1328
|
-
from beacon import roadmap as _roadmap
|
|
1329
1336
|
from datetime import date
|
|
1330
1337
|
|
|
1338
|
+
from beacon import roadmap as _roadmap
|
|
1339
|
+
|
|
1331
1340
|
root = _resolve_root(here, path)
|
|
1332
1341
|
if not (root / "project-management").is_dir():
|
|
1333
1342
|
console.print(f"[red]✗[/red] Not a BEACON project at [cyan]{root}[/cyan].")
|
|
@@ -1341,9 +1350,7 @@ def roadmap_render(
|
|
|
1341
1350
|
content = _roadmap.render_html(data, today)
|
|
1342
1351
|
dest = output or (root / "ROADMAP.html")
|
|
1343
1352
|
dest.write_text(content, encoding="utf-8")
|
|
1344
|
-
console.print(
|
|
1345
|
-
f"[green]✓[/green] Roadmap rendered → [cyan]{dest.relative_to(root)}[/cyan]"
|
|
1346
|
-
)
|
|
1353
|
+
console.print(f"[green]✓[/green] Roadmap rendered → [cyan]{dest.relative_to(root)}[/cyan]")
|
|
1347
1354
|
console.print(
|
|
1348
1355
|
"[dim]i[/dim] Add [dim]ROADMAP.html[/dim] to [dim].gitignore[/dim] "
|
|
1349
1356
|
"to keep it out of version control."
|
|
@@ -162,8 +162,8 @@ def _extract_list_under_header(content: str, header: str) -> list[str]:
|
|
|
162
162
|
if in_section:
|
|
163
163
|
m = _LIST_ITEM_RE.match(line)
|
|
164
164
|
if m and not m.group("body").startswith("<!--"):
|
|
165
|
-
# Strip trailing "
|
|
166
|
-
body = m.group("body").split("
|
|
165
|
+
# Strip trailing " — description" (em dash with any surrounding spaces)
|
|
166
|
+
body = m.group("body").split("—", 1)[0].split(" --", 1)[0].strip()
|
|
167
167
|
items.append(body.rstrip("/"))
|
|
168
168
|
return items
|
|
169
169
|
|
|
@@ -72,6 +72,7 @@ class RoadmapData:
|
|
|
72
72
|
fidelity: dict[str, EpicFidelity]
|
|
73
73
|
adrs: list[AdrSummary]
|
|
74
74
|
in_flight_bullets: list # list[Bullet] — avoid circular import
|
|
75
|
+
archived_epics: list[Epic] = field(default_factory=list)
|
|
75
76
|
|
|
76
77
|
|
|
77
78
|
# ---------------------------------------------------------------------------
|
|
@@ -168,10 +169,10 @@ def _task_pct(root: Path, epic: Epic) -> int | None:
|
|
|
168
169
|
|
|
169
170
|
|
|
170
171
|
def _fidelity_badge(f: EpicFidelity) -> str:
|
|
171
|
-
"""Return ASCII fidelity string like 'S+ A+ T:67%' or 'S? A? T
|
|
172
|
+
"""Return ASCII fidelity string like 'S+ A+ T:67%' or 'S? A? T:-'."""
|
|
172
173
|
spec = "S+" if f.has_specs else "S?"
|
|
173
174
|
adr = "A+" if f.has_adrs else "A?"
|
|
174
|
-
task = f"T:{f.task_pct}%" if f.task_pct is not None else "T
|
|
175
|
+
task = f"T:{f.task_pct}%" if f.task_pct is not None else "T:-"
|
|
175
176
|
return f"{spec} {adr} {task}"
|
|
176
177
|
|
|
177
178
|
|
|
@@ -257,9 +258,7 @@ def _mermaid_gantt_src(
|
|
|
257
258
|
else:
|
|
258
259
|
tag = ""
|
|
259
260
|
safe_title = e.title.replace(":", " -").replace(",", " ")
|
|
260
|
-
lines.append(
|
|
261
|
-
f" {safe_title} :{tag}{e.slug}, {start}, {dur}d"
|
|
262
|
-
)
|
|
261
|
+
lines.append(f" {safe_title} :{tag}{e.slug}, {start}, {dur}d")
|
|
263
262
|
lines.append("")
|
|
264
263
|
|
|
265
264
|
return "\n".join(lines)
|
|
@@ -273,7 +272,11 @@ def _markdown_status_table(
|
|
|
273
272
|
"""Render the epic status Markdown table."""
|
|
274
273
|
rows = ["| Epic | Title | Status | Specs | Fidelity |", "|---|---|---|---|---|"]
|
|
275
274
|
for e in epics:
|
|
276
|
-
|
|
275
|
+
if e.path.parent.name == "archive":
|
|
276
|
+
path_rel = f"project-management/Roadmap/epics/archive/{e.slug}.md"
|
|
277
|
+
else:
|
|
278
|
+
path_rel = f"project-management/Roadmap/epics/{e.slug}.md"
|
|
279
|
+
link = f"[{e.slug}]({path_rel})"
|
|
277
280
|
roll = rollups.get(e.slug)
|
|
278
281
|
if roll and roll.total > 0:
|
|
279
282
|
specs_col = f"{len(roll.shipped)}/{roll.total} shipped"
|
|
@@ -289,33 +292,36 @@ def _markdown_status_table(
|
|
|
289
292
|
|
|
290
293
|
def _to_json_data(data: RoadmapData, generated_at: str, *, include_done: bool = False) -> dict:
|
|
291
294
|
"""Serialise RoadmapData to the shape embedded in ROADMAP.html."""
|
|
295
|
+
all_epics = data.epics + (data.archived_epics if include_done else [])
|
|
292
296
|
epics_list = []
|
|
293
|
-
for e in
|
|
297
|
+
for e in all_epics:
|
|
294
298
|
if not include_done and e.status == "Done":
|
|
295
299
|
continue
|
|
296
300
|
roll = data.rollups.get(e.slug)
|
|
297
301
|
f = data.fidelity.get(e.slug)
|
|
298
302
|
dur = max(7, (len(roll.in_flight) + len(roll.missing)) * 7) if roll else 7
|
|
299
|
-
epics_list.append(
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
303
|
+
epics_list.append(
|
|
304
|
+
{
|
|
305
|
+
"slug": e.slug,
|
|
306
|
+
"title": e.title,
|
|
307
|
+
"status": e.status,
|
|
308
|
+
"started": e.started or "",
|
|
309
|
+
"specs_total": roll.total if roll else 0,
|
|
310
|
+
"specs_shipped": len(roll.shipped) if roll else 0,
|
|
311
|
+
"specs_in_flight": len(roll.in_flight) if roll else 0,
|
|
312
|
+
"has_adrs": f.has_adrs if f else False,
|
|
313
|
+
"adr_count": f.adr_count if f else 0,
|
|
314
|
+
"task_pct": f.task_pct if f else None,
|
|
315
|
+
"fidelity_badge": _fidelity_badge(f) if f else "—",
|
|
316
|
+
"duration_days": dur,
|
|
317
|
+
}
|
|
318
|
+
)
|
|
313
319
|
|
|
314
320
|
# Deduplicate ADRs and attach which epics reference each
|
|
315
321
|
adr_epics: dict[str, list[str]] = {}
|
|
316
322
|
for adr in data.adrs:
|
|
317
323
|
adr_epics.setdefault(adr.token, [])
|
|
318
|
-
for e in
|
|
324
|
+
for e in all_epics:
|
|
319
325
|
for adr_path in e.adrs:
|
|
320
326
|
m = _ADR_TOKEN_RE.search(adr_path)
|
|
321
327
|
if m:
|
|
@@ -347,20 +353,22 @@ def _to_json_data(data: RoadmapData, generated_at: str, *, include_done: bool =
|
|
|
347
353
|
|
|
348
354
|
# Build gantt_bars for D3
|
|
349
355
|
gantt_bars = []
|
|
350
|
-
for e in
|
|
356
|
+
for e in all_epics:
|
|
351
357
|
if not include_done and e.status == "Done":
|
|
352
358
|
continue
|
|
353
359
|
if not e.started:
|
|
354
360
|
continue
|
|
355
361
|
roll = data.rollups.get(e.slug)
|
|
356
362
|
dur = max(7, (len(roll.in_flight) + len(roll.missing)) * 7) if roll else 7
|
|
357
|
-
gantt_bars.append(
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
363
|
+
gantt_bars.append(
|
|
364
|
+
{
|
|
365
|
+
"slug": e.slug,
|
|
366
|
+
"title": e.title,
|
|
367
|
+
"status": e.status,
|
|
368
|
+
"started": e.started,
|
|
369
|
+
"duration_days": dur,
|
|
370
|
+
}
|
|
371
|
+
)
|
|
364
372
|
|
|
365
373
|
return {
|
|
366
374
|
"project_name": data.project_name,
|
|
@@ -384,13 +392,14 @@ def collect(root: Path) -> RoadmapData:
|
|
|
384
392
|
from beacon import epic as _epic
|
|
385
393
|
|
|
386
394
|
epics = _epic.list_active(root)
|
|
395
|
+
archived = _epic.list_archived(root)
|
|
387
396
|
rollups: dict[str, Rollup] = {}
|
|
388
397
|
fidelity_map: dict[str, EpicFidelity] = {}
|
|
389
398
|
|
|
390
|
-
# Collect ADRs deduplicating across all epics
|
|
399
|
+
# Collect ADRs deduplicating across all epics (active + archived)
|
|
391
400
|
seen_adrs: dict[str, AdrSummary] = {} # token → summary
|
|
392
401
|
|
|
393
|
-
for e in epics:
|
|
402
|
+
for e in epics + archived:
|
|
394
403
|
try:
|
|
395
404
|
roll = _epic.rollup(root, e)
|
|
396
405
|
except Exception:
|
|
@@ -435,6 +444,7 @@ def collect(root: Path) -> RoadmapData:
|
|
|
435
444
|
fidelity=fidelity_map,
|
|
436
445
|
adrs=adrs,
|
|
437
446
|
in_flight_bullets=bullets,
|
|
447
|
+
archived_epics=archived,
|
|
438
448
|
)
|
|
439
449
|
|
|
440
450
|
|
|
@@ -455,27 +465,51 @@ def render_markdown(
|
|
|
455
465
|
lines.append(f"> {data.vision_excerpt}")
|
|
456
466
|
lines.append("")
|
|
457
467
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
468
|
+
visible_epics = data.epics + (data.archived_epics if include_done else [])
|
|
469
|
+
|
|
470
|
+
if not visible_epics:
|
|
471
|
+
if data.archived_epics:
|
|
472
|
+
n = len(data.archived_epics)
|
|
473
|
+
plural = "s" if n > 1 else ""
|
|
474
|
+
lines.append(
|
|
475
|
+
f"_No active epics — {n} epic{plural} archived. "
|
|
476
|
+
f"Run `beacon roadmap export --include-done` to include completed work._"
|
|
477
|
+
)
|
|
478
|
+
else:
|
|
479
|
+
lines.append(
|
|
480
|
+
'_No epics declared yet. Run `beacon epic new <slug> --title "<title>"` to start._'
|
|
481
|
+
)
|
|
482
|
+
# Still render ADR section if there are any (e.g. from archived epics)
|
|
483
|
+
if data.adrs:
|
|
484
|
+
lines.append("")
|
|
485
|
+
lines.append("## Architectural Decisions")
|
|
486
|
+
lines.append("")
|
|
487
|
+
lines.append("| ADR | Title | Status |")
|
|
488
|
+
lines.append("|---|---|---|")
|
|
489
|
+
for a in data.adrs:
|
|
490
|
+
link = f"[{a.token}]({a.path})"
|
|
491
|
+
lines.append(f"| {link} | {a.title} | {a.status} |")
|
|
492
|
+
lines.append("")
|
|
462
493
|
return "\n".join(lines)
|
|
463
494
|
|
|
464
495
|
# Mermaid Gantt
|
|
465
496
|
lines.append("## Timeline")
|
|
466
497
|
lines.append("")
|
|
467
498
|
lines.append("```mermaid")
|
|
468
|
-
lines.append(
|
|
499
|
+
lines.append(
|
|
500
|
+
_mermaid_gantt_src(visible_epics, data.rollups, generated_at, include_done=include_done)
|
|
501
|
+
)
|
|
469
502
|
lines.append("```")
|
|
470
503
|
lines.append("")
|
|
471
504
|
|
|
472
505
|
# Epic status table
|
|
473
506
|
lines.append("## Epics")
|
|
474
507
|
lines.append("")
|
|
475
|
-
lines.append(_markdown_status_table(
|
|
508
|
+
lines.append(_markdown_status_table(visible_epics, data.rollups, data.fidelity))
|
|
476
509
|
lines.append("")
|
|
477
510
|
lines.append(
|
|
478
|
-
"_Fidelity: `S+/S?` = has specs / none
|
|
511
|
+
"_Fidelity: `S+/S?` = has specs / none"
|
|
512
|
+
" · `A+/A?` = has ADRs / none · `T:N%` = task completion_"
|
|
479
513
|
)
|
|
480
514
|
lines.append("")
|
|
481
515
|
|
|
@@ -516,10 +550,7 @@ def render_html(data: RoadmapData, generated_at: str) -> str:
|
|
|
516
550
|
from importlib import resources as _res
|
|
517
551
|
|
|
518
552
|
template_bytes = (
|
|
519
|
-
_res.files("beacon")
|
|
520
|
-
.joinpath("resources")
|
|
521
|
-
.joinpath("roadmap_template.html")
|
|
522
|
-
.read_bytes()
|
|
553
|
+
_res.files("beacon").joinpath("resources").joinpath("roadmap_template.html").read_bytes()
|
|
523
554
|
)
|
|
524
555
|
template = template_bytes.decode("utf-8")
|
|
525
556
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/languages/python.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/roadmap_template.html
RENAMED
|
File without changes
|
{beacon_framework-1.2.0 → beacon_framework-1.2.2}/src/beacon/resources/user-facing-docs/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|