Files
openchamber/packages/web/server/lib/skills-catalog/git.js
T
Bohdan Triapitsyn 3123de5f43 fix: improve Windows UX and stabilize chat/session behavior across runtimes (#693)
* 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
2026-03-17 13:18:54 +02:00

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 };
}