Files
Netcatty/scripts/beforePackCursorSdk.test.cjs
T
bincxz d422a27715 Merge origin/main into feature/app-lock-screen
Reconcile the app-lock feature with main's refactored renderer
architecture (publishers/hosts/AppShell) and main-process changes:

- index.tsx/App.tsx: AppLockGate keeps ownership of useSettingsState and
  useAppLockState; new AppLockRuntimePublisher publishes the runtime via
  appRuntimeBridge; SettingsPublisher now binds the gate-owned settings.
- AppSideEffects: defer deep links, tray port-forward toggles, global
  hotkeys and window close commands while locked; flush on unlock.
- main.cjs: keep fresh-session re-lock before main's reusable-window
  fast path; before-quit guard delegates to handleBeforeQuit with main's
  async plugin-shutdown commitQuit and pending-update cancellation.
- globalShortcutBridge: keep locked-state tray redaction on top of
  main's deferred tray panel show logic.
- preload: adopt main's lastPayload replay for terminal popup config
  (superset of the gate-delay replay fix).
- vite config: keep dev CSP plugin, adopt main's warn-only stale
  optimize-dep handling; electron-builder: keep Windows Hello helper
  extraResource with main's CLI-controlled arch targets.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-18 16:30:30 +08:00

215 lines
7.2 KiB
JavaScript

const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const {
CURSOR_PLATFORM_PACKAGES,
beforePackCursorSdk,
ensureCursorSdkPlatformPackages,
} = require("./beforePackCursorSdk.cjs");
const {
copyPatchedNodePtyToPackagedApp,
rebuildPatchedNodePty,
} = require("./nodePtyConptyPatch.cjs");
function writeJson(filePath, value) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
}
test("ensureCursorSdkPlatformPackages installs both macOS Cursor runtime packages", (t) => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "netcatty-cursor-pack-"));
t.after(() => fs.rmSync(tempDir, { recursive: true, force: true }));
writeJson(path.join(tempDir, "node_modules", "@cursor", "sdk", "package.json"), { version: "1.0.18" });
writeJson(path.join(tempDir, "node_modules", "@cursor", "sdk-darwin-arm64", "package.json"), { version: "1.0.18" });
const calls = [];
const installed = ensureCursorSdkPlatformPackages({
projectDir: tempDir,
platform: "darwin",
run: (...args) => calls.push(args),
logger: { log() {}, warn() {} },
});
assert.deepEqual(installed, ["@cursor/sdk-darwin-x64"]);
assert.equal(calls.length, 1);
assert.equal(calls[0][0], process.platform === "win32" ? "npm.cmd" : "npm");
assert.deepEqual(calls[0][1], [
"install",
"--no-save",
"--force",
"--ignore-scripts",
"@cursor/sdk-darwin-x64@1.0.18",
]);
assert.equal(calls[0][2].cwd, tempDir);
});
test("ensureCursorSdkPlatformPackages is a no-op when target packages exist", (t) => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "netcatty-cursor-pack-"));
t.after(() => fs.rmSync(tempDir, { recursive: true, force: true }));
writeJson(path.join(tempDir, "node_modules", "@cursor", "sdk", "package.json"), { version: "1.0.18" });
for (const packageName of CURSOR_PLATFORM_PACKAGES.linux) {
writeJson(path.join(tempDir, "node_modules", ...packageName.split("/"), "package.json"), { version: "1.0.18" });
}
const calls = [];
const installed = ensureCursorSdkPlatformPackages({
projectDir: tempDir,
platform: "linux",
run: (...args) => calls.push(args),
logger: { log() {}, warn() {} },
});
assert.deepEqual(installed, []);
assert.deepEqual(calls, []);
});
test("beforePackCursorSdk builds Windows Hello helper only for Windows packages", () => {
const calls = [];
beforePackCursorSdk({
appDir: process.cwd(),
electronPlatformName: "win32",
arch: 3,
ensureCursorSdkPlatformPackages: () => [],
buildWindowsHelloHelper: (projectDir) => calls.push(projectDir),
});
assert.deepEqual(calls, [{ projectDir: process.cwd(), platform: "win32", arch: "arm64" }]);
beforePackCursorSdk({
appDir: process.cwd(),
electronPlatformName: "darwin",
ensureCursorSdkPlatformPackages: () => [],
buildWindowsHelloHelper: (projectDir) => calls.push(projectDir),
});
assert.deepEqual(calls, [{ projectDir: process.cwd(), platform: "win32", arch: "arm64" }]);
});
test("beforePackCursorSdk falls back to npm_config_arch for Windows Hello helper arch", () => {
const calls = [];
const originalArch = process.env.npm_config_arch;
process.env.npm_config_arch = "x64";
try {
beforePackCursorSdk({
appDir: process.cwd(),
electronPlatformName: "win32",
ensureCursorSdkPlatformPackages: () => [],
buildWindowsHelloHelper: (projectDir) => calls.push(projectDir),
});
} finally {
if (originalArch === undefined) {
delete process.env.npm_config_arch;
} else {
process.env.npm_config_arch = originalArch;
}
}
assert.deepEqual(calls, [{ projectDir: process.cwd(), platform: "win32", arch: "x64" }]);
});
test("beforePackCursorSdk fails Windows packaging when Windows Hello helper build is skipped", () => {
assert.throws(
() => beforePackCursorSdk({
appDir: process.cwd(),
electronPlatformName: "win32",
ensureCursorSdkPlatformPackages: () => [],
buildWindowsHelloHelper: () => ({ skipped: true, reason: "compiler-unavailable" }),
}),
/Windows Hello helper was not built: compiler-unavailable/,
);
});
test("Windows packaging rebuilds patched node-pty from source for the target architecture", () => {
const calls = [];
const rebuilt = rebuildPatchedNodePty({
projectDir: "/workspace/netcatty",
platform: "win32",
arch: 3,
run: (...args) => calls.push(args),
exists: () => true,
logger: { log() {} },
});
assert.equal(rebuilt, true);
assert.equal(calls.length, 2);
assert.equal(calls[0][0], process.execPath);
assert.deepEqual(calls[0][1], [
path.join("/workspace/netcatty", "node_modules", "@electron", "rebuild", "lib", "cli.js"),
"--force",
"--build-from-source",
"--only",
"node-pty",
"--arch",
"arm64",
]);
assert.equal(calls[0][2].cwd, "/workspace/netcatty");
assert.equal(calls[1][0], process.execPath);
assert.equal(
calls[1][1][0],
path.join("/workspace/netcatty", "node_modules", "node-pty", "scripts", "post-install.js"),
);
assert.equal(calls[1][2].env.npm_config_arch, "arm64");
});
test("Windows packaging fails when rebuilt node-pty runtime files are incomplete", () => {
assert.throws(() => rebuildPatchedNodePty({
projectDir: "/workspace/netcatty",
platform: "win32",
arch: 1,
run() {},
exists: (filePath) => !filePath.endsWith("conpty.dll"),
logger: { log() {} },
}), /Patched node-pty artifacts missing: .*conpty\.dll/);
});
test("non-Windows packaging keeps the prebuilt node-pty path", () => {
const calls = [];
const rebuilt = rebuildPatchedNodePty({
projectDir: "/workspace/netcatty",
platform: "linux",
arch: 1,
run: (...args) => calls.push(args),
logger: { log() {} },
});
assert.equal(rebuilt, false);
assert.deepEqual(calls, []);
});
test("Windows afterPack copies rebuilt ConPTY files over packaged prebuilds", () => {
const copied = [];
const made = [];
const destinations = copyPatchedNodePtyToPackagedApp({
projectDir: "/workspace/netcatty",
resourcesDir: "/workspace/release/resources",
copy: (...args) => copied.push(args),
mkdir: (...args) => made.push(args),
});
assert.equal(copied.length, 3);
assert.equal(made.length, 3);
assert.equal(copied[0][0], path.join(
"/workspace/netcatty", "node_modules", "node-pty", "build", "Release", "conpty.node",
));
assert.equal(copied[0][1], path.join(
"/workspace/release/resources", "app.asar.unpacked", "node_modules", "node-pty", "build", "Release", "conpty.node",
));
assert.deepEqual(destinations, copied.map(([, destination]) => destination));
});
test("node-pty patch matches bundled ConPTY clear ABI and preserves the cursor row", () => {
const patch = fs.readFileSync(
path.join(__dirname, "..", "patches", "node-pty+1.1.0.patch"),
"utf8",
);
assert.match(patch, /ConptyClearPseudoConsole\(HPCON hPC, BOOL keepCursorRow\)/);
assert.match(patch, /PFNCLEARPSEUDOCONSOLE\)\(HPCON hpc, BOOL keepCursorRow\)/);
assert.match(patch, /pfnClearPseudoConsole\(handle->hpc, TRUE\)/);
assert.doesNotMatch(patch, /node_modules\/node-pty\/build\//);
});