gem-contribute 0.1.0 → 0.3.0

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gem_release.yml +1 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +28 -0
  4. data/.github/workflows/ci.yml +26 -0
  5. data/.github/workflows/pr-template-check.yml +100 -0
  6. data/CHANGELOG.md +41 -0
  7. data/CLAUDE.md +1 -1
  8. data/CODE_OF_CONDUCT.md +86 -0
  9. data/CONTRIBUTING.md +12 -13
  10. data/README.md +21 -8
  11. data/docs/OPEN_QUESTIONS.md +167 -0
  12. data/docs/ROADMAP.md +266 -0
  13. data/docs/adr/0006-standalone-gem-not-plugin.md +1 -1
  14. data/docs/adr/0008-rooibos-tui-framework.md +3 -3
  15. data/docs/adr/0010-charm-ruby-tui-framework.md +84 -0
  16. data/docs/adr/0011-host-adapter-owns-host-verbs.md +58 -0
  17. data/docs/adr/0012-output-free-service-objects-three-interface-architecture.md +79 -0
  18. data/docs/adr/0013-revert-to-rooibos.md +71 -0
  19. data/docs/adr/0014-ship-bundler-and-rubygems-plugins.md +75 -0
  20. data/docs/adr/README.md +7 -2
  21. data/docs/design-interface-layer.md +295 -0
  22. data/docs/design.md +31 -8
  23. data/docs/ideas.md +1 -0
  24. data/docs/index.md +2 -2
  25. data/docs/prep-plan.md +6 -6
  26. data/docs/talk/README.md +45 -0
  27. data/docs/talk/index.html +4165 -0
  28. data/docs/talk/lightning.md +425 -0
  29. data/docs/talk/lightning.pdf +0 -0
  30. data/lib/gem_contribute/cli/auth.rb +22 -44
  31. data/lib/gem_contribute/cli/config.rb +32 -16
  32. data/lib/gem_contribute/cli/fix.rb +122 -0
  33. data/lib/gem_contribute/cli/fork.rb +145 -0
  34. data/lib/gem_contribute/cli/init.rb +78 -0
  35. data/lib/gem_contribute/cli/issue_announcer.rb +42 -0
  36. data/lib/gem_contribute/cli/issues.rb +37 -44
  37. data/lib/gem_contribute/cli/platform_tools.rb +33 -0
  38. data/lib/gem_contribute/cli/post_clone_hooks.rb +50 -0
  39. data/lib/gem_contribute/cli/rate_limit_footer.rb +34 -0
  40. data/lib/gem_contribute/cli/scan.rb +20 -15
  41. data/lib/gem_contribute/cli/submit.rb +60 -64
  42. data/lib/gem_contribute/cli/workflow.rb +63 -0
  43. data/lib/gem_contribute/cli.rb +11 -14
  44. data/lib/gem_contribute/config.rb +28 -4
  45. data/lib/gem_contribute/git.rb +49 -0
  46. data/lib/gem_contribute/host_adapter.rb +52 -5
  47. data/lib/gem_contribute/host_adapters/github_adapter.rb +126 -37
  48. data/lib/gem_contribute/operations/announce.rb +52 -0
  49. data/lib/gem_contribute/operations/branch.rb +35 -0
  50. data/lib/gem_contribute/operations/clone.rb +41 -0
  51. data/lib/gem_contribute/operations/fix_pipeline.rb +70 -0
  52. data/lib/gem_contribute/operations/fork.rb +35 -0
  53. data/lib/gem_contribute/output/null.rb +20 -0
  54. data/lib/gem_contribute/output/standard.rb +71 -0
  55. data/lib/gem_contribute/version.rb +1 -1
  56. data/lib/gem_contribute.rb +10 -18
  57. metadata +120 -3
  58. data/lib/gem_contribute/cli/fork_clone_branch.rb +0 -197
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f6941e81cacd8ab2bb7abb6824bb54d5b04ec05789d24c792b48eb4c5125e02
4
- data.tar.gz: 9a548392f2d027dbc99719d74de627940086e3858fd5c5152fa8d4ecffddb7b8
3
+ metadata.gz: fb726fe2025ba0cc501be01d13b4138ff4b21a9c755ad81c9b0181ef35f41c88
4
+ data.tar.gz: 33e6e83e38b27f2b4e2079fc79cfa76c2bfb178a2ba37424a05dfc8ad91398c0
5
5
  SHA512:
