feat: added /rename command to set session titles for status/header/tab display
- Added `/rename <title>` slash command to set explicit session names and update header/tab titles. - Added `session_name` status segment with hash-derived accent color for session titles. - Fixed shell execution failure sanitization to preserve all `execResult` fields after redacting stderr. - Fixed tool execution completion output to pass original `toolResult` text instead of sanitized `content`.
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed shell execution failure responses to preserve all result fields when sanitizing, preventing truncated metadata in stream results
|
||||
- Fixed context overflow detection to recognize `model_context_window_exceeded` from z.ai / GLM providers, preventing infinite retry loops when context window is exceeded ([#638](https://github.com/can1357/oh-my-pi/issues/638))
|
||||
|
||||
|
||||
## [14.1.0] - 2026-04-11
|
||||
### Added
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ import {
|
||||
type ShellArgs,
|
||||
ShellFailureSchema,
|
||||
ShellRejectedSchema,
|
||||
type ShellResult,
|
||||
ShellResultSchema,
|
||||
type ShellStream,
|
||||
ShellStreamExitSchema,
|
||||
@@ -675,9 +676,7 @@ function sendShellStreamEvent(
|
||||
sendExecClientMessage(h2Request, execMsg, "shellStream", create(ShellStreamSchema, { event }));
|
||||
}
|
||||
|
||||
function sanitizeShellExecResult(execResult: { result: { case?: string; value?: any } }): {
|
||||
result: { case?: string; value?: any };
|
||||
} {
|
||||
function sanitizeShellExecResult(execResult: ShellResult): ShellResult {
|
||||
const result = execResult.result;
|
||||
if (!result) return execResult;
|
||||
|
||||
@@ -686,6 +685,7 @@ function sanitizeShellExecResult(execResult: { result: { case?: string; value?:
|
||||
case "failure": {
|
||||
const value = result.value;
|
||||
return {
|
||||
...execResult,
|
||||
result: {
|
||||
case: result.case,
|
||||
value: {
|
||||
@@ -694,7 +694,7 @@ function sanitizeShellExecResult(execResult: { result: { case?: string; value?:
|
||||
stderr: value.stderr ? sanitizeText(value.stderr) : value.stderr,
|
||||
},
|
||||
},
|
||||
};
|
||||
} as ShellResult;
|
||||
}
|
||||
default:
|
||||
return execResult;
|
||||
@@ -854,7 +854,7 @@ async function handleShellStreamArgs(
|
||||
function sendShellStreamExitFromResult(
|
||||
h2Request: http2.ClientHttp2Stream,
|
||||
execMsg: ExecServerMessage,
|
||||
execResult: { result: { case?: string; value?: any } },
|
||||
execResult: ShellResult,
|
||||
sendBufferedOutput: boolean,
|
||||
): void {
|
||||
const result = execResult.result;
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for `computeHashlineDiff` to accept hashline edits with `loc` and `content` payloads without requiring pre-resolved `op` fields
|
||||
- Added `/rename <title>` slash command to set an explicit session name, updating the session header and terminal tab title ([#658](https://github.com/can1357/oh-my-pi/issues/658))
|
||||
- Added `session_name` status line segment: displays the session name in the status bar right side with a stable hash-derived accent color unique to each name; shown in all presets when a name is set
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed eager todo enforcement to only apply on the first user message of a conversation, skipping subsequent user turns that may correct, clarify, or redirect the prior task
|
||||
|
||||
### Added
|
||||
|
||||
- Added `/rename <title>` slash command to set an explicit session name, updating the session header and terminal tab title ([#658](https://github.com/can1357/oh-my-pi/issues/658))
|
||||
- Added `session_name` status line segment: displays the session name in the status bar right side with a stable hash-derived accent color unique to each name; shown in all presets when a name is set
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed tool execution output to return the original `toolResult` text content from tools instead of sanitizing it before sending completion messages
|
||||
- Fixed session accent rendering in the status line and editor to reset only foreground color (`\x1b[39m`) so applying a session color no longer clears other ANSI styles
|
||||
- Session name sanitization: strip C0/C1 control characters (including ANSI ESC) from session names at storage time and in status line rendering, preventing escape sequence injection into TUI output
|
||||
- Auto-generated session titles no longer overwrite a name set via `/rename`: `setSessionName` now tracks whether the name was set by the user or auto-generated and silently ignores auto titles once a user name is in place; terminal title follows the same guard
|
||||
- Session accent border color now applied on session resume and after auto-title generation, not only after an explicit `/rename`
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed retained Python kernel ownership so `AgentSession.dispose()` only shuts down kernels owned by that session, including warmup-created kernels
|
||||
|
||||
## [14.1.0] - 2026-04-11
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"puppeteer": "catalog:",
|
||||
"turndown": "catalog:",
|
||||
"turndown-plugin-gfm": "catalog:",
|
||||
"zod": "catalog:pinned"
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "catalog:",
|
||||
|
||||
@@ -769,7 +769,6 @@ export class ModelRegistry {
|
||||
// models registered by extensions survive the model selector's offline reload.
|
||||
#runtimeModelOverlays: CustomModelOverlay[] = [];
|
||||
#runtimeProviderApiKeys: Map<string, string> = new Map();
|
||||
#runtimeKeylessProviders: Set<string> = new Set();
|
||||
#runtimeProvidersBySource: Map<string, Set<string>> = new Map();
|
||||
#runtimeProviderSourceByName: Map<string, string> = new Map();
|
||||
|
||||
@@ -847,11 +846,6 @@ export class ModelRegistry {
|
||||
this.#configError = undefined;
|
||||
this.#providerDiscoveryStates.clear();
|
||||
this.#loadModels();
|
||||
// Restore runtime keyless providers AFTER #loadModels, because #loadModels
|
||||
// replaces this.#keylessProviders via = with a new Set from models.yml.
|
||||
for (const k of this.#runtimeKeylessProviders) {
|
||||
this.#keylessProviders.add(k);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1938,7 +1932,6 @@ export class ModelRegistry {
|
||||
}
|
||||
this.#runtimeProviderSourceByName.delete(providerName);
|
||||
this.#runtimeProviderApiKeys.delete(providerName);
|
||||
this.#runtimeKeylessProviders.delete(providerName);
|
||||
this.#runtimeModelOverlays = this.#runtimeModelOverlays.filter(overlay => overlay.provider !== providerName);
|
||||
}
|
||||
this.#reloadStaticModels();
|
||||
|
||||
@@ -33,7 +33,7 @@ function createToolResultMessage(
|
||||
role: "toolResult",
|
||||
toolCallId,
|
||||
toolName,
|
||||
content: result.content.map(c => (c.type === "text" ? { ...c, text: sanitizeText(c.text) } : c)),
|
||||
content: result.content,
|
||||
details: result.details,
|
||||
isError,
|
||||
timestamp: Date.now(),
|
||||
@@ -100,7 +100,7 @@ async function executeTool(
|
||||
};
|
||||
options.emitEvent?.({ type: "tool_execution_end", toolCallId, toolName, result: sanitizedFinalResult, isError });
|
||||
|
||||
return createToolResultMessage(toolCallId, toolName, sanitizedFinalResult, isError);
|
||||
return createToolResultMessage(toolCallId, toolName, result, isError);
|
||||
}
|
||||
|
||||
async function executeDelete(options: CursorExecBridgeOptions, pathArg: string, toolCallId: string) {
|
||||
@@ -315,7 +315,7 @@ export class CursorExecHandlers implements ICursorExecHandlers {
|
||||
result: sanitizedFinalResult,
|
||||
isError,
|
||||
});
|
||||
return createToolResultMessage(toolCallId, toolName, sanitizedFinalResult, isError);
|
||||
return createToolResultMessage(toolCallId, toolName, result, isError);
|
||||
}
|
||||
|
||||
async diagnostics(args: Parameters<NonNullable<ICursorExecHandlers["diagnostics"]>>[0]) {
|
||||
|
||||
@@ -1150,7 +1150,7 @@ export class AcpAgent implements Agent {
|
||||
setThinkingLevel: level => record.session.setThinkingLevel(level),
|
||||
getSessionName: () => record.session.sessionManager.getSessionName(),
|
||||
setSessionName: async name => {
|
||||
await record.session.sessionManager.setSessionName(name);
|
||||
await record.session.sessionManager.setSessionName(name, "user");
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ import { theme } from "../../modes/theme/theme";
|
||||
import type { AgentSession } from "../../session/agent-session";
|
||||
import { calculatePromptTokens } from "../../session/compaction/compaction";
|
||||
import * as git from "../../utils/git";
|
||||
import { getSessionAccentHexForTitle } from "../../utils/session-color";
|
||||
import { getSessionAccentAnsi, getSessionAccentHexForTitle } from "../../utils/session-color";
|
||||
import { sanitizeStatusText } from "../shared";
|
||||
import {
|
||||
canReuseCachedPr,
|
||||
@@ -476,10 +476,8 @@ export class StatusLineComponent implements Component {
|
||||
this.session.sessionManager?.getSessionName(),
|
||||
this.session.sessionManager?.titleSource,
|
||||
);
|
||||
const gapColor = accentHex
|
||||
? (Bun.color(accentHex, "ansi-16m") ?? theme.getFgAnsi("border"))
|
||||
: theme.getFgAnsi("border");
|
||||
const gapFill = `${gapColor}${theme.boxRound.horizontal.repeat(gapWidth)}\x1b[0m`;
|
||||
const gapColor = getSessionAccentAnsi(accentHex) ?? theme.getFgAnsi("border");
|
||||
const gapFill = `${gapColor}${theme.boxRound.horizontal.repeat(gapWidth)}\x1b[39m`;
|
||||
return leftGroup + gapFill + rightGroup;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { TERMINAL } from "@oh-my-pi/pi-tui";
|
||||
import { formatDuration, formatNumber, getProjectDir, relativePathWithinRoot } from "@oh-my-pi/pi-utils";
|
||||
import { theme } from "../../../modes/theme/theme";
|
||||
import { shortenPath } from "../../../tools/render-utils";
|
||||
import { getSessionAccentHex } from "../../../utils/session-color";
|
||||
import { getSessionAccentAnsi, getSessionAccentHex } from "../../../utils/session-color";
|
||||
import { sanitizeStatusText } from "../../shared";
|
||||
import { getContextUsageLevel, getContextUsageThemeColor } from "./context-thresholds";
|
||||
import type { RenderedSegment, SegmentContext, StatusLineSegment, StatusLineSegmentId } from "./types";
|
||||
@@ -362,8 +362,7 @@ const sessionNameSegment: StatusLineSegment = {
|
||||
const name = ctx.session.sessionManager?.getSessionName();
|
||||
if (!name) return { content: "", visible: false };
|
||||
|
||||
const hex = getSessionAccentHex(name);
|
||||
const ansi = Bun.color(hex, "ansi-16m") ?? theme.getFgAnsi("accent");
|
||||
const ansi = getSessionAccentAnsi(getSessionAccentHex(name)) ?? theme.getFgAnsi("accent");
|
||||
return { content: `${ansi}${sanitizeStatusText(name)}\x1b[39m`, visible: true };
|
||||
},
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ import { STTController, type SttState } from "../stt";
|
||||
import type { ExitPlanModeDetails, LspStartupServerInfo } from "../tools";
|
||||
import type { EventBus } from "../utils/event-bus";
|
||||
import { getEditorCommand, openInEditor } from "../utils/external-editor";
|
||||
import { getSessionAccentHexForTitle } from "../utils/session-color";
|
||||
import { getSessionAccentAnsi, getSessionAccentHexForTitle } from "../utils/session-color";
|
||||
import { popTerminalTitle, pushTerminalTitle, setSessionTerminalTitle } from "../utils/title-generator";
|
||||
import type { AssistantMessageComponent } from "./components/assistant-message";
|
||||
import type { BashExecutionComponent } from "./components/bash-execution";
|
||||
@@ -534,14 +534,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
||||
this.editor.borderColor = theme.getPythonModeBorderColor();
|
||||
} else {
|
||||
const hex = getSessionAccentHexForTitle(this.sessionManager.getSessionName(), this.sessionManager.titleSource);
|
||||
if (hex) {
|
||||
const ansi = Bun.color(hex, "ansi-16m");
|
||||
if (ansi) {
|
||||
this.editor.borderColor = (str: string) => `${ansi}${str}\x1b[0m`;
|
||||
} else {
|
||||
const level = this.session.thinkingLevel ?? ThinkingLevel.Off;
|
||||
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
||||
}
|
||||
const ansi = getSessionAccentAnsi(hex);
|
||||
if (ansi) {
|
||||
this.editor.borderColor = (str: string) => `${ansi}${str}\x1b[39m`;
|
||||
} else {
|
||||
const level = this.session.thinkingLevel ?? ThinkingLevel.Off;
|
||||
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
||||
|
||||
@@ -75,7 +75,7 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
|
||||
setThinkingLevel: level => session.setThinkingLevel(level),
|
||||
getSessionName: () => session.sessionManager.getSessionName(),
|
||||
setSessionName: async name => {
|
||||
await session.sessionManager.setSessionName(name);
|
||||
await session.sessionManager.setSessionName(name, "user");
|
||||
},
|
||||
},
|
||||
// ExtensionContextActions
|
||||
|
||||
@@ -442,7 +442,7 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
||||
setThinkingLevel: level => session.setThinkingLevel(level),
|
||||
getSessionName: () => session.sessionManager.getSessionName(),
|
||||
setSessionName: async name => {
|
||||
await session.sessionManager.setSessionName(name);
|
||||
await session.sessionManager.setSessionName(name, "user");
|
||||
},
|
||||
},
|
||||
// ExtensionContextActions
|
||||
|
||||
@@ -44,3 +44,12 @@ export function getSessionAccentHexForTitle(
|
||||
if (!name || titleSource === "auto") return undefined;
|
||||
return getSessionAccentHex(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hex accent color to an ANSI-16m foreground escape sequence.
|
||||
* Returns `undefined` if `hex` is nullish or Bun.color conversion fails.
|
||||
*/
|
||||
export function getSessionAccentAnsi(hex: string | undefined): string | undefined {
|
||||
if (!hex) return undefined;
|
||||
return Bun.color(hex, "ansi-16m") ?? undefined;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
|
||||
- Added support for honoring the `ZIG` environment variable when resolving the Zig executable for native builds
|
||||
|
||||
## [14.0.5] - 2026-04-11
|
||||
### Breaking Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as fsSync from "node:fs";
|
||||
import * as fs from "node:fs/promises";
|
||||
import * as path from "node:path";
|
||||
import { $ } from "bun";
|
||||
import { detectHostAvx2Support } from "./host-detect";
|
||||
|
||||
const repoRoot = path.join(import.meta.dir, "../../..");
|
||||
const rustDir = path.join(repoRoot, "crates/pi-natives");
|
||||
@@ -34,48 +34,6 @@ if (configuredVariantRaw) {
|
||||
configuredVariant = configuredVariantRaw;
|
||||
}
|
||||
|
||||
function runCommand(command: string, args: string[]): string | null {
|
||||
try {
|
||||
const result = Bun.spawnSync([command, ...args], { stdout: "pipe", stderr: "pipe" });
|
||||
if (result.exitCode !== 0) return null;
|
||||
return result.stdout.toString("utf-8").trim();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function detectHostAvx2Support(): boolean {
|
||||
if (process.arch !== "x64") return false;
|
||||
|
||||
if (process.platform === "linux") {
|
||||
try {
|
||||
const cpuInfo = fsSync.readFileSync("/proc/cpuinfo", "utf8");
|
||||
return /\bavx2\b/i.test(cpuInfo);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
const leaf7 = runCommand("sysctl", ["-n", "machdep.cpu.leaf7_features"]);
|
||||
if (leaf7 && /\bAVX2\b/i.test(leaf7)) return true;
|
||||
const features = runCommand("sysctl", ["-n", "machdep.cpu.features"]);
|
||||
return Boolean(features && /\bAVX2\b/i.test(features));
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const output = runCommand("powershell.exe", [
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-Command",
|
||||
"[System.Runtime.Intrinsics.X86.Avx2]::IsSupported",
|
||||
]);
|
||||
return output?.toLowerCase() === "true";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveEffectiveVariant(): X64Variant | null {
|
||||
if (targetArch !== "x64") return null;
|
||||
if (configuredVariant) return configuredVariant;
|
||||
@@ -101,7 +59,7 @@ function resolveSafeHostZigBuildConfig(): SafeHostZigBuildConfig | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
const realZigPath = Bun.which("zig");
|
||||
const realZigPath = Bun.env.ZIG ?? Bun.which("zig");
|
||||
if (!realZigPath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
### Changed
|
||||
|
||||
- Changed truncation debug logging to run only when `debugRedraw` is enabled
|
||||
|
||||
## [14.0.5] - 2026-04-11
|
||||
|
||||
|
||||
+12
-13
@@ -1196,19 +1196,18 @@ export class TUI extends Container {
|
||||
let truncatedLine = line;
|
||||
const isImage = TERMINAL.isImageLine(line);
|
||||
if (!isImage && visibleWidth(line) > width) {
|
||||
// Debug log for component developers (not a crash)
|
||||
const debugLogPath = getDebugLogPath();
|
||||
const debugData = [
|
||||
`[TUI Truncate] ${new Date().toISOString()}`,
|
||||
`Line ${i} truncated: ${visibleWidth(line)} > ${width}`,
|
||||
`Content preview: ${line.slice(0, 100)}...`,
|
||||
"",
|
||||
].join("\n");
|
||||
try {
|
||||
fs.mkdirSync(path.dirname(debugLogPath), { recursive: true });
|
||||
fs.appendFileSync(debugLogPath, debugData);
|
||||
} catch {
|
||||
// Ignore write errors - truncation should still work
|
||||
if (debugRedraw) {
|
||||
const debugData = [
|
||||
`[TUI Truncate] ${new Date().toISOString()}`,
|
||||
`Line ${i} truncated: ${visibleWidth(line)} > ${width}`,
|
||||
`Content preview: ${line.slice(0, 100)}...`,
|
||||
"",
|
||||
].join("\n");
|
||||
try {
|
||||
fs.appendFileSync(getDebugLogPath(), debugData);
|
||||
} catch {
|
||||
// Ignore write errors - truncation should still work
|
||||
}
|
||||
}
|
||||
truncatedLine = truncateToWidth(line, width, Ellipsis.Omit);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { $ } from "bun";
|
||||
import { detectHostAvx2Support } from "../packages/natives/scripts/host-detect";
|
||||
|
||||
interface NativeBuildVariant {
|
||||
name: "baseline" | "modern";
|
||||
@@ -37,48 +37,6 @@ function parseTargetVariants(): NativeBuildVariant[] {
|
||||
});
|
||||
}
|
||||
|
||||
function runCommand(command: string, args: string[]): string | null {
|
||||
try {
|
||||
const result = Bun.spawnSync([command, ...args], { stdout: "pipe", stderr: "pipe" });
|
||||
if (result.exitCode !== 0) return null;
|
||||
return result.stdout.toString("utf-8").trim();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function detectHostAvx2Support(): boolean {
|
||||
if (process.arch !== "x64") return false;
|
||||
|
||||
if (process.platform === "linux") {
|
||||
try {
|
||||
const cpuInfo = fs.readFileSync("/proc/cpuinfo", "utf8");
|
||||
return /\bavx2\b/i.test(cpuInfo);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
const leaf7 = runCommand("sysctl", ["-n", "machdep.cpu.leaf7_features"]);
|
||||
if (leaf7 && /\bAVX2\b/i.test(leaf7)) return true;
|
||||
const features = runCommand("sysctl", ["-n", "machdep.cpu.features"]);
|
||||
return Boolean(features && /\bAVX2\b/i.test(features));
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const output = runCommand("powershell.exe", [
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-Command",
|
||||
"[System.Runtime.Intrinsics.X86.Avx2]::IsSupported",
|
||||
]);
|
||||
return output?.toLowerCase() === "true";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveExpectedAddons(variants: NativeBuildVariant[]): string[] {
|
||||
if (variants.length > 0) {
|
||||
return variants.map(variant => `${targetPlatform}-${targetArch}-${variant.name}`);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import * as fs from "node:fs";
|
||||
|
||||
function runCommand(command: string, args: string[]): string | null {
|
||||
try {
|
||||
const result = Bun.spawnSync([command, ...args], { stdout: "pipe", stderr: "pipe" });
|
||||
if (result.exitCode !== 0) return null;
|
||||
return result.stdout.toString("utf-8").trim();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function detectHostAvx2Support(): boolean {
|
||||
if (process.arch !== "x64") return false;
|
||||
|
||||
if (process.platform === "linux") {
|
||||
try {
|
||||
const cpuInfo = fs.readFileSync("/proc/cpuinfo", "utf8");
|
||||
return /\bavx2\b/i.test(cpuInfo);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
const leaf7 = runCommand("sysctl", ["-n", "machdep.cpu.leaf7_features"]);
|
||||
if (leaf7 && /\bAVX2\b/i.test(leaf7)) return true;
|
||||
const features = runCommand("sysctl", ["-n", "machdep.cpu.features"]);
|
||||
return Boolean(features && /\bAVX2\b/i.test(features));
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const output = runCommand("powershell.exe", [
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-Command",
|
||||
"[System.Runtime.Intrinsics.X86.Avx2]::IsSupported",
|
||||
]);
|
||||
return output?.toLowerCase() === "true";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user