VS Code Copilot never sets COPILOT_PLUGIN_DATA, only CLAUDE_PLUGIN_ROOT (pointed at an .vscode/agent-plugins/... install path), so isCopilot was false and ponytail assumed native Claude Code — emitting the statusline setup nudge, which VS Code Copilot doesn't read. Also guard stateDir: it was built from the same unset COPILOT_PLUGIN_DATA whenever isCopilot resolved via this new fallback, so fall back to getClaudeDir() there too.
This commit is contained in:
@@ -4,13 +4,28 @@ const os = require('os');
|
||||
const { getClaudeDir, getConfigDir } = require('./ponytail-config');
|
||||
|
||||
const STATE_FILE = '.ponytail-active';
|
||||
const isCopilot = Boolean(process.env.COPILOT_PLUGIN_DATA);
|
||||
|
||||
// ponytail: VS Code Copilot never sets COPILOT_PLUGIN_DATA — it only injects
|
||||
// CLAUDE_PLUGIN_ROOT, pointed at an install path under .vscode/agent-plugins/
|
||||
// (#528). Without this fallback isCopilot was false, so ponytail assumed
|
||||
// native Claude Code and emitted the statusline nudge, which VS Code Copilot
|
||||
// doesn't read.
|
||||
function isVsCodeCopilotRoot(pluginRoot) {
|
||||
if (!pluginRoot) return false;
|
||||
return pluginRoot.split(/[\\/]+/).includes('agent-plugins') &&
|
||||
pluginRoot.toLowerCase().includes('.vscode');
|
||||
}
|
||||
|
||||
const isCopilot = Boolean(process.env.COPILOT_PLUGIN_DATA) ||
|
||||
isVsCodeCopilotRoot(process.env.CLAUDE_PLUGIN_ROOT);
|
||||
const isCodex = !isCopilot && Boolean(process.env.PLUGIN_DATA);
|
||||
const isQoder = !isCopilot && !isCodex && Boolean(process.env.QODER_SESSION_ID);
|
||||
|
||||
let stateDir = getClaudeDir();
|
||||
if (isCodex) stateDir = process.env.PLUGIN_DATA;
|
||||
if (isCopilot) stateDir = process.env.COPILOT_PLUGIN_DATA;
|
||||
// COPILOT_PLUGIN_DATA is unset under VS Code Copilot, so fall back to
|
||||
// getClaudeDir() rather than building a path from undefined.
|
||||
if (isCopilot) stateDir = process.env.COPILOT_PLUGIN_DATA || getClaudeDir();
|
||||
if (isQoder) stateDir = path.join(os.homedir(), '.qoder');
|
||||
|
||||
const statePath = path.join(stateDir, STATE_FILE);
|
||||
|
||||
@@ -198,6 +198,36 @@ assert.equal(
|
||||
output = JSON.parse(result.stdout);
|
||||
assert.match(output.additionalContext, /PONYTAIL MODE ACTIVE — level: full/);
|
||||
|
||||
// VS Code Copilot never sets COPILOT_PLUGIN_DATA — it only injects
|
||||
// CLAUDE_PLUGIN_ROOT pointed at an agent-plugins/.../.vscode install path
|
||||
// (#528). Without a fallback, isCopilot was false, so ponytail assumed
|
||||
// native Claude Code and emitted the statusline nudge — noise, since VS
|
||||
// Code Copilot doesn't read Claude's statusLine setting.
|
||||
const vscodeHome = path.join(temp, 'vscode-copilot-home');
|
||||
const vscodePluginRoot = path.join(
|
||||
vscodeHome, '.vscode', 'agent-plugins', 'github.com', 'DietrichGebert', 'ponytail', 'hooks',
|
||||
);
|
||||
fs.mkdirSync(vscodeHome, { recursive: true });
|
||||
result = run('ponytail-activate.js', {
|
||||
HOME: vscodeHome,
|
||||
USERPROFILE: vscodeHome,
|
||||
CLAUDE_PLUGIN_ROOT: vscodePluginRoot,
|
||||
PONYTAIL_DEFAULT_MODE: 'full',
|
||||
});
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.ok(
|
||||
!result.stdout.includes('STATUSLINE SETUP NEEDED'),
|
||||
'VS Code Copilot (detected via CLAUDE_PLUGIN_ROOT) must not get the Claude-only statusline nudge',
|
||||
);
|
||||
// isCopilot must still resolve a state dir even though COPILOT_PLUGIN_DATA
|
||||
// is unset under VS Code — falling back to ~/.claude, not crashing on an
|
||||
// undefined path.
|
||||
assert.equal(
|
||||
fs.readFileSync(path.join(vscodeHome, '.claude', '.ponytail-active'), 'utf8'),
|
||||
'full',
|
||||
'VS Code Copilot must persist mode state under getClaudeDir(), not a path built from the unset COPILOT_PLUGIN_DATA',
|
||||
);
|
||||
|
||||
result = run(
|
||||
'ponytail-mode-tracker.js',
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user