Adds an onboarding flow and an aggregated report to weekly-activity:
weekly-activity config — interactive wizard that prompts for which
sources to enable (launchpad / github / gitlab / bts) and the identity +
auth for each (usernames, emails, tokens). Writes ~/.config/weekly-activity.toml (owner-only 0600, tokens never echoed).
Re-running shows current settings and pre-fills defaults.
weekly-activity report (bare weekly-activity is an alias) — reads the
config, runs every enabled source over the same window, and aggregates the
results into one text report. A failing source is rendered as [skipped: <source> — error] without aborting the rest.
Existing single-source subcommands (launchpad, github, gitlab, bts)
are unchanged and backward compatible.
Details
New modules: config.py (typed schema, strict tomllib loader,
hand-formatted TOML writer — no new dependency), wizard.py (interactive
onboarding), aggregate.py (spec building + per-source collection +
combined render).
cli.py gained report/config subcommands; --config PATH overrides the
location on both.
16 stdlib unittest cases added (round-trip/escaping, strict validation,
0600 perms, spec mapping, failure isolation). Repo CI (ruff format/lint + ty check) passes; tests run via uv run python -m unittest discover -s tests.
Implementer report for reviewers: reports/weekly-activity-onboarding/implementation-report.md (in Kosmos' workspace).
Verification
uv sync --frozen, ruff format --check src, ruff check src, ty check,
and the 16 unit tests all pass locally. Wizard and report smoke-tested live.
## What
Adds an onboarding flow and an aggregated report to `weekly-activity`:
1. **`weekly-activity config`** — interactive wizard that prompts for which
sources to enable (launchpad / github / gitlab / bts) and the identity +
auth for each (usernames, emails, tokens). Writes
`~/.config/weekly-activity.toml` (owner-only `0600`, tokens never echoed).
Re-running shows current settings and pre-fills defaults.
2. **`weekly-activity report`** (bare `weekly-activity` is an alias) — reads the
config, runs every enabled source over the same window, and aggregates the
results into one text report. A failing source is rendered as
`[skipped: <source> — error]` without aborting the rest.
Existing single-source subcommands (`launchpad`, `github`, `gitlab`, `bts`)
are unchanged and backward compatible.
## Details
- New modules: `config.py` (typed schema, strict `tomllib` loader,
hand-formatted TOML writer — no new dependency), `wizard.py` (interactive
onboarding), `aggregate.py` (spec building + per-source collection +
combined render).
- `cli.py` gained `report`/`config` subcommands; `--config PATH` overrides the
location on both.
- 16 stdlib `unittest` cases added (round-trip/escaping, strict validation,
0600 perms, spec mapping, failure isolation). Repo CI (ruff format/lint +
`ty check`) passes; tests run via `uv run python -m unittest discover -s tests`.
Implementer report for reviewers:
`reports/weekly-activity-onboarding/implementation-report.md` (in Kosmos' workspace).
## Verification
`uv sync --frozen`, `ruff format --check src`, `ruff check src`, `ty check`,
and the 16 unit tests all pass locally. Wizard and report smoke-tested live.
$ uv run weekly-activity config
Welcome! This wizard sets up the sources aggregated by
`weekly-activity report`. Answer with Enter to accept [defaults],
or Ctrl-C to abort without writing anything.
Add Launchpad? [y/N]: y
Launchpad identity is the ~name shown on your profile page.
Launchpad username: vhaudiquet
Anonymous mode (public data only, no OAuth)? [Y/n]: n
OAuth is obtained at report time: launchpadlib opens a browser and
stores the token in your system keyring, or reads it from a file.
Credentials file (empty to use the system keyring):
Add GitHub? [y/N]: y
GitHub username: vhaudiquet
Leave the token empty to fall back to $GITHUB_TOKEN or `gh auth token`.
GitHub token (input hidden):
Add GitLab? [y/N]: y
GitLab username: vhaudiquet
Instance URL [https://gitlab.com]: https://debian.....
Leave the token empty to discover it from the environment instead.
API token (input hidden):
Env var holding the token (optional, e.g. SALSA_TOKEN):
Add Debian BTS? [y/N]: y
The BTS identifies people by the email used on bugs (submitter/owner).
Email address on Debian bugs: v
Configuration written to /home/vhaudiquet/.config/weekly-activity.toml.
Enabled sources: launchpad, github, gitlab, bts.
launchpad: vhaudiquet — OAuth via system keyring
github: vhaudiquet — token not stored (uses GITHUB_TOKEN / gh)
gitlab: vhaudiquet @ https://debian..... — token not stored (uses <HOST>_TOKEN / GITLAB_TOKEN env)
bts: v
Tokens are never printed back. Run `weekly-activity report` to
aggregate activity across all of them in one output.
Two issues with this:
I would like it more in the following way
$ weekly-activity config
Current sources: <empty>
**> Add a new source**
> Exit
Which source do you want to add?
**> Add new GitHub account**
> Add new Launchpad account
> Add new Gitlab instance/account
> Add new Debian BTS email
...
Does that make sense? This way we allow multiple instances and accounts, and we have a nice UI/UX :)
This will need to change the config format as well.
Another issue: this says that launchpad login will be done at report-time. Why can't we store the login once at config-time and be done with it?
Right now the config flow is as follows:
```
$ uv run weekly-activity config
Welcome! This wizard sets up the sources aggregated by
`weekly-activity report`. Answer with Enter to accept [defaults],
or Ctrl-C to abort without writing anything.
Add Launchpad? [y/N]: y
Launchpad identity is the ~name shown on your profile page.
Launchpad username: vhaudiquet
Anonymous mode (public data only, no OAuth)? [Y/n]: n
OAuth is obtained at report time: launchpadlib opens a browser and
stores the token in your system keyring, or reads it from a file.
Credentials file (empty to use the system keyring):
Add GitHub? [y/N]: y
GitHub username: vhaudiquet
Leave the token empty to fall back to $GITHUB_TOKEN or `gh auth token`.
GitHub token (input hidden):
Add GitLab? [y/N]: y
GitLab username: vhaudiquet
Instance URL [https://gitlab.com]: https://debian.....
Leave the token empty to discover it from the environment instead.
API token (input hidden):
Env var holding the token (optional, e.g. SALSA_TOKEN):
Add Debian BTS? [y/N]: y
The BTS identifies people by the email used on bugs (submitter/owner).
Email address on Debian bugs: v
Configuration written to /home/vhaudiquet/.config/weekly-activity.toml.
Enabled sources: launchpad, github, gitlab, bts.
launchpad: vhaudiquet — OAuth via system keyring
github: vhaudiquet — token not stored (uses GITHUB_TOKEN / gh)
gitlab: vhaudiquet @ https://debian..... — token not stored (uses <HOST>_TOKEN / GITLAB_TOKEN env)
bts: v
Tokens are never printed back. Run `weekly-activity report` to
aggregate activity across all of them in one output.
```
Two issues with this:
- I would like it more in the following way
```
$ weekly-activity config
Current sources: <empty>
**> Add a new source**
> Exit
Which source do you want to add?
**> Add new GitHub account**
> Add new Launchpad account
> Add new Gitlab instance/account
> Add new Debian BTS email
...
```
Does that make sense? This way we allow multiple instances and accounts, and we have a nice UI/UX :)
This will need to change the config format as well.
- Another issue: this says that launchpad login will be done at report-time. Why can't we store the login once at config-time and be done with it?
Thanks for the review — both points are clear and I agree. Quick summary of what I'll do, plus one design question on the Launchpad flow before I wire it up.
1. Menu-driven wizard + multi-account config. I'll replace the linear walk-through with the navigable menu you sketched (Current sources → Add a new source → which kind → configure → back; plus remove/exit), and change the config schema from one section per source to arrays of accounts so multiple instances/accounts per provider are supported. Proposed TOML shape (v2, with a version key so old files can be migrated):
(report will aggregate across every account; source blocks get the account label when there's more than one.) If you'd prefer a different shape — e.g. [sources.github] namespace or per-account [[accounts]] objects — say so and I'll adjust before implementing.
2. Launchpad login at config-time. Fair point — no reason to defer it. I'll change the wizard so that when you pick a non-anonymous Launchpad account, it runs launchpadlib's OAuth flow right there (opens the browser once, stores the token in the keyring or a credentials file) and marks the account as authenticated, instead of leaving auth for report time. One question: for the non-interactive/CI case it may still make sense to accept a pre-existing credentials_file path instead of forcing a browser — keep that as an option alongside the in-wizard OAuth? That's the only open question; everything else I'll build as described.
Thanks for the review — both points are clear and I agree. Quick summary of what I'll do, plus one design question on the Launchpad flow before I wire it up.
**1. Menu-driven wizard + multi-account config.** I'll replace the linear walk-through with the navigable menu you sketched (Current sources → Add a new source → which kind → configure → back; plus remove/exit), and change the config schema from one section per source to arrays of accounts so multiple instances/accounts per provider are supported. Proposed TOML shape (v2, with a `version` key so old files can be migrated):
```toml
version = 2
[[launchpad.accounts]]
name = "work" # optional display label
username = "jane"
[[github.accounts]]
name = "personal"
username = "octocat"
token_env = "GITHUB_TOKEN"
[[github.accounts]]
name = "work"
username = "acme-jane"
token = "ghp_..." # optional; stored plaintext, 0600
[[gitlab.accounts]]
name = "salsa"
url = "https://salsa.debian.org"
username = "jane"
token_env = "SALSA_TOKEN"
[[bts.accounts]]
name = "personal"
email = "jane@example.org"
```
(`report` will aggregate across every account; source blocks get the account label when there's more than one.) If you'd prefer a different shape — e.g. `[sources.github]` namespace or per-account `[[accounts]]` objects — say so and I'll adjust before implementing.
**2. Launchpad login at config-time.** Fair point — no reason to defer it. I'll change the wizard so that when you pick a non-anonymous Launchpad account, it runs launchpadlib's OAuth flow right there (opens the browser once, stores the token in the keyring or a credentials file) and marks the account as authenticated, instead of leaving auth for `report` time. One question: for the non-interactive/CI case it may still make sense to accept a pre-existing `credentials_file` path instead of forcing a browser — keep that as an option alongside the in-wizard OAuth? That's the only open question; everything else I'll build as described.
One question: for the non-interactive/CI case it may still make sense to accept a pre-existing credentials_file path instead of forcing a browser — keep that as an option alongside the in-wizard OAuth?
Yes, please.
That sounds ok.
> One question: for the non-interactive/CI case it may still make sense to accept a pre-existing credentials_file path instead of forcing a browser — keep that as an option alongside the in-wizard OAuth?
Yes, please.
Address review of PR #1 (Valentin): replace the linear config walk-through
and single-section schema.
- weekly-activity config becomes a menu loop: Current sources (masked) ->
Add a new source (pick kind, repeatable) / Remove a source / Exit; the
file is written only when something changed
- new versioned config layout (version = 2): [[kind.accounts]] arrays so
several accounts or instances per provider coexist; optional display
labels; strict unknown-key/type validation kept (errors carry account
position, e.g. [github.accounts[1]])
- legacy v1 files (no version key, one section per source) migrate
transparently in memory on load; saving from the wizard persists v2;
the file itself is never rewritten by load_config
- non-anonymous Launchpad accounts now authenticate at config time:
constructing LaunchpadSource runs launchpadlib's browser OAuth and the
token lands in the system keyring before any report; an explicit
credentials_file stays supported as an additive opt-out
- report aggregates every configured account in stable order with failure
isolation intact; headings add the account label when it disambiguates
(source_label shared between aggregate and wizard)
- GitHub accounts gain optional token_env resolved lazily against the
environment before falling back to GITHUB_TOKEN / `gh auth token`
Both review points are now addressed and pushed (commit 5f4487f), and I verified everything locally before handing back:
1. Menu-driven wizard + multi-account config — weekly-activity config is now a menu loop (Current sources → Add a new source / Remove a source / Exit, file written only on change). Config schema is now v2 with per-provider [[kind.accounts]] arrays (#accounts are in their own block):
Legacy v1 files (no version key) migrate transparently in memory on load; the file is only rewritten as v2 when the wizard saves. report aggregates across every account and adds the account label to headings when it disambiguates.
2. Launchpad login at config-time — picking a non-anonymous Launchpad account now runs launchpadlib's browser OAuth right in the wizard, so the token lands in the system keyring before any report ever runs. Per your note, an explicit credentials_file path stays available as an opt-out for the non-interactive/CI case.
Verification (all local):ruff format --check src ✓, ruff check src ✓, ty check ✓, and the test suite grew from 16 → 34 cases, all passing (uv run python -m unittest discover -s tests). README documents the v2 schema and menu flow.
Also bumped requested reviewer to @vhaudiquet so you can re-review when ready.
Both review points are now addressed and pushed (commit `5f4487f`), and I verified everything locally before handing back:
**1. Menu-driven wizard + multi-account config** — `weekly-activity config` is now a menu loop (Current sources → **Add a new source** / **Remove a source** / **Exit**, file written only on change). Config schema is now v2 with per-provider `[[kind.accounts]]` arrays (#accounts are in their own block):
```toml
version = 2
[[launchpad.accounts]]
name = "work"
username = "jane"
[[github.accounts]]
name = "personal"
username = "octocat"
token_env = "GITHUB_TOKEN"
```
Legacy v1 files (no `version` key) migrate transparently in memory on load; the file is only rewritten as v2 when the wizard saves. `report` aggregates across every account and adds the account label to headings when it disambiguates.
**2. Launchpad login at config-time** — picking a non-anonymous Launchpad account now runs launchpadlib's browser OAuth right in the wizard, so the token lands in the system keyring before any report ever runs. Per your note, an explicit `credentials_file` path stays available as an opt-out for the non-interactive/CI case.
**Verification (all local):** `ruff format --check src` ✓, `ruff check src` ✓, `ty check` ✓, and the test suite grew from 16 → **34** cases, all passing (`uv run python -m unittest discover -s tests`). README documents the v2 schema and menu flow.
Also bumped requested reviewer to @vhaudiquet so you can re-review when ready.
For the menu-driven flow, I would much rather like having options with keyboard navigation:
**> Option 1** (bold, currently selected, shown with `>`)
Option 2
Option 3
Is that possible?
When I run weekly-activity report, it hangs until the report is generated (it seems), which can take time. Please add user-facing temporary loading messages / a loading animation with the current task (i.e. which source it is aggregating data from) that would be cleared once the report is done.
Looks much better. Two small things
- For the menu-driven flow, I would much rather like having options with keyboard navigation:
```
**> Option 1** (bold, currently selected, shown with `>`)
Option 2
Option 3
```
Is that possible?
- When I run `weekly-activity report`, it hangs until the report is generated (it seems), which can take time. Please add user-facing temporary loading messages / a loading animation with the current task (i.e. which source it is aggregating data from) that would be cleared once the report is done.
```
$ weekly-activity report
# Generating report: pulling Launchpad data...
```
which would go to, once finished,
```
$ weekly-activity report
Report for ...
....
```
(message cleared and disappeared)
wizard: when stdin and stdout are both TTYs, menus render inline and
are driven by keys: up/down/j/k/Home/End move the bold '>' highlight,
Enter accepts, Esc/Ctrl-C/q back out of cancellable menus while Ctrl-C
on fixed menus still aborts. Rows redraw with erase+CR across the
option block only and clear before returning so prompts stay aligned.
Non-TTY stdio keeps the original numbered prompt verbatim.
report: each configured source shows a transient "# Generating
report: pulling <name> data..." line that is erased on completion,
only when stdout is a TTY; piped output remains exactly the report.
tests: cover the numbered fallback, row rendering, status suppression
and show+clear parity; reformat stray test files to satisfy ruff.
Both comments from your latest review are addressed and pushed (commit 85ddfb4).
1. Arrow-key menu navigation — when stdin and stdout are both TTYs, the config menus render inline and are keyboard-driven: Up/Down (and j/k) move the highlight, Home/End jump to first/last, Enter accepts, and Esc/Ctrl-C/q back out of cancellable menus (Ctrl-C still aborts fixed ones). The selected row is bold with a > marker, exactly like your sketch. Non-TTY stdio keeps the original numbered prompt, so piped/scripted use is unchanged.
2. Report loading status — weekly-activity report now shows a transient # Generating report: pulling <name> data... line for each source, erased as each finishes and gone entirely by the time the final report prints. It activates only when stdout is a TTY; piped output stays exactly the report with no status noise.
Verification: ruff format --check, ruff check, and ty check all pass; the test suite grew to 42 cases, all green via uv run python -m unittest discover -s tests. Ready for your re-review whenever you are.
Both comments from your latest review are addressed and pushed (commit `85ddfb4`).
**1. Arrow-key menu navigation** — when stdin and stdout are both TTYs, the `config` menus render inline and are keyboard-driven: Up/Down (and j/k) move the highlight, Home/End jump to first/last, Enter accepts, and Esc/Ctrl-C/q back out of cancellable menus (Ctrl-C still aborts fixed ones). The selected row is bold with a `>` marker, exactly like your sketch. Non-TTY stdio keeps the original numbered prompt, so piped/scripted use is unchanged.
**2. Report loading status** — `weekly-activity report` now shows a transient `# Generating report: pulling <name> data...` line for each source, erased as each finishes and gone entirely by the time the final report prints. It activates only when stdout is a TTY; piped output stays exactly the report with no status noise.
Verification: `ruff format --check`, `ruff check`, and `ty check` all pass; the test suite grew to **42** cases, all green via `uv run python -m unittest discover -s tests`. Ready for your re-review whenever you are.
What do you want to do?
> Add a new source
Remove a source
Exit
This looks nice, but now keyboard navigation does not work :(
Pressing arrow keys does not move.
Did you use a library for this or implement all the logic yourself?
Perhaps using a known good library would eliminate bugs and speed up the process?
```
What do you want to do?
> Add a new source
Remove a source
Exit
```
This looks nice, but now keyboard navigation does not work :(
Pressing arrow keys does not move.
Did you use a library for this or implement all the logic yourself?
Perhaps using a known good library would eliminate bugs and speed up the process?
sys.stdin.read(1) on the buffered TextIOWrapper pulls the whole escape
sequence into its Python-level buffer, so the follow-up select() sees an
empty fd and every arrow/Home/End press degrades to bare Esc; the unread
'[B' tail then leaks into the next keypress. Read raw bytes via os.read()
and select() on the file descriptor instead, keeping the same key tokens
and classifications. Add pty-driven regression tests over a real cbreak
terminal covering CSI sequences, single-byte keys, bare Esc, and tail-leak.
vhaudiquet
approved these changes 2026-08-27 08:23:37 +00:00
Thanks for the approval! 🎉 The PR is green and mergeable on head 12ca06b.
One housekeeping note: I accidentally double-posted the same summary-commit note earlier (comments #145 and #146) — I removed the redundant copy (#146) so the thread stays clean for the record.
Merging is on your side since the kosmos account doesn't have merge permission on this repo. Whenever you're ready, feel free to hit merge (any style works — squash/rebase both fine).
Thanks for the approval! 🎉 The PR is green and mergeable on head `12ca06b`.
One housekeeping note: I accidentally double-posted the same summary-commit note earlier (comments #145 and #146) — I removed the redundant copy (#146) so the thread stays clean for the record.
Merging is on your side since the `kosmos` account doesn't have merge permission on this repo. Whenever you're ready, feel free to hit merge (any style works — squash/rebase both fine).
The reviewer asked for a known-good interactive-menu library instead of
the custom termios/select key reader; arrow keys had failed in their
terminal. The TTY path now delegates to questionary.select (pointer ">",
bold highlight via pointer/selected styles), keeping choice values mapped
to list indices. Cancellable menus graft an eager Escape binding onto the
prompt's own key-binding registry so Esc backs out while Ctrl-C still
aborts fixed menus and backs out of cancellable ones. The non-TTY
numbered fallback is untouched, and hand-rolled internals
(_arrow_menu/_read_keypress/_option_line/_draw_menu_rows) are gone.
Follow-up on your questionary suggestion (#147): pushed daf0a20 — refactor(wizard): replace hand-rolled arrow-key menu with questionary.
I swapped the custom termios/select key reader for questionary.select (the known-good library you hinted at). Arrow/navigation keys are now handled by prompt-toolkit, so the > + bold highlight and Up/Down (j/k)/Home/End/Enter all work reliably across terminals — the same reason the hand-rolled version broke for you. Esc still backs out of cancellable menus and Ctrl-C aborts fixed ones; the non-TTY numbered fallback is unchanged. New dep is questionary>=2.1.1 in pyproject.
Verification on the new head daf0a20: uv sync --frozen ✓, ruff format --check ✓, ruff check ✓, ty check ✓, uv build ✓, and 48 unit tests pass (uv run python -m unittest discover -s tests). Author identity is Kosmos on every commit in the PR.
This bumps the head past your earlier approval on 12ca06b, so it’ll need a fresh approve/merge on your side whenever you’re ready. I can’t merge from the kosmos account, so the green button is yours — squash or rebase both fine. 👍🎉
Follow-up on your questionary suggestion (#147): pushed `daf0a20` — `refactor(wizard): replace hand-rolled arrow-key menu with questionary`.
I swapped the custom termios/select key reader for `questionary.select` (the known-good library you hinted at). Arrow/navigation keys are now handled by prompt-toolkit, so the `>` + bold highlight and Up/Down (j/k)/Home/End/Enter all work reliably across terminals — the same reason the hand-rolled version broke for you. Esc still backs out of cancellable menus and Ctrl-C aborts fixed ones; the non-TTY numbered fallback is unchanged. New dep is `questionary>=2.1.1` in pyproject.
Verification on the new head `daf0a20`: `uv sync --frozen` ✓, `ruff format --check` ✓, `ruff check` ✓, `ty check` ✓, `uv build` ✓, and 48 unit tests pass (`uv run python -m unittest discover -s tests`). Author identity is Kosmos on every commit in the PR.
This bumps the head past your earlier approval on `12ca06b`, so it’ll need a fresh approve/merge on your side whenever you’re ready. I can’t merge from the `kosmos` account, so the green button is yours — squash or rebase both fine. 👍🎉
vhaudiquet
approved these changes 2026-08-27 08:45:02 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
Adds an onboarding flow and an aggregated report to
weekly-activity:weekly-activity config— interactive wizard that prompts for whichsources to enable (launchpad / github / gitlab / bts) and the identity +
auth for each (usernames, emails, tokens). Writes
~/.config/weekly-activity.toml(owner-only0600, tokens never echoed).Re-running shows current settings and pre-fills defaults.
weekly-activity report(bareweekly-activityis an alias) — reads theconfig, runs every enabled source over the same window, and aggregates the
results into one text report. A failing source is rendered as
[skipped: <source> — error]without aborting the rest.Existing single-source subcommands (
launchpad,github,gitlab,bts)are unchanged and backward compatible.
Details
config.py(typed schema, stricttomllibloader,hand-formatted TOML writer — no new dependency),
wizard.py(interactiveonboarding),
aggregate.py(spec building + per-source collection +combined render).
cli.pygainedreport/configsubcommands;--config PATHoverrides thelocation on both.
unittestcases added (round-trip/escaping, strict validation,0600 perms, spec mapping, failure isolation). Repo CI (ruff format/lint +
ty check) passes; tests run viauv run python -m unittest discover -s tests.Implementer report for reviewers:
reports/weekly-activity-onboarding/implementation-report.md(in Kosmos' workspace).Verification
uv sync --frozen,ruff format --check src,ruff check src,ty check,and the 16 unit tests all pass locally. Wizard and report smoke-tested live.
453a03c10ato6d8cc3d817Right now the config flow is as follows:
Two issues with this:
I would like it more in the following way
Does that make sense? This way we allow multiple instances and accounts, and we have a nice UI/UX :)
This will need to change the config format as well.
Another issue: this says that launchpad login will be done at report-time. Why can't we store the login once at config-time and be done with it?
Please apply changes in my above comment.
Thanks for the review — both points are clear and I agree. Quick summary of what I'll do, plus one design question on the Launchpad flow before I wire it up.
1. Menu-driven wizard + multi-account config. I'll replace the linear walk-through with the navigable menu you sketched (Current sources → Add a new source → which kind → configure → back; plus remove/exit), and change the config schema from one section per source to arrays of accounts so multiple instances/accounts per provider are supported. Proposed TOML shape (v2, with a
versionkey so old files can be migrated):(
reportwill aggregate across every account; source blocks get the account label when there's more than one.) If you'd prefer a different shape — e.g.[sources.github]namespace or per-account[[accounts]]objects — say so and I'll adjust before implementing.2. Launchpad login at config-time. Fair point — no reason to defer it. I'll change the wizard so that when you pick a non-anonymous Launchpad account, it runs launchpadlib's OAuth flow right there (opens the browser once, stores the token in the keyring or a credentials file) and marks the account as authenticated, instead of leaving auth for
reporttime. One question: for the non-interactive/CI case it may still make sense to accept a pre-existingcredentials_filepath instead of forcing a browser — keep that as an option alongside the in-wizard OAuth? That's the only open question; everything else I'll build as described.That sounds ok.
Yes, please.
Both review points are now addressed and pushed (commit
5f4487f), and I verified everything locally before handing back:1. Menu-driven wizard + multi-account config —
weekly-activity configis now a menu loop (Current sources → Add a new source / Remove a source / Exit, file written only on change). Config schema is now v2 with per-provider[[kind.accounts]]arrays (#accounts are in their own block):Legacy v1 files (no
versionkey) migrate transparently in memory on load; the file is only rewritten as v2 when the wizard saves.reportaggregates across every account and adds the account label to headings when it disambiguates.2. Launchpad login at config-time — picking a non-anonymous Launchpad account now runs launchpadlib's browser OAuth right in the wizard, so the token lands in the system keyring before any report ever runs. Per your note, an explicit
credentials_filepath stays available as an opt-out for the non-interactive/CI case.Verification (all local):
ruff format --check src✓,ruff check src✓,ty check✓, and the test suite grew from 16 → 34 cases, all passing (uv run python -m unittest discover -s tests). README documents the v2 schema and menu flow.Also bumped requested reviewer to @vhaudiquet so you can re-review when ready.
Looks much better. Two small things
weekly-activity report, it hangs until the report is generated (it seems), which can take time. Please add user-facing temporary loading messages / a loading animation with the current task (i.e. which source it is aggregating data from) that would be cleared once the report is done.Both comments from your latest review are addressed and pushed (commit
85ddfb4).1. Arrow-key menu navigation — when stdin and stdout are both TTYs, the
configmenus render inline and are keyboard-driven: Up/Down (and j/k) move the highlight, Home/End jump to first/last, Enter accepts, and Esc/Ctrl-C/q back out of cancellable menus (Ctrl-C still aborts fixed ones). The selected row is bold with a>marker, exactly like your sketch. Non-TTY stdio keeps the original numbered prompt, so piped/scripted use is unchanged.2. Report loading status —
weekly-activity reportnow shows a transient# Generating report: pulling <name> data...line for each source, erased as each finishes and gone entirely by the time the final report prints. It activates only when stdout is a TTY; piped output stays exactly the report with no status noise.Verification:
ruff format --check,ruff check, andty checkall pass; the test suite grew to 42 cases, all green viauv run python -m unittest discover -s tests. Ready for your re-review whenever you are.This looks nice, but now keyboard navigation does not work :(
Pressing arrow keys does not move.
Did you use a library for this or implement all the logic yourself?
Perhaps using a known good library would eliminate bugs and speed up the process?
This looks great, thanks.
Thanks for the approval! 🎉 The PR is green and mergeable on head
12ca06b.One housekeeping note: I accidentally double-posted the same summary-commit note earlier (comments #145 and #146) — I removed the redundant copy (#146) so the thread stays clean for the record.
Merging is on your side since the
kosmosaccount doesn't have merge permission on this repo. Whenever you're ready, feel free to hit merge (any style works — squash/rebase both fine).Follow-up on your questionary suggestion (#147): pushed
daf0a20—refactor(wizard): replace hand-rolled arrow-key menu with questionary.I swapped the custom termios/select key reader for
questionary.select(the known-good library you hinted at). Arrow/navigation keys are now handled by prompt-toolkit, so the>+ bold highlight and Up/Down (j/k)/Home/End/Enter all work reliably across terminals — the same reason the hand-rolled version broke for you. Esc still backs out of cancellable menus and Ctrl-C aborts fixed ones; the non-TTY numbered fallback is unchanged. New dep isquestionary>=2.1.1in pyproject.Verification on the new head
daf0a20:uv sync --frozen✓,ruff format --check✓,ruff check✓,ty check✓,uv build✓, and 48 unit tests pass (uv run python -m unittest discover -s tests). Author identity is Kosmos on every commit in the PR.This bumps the head past your earlier approval on
12ca06b, so it’ll need a fresh approve/merge on your side whenever you’re ready. I can’t merge from thekosmosaccount, so the green button is yours — squash or rebase both fine. 👍🎉Looks much better. Merging.