6
- metadata.gz: 1a4c00ea48ba2ef0245f3564d97b2bb0e6d3eb7098a79ef598a58dda95c6130630648e04351e8a5ef7f767456d938a836c647aa02c18d7b22663816a6b9d7d2e
7
- data.tar.gz: 1d60a359d87cc17ba4e2c8bad1acab5f039334df63afd34055165d1a61b569e3c9c7fd57f5159d33ed0031e7634cabb93fd1b82e52f36cd4a5d0e30bfd2ef2ca
6
+ metadata.gz: fa04494e7ac4294f90d14ecb01d3f111d7e890dd5dc9ec1c5b77bc83aa215e8c0cac467f6bd9fa38ffa73c4665aece92520269473cf0f95555f48096a5a2b372
7
+ data.tar.gz: 4e9bfd2d676ac59d5d8c8c8db0e7928641c8e4f031a85fd435f1e52ec3b1b770aa41a705f456ad488a23019520093787d58e8326bbbf42e51f24a30e185a0cfc
data/.gem_release.yml ADDED
@@ -0,0 +1 @@
1
+ file: lib/gem_contribute/version.rb
@@ -0,0 +1,28 @@
1
+ ## Summary
2
+
3
+ <!-- One or two sentences. What changes, and why. The "why" is the part that's hard to recover later. -->
4
+
5
+ ## Linked issue / ADR
6
+
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
+ -->
11
+
12
+ ## Working agreement
13
+
14
+ - [ ] Single concern (multi-concern PRs get bounced — see [CLAUDE.md](../CLAUDE.md))
15
+ - [ ] `bin/rubocop` and `bin/rspec` pass locally
16
+ - [ ] New behavior has a test; bug fix has a regression test
17
+ - [ ] Async work goes through Rooibos Commands (no direct threads / `Async` / synchronous shellouts)
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
+
26
+ ## Notes for reviewer
27
+
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
data/CHANGELOG.md CHANGED
@@ -4,6 +4,47 @@ All notable changes to this project will be documented here. The format is based
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ### Added
8
+
9
+ - `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)).
10
+ - `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)).
11
+ - `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)).
12
+ - `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)).
13
+ - `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)).
14
+ - `issues <gem|all>` prefixes claimed issues with `[claimed]` for the same reason (closes [#20](https://github.com/cdhagmann/gem-contribute/issues/20)).
15
+ - 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)).
16
+
17
+ ### Changed
18
+
19
+ - `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)).
20
+ - Internal class `ForkCloneBranch` renamed to `Fix` (the long name was cumbersome and didn't mirror the `fix` CLI verb). User-facing CLI surface unchanged.
21
+ - 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.
22
+ - 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.
23
+ - 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)).
24
+
25
+ ### Removed
26
+
27
+ - The `fork-clone-branch` CLI alias has been removed. Use `gem-contribute fix` instead — same behavior, shorter to type.
28
+
29
+ ### Fixed
30
+
31
+ - `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.
32
+
33
+ ## [0.2.0] - 2026-05-02
34
+
35
+ ### Added
36
+
37
+ - `gem-contribute init` — interactive first-run setup: prompts for `clone_root` and chains into `auth login` when no token is cached. Users who skip it can run each step separately at any time.
38
+ - Rate-limit footer after `scan` and `issues` runs: `GitHub rate limit: 4,587 / 5,000 remaining · resets at 14:32 UTC`. Surfaced so users know whether a degraded run is seconds or minutes away from recovering (closes [#4](https://github.com/cdhagmann/gem-contribute/issues/4)).
39
+
40
+ ### Changed
41
+
42
+ - `gem-contribute fix` now errors with an `init` hint when `clone_root` is not configured, instead of silently defaulting to `~/code/oss/`. Existing users with a configured `clone_root` are unaffected (closes [#15](https://github.com/cdhagmann/gem-contribute/issues/15)).
43
+
44
+ ### Fixed
45
+
46
+ - `gem-contribute submit` no longer requires an `upstream` remote. When only `origin` is present (e.g. when dogfooding on your own repo), it treats `origin` as the upstream and emits a same-repo compare URL. The cross-fork path is unchanged for normal contributors.
47
+
7
48
  ## [0.1.0] - 2026-04-28
8
49
 
9
50
  ### 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 fork-clone-branch.
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
 
@@ -0,0 +1,86 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ Version 3.0.
4
+
5
+ ## Our Pledge
6
+
7
+ We pledge to make our community welcoming, safe, and equitable for all.
8
+
9
+ We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant.
10
+
11
+ ## Encouraged Behaviors
12
+
13
+ While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language.
14
+
15
+ With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including:
16
+
17
+ 1. Respecting the **purpose of our community**, our activities, and our ways of gathering.
18
+ 2. Engaging **kindly and honestly** with others.
19
+ 3. Respecting **different viewpoints** and experiences.
20
+ 4. **Taking responsibility** for our actions and contributions.
21
+ 5. Gracefully giving and accepting **constructive feedback**.
22
+ 6. Committing to **repairing harm** when it occurs.
23
+ 7. Behaving in other ways that promote and sustain the **well-being of our community**.
24
+
25
+ ## Restricted Behaviors
26
+
27
+ We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct.
28
+
29
+ 1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop.
30
+ 2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people.
31
+ 3. **Stereotyping or discrimination.** Characterizing anyone's personality or behavior on the basis of immutable identities or traits.
32
+ 4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community.
33
+ 5. **Violating confidentiality.** Sharing or acting on someone's personal or private information without their permission.
34
+ 6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.
35
+ 7. Behaving in other ways that **threaten the well-being** of our community.
36
+
37
+ ### Other Restrictions
38
+
39
+ 1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions.
40
+ 2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.
41
+ 3. **Promotional materials.** Sharing marketing or other commercial content in a way that is outside the norms of the community.
42
+ 4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors.
43
+
44
+ ## Reporting an Issue
45
+
46
+ Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm.
47
+
48
+ When an incident does occur, it is important to report it promptly. To report a possible violation, email **gem.contribute@cdhagmann.com**. Reports are read by the project maintainer.
49
+
50
+ Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution.
51
+
52
+ ## Addressing and Repairing Harm
53
+
54
+ If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped.
55
+
56
+ 1. Warning
57
+ 1. Event: A violation involving a single incident or series of incidents.
58
+ 2. Consequence: A private, written warning from the Community Moderators.
59
+ 3. Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations.
60
+
61
+ 2. Temporarily Limited Activities
62
+ 1. Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation.
63
+ 2. Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members.
64
+ 3. Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over.
65
+
66
+ 3. Temporary Suspension
67
+ 1. Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation.
68
+ 2. Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions.
69
+ 3. Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted.
70
+
71
+ 4. Permanent Ban
72
+ 1. Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member.
73
+ 2. Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior.
74
+ 3. Repair: There is no possible repair in cases of this severity.
75
+
76
+ This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community.
77
+
78
+ ## Scope
79
+
80
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
81
+
82
+ ## Attribution
83
+
84
+ This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at https://www.contributor-covenant.org/version/3/0/.
85
+
86
+ Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0.
data/CONTRIBUTING.md CHANGED
@@ -5,11 +5,18 @@ Thanks for considering a contribution. This project is *about* lowering the fric
5
5
  ## Quick start
6
6
 
7
7
  ```
