mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-14 20:37:14 +01:00
v1.92.22.0 feat: Gemini CLI host, and older installs drop the dev toolchain (#3778)
* setup: explicit contributor marker; move pre-v1.91.231.0 installs to production deps (#3447) ./setup used node_modules/typescript as its contributor signal, so every install made before v1.91.231.0 (a full bun install) kept ~520 MB of test and eval packages forever. The contributor is now the clone bin/dev-setup marks with git config gstack.contributor true, or GSTACK_CONTRIBUTOR=1. An unmarked clone with the dev toolchain moves node_modules aside under a checkout lock, installs production-only, verifies every dependency, and drops the backup; any failure puts the full install back with SETUP_DEPS_MIGRATE_FAILED. CI and a clone whose git config cannot be read never migrate. Bun cache entries for the pinned Agent SDK are removed only when no other project links to them. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * hosts: add Gemini CLI as an experimental host (#1247) ./setup --host gemini (alias gemini-cli; --host auto when gemini is on PATH) installs gstack-<skill> directories into ~/.gemini/skills, which Gemini CLI 0.66.0 lists with gemini skills list, plus the ~/.gemini/skills/gstack runtime root. Renders go to .gemini-cli/ (gitignored) with name+description frontmatter whose names match their directories, CLAUDE.md rewritten to GEMINI.md, and a tool glossary for Gemini CLI's names (and Antigravity's, which can read the same folder). gstack-uninstall removes only gstack-managed entries there, so the user's own skills stay. Docs: ADDING_A_HOST.md verified facts, hosts.md, uninstall.md, README. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes (leave Bun's shared cache alone) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * changelog: Gemini CLI host and contributor marker (#1247, #3447) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: host lists name Copilot, Antigravity and Gemini CLI Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: the plan-mode re-render guard count includes the Gemini CLI host Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: troubleshooting's runtime-root guard host list names Gemini CLI Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
c03f185d15
commit
e4e4e42967
34 files changed
+910
-74
No files matched your search
@@ -204,6 +204,46 @@ describe('gstack-uninstall', () => {
|
||||
expect(fs.existsSync(path.join(mockGitRoot, '.cursor', 'rules', 'keep.md'))).toBe(true);
|
||||
});
|
||||
|
||||
// Value: protects=uninstall clears gstack's Gemini CLI skills from ~/.gemini/skills, a folder the user's own skills share;
|
||||
// fails_when=the Gemini block is dropped, or loses the provenance gate and sweeps a user's gstack-prefixed skill;
|
||||
// why_new=#1247 adds the Gemini CLI host; seam=none; no_claim=Gemini CLI itself (temp HOME fixture)
|
||||
test('--force removes Gemini CLI gstack skills and leaves the user\'s own', () => {
|
||||
const banner = '<!-- AUTO-GENERATED from SKILL.md.tmpl - DO NOT EDIT DIRECTLY -->\n# x\n';
|
||||
const skills = path.join(mockHome, '.gemini', 'skills');
|
||||
const render = path.join(tmpDir, 'render', 'gstack-review');
|
||||
fs.mkdirSync(render, { recursive: true });
|
||||
fs.writeFileSync(path.join(render, 'SKILL.md'), banner);
|
||||
fs.mkdirSync(path.join(skills, 'gstack'), { recursive: true });
|
||||
fs.writeFileSync(path.join(skills, 'gstack', 'SKILL.md'), banner);
|
||||
fs.symlinkSync(render, path.join(skills, 'gstack-review'));
|
||||
for (const [name, body] of [['gstack-my-notes', '# mine\n'], ['frontend-design', 'keep']]) {
|
||||
fs.mkdirSync(path.join(skills, name), { recursive: true });
|
||||
fs.writeFileSync(path.join(skills, name, 'SKILL.md'), body);
|
||||
}
|
||||
fs.writeFileSync(path.join(mockHome, '.gemini', 'settings.json'), '{}');
|
||||
|
||||
const result = spawnSync('bash', [UNINSTALL, '--force'], {
|
||||
stdio: 'pipe',
|
||||
timeout: 30_000,
|
||||
env: {
|
||||
...process.env,
|
||||
HOME: mockHome,
|
||||
GSTACK_DIR: path.join(mockHome, '.claude', 'skills', 'gstack'),
|
||||
GSTACK_STATE_DIR: path.join(mockHome, '.gstack'),
|
||||
},
|
||||
cwd: mockGitRoot,
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(fs.existsSync(path.join(skills, 'gstack'))).toBe(false);
|
||||
expect(fs.existsSync(path.join(skills, 'gstack-review'))).toBe(false);
|
||||
expect(fs.existsSync(path.join(render, 'SKILL.md'))).toBe(true);
|
||||
expect(fs.existsSync(path.join(skills, 'gstack-my-notes', 'SKILL.md'))).toBe(true);
|
||||
expect(fs.existsSync(path.join(skills, 'frontend-design', 'SKILL.md'))).toBe(true);
|
||||
expect(fs.existsSync(path.join(mockHome, '.gemini', 'settings.json'))).toBe(true);
|
||||
expect(result.stderr.toString()).toContain('gstack-my-notes');
|
||||
});
|
||||
|
||||
test("a user's own gstack-prefixed Cursor dir (no banner) survives and is listed", () => {
|
||||
// S5: the bare gstack* glob must not sweep a dir that merely starts
|
||||
// with "gstack" — provenance comes from the generated banner, and a
|
||||
|
||||
Reference in new issue
Block a user