feat: user-global settings tier + hook gates (global enable, PR 1/3) - #1894
Open
peyton-alt wants to merge 2 commits into
Open
feat: user-global settings tier + hook gates (global enable, PR 1/3)#1894peyton-alt wants to merge 2 commits into
peyton-alt wants to merge 2 commits into
Conversation
New ~/.config/entire/settings.json tier (via userdirs) with global.enabled, exclude_paths (doublestar vs worktree root), exclude_origins (doublestar vs normalized host/owner/repo). IsActiveForRepo is the new gate predicate: repo-level setup always wins; the global tier is a fallback, never a merge layer. All error paths fail closed. Review hardening: strict JSON decoding, fail-closed origin lookup (new gitremote.GetRemoteURLInDirIfSet distinguishes unset from failed), case-folded path matching on case-insensitive filesystems, trailing-slash pattern normalization, and debug logging on every skipped/failed input. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 01KZ4X27VH2530080P3WE92P1W
The agent-hook and git-hook gates now use settings.IsActiveForRepo: repos with no repo-level setup proceed when global mode is enabled and the repo is not excluded. Repos with any repo-level setup keep exactly their current behavior. Dark-launched: no user-facing command writes the global settings file yet (that arrives with enable --global in a later PR). The defense-in-depth check inside initHookLogging converts too: all hook-path gates must agree on a single predicate. A split gate would mean global-mode repos do full lifecycle work with no hook logging and no EnsureRedactionConfigured() call (privacy-relevant). The resulting .entire/logs worktree write in global-mode repos is deliberately deferred to PR 2, which reroutes .entire writes for invisible-mode repos; nothing can trigger it in this PR's dark-launch state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 01KZ4Y5BBHBDE8W11125Y82SSE
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new user-global settings tier (dark-launched) and updates hook gating to treat a repo as “active” either via existing repo-level setup or (when absent) via the global tier, enabling groundwork for “global auto-enable” (#1098).
Changes:
- Add parsing and evaluation of
~/.config/entire/settings.json(viaENTIRE_CONFIG_DIR) with global enable + exclude rules, and a unifiedsettings.IsActiveForRepopredicate. - Switch all hook gates (git hook entry + agent hook dispatch + hook logging init) to use the unified predicate.
- Add supporting git-remote utilities and unit tests for global-mode matching and multi-URL remotes.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| go.mod | Adds github.com/bmatcuk/doublestar/v4 dependency for glob matching. |
| go.sum | Records checksums for the new doublestar dependency. |
| cmd/entire/cli/settings/global.go | Implements user-global settings loading, exclude matching, GlobalModeActive, and IsActiveForRepo. |
| cmd/entire/cli/settings/global_test.go | Adds unit tests covering global settings parsing and activation semantics (including excludes). |
| cmd/entire/cli/settings/global_darwin_test.go | Adds a darwin-only test to pin case-folding wiring for exclude path matching. |
| cmd/entire/cli/hooks_git_cmd.go | Updates hook command gating and hook logging init to use settings.IsActiveForRepo. |
| cmd/entire/cli/hooks_git_cmd_test.go | Adds a test asserting hook logging initializes under global mode with no repo-level setup. |
| cmd/entire/cli/hook_registry.go | Updates agent hook dispatch short-circuiting to use settings.IsActiveForRepo. |
| cmd/entire/cli/gitremote/gitremote.go | Adds GetRemoteURLsInDirIfSet to support multi-URL origin matching and “unset vs error” semantics. |
| cmd/entire/cli/gitremote/gitremote_test.go | Adds tests for GetRemoteURLsInDirIfSet behavior (missing, multiple URLs, errors). |
Comment on lines
+238
to
+243
| func IsActiveForRepo(ctx context.Context) bool { | ||
| if IsSetUpAny(ctx) { | ||
| return IsSetUpAndEnabled(ctx) | ||
| } | ||
| return GlobalModeActive(ctx) | ||
| } |
Comment on lines
+44
to
+48
| // ExcludeOrigins are doublestar globs matched against the origin remote | ||
| // URL normalized to host/owner/repo. A repo without an origin matches | ||
| // no origin pattern. Origins stored via git insteadOf shorthands (e.g. | ||
| // gh:acme/widgets) normalize to the shorthand form, not the expanded | ||
| // host — patterns match what git config stores. |
Comment on lines
+183
to
+188
| // Initialize git repo | ||
| gitInit := exec.CommandContext(context.Background(), "git", "init") | ||
| gitInit.Dir = tmpDir | ||
| if err := gitInit.Run(); err != nil { | ||
| t.Fatalf("failed to init git repo: %v", err) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
https://entire.io/gh/entireio/cli/trails/968
First of three PRs building global auto-enable (#1098). This PR adds the user-global settings tier and wires it into the hook gates.
Dark-launch state
No user-facing command writes
~/.config/entire/settings.jsonyet — that arrives in PR 3 asenable --global. Until then, no repo can observe the global tier unless the file is hand-authored, so behavior is unchanged for everyone.IsActiveForReposemanticsRepo-level setup always wins; the global tier is consulted only when no repo-level setup exists.
Exclude semantics
exclude_pathsare~-expanded doublestar globs matched against the worktree root. A bare-directory pattern also excludes everything under it:~/ossexcludes~/oss/repobut cannot over-match~/oss-other. Matching is case-folded on darwin/windows.exclude_originsmatch against any configured origin URL, normalized tohost/owner/repo.Hook gates
The third gate (
initHookLogging) was converted as well, so all hook gates now share one predicate.Deliberately deferred follow-ups
GlobalModeActiveper process before PR 3 shipsenable --global. Cost today:exclude_originsforksgit configper gate evaluation (~11ms × 2 per hook event). Memoization also makes the twice-evaluated gate atomic per invocation.InitHookLoggingtests (baregit init→testutilhelpers).🤖 Generated with Claude Code
Note
Medium Risk
Hook activation semantics change whenever a hand-authored global settings file enables the tier; mistakes in exclude rules or origin lookup failures disable global mode fail-closed, but repos without repo-level setup could start running Entire hooks unexpectedly once global is on.
Overview
Introduces a user-global settings tier (
~/.config/entire/settings.jsonviaENTIRE_CONFIG_DIR) with aglobalsection:enabled,exclude_paths(tilde-expanded doublestar globs on the worktree root, case-folded on darwin/windows), andexclude_origins(globs on normalizedhost/owner/repo). Loading is strict (DisallowUnknownFields); missing file is unconfigured; read/parse errors fail closed on the hook path.Adds
IsActiveForRepo: if any repo-level setup exists, repo enable/disable (and read errors) win and global is ignored; otherwiseGlobalModeActiveapplies (enabled global + not excluded). Origin exclusion uses newGetRemoteURLsInDirIfSet(git config --get-all) so multipleoriginURLs and “remote unset” vs real errors are handled correctly.Git and agent hook entry points (
hooks_git_cmd,hook_registry,initHookLogging) now gate onIsActiveForRepoinstead ofIsSetUpAndEnabled, including a test that hook logging initializes under global mode without.entire/settings.json. Addsdoublestar/v4and broad unit tests; no user-facing command writes the global file yet (dark launch until a later PR).Reviewed by Cursor Bugbot for commit f6b4403. Configure here.