8
- git clone https://github.com/cdhagmann/gem-contribute
9
- cd gem-contribute
8
+ gem install 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
10
11
  bundle install
11
- bin/rspec # tests should pass on a clean checkout
12
- bin/gem-contribute # tool should run against this repo's own Gemfile.lock
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
13
20
  ```
14
21
 
15
22
  ## What we welcome
@@ -21,14 +28,6 @@ bin/gem-contribute # tool should run against this repo's own Gemfile.lock
21
28
  - Performance improvements with before/after numbers
22
29
  - Accessibility improvements to the TUI (color contrast, keyboard-only flows, screen-reader compatibility)
23
30
 
24
- ## What we'd push back on
25
-
26
- - Label normalization (see [ADR-0005](docs/adr/0005-render-labels-verbatim.md))
27
- - Parsing CONTRIBUTING.md for structured data (see [ADR-0007](docs/adr/0007-display-contributing-verbatim.md))
28
- - AI-anything that summarizes, suggests, or rewrites maintainer-authored content
29
- - Bundler plugin packaging (see [ADR-0006](docs/adr/0006-standalone-gem-not-plugin.md)) — we'll consider it later, just not now
30
-
31
- If you have a strong case for any of the above, open an issue first and let's talk before you write code.
32
31
 
33
32
  ## PR expectations
34
33
 
@@ -39,7 +38,7 @@ If you have a strong case for any of the above, open an issue first and let's ta
39
38
 
40
39
  ## Code of Conduct
41
40
 
42
- Be kind. Assume good faith. The Ruby community deserves both. Specific incidents go to chris@example.com (placeholderTODO: update before merging this).
41
+ Be kind. Assume good faith. The Ruby community deserves both. The full text adapted from [Contributor Covenant 3.0](https://www.contributor-covenant.org/version/3/0/)lives in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md). Specific incidents go to gem.contribute@cdhagmann.com.
43
42
 
44
43
  ## AI assistance
45
44
 
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # gem-contribute
2
2
 
3
+ [![CI](https://github.com/cdhagmann/gem-contribute/actions/workflows/ci.yml/badge.svg)](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
  ```
