Revert "feat: draw the grid by default, --markdown to opt out"

The drawn grid was solving the wrong problem: the script output was
already right, and fencing it in chat is what turned a rendered table
into raw dashes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
naps62
2026-08-14 19:52:30 +00:00
parent bf1dc76125
commit b453e72d42
2 changed files with 17 additions and 48 deletions
+2 -6
View File
@@ -43,13 +43,9 @@ missing step if not.
python3 <skill-dir>/scripts/scan-activity.py --week last python3 <skill-dir>/scripts/scan-activity.py --week last
``` ```
Prints a drawn grid: one row per day, one column per project holding Prints a markdown table: 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 — show it as-is, inside a fenced code block so the terminal deliverable — paste it as-is rather than restating it in prose.
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
+15 -42
View File
@@ -14,16 +14,11 @@ 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 a table: one row per day, one column per project, each cell holding Output is one line per project per day: suggested hours, share of the day, and
suggested hours, share of the day, and the active minutes behind it. The the active minutes behind it. The suggestion splits a nominal working day by
suggestion splits a nominal working day by share, in 15-minute steps — active share, in 15-minute steps — active minutes are a floor on real work, never a
minutes are a floor on real work, never a measure of it, so the day's length measure of it, so the day's length comes from the calendar and only the split
comes from the calendar and only the split between projects comes from the between projects comes from the sessions. See SKILL.md.
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
@@ -160,35 +155,17 @@ 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 = widths(rows) w = [max(len(r[i]) for r in rows) for i in range(len(rows[0]))]
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( return "\n".join([line(rows[0]), sep] + [line(r) for r in rows[1:]])
[_cells(rows[0], w, align_right), sep] +
[_cells(r, w, align_right) for r in rows[1:]])
def main(): def main():
@@ -198,8 +175,6 @@ 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)
@@ -333,13 +308,11 @@ 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)])
bold = (lambda s: f"**{s}**") if a.markdown else (lambda s: s) rows.append(["**total**"] +
rows.append([bold("total")] + [f"**{fmt_hours(week[c])}**" for c in cols] +
[bold(fmt_hours(week[c])) for c in cols] + [f"**{fmt_hours(sum(week.values()))}**", ""])
[bold(fmt_hours(sum(week.values()))), ""])
right = set(range(1, len(cols) + 2)) right = set(range(1, len(cols) + 2))
render = md_table if a.markdown else box_table print(md_table(rows, align_right=right))
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:")