standard_id-google 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88bce7685da60d2df6e41c103d179a5baa6bfb71d9e7f82ecaabb43e280680c7
4
- data.tar.gz: 55a57eaba19c3907515a9609548e4d1370adaf400aa3481125e3d2a42e866c9b
3
+ metadata.gz: 24f43e5bf2451f85eeefc67854060b443fe88781f76228eac4754dc8fcaf42c7
4
+ data.tar.gz: d17aa2f191d3616e3c17f838f2c4c0630c93c4e1afb8372d1f6fd311b61ccbf1
5
5
  SHA512:
6
- metadata.gz: 1453686923aaf994a195d5d8d811fce1d1f02a4128eba1bcecffe457a533bad0a9345be8ae6f2545375e5c65d5357a170d450f18ca5ae71ae322f822b5a2013c
7
- data.tar.gz: 1d23bfa48f33aab5980bbd9f6a4e5594dba9259dbe8cac91b434a3700f13187884972ca783674bc29986ebfc7c22040bf516445c338cc0d24ae15eb1099a0f9f
6
+ metadata.gz: 361bd688a31baaf8bed7ec6a4adfd13c130f146af786ec20e00809be932ee304b9f27bd73890754053a972bad67e51e92dacd1dd6dfc8fe20e5b5c13800a10f8
7
+ data.tar.gz: 7dfbd6c33aa66ec005e29774a7b8419c68593d78c5959933b7ec8c71814dfe454f718e147a8714b32a6b51ce85f04d0cf8c163b0f69d1ae9d0bc636aa2cf4e8d
data/CHANGELOG.md CHANGED
@@ -7,6 +7,73 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.0] - 2026-07-31
11
+
12
+ ### Added
13
+
14
+ - **Install generator: `bin/rails g standard_id:google:install`.** Writes
15
+ `config/initializers/standard_id_google.rb` with the `social.google_*` fields
16
+ wired to ENV, then prints the environment variables the host has to set and
17
+ the reminder that `/auth/callback/google` must be registered as an authorized
18
+ redirect URI for **every** origin served — the Google console matches the
19
+ redirect exactly, so staging and production each need their own. Idempotent:
20
+ re-running skips an existing initializer; `--force` overwrites,
21
+ `--skip-initializer` writes nothing.
22
+
23
+ It writes a **separate** file rather than editing `standard_id.rb`, so the
24
+ provider can be removed by deleting one file and `standard_id`'s own install
25
+ generator stays free to overwrite its initializer without clobbering these
26
+ credentials. Initializers load alphabetically, so the base config is applied
27
+ first. The generated file uses the `config.social.` form throughout — a spec
28
+ pins that it never emits the unqualified `config.google_*` form, which works
29
+ today only because the names happen to be unique across scopes.
30
+
31
+ Five of the nine `standard_*` gems shipped an install generator and this was
32
+ not one of them, which left both consumers assembling the block from the
33
+ README by hand.
34
+
35
+ ### Documentation
36
+
37
+ - **Consumer list corrected in `CLAUDE.md`: this gem has two consumers, not
38
+ one.** It named `luminality-web` only; `sidekick-web` also consumes it. Both
39
+ live in sibling workspaces rather than beside this repo, which is how the
40
+ second one went unnoticed.
41
+
42
+ - **Corrected the Configuration section, which showed a form that raised on
43
+ `standard_id` <= 0.32.0.** These fields are declared by this gem, and until
44
+ `standard_id` 0.33.0 they were declared from this gem's Railtie
45
+ `after_initialize` — after `config/initializers` — so the documented plain
46
+ initializer raised `StandardId::ConfigurationError: Unknown field
47
+ 'google_client_id' for scope 'social'`. The README now records the
48
+ `after_initialize` workaround for older `standard_id`, states that 0.33.0
49
+ declares provider fields before `:load_config_initializers` so the plain form
50
+ is correct there, and notes that the fields do not exist at all without this
51
+ gem in the Gemfile — on any `standard_id` version.
52
+
53
+ ### Changed
54
+
55
+ - **`standard_id` dependency tightened from `~> 0.1, >= 0.1.7` to `~> 0.29.0`.**
56
+ The old constraint claimed compatibility with every `0.x` release while this
57
+ plugin reaches into `StandardId::ProviderRegistry` and
58
+ `StandardId::Providers::Google`, and `standard_id` is pre-1.0 with breaking
59
+ minors. Bundler would happily resolve against an untested minor and fail at
60
+ runtime instead of at resolution. Both current consumers already pin
61
+ `standard_id "~> 0.29.0"`, so nothing existing is affected.
62
+
63
+ ### Fixed
64
+
65
+ - Gemspec no longer packages the `.claude/` directory. Published `0.3.0` shipped
66
+ `.claude/settings.json`, `.claude/hooks/enforce-worktree.sh`, and three skill
67
+ files to every consumer — this gem's `spec.files` reject-list was the only one
68
+ in the `standard_*` family missing the `.claude/` prefix (`standard_id-apple`
69
+ already had it). Packaged file count drops 21 → 16; `lib/` and `LICENSE` are
70
+ unaffected.
71
+ - Gemspec now uses an allow-list (`Dir["lib/**/*", …]`) rather than a
72
+ `git ls-files` reject-list, so packaging fails **closed** and this class of
73
+ leak cannot recur. Also drops `.editorconfig`, `.pinact.yaml`, `.rspec`,
74
+ `.rubocop.yml`, `.ruby-version`, `AGENTS.md`, `CLAUDE.md`, and
75
+ `CODE_OF_CONDUCT.md`; `lib/` is byte-identical.
76
+
10
77
  ## [0.3.0] - 2026-04-29
11
78
 
12
79
  ### Added
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) Jaryl Sim
3
+ Copyright (c) 2026 Rarebit One
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -20,11 +20,28 @@ bundle install
20
20
 
21
21
  The gem automatically registers itself with StandardId when it is required.
22
22
 
23
+ Then run the install generator to drop the credentials block in place:
24
+
25
+ ```bash
26
+ bin/rails g standard_id:google:install
27
+ ```
28
+
29
+ This writes `config/initializers/standard_id_google.rb` — deliberately a
30
+ separate file from `config/initializers/standard_id.rb`, so the provider can be
31
+ removed by deleting one file and `standard_id`'s own install generator stays
32
+ free to overwrite its initializer without clobbering these values. Initializers
33
+ load alphabetically, so the base config is applied first. The generator is
34
+ idempotent; re-running on an existing initializer skips with a clear message
35
+ (pass `--force` to overwrite).
36
+
23
37
  ## Configuration
24
38
 
25
- Configure your Google credentials inside the StandardId configuration block:
39
+ The generator writes this for you; the block is documented here for hosts
40
+ configuring by hand. Configure your Google credentials inside the StandardId
41
+ configuration block:
26
42
 
