Commit Graph

4 Commits

Author SHA1 Message Date
Tom Boucher
19295f5ab6 fix(gemini): make Windows hooks and agent tools valid 2026-05-10 17:39:06 -04:00
Tom Boucher
dca12242b5 fix(install): skip Gemini local commands/gsd when global GSD present (#3037) (#3041)
* fix(install): skip Gemini local commands/gsd when global GSD present (#3037)

Reporter showed that running `npx get-shit-done-cc --gemini --global`
followed by `--gemini --local` in a project creates the same 65 GSD
command files in both Gemini scopes:
  - ~/.gemini/commands/gsd/ (user scope)
  - <project>/.gemini/commands/gsd/ (workspace scope)

Gemini conflict-detects by command name across scopes and renames every
overlapping /gsd:* command to /workspace.gsd:* and /user.gsd:*, breaking
the documented /gsd:* namespace.

Fix: in bin/install.js, when handling --gemini --local, detect whether
~/.gemini/commands/gsd/ already exists with managed-shape content. If
so, skip the local copy and print a clear three-line warning explaining
the conflict avoidance. The user-scope install already provides the
same /gsd:* commands in this project; the local copy adds zero value.

Sibling fixes (test isolation):
- tests/install-minimal-all-runtimes.test.cjs: pass HOME/USERPROFILE
  through the spawned installer's env so the developer's real
  ~/.gemini/commands/gsd/ doesn't trigger the new skip path during
  test runs that want to assert the local-install populates
  commands/gsd/.
- tests/gemini-namespacing.test.cjs: the "Gemini Install (Behavioral)"
  describe block now creates an isolated tmpHome and points
  process.env.HOME at it before calling install(false, 'gemini'),
  with proper restore in afterEach.

Test:
- tests/bug-3037-gemini-duplicate-commands.test.cjs — 4 structural
  tests:
    1. global install populates HOME/.gemini/commands/gsd
    2. local install AFTER global skips the local copy
    3. local install with NO existing global still populates locally
       (no-regression)
    4. local install when HOME has .gemini/ but no GSD-managed
       commands/gsd/ still populates locally (non-GSD-Gemini-user
       no-regression)

6909/6909 full suite pass. Lints clean.

Closes #3037

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: address CR feedback on PR #3041 — narrower detection + USERPROFILE restore

CR findings:

1. **bin/install.js (Major)** — userScopeHasGsd used
   `fs.readdirSync(homeGeminiGsd).length > 0` which would skip the
   local install for any non-empty directory, including a user who
   hand-dropped a single override at ~/.gemini/commands/gsd/<thing>
   .toml without ever running --gemini --global. Narrowed the
   detection to require at least 3 canonical GSD command files
   (help.toml, progress.toml, new-project.toml) — a marker that
   ships in every GSD Gemini install (minimal mode included) and is
   structurally impossible to produce by accident.

2. **tests/bug-3037-...:59 (Minor)** — beforeEach overwrites
   process.env.USERPROFILE but afterEach only restores HOME, leaking
   the temp home into later tests on Windows or any code path that
   reads USERPROFILE. Added save/restore symmetric with HOME.

Plus added a 5th regression test covering the narrowed detection:
"local install when HOME has hand-dropped overrides UNDER commands/gsd/
(but no full GSD) still populates locally" — directly exercises the
edge case CR identified.

5/5 targeted tests pass. 6910/6910 full suite pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 17:44:52 -04:00
Tom Boucher
c72b893916 fix(test): unbreak gemini-namespacing test after #2790 skill consolidation (#2886)
Closes #2876 follow-up — CI on main fails because the punctuation test
in tests/gemini-namespacing.test.cjs hardcoded `/gsd-scan` as a known
command, but #2824 (consolidate 86 → 59 skills) removed scan.md from
commands/gsd/. The roster now correctly returns "scan is unknown, leave
unchanged" — the conversion is right, the test fixture is stale.

Swap `scan` for `health` in the punctuation test. Both are bedrock
commands; the test still exercises the original intent (period vs
exclamation handling on adjacent slash commands).

Note added so the next consolidation reviewer knows the swap pattern.

`npm test`: 5936/5936 pass.
2026-04-30 00:57:17 -04:00
Oleksander Palian
73b9d1dac0 fix(install): use colon namespace for Gemini slash commands (#2768)
* fix(install): use colon namespace for Gemini slash commands and help reference

This fixes unexecutable command recommendations in Gemini CLI by correctly
namespacing slash commands (/gsd: instead of /gsd-) in all installed
artifacts (agents, commands, workflows).

- Implements a lazy command roster discovery to ensure 100% accurate
  conversion and protect file paths, URLs, and agent names.
- Adds isolated behavioral and unit tests covering all boundary cases.
- Fixes hardcoded command strings in banners and help output.

Closes #2783

* fix(install): close roster gaps in Gemini /gsd- → /gsd: conversion (#2783)

Addresses adversarial review findings on PR #2768:

- Restore regex boundaries (lookbehind + extension lookahead). Roster-only
  matching was insufficient: a URL like `https://example.com/gsd-plan-phase`
  ends in a known command and would be incorrectly converted. Boundaries +
  roster now agree before any conversion fires.
- Smarter trailing lookahead `(?!\.[a-z])` distinguishes file extensions
  (`.cjs`, `.md`) from sentence-ending punctuation (`.` at end of input or
  before whitespace), so `/gsd-help.` correctly converts.
- Fail loud on missing roster. `commands/gsd/` not found previously fell
  through to an empty Set, silently no-op'ing every conversion — exactly the
  bug this code exists to prevent. Now emits a one-shot console.warn (gated
  on GSD_TEST_MODE) before returning the empty set.
- Drop unnecessary `i` flag — GSD commands are always lowercase; matching
  uppercase tokens against a lowercase roster always misses anyway.
- Export `_resetGsdCommandRoster` for test isolation against the module-level
  cache.

Test additions pin the actual safety property of the roster check by using
KNOWN command names embedded in URLs and sub-paths — the cases the prior
tests didn't reach because they used `gsd-tools` (not in roster). Added a
roster-load assertion that fails loudly if the empty-Set fallback path
silently neutralises conversions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(install): centralize <sub> stripping and add structural test assertions

CodeRabbit findings on the prior commit:

- (actionable) Centralizing the Gemini conversion through
  convertClaudeToGeminiMarkdown dropped the stripSubTags() call that the
  inline command path used to make before TOML conversion. Move stripSubTags
  inside convertClaudeToGeminiMarkdown so command/agent/non-command Gemini
  outputs all have <sub> consistently stripped. Remove the now-redundant
  stripSubTags call in convertClaudeToGeminiAgent (single source of truth).
- (nitpick) Replace `.includes()` checks in the TOML test with structured
  parsing — JSON-decode each TOML value and assert on parsed fields, per
  the project's "tests parse, never grep" convention.
- (nitpick) Strengthen the install behavioral test to read a real installed
  artifact (.gemini/commands/gsd/plan-phase.toml), parse it, and assert the
  prompt body actually contains a /gsd: reference and no unconverted
  /gsd-plan-phase. A directory-only check would have passed even if every
  conversion silently no-op'd.
- Add a regression test that <sub> tags are stripped through the
  convertClaudeToGeminiMarkdown pipeline.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 22:37:57 -04:00