Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ jobs:
cache: npm
- run: npm ci
- run: npm audit --audit-level=high
- run: npm run build
- run: npm run typecheck
- run: npm test
- run: npm run build
- name: Parse JavaScript entry points
run: |
node --check apps/tray/session-host.mjs
Expand Down
4 changes: 2 additions & 2 deletions packages/beauticode-desktop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Windows-only aggregate package for the beautiCode desktop hosts. Requires Node.js 22 or newer.

The source workspace installs on Linux for CI validation. `npm run desktop:pack`
adds the Windows-only npm platform restriction to the distributable; running
The private source workspace installs on Linux for CI validation. `npm run desktop:pack`
creates the publishable distributable with the Windows-only npm platform restriction; running
Windows installation commands on another platform remains unsupported.

Codex MSIX safety notice: direct launching an executable inside WindowsApps
Expand Down
2 changes: 1 addition & 1 deletion packages/beauticode-desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "beauticode-desktop",
"version": "0.1.0-test.12",
"private": false,
"private": true,
"description": "beautiCode desktop host aggregate for DSH, Codex, WorkBuddy, Cursor, and Doubao.",
"type": "module",
"bin": {
Expand Down
3 changes: 3 additions & 0 deletions packages/beauticode-desktop/src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,9 @@ export function resolveRoute(host, command, options = {}) {
}

export function runHostCommand(host, command, options = {}) {
if ((command === "install" || command === "uninstall") && (options.platform || process.platform) !== "win32") {
throw new Error("Desktop host installation is only supported on Windows.");
}
const route = resolveRoute(host, command, options);
if (command === "health") throw new Error("Use the asynchronous runHostHealth API for health checks.");
if (route.readOnly) return getHostStatus(host, options);
Expand Down
2 changes: 1 addition & 1 deletion packages/beauticode-desktop/test/contract.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ test("desktop source workspace can be installed for cross-platform validation",
const manifest = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
assert.equal(manifest.name, "beauticode-desktop");
assert.equal(manifest.version, "0.1.0-test.12");
assert.equal(manifest.private, false);
assert.equal(manifest.private, true);
assert.equal(manifest.os, undefined);
assert.equal(manifest.bin["beauticode-desktop"], "./bin/beauticode-desktop.mjs");
assert.ok(manifest.files.includes("runtime"));
Expand Down
16 changes: 16 additions & 0 deletions packages/beauticode-desktop/test/route.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ test("status has no child-process route", () => {
test("install route is executable through an injected child-process seam", () => {
let call;
const result = runHostCommand("workbuddy", "install", {
platform: "win32",
runtimeRoot: "C:/package/runtime",
env: { TEST_ENV: "1" },
spawnSync(...args) {
Expand All @@ -49,3 +50,18 @@ test("install route is executable through an injected child-process seam", () =>
assert.deepEqual(call[1].slice(1), ["install"]);
assert.equal(call[2].env.BEAUTICODE_PACKAGED_RUNTIME, "1");
});

test("non-Windows install and uninstall reject before invoking a host script", () => {
for (const platform of ["linux", "darwin"]) {
for (const host of HOSTS) {
for (const command of ["install", "uninstall"]) {
let called = false;
assert.throws(() => runHostCommand(host, command, {
platform,
spawnSync() { called = true; return { status: 0 }; },
}), /only supported on Windows/);
assert.equal(called, false);
}
}
}
});
19 changes: 17 additions & 2 deletions packages/core/test/process-liveness.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import assert from "node:assert/strict";
import test from "node:test";
import childProcess from "node:child_process";
import { syncBuiltinESMExports } from "node:module";
import { isRecordedPidLive } from "../dist/process-liveness.js";

test("a live process may create its claim long after it starts", async () => {
Expand All @@ -8,7 +10,20 @@ test("a live process may create its claim long after it starts", async () => {
assert.equal(await isRecordedPidLive(process.pid, claimTime), true);
});

test("a claim from before this process started cannot identify this PID", async () => {
const oldClaim = new Date(Date.now() - Math.max(120_000, process.uptime() * 1_000 + 120_000)).toISOString();
test("a claim from before this process started cannot identify this PID", async (t) => {
const start = Date.now();
t.mock.method(childProcess, "execFile", (_command, _args, _options, callback) => callback(null, new Date(start).toISOString()));
// Refresh the source's named ESM import after mocking the builtin's CJS export.
// A real PowerShell probe can time out on CI and deliberately fail open.
syncBuiltinESMExports();
t.after(() => { t.mock.restoreAll(); syncBuiltinESMExports(); });
const oldClaim = new Date(start - 120_000).toISOString();
assert.equal(await isRecordedPidLive(process.pid, oldClaim), false);
});

test("a live process is retained when its platform start-time probe is unavailable", async (t) => {
t.mock.method(childProcess, "execFile", (_command, _args, _options, callback) => callback(new Error("probe unavailable"), ""));
syncBuiltinESMExports();
t.after(() => { t.mock.restoreAll(); syncBuiltinESMExports(); });
assert.equal(await isRecordedPidLive(process.pid, new Date(0).toISOString()), true);
});
1 change: 1 addition & 0 deletions scripts/pack-desktop-aggregate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export async function stageDesktopAggregate(destRoot = defaultStageDir(), opts =
await fsp.mkdir(destRoot, { recursive: true });
const manifest = JSON.parse(await fsp.readFile(path.join(sourceRoot, "package.json"), "utf8"));
// Source workspaces must install on Linux CI; only the distributable has a Windows-only runtime contract.
manifest.private = false;
manifest.os = ["win32"];
await fsp.writeFile(path.join(destRoot, "package.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
for (const name of ["README.md", "LICENSE"]) {
Expand Down
Loading