27
43
  ```ruby
44
+ # config/initializers/standard_id.rb
28
45
  StandardId.configure do |config|
29
46
  config.social.google_client_id = ENV.fetch("GOOGLE_OAUTH_CLIENT_ID", nil)
30
47
  config.social.google_client_secret = ENV.fetch("GOOGLE_OAUTH_CLIENT_SECRET", nil)
@@ -33,6 +50,37 @@ end
33
50
 
34
51
  With those values in place, StandardId routes such as `/auth/callback/google` continue to function using this provider gem.
35
52
 
53
+ ### Boot ordering (standard_id <= 0.32.0)
54
+
55
+ These fields are declared by *this gem*, not by `standard_id`, and until
56
+ `standard_id` 0.33.0 they were declared from this gem's Railtie
57
+ `after_initialize` — which runs *after* `config/initializers`. On `standard_id`
58
+ **0.32.0 and earlier** the block above therefore raised:
59
+
60
+ ```
61
+ StandardId::ConfigurationError: Unknown field 'google_client_id' for scope 'social'
62
+ ```
63
+
64
+ The workaround was to wrap the writes:
65
+
66
+ ```ruby
67
+ # Only needed on standard_id <= 0.32.0
68
+ Rails.application.config.after_initialize do
69
+ StandardId.configure do |config|
70
+ config.social.google_client_id = ENV.fetch("GOOGLE_OAUTH_CLIENT_ID", nil)
71
+ config.social.google_client_secret = ENV.fetch("GOOGLE_OAUTH_CLIENT_SECRET", nil)
72
+ end
73
+ end
74
+ ```
75
+
76
+ `standard_id` **>= 0.33.0** declares every loaded provider's fields before
77
+ `:load_config_initializers`, so a plain initializer is correct. The wrapper is no
78
+ longer needed and existing ones keep working unchanged.
79
+
80
+ Note this is about *ordering*, not just versions: **the fields do not exist
81
+ without this gem in your Gemfile**, on any `standard_id` version. Configuring
82
+ `social.google_*` with the plugin absent raises the same error, correctly.
83
+
36
84
  ## Testing
37
85
 
38
86
  Run the provider test suite with:
@@ -53,4 +101,4 @@ To release a new version:
53
101
 
54
102
  ## License
55
103
 
56
- The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
104
+ The gem is available as open source under the terms of the [MIT License](LICENSE).
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module StandardId
6
+ module Google
7
+ module Generators
8
+ # Installs the Google provider's credentials block in a host Rails app.
9
+ #
10
+ # Writes `config/initializers/standard_id_google.rb` — a separate file
11
+ # from `config/initializers/standard_id.rb` on purpose. The provider is
12
+ # opt-in per app, so its credentials should be removable by deleting one
13
+ # file, and `standard_id`'s own install generator must stay free to
14
+ # overwrite its initializer without clobbering these values.
15
+ #
16
+ # Initializers load alphabetically, so `standard_id.rb` runs before
17
+ # `standard_id_google.rb` — the base configuration is already applied by
18
+ # the time this file sets the `social.google_*` fields.
19
+ #
20
+ # Idempotent: re-running skips an initializer that is already there.
21
+ # `--skip-initializer` opts out; `--force` overwrites.
22
+ class InstallGenerator < Rails::Generators::Base
23
+ source_root File.expand_path("templates", __dir__)
24
+
25
+ INITIALIZER_PATH = "config/initializers/standard_id_google.rb"
26
+
27
+ desc <<~DESC
28
+ Installs StandardId Google. This writes #{INITIALIZER_PATH} with the
29
+ social.google_* fields wired to ENV, and prints the env vars the host
30
+ needs to set.
31
+
32
+ The generator is idempotent — an existing initializer is skipped with
33
+ a clear message. Pass --force to overwrite.
34
+ DESC
35
+
36
+ class_option :skip_initializer, type: :boolean, default: false,
37
+ desc: "Do not write #{INITIALIZER_PATH}"
38
+ class_option :force, type: :boolean, default: false,
39
+ desc: "Overwrite #{INITIALIZER_PATH} if it already exists"
40
+
41
+ def copy_initializer
42
+ if options[:skip_initializer]
43
+ say_status("skip", "#{INITIALIZER_PATH} (--skip-initializer)", :yellow)
44
+ return
45
+ end
46
+
47
+ if File.exist?(File.join(destination_root, INITIALIZER_PATH)) && !options[:force]
48
+ say_status("identical", "#{INITIALIZER_PATH} (already exists; pass --force to overwrite)", :blue)
49
+ return
50
+ end
51
+
52
+ template "initializer.rb.erb", INITIALIZER_PATH, force: options[:force]
53
+ end
54
+
55
+ def print_env_hint
56
+ return if options[:skip_initializer]
57
+
58
+ say ""
59
+ say "=" * 79
60
+ say "StandardId Google installed."
61
+ say ""
62
+ say "Set these in the host's environment (1Password / DO app spec / .env):"
63
+ say ""
64
+ say " GOOGLE_OAUTH_CLIENT_ID the OAuth 2.0 Web application client ID"
65
+ say " GOOGLE_OAUTH_CLIENT_SECRET its client secret"
66
+ say ""
67
+ say "Register /auth/callback/google as an authorized redirect URI in the"
68
+ say "Google Cloud console for EVERY origin you serve — the console matches"
69
+ say "the redirect exactly, so staging and production each need their own."
70
+ say "=" * 79
71
+ say ""
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Google Sign In credentials for StandardId.
4
+ #
5
+ # These two fields are declared by the standard_id-google gem, NOT by
6
+ # standard_id — they do not exist unless this gem is in the Gemfile, on any
7
+ # standard_id version. Removing the gem and leaving this file behind raises
8
+ # `StandardId::ConfigurationError: Unknown field 'google_client_id' for scope
9
+ # 'social'`, which is correct behaviour, not a bug.
10
+ #
11
+ # Set them in the `social` scope, as below. The unqualified form
12
+ # (`config.google_client_id = ...`) happens to work today because StandardId
13
+ # routes a unique unqualified name to its owning scope, but it stops working
14
+ # the day another scope declares a colliding name. Use `config.social.`.
15
+ #
16
+ # On standard_id <= 0.32.0 these fields were declared from this gem's Railtie
17
+ # `after_initialize`, which runs AFTER config/initializers — so the plain block
18
+ # below raised at boot and had to be wrapped:
19
+ #
20
+ # Rails.application.config.after_initialize do
21
+ # StandardId.configure { |config| config.social.google_client_id = ... }
22
+ # end
23
+ #
24
+ # standard_id >= 0.33.0 declares every loaded provider's fields before
25
+ # `:load_config_initializers`, so the plain form is correct. Existing wrappers
26
+ # keep working and need no change.
27
+ StandardId.configure do |config|
28
+ config.social.google_client_id = ENV.fetch("GOOGLE_OAUTH_CLIENT_ID", nil)
29
+ config.social.google_client_secret = ENV.fetch("GOOGLE_OAUTH_CLIENT_SECRET", nil)
30
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module StandardId
4
4
  module Google
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: standard_id-google
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaryl Sim
8
- bindir: exe
8
+ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
@@ -27,22 +27,22 @@ dependencies:
27
27
  name: standard_id
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - "~>"
31
- - !ruby/object:Gem::Version
32
- version: '0.1'
33
30
  - - ">="
