feat: draw the grid by default, --markdown to opt out
A markdown table carries no borders of its own; whether any get drawn is up to the renderer, and terminal renderers mostly draw none. Emitting the grid directly makes the output look the same everywhere it lands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,9 +43,13 @@ missing step if not.
|
|||||||
python3 <skill-dir>/scripts/scan-activity.py --week last
|
python3 <skill-dir>/scripts/scan-activity.py --week last
|
||||||
```
|
```
|
||||||
|
|
||||||
Prints a markdown table: one row per day, one column per project holding
|
Prints a drawn grid: one row per day, one column per project holding
|
||||||
`hours · share · active minutes`, then a totals row. That table is the
|
`hours · share · active minutes`, then a totals row. That table is the
|
||||||
deliverable — paste it as-is rather than restating it in prose.
|
deliverable — show it as-is, inside a fenced code block so the terminal
|
||||||
|
renderer leaves the borders alone, rather than restating it in prose.
|
||||||
|
|
||||||
|
`--markdown` swaps the grid for pipes when the destination renders tables
|
||||||
|
itself (a PR body, an issue, a doc).
|
||||||
|
|
||||||
The unit behind it is a 5-minute slot in which at least one message was
|
The unit behind it is a 5-minute slot in which at least one message was
|
||||||
written, deduplicated per project — so a 40-subagent swarm on one project
|
written, deduplicated per project — so a 40-subagent swarm on one project
|
||||||
|
|||||||
@@ -14,11 +14,16 @@ transcripts on one project counts once, and two projects worked in parallel
|
|||||||
each keep their own slots. Message counts would make one overnight autonomous
|
each keep their own slots. Message counts would make one overnight autonomous
|
||||||
run outweigh a real morning; wall-clock presence does not.
|
run outweigh a real morning; wall-clock presence does not.
|
||||||
|
|
||||||
Output is one line per project per day: suggested hours, share of the day, and
|
Output is a table: one row per day, one column per project, each cell holding
|
||||||
the active minutes behind it. The suggestion splits a nominal working day by
|
suggested hours, share of the day, and the active minutes behind it. The
|
||||||
share, in 15-minute steps — active minutes are a floor on real work, never a
|
suggestion splits a nominal working day by share, in 15-minute steps — active
|
||||||
measure of it, so the day's length comes from the calendar and only the split
|
minutes are a floor on real work, never a measure of it, so the day's length
|
||||||
between projects comes from the sessions. See SKILL.md.
|
comes from the calendar and only the split between projects comes from the
|
||||||
|
sessions. See SKILL.md.
|
||||||
|
|
||||||
|
Default rendering is a drawn grid, because a markdown table has no borders of
|
||||||
|
its own and terminal renderers vary in whether they draw any. --markdown emits
|
||||||
|
pipes instead, for pasting somewhere that does render them.
|
||||||
"""
|
"""
|
||||||
import argparse
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
@@ -155,17 +160,35 @@ def fmt_hour_list(hours):
|
|||||||
return ", ".join(out)
|
return ", ".join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def widths(rows):
|
||||||
|
return [max(len(r[i]) for r in rows) for i in range(len(rows[0]))]
|
||||||
|
|
||||||
|
|
||||||
|
def _cells(row, w, align_right):
|
||||||
|
return "| " + " | ".join(
|
||||||
|
c.rjust(w[i]) if i in align_right else c.ljust(w[i])
|
||||||
|
for i, c in enumerate(row)) + " |"
|
||||||
|
|
||||||
|
|
||||||
|
def box_table(rows, align_right=()):
|
||||||
|
"""Render rows (first is the header) as a grid with every cell bordered."""
|
||||||
|
w = widths(rows)
|
||||||
|
rule = "+" + "+".join("-" * (n + 2) for n in w) + "+"
|
||||||
|
out = [rule]
|
||||||
|
for row in rows:
|
||||||
|
out += [_cells(row, w, align_right), rule]
|
||||||
|
return "\n".join(out)
|
||||||
|
|
||||||
|
|
||||||
def md_table(rows, align_right=()):
|
def md_table(rows, align_right=()):
|
||||||
"""Render rows (first is the header) as a padded markdown table."""
|
"""Render rows (first is the header) as a padded markdown table."""
|
||||||
w = [max(len(r[i]) for r in rows) for i in range(len(rows[0]))]
|
w = widths(rows)
|
||||||
def line(cells):
|
|
||||||
return "| " + " | ".join(
|
|
||||||
c.rjust(w[i]) if i in align_right else c.ljust(w[i])
|
|
||||||
for i, c in enumerate(cells)) + " |"
|
|
||||||
sep = "|" + "|".join(
|
sep = "|" + "|".join(
|
||||||
("-" * (w[i] + 1) + ":") if i in align_right else ("-" * (w[i] + 2))
|
("-" * (w[i] + 1) + ":") if i in align_right else ("-" * (w[i] + 2))
|
||||||
for i in range(len(w))) + "|"
|
for i in range(len(w))) + "|"
|
||||||
return "\n".join([line(rows[0]), sep] + [line(r) for r in rows[1:]])
|
return "\n".join(
|
||||||
|
[_cells(rows[0], w, align_right), sep] +
|
||||||
|
[_cells(r, w, align_right) for r in rows[1:]])
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -175,6 +198,8 @@ def main():
|
|||||||
ap.add_argument("--week", choices=["last", "this"])
|
ap.add_argument("--week", choices=["last", "this"])
|
||||||
ap.add_argument("--config", default=CONFIG)
|
ap.add_argument("--config", default=CONFIG)
|
||||||
ap.add_argument("--json", action="store_true")
|
ap.add_argument("--json", action="store_true")
|
||||||
|
ap.add_argument("--markdown", action="store_true",
|
||||||
|
help="pipe table for pasting, instead of a drawn grid")
|
||||||
a = ap.parse_args()
|
a = ap.parse_args()
|
||||||
|
|
||||||
cfg = load_config(a.config)
|
cfg = load_config(a.config)
|
||||||
@@ -308,11 +333,13 @@ def main():
|
|||||||
rows.append([f"{e['date']} {e['weekday']}"] + cells +
|
rows.append([f"{e['date']} {e['weekday']}"] + cells +
|
||||||
[fmt_hours(day_sum) if day_sum else "—", "; ".join(flags)])
|
[fmt_hours(day_sum) if day_sum else "—", "; ".join(flags)])
|
||||||
|
|
||||||
rows.append(["**total**"] +
|
bold = (lambda s: f"**{s}**") if a.markdown else (lambda s: s)
|
||||||
[f"**{fmt_hours(week[c])}**" for c in cols] +
|
rows.append([bold("total")] +
|
||||||
[f"**{fmt_hours(sum(week.values()))}**", ""])
|
[bold(fmt_hours(week[c])) for c in cols] +
|
||||||
|
[bold(fmt_hours(sum(week.values()))), ""])
|
||||||
right = set(range(1, len(cols) + 2))
|
right = set(range(1, len(cols) + 2))
|
||||||
print(md_table(rows, align_right=right))
|
render = md_table if a.markdown else box_table
|
||||||
|
print(render(rows, align_right=right))
|
||||||
|
|
||||||
if unmapped:
|
if unmapped:
|
||||||
print("\nunmapped paths — add them to the config or the exclude list:")
|
print("\nunmapped paths — add them to the config or the exclude list:")
|
||||||
|
|||||||
Reference in New Issue
Block a user