Add json/csv support to the posting script (issue #012)

TEXT_KINDS and TEXT_SUFFIXES now include json/csv, with matching
sniff_text_kind branches so both explicit --kind and positional auto-mode
work. Added validate_payload's JSON shape check mirroring the server.
Updated SKILL.md/docs/llm_posting_helper.md with real usage examples,
replacing the stale --as-markdown workaround guidance (kept only for
genuinely unstructured code, which still has no dedicated kind). Also
fixed an unrelated stale doc line found in the same table: html_full's
validation was documented as requiring <!doctype AND <html, but only
<html is actually required.

Verified via dry-run (explicit --kind, auto-mode, invalid-JSON rejection)
and one real end-to-end post through the script against the live dev
instance.

Added tests/scripts/test_daybook_post.py - 17 tests, plain unittest, zero
new dependencies, loaded via importlib since the script isn't a package.
Closes the test-coverage question the issue raised.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
peter 2026-09-02 15:38:47 +01:00
parent 532b4bd4eb
commit e137725cab
6 changed files with 177 additions and 8 deletions

View file

@ -93,7 +93,18 @@ python skills/daybook-posting/scripts/daybook_post.py report.md
The image is linked to the artifact that references it and is deleted along with it.
Unreferenced uploads are cleaned up after 24 hours.
For CSV, JSON, or code that should render today, use `--file path --as-markdown` to post it as a Markdown fenced code block. Without `--as-markdown`, these upload as downloadable binary files.
For CSV and JSON, use `--kind csv`/`--kind json` with `--content-file` — or
just post the file positionally; auto-mode detects `.csv`/`.json` and picks
the right kind automatically:
```bash
python skills/daybook-posting/scripts/daybook_post.py results.csv
python skills/daybook-posting/scripts/daybook_post.py --kind json --title "Run Summary" --content-file summary.json
```
For other code that should render today, use `--file path --as-markdown` to
post it as a Markdown fenced code block. Without `--as-markdown`, it uploads
as a downloadable binary file.
## Rules

View file

@ -18,8 +18,8 @@ from urllib.parse import urljoin
from urllib.request import Request, urlopen
TEXT_KINDS = {"markdown", "html_fragment", "html_full", "deck"}
TEXT_SUFFIXES = {".md", ".markdown", ".txt", ".html", ".htm"}
TEXT_KINDS = {"markdown", "html_fragment", "html_full", "deck", "json", "csv"}
TEXT_SUFFIXES = {".md", ".markdown", ".txt", ".html", ".htm", ".json", ".csv"}
DEFAULT_URL = "http://127.0.0.1:8001"
DEFAULT_SOURCE = "agent"
@ -156,6 +156,10 @@ def resolve_auto_path(args):
def sniff_text_kind(suffix, text):
if suffix in (".md", ".markdown", ".txt"):
return "markdown"
if suffix == ".json":
return "json"
if suffix == ".csv":
return "csv"
lower = text.lower()
if "<!doctype" in lower or "<html" in lower:
return "html_full"
@ -301,6 +305,11 @@ def validate_payload(payload, args):
raise ValueError("html_full must be a complete HTML document with <html> (and ideally <!doctype html>)")
if kind == "markdown" and not payload["content"].strip():
raise ValueError("markdown content cannot be blank")
if kind == "json":
try:
json.loads(payload["content"])
except json.JSONDecodeError as exc:
raise ValueError(f"json content must be valid JSON: {exc}") from exc
def print_dry_run(base_url, token, payload, args):