34
31
  - !ruby/object:Gem::Version
35
- version: 0.1.7
32
+ version: '0.29'
33
+ - - "<"
34
+ - !ruby/object:Gem::Version
35
+ version: '1.0'
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - "~>"
41
- - !ruby/object:Gem::Version
42
- version: '0.1'
43
40
  - - ">="
44
41
  - !ruby/object:Gem::Version
45
- version: 0.1.7
42
+ version: '0.29'
43
+ - - "<"
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
46
  description: Extracted StandardId::Providers::Google implementation packaged as a
47
47
  standalone gem so StandardId installations can opt into Sign in with Google independently.
48
48
  email:
@@ -51,22 +51,12 @@ executables: []
51
51
  extensions: []
52
52
  extra_rdoc_files: []
53
53
  files:
54
- - ".claude/hooks/enforce-worktree.sh"
55
- - ".claude/settings.json"
56
- - ".claude/skills/publish-gem/SKILL.md"
57
- - ".claude/skills/start/SKILL.md"
58
- - ".claude/skills/worktree/SKILL.md"
59
- - ".editorconfig"
60
- - ".rspec"
61
- - ".rubocop.yml"
62
- - ".ruby-version"
63
- - AGENTS.md
64
54
  - CHANGELOG.md
65
- - CLAUDE.md
66
- - CODE_OF_CONDUCT.md
67
- - LICENSE.txt
55
+ - LICENSE
68
56
  - README.md
69
57
  - Rakefile
58
+ - lib/generators/standard_id/google/install/install_generator.rb
59
+ - lib/generators/standard_id/google/install/templates/initializer.rb.erb
70
60
  - lib/standard_id/google.rb
71
61
  - lib/standard_id/google/providers/google.rb
72
62
  - lib/standard_id/google/railtie.rb
