mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
fix(desktop): restore packaged terminal hooks
The desktop daemon resolved the CLI through a packaged module entrypoint that is not an executable outside the archive. Publish the existing bundled shim as the daemon's authoritative CLI path so terminal hooks use a callable command.
This commit is contained in:
@@ -107,6 +107,6 @@ Codex also receives the Windows equivalent:
|
|||||||
if defined PASEO_TERMINAL_ID (if defined PASEO_HOOK_CLI ("%PASEO_HOOK_CLI%" hooks codex <event>) else (paseo hooks codex <event>))
|
if defined PASEO_TERMINAL_ID (if defined PASEO_HOOK_CLI ("%PASEO_HOOK_CLI%" hooks codex <event>) else (paseo hooks codex <event>))
|
||||||
```
|
```
|
||||||
|
|
||||||
Paseo injects `PASEO_HOOK_CLI` so Codex's hook shell cannot pick up a stale global `paseo` before the current one. The command still falls back to bare `paseo` if the env is missing, and it still no-ops outside Paseo terminals because the `PASEO_TERMINAL_ID` gate remains first. Paseo also prepends the CLI binary directory to each terminal `PATH` as a secondary fallback. All other behavior lives in `paseo hooks`: read the env, map the event, POST activity, and no-op/fail-open when anything is missing or unavailable.
|
The daemon resolves the current CLI through `PASEO_CLI` when its launcher supplies one, or through the npm package shim for standalone installs. Terminal setup exposes that resolved executable to hooks as `PASEO_HOOK_CLI`; desktop and other daemon launchers do not know about the hook-specific variable. The generated command falls back to bare `paseo` if the hook env is missing and no-ops outside Paseo terminals because the `PASEO_TERMINAL_ID` gate remains first. Paseo also prepends the resolved CLI directory to each terminal `PATH` as a secondary fallback. All other behavior lives in `paseo hooks`: read the env, map the event, POST activity, and no-op/fail-open when anything is missing or unavailable.
|
||||||
|
|
||||||
If config installation fails, daemon startup and terminal spawn continue without terminal activity hooks.
|
If config installation fails, daemon startup and terminal spawn continue without terminal activity hooks.
|
||||||
|
|||||||
@@ -46,4 +46,4 @@ CLI_ENTRYPOINT="${RESOURCES_DIR}/app.asar/node_modules/@getpaseo/cli/dist/index.
|
|||||||
|
|
||||||
# PASEO_DESKTOP_MANAGED marks daemons started through this bundled CLI as
|
# PASEO_DESKTOP_MANAGED marks daemons started through this bundled CLI as
|
||||||
# desktop-managed, so the desktop app restarts them when it upgrades.
|
# desktop-managed, so the desktop app restarts them when it upgrades.
|
||||||
exec env ELECTRON_RUN_AS_NODE=1 PASEO_NODE_ENV=production PASEO_DESKTOP_MANAGED=1 "${APP_EXECUTABLE}" --disable-warning=DEP0040 "${RUNNER_PATH}" node-script "${CLI_ENTRYPOINT}" "$@"
|
exec env ELECTRON_RUN_AS_NODE=1 PASEO_NODE_ENV=production PASEO_DESKTOP_MANAGED=1 PASEO_CLI="${SCRIPT_PATH}" "${APP_EXECUTABLE}" --disable-warning=DEP0040 "${RUNNER_PATH}" node-script "${CLI_ENTRYPOINT}" "$@"
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ set "PASEO_NODE_ENV=production"
|
|||||||
rem PASEO_DESKTOP_MANAGED marks daemons started through this bundled CLI as
|
rem PASEO_DESKTOP_MANAGED marks daemons started through this bundled CLI as
|
||||||
rem desktop-managed, so the desktop app restarts them when it upgrades.
|
rem desktop-managed, so the desktop app restarts them when it upgrades.
|
||||||
set "PASEO_DESKTOP_MANAGED=1"
|
set "PASEO_DESKTOP_MANAGED=1"
|
||||||
|
set "PASEO_CLI=%~f0"
|
||||||
"%APP_EXECUTABLE%" --disable-warning=DEP0040 "%RESOURCES_DIR%\app.asar.unpacked\dist\daemon\node-entrypoint-runner.js" node-script "%RESOURCES_DIR%\app.asar\node_modules\@getpaseo\cli\dist\index.js" %*
|
"%APP_EXECUTABLE%" --disable-warning=DEP0040 "%RESOURCES_DIR%\app.asar.unpacked\dist\daemon\node-entrypoint-runner.js" node-script "%RESOURCES_DIR%\app.asar\node_modules\@getpaseo\cli\dist\index.js" %*
|
||||||
exit /b %errorlevel%
|
exit /b %errorlevel%
|
||||||
|
|||||||
@@ -128,6 +128,14 @@ function shellQuoteCliArg(value) {
|
|||||||
return shellQuote(String(value));
|
return shellQuote(String(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTerminalHookSmokeCommand(marker) {
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
return `"%PASEO_HOOK_CLI%" hooks codex Stop && echo ${marker}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `"$PASEO_HOOK_CLI" hooks codex Stop && echo ${marker}`;
|
||||||
|
}
|
||||||
|
|
||||||
function getShellCommand(script) {
|
function getShellCommand(script) {
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
return {
|
return {
|
||||||
@@ -740,8 +748,8 @@ async function smokeCliTerminal({ appPath, env }) {
|
|||||||
await runCliShimJsonCommand({
|
await runCliShimJsonCommand({
|
||||||
appPath,
|
appPath,
|
||||||
env,
|
env,
|
||||||
args: ["terminal", "send-keys", terminalId, "echo", "Space", marker, "Enter"],
|
args: ["terminal", "send-keys", terminalId, getTerminalHookSmokeCommand(marker), "Enter"],
|
||||||
label: "Bundled CLI shim terminal send-keys",
|
label: "Bundled CLI shim terminal hook command",
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let attempt = 1; attempt <= TERMINAL_CAPTURE_ATTEMPTS; attempt += 1) {
|
for (let attempt = 1; attempt <= TERMINAL_CAPTURE_ATTEMPTS; attempt += 1) {
|
||||||
@@ -753,7 +761,7 @@ async function smokeCliTerminal({ appPath, env }) {
|
|||||||
});
|
});
|
||||||
const lines = Array.isArray(capture?.lines) ? capture.lines : [];
|
const lines = Array.isArray(capture?.lines) ? capture.lines : [];
|
||||||
if (lines.join("\n").includes(marker)) {
|
if (lines.join("\n").includes(marker)) {
|
||||||
console.log("Packaged desktop smoke: terminal command output captured");
|
console.log("Packaged desktop smoke: terminal hook command completed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import { DEFAULT_DESKTOP_SETTINGS } from "../settings/desktop-settings";
|
import { DEFAULT_DESKTOP_SETTINGS } from "../settings/desktop-settings";
|
||||||
|
import { getBundledCliShimPath } from "../integrations/cli-install";
|
||||||
import { createDaemonCommandHandlers } from "./daemon-manager";
|
import { createDaemonCommandHandlers } from "./daemon-manager";
|
||||||
|
|
||||||
const mocks = vi.hoisted(() => ({
|
const mocks = vi.hoisted(() => ({
|
||||||
@@ -451,7 +452,10 @@ describe("daemon-manager commands", () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: ["ignore", "ignore", "ignore"],
|
stdio: ["ignore", "ignore", "ignore"],
|
||||||
envOverlay: expect.objectContaining({ PASEO_WEB_UI_ENABLED: "false" }),
|
envOverlay: expect.objectContaining({
|
||||||
|
PASEO_CLI: getBundledCliShimPath(),
|
||||||
|
PASEO_WEB_UI_ENABLED: "false",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ import {
|
|||||||
type AppUpdateCheckIntent,
|
type AppUpdateCheckIntent,
|
||||||
type AppReleaseChannel,
|
type AppReleaseChannel,
|
||||||
} from "../features/auto-updater.js";
|
} from "../features/auto-updater.js";
|
||||||
import { getCliInstallStatus, installCli } from "../integrations/cli-install/index.js";
|
import {
|
||||||
|
getBundledCliShimPath,
|
||||||
|
getCliInstallStatus,
|
||||||
|
installCli,
|
||||||
|
} from "../integrations/cli-install/index.js";
|
||||||
import {
|
import {
|
||||||
getSkillsStatus,
|
getSkillsStatus,
|
||||||
installSkills,
|
installSkills,
|
||||||
@@ -413,7 +417,11 @@ async function startDaemon(): Promise<DesktopDaemonStatus> {
|
|||||||
detached: true,
|
detached: true,
|
||||||
envMode: "internal",
|
envMode: "internal",
|
||||||
env: invocation.env,
|
env: invocation.env,
|
||||||
envOverlay: { PASEO_DESKTOP_MANAGED: "1", PASEO_WEB_UI_ENABLED: "false" },
|
envOverlay: {
|
||||||
|
PASEO_DESKTOP_MANAGED: "1",
|
||||||
|
PASEO_CLI: getBundledCliShimPath(),
|
||||||
|
PASEO_WEB_UI_ENABLED: "false",
|
||||||
|
},
|
||||||
stdio: ["ignore", "ignore", "ignore"],
|
stdio: ["ignore", "ignore", "ignore"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ function createFakeMacBundle(options: { includeHelper: boolean }): {
|
|||||||
helperPath,
|
helperPath,
|
||||||
[
|
[
|
||||||
"#!/bin/sh",
|
"#!/bin/sh",
|
||||||
'printf "helper env=%s/%s\\n" "$ELECTRON_RUN_AS_NODE" "$PASEO_NODE_ENV"',
|
'printf "helper env=%s/%s cli=%s\\n" "$ELECTRON_RUN_AS_NODE" "$PASEO_NODE_ENV" "$PASEO_CLI"',
|
||||||
'printf "args=%s\\n" "$*"',
|
'printf "args=%s\\n" "$*"',
|
||||||
"",
|
"",
|
||||||
].join("\n"),
|
].join("\n"),
|
||||||
@@ -114,7 +114,7 @@ describe("desktop packaging", () => {
|
|||||||
const result = spawnSync(bundle.shimPath, ["--version"], { encoding: "utf8" });
|
const result = spawnSync(bundle.shimPath, ["--version"], { encoding: "utf8" });
|
||||||
|
|
||||||
expect(result.status).toBe(0);
|
expect(result.status).toBe(0);
|
||||||
expect(result.stdout).toContain("helper env=1/production");
|
expect(result.stdout).toContain(`helper env=1/production cli=${bundle.shimPath}`);
|
||||||
expect(result.stdout).toContain("node-entrypoint-runner.js");
|
expect(result.stdout).toContain("node-entrypoint-runner.js");
|
||||||
expect(result.stdout).toContain("node-script");
|
expect(result.stdout).toContain("node-script");
|
||||||
expect(result.stdout).toContain("@getpaseo/cli/dist/index.js");
|
expect(result.stdout).toContain("@getpaseo/cli/dist/index.js");
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export { getCliInstallStatus, installCli } from "./install.js";
|
export { getCliInstallStatus, installCli } from "./install.js";
|
||||||
|
export { getBundledCliShimPath } from "./paths.js";
|
||||||
|
|||||||
@@ -308,16 +308,16 @@ function resolveExternalProcessPath(filePath: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function resolvePaseoCliBinDir(): string | null {
|
export function resolvePaseoCliBinDir(): string | null {
|
||||||
const cliEntrypoint = resolvePaseoCliBinEntrypoint();
|
const cliExecutable = resolvePaseoCliExecutablePath();
|
||||||
if (!cliEntrypoint) {
|
return cliExecutable ? dirname(cliExecutable) : null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const externalCliEntrypoint = resolveExternalProcessPath(cliEntrypoint);
|
|
||||||
return findNpmBinDir(dirname(externalCliEntrypoint)) ?? dirname(externalCliEntrypoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolvePaseoCliExecutablePath(): string | null {
|
export function resolvePaseoCliExecutablePath(): string | null {
|
||||||
|
const configuredCli = process.env.PASEO_CLI?.trim();
|
||||||
|
if (configuredCli) {
|
||||||
|
return resolvePath(configuredCli);
|
||||||
|
}
|
||||||
|
|
||||||
const cliEntrypoint = resolvePaseoCliBinEntrypoint();
|
const cliEntrypoint = resolvePaseoCliBinEntrypoint();
|
||||||
if (!cliEntrypoint) {
|
if (!cliEntrypoint) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user