From d942b847cc600c8bb31a71bb7152086dbcee1b17 Mon Sep 17 00:00:00 2001 From: NagyVikt Date: Wed, 22 Apr 2026 13:52:52 +0200 Subject: [PATCH 1/2] Make top-level-only repo scoping consistent across setup and doctor Users already learn gx doctor --current, but gx setup still required --no-recursive for the same traversal behavior. This change accepts --current in the shared traversal parser, updates setup-facing copy, and locks the behavior with a focused setup regression. Constraint: Setup and doctor share the same nested-repo traversal defaults Rejected: Keep --current doctor-only | setup/doctor surface drift stays confusing Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep traversal aliases wired through parseRepoTraversalArgs so setup and doctor do not drift again Tested: node --check bin/multiagent-safety.js; node --test test/setup.test.js; openspec validate agent-codex-setup-current-single-repo-alias-2026-04-22-13-48 --type change --strict; openspec validate --specs Not-tested: downstream repo self-update/install path after consuming a new CLI package --- README.md | 2 ++ .../proposal.md | 18 ++++++++++ .../specs/nested-repo-setup/spec.md | 10 ++++++ .../tasks.md | 34 +++++++++++++++++++ src/cli/main.js | 8 ++--- src/context.js | 4 +-- test/setup.test.js | 22 ++++++++++++ 7 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/proposal.md create mode 100644 openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/specs/nested-repo-setup/spec.md create mode 100644 openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/tasks.md diff --git a/README.md b/README.md index 1a57264..1c4243b 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,8 @@ Setup auto-installs into every nested git repo (e.g. `apps/*/.git`). Submodules ```sh gx setup --target /mainfolder gx setup --target /mainfolder --no-recursive +gx setup --target /mainfolder --current +gx doctor --target /mainfolder --current ``` ### Fresh repos + Docker Compose diff --git a/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/proposal.md b/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/proposal.md new file mode 100644 index 0000000..6fd02f6 --- /dev/null +++ b/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/proposal.md @@ -0,0 +1,18 @@ +## Why + +- `gx setup` recurses into nested repos by default, so operators need a short explicit way to keep a bootstrap or repair run scoped to just the target repo. +- `--no-recursive` already provides that behavior, but users naturally reach for `--current` after learning `gx doctor --current`. +- The current mismatch makes `setup` and `doctor` feel inconsistent even though they share the same repo-traversal model. + +## What Changes + +- Accept `--current` as a top-level-only alias for repo traversal in `gx setup`. +- Keep `gx doctor --current` working through the same shared traversal parser instead of a command-local special case. +- Update setup-facing operator copy to mention `--current` alongside `--no-recursive`. +- Add a regression proving nested repos under the target path stay untouched when `gx setup --current` is used. + +## Impact + +- Affected surface: `src/cli/main.js`, `src/context.js`, `test/setup.test.js`, `README.md`. +- Expected outcome: `gx setup --current` and `gx doctor --current` both scope work to the target repo only. +- Risk: low, because the alias reuses the existing non-recursive traversal path. diff --git a/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/specs/nested-repo-setup/spec.md b/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/specs/nested-repo-setup/spec.md new file mode 100644 index 0000000..bc7411a --- /dev/null +++ b/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/specs/nested-repo-setup/spec.md @@ -0,0 +1,10 @@ +## ADDED Requirements + +### Requirement: setup current alias limits bootstrap to the target repo +The system SHALL support `gx setup --current` as an alias for the existing top-level-only traversal path. + +#### Scenario: current alias skips nested repo installs +- **GIVEN** a parent repo contains a nested standalone git repo +- **WHEN** `gx setup --target --current` runs +- **THEN** the setup flow SHALL install or repair only `` +- **AND** the nested repo SHALL not be traversed or modified during that run. diff --git a/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/tasks.md b/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/tasks.md new file mode 100644 index 0000000..2ddc220 --- /dev/null +++ b/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/tasks.md @@ -0,0 +1,34 @@ +## Definition of Done + +This change is complete only when **all** of the following are true: + +- Every checkbox below is checked. +- The agent branch reaches `MERGED` state on `origin` and the PR URL + state are recorded in the completion handoff. +- If any step blocks, add a `BLOCKED:` line under section 4 and stop. + +Handoff: change=`agent-codex-setup-current-single-repo-alias-2026-04-22-13-48`; branch=`agent/codex/setup-current-single-repo-alias-2026-04-22-13-48`; scope=`OpenSpec change docs, setup traversal parsing, setup regression coverage, operator-facing setup copy`; action=`accept --current as the top-repo-only setup alias and keep traversal messaging aligned with doctor`. + +## 1. Specification + +- [x] 1.1 Capture the `gx setup --current` alias scope and acceptance criteria. +- [x] 1.2 Add normative OpenSpec coverage for the setup single-repo alias behavior. + +## 2. Implementation + +- [x] 2.1 Accept `--current` as a setup alias for the existing top-level-only traversal path. +- [x] 2.2 Update setup-facing help/output/docs to advertise `--current`. +- [x] 2.3 Add a regression proving nested repos under the target path stay untouched. + +## 3. Verification + +- [x] 3.1 Run `node --check bin/multiagent-safety.js`. Result: passed. +- [x] 3.2 Run `node --test test/setup.test.js`. Result: passed (`42/42` tests, including `setup --current limits install to the top-level repo`). +- [x] 3.3 Run `openspec validate agent-codex-setup-current-single-repo-alias-2026-04-22-13-48 --type change --strict`. Result: passed. +- [x] 3.4 Run `openspec validate --specs`. Result: passed (`No items found to validate.`). + +## 4. Cleanup + +- [ ] 4.1 Commit the change with a Lore commit message. +- [ ] 4.2 Run `gx branch finish --branch agent/codex/setup-current-single-repo-alias-2026-04-22-13-48 --base main --via-pr --wait-for-merge --cleanup`. +- [ ] 4.3 Record the PR URL and final merge state (`MERGED`) in the completion handoff. +- [ ] 4.4 Confirm the sandbox worktree and branch refs are gone after cleanup. diff --git a/src/cli/main.js b/src/cli/main.js index 1f20901..6f349dc 100755 --- a/src/cli/main.js +++ b/src/cli/main.js @@ -2013,7 +2013,7 @@ function parseRepoTraversalArgs(rawArgs, defaults) { for (let index = 0; index < rawArgs.length; index += 1) { const arg = rawArgs[index]; - if (arg === '--no-recursive' || arg === '--no-nested' || arg === '--single-repo') { + if (arg === '--no-recursive' || arg === '--no-nested' || arg === '--single-repo' || arg === '--current') { traversalDefaults.recursive = false; continue; } @@ -2088,10 +2088,6 @@ function parseDoctorArgs(rawArgs) { for (let index = 0; index < rawArgs.length; index += 1) { const arg = rawArgs[index]; - if (arg === '--current') { - forwardedArgs.push('--single-repo'); - continue; - } if (arg === '--verbose-auto-finish') { doctorDefaults.verboseAutoFinish = true; continue; @@ -6689,7 +6685,7 @@ function setup(rawArgs) { if (discoveredRepos.length > 1) { console.log( - `[${TOOL_NAME}] Detected ${discoveredRepos.length} git repos under ${topRepoRoot}. Installing into each (use --no-recursive to limit to the top-level).`, + `[${TOOL_NAME}] Detected ${discoveredRepos.length} git repos under ${topRepoRoot}. Installing into each (use --no-recursive or --current to limit to the top-level).`, ); for (const repoPath of discoveredRepos) { const marker = repoPath === topRepoRoot ? ' (top-level)' : ''; diff --git a/src/context.js b/src/context.js index f64dbf3..623dc8c 100644 --- a/src/context.js +++ b/src/context.js @@ -322,8 +322,8 @@ const SUGGESTIBLE_COMMANDS = [ ]; const CLI_COMMAND_DESCRIPTIONS = [ ['status', 'Show GitGuardex CLI + service health without modifying files'], - ['setup', 'Install, repair, and verify guardrails (flags: --repair, --install-only, --target)'], - ['doctor', 'Repair drift + verify (auto-sandboxes on protected main)'], + ['setup', 'Install, repair, and verify guardrails (flags: --repair, --install-only, --target, --current)'], + ['doctor', 'Repair drift + verify (flags: --target, --current; auto-sandboxes on protected main)'], ['branch', 'CLI-owned branch workflow surface (start/finish/merge)'], ['locks', 'CLI-owned file lock surface (claim/allow-delete/release/status/validate)'], ['worktree', 'CLI-owned worktree cleanup surface (prune)'], diff --git a/test/setup.test.js b/test/setup.test.js index fcbb467..10d1c21 100644 --- a/test/setup.test.js +++ b/test/setup.test.js @@ -703,6 +703,28 @@ test('setup --no-recursive limits install to the top-level repo', () => { ); }); +test('setup --current limits install to the top-level repo', () => { + const topDir = initRepo(); + const nestedA = path.join(topDir, 'apps', 'a'); + fs.mkdirSync(nestedA, { recursive: true }); + const initResult = runCmd('git', ['init', '-b', 'dev'], nestedA); + assert.equal(initResult.status, 0, initResult.stderr); + + const result = runNode( + ['setup', '--target', topDir, '--no-global-install', '--current'], + topDir, + ); + assert.equal(result.status, 0, result.stderr || result.stdout); + assert.doesNotMatch(result.stdout, /Detected \d+ git repos under/); + + assert.equal(fs.existsSync(path.join(topDir, 'AGENTS.md')), true); + assert.equal( + fs.existsSync(path.join(nestedA, 'AGENTS.md')), + false, + 'nested repo must not be touched when --current is set', + ); +}); + test('setup refreshes initialized protected main through a sandbox and prunes it', () => { const repoDir = initRepoOnBranch('main'); From 85f17b84387c347b069771c53ffb685766b0df8a Mon Sep 17 00:00:00 2001 From: NagyVikt Date: Wed, 22 Apr 2026 13:53:40 +0200 Subject: [PATCH 2/2] Keep the setup alias task log truthful before finish The implementation commit landed, but the OpenSpec tasks still showed the verification and commit steps unchecked. This updates the task log with the real verification evidence and the recorded commit SHA before handoff into the finish flow. Constraint: tasks.md is the active execution record for this change Rejected: Leave verification and commit evidence implicit | downstream cleanup handoff becomes misleading Confidence: high Scope-risk: narrow Reversibility: clean Directive: Update OpenSpec task state as steps happen instead of batching it after finish Tested: not applicable (task-state sync only) Not-tested: none --- .../tasks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/tasks.md b/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/tasks.md index 2ddc220..b7c3e88 100644 --- a/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/tasks.md +++ b/openspec/changes/agent-codex-setup-current-single-repo-alias-2026-04-22-13-48/tasks.md @@ -28,7 +28,7 @@ Handoff: change=`agent-codex-setup-current-single-repo-alias-2026-04-22-13-48`; ## 4. Cleanup -- [ ] 4.1 Commit the change with a Lore commit message. +- [x] 4.1 Commit the change with a Lore commit message. Result: `d942b84`. - [ ] 4.2 Run `gx branch finish --branch agent/codex/setup-current-single-repo-alias-2026-04-22-13-48 --base main --via-pr --wait-for-merge --cleanup`. - [ ] 4.3 Record the PR URL and final merge state (`MERGED`) in the completion handoff. - [ ] 4.4 Confirm the sandbox worktree and branch refs are gone after cleanup.