@@ -1,84 +0,0 @@
1
- #!/bin/bash
2
- # Enforce worktree-only file modifications for Claude Code
3
- #
4
- # Runs on PreToolUse for Edit, Write, and NotebookEdit tools.
5
- # Blocks all file modifications in the main checkout — changes must
6
- # happen inside a git worktree (.worktrees/<name>/).
7
- #
8
- # Exit codes:
9
- # 0 — allow (in a worktree, CI, or non-git path)
10
- # 2 — block (in main checkout)
11
- #
12
- # No programmatic bypass — this is intentional. If the hook itself has a bug,
13
- # a human must fix it manually (edit the file or remove from settings.json).
14
- #
15
- # Note: This hook covers Edit, Write, and NotebookEdit tools. Bash tool writes
16
- # (echo/sed/tee/cp) are not intercepted — the CLAUDE.md instruction is the
17
- # enforcement layer for those. Covering Bash reliably would require parsing
18
- # arbitrary shell commands, which is brittle.
19
-
20
- # Guard: jq required for JSON parsing
21
- if ! command -v jq >/dev/null 2>&1; then
22
- exit 0
23
- fi
24
-
25
- # Skip in CI environments
26
- if [[ "${CI:-}" == "true" ]] || [[ -n "${GITHUB_ACTIONS:-}" ]]; then
27
- exit 0
28
- fi
29
-
30
- INPUT=$(cat)
31
- TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // ""') || exit 0
32
-
33
- # Extract file path based on tool (NotebookEdit uses notebook_path, not file_path)
34
- case "$TOOL_NAME" in
35
- Edit|Write)
36
- FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // ""') || exit 0
37
- ;;
38
- NotebookEdit)
39
- FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.notebook_path // .tool_input.file_path // ""') || exit 0
40
- ;;
41
- *)
42
- exit 0
43
- ;;
44
- esac
45
-
46
- if [[ -z "$FILE_PATH" ]]; then
47
- exit 0
48
- fi
49
-
50
- # Find an existing directory to run git commands in
51
- if [[ -d "$FILE_PATH" ]]; then
52
- CHECK_DIR="$FILE_PATH"
53
- elif [[ -e "$FILE_PATH" ]]; then
54
- CHECK_DIR=$(dirname "$FILE_PATH")
55
- else
56
- # File doesn't exist yet — walk up to find an existing directory
57
- CHECK_DIR=$(dirname "$FILE_PATH")
58
- while [[ ! -d "$CHECK_DIR" ]] && [[ "$CHECK_DIR" != "/" ]]; do
59
- CHECK_DIR=$(dirname "$CHECK_DIR")
60
- done
61
- fi
62
-
63
- if [[ ! -d "$CHECK_DIR" ]]; then
64
- exit 0
65
- fi
66
-
67
- # Check if we're inside a git repository at all
68
- GIT_DIR=$(cd "$CHECK_DIR" && git rev-parse --git-dir 2>/dev/null) || exit 0
69
-
70
- # Make relative paths absolute
71
- if [[ "$GIT_DIR" != /* ]]; then
72
- GIT_DIR=$(cd "$CHECK_DIR" && cd "$GIT_DIR" && pwd) || exit 0
73
- fi
74
-
75
- # If git-dir contains /worktrees/, we're in a worktree — allow
76
- if [[ "$GIT_DIR" == *".git/worktrees/"* ]]; then
77
- exit 0
78
- fi
79
-
80
- # We're in the main checkout — block
81
- echo "❌ Blocked: Cannot modify files in the main checkout." >&2
82
- echo " Create a worktree first: /worktree or /start <issue>" >&2
83
- echo " File: $FILE_PATH" >&2
84
- exit 2
@@ -1,24 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Skill(worktree)",
5
- "Skill(start)",
6
- "Bash(git worktree:*)",
7
- "Bash(git stash:*)"
8
- ]
9
- },
10
- "hooks": {
11
- "PreToolUse": [
12
- {
13
- "matcher": "Edit|Write|NotebookEdit",
14
- "hooks": [
15
- {
16
- "type": "command",
17
- "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/enforce-worktree.sh",
18
- "timeout": 10
19
- }
20
- ]
21
- }
22
- ]
23
- }
24
- }
@@ -1,211 +0,0 @@
1
- ---
2
- name: publish-gem
3
- description: "Publish a Ruby gem to RubyGems.org via CI. Use when the user says 'publish gem', 'push gem', 'release gem', or '/publish-gem'. Handles version bump, changelog, build verification, PR, tagging, and CI-driven publish."
4
- ---
5
-
6
- # Publish Gem Skill
7
-
8
- Prepare and publish a Ruby gem to RubyGems.org via GitHub Actions trusted publishing.
9
-
10
- Publishing is done by CI (not locally) — pushing a version tag triggers the `release.yml` workflow which builds the gem, creates a GitHub Release, and pushes to RubyGems via OIDC. This skill handles everything up to and including the tag push.
11
-
12
- ## Usage
13
-
14
- ```
15
- /publish-gem # Full release flow
16
- /publish-gem --dry-run # Verify everything, stop before PR creation
17
- ```
18
-
19
- ## Workflow
20
-
21
- ### 1. Verify Context
22
-
23
- Confirm we're in a gem project:
24
-
25
- ```bash
26
- # Check current branch
27
- git branch --show-current
28
-
29
- # Must have a .gemspec file
30
- ls *.gemspec
31
- ```
32
-
33
- **Blockers:**
34
- - No `.gemspec` found — stop, not a gem project
35
- - Multiple `.gemspec` files found — ask the user which one to build
36
-
37
- **Branch handling:**
38
- - If not on `main`, switch automatically: `git checkout main` (publishing from non-main is almost never intentional). If the user explicitly requested publishing from a non-main branch, warn and ask for confirmation before switching.
39
- - After switching (or if already on `main`), always sync with remote:
40
- ```bash
41
- git pull --rebase origin main
42
- ```
43
- - If the rebase fails due to conflicts, stop and ask the user to resolve them before proceeding
44
- - After syncing, verify the working tree is clean (`git status --porcelain`). Warn if dirty — the build may include uncommitted changes.
45
- - Clean up any stale `.gem` files in the working directory before proceeding:
46
- ```bash
47
- rm -f *.gem
48
- ```
49
-
50
- ### 2. Extract Gem Metadata
51
-
52
- Read the gemspec to extract key details:
53
-
54
- ```bash
55
- # Get gem name and version
56
- ruby -e "spec = Gem::Specification.load(Dir['*.gemspec'].first); puts \"#{spec.name} #{spec.version}\""
57
- ```
58
-
59
- Also read and display:
60
- - Current version from the gemspec
61
- - CHANGELOG.md entry for this version (if exists)
62
- - `spec.files` count to verify packaging
63
-
64
- ### 3. Pre-Publish Checks
65
-
66
- ```bash
67
- # Check if this version is already published on RubyGems.org
68
- gem info -r <gem_name> -v <version>
69
-
70
- # Check if CHANGELOG.md exists when gemspec references it
71
- ruby -e "spec = Gem::Specification.load(Dir['*.gemspec'].first); puts spec.metadata['changelog_uri']"
72
- test -f CHANGELOG.md && echo "CHANGELOG.md found" || echo "CHANGELOG.md missing"
73
- ```
74
-
75
- **Blockers:**
76
- - Version already published — ask the user what version to bump to (suggest next patch/minor/major). If the user declines, abort the publish.
77
-
78
- **Warnings:**
79
- - Gemspec `changelog_uri` is set but `CHANGELOG.md` does not exist locally — warn the user. This will result in a broken link on RubyGems.org.
80
- - CHANGELOG.md has no entry for the version being published — warn the user. The `release.yml` workflow will fail if no changelog entry exists for the version.
81
-
82
- ### 4. Version Bump (if needed)
83
-
84
- When the current version is already published, or the user requests a bump:
85
-
86
- 1. Update `lib/<gem_name>/version.rb` with the new version
87
- 2. Run `bundle install` to sync `Gemfile.lock`
88
-
89
- **Critical:** Always run `bundle install` after changing the version to keep `Gemfile.lock` in sync. Skipping this causes CI failures.
90
-
91
- ### 5. Update CHANGELOG.md
92
-
93
- If the `[Unreleased]` section in CHANGELOG.md has content:
94
- 1. Rename `[Unreleased]` to `[<version>] - <today's date>` (format: YYYY-MM-DD)
95
- 2. Add a new empty `[Unreleased]` section above it
96
-
97
- If `[Unreleased]` is empty, warn the user and ask if they want to proceed without changelog entries for this version.
98
-
99
- ### 6. Run Tests
100
-
101
- ```bash
102
- bundle exec rspec
103
- ```
104
-
105
- **Blockers:**
106
- - Tests fail — stop and ask the user to fix. Do not proceed with a failing test suite.
107
-
108
- ### 7. Build Verification
109
-
110
- ```bash
111
- gem build <name>.gemspec
112
- ```
113
-
114
- Verify the `.gem` file was created, show its size, then clean up:
115
-
116
- ```bash
117
- rm <name>-<version>.gem
118
- ```
119
-
120
- ### 8. Release Summary
121
-
122
- Present a summary before proceeding:
123
-
124
- ```
125
- ## Release Summary
126
-
127
- Name: <gem_name>
128
- Version: <version>
129
- Files: <file count> files in gem
130
- Registry: https://rubygems.org (published by CI via trusted publisher)
131
-
132
- Changelog:
133
- <first few lines of the version's CHANGELOG entry>
134
-
135
- Next steps:
136
- 1. Create version bump PR
137
- 2. Merge PR (manual)
138
- 3. Tag release → CI publishes to RubyGems + creates GitHub Release
139
- ```
140
-
141
- If `--dry-run` was passed, stop here.
142
-
143
- ### 9. Create Version Bump PR
144
-
145
- Commit the version bump, changelog, and lockfile on a branch and open a PR:
146
-
147
- ```bash
148
- git checkout -b chore/release-v<version>
149
- git add lib/<gem_name>/version.rb Gemfile.lock CHANGELOG.md
150
- git commit -m "chore: Release v<version>"
151
- git push -u origin chore/release-v<version>
152
- gh pr create --title "chore: Release v<version>" --body "$(cat <<'EOF'
153
- ## Release v<version>
154
-
155
- <changelog entry for this version>
156
-
157
- After merging, Claude will tag `v<version>` which triggers CI to:
158
- - Create a GitHub Release with changelog notes
159
- - Build and publish the gem to RubyGems.org via trusted publisher
160
- EOF
161
- )"
162
- ```
163
-
164
- Tell the user to review and merge the PR, then let you know when it's merged.
165
-
166
- ### 10. Tag the Release (after PR merge)
167
-
168
- When the user confirms the PR is merged:
169
-
170
- ```bash
171
- # Sync main — use reset to avoid divergent branch issues from squash merge
172
- git checkout main
173
- git fetch origin main
174
- git reset --hard origin/main
175
-
176
- # Tag the merged commit
177
- git tag -a v<version> -m "Release v<version>"
178
- git push origin v<version>
179
-
180
- # Clean up the bump branch locally
181
- # -D needed because squash merge doesn't preserve individual commits in main's history
182
- git branch -D chore/release-v<version>
183
- # Remote branch may already be deleted by GitHub's auto-delete setting — ignore errors
184
- git push origin --delete chore/release-v<version> 2>/dev/null || true
185
- ```
186
-
187
- The tag push triggers `release.yml` which:
188
- 1. Verifies the tag version matches `version.rb`
189
- 2. Waits for CI to pass
190
- 3. Extracts changelog notes and creates a GitHub Release
191
- 4. Builds the gem and publishes to RubyGems.org via OIDC trusted publisher
192
-
193
- ### 11. Output
194
-
195
- Report:
196
- 1. RubyGems URL: `https://rubygems.org/gems/<name>` (available after CI completes)
197
- 2. Git tag created: `v<version>`
198
- 3. GitHub Release + RubyGems publish: triggered by CI — link: `https://github.com/<owner>/<repo>/actions`
199
- 4. Remind: allow a few minutes for CI to complete, then the gem will appear on RubyGems and the GitHub Release will be created
200
-
201
- ## Error Handling
202
-
203
- | Error | Solution |
204
- |-------|----------|
205
- | `gem build` fails | Fix gemspec errors and retry |
206
- | Tests fail | Fix tests before proceeding |
207
- | Tag already exists | Version was previously tagged — skip tagging |
208
- | Tag push fails | Likely a permissions issue — report and continue |
209
- | Remote branch already deleted | GitHub auto-deleted it — ignore the error |
210
- | User declines version bump | Abort the publish |
211
- | CI publish fails | Check the Actions tab — common causes: trusted publisher not configured on RubyGems.org, `rubygems` environment not set up in GitHub repo settings, or version mismatch between tag and version.rb |
@@ -1,185 +0,0 @@
1
- ---
2
- name: start
3
- description: "Start working on Linear issues. Use when the user says 'start working on', 'pick up issue', 'work on RAR-123', or wants to begin development on Linear issues. Handles status updates, branch creation, and context gathering."
4
- ---
5
-
6
- # Start Skill
7
-
8
- Begin working on Linear issues with proper setup: update status, create branches, gather context, and track progress.
9
-
10
- ## Prerequisites
11
-
12
- This skill requires the Linear MCP server to be configured. If Linear tools (`mcp__linear__*`) are not available, the skill will warn and offer to proceed with git-only setup (branch creation without status updates).
13
-
14
- ## Scope
15
-
16
- This skill sets up local development for Linear issues. It does **NOT**:
17
- - Merge PRs to main (merging is a human decision)
18
- - Delete branches or worktrees automatically
19
- - Close or complete Linear issues
20
-
21
- ## Usage
22
-
23
- ```
24
- /start <issue-identifiers...> # Start specific issues (e.g., /start RAR-123 RAR-124)
25
- /start --mine # Show my assigned issues ready to start
26
- /start --backlog # Show backlog issues for a team
27
- ```
28
-
29
- ## Workflow
30
-
31
- > **Note:** MCP tool calls shown below use pseudocode syntax for readability.
32
- > Actual invocation uses Claude's tool use API with the `mcp__linear__*` tools.
33
-
34
- ### 1. Parse Input and Fetch Issues
35
-
36
- **If specific identifiers provided:**
37
-
38
- Fetch each issue using Linear MCP:
39
-
40
- ```
41
- mcp__linear__get_issue(id: "RAR-123", includeRelations: true)
42
- ```
43
-
44
- **If `--mine` flag:**
45
-
46
- ```
47
- mcp__linear__list_issues(assignee: "me", state: "Todo", limit: 10)
48
- ```
49
-
50
- **If `--backlog` flag (with optional `--team` and `--project` filters):**
51
-
52
- ```
53
- mcp__linear__list_issues(
54
- team: "<from --team flag, default: Rarebit>",
55
- project: "<from --project flag, if provided>",
56
- state: "Backlog",
57
- limit: 10
58
- )
59
- ```
60
-
61
- Present the issues and let the user select which to work on.
62
-
63
- ### 2. Pre-Work Checks
64
-
65
- Before starting, verify:
66
-
67
- **Check for blockers:**
68
-
69
- ```
70
- # From get_issue with includeRelations: true
71
- # Look at the blocking/blockedBy relations
72
- ```
73
-
74
- If blocked:
75
- ```
76
- Warning: RAR-123 is blocked by:
77
- - RAR-120: "Set up middleware" (In Progress)
78
-
79
- Options:
80
- 1. Start anyway (work may be blocked)
81
- 2. Start the blocking issue instead
82
- 3. Cancel
83
- ```
84
-
85
- **Check issue readiness:**
86
- - Has description/acceptance criteria?
87
- - Has assigned estimate?
88
-
89
- If missing context, warn but allow proceeding.
90
-
91
- ### 3. Update Issue Status
92
-
93
- **Skip this step if `--no-status` flag is provided.**
94
-
95
- Update each issue to "In Progress":
96
-
97
- ```
98
- mcp__linear__save_issue(
99
- id: "<issue-uuid>",
100
- stateId: "<in-progress-state-id>"
101
- )
102
- ```
103
-
104
- The workflow should not block on Linear failures — local development can proceed.
105
-
106
- ### 4. Set Up Worktree
107
-
108
- **Always create a worktree** to isolate this work from any other state in the repo. This prevents changes from different sessions bleeding into unrelated PRs.
109
-
110
- ```bash
111
- DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@refs/remotes/origin/@@')
112
- DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
113
- git fetch origin "$DEFAULT_BRANCH"
114
- git worktree add .worktrees/<identifier> -b <branch-name> "origin/$DEFAULT_BRANCH"
115
- ```
116
-
117
- **`--no-worktree` flag:** If the user explicitly passes `--no-worktree`, check the current state:
118
- - On the default branch with a clean working tree → fall back to a simple branch:
119
- ```bash
120
- DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@refs/remotes/origin/@@')
121
- DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
122
- git fetch origin "$DEFAULT_BRANCH"
123
- git checkout -b <branch-name> "origin/$DEFAULT_BRANCH"
124
- ```
125
- - Otherwise → **stop and report why**:
126
- _"Cannot skip worktree: working tree has uncommitted changes (or is on a feature branch). Stash or commit your changes first, switch to the default branch, then re-run with `--no-worktree`."_
127
-
128
- > **Note:** The previous version of this skill offered stash and branch-switch workflows. Those paths have been removed in favor of always using worktrees. If you prefer to stash instead, run `git stash push -m "WIP"` manually before `/start`.
129
-
130
- See `/worktree` skill for full worktree conventions.
131
-
132
- **Branch name format:**
133
-
134
- Use Linear's `gitBranchName` field if available, or generate:
135
- `{identifier}/{short-description}` (e.g., `rar-123/add-feature-name`)
136
-
137
- **Worktree naming:** `.worktrees/<identifier>` (e.g., `.worktrees/rar-123`)
138
-
139
- ### 5. Display Issue Context
140
-
141
- ```
142
- Starting: RAR-123
143
- Issue: <title>
144
- URL: https://linear.app/...
145
-
146
- Description:
147
- <full description>
148
-
149
- Acceptance Criteria:
150
- - [ ] ...
151
-
152
- Branch: <branch-name>
153
- ```
154
-
155
- ### 6. Create Initial Todo List
156
-
157
- Based on the issue description, create a todo list to track progress.
158
-
159
- ## Flags Reference
160
-
161
- | Flag | Description |
162
- |------|-------------|
163
- | `--mine` | List my assigned issues in Todo state |
164
- | `--backlog` | List team backlog issues |
165
- | `--no-worktree` | Skip worktree if on the default branch + clean; stops with error otherwise |
166
- | `--no-status` | Skip status update (just create branch) |
167
- | `--team <name>` | Filter by team (default: Rarebit) |
168
- | `--project <name>` | Filter by project |
169
-
170
- ## Error Handling
171
-
172
- | Error | Solution |
173
- |-------|----------|
174
- | Linear MCP unavailable | Warn and offer to proceed with just git setup |
175
- | Issue not found | Verify identifier, check team access |
176
- | Issue already in progress | Ask if user wants to continue anyway |
177
- | Issue is done/canceled | Warn and suggest reopening or selecting different issue |
178
- | Status update fails | Offer to continue with local setup, retry, or cancel |
179
- | Branch already exists | Offer to checkout existing or create with suffix |
180
- | Worktree already exists | Offer to use existing worktree or create with suffix |
181
-
182
- ## Integration with Other Skills
183
-
184
- - After completing work, create a PR with `gh pr create`, or use `/publish-gem` when ready to release
185
- - The branch naming convention ensures the Linear issue can be auto-detected from the branch
@@ -1,143 +0,0 @@
1
- ---
2
- name: worktree
3
- description: "Create an isolated worktree for new work. Always creates a worktree by default to prevent cross-contamination between sessions. Use at the start of any session, or when the user says 'worktree', 'isolate', 'fresh start', or 'new worktree'."
4
- ---
5
-
6
- # Worktree Skill
7
-
8
- Creates an isolated worktree for new work. **Always creates a worktree by default** — this prevents changes from different work sessions bleeding into unrelated PRs.
9
-
10
- ## Why Worktree-by-Default
11
-
12
- Every new piece of work gets its own worktree. This eliminates the most common source of cross-contamination: starting new work in a repo that has leftover state from a previous session (uncommitted changes, wrong branch, etc.). The only exception is when the user explicitly opts out.
13
-
14
- > **Note:** The previous version of this skill offered a stash-based workflow. That path has been removed in favor of always using worktrees. If you prefer to stash instead, run `git stash push -m "WIP"` manually before invoking `/start` or `/worktree`.
15
-
16
- ## Why `.worktrees/`
17
-
18
- Worktrees are created inside the repo at `.worktrees/<name>` (not under `.claude/worktrees/`). This ensures:
19
- - Worktrees are accessible inside devcontainers (mounted at `/workspace/.worktrees/`)
20
- - Consistent convention across all repos in the workspace
21
- - The `.worktrees/` directory is gitignored in each repo
22
-
23
- ## Usage
24
-
25
- ```
26
- /worktree # Create a worktree (always, regardless of state)
27
- /worktree <name> # Create a named worktree directly
28
- /worktree --stay # Skip worktree creation, work in current checkout
29
- ```
30
-
31
- ## Workflow
32
-
33
- ### Phase 1: Detect Current State
34
-
35
- Gather the repo state (for reporting, not for deciding whether to create a worktree):
36
-
37
- ```bash
38
- # Current branch
39
- CURRENT_BRANCH=$(git branch --show-current)
40
-
41
- # Default branch
42
- DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@refs/remotes/origin/@@')
43
- DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
44
-
45
- # Uncommitted changes (staged + unstaged + untracked)
46
- git status --porcelain
47
- ```
48
-
49
- ### Phase 2: Decision
50
-
51
- **Default behavior:** Always create a worktree. Go straight to Phase 3 → Phase 4. Any uncommitted changes on the current branch are left untouched — the worktree is a separate checkout, so existing work is preserved exactly as-is.
52
-
53
- **`--stay` flag:** Skip worktree creation and stay in the current checkout. This is for when the user explicitly wants to continue work on the current branch (e.g., resuming a previous session). If dirty state is detected, inform the user what's there but **do not stop** — the user is consciously choosing to stay. This differs from `/start --no-worktree`, which hard-stops on dirty state because starting new work on an unclean tree risks cross-contamination.
54
-
55
- ### Phase 3: Fetch Latest
56
-
57
- Always fetch the latest default branch, regardless of whether a worktree will be created:
58
-
59
- ```bash
60
- git fetch origin "$DEFAULT_BRANCH"
61
- ```
62
-
63
- This ensures any new branch or worktree starts from the latest codebase.
64
-
65
- ### Phase 4: Create Worktree
66
-
67
- **Naming convention:**
68
-
69
- If a name is provided (e.g., from a Linear issue identifier):
70
- ```bash
71
- git worktree add .worktrees/<name> -b <branch-name> "origin/$DEFAULT_BRANCH"
72
- ```
73
-
74
- If no name is provided, generate one from context:
75
- - If starting a Linear issue: use the issue identifier (e.g., `swe-123`)
76
- - If the user described the task: use a short slug (e.g., `fix-auth-timeout`)
77
- - Fallback: use today's date in `YYYY-MM-DD` format
78
-
79
- **Ensure `.worktrees/` is gitignored:**
80
-
81
- ```bash
82
- # Check if .worktrees is already in .gitignore
83
- if ! grep -q '\.worktrees' .gitignore 2>/dev/null; then
84
- echo '.worktrees/' >> .gitignore
85
- fi
86
- ```
87
-
88
- ### Phase 5: Report
89
-
90
- After setup, display:
91
-
92
- ```
93
- Worktree created at: .worktrees/<name>
94
- Branch: <branch-name>
95
- Based on: origin/$DEFAULT_BRANCH (fetched latest)
96
-
97
- Previous state preserved:
98
- Branch: <original-branch>
99
- Changes: <summary of uncommitted changes left behind, if any>
100
-
101
- Working directory: .worktrees/<name>
102
- ```
103
-
104
- If `--stay` was used:
105
-
106
- ```
107
- Staying in current checkout: <branch>
108
- (fetched latest origin/$DEFAULT_BRANCH)
109
- <summary of uncommitted changes, if any>
110
-
111
- To create a new branch:
112
- git checkout -b <branch-name> origin/$DEFAULT_BRANCH
113
- ```
114
-
115
- ## Integration with /start
116
-
117
- The `/start` skill always creates a worktree as part of its workflow. Both skills follow the same conventions:
118
- - Worktrees go in `.worktrees/`
119
- - Always fetch latest before creating
120
- - Naming follows the `<identifier>` convention (e.g., `.worktrees/swe-123`)
121
-
122
- **Opt-out flags differ by context:**
123
- - `/worktree --stay` — "stay in current checkout" (you invoked the worktree tool, you're opting out of its action; dirty state is allowed)
124
- - `/start --no-worktree` — "don't create a worktree" (you're starting new work, skipping one aspect; dirty state causes a hard stop)
125
-
126
- This `/worktree` skill can also be invoked independently when you want to isolate work without picking up a Linear issue.
127
-
128
- ## Error Handling
129
-
130
- | Error | Solution |
131
- |-------|----------|
132
- | `.worktrees/<name>` already exists | Offer to reuse existing or create with suffix |
133
- | Branch name already exists | Check out existing branch in the worktree instead of `-b` |
134
- | No origin remote | Create worktree from local default branch HEAD |
135
- | Fetch fails | Warn and create from local default branch HEAD |
136
- | `.gitignore` is read-only | Warn the user to add `.worktrees/` manually |
137
-
138
- ## Safety Rules
139
-
140
- 1. **Never discard uncommitted changes** - the whole point is to preserve them
141
- 2. **Never force-checkout** over dirty state - always worktree instead
142
- 3. **Always fetch before creating** - worktrees should start from latest
143
- 4. **This skill only creates worktrees** - it does not remove or clean up stale ones
data/.editorconfig DELETED
@@ -1,15 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_style = space
5
- indent_size = 2
6
- end_of_line = lf
7
- charset = utf-8
8
- trim_trailing_whitespace = true
9
- insert_final_newline = true
10
-
11
- [*.md]
12
- trim_trailing_whitespace = false
13
-
14
- [Makefile]
15
- indent_style = tab
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,8 +0,0 @@
1
- # Omakase Ruby styling for Rails
2
- inherit_gem: { rubocop-rails-omakase: rubocop.yml }
3
-
4
- # Overwrite or add rules to create your own house style
5
-
6
- # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
7
- Layout/SpaceInsideArrayLiteralBrackets:
8
- EnforcedStyle: no_space
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 4.0.1
data/AGENTS.md DELETED
@@ -1,71 +0,0 @@
1
- # AGENTS.md - AI Agent Guide for standard_id-google
2
-
3
- `standard_id-google` is a provider plugin for the [StandardId](https://github.com/rarebit-one/standard_id) authentication engine. It packages a `StandardId::Providers::Google` implementation for Sign in with Google, and auto-registers itself with the host StandardId installation via a `Rails::Railtie` so apps that bundle the gem don't need an explicit initializer.
4
-
5
- ## Quick Reference
6
-
7
- ```bash
8
- # Run tests
9
- bundle exec rspec
10
-
11
- # Run a single spec file
12
- bundle exec rspec spec/standard_id/google/providers/google_spec.rb
13
-
14
- # Run linting (note: --config flag is required on Ruby 4.0)
15
- bundle exec rubocop --config .rubocop.yml
16
-
17
- # Auto-fix lint issues
18
- bundle exec rubocop --config .rubocop.yml -A
19
- ```
20
-
21
- ## Project Structure
22
-
23
- ```
24
- standard_id-google/
25
- ├── lib/standard_id/
26
- │ ├── google.rb # Top-level require entrypoint
27
- │ └── google/
28
- │ ├── version.rb # Gem version constant
29
- │ ├── railtie.rb # Auto-registers provider on after_initialize
30
- │ └── providers/google.rb # StandardId::Providers::Google implementation
31
- └── spec/
32
- ├── spec_helper.rb # Boots a minimal Rails app so the Railtie fires
33
- └── standard_id/ # Provider specs
34
- ```
35
-
36
- ## Key Patterns
37
-
38
- ### Provider class
39
-
40
- `StandardId::Providers::Google` inherits from `StandardId::Providers::Base` (defined in the parent `standard_id` gem) and implements the provider contract: `provider_name`, `authorization_url`, `get_user_info`, `config_schema`, plus Google-specific helpers (`verify_id_token`, `fetch_user_info`, code/token exchange via Google's tokeninfo + userinfo endpoints).
41
-
42
- ### Railtie auto-registration
43
-
44
- `StandardId::Google::Railtie` runs on `config.after_initialize` and calls `StandardId::ProviderRegistry.register(:google, StandardId::Providers::Google)`. Host apps just need the gem in their Gemfile — no initializer required.
45
-
46
- ### Spec bootstrapping
47
-
48
- `spec/spec_helper.rb` defines a tiny `Rails::Application` and calls `Rails.application.initialize!` so the Railtie's `after_initialize` hook fires during the spec run; without this the provider would not appear in the registry.
49
-
50
- ## Key Files
51
-
52
- | File | Purpose |
53
- |------|---------|
54
- | `lib/standard_id/google.rb` | Top-level require entrypoint |
55
- | `lib/standard_id/google/railtie.rb` | Provider registration on Rails boot |
56
- | `lib/standard_id/google/providers/google.rb` | Google provider implementation |
57
- | `lib/standard_id/google/version.rb` | Gem version constant |
58
- | `standard_id-google.gemspec` | Gem metadata + runtime deps |
59
-
60
- ## Dependencies
61
-
62
- - **standard_id** `~> 0.1`, `>= 0.1.7` (parent engine — provides `Providers::Base`, `ProviderRegistry`, `HttpClient`, errors)
63
- - **activesupport** `>= 8.0` (`present?`/`blank?`, indifferent access)
64
-
65
- Dev: rspec, rubocop, webmock, lefthook.
66
-
67
- ## Testing
68
-
69
- - WebMock stubs Google's tokeninfo and userinfo endpoints — never make real network calls in specs.
70
- - The dummy Rails app in `spec_helper.rb` is intentionally minimal; add config via `StandardId.config.google_*` setters in individual specs rather than expanding the dummy app.
71
- - CI runs the full Ruby 4.0.x patch matrix via the shared `rarebit-one/.github` reusable workflow.
data/CLAUDE.md DELETED
@@ -1,26 +0,0 @@
1
- # CLAUDE.md
2
-
3
- ## Worktree-Only Workflow (Enforced)
4
-
5
- **All file modifications are blocked in the main checkout.** A PreToolUse hook (`enforce-worktree.sh`) rejects Edit, Write, and NotebookEdit operations targeting files outside a worktree. There are no opt-outs. Do not use Bash to write files in the main checkout either (e.g., `echo >`, `sed -i`, `tee`, `cp`) — the hook cannot intercept shell commands, so this rule is instruction-enforced.
6
-
7
- Before writing any code, create a worktree:
8
-
9
- ```bash
10
- DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@refs/remotes/origin/@@')
11
- DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
12
- git fetch origin "$DEFAULT_BRANCH"
13
- git worktree add .worktrees/<name> -b <branch-name> "origin/$DEFAULT_BRANCH"
14
- ```
15
-
16
- Then work inside `.worktrees/<name>/` for the rest of the session.
17
-
18
- **Naming:** Use the Linear issue identifier if available (e.g., `.worktrees/<identifier>`), a task slug (e.g., `.worktrees/fix-auth-timeout`), or today's date (e.g., `.worktrees/2026-04-01`) as fallback.
19
-
20
- **The hook allows modifications only when:**
21
-
22
- 1. The file is inside a git worktree (detected via `git rev-parse --git-dir` returning a path under `.git/worktrees/`)
23
- 2. Running in a CI/automated context where the checkout is already isolated
24
- **Why this matters:** Working directly on the main checkout causes cross-contamination between sessions — uncommitted changes, wrong branches, and dirty state leak into unrelated work. Worktrees eliminate this entirely.
25
-
26
- See the `/worktree` and `/start` skills for full conventions and flags.
data/CODE_OF_CONDUCT.md DELETED
@@ -1,132 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- We as members, contributors, and leaders pledge to make participation in our
6
- community a harassment-free experience for everyone, regardless of age, body
7
- size, visible or invisible disability, ethnicity, sex characteristics, gender
8
- identity and expression, level of experience, education, socio-economic status,
9
- nationality, personal appearance, race, caste, color, religion, or sexual
10
- identity and orientation.
11
-
12
- We pledge to act and interact in ways that contribute to an open, welcoming,
13
- diverse, inclusive, and healthy community.
14
-
15
- ## Our Standards
16
-
17
- Examples of behavior that contributes to a positive environment for our
18
- community include:
19
-
20
- * Demonstrating empathy and kindness toward other people
21
- * Being respectful of differing opinions, viewpoints, and experiences
22
- * Giving and gracefully accepting constructive feedback
23
- * Accepting responsibility and apologizing to those affected by our mistakes,
24
- and learning from the experience
25
- * Focusing on what is best not just for us as individuals, but for the overall
26
- community
27
-
28
- Examples of unacceptable behavior include:
29
-
30
- * The use of sexualized language or imagery, and sexual attention or advances of
31
- any kind
32
- * Trolling, insulting or derogatory comments, and personal or political attacks
33
- * Public or private harassment
34
- * Publishing others' private information, such as a physical or email address,
35
- without their explicit permission
36
- * Other conduct which could reasonably be considered inappropriate in a
37
- professional setting
38
-
39
- ## Enforcement Responsibilities
40
-
41
- Community leaders are responsible for clarifying and enforcing our standards of
42
- acceptable behavior and will take appropriate and fair corrective action in
43
- response to any behavior that they deem inappropriate, threatening, offensive,
44
- or harmful.
45
-
46
- Community leaders have the right and responsibility to remove, edit, or reject
47
- comments, commits, code, wiki edits, issues, and other contributions that are
48
- not aligned to this Code of Conduct, and will communicate reasons for moderation
49
- decisions when appropriate.
50
-
51
- ## Scope
52
-
53
- This Code of Conduct applies within all community spaces, and also applies when
54
- an individual is officially representing the community in public spaces.
55
- Examples of representing our community include using an official email address,
56
- posting via an official social media account, or acting as an appointed
57
- representative at an online or offline event.
58
-
59
- ## Enforcement
60
-
61
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
- reported to the community leaders responsible for enforcement at
63
- [INSERT CONTACT METHOD].
64
- All complaints will be reviewed and investigated promptly and fairly.
65
-
66
- All community leaders are obligated to respect the privacy and security of the
67
- reporter of any incident.
68
-
69
- ## Enforcement Guidelines
70
-
71
- Community leaders will follow these Community Impact Guidelines in determining
72
- the consequences for any action they deem in violation of this Code of Conduct:
73
-
74
- ### 1. Correction
75
-
76
- **Community Impact**: Use of inappropriate language or other behavior deemed
77
- unprofessional or unwelcome in the community.
78
-
79
- **Consequence**: A private, written warning from community leaders, providing
80
- clarity around the nature of the violation and an explanation of why the
81
- behavior was inappropriate. A public apology may be requested.
82
-
83
- ### 2. Warning
84
-
85
- **Community Impact**: A violation through a single incident or series of
86
- actions.
87
-
88
- **Consequence**: A warning with consequences for continued behavior. No
89
- interaction with the people involved, including unsolicited interaction with
90
- those enforcing the Code of Conduct, for a specified period of time. This
91
- includes avoiding interactions in community spaces as well as external channels
92
- like social media. Violating these terms may lead to a temporary or permanent
93
- ban.
94
-
95
- ### 3. Temporary Ban
96
-
97
- **Community Impact**: A serious violation of community standards, including
98
- sustained inappropriate behavior.
99
-
100
- **Consequence**: A temporary ban from any sort of interaction or public
101
- communication with the community for a specified period of time. No public or
102
- private interaction with the people involved, including unsolicited interaction
103
- with those enforcing the Code of Conduct, is allowed during this period.
104
- Violating these terms may lead to a permanent ban.
105
-
106
- ### 4. Permanent Ban
107
-
108
- **Community Impact**: Demonstrating a pattern of violation of community
109
- standards, including sustained inappropriate behavior, harassment of an
110
- individual, or aggression toward or disparagement of classes of individuals.
111
-
112
- **Consequence**: A permanent ban from any sort of public interaction within the
113
- community.
114
-
115
- ## Attribution
116
-
117
- This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
- version 2.1, available at
119
- [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
-
121
- Community Impact Guidelines were inspired by
122
- [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
-
124
- For answers to common questions about this code of conduct, see the FAQ at
125
- [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
- [https://www.contributor-covenant.org/translations][translations].
127
-
128
- [homepage]: https://www.contributor-covenant.org
129
- [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
- [Mozilla CoC]: https://github.com/mozilla/diversity
131
- [FAQ]: https://www.contributor-covenant.org/faq
132
- [translations]: https://www.contributor-covenant.org/translations