@@ -35,10 +37,12 @@ Requires Ruby 3.2 or later.
35
37
  The CLI is a small set of subcommands:
36
38
 
37
39
  ```
40
+ gem-contribute init One-time interactive setup (sets clone_root, then auth).
38
41
  gem-contribute scan [path] Summarize the contributable surface of a Gemfile.lock.
39
42
  gem-contribute issues <gem|all> List "good first issue" issues for one gem (or all).
40
43
  gem-contribute auth login Authenticate with GitHub via OAuth device flow.
41
- gem-contribute fix <gem>/<issue#> Fork the gem's repo, clone the fork, branch from main.
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.
42
46
  gem-contribute submit Push the branch and open a pre-filled PR in the browser.
43
47
  gem-contribute config set <key> <val> Persist user preferences (e.g. clone_root).
44
48
  ```
@@ -46,29 +50,38 @@ gem-contribute config set <key> <val> Persist user preferences (e.g. clone_root)
46
50
  A typical session:
47
51
 
48
52
  ```sh
49
- $ gem-contribute auth login # one-time; uses GitHub device flow
53
+ $ gem-contribute init # one-time: sets clone_root, then auth via GitHub device flow
50
54
  $ gem-contribute scan # see what's worth contributing to
51
55
  $ gem-contribute issues rubocop # drill into one project's issues
52
56
  $ gem-contribute fix rubocop/12345 # fork, clone, branch
53
- $ cd ~/code/oss/rubocop/rubocop # (or wherever clone_root points)
57
+ $ cd ~/code/oss/rubocop/rubocop # whatever clone_root you set during init
54
58
  # ... make your change, commit ...
55
59
  $ gem-contribute submit # push + open the PR compare page in your browser
56
60
  ```
57
61
 
58
- The `auth login` step 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).
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
+
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).
59
72
 
60
73
  ## Configuration
61
74
 
62
- User config lives at `~/.config/gem-contribute/config.yml`. Manage it with `gem-contribute config`:
75
+ User config lives at `~/.config/gem-contribute/config.yml`. The interactive way to set it is `gem-contribute init`; for scripted setup, use `gem-contribute config`:
63
76
 
64
77
  ```sh
65
78
  gem-contribute config set clone_root ~/Projects/oss
66
79
  gem-contribute config list
67
80
  ```
68
81
 
69
- | Key | Default | Notes |
70
- |--------------|--------------|--------------------------------------------------|
71
- | `clone_root` | `~/code/oss` | Where `fix` clones forks (`<root>/<owner>/<repo>`). |
82
+ | Key | Notes |
83
+ |--------------|------------------------------------------------------------------------------------|
84
+ | `clone_root` | Where `fix` clones forks (`<root>/<owner>/<repo>`). Set via `init` or `config set`. No default — `fix` errors if unset. |
72
85
 
73
86
  ## Design
74
87
 
@@ -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.