gem-contribute 0.2.0 → 0.3.1
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.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE.md +14 -8
- data/.github/workflows/ci.yml +26 -0
- data/.github/workflows/pr-template-check.yml +100 -0
- data/.github/workflows/release.yml +71 -0
- data/CHANGELOG.md +38 -0
- data/CLAUDE.md +1 -1
- data/CONTRIBUTING.md +10 -4
- data/MAINTAINER.md +119 -2
- data/README.md +13 -1
- data/docs/OPEN_QUESTIONS.md +167 -0
- data/docs/ROADMAP.md +266 -0
- data/docs/adr/0006-standalone-gem-not-plugin.md +1 -1
- data/docs/adr/0008-rooibos-tui-framework.md +3 -3
- data/docs/adr/0010-charm-ruby-tui-framework.md +2 -2
- data/docs/adr/0011-host-adapter-owns-host-verbs.md +58 -0
- data/docs/adr/0012-output-free-service-objects-three-interface-architecture.md +79 -0
- data/docs/adr/0013-revert-to-rooibos.md +71 -0
- data/docs/adr/0014-ship-bundler-and-rubygems-plugins.md +75 -0
- data/docs/adr/README.md +7 -3
- data/docs/design-interface-layer.md +295 -0
- data/docs/design.md +31 -8
- data/docs/index.md +1 -1
- data/docs/prep-plan.md +6 -6
- data/lib/gem_contribute/cli/auth.rb +22 -44
- data/lib/gem_contribute/cli/config.rb +29 -15
- data/lib/gem_contribute/cli/fix.rb +122 -0
- data/lib/gem_contribute/cli/fork.rb +145 -0
- data/lib/gem_contribute/cli/init.rb +19 -24
- data/lib/gem_contribute/cli/issue_announcer.rb +42 -0
- data/lib/gem_contribute/cli/issues.rb +36 -47
- data/lib/gem_contribute/cli/platform_tools.rb +33 -0
- data/lib/gem_contribute/cli/post_clone_hooks.rb +50 -0
- data/lib/gem_contribute/cli/rate_limit_footer.rb +5 -3
- data/lib/gem_contribute/cli/scan.rb +20 -16
- data/lib/gem_contribute/cli/submit.rb +60 -64
- data/lib/gem_contribute/cli/workflow.rb +63 -0
- data/lib/gem_contribute/cli.rb +9 -16
- data/lib/gem_contribute/config.rb +27 -1
- data/lib/gem_contribute/git.rb +49 -0
- data/lib/gem_contribute/host_adapter.rb +52 -5
- data/lib/gem_contribute/host_adapters/github_adapter.rb +126 -37
- data/lib/gem_contribute/operations/announce.rb +52 -0
- data/lib/gem_contribute/operations/branch.rb +35 -0
- data/lib/gem_contribute/operations/clone.rb +41 -0
- data/lib/gem_contribute/operations/fix_pipeline.rb +70 -0
- data/lib/gem_contribute/operations/fork.rb +35 -0
- data/lib/gem_contribute/output/null.rb +20 -0
- data/lib/gem_contribute/output/standard.rb +71 -0
- data/lib/gem_contribute/version.rb +1 -1
- data/lib/gem_contribute.rb +10 -18
- metadata +115 -5
- data/lib/gem_contribute/cli/fork_clone_branch.rb +0 -204
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 642744289b8e25b5109868d7ef71fbb33e7067d79d8fb9c6580e8a88b566dea6
|
|
4
|
+
data.tar.gz: d2e5cca3a504bd75de537e9b38ba22a0ff2f2b6915162cb9d37f5d065933cc72
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a2600e3b0ee2adf44fcadab52639e446aae0d15f7d4843c111d68d86b3fd726bed20d72ad62063c72230656cdf8c62a52d7fc1507b7e5fb85032678f77ae99a7
|
|
7
|
+
data.tar.gz: 1f208fe93824d839c8ca78cf842a5cc0fcbebcf3c9b4f89cf8d9fcdd1c403ce19b9b1f0c1e664b1a3b5d681e45f80559e8c333d3ba752111e64726b633491ed9
|
|
@@ -2,21 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- One or two sentences. What changes, and why. The "why" is the part that's hard to recover later. -->
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Linked issue / ADR
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<!--
|
|
8
|
+
Issue # this closes (or "none — drive-by fix").
|
|
9
|
+
For non-trivial changes: which ADR(s) does this touch? If you skipped that step, write "no ADR" plus a one-line reason.
|
|
10
|
+
-->
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
- [ ] **Full review, please.** Feedback on style, naming, idioms, and alternative designs welcome. I want the deep version, whether to learn the Ruby way or to stress-test a pattern I'm trying.
|
|
11
|
-
|
|
12
|
-
## Working agreement check
|
|
12
|
+
## Working agreement
|
|
13
13
|
|
|
14
14
|
- [ ] Single concern (multi-concern PRs get bounced — see [CLAUDE.md](../CLAUDE.md))
|
|
15
|
-
- [ ] ADRs touched: <!-- list ADR numbers, or "none" -->
|
|
16
15
|
- [ ] `bin/rubocop` and `bin/rspec` pass locally
|
|
17
16
|
- [ ] New behavior has a test; bug fix has a regression test
|
|
18
17
|
- [ ] Async work goes through Rooibos Commands (no direct threads / `Async` / synchronous shellouts)
|
|
19
18
|
|
|
19
|
+
## Test plan
|
|
20
|
+
|
|
21
|
+
<!--
|
|
22
|
+
How was this verified? Spec output, manual smoke, screenshots — whatever applies.
|
|
23
|
+
"`bin/rspec` passes" is the floor, not a test plan.
|
|
24
|
+
-->
|
|
25
|
+
|
|
20
26
|
## Notes for reviewer
|
|
21
27
|
|
|
22
|
-
<!-- Tradeoffs, open questions, follow-ups — anything not obvious from the diff. -->
|
|
28
|
+
<!-- Tradeoffs, open questions, follow-ups — anything not obvious from the diff. Delete the section if there's nothing to add. -->
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
name: Specs and Rubocop
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Ruby
|
|
17
|
+
uses: ruby/setup-ruby@v1
|
|
18
|
+
with:
|
|
19
|
+
ruby-version: "3.2"
|
|
20
|
+
bundler-cache: true
|
|
21
|
+
|
|
22
|
+
- name: Run specs
|
|
23
|
+
run: bin/rspec
|
|
24
|
+
|
|
25
|
+
- name: Run rubocop
|
|
26
|
+
run: bin/rubocop
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: PR template check
|
|
2
|
+
|
|
3
|
+
# Verifies that PR descriptions include all required sections from
|
|
4
|
+
# .github/PULL_REQUEST_TEMPLATE.md. Posts (or updates) a single comment
|
|
5
|
+
# listing what's missing, and fails the check until the body is fixed.
|
|
6
|
+
#
|
|
7
|
+
# Security note: pull_request_target gives us write access to comment
|
|
8
|
+
# back on the PR. We never check out PR HEAD; the body is read via the
|
|
9
|
+
# event payload (data, not code).
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
pull_request_target:
|
|
13
|
+
types: [opened, edited, reopened, synchronize]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
pull-requests: write
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
template-check:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- name: Verify required sections
|
|
23
|
+
env:
|
|
24
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
25
|
+
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
26
|
+
REPO: ${{ github.repository }}
|
|
27
|
+
PR_BODY: ${{ github.event.pull_request.body }}
|
|
28
|
+
run: |
|
|
29
|
+
set -euo pipefail
|
|
30
|
+
|
|
31
|
+
MARKER="<!-- pr-template-check -->"
|
|
32
|
+
|
|
33
|
+
# Required headings — must appear verbatim somewhere in the body.
|
|
34
|
+
required=(
|
|
35
|
+
"## Summary"
|
|
36
|
+
"## Linked issue / ADR"
|
|
37
|
+
"## Working agreement"
|
|
38
|
+
"## Test plan"
|
|
39
|
+
)
|
|
40
|
+
# "## Notes for reviewer" is intentionally optional — the template
|
|
41
|
+
# tells contributors to delete it when there's nothing to add.
|
|
42
|
+
|
|
43
|
+
missing=()
|
|
44
|
+
for heading in "${required[@]}"; do
|
|
45
|
+
if ! grep -Fq "$heading" <<< "${PR_BODY:-}"; then
|
|
46
|
+
missing+=("$heading")
|
|
47
|
+
fi
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
# Strip HTML comments and template placeholder text, then check
|
|
51
|
+
# the body has *some* substance. Catches PRs filed with the raw
|
|
52
|
+
# unmodified template.
|
|
53
|
+
stripped=$(printf '%s' "${PR_BODY:-}" | perl -0777 -pe 's/<!--.*?-->//gs')
|
|
54
|
+
# Drop heading lines and checklist scaffolding; what's left should
|
|
55
|
+
# be the contributor's own prose.
|
|
56
|
+
prose=$(printf '%s' "$stripped" | grep -Ev '^\s*(##|- \[[ x]\]|$)' || true)
|
|
57
|
+
prose_chars=$(printf '%s' "$prose" | tr -d '[:space:]' | wc -c | tr -d ' ')
|
|
58
|
+
|
|
59
|
+
# Find any prior bot comment so we can edit instead of stacking.
|
|
60
|
+
prior_id=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" \
|
|
61
|
+
--jq ".[] | select(.user.login == \"github-actions[bot]\" and (.body | contains(\"$MARKER\"))) | .id" \
|
|
62
|
+
| head -n1)
|
|
63
|
+
|
|
64
|
+
if [ ${#missing[@]} -eq 0 ] && [ "$prose_chars" -ge 40 ]; then
|
|
65
|
+
echo "PR body looks good."
|
|
66
|
+
if [ -n "$prior_id" ]; then
|
|
67
|
+
gh api -X PATCH "repos/$REPO/issues/comments/$prior_id" \
|
|
68
|
+
-f body="$MARKER
|
|
69
|
+
✅ PR template check passed. Thanks for filling out the template."
|
|
70
|
+
fi
|
|
71
|
+
exit 0
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
echo "$MARKER"
|
|
76
|
+
echo "👋 This PR is missing pieces from the [PR template](https://github.com/$REPO/blob/main/.github/PULL_REQUEST_TEMPLATE.md):"
|
|
77
|
+
echo ""
|
|
78
|
+
if [ ${#missing[@]} -gt 0 ]; then
|
|
79
|
+
echo "**Missing sections:**"
|
|
80
|
+
for m in "${missing[@]}"; do
|
|
81
|
+
echo "- \`$m\`"
|
|
82
|
+
done
|
|
83
|
+
echo ""
|
|
84
|
+
fi
|
|
85
|
+
if [ "$prose_chars" -lt 40 ]; then
|
|
86
|
+
echo "**Body looks unfilled** — the template comments are still there but no actual content has been written. Please fill in at least the Summary and Test plan."
|
|
87
|
+
echo ""
|
|
88
|
+
fi
|
|
89
|
+
echo "Edit the PR description (no new commit needed) and the check will re-run automatically. See [CLAUDE.md](https://github.com/$REPO/blob/main/CLAUDE.md) for why these sections matter."
|
|
90
|
+
} > /tmp/comment.md
|
|
91
|
+
|
|
92
|
+
if [ -n "$prior_id" ]; then
|
|
93
|
+
gh api -X PATCH "repos/$REPO/issues/comments/$prior_id" \
|
|
94
|
+
-F body=@/tmp/comment.md
|
|
95
|
+
else
|
|
96
|
+
gh pr comment "$PR_NUMBER" --repo "$REPO" --body-file /tmp/comment.md
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
echo "::error::PR template is incomplete — see the bot comment on the PR."
|
|
100
|
+
exit 1
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Triggers on `v*` tag pushes (e.g. `v0.4.0`). Verifies the tag matches
|
|
4
|
+
# `GemContribute::VERSION` and that CHANGELOG.md has a dated section for
|
|
5
|
+
# it, then runs rubocop + rspec as a final gate and publishes to
|
|
6
|
+
# rubygems.org via Trusted Publishing (OIDC). No `RUBYGEMS_API_KEY`
|
|
7
|
+
# secret — the rubygems.org-side trusted-publisher entry mints a
|
|
8
|
+
# short-lived token from the GitHub Actions OIDC claim. Compatible with
|
|
9
|
+
# `rubygems_mfa_required = true`, which the gemspec already sets.
|
|
10
|
+
#
|
|
11
|
+
# First-run setup (one-time, before the first tag push): see
|
|
12
|
+
# MAINTAINER.md → "Cutting a release". The rubygems.org Trusted
|
|
13
|
+
# Publisher entry must exist before this workflow can succeed.
|
|
14
|
+
#
|
|
15
|
+
# The `release` environment scopes the OIDC claim — only workflow runs
|
|
16
|
+
# in that environment can authenticate to rubygems.org. Configure it at
|
|
17
|
+
# Settings → Environments in the GitHub repo (no secrets, no protection
|
|
18
|
+
# rules required, but adding a "required reviewer" gives a manual
|
|
19
|
+
# approval gate before publishes).
|
|
20
|
+
|
|
21
|
+
on:
|
|
22
|
+
push:
|
|
23
|
+
tags:
|
|
24
|
+
- 'v*'
|
|
25
|
+
|
|
26
|
+
permissions:
|
|
27
|
+
contents: write # create the GitHub release with auto-generated notes
|
|
28
|
+
id-token: write # request OIDC token for Trusted Publishing
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
release:
|
|
32
|
+
name: Build, test, and publish
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
environment: release
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
|
|
38
|
+
- name: Set up Ruby
|
|
39
|
+
uses: ruby/setup-ruby@v1
|
|
40
|
+
with:
|
|
41
|
+
ruby-version: "3.2"
|
|
42
|
+
bundler-cache: true
|
|
43
|
+
|
|
44
|
+
- name: Verify tag matches gemspec version and CHANGELOG section
|
|
45
|
+
env:
|
|
46
|
+
REF_NAME: ${{ github.ref_name }}
|
|
47
|
+
run: |
|
|
48
|
+
set -euo pipefail
|
|
49
|
+
tag_version="${REF_NAME#v}"
|
|
50
|
+
gem_version=$(ruby -r./lib/gem_contribute/version -e 'print GemContribute::VERSION')
|
|
51
|
+
|
|
52
|
+
if [ "$tag_version" != "$gem_version" ]; then
|
|
53
|
+
echo "::error::Tag $REF_NAME does not match GemContribute::VERSION ($gem_version)."
|
|
54
|
+
echo "Bump lib/gem_contribute/version.rb or retag, then push."
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if ! grep -Fq "## [$gem_version]" CHANGELOG.md; then
|
|
59
|
+
echo "::error::CHANGELOG.md is missing a '## [$gem_version]' section."
|
|
60
|
+
echo "Add a dated section before tagging — see existing entries for the shape."
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
- name: rubocop
|
|
65
|
+
run: bin/rubocop
|
|
66
|
+
|
|
67
|
+
- name: rspec
|
|
68
|
+
run: bin/rspec
|
|
69
|
+
|
|
70
|
+
- name: Publish to rubygems.org via Trusted Publishing
|
|
71
|
+
uses: rubygems/release-gem@v1
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,44 @@ All notable changes to this project will be documented here. The format is based
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.3.1] - 2026-05-04
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Release workflow (`.github/workflows/release.yml`) — `v*` tag push triggers a publish to rubygems.org via [Trusted Publishing](https://guides.rubygems.org/trusted-publishing/) (OIDC). No `RUBYGEMS_API_KEY` secret involved; rubygems.org issues a short-lived token from the GitHub Actions OIDC claim. The workflow verifies the tag matches `GemContribute::VERSION` and that `CHANGELOG.md` has a dated section for it before running rubocop, rspec, and the publish step. First-time setup (rubygems.org pending-trusted-publisher entry, `release` GitHub Environment) is documented in `MAINTAINER.md` (closes [#44](https://github.com/cdhagmann/gem-contribute/issues/44)).
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- `Gemfile.lock` regenerated to match `GemContribute::VERSION` after the 0.3.0 bump (commit `077eadb`) updated `version.rb` without running `bundle install`. CI runs bundler in deployment mode and was failing on the lockfile/gemspec mismatch. The MAINTAINER.md per-release checklist now calls out `bundle install` as an explicit step so the next bump doesn't repeat this.
|
|
16
|
+
|
|
17
|
+
## [0.3.0] - 2026-05-04
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `gem-contribute fork <gem>` — the look-around-first counterpart to `fix`: fork the gem's repo, clone it, leave you on the default branch with no issue-tied work yet. Same `-e` / `-a` flags. Use this when you want to read the code before deciding whether to commit to a specific issue (closes [#12](https://github.com/cdhagmann/gem-contribute/issues/12)).
|
|
22
|
+
- `gem-contribute fix -e` opens your editor in the clone directory after fork/clone/branch. Uses the new `editor` config key, falling back to `$EDITOR` (closes [#14](https://github.com/cdhagmann/gem-contribute/issues/14)).
|
|
23
|
+
- `gem-contribute fix -a` launches your configured AI coding tool (new `ai_tool` config key) with the clone directory as cwd. Combine with `-e` to open both — editor first, AI tool second (closes [#14](https://github.com/cdhagmann/gem-contribute/issues/14)).
|
|
24
|
+
- `gem-contribute fix` posts a "👋 I've started working on this" comment to the issue by default so other contributors don't double up on the same work. Opt out per-invocation with `--no-comment`, globally with `comment_on_fix: false` in config, or per-repo via `comment_on_fix_overrides` (YAML-only). Posting is soft-fail — the fork/clone/branch part still succeeds even if the comment can't be posted (closes [#18](https://github.com/cdhagmann/gem-contribute/issues/18)).
|
|
25
|
+
- `scan` appends `· N claimed` to project lines whose open issues have already been claimed via the working-on-this marker, so you can spot already-in-progress work at a glance (closes [#20](https://github.com/cdhagmann/gem-contribute/issues/20)).
|
|
26
|
+
- `issues <gem|all>` prefixes claimed issues with `[claimed]` for the same reason (closes [#20](https://github.com/cdhagmann/gem-contribute/issues/20)).
|
|
27
|
+
- Long-running CLI operations (`fix`'s fork → clone → branch pipeline; `submit`'s `git push`) now show a tty-spinner in interactive terminals. Non-TTY contexts (CI, piped output, redirected stderr) fall back to plain status lines — no behavior change for scripted use (closes [#30](https://github.com/cdhagmann/gem-contribute/issues/30)).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- `gem-contribute init` reads input through `tty-prompt`. Cosmetic side effect: default values are now displayed in parens — `(~/code/oss)` — instead of brackets — `[~/code/oss]` — matching tty-prompt's convention. Y/n parsing is now built-in instead of hand-rolled (closes [#31](https://github.com/cdhagmann/gem-contribute/issues/31)).
|
|
32
|
+
- Internal class `ForkCloneBranch` renamed to `Fix` (the long name was cumbersome and didn't mirror the `fix` CLI verb). User-facing CLI surface unchanged.
|
|
33
|
+
- Internal architecture: `HostAdapter` now owns every host-API verb (`fork`, `comment`, `pull_request_url`) plus host-specific URL templating (`clone_url`, `repo_url`); the new `Operations::Fork` / `Operations::Clone` primitives compose those with `Git`; `CLI::Fork` and `CLI::Fix` are thin compositions on top. The fork-readiness polling moved into the adapter — multi-host adapters can model readiness however the host actually works. See [ADR-0011](docs/adr/0011-host-adapter-owns-host-verbs.md). User-facing CLI surface unchanged.
|
|
34
|
+
- Internal architecture (ADR-0012 Phase 1): `Operations::*` classes are now output-free and return `dry-monads` `Success` / `Failure` `Result` types; new `Operations::Branch` and `Operations::Announce` primitives; `Operations::FixPipeline` composes Fork → Clone → Branch → Announce via `dry-operation`; `Workflow#build_adapter` returns a `Result` and the old `with_workflow_rescues` rescue chain is gone; `CLI::Fork` / `CLI::Fix` initializers use `dry-initializer`. See [ADR-0012](docs/adr/0012-output-free-service-objects-three-interface-architecture.md). User-facing CLI surface unchanged.
|
|
35
|
+
- Internal architecture (ADR-0012 Phase 2): every CLI verb writes through a semantic `Output::Standard` (or `Output::Null` in tests) abstraction — `#info`, `#progress`, `#warn`, `#error` — instead of raw `@stdout.puts` / `@stderr.puts`. `#progress` accepts an optional block and wraps a `tty-spinner` in TTY contexts. Existing constructors still accept `stdout:` / `stderr:` and auto-wrap them, so test suites injecting StringIO streams keep working unchanged. New deps: `tty-spinner ~> 0.9`, `tty-prompt ~> 0.23` (both pure-Ruby) (closes [#29](https://github.com/cdhagmann/gem-contribute/issues/29)).
|
|
36
|
+
|
|
37
|
+
### Removed
|
|
38
|
+
|
|
39
|
+
- The `fork-clone-branch` CLI alias has been removed. Use `gem-contribute fix` instead — same behavior, shorter to type.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- `gem-contribute fork` no longer prints `cd <path> && explore` — `explore` was meant as English but read as a (non-existent) shell command, so a copy-paste produced `command not found`. The "Next:" hint is now conditional on `-e` / `-a`: with neither flag it suggests `cd <path> && $EDITOR .`; with either flag it skips the directory step (you're already in your editor) and just points at the `fix` command.
|
|
44
|
+
|
|
7
45
|
## [0.2.0] - 2026-05-02
|
|
8
46
|
|
|
9
47
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -4,7 +4,7 @@ This file is read by Claude Code when working in this repository. Treat it as th
|
|
|
4
4
|
|
|
5
5
|
## Project shape
|
|
6
6
|
|
|
7
|
-
`gem-contribute` is a terminal UI that reads a project's `Gemfile.lock`, surfaces open contributable issues from the gems' source repositories, and offers one-keystroke
|
|
7
|
+
`gem-contribute` is a terminal UI that reads a project's `Gemfile.lock`, surfaces open contributable issues from the gems' source repositories, and offers a one-keystroke `fix` flow.
|
|
8
8
|
|
|
9
9
|
Read `docs/design.md` and the ADRs in `docs/adr/` before making non-trivial changes. The design doc describes the architecture and the ADRs explain why specific decisions were made. If a change conflicts with an ADR, propose updating the ADR first; don't silently violate it.
|
|
10
10
|
|
data/CONTRIBUTING.md
CHANGED
|
@@ -6,11 +6,17 @@ Thanks for considering a contribution. This project is *about* lowering the fric
|
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
gem install gem-contribute
|
|
9
|
-
gem-contribute init
|
|
10
|
-
gem-contribute
|
|
9
|
+
gem-contribute init # set clone_root and auth with GitHub
|
|
10
|
+
gem-contribute fork gem-contribute # fork + clone; lands on the default branch
|
|
11
11
|
bundle install
|
|
12
|
-
bin/rspec
|
|
13
|
-
bin/gem-contribute
|
|
12
|
+
bin/rspec # tests should pass on a clean checkout
|
|
13
|
+
bin/gem-contribute # tool should run against this repo's own Gemfile.lock
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Once you've picked an issue to work on, branch off the default with `fix`:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
gem-contribute fix gem-contribute/<issue#> # creates gem-contribute/issue-<N> off the default branch
|
|
14
20
|
```
|
|
15
21
|
|
|
16
22
|
## What we welcome
|
data/MAINTAINER.md
CHANGED
|
@@ -86,7 +86,124 @@ older gem versions continue to work.
|
|
|
86
86
|
|
|
87
87
|
## Cutting a release
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
Releases publish to rubygems.org via [Trusted Publishing][gh-trusted-pub]
|
|
90
|
+
(OIDC) — there is no `RUBYGEMS_API_KEY` secret and no manual `gem push`.
|
|
91
|
+
A `v*` tag push triggers `.github/workflows/release.yml`, which verifies
|
|
92
|
+
the tag matches `GemContribute::VERSION`, checks that `CHANGELOG.md` has a
|
|
93
|
+
dated section for the version, runs rubocop and rspec, and then publishes.
|
|
94
|
+
|
|
95
|
+
### One-time setup (before the first automated release)
|
|
96
|
+
|
|
97
|
+
The rubygems.org Trusted Publisher entry must exist before any tag push
|
|
98
|
+
can succeed. For an unclaimed gem name, use the **pending publisher**
|
|
99
|
+
flow:
|
|
100
|
+
|
|
101
|
+
1. Sign in at <https://rubygems.org>.
|
|
102
|
+
|
|
103
|
+
2. Go to <https://rubygems.org/profile/me/oidc/pending_trusted_publishers/new>.
|
|
104
|
+
|
|
105
|
+
3. Fill in the form:
|
|
106
|
+
|
|
107
|
+
| Field | Value |
|
|
108
|
+
|-------------------|----------------------|
|
|
109
|
+
| Gem name | `gem-contribute` |
|
|
110
|
+
| Repository owner | `cdhagmann` |
|
|
111
|
+
| Repository name | `gem-contribute` |
|
|
112
|
+
| Workflow filename | `release.yml` |
|
|
113
|
+
| Environment | `release` |
|
|
114
|
+
|
|
115
|
+
The "Environment" value matches `environment: release` in the
|
|
116
|
+
workflow. Leave blank if you removed that line; otherwise both must
|
|
117
|
+
match exactly.
|
|
118
|
+
|
|
119
|
+
4. Submit. The publisher entry is now "pending" — it has no gem attached
|
|
120
|
+
yet. The first successful publish from this workflow claims the name
|
|
121
|
+
and promotes the entry to a regular trusted publisher.
|
|
122
|
+
|
|
123
|
+
After the gem is published, you can add additional trusted publishers
|
|
124
|
+
(e.g. for a fork or replacement workflow) from the gem's settings page on
|
|
125
|
+
rubygems.org instead of the pending-publisher flow.
|
|
126
|
+
|
|
127
|
+
### Configure the GitHub environment (one-time)
|
|
128
|
+
|
|
129
|
+
The workflow runs in an `environment: release` job. Create the environment
|
|
130
|
+
in the repo so the OIDC claim carries the correct value:
|
|
131
|
+
|
|
132
|
+
1. GitHub repo → Settings → Environments → **New environment**.
|
|
133
|
+
2. Name it `release`.
|
|
134
|
+
3. (Optional) Add yourself as a **Required reviewer** for a manual
|
|
135
|
+
approval gate before each publish. Recommended for the first few
|
|
136
|
+
releases until you trust the workflow.
|
|
137
|
+
4. No secrets to configure. Trusted publishing replaces secrets entirely.
|
|
138
|
+
|
|
139
|
+
### Per-release checklist
|
|
140
|
+
|
|
141
|
+
When cutting a new version:
|
|
142
|
+
|
|
143
|
+
1. **Bump the version.** Edit `lib/gem_contribute/version.rb` to the new
|
|
144
|
+
`MAJOR.MINOR.PATCH`. Follow [SemVer](https://semver.org/).
|
|
145
|
+
|
|
146
|
+
2. **Regenerate `Gemfile.lock`.** Run `bundle install`. The lockfile's
|
|
147
|
+
`gem-contribute (X.Y.Z)` line must match the new version in both the
|
|
148
|
+
PATH spec at the top and the CHECKSUMS section near the bottom. CI
|
|
149
|
+
runs bundler in deployment/`--frozen` mode and refuses to install if
|
|
150
|
+
the lockfile is out of sync with the gemspec.
|
|
151
|
+
|
|
152
|
+
3. **Update CHANGELOG.md.** Move the contents of `[Unreleased]` into a
|
|
153
|
+
new dated section: `## [X.Y.Z] - YYYY-MM-DD`. Leave `[Unreleased]`
|
|
154
|
+
empty for the next cycle. The release workflow refuses to publish if
|
|
155
|
+
it can't find a `## [X.Y.Z]` section matching the tag.
|
|
156
|
+
|
|
157
|
+
4. **Commit on `main`.** Bump version.rb, the regenerated Gemfile.lock,
|
|
158
|
+
and CHANGELOG.md all in the same commit. Conventional message:
|
|
159
|
+
`Bump gem-contribute to X.Y.Z`.
|
|
160
|
+
|
|
161
|
+
5. **Tag and push.**
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
git tag -a vX.Y.Z -m "X.Y.Z"
|
|
165
|
+
git push origin main vX.Y.Z
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
6. **Watch the Actions tab.** The workflow will:
|
|
169
|
+
- verify the tag/version/CHANGELOG match
|
|
170
|
+
- run rubocop and rspec
|
|
171
|
+
- request an OIDC token, exchange it for a short-lived rubygems API
|
|
172
|
+
key, and publish the gem
|
|
173
|
+
- create a draft GitHub release with auto-generated notes
|
|
174
|
+
|
|
175
|
+
If the environment has a required-reviewer protection rule, the
|
|
176
|
+
workflow will pause for your manual approval before the publish step.
|
|
177
|
+
|
|
178
|
+
7. **Sanity check.** After publish, `gem info gem-contribute` should show
|
|
179
|
+
the new version. The draft GitHub release is yours to edit and publish
|
|
180
|
+
when ready.
|
|
181
|
+
|
|
182
|
+
### Troubleshooting
|
|
183
|
+
|
|
184
|
+
- **"Tag … does not match GemContribute::VERSION"** — version.rb is out of
|
|
185
|
+
sync with the tag. Either delete the tag and bump version.rb, or
|
|
186
|
+
re-tag at the right SHA after fixing version.rb.
|
|
187
|
+
- **"CHANGELOG.md is missing a section for …"** — add the dated section,
|
|
188
|
+
amend the bump commit, force-push, delete the old tag, retag, push.
|
|
189
|
+
(Force-push is fine on the bump commit before the publish has
|
|
190
|
+
succeeded.)
|
|
191
|
+
- **OIDC failure / "no trusted publisher matches"** — check the
|
|
192
|
+
rubygems.org publisher entry: gem name, repo owner, repo name,
|
|
193
|
+
workflow filename (`release.yml`, not the full path), and environment
|
|
194
|
+
must all match. The workflow filename is the basename only, no
|
|
195
|
+
`.github/workflows/` prefix.
|
|
196
|
+
- **`gem push` fails with `multifactor authentication required`** —
|
|
197
|
+
trusted publishing satisfies MFA. If you see this error, the workflow
|
|
198
|
+
fell back to a non-OIDC path; verify `permissions.id-token: write` is
|
|
199
|
+
set on the job.
|
|
200
|
+
|
|
201
|
+
### Yanking a release
|
|
202
|
+
|
|
203
|
+
Yanks happen via the rubygems.org web UI or `gem yank gem-contribute -v
|
|
204
|
+
X.Y.Z`. There is no automated yank flow — by design. If you need to yank,
|
|
205
|
+
also delete the corresponding `vX.Y.Z` tag and GitHub release so the
|
|
206
|
+
record on GitHub matches what's available on rubygems.org.
|
|
91
207
|
|
|
92
208
|
[gh-device-flow]: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow
|
|
209
|
+
[gh-trusted-pub]: https://guides.rubygems.org/trusted-publishing/
|
data/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# gem-contribute
|
|
2
2
|
|
|
3
|
+
[](https://github.com/cdhagmann/gem-contribute/actions/workflows/ci.yml)
|
|
4
|
+
|
|
3
5
|
Find contributable issues in the gems your project already depends on.
|
|
4
6
|
|
|
5
7
|
```
|
|
@@ -39,7 +41,8 @@ gem-contribute init One-time interactive setup (sets clone_roo
|
|
|
39
41
|
gem-contribute scan [path] Summarize the contributable surface of a Gemfile.lock.
|
|
40
42
|
gem-contribute issues <gem|all> List "good first issue" issues for one gem (or all).
|
|
41
43
|
gem-contribute auth login Authenticate with GitHub via OAuth device flow.
|
|
42
|
-
gem-contribute
|
|
44
|
+
gem-contribute fork <gem|owner/repo> Fork and clone any GitHub repo, land on the default branch.
|
|
45
|
+
gem-contribute fix <gem>/<issue#> Fork, clone, and branch from main for a specific issue.
|
|
43
46
|
gem-contribute submit Push the branch and open a pre-filled PR in the browser.
|
|
44
47
|
gem-contribute config set <key> <val> Persist user preferences (e.g. clone_root).
|
|
45
48
|
```
|
|
@@ -56,6 +59,15 @@ $ cd ~/code/oss/rubocop/rubocop # whatever clone_root you set during in
|
|
|
56
59
|
$ gem-contribute submit # push + open the PR compare page in your browser
|
|
57
60
|
```
|
|
58
61
|
|
|
62
|
+
Or, when you want to look around a project before picking an issue, use `fork`:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
$ gem-contribute fork rubocop # fork-and-clone a gem by name
|
|
66
|
+
$ gem-contribute fork rubyevents/rubyevents -e # fork-and-clone any GitHub repo and open your editor
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`fork` does the same fork-clone-upstream sequence as `fix` but stops on the default branch — no issue branch, no comment. Handy for "build it locally and decide what to fix later." When you've picked an issue, `gem-contribute fix <gem>/<issue#>` branches off cleanly.
|
|
70
|
+
|
|
59
71
|
The auth step (run automatically by `init`, or directly via `gem-contribute auth login`) opens GitHub's device-flow page in your browser and copies the one-time code to your clipboard — same UX as `gh auth login`, no token paste, no client secret. Tokens cache at `~/.config/gem-contribute/auth.json` (mode 0600).
|
|
60
72
|
|
|
61
73
|
## Configuration
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Open Questions — Roadmap to v1
|
|
2
|
+
|
|
3
|
+
Working list of unresolved planning questions for the v1 roadmap (TUI + CLI + `bundle contribute` + `gem contribute`). Walked through one at a time with the maintainer; each gets crossed off and folded into the ROADMAP / ADRs as it's answered.
|
|
4
|
+
|
|
5
|
+
Order is rough priority — top items block downstream design, bottom items are polish.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Q1. ~~What is the "world map view"?~~ — ANSWERED 2026-05-03
|
|
10
|
+
|
|
11
|
+
A near-easter-egg view showing the locations of people who've kicked the tires on `gem-contribute`. Tracked as [issue #5](https://github.com/cdhagmann/gem-contribute/issues/5). Not a primary fragment — a hidden/discoverable view.
|
|
12
|
+
|
|
13
|
+
**Implications this surfaces:**
|
|
14
|
+
- Requires some form of opt-in usage reporting (the tool has to phone home with *something* to populate the map). New component: a tire-kicker reporting backend.
|
|
15
|
+
- Privacy/consent UX needs to live somewhere — likely first-run prompt or `init` flow.
|
|
16
|
+
- Backend service is itself a v1 dependency *if* the map ships in v1.
|
|
17
|
+
|
|
18
|
+
→ See **Q1a** below.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Q1a. ~~Does the world map ship in v1?~~ — ANSWERED 2026-05-03
|
|
23
|
+
|
|
24
|
+
No. Preserving the option by choosing Rooibos now; tire-kicker map waits until there's enough adoption to make the data interesting. No backend work in v1 scope.
|
|
25
|
+
|
|
26
|
+
**ADR-0013 reasoning lock-in:**
|
|
27
|
+
1. Workshop onboarding cost — the main argument for bubbletea — is no longer a constraint (workshop ended 2026-05-02)
|
|
28
|
+
2. Preserving the world map view (issue #5) as a future option
|
|
29
|
+
3. ADR-0008's original technical reasoning still stands (Command primitives matched our verbs, snapshot test helpers, fractal Router architecture)
|
|
30
|
+
4. Bubbletea-ruby's testing story was unverified per ADR-0010; Rooibos shipped tested helpers
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Q2. ~~Packaging shape~~ — ANSWERED 2026-05-03
|
|
35
|
+
|
|
36
|
+
One gem. `gem-contribute` ships the standalone CLI, the Bundler plugin hooks, and the RubyGems plugin hooks all together. ADR-0012's mention of a future `rubygems-contribute` gem is overridden by ADR-0014 (the new plugin ADR).
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Q3. ~~What do `bundle contribute` / `gem contribute` do?~~ — ANSWERED 2026-05-03
|
|
41
|
+
|
|
42
|
+
CLI only — no TUI from the plugins. Reasoning: Bundler and RubyGems plugins aren't typically interactive; they're CLI subcommands. The TUI is a property of the standalone `gem-contribute` binary.
|
|
43
|
+
|
|
44
|
+
- `gem-contribute` (no args) → TUI
|
|
45
|
+
- `bundle contribute` (no args) → CLI default (`scan` or `list all` — see **Q3a**)
|
|
46
|
+
- `gem contribute` (no args) → CLI default (same)
|
|
47
|
+
- `<any>` `<verb>` → CLI verb
|
|
48
|
+
|
|
49
|
+
**Architectural consequence:** the plugin entry points never need to load Rooibos. Keeps plugin install lightweight.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Q3a. Bare-call default for the plugins: `scan` or `list all`?
|
|
54
|
+
|
|
55
|
+
User flagged as undecided. Both are read-only summary actions; difference is granularity and verbosity.
|
|
56
|
+
|
|
57
|
+
- **`scan`** — current verb; prints the summary table (`47 gems · 44 on github.com · 2 on gitlab.com · …`) plus top contributable projects by issue count. Hits the network for the issue counts (cached).
|
|
58
|
+
- **`list all`** — would presumably print every gem with its resolved source. Less network, more data, less curated.
|
|
59
|
+
|
|
60
|
+
No urgency to pick — can be deferred to Phase 4. Worth deciding alongside the verb taxonomy review (does `list` exist as a separate verb? sub-verbs of `list`?).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Q4. ~~Default behavior of bare `gem-contribute`~~ — ANSWERED 2026-05-03
|
|
65
|
+
|
|
66
|
+
Packwerk-style launcher: `gem-contribute` (no args) opens a mini TUI that lists subcommands; arrow keys + enter pick one. `gem-contribute <verb>` runs the verb directly with no TUI in the way.
|
|
67
|
+
|
|
68
|
+
→ See **Q4a**: this reframes what the "full TUI" is.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Q4a. ~~What happens to the design.md "full TUI"?~~ — ANSWERED 2026-05-03
|
|
73
|
+
|
|
74
|
+
Bare `gem-contribute` launches the design.md four-fragment TUI (ProjectList → IssueList → IssueDetail → ContributingViewer + AuthOverlay + the eventual WorldMap). The packwerk reference was establishing "yes, raw command launches a TUI" as precedent — not a directive to mirror packwerk's exact subcommand-picker shape. Subcommands stay CLI.
|
|
75
|
+
|
|
76
|
+
Phase 3 of ROADMAP doesn't need rewriting; just confirm the entry-point wiring in `cli.rb` (no-arg → launch TUI vs print USAGE).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Q5. ~~Multi-host adapters in v1?~~ — ANSWERED 2026-05-03
|
|
81
|
+
|
|
82
|
+
GitHub-only at v1.0. v1.x point releases will add adapters (GitLab, Codeberg, etc.). ADR-0011's architecture is the bet that paying off.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Q6. ~~Does ADR-0012's dry-rb adoption survive the framework revert?~~ — ANSWERED 2026-05-03
|
|
87
|
+
|
|
88
|
+
Yes. We need both a CLI and a TUI; output-free service objects with `Result` returns are what lets both consume the same service layer. ADR-0013 (Rooibos revert) doesn't touch ADR-0012.
|
|
89
|
+
|
|
90
|
+
Sub-question on `dry-cli` adoption is **deferred to Phase 4/5** when the plugin entry points get wired — easier to decide once the plugin shape is concrete.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Q7. Rooibos 0.7.x verification — ASSIGNED TO ME
|
|
95
|
+
|
|
96
|
+
Pre-Phase-3 task (no user decision needed): confirm Rooibos's current version on rubygems.org, verify Command primitives still exist, verify snapshot test helpers still ship. Folded into ROADMAP Phase 3.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Q8. ~~Workshop docs disposition~~ — MY CALL: archive
|
|
101
|
+
|
|
102
|
+
Moving workshop-era docs (`workshop.md`, `talk/`, `workshop-issues/`, `prep-plan.md`) to `docs/archive/` in Phase 6. Preserves history without polluting the active doc surface. Flag if you'd rather delete or keep them in place.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Q9. ~~Test framework + cassette policy~~ — MY CALL: keep design.md's strategy as-is
|
|
107
|
+
|
|
108
|
+
RSpec, VCR cassettes committed, no formal coverage target (just "every public method, every Update branch"). Snapshot helpers come from Rooibos — verified in Q7. Flag if you want a different testing posture for v1.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Q10. ~~v1 out-of-scope confirmation~~ — MY CALL: existing exclusions stand
|
|
113
|
+
|
|
114
|
+
All ADR-mandated out-of-scope items remain out for v1.0:
|
|
115
|
+
- Private repos / `repo` OAuth scope
|
|
116
|
+
- PR creation from inside the TUI (browser-based stays per ADR-0011)
|
|
117
|
+
- AI-anything
|
|
118
|
+
- Label normalization
|
|
119
|
+
- CONTRIBUTING parsing
|
|
120
|
+
- Multi-host adapters (per Q5; v1.x territory)
|
|
121
|
+
- World map view (per Q1a; post-v1)
|
|
122
|
+
|
|
123
|
+
Flag if anything moves into v1.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Q11. Branding / homepage — DEFER
|
|
128
|
+
|
|
129
|
+
Pre-release polish; revisit during Phase 6.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Q12. CHANGELOG.md / CONTRIBUTING.md / MAINTAINER.md — task list, not decision
|
|
134
|
+
|
|
135
|
+
Folded into ROADMAP Phase 6. No decision needed.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Q13. ~~OAuth App identity for v1 release~~ — ANSWERED 2026-05-03
|
|
140
|
+
|
|
141
|
+
Stay on the personal-account OAuth App for v1.0. Migrate to a dedicated identity when rate limits actually bite. Pragmatic — fits the rest of the v1 scope (don't pay for problems we don't have yet).
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Q14. ~~CI / release automation~~ — ANSWERED 2026-05-03
|
|
146
|
+
|
|
147
|
+
GitHub Actions, two workflows:
|
|
148
|
+
|
|
149
|
+
**CI (`ci.yml`)** — runs on push/PR:
|
|
150
|
+
- rubocop
|
|
151
|
+
- rspec
|
|
152
|
+
- integration tests gated behind `GEM_CONTRIBUTE_INTEGRATION=1` (off by default)
|
|
153
|
+
- smoke test: `bundle plugin install` + `gem install` on a clean Ruby image, verify both plugin entry points dispatch a verb
|
|
154
|
+
|
|
155
|
+
**Release (`release.yml`)** — runs on `v*` tag push:
|
|
156
|
+
- **Trusted Publishing via OIDC.** No API key stored as a secret; rubygems.org issues a short-lived token from the GitHub Actions OIDC claim. Compatible with `rubygems_mfa_required = true` (which the gemspec already sets).
|
|
157
|
+
- Setup: configure a trusted publisher entry on rubygems.org (gem name + repo + workflow filename) before the first automated release.
|
|
158
|
+
|
|
159
|
+
Multi-Ruby matrix and signed gems are post-v1.0 unless they become a real ask.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Notes / parking lot
|
|
164
|
+
|
|
165
|
+
- `docs/ideas.md` has one stray idea: "Make sure it respects PR templates" — file as a v1 issue.
|
|
166
|
+
- `docs/index.md` and `docs/_config.yml` suggest a Jekyll site; not yet investigated.
|
|
167
|
+
- `docs/claude-code-prompt.md` — not yet investigated.
|