qwen-code/scripts/check-desktop-isolation.js
易良 ce72ddbe6c
feat(desktop): remove packages/desktop after OpenWork fork; keep the Tauri upgrade bridge (#9085)
OpenWork (modelstudioai/openwork) has forked the Electron desktop code and is
self-contained now, so retire the Electron package and its release/sync
machinery from this repo:

- Delete packages/desktop (Electron app, live-host app, bun workspace).
- Retire scripts/desktop-openwork-sync.ts and the desktop-openwork-sync root
  script; the OpenWork sync is no longer needed.
- Retire .github/workflows/live-host.yml, live-host-release.yml and
  sync-live-host-to-oss.yml; live-host releases now live in OpenWork. The
  CLI-side packages/cli/src/serve/live code stays for now (separate cleanup).
- Retire scripts/check-voice-guard-sync.js (cli<->desktop parity only) and
  its CI step.
- Clean up remaining references: root package.json workspaces negation and
  package-lock.json, eslint/prettier/yamllint ignores, architecture docs,
  web-shell skill descriptions, and review-lib workspace fixtures/comments
  (renamed to point at packages/desktop-shell, the remaining negation).

Deliberately kept: the Electron->Tauri upgrade bridge — desktop-release.yml
(incl. the electron_bridge input), create-electron-bridge-manifest.mjs,
sync-desktop-to-oss.yml (mirrors Tauri desktop-shell artifacts only) and
everything under packages/desktop-shell.
2026-08-25 05:26:11 +00:00

99 lines
2.4 KiB
JavaScript

/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import { execSync } from 'node:child_process';
import { existsSync, readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = join(__dirname, '..');
const desktopPrefixes = ['packages/desktop-shell'];
const forbiddenRootPackages = [
'electron',
'electron-builder',
'@sentry/cli',
'@sentry/electron',
'@sentry/vite-plugin',
];
let hasError = false;
console.log('Checking desktop workspace isolation...');
function isDesktopLocation(location) {
return desktopPrefixes.some(
(prefix) => location === prefix || location.startsWith(`${prefix}/`),
);
}
function reportError(message, values = []) {
hasError = true;
console.error(`\nError: ${message}`);
for (const value of values) {
console.error(`- ${value}`);
}
}
function rootPackageJsonPath(packageName) {
return join(root, 'node_modules', ...packageName.split('/'), 'package.json');
}
let workspaces;
try {
workspaces = JSON.parse(
execSync('npm query .workspace --json', {
cwd: root,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
}),
);
} catch (error) {
console.error('Failed to query npm workspaces:', error.message);
process.exit(1);
}
const desktopWorkspaces = workspaces
.map((workspace) => workspace.location)
.filter(isDesktopLocation);
if (desktopWorkspaces.length > 0) {
reportError(
'Desktop packages should not be part of the root npm workspace set.',
desktopWorkspaces,
);
}
const lockfile = JSON.parse(
readFileSync(join(root, 'package-lock.json'), 'utf8'),
);
const desktopLockfileEntries = Object.keys(lockfile.packages ?? {}).filter(
isDesktopLocation,
);
if (desktopLockfileEntries.length > 0) {
reportError(
'Root package-lock.json should not contain desktop package entries.',
desktopLockfileEntries,
);
}
const installedForbiddenPackages = forbiddenRootPackages.filter((packageName) =>
existsSync(rootPackageJsonPath(packageName)),
);
if (installedForbiddenPackages.length > 0) {
reportError(
'Desktop-only dependencies should not be installed in root node_modules.',
installedForbiddenPackages,
);
}
if (hasError) {
process.exit(1);
}
console.log('Desktop workspace isolation check passed.');