* fix: preserve unsent prompt when adding editor context in VS Code * fix: append Add to chat selections as markdown blocks with stable spacing Convert selected assistant content to markdown before appending Wrap each Add to chat selection in an `md` fenced block Preserve multiline composer formatting across repeated appends * fix: normalize persisted Windows paths to prevent identity mismatches * fix: hide Windows subprocess console popups across server tasks Hide OpenCode startup and shell command child windows in the web server Apply windowsHide to cloudflared and skills-catalog git subprocesses Cover remaining git service exec paths that could surface console windows * fix: restore chat auto re-pin when reaching bottom Re-pin now triggers when scrolling back into the bottom zone, not only via the button. Upward user scroll intent still unpins immediately and is not overridden by re-pin. Unified bottom/re-pin threshold logic to reduce sensitivity mismatches. * fix: restore chat scroll release on mobile during streaming Restores pinned-scroll release on touch scroll up so mobile users can leave auto-follow while streaming. Improves re-pin behavior near bottom to avoid sticky or inconsistent pin states. Includes related chat UI and dependency updates in the same change set. * fix: hide daemon startup probe consoles on Windows * fix: prevent pinned scroll tug-of-war during streaming * fix: prefer git.exe to avoid Windows diff popup flashes * fix: prefer git.exe discovery in Windows git flows * fix: avoid where probes in Windows git resolution * fix: avoid update-check subprocess flashes on Windows * fix: normalize read file path labels * feat: add OpenChamber defaults and improve theme ports Add new OpenChamber light and dark themes Regenerate imported themes with stronger surface mapping Set OpenChamber themes as the default top options * fix: stabilize chat pin and unpin behavior during streaming Restores reliable unpin on upward wheel and touch gestures while auto-follow is active. Prevents immediate re-pin while the user is actively scrolling upward near the bottom. Keeps smooth follow-to-bottom behavior while reducing scroll tug-of-war. * fix: suppress Windows command popups in VSCode runtime processes Hide spawned git and server process windows in VS Code runtime Extend hidden-window handling to server port cleanup and reveal commands Keep behavior unchanged on non-Windows platforms
78 lines
2.3 KiB
JavaScript
78 lines
2.3 KiB
JavaScript
import { execFile } from 'child_process';
|
|
import { promisify } from 'util';
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
|
|
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
const DEFAULT_MAX_BUFFER = 4 * 1024 * 1024;
|
|
|
|
export function looksLikeAuthError(message) {
|
|
const text = String(message || '');
|
|
return (
|
|
/permission denied/i.test(text) ||
|
|
/publickey/i.test(text) ||
|
|
/could not read from remote repository/i.test(text) ||
|
|
/authentication failed/i.test(text) ||
|
|
/fatal: could not/i.test(text)
|
|
);
|
|
}
|
|
|
|
export async function runGit(args, options = {}) {
|
|
const cwd = options.cwd;
|
|
const timeoutMs = Number.isFinite(options.timeoutMs) ? options.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
const maxBuffer = Number.isFinite(options.maxBuffer) ? options.maxBuffer : DEFAULT_MAX_BUFFER;
|
|
|
|
const identity = options.identity || null;
|
|
const normalizedArgs = Array.isArray(args) ? args.slice() : [];
|
|
|
|
// Non-interactive git (avoid prompts / hangs)
|
|
const env = {
|
|
...process.env,
|
|
GIT_TERMINAL_PROMPT: '0',
|
|
};
|
|
|
|
if (identity?.sshKey) {
|
|
const sshKeyPath = String(identity.sshKey).trim();
|
|
if (sshKeyPath) {
|
|
// Avoid interactive host key prompts; still safe against changed keys.
|
|
const sshCommand = `ssh -i ${sshKeyPath} -o BatchMode=yes -o StrictHostKeyChecking=accept-new`;
|
|
normalizedArgs.unshift(`core.sshCommand=${sshCommand}`);
|
|
normalizedArgs.unshift('-c');
|
|
}
|
|
}
|
|
|
|
try {
|
|
const { stdout, stderr } = await execFileAsync('git', normalizedArgs, {
|
|
cwd,
|
|
env,
|
|
windowsHide: true,
|
|
timeout: timeoutMs,
|
|
maxBuffer,
|
|
});
|
|
|
|
return { ok: true, stdout: stdout || '', stderr: stderr || '' };
|
|
} catch (error) {
|
|
const err = error;
|
|
const stdout = typeof err?.stdout === 'string' ? err.stdout : '';
|
|
const stderr = typeof err?.stderr === 'string' ? err.stderr : '';
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
|
|
return {
|
|
ok: false,
|
|
stdout,
|
|
stderr,
|
|
message,
|
|
code: typeof err?.code === 'number' ? err.code : null,
|
|
signal: typeof err?.signal === 'string' ? err.signal : null,
|
|
};
|
|
}
|
|
}
|
|
|
|
export async function assertGitAvailable() {
|
|
const result = await runGit(['--version'], { timeoutMs: 5_000 });
|
|
if (!result.ok) {
|
|
return { ok: false, error: { kind: 'gitUnavailable', message: 'Git is not available in PATH' } };
|
|
}
|
|
return { ok: true };
|
|
}
|