* fix(#213): support antigravity 2.x config directory split * fix(#213): harden antigravity tests for windows parity
This commit is contained in:
5
.changeset/213-antigravity-2-runtime-dirs.md
Normal file
5
.changeset/213-antigravity-2-runtime-dirs.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 213
|
||||
---
|
||||
Add Antigravity 2.x config-dir compatibility by auto-detecting `~/.gemini/antigravity-ide` and `~/.gemini/antigravity-cli` (with legacy `~/.gemini/antigravity` fallback), then routing installer, SDK runtime config resolution, and `/gsd-update` runtime classification through the same detection model.
|
||||
@@ -28,6 +28,9 @@ const {
|
||||
transformContentToHyphen,
|
||||
readCmdNames: readGsdCommandNames,
|
||||
} = require(path.join(__dirname, '..', 'scripts', 'fix-slash-commands.cjs'));
|
||||
const {
|
||||
resolveAntigravityGlobalDir,
|
||||
} = require('../get-shit-done/bin/lib/runtime-homes.cjs');
|
||||
|
||||
/**
|
||||
* Runtimes that register hyphen-form `name:` per #2808 AND copy agent bodies
|
||||
@@ -325,6 +328,14 @@ function getConfigDirFromHome(runtime, isGlobal) {
|
||||
if (runtime === 'codex') return "'.codex'";
|
||||
if (runtime === 'antigravity') {
|
||||
if (!isGlobal) return "'.agent'";
|
||||
const antigravityDir = resolveAntigravityGlobalDir();
|
||||
const rel = path.relative(os.homedir(), antigravityDir);
|
||||
const segments = rel.split(path.sep).filter(Boolean);
|
||||
if (segments.length > 0 && !rel.startsWith('..') && !path.isAbsolute(rel)) {
|
||||
return segments.map((seg) => `'${seg}'`).join(', ');
|
||||
}
|
||||
// If resolution points outside HOME (e.g. via env override), keep the
|
||||
// stable legacy template so generated path.join() calls remain valid.
|
||||
return "'.gemini', 'antigravity'";
|
||||
}
|
||||
if (runtime === 'cursor') return "'.cursor'";
|
||||
@@ -444,14 +455,12 @@ function getGlobalDir(runtime, explicitDir = null) {
|
||||
}
|
||||
|
||||
if (runtime === 'antigravity') {
|
||||
// Antigravity: --config-dir > ANTIGRAVITY_CONFIG_DIR > ~/.gemini/antigravity
|
||||
// Antigravity: --config-dir > ANTIGRAVITY_CONFIG_DIR > auto-detected
|
||||
// ~/.gemini/{antigravity,antigravity-ide,antigravity-cli}
|
||||
if (explicitDir) {
|
||||
return expandTilde(explicitDir);
|
||||
}
|
||||
if (process.env.ANTIGRAVITY_CONFIG_DIR) {
|
||||
return expandTilde(process.env.ANTIGRAVITY_CONFIG_DIR);
|
||||
}
|
||||
return path.join(os.homedir(), '.gemini', 'antigravity');
|
||||
return resolveAntigravityGlobalDir();
|
||||
}
|
||||
|
||||
if (runtime === 'cursor') {
|
||||
|
||||
@@ -510,7 +510,7 @@ Equivalent paths for other runtimes:
|
||||
- **Gemini CLI:** `~/.gemini/` global or `./.gemini/` local
|
||||
- **Codex:** `~/.codex/` global or `./.codex/` local
|
||||
- **Copilot:** `~/.copilot/` global or `./.github/` local
|
||||
- **Antigravity:** `~/.gemini/antigravity/` global or `./.agent/` local
|
||||
- **Antigravity:** auto-detected global root (`~/.gemini/antigravity/`, `~/.gemini/antigravity-ide/`, or `~/.gemini/antigravity-cli/`) or `./.agent/` local
|
||||
- **Cursor:** `~/.cursor/` global or `./.cursor/` local
|
||||
- **Windsurf:** `~/.codeium/windsurf/` global or `./.windsurf/` local
|
||||
- **Augment Code:** `~/.augment/` global or `./.augment/` local
|
||||
@@ -743,7 +743,7 @@ The migration-specific ownership and source snapshots live in
|
||||
| Gemini CLI | `~/.gemini` | `./.gemini` | `commands/gsd/*.toml` | `agents/gsd-*.md` | `settings.json` feature flag, hooks, and statusline |
|
||||
| Codex | `~/.codex` | `./.codex` | `skills/gsd-*/SKILL.md` | `agents/` source markdown plus per-agent TOML | `config.toml` `[agents.gsd-*]`, `[features].hooks` (canonical; legacy alias `codex_hooks` is recognized and migrated forward on reinstall, #3566), and hook tables |
|
||||
| GitHub Copilot | `~/.copilot` | `./.github` | `skills/gsd-*/SKILL.md` and `copilot-instructions.md` | `.agent.md` files | No GSD hooks or statusline |
|
||||
| Antigravity | `~/.gemini/antigravity` | `./.agent` | `skills/gsd-*/SKILL.md` | `agents/gsd-*.md` | Gemini-style `settings.json` hook entries when installed by GSD |
|
||||
| Antigravity | auto-detected: `~/.gemini/antigravity`, `~/.gemini/antigravity-ide`, or `~/.gemini/antigravity-cli` | `./.agent` | `skills/gsd-*/SKILL.md` | `agents/gsd-*.md` | Gemini-style `settings.json` hook entries when installed by GSD |
|
||||
| Cursor | `~/.cursor` | `./.cursor` | `skills/gsd-*/SKILL.md` | `agents/gsd-*.md` | Rule references under `rules/`; no GSD hooks |
|
||||
| Windsurf | `~/.codeium/windsurf` | `./.windsurf` | `skills/gsd-*/SKILL.md` | `agents/gsd-*.md` | Rule references under `rules/`; no GSD hooks |
|
||||
| Augment Code | `~/.augment` | `./.augment` | `skills/gsd-*/SKILL.md` | `agents/gsd-*.md` | No GSD hooks or statusline |
|
||||
|
||||
@@ -1354,7 +1354,7 @@ Select the corresponding stable runtime in the installer prompt. Skills land in
|
||||
| Copilot | `~/.copilot` | `COPILOT_CONFIG_DIR` |
|
||||
| Cursor | `~/.cursor` | `CURSOR_CONFIG_DIR` |
|
||||
| Windsurf | `~/.codeium/windsurf` | `WINDSURF_CONFIG_DIR` |
|
||||
| Antigravity | `~/.gemini/antigravity` | `ANTIGRAVITY_CONFIG_DIR` |
|
||||
| Antigravity | auto-detected: `~/.gemini/antigravity` (legacy), `~/.gemini/antigravity-ide`, or `~/.gemini/antigravity-cli` | `ANTIGRAVITY_CONFIG_DIR` |
|
||||
| Augment | `~/.augment` | `AUGMENT_CONFIG_DIR` |
|
||||
| Trae | `~/.trae` | `TRAE_CONFIG_DIR` |
|
||||
| Qwen Code | `~/.qwen` | `QWEN_CONFIG_DIR` |
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
/**
|
||||
* Expand a leading ~ to os.homedir().
|
||||
@@ -34,6 +35,43 @@ function expandTilde(p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve Antigravity global config dir across 1.x and 2.x layouts.
|
||||
*
|
||||
* Order:
|
||||
* 1) ANTIGRAVITY_CONFIG_DIR override
|
||||
* 2) Existing legacy/new runtime directories under ~/.gemini/
|
||||
* - antigravity (1.x + documented baseline)
|
||||
* - antigravity-ide (2.x IDE split)
|
||||
* - antigravity-cli (2.x CLI split)
|
||||
* 3) Legacy default (~/.gemini/antigravity) for backward compatibility
|
||||
*
|
||||
* @param {object} [opts]
|
||||
* @param {Record<string, string | undefined>} [opts.env]
|
||||
* @param {string} [opts.home]
|
||||
* @param {(p: string) => boolean} [opts.existsSync]
|
||||
* @returns {string}
|
||||
*/
|
||||
function resolveAntigravityGlobalDir(opts = {}) {
|
||||
const env = opts.env || process.env;
|
||||
const home = opts.home || os.homedir();
|
||||
const existsSyncFn = opts.existsSync || fs.existsSync;
|
||||
|
||||
if (env.ANTIGRAVITY_CONFIG_DIR) return expandTilde(env.ANTIGRAVITY_CONFIG_DIR);
|
||||
|
||||
const base = path.join(home, '.gemini');
|
||||
const candidates = [
|
||||
path.join(base, 'antigravity'),
|
||||
path.join(base, 'antigravity-ide'),
|
||||
path.join(base, 'antigravity-cli'),
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
if (existsSyncFn(candidate)) return candidate;
|
||||
}
|
||||
|
||||
return path.join(base, 'antigravity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the global config base directory for the given runtime.
|
||||
* Respects the same env-var overrides as bin/install.js getGlobalDir().
|
||||
@@ -75,9 +113,7 @@ function getGlobalConfigDir(runtime) {
|
||||
|
||||
// ── Antigravity ──────────────────────────────────────────────────────────
|
||||
case 'antigravity':
|
||||
return env.ANTIGRAVITY_CONFIG_DIR
|
||||
? expandTilde(env.ANTIGRAVITY_CONFIG_DIR)
|
||||
: path.join(home, '.gemini', 'antigravity');
|
||||
return resolveAntigravityGlobalDir({ env, home });
|
||||
|
||||
// ── Windsurf ─────────────────────────────────────────────────────────────
|
||||
case 'windsurf':
|
||||
@@ -182,4 +218,5 @@ module.exports = {
|
||||
getGlobalSkillsBase,
|
||||
getGlobalSkillDir,
|
||||
getGlobalSkillDisplayPath,
|
||||
resolveAntigravityGlobalDir,
|
||||
};
|
||||
|
||||
@@ -14,6 +14,8 @@ Detect whether GSD is installed locally or globally by checking both locations a
|
||||
First, derive `PREFERRED_CONFIG_DIR` and `PREFERRED_RUNTIME` from the invoking prompt's `execution_context` path:
|
||||
- If the path contains `/get-shit-done/workflows/update.md`, strip that suffix and store the remainder as `PREFERRED_CONFIG_DIR`
|
||||
- Path contains `/.codex/` -> `codex`
|
||||
- Path contains `/.gemini/antigravity-ide/` -> `antigravity`
|
||||
- Path contains `/.gemini/antigravity-cli/` -> `antigravity`
|
||||
- Path contains `/.gemini/antigravity/` -> `antigravity`
|
||||
- Path contains `/.gemini/` -> `gemini`
|
||||
- Path contains `/.config/kilo/` or `/.kilo/`, or `PREFERRED_CONFIG_DIR` contains `kilo.json` / `kilo.jsonc` -> `kilo`
|
||||
@@ -37,7 +39,7 @@ expand_home() {
|
||||
# Using an array instead of a space-separated string ensures correct
|
||||
# iteration in both bash and zsh (zsh does not word-split unquoted
|
||||
# variables by default). Fixes #1173.
|
||||
RUNTIME_DIRS=( "claude:.claude" "opencode:.config/opencode" "opencode:.opencode" "antigravity:.gemini/antigravity" "gemini:.gemini" "kilo:.config/kilo" "kilo:.kilo" "codex:.codex" )
|
||||
RUNTIME_DIRS=( "claude:.claude" "opencode:.config/opencode" "opencode:.opencode" "antigravity:.gemini/antigravity-ide" "antigravity:.gemini/antigravity-cli" "antigravity:.gemini/antigravity" "gemini:.gemini" "kilo:.config/kilo" "kilo:.kilo" "codex:.codex" )
|
||||
ENV_RUNTIME_DIRS=()
|
||||
|
||||
# PREFERRED_CONFIG_DIR / PREFERRED_RUNTIME should be set from execution_context
|
||||
@@ -98,7 +100,7 @@ if [ -n "$PREFERRED_CONFIG_DIR" ] && { [ -f "$PREFERRED_CONFIG_DIR/get-shit-done
|
||||
printf '%s' "$p"
|
||||
}
|
||||
normalized_preferred="$(normalize_path "$PREFERRED_CONFIG_DIR")"
|
||||
for dir in .claude .config/opencode .opencode .gemini/antigravity .gemini .config/kilo .kilo .codex; do
|
||||
for dir in .claude .config/opencode .opencode .gemini/antigravity-ide .gemini/antigravity-cli .gemini/antigravity .gemini .config/kilo .kilo .codex; do
|
||||
resolved_local="$(cd "./$dir" 2>/dev/null && pwd)"
|
||||
normalized_local="$(normalize_path "$resolved_local")"
|
||||
if [ -n "$normalized_local" ] && [ "$normalized_local" = "$normalized_preferred" ]; then
|
||||
@@ -607,7 +609,7 @@ for dir in "${CACHE_DIRS[@]}"; do
|
||||
fi
|
||||
done
|
||||
|
||||
for dir in .claude .config/opencode .opencode .gemini/antigravity .gemini .config/kilo .kilo .codex; do
|
||||
for dir in .claude .config/opencode .opencode .gemini/antigravity-ide .gemini/antigravity-cli .gemini/antigravity .gemini .config/kilo .kilo .codex; do
|
||||
rm -f "./$dir/cache/gsd-update-check.json"
|
||||
rm -f "$HOME/$dir/cache/gsd-update-check.json"
|
||||
done
|
||||
|
||||
@@ -308,10 +308,18 @@ const RUNTIME_ENV_VARS = [
|
||||
|
||||
describe('getRuntimeConfigDir', () => {
|
||||
const saved: Record<string, string | undefined> = {};
|
||||
let savedHome: string | undefined;
|
||||
let savedUserProfile: string | undefined;
|
||||
beforeEach(() => {
|
||||
savedHome = process.env.HOME;
|
||||
savedUserProfile = process.env.USERPROFILE;
|
||||
for (const k of RUNTIME_ENV_VARS) { saved[k] = process.env[k]; delete process.env[k]; }
|
||||
});
|
||||
afterEach(() => {
|
||||
if (savedHome === undefined) delete process.env.HOME;
|
||||
else process.env.HOME = savedHome;
|
||||
if (savedUserProfile === undefined) delete process.env.USERPROFILE;
|
||||
else process.env.USERPROFILE = savedUserProfile;
|
||||
for (const k of RUNTIME_ENV_VARS) {
|
||||
if (saved[k] === undefined) delete process.env[k];
|
||||
else process.env[k] = saved[k];
|
||||
@@ -380,6 +388,15 @@ describe('getRuntimeConfigDir', () => {
|
||||
process.env.XDG_CONFIG_HOME = '/xdg';
|
||||
expect(getRuntimeConfigDir('kilo')).toBe(join('/xdg', 'kilo'));
|
||||
});
|
||||
|
||||
it('antigravity detects 2.x IDE dir when present and legacy dir is absent', async () => {
|
||||
const home = await mkdtemp(join(tmpdir(), 'gsd-antigravity-sdk-'));
|
||||
await mkdir(join(home, '.gemini', 'antigravity-ide'), { recursive: true });
|
||||
process.env.HOME = home;
|
||||
process.env.USERPROFILE = home;
|
||||
expect(getRuntimeConfigDir('antigravity')).toBe(join(home, '.gemini', 'antigravity-ide'));
|
||||
await rm(home, { recursive: true, force: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('detectRuntime', () => {
|
||||
|
||||
@@ -35,6 +35,24 @@ function expandTilde(p: string): string {
|
||||
return p.startsWith('~/') || p === '~' ? join(homedir(), p.slice(1)) : p;
|
||||
}
|
||||
|
||||
function resolveAntigravityConfigDir(): string {
|
||||
if (process.env.ANTIGRAVITY_CONFIG_DIR) {
|
||||
return expandTilde(process.env.ANTIGRAVITY_CONFIG_DIR);
|
||||
}
|
||||
|
||||
const home = homedir();
|
||||
const base = join(home, '.gemini');
|
||||
const candidates = [
|
||||
join(base, 'antigravity'),
|
||||
join(base, 'antigravity-ide'),
|
||||
join(base, 'antigravity-cli'),
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
if (existsSync(candidate)) return candidate;
|
||||
}
|
||||
return join(base, 'antigravity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the per-runtime config directory, mirroring
|
||||
* `bin/install.js:getGlobalDir()`. Agents live at `<configDir>/agents`.
|
||||
@@ -62,7 +80,7 @@ export function getRuntimeConfigDir(runtime: Runtime): string {
|
||||
case 'copilot':
|
||||
return process.env.COPILOT_CONFIG_DIR ? expandTilde(process.env.COPILOT_CONFIG_DIR) : join(homedir(), '.copilot');
|
||||
case 'antigravity':
|
||||
return process.env.ANTIGRAVITY_CONFIG_DIR ? expandTilde(process.env.ANTIGRAVITY_CONFIG_DIR) : join(homedir(), '.gemini', 'antigravity');
|
||||
return resolveAntigravityConfigDir();
|
||||
case 'cursor':
|
||||
return process.env.CURSOR_CONFIG_DIR ? expandTilde(process.env.CURSOR_CONFIG_DIR) : join(homedir(), '.cursor');
|
||||
case 'windsurf':
|
||||
|
||||
@@ -20,6 +20,7 @@ const { describe, test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const path = require('node:path');
|
||||
const os = require('node:os');
|
||||
const { cleanup } = require('./helpers.cjs');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const {
|
||||
@@ -117,6 +118,29 @@ describe('bug #3126: runtime-homes env-var overrides', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('antigravity detects 2.x IDE dir when legacy dir is absent', () => {
|
||||
const home = require('node:fs').mkdtempSync(path.join(os.tmpdir(), 'gsd-antigravity-home-'));
|
||||
try {
|
||||
require('node:fs').mkdirSync(path.join(home, '.gemini', 'antigravity-ide'), { recursive: true });
|
||||
const savedHome = process.env.HOME;
|
||||
const savedUserProfile = process.env.USERPROFILE;
|
||||
process.env.HOME = home;
|
||||
process.env.USERPROFILE = home;
|
||||
withEnv('ANTIGRAVITY_CONFIG_DIR', undefined, () => {
|
||||
assert.strictEqual(
|
||||
getGlobalConfigDir('antigravity'),
|
||||
path.join(home, '.gemini', 'antigravity-ide'),
|
||||
);
|
||||
});
|
||||
if (savedHome === undefined) delete process.env.HOME;
|
||||
else process.env.HOME = savedHome;
|
||||
if (savedUserProfile === undefined) delete process.env.USERPROFILE;
|
||||
else process.env.USERPROFILE = savedUserProfile;
|
||||
} finally {
|
||||
cleanup(home);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('bug #3126: runtime-homes getGlobalSkillsBase', () => {
|
||||
|
||||
@@ -71,17 +71,23 @@ describe('bug #3608: update.md models Antigravity as a first-class runtime', ()
|
||||
);
|
||||
});
|
||||
|
||||
test('RUNTIME_DIRS antigravity entry points at .gemini/antigravity', () => {
|
||||
test('RUNTIME_DIRS includes antigravity entries for 2.x + legacy dirs', () => {
|
||||
const entries = parseBashArray(content, 'RUNTIME_DIRS');
|
||||
assert.ok(entries);
|
||||
|
||||
const ant = entries.find((e) => e.startsWith('antigravity:'));
|
||||
assert.ok(ant, 'antigravity entry missing');
|
||||
assert.strictEqual(
|
||||
ant,
|
||||
'antigravity:.gemini/antigravity',
|
||||
`antigravity entry must be exactly "antigravity:.gemini/antigravity" to match the installer ` +
|
||||
`(bin/install.js line ~404: ~/.gemini/antigravity)`,
|
||||
const antEntries = entries.filter((e) => e.startsWith('antigravity:'));
|
||||
assert.ok(antEntries.length >= 1, 'antigravity entry missing');
|
||||
assert.ok(
|
||||
antEntries.includes('antigravity:.gemini/antigravity-ide'),
|
||||
'RUNTIME_DIRS must include antigravity:.gemini/antigravity-ide',
|
||||
);
|
||||
assert.ok(
|
||||
antEntries.includes('antigravity:.gemini/antigravity-cli'),
|
||||
'RUNTIME_DIRS must include antigravity:.gemini/antigravity-cli',
|
||||
);
|
||||
assert.ok(
|
||||
antEntries.includes('antigravity:.gemini/antigravity'),
|
||||
'RUNTIME_DIRS must include legacy antigravity:.gemini/antigravity fallback',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -125,7 +131,7 @@ describe('bug #3608: update.md models Antigravity as a first-class runtime', ()
|
||||
);
|
||||
});
|
||||
|
||||
test('local-scope scan dir list includes .gemini/antigravity before .gemini', () => {
|
||||
test('local-scope scan dir list includes 2.x antigravity dirs before .gemini', () => {
|
||||
// Lines like: for dir in .claude .config/opencode .opencode .gemini ...
|
||||
// The first iteration of the local scan ranges over a hardcoded list.
|
||||
const forLoops = [...content.matchAll(/for dir in ([^;]+); do/g)];
|
||||
@@ -133,38 +139,66 @@ describe('bug #3608: update.md models Antigravity as a first-class runtime', ()
|
||||
|
||||
for (const m of forLoops) {
|
||||
const tokens = m[1].trim().split(/\s+/);
|
||||
const antIdx = tokens.indexOf('.gemini/antigravity');
|
||||
const antLegacyIdx = tokens.indexOf('.gemini/antigravity');
|
||||
const antIdeIdx = tokens.indexOf('.gemini/antigravity-ide');
|
||||
const antCliIdx = tokens.indexOf('.gemini/antigravity-cli');
|
||||
const gemIdx = tokens.indexOf('.gemini');
|
||||
if (gemIdx === -1) continue; // scan loop without .gemini — irrelevant
|
||||
assert.notStrictEqual(
|
||||
antIdx,
|
||||
antIdeIdx,
|
||||
-1,
|
||||
`scan loop "for dir in ${m[1].trim()}" mentions .gemini but not .gemini/antigravity — ` +
|
||||
`the more-specific Antigravity dir must be present`,
|
||||
`scan loop "for dir in ${m[1].trim()}" mentions .gemini but not .gemini/antigravity-ide — ` +
|
||||
`the more-specific Antigravity 2.x dir must be present`,
|
||||
);
|
||||
assert.ok(
|
||||
antIdx < gemIdx,
|
||||
`scan loop "for dir in ${m[1].trim()}": .gemini/antigravity (idx ${antIdx}) must precede .gemini (idx ${gemIdx})`,
|
||||
antIdeIdx < gemIdx,
|
||||
`scan loop "for dir in ${m[1].trim()}": .gemini/antigravity-ide (idx ${antIdeIdx}) must precede .gemini (idx ${gemIdx})`,
|
||||
);
|
||||
assert.notStrictEqual(
|
||||
antCliIdx,
|
||||
-1,
|
||||
`scan loop "for dir in ${m[1].trim()}" must include .gemini/antigravity-cli for Antigravity 2.x CLI installs`,
|
||||
);
|
||||
assert.ok(
|
||||
antCliIdx < gemIdx,
|
||||
`scan loop "for dir in ${m[1].trim()}": .gemini/antigravity-cli (idx ${antCliIdx}) must precede .gemini (idx ${gemIdx})`,
|
||||
);
|
||||
assert.notStrictEqual(
|
||||
antLegacyIdx,
|
||||
-1,
|
||||
`scan loop "for dir in ${m[1].trim()}" must retain .gemini/antigravity legacy fallback`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('path-to-runtime classification documents /.gemini/antigravity/ before /.gemini/', () => {
|
||||
test('path-to-runtime classification documents antigravity 2.x and legacy paths before /.gemini/', () => {
|
||||
// The markdown bullet list near the top of get_installed_version step.
|
||||
// We assert the antigravity bullet exists and appears before the gemini bullet
|
||||
// in the file (textual order = evaluation order in the prose contract).
|
||||
const antBullet = content.search(/Path contains `\/\.gemini\/antigravity\/?` -> `antigravity`/);
|
||||
const antIdeBullet = content.search(/Path contains `\/\.gemini\/antigravity-ide\/?` -> `antigravity`/);
|
||||
const antCliBullet = content.search(/Path contains `\/\.gemini\/antigravity-cli\/?` -> `antigravity`/);
|
||||
const antLegacyBullet = content.search(/Path contains `\/\.gemini\/antigravity\/?` -> `antigravity`/);
|
||||
const gemBullet = content.search(/Path contains `\/\.gemini\/` -> `gemini`/);
|
||||
|
||||
assert.notStrictEqual(
|
||||
antBullet,
|
||||
antIdeBullet,
|
||||
-1,
|
||||
'classification bullet for /.gemini/antigravity-ide/ -> antigravity is missing',
|
||||
);
|
||||
assert.notStrictEqual(
|
||||
antCliBullet,
|
||||
-1,
|
||||
'classification bullet for /.gemini/antigravity-cli/ -> antigravity is missing',
|
||||
);
|
||||
assert.notStrictEqual(
|
||||
antLegacyBullet,
|
||||
-1,
|
||||
'classification bullet for /.gemini/antigravity/ -> antigravity is missing',
|
||||
);
|
||||
assert.notStrictEqual(gemBullet, -1, 'classification bullet for /.gemini/ -> gemini is missing');
|
||||
assert.ok(
|
||||
antBullet < gemBullet,
|
||||
'antigravity bullet must precede gemini bullet in path-classification list',
|
||||
antIdeBullet < gemBullet && antCliBullet < gemBullet && antLegacyBullet < gemBullet,
|
||||
'all antigravity bullets must precede gemini bullet in path-classification list',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -95,6 +95,62 @@ describe('getGlobalDir — all runtimes default paths', () => {
|
||||
}
|
||||
});
|
||||
|
||||
describe('getGlobalDir/getConfigDirFromHome — antigravity 2.x layout detection', () => {
|
||||
const saved = {};
|
||||
beforeEach(() => {
|
||||
saved.HOME = process.env.HOME;
|
||||
saved.USERPROFILE = process.env.USERPROFILE;
|
||||
saved.ANTIGRAVITY_CONFIG_DIR = process.env.ANTIGRAVITY_CONFIG_DIR;
|
||||
delete process.env.ANTIGRAVITY_CONFIG_DIR;
|
||||
});
|
||||
afterEach(() => {
|
||||
if (saved.HOME !== undefined) process.env.HOME = saved.HOME;
|
||||
else delete process.env.HOME;
|
||||
if (saved.USERPROFILE !== undefined) process.env.USERPROFILE = saved.USERPROFILE;
|
||||
else delete process.env.USERPROFILE;
|
||||
if (saved.ANTIGRAVITY_CONFIG_DIR !== undefined) process.env.ANTIGRAVITY_CONFIG_DIR = saved.ANTIGRAVITY_CONFIG_DIR;
|
||||
else delete process.env.ANTIGRAVITY_CONFIG_DIR;
|
||||
});
|
||||
|
||||
test('uses ~/.gemini/antigravity-ide when legacy dir is absent and ide dir exists', () => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-antigravity-ide-'));
|
||||
try {
|
||||
fs.mkdirSync(path.join(home, '.gemini', 'antigravity-ide'), { recursive: true });
|
||||
process.env.HOME = home;
|
||||
process.env.USERPROFILE = home;
|
||||
assert.strictEqual(
|
||||
getGlobalDir('antigravity'),
|
||||
path.join(home, '.gemini', 'antigravity-ide'),
|
||||
);
|
||||
assert.strictEqual(
|
||||
getConfigDirFromHome('antigravity', true),
|
||||
"'.gemini', 'antigravity-ide'",
|
||||
);
|
||||
} finally {
|
||||
cleanup(home);
|
||||
}
|
||||
});
|
||||
|
||||
test('uses ~/.gemini/antigravity-cli when only cli dir exists', () => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-antigravity-cli-'));
|
||||
try {
|
||||
fs.mkdirSync(path.join(home, '.gemini', 'antigravity-cli'), { recursive: true });
|
||||
process.env.HOME = home;
|
||||
process.env.USERPROFILE = home;
|
||||
assert.strictEqual(
|
||||
getGlobalDir('antigravity'),
|
||||
path.join(home, '.gemini', 'antigravity-cli'),
|
||||
);
|
||||
assert.strictEqual(
|
||||
getConfigDirFromHome('antigravity', true),
|
||||
"'.gemini', 'antigravity-cli'",
|
||||
);
|
||||
} finally {
|
||||
cleanup(home);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGlobalDir — explicit configDir overrides env for all runtimes', () => {
|
||||
test('explicit dir overrides any env var for hermes', () => {
|
||||
const savedHome = process.env.HERMES_HOME;
|
||||
@@ -195,9 +251,26 @@ describe('getConfigDirFromHome — spot-checks', () => {
|
||||
assert.strictEqual(getConfigDirFromHome('trae', true), "'.trae'");
|
||||
});
|
||||
|
||||
test('antigravity returns .agent (local) and .gemini, antigravity (global)', () => {
|
||||
assert.strictEqual(getConfigDirFromHome('antigravity', false), "'.agent'");
|
||||
assert.strictEqual(getConfigDirFromHome('antigravity', true), "'.gemini', 'antigravity'");
|
||||
test('antigravity returns .agent (local) and legacy fallback global path when no 2.x dirs exist', () => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-antigravity-empty-'));
|
||||
const savedHome = process.env.HOME;
|
||||
const savedUserProfile = process.env.USERPROFILE;
|
||||
const savedAntigravityConfig = process.env.ANTIGRAVITY_CONFIG_DIR;
|
||||
delete process.env.ANTIGRAVITY_CONFIG_DIR;
|
||||
process.env.HOME = home;
|
||||
process.env.USERPROFILE = home;
|
||||
try {
|
||||
assert.strictEqual(getConfigDirFromHome('antigravity', false), "'.agent'");
|
||||
assert.strictEqual(getConfigDirFromHome('antigravity', true), "'.gemini', 'antigravity'");
|
||||
} finally {
|
||||
if (savedHome === undefined) delete process.env.HOME;
|
||||
else process.env.HOME = savedHome;
|
||||
if (savedUserProfile === undefined) delete process.env.USERPROFILE;
|
||||
else process.env.USERPROFILE = savedUserProfile;
|
||||
if (savedAntigravityConfig === undefined) delete process.env.ANTIGRAVITY_CONFIG_DIR;
|
||||
else process.env.ANTIGRAVITY_CONFIG_DIR = savedAntigravityConfig;
|
||||
cleanup(home);
|
||||
}
|
||||
});
|
||||
|
||||
test('kilo returns .kilo (local) and .config, kilo (global)', () => {
|
||||
|
||||
Reference in New Issue
Block a user