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
This commit is contained in:
committed by
GitHub
parent
a07c068b66
commit
3123de5f43
@@ -11,6 +11,11 @@ const __dirname = path.dirname(__filename);
|
||||
const PACKAGE_NAME = '@openchamber/web';
|
||||
const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}`;
|
||||
const CHANGELOG_URL = 'https://raw.githubusercontent.com/btriapitsyn/openchamber/main/CHANGELOG.md';
|
||||
let cachedDetectedPm = null;
|
||||
|
||||
function getSpawnSyncBaseOptions() {
|
||||
return process.platform === 'win32' ? { windowsHide: true } : {};
|
||||
}
|
||||
const UPDATE_CHECK_URL = process.env.OPENCHAMBER_UPDATE_API_URL || 'https://api.openchamber.dev/v1/update/check';
|
||||
|
||||
function getOpenChamberConfigDir() {
|
||||
@@ -131,18 +136,24 @@ async function checkForUpdatesFromApi(currentVersion, options = {}) {
|
||||
* 4. Fall back to npm
|
||||
*/
|
||||
export function detectPackageManager() {
|
||||
if (cachedDetectedPm) {
|
||||
return cachedDetectedPm;
|
||||
}
|
||||
|
||||
const forcedPm = process.env.OPENCHAMBER_PACKAGE_MANAGER?.trim();
|
||||
if (forcedPm && ['npm', 'pnpm', 'yarn', 'bun'].includes(forcedPm)) {
|
||||
const forcedPmCommand = resolvePackageManagerCommand(forcedPm);
|
||||
if (isCommandAvailable(forcedPmCommand)) {
|
||||
return forcedPm;
|
||||
cachedDetectedPm = forcedPm;
|
||||
return cachedDetectedPm;
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 1: Detect from runtime executable path (reliable for server-side updates)
|
||||
const runtimePm = detectPackageManagerFromRuntimePath(process.execPath);
|
||||
if (runtimePm && isCommandAvailable(resolvePackageManagerCommand(runtimePm))) {
|
||||
return runtimePm;
|
||||
cachedDetectedPm = runtimePm;
|
||||
return cachedDetectedPm;
|
||||
}
|
||||
|
||||
// Strategy 2: Check user agent (most reliable during install)
|
||||
@@ -165,7 +176,8 @@ export function detectPackageManager() {
|
||||
// Strategy 4: Detect from invoked binary path (works for bun global symlink installs)
|
||||
const invokedPm = detectPackageManagerFromInvocationPath(process.argv?.[1]);
|
||||
if (invokedPm && isCommandAvailable(resolvePackageManagerCommand(invokedPm))) {
|
||||
return invokedPm;
|
||||
cachedDetectedPm = invokedPm;
|
||||
return cachedDetectedPm;
|
||||
}
|
||||
if (!hintedPm) {
|
||||
hintedPm = invokedPm;
|
||||
@@ -176,7 +188,8 @@ export function detectPackageManager() {
|
||||
const pkgPath = path.resolve(__dirname, '..', '..');
|
||||
const pmFromPath = detectPackageManagerFromInstallPath(pkgPath);
|
||||
if (pmFromPath && isCommandAvailable(resolvePackageManagerCommand(pmFromPath))) {
|
||||
return pmFromPath;
|
||||
cachedDetectedPm = pmFromPath;
|
||||
return cachedDetectedPm;
|
||||
}
|
||||
if (!hintedPm) {
|
||||
hintedPm = pmFromPath;
|
||||
@@ -188,7 +201,8 @@ export function detectPackageManager() {
|
||||
// Validate the hinted PM actually owns the global install.
|
||||
// This avoids false positives (for example running via bunx while installed with npm).
|
||||
if (hintedPm && isCommandAvailable(resolvePackageManagerCommand(hintedPm)) && isPackageInstalledWith(hintedPm)) {
|
||||
return hintedPm;
|
||||
cachedDetectedPm = hintedPm;
|
||||
return cachedDetectedPm;
|
||||
}
|
||||
|
||||
// Strategy 6: Check which PM binaries are available and preferred
|
||||
@@ -203,12 +217,14 @@ export function detectPackageManager() {
|
||||
if (check()) {
|
||||
// Verify this PM actually has the package installed globally
|
||||
if (isPackageInstalledWith(name)) {
|
||||
return name;
|
||||
cachedDetectedPm = name;
|
||||
return cachedDetectedPm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 'npm';
|
||||
cachedDetectedPm = 'npm';
|
||||
return cachedDetectedPm;
|
||||
}
|
||||
|
||||
function detectPackageManagerFromInstallPath(pkgPath) {
|
||||
@@ -285,6 +301,7 @@ function isCommandAvailable(command) {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
timeout: 5000,
|
||||
...getSpawnSyncBaseOptions(),
|
||||
});
|
||||
return result.status === 0;
|
||||
} catch {
|
||||
@@ -314,6 +331,7 @@ function isPackageInstalledWith(pm) {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
timeout: 10000,
|
||||
...getSpawnSyncBaseOptions(),
|
||||
});
|
||||
|
||||
if (result.status !== 0) return false;
|
||||
@@ -444,7 +462,6 @@ export async function checkForUpdates(options = {}) {
|
||||
const currentNum = parseVersion(currentVersion);
|
||||
const latestNum = parseVersion(latestVersion);
|
||||
const available = latestNum > currentNum;
|
||||
|
||||
let changelog;
|
||||
if (available) {
|
||||
changelog = await fetchChangelogNotes(currentVersion, latestVersion);
|
||||
@@ -474,6 +491,7 @@ export function executeUpdate(pm = detectPackageManager(), options = {}) {
|
||||
const result = spawnSync(command, {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
...getSpawnSyncBaseOptions(),
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user