chore: checkpoint existing workspace changes
This commit is contained in:
parent
74fea9c176
commit
64fdfd2422
8 changed files with 193 additions and 50 deletions
|
|
@ -84,6 +84,14 @@ const faqIcons = [
|
|||
<style scoped>
|
||||
.faq-section {
|
||||
position: relative;
|
||||
--faq-title-gradient: linear-gradient(135deg, #e0e6ff 0%, #ffd700 100%);
|
||||
--faq-subtitle-color: #8892b0;
|
||||
--faq-panel-bg: rgba(10, 10, 15, 0.8);
|
||||
--faq-panel-border: rgba(0, 240, 255, 0.08);
|
||||
--faq-panel-question: #e0e6ff;
|
||||
--faq-panel-answer: #8892b0;
|
||||
--faq-panel-hover-shadow: 0 8px 32px rgba(0, 240, 255, 0.06);
|
||||
--faq-panel-hover-border: rgba(0, 240, 255, 0.2);
|
||||
}
|
||||
|
||||
.faq-section__header {
|
||||
|
|
@ -100,7 +108,7 @@ const faqIcons = [
|
|||
letter-spacing: -0.03em;
|
||||
line-height: 1.15;
|
||||
margin-bottom: 16px;
|
||||
background: linear-gradient(135deg, #e0e6ff 0%, #ffd700 100%);
|
||||
background: var(--faq-title-gradient);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
|
|
@ -108,7 +116,7 @@ const faqIcons = [
|
|||
|
||||
.faq-section__subtitle {
|
||||
font-size: 1.1rem;
|
||||
color: #8892b0;
|
||||
color: var(--faq-subtitle-color);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
|
@ -134,9 +142,10 @@ const faqIcons = [
|
|||
|
||||
.faq-section__panel {
|
||||
border-radius: 16px !important;
|
||||
background: rgba(10, 10, 15, 0.8) !important;
|
||||
border: 1px solid rgba(0, 240, 255, 0.08) !important;
|
||||
background: var(--faq-panel-bg) !important;
|
||||
border: 1px solid var(--faq-panel-border) !important;
|
||||
backdrop-filter: blur(12px);
|
||||
color: var(--faq-panel-question) !important;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
|
||||
overflow: hidden;
|
||||
animation: faqFadeIn 0.5s ease both;
|
||||
|
|
@ -145,8 +154,8 @@ const faqIcons = [
|
|||
|
||||
.faq-section__panel:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: rgba(0, 240, 255, 0.2) !important;
|
||||
box-shadow: 0 8px 32px rgba(0, 240, 255, 0.06);
|
||||
border-color: var(--faq-panel-hover-border) !important;
|
||||
box-shadow: var(--faq-panel-hover-shadow);
|
||||
}
|
||||
|
||||
.faq-section__panel::after {
|
||||
|
|
@ -160,6 +169,8 @@ const faqIcons = [
|
|||
.faq-section__panel-title {
|
||||
padding: 20px 24px !important;
|
||||
min-height: unset !important;
|
||||
background: transparent !important;
|
||||
color: var(--faq-panel-question) !important;
|
||||
}
|
||||
|
||||
:deep(.faq-section__panel-title .v-expansion-panel-title__overlay) {
|
||||
|
|
@ -198,17 +209,18 @@ const faqIcons = [
|
|||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
color: #e0e6ff;
|
||||
color: var(--faq-panel-question);
|
||||
}
|
||||
|
||||
:deep(.faq-section__panel-text .v-expansion-panel-text__wrapper) {
|
||||
padding: 0 24px 20px 82px !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.faq-section__answer {
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.7;
|
||||
color: #8892b0;
|
||||
color: var(--faq-panel-answer);
|
||||
}
|
||||
|
||||
.faq-section__answer :deep(a) {
|
||||
|
|
@ -300,32 +312,28 @@ const faqIcons = [
|
|||
}
|
||||
|
||||
/* Light Theme */
|
||||
.v-theme--light .faq-section__title {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #d97706 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
:global(.v-theme--light) .faq-section,
|
||||
:global(html.light) .faq-section {
|
||||
--faq-title-gradient: linear-gradient(135deg, #1e293b 0%, #d97706 100%);
|
||||
--faq-subtitle-color: #475569;
|
||||
--faq-panel-bg: rgba(255, 255, 255, 0.75);
|
||||
--faq-panel-border: rgba(0, 0, 0, 0.06);
|
||||
--faq-panel-question: #1e293b;
|
||||
--faq-panel-answer: #475569;
|
||||
--faq-panel-hover-shadow: 0 8px 32px rgba(0, 180, 200, 0.08);
|
||||
--faq-panel-hover-border: rgba(0, 240, 255, 0.2);
|
||||
}
|
||||
|
||||
.v-theme--light .faq-section__subtitle {
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.v-theme--light .faq-section__panel {
|
||||
background: rgba(255, 255, 255, 0.75) !important;
|
||||
border-color: rgba(0, 0, 0, 0.06) !important;
|
||||
}
|
||||
|
||||
.v-theme--light .faq-section__panel:hover {
|
||||
box-shadow: 0 8px 32px rgba(0, 180, 200, 0.08);
|
||||
}
|
||||
|
||||
.v-theme--light .faq-section__panel-question {
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.v-theme--light .faq-section__answer {
|
||||
color: #475569;
|
||||
:global(.v-theme--dark) .faq-section,
|
||||
:global(html.dark) .faq-section {
|
||||
--faq-title-gradient: linear-gradient(135deg, #e0e6ff 0%, #ffd700 100%);
|
||||
--faq-subtitle-color: #8892b0;
|
||||
--faq-panel-bg: rgba(10, 10, 15, 0.8);
|
||||
--faq-panel-border: rgba(0, 240, 255, 0.08);
|
||||
--faq-panel-question: #e0e6ff;
|
||||
--faq-panel-answer: #8892b0;
|
||||
--faq-panel-hover-shadow: 0 8px 32px rgba(0, 240, 255, 0.06);
|
||||
--faq-panel-hover-border: rgba(0, 240, 255, 0.2);
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ export const useBrowserTheme = () => {
|
|||
const applyDocumentTheme = (name: ThemeName) => {
|
||||
if (!import.meta.client) return;
|
||||
|
||||
document.documentElement.classList.toggle("dark", name === "dark");
|
||||
document.documentElement.classList.toggle("light", name === "light");
|
||||
document.documentElement.style.colorScheme = name;
|
||||
|
||||
document.querySelectorAll(".v-application").forEach((app) => {
|
||||
app.classList.toggle("v-theme--dark", name === "dark");
|
||||
app.classList.toggle("v-theme--light", name === "light");
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@
|
|||
"target": [
|
||||
"nsis"
|
||||
],
|
||||
"executableName": "AgentTeamsAI",
|
||||
"icon": "resources/icons/win/icon.ico"
|
||||
},
|
||||
"linux": {
|
||||
|
|
@ -348,7 +349,8 @@
|
|||
"artifactName": "Agent.Teams.AI.Setup.${version}.${ext}",
|
||||
"oneClick": false,
|
||||
"perMachine": false,
|
||||
"allowToChangeInstallationDirectory": true
|
||||
"allowToChangeInstallationDirectory": true,
|
||||
"shortcutName": "Agent Teams AI"
|
||||
},
|
||||
"publish": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -92,9 +92,7 @@ function shouldKeepNodePtyPrebuild(entryName, platform, archLabel) {
|
|||
|
||||
if (platform === 'darwin' && archLabel === 'universal') {
|
||||
return (
|
||||
entryName === 'darwin-universal' ||
|
||||
entryName === 'darwin-arm64' ||
|
||||
entryName === 'darwin-x64'
|
||||
entryName === 'darwin-universal' || entryName === 'darwin-arm64' || entryName === 'darwin-x64'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -154,11 +152,85 @@ async function pruneNodePtyArtifacts(appOutDir, platform, archLabel) {
|
|||
removedPaths.push(absolutePath);
|
||||
}
|
||||
}
|
||||
|
||||
const hasTargetPrebuild = await hasNodePtyTargetPrebuild(nodePtyRoot, platform, archLabel);
|
||||
if (!hasTargetPrebuild) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const buildName of ['Release', 'Debug']) {
|
||||
const buildDir = path.join(nodePtyRoot, 'build', buildName);
|
||||
if (!(await directoryExists(buildDir))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (await containsIncompatibleNativeBinary(buildDir, platform, archLabel)) {
|
||||
await fs.promises.rm(buildDir, { recursive: true, force: true });
|
||||
removedPaths.push(buildDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return removedPaths;
|
||||
}
|
||||
|
||||
async function directoryExists(dirPath) {
|
||||
try {
|
||||
const stat = await fs.promises.stat(dirPath);
|
||||
return stat.isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function hasNodePtyTargetPrebuild(nodePtyRoot, platform, archLabel) {
|
||||
const prebuildsDir = path.join(nodePtyRoot, 'prebuilds');
|
||||
let entries;
|
||||
try {
|
||||
entries = await fs.promises.readdir(prebuildsDir, { withFileTypes: true });
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory() || !shouldKeepNodePtyPrebuild(entry.name, platform, archLabel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ptyNativePath = path.join(prebuildsDir, entry.name, 'pty.node');
|
||||
if (await fileExists(ptyNativePath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async function fileExists(filePath) {
|
||||
try {
|
||||
const stat = await fs.promises.stat(filePath);
|
||||
return stat.isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function containsIncompatibleNativeBinary(rootDir, targetPlatform, targetArch) {
|
||||
const files = await walkFiles(rootDir);
|
||||
for (const filePath of files) {
|
||||
const metadata = await detectBinaryMetadata(filePath);
|
||||
if (!metadata) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isBinaryCompatible(metadata.format, metadata.archs, targetPlatform, targetArch)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function findNodeModulesSequence(segments, sequence) {
|
||||
for (let index = 0; index <= segments.length - sequence.length; index += 1) {
|
||||
let matches = true;
|
||||
|
|
@ -332,12 +404,7 @@ function parseElf(buffer) {
|
|||
if (buffer.length < 20) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
buffer[0] !== 0x7f ||
|
||||
buffer[1] !== 0x45 ||
|
||||
buffer[2] !== 0x4c ||
|
||||
buffer[3] !== 0x46
|
||||
) {
|
||||
if (buffer[0] !== 0x7f || buffer[1] !== 0x45 || buffer[2] !== 0x4c || buffer[3] !== 0x46) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -454,11 +521,7 @@ async function afterPack(context) {
|
|||
|
||||
const removedPaths = [
|
||||
...(await pruneNodePtyArtifacts(context.appOutDir, targetPlatform, targetArch)),
|
||||
...(await pruneKnownIncompatibleNativeArtifacts(
|
||||
context.appOutDir,
|
||||
targetPlatform,
|
||||
targetArch
|
||||
)),
|
||||
...(await pruneKnownIncompatibleNativeArtifacts(context.appOutDir, targetPlatform, targetArch)),
|
||||
];
|
||||
const mismatches = await validateNativeBinaries(context.appOutDir, targetPlatform, targetArch);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import type { ChildProcessWithoutNullStreams } from 'child_process';
|
|||
|
||||
const PROBE_COMMAND_TIMEOUT_MS = 90_000;
|
||||
const COMMAND_TIMEOUT_MS = PROBE_COMMAND_TIMEOUT_MS;
|
||||
const COMMAND_MAX_BUFFER_BYTES = 8 * 1024 * 1024;
|
||||
const COMMAND_ERROR_DETAIL_LIMIT = 1_600;
|
||||
const COMMAND_OUTPUT_PREVIEW_LIMIT = 1_200;
|
||||
const ESCAPE_CHARACTER = String.fromCharCode(27);
|
||||
|
|
@ -870,8 +871,12 @@ function appendOptionalArg(args: string[], name: string, value: string | null |
|
|||
function runtimeProviderCommandOptions<T extends { env: NodeJS.ProcessEnv }>(
|
||||
options: T,
|
||||
projectPath: string | null
|
||||
): T & { cwd?: string } {
|
||||
return projectPath ? { ...options, cwd: projectPath } : options;
|
||||
): T & { cwd?: string; maxBuffer: number } {
|
||||
const commandOptions = {
|
||||
...options,
|
||||
maxBuffer: COMMAND_MAX_BUFFER_BYTES,
|
||||
};
|
||||
return projectPath ? { ...commandOptions, cwd: projectPath } : commandOptions;
|
||||
}
|
||||
|
||||
async function resolveCliEnv(): Promise<{
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
SelectValue,
|
||||
} from '@renderer/components/ui/select';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@renderer/components/ui/tabs';
|
||||
import { cn } from '@renderer/lib/utils';
|
||||
import {
|
||||
compareOpenCodeTeamModelRecommendations,
|
||||
getOpenCodeTeamModelRecommendation,
|
||||
|
|
@ -819,7 +820,10 @@ const RuntimeProviderErrorAlert = ({
|
|||
type="button"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-6 shrink-0 px-2 text-[11px]"
|
||||
className={cn(
|
||||
'h-6 shrink-0 px-2 text-[11px]',
|
||||
!copied && 'member-launch-diagnostics-pulse'
|
||||
)}
|
||||
title={copied ? 'Diagnostics copied' : 'Copy diagnostics'}
|
||||
aria-label={copied ? 'Diagnostics copied' : 'Copy diagnostics'}
|
||||
onClick={(event) => {
|
||||
|
|
|
|||
|
|
@ -134,6 +134,62 @@ describe('electron-builder afterPack', () => {
|
|||
expect(fs.existsSync(path.join(prebuildsDir, 'darwin-x64'))).toBe(false);
|
||||
});
|
||||
|
||||
it('prunes host node-pty build outputs when a matching target prebuild exists', async () => {
|
||||
const tempDir = createTempDir();
|
||||
tempDirs.push(tempDir);
|
||||
const nodePtyDir = path.join(
|
||||
tempDir,
|
||||
'resources',
|
||||
'app.asar.unpacked',
|
||||
'node_modules',
|
||||
'node-pty'
|
||||
);
|
||||
const releaseDir = path.join(nodePtyDir, 'build', 'Release');
|
||||
const prebuildDir = path.join(nodePtyDir, 'prebuilds', 'win32-x64');
|
||||
|
||||
writeFile(path.join(tempDir, 'AgentTeamsAI.exe'), createPortableExecutableBuffer('x64'));
|
||||
writeFile(path.join(releaseDir, 'pty.node'), createMachOBuffer('arm64'));
|
||||
writeFile(path.join(releaseDir, 'spawn-helper'), createMachOBuffer('arm64'));
|
||||
writeFile(path.join(prebuildDir, 'pty.node'), createPortableExecutableBuffer('x64'));
|
||||
writeFile(path.join(prebuildDir, 'conpty.node'), createPortableExecutableBuffer('x64'));
|
||||
|
||||
await afterPackModule({
|
||||
appOutDir: tempDir,
|
||||
electronPlatformName: 'win32',
|
||||
arch: 1,
|
||||
});
|
||||
|
||||
expect(fs.existsSync(releaseDir)).toBe(false);
|
||||
expect(fs.existsSync(path.join(prebuildDir, 'pty.node'))).toBe(true);
|
||||
});
|
||||
|
||||
it('keeps incompatible node-pty build outputs when no target prebuild exists', async () => {
|
||||
const tempDir = createTempDir();
|
||||
tempDirs.push(tempDir);
|
||||
const releaseDir = path.join(
|
||||
tempDir,
|
||||
'resources',
|
||||
'app.asar.unpacked',
|
||||
'node_modules',
|
||||
'node-pty',
|
||||
'build',
|
||||
'Release'
|
||||
);
|
||||
|
||||
writeFile(path.join(tempDir, 'agent-teams-ai'), createElfBuffer('x64'));
|
||||
writeFile(path.join(releaseDir, 'pty.node'), createMachOBuffer('arm64'));
|
||||
|
||||
await expect(
|
||||
afterPackModule({
|
||||
appOutDir: tempDir,
|
||||
electronPlatformName: 'linux',
|
||||
arch: 1,
|
||||
})
|
||||
).rejects.toThrow('Found incompatible native binaries in linux-x64 bundle after pruning');
|
||||
|
||||
expect(fs.existsSync(releaseDir)).toBe(true);
|
||||
});
|
||||
|
||||
it('fails validation when a foreign-arch native binary remains in the bundle', async () => {
|
||||
const tempDir = createTempDir();
|
||||
tempDirs.push(tempDir);
|
||||
|
|
|
|||
|
|
@ -1380,6 +1380,7 @@ describe('AgentTeamsRuntimeProviderManagementCliClient', () => {
|
|||
],
|
||||
expect.objectContaining({ cwd: '/Users/test/project' })
|
||||
);
|
||||
expect(execCliMock.mock.calls[0]?.[2]).toMatchObject({ maxBuffer: 8 * 1024 * 1024 });
|
||||
expect(JSON.stringify(execCliMock.mock.calls[0])).not.toContain('undefined');
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue