merge: integrate main into dev

Resolve 9 merge conflicts preserving both sides' intent:
- nix hash, bootstrap hostnames rename, websocket-server wiring
- session.ts handler dedup, snapshot fallback, worktree registration
- worktree-session git service + script/setup features
- sidebar-workspace-list setup navigation, session-context cleanup
- workspace-registry-bootstrap test kept (code still exists)
- checkout-git test additions from both sides

Post-merge fixes: isPaneFocused prop rename, server type rebuild.
This commit is contained in:
Mohamed Boudra
2026-04-15 16:07:39 +07:00
73 changed files with 2288 additions and 1126 deletions
+21 -4
View File
@@ -1,4 +1,4 @@
import { Command } from "commander";
import { Command, Option } from "commander";
import { createRequire } from "node:module";
import { createAgentCommand } from "./commands/agent/index.js";
import { createDaemonCommand } from "./commands/daemon/index.js";
@@ -124,10 +124,27 @@ export function createCli(): Command {
.option("--no-relay", "Disable relay on restarted daemon")
.option("--no-mcp", "Disable Agent MCP on restarted daemon")
.option(
"--allowed-hosts <hosts>",
'Comma-separated Host allowlist values (example: "localhost,.example.com" or "true")',
"--hostnames <hosts>",
'Daemon hostnames (comma-separated, e.g. "myhost,.example.com" or "true" for any)',
)
.action(withOutput(runDaemonRestartCommand));
.addOption(new Option("--allowed-hosts <hosts>").hideHelp())
.action(
withOutput((...args) => {
const [options, command] = args.slice(-2) as [(typeof args)[number], Command];
return runDaemonRestartCommand(
{
...options,
hostnames:
typeof options.hostnames === "string"
? options.hostnames
: typeof options.allowedHosts === "string"
? options.allowedHosts
: undefined,
},
command,
);
}),
);
// Advanced agent commands (less common operations)
program.addCommand(createAgentCommand());
+21 -4
View File
@@ -1,4 +1,4 @@
import { Command } from "commander";
import { Command, Option } from "commander";
import { startCommand } from "./start.js";
import { runStatusCommand } from "./status.js";
import { runStopCommand } from "./stop.js";
@@ -36,10 +36,27 @@ export function createDaemonCommand(): Command {
.option("--no-mcp", "Disable Agent MCP on restarted daemon")
.option("--no-inject-mcp", "Disable auto-injecting the Paseo MCP into created agents")
.option(
"--allowed-hosts <hosts>",
'Comma-separated Host allowlist values (example: "localhost,.example.com" or "true")',
"--hostnames <hosts>",
'Daemon hostnames (comma-separated, e.g. "myhost,.example.com" or "true" for any)',
)
.action(withOutput(runRestartCommand));
.addOption(new Option("--allowed-hosts <hosts>").hideHelp())
.action(
withOutput((...args) => {
const [options, command] = args.slice(-2) as [(typeof args)[number], Command];
return runRestartCommand(
{
...options,
hostnames:
typeof options.hostnames === "string"
? options.hostnames
: typeof options.allowedHosts === "string"
? options.allowedHosts
: undefined,
},
command,
);
}),
);
return daemon;
}
@@ -13,7 +13,7 @@ export interface DaemonStartOptions {
relay?: boolean;
mcp?: boolean;
injectMcp?: boolean;
allowedHosts?: string;
hostnames?: string;
}
export interface LocalDaemonPidInfo {
@@ -113,8 +113,8 @@ function buildChildEnv(options: DaemonStartOptions): NodeJS.ProcessEnv {
} else if (options.port) {
childEnv.PASEO_LISTEN = `127.0.0.1:${options.port}`;
}
if (options.allowedHosts) {
childEnv.PASEO_ALLOWED_HOSTS = options.allowedHosts;
if (options.hostnames) {
childEnv.PASEO_HOSTNAMES = options.hostnames;
}
return childEnv;
}
@@ -322,6 +322,7 @@ export function resolveLocalDaemonState(options: { home?: string } = {}): LocalD
...envWithHome(options.home),
// Status should reflect local persisted config + pid file, not inherited daemon env overrides.
PASEO_LISTEN: undefined,
PASEO_HOSTNAMES: undefined,
PASEO_ALLOWED_HOSTS: undefined,
};
const home = resolvePaseoHome(env);
+1 -1
View File
@@ -61,7 +61,7 @@ function toStartOptions(options: CommandOptions): DaemonStartOptions {
relay: typeof options.relay === "boolean" ? options.relay : undefined,
mcp: typeof options.mcp === "boolean" ? options.mcp : undefined,
injectMcp: typeof options.injectMcp === "boolean" ? options.injectMcp : undefined,
allowedHosts: typeof options.allowedHosts === "string" ? options.allowedHosts : undefined,
hostnames: typeof options.hostnames === "string" ? options.hostnames : undefined,
};
if (startOptions.listen && startOptions.port) {
+13 -5
View File
@@ -1,4 +1,4 @@
import { Command } from "commander";
import { Command, Option } from "commander";
import chalk from "chalk";
import {
startLocalDaemonForeground,
@@ -9,6 +9,10 @@ import { getErrorMessage } from "../../utils/errors.js";
export type { DaemonStartOptions as StartOptions } from "./local-daemon.js";
type RawStartCommandOptions = StartOptions & {
allowedHosts?: string;
};
export function startCommand(): Command {
return new Command("start")
.description("Start the local Paseo daemon")
@@ -20,11 +24,15 @@ export function startCommand(): Command {
.option("--no-mcp", "Disable the Agent MCP HTTP endpoint")
.option("--no-inject-mcp", "Disable auto-injecting the Paseo MCP into created agents")
.option(
"--allowed-hosts <hosts>",
'Comma-separated Host allowlist values (example: "localhost,.example.com" or "true")',
"--hostnames <hosts>",
'Daemon hostnames (comma-separated, e.g. "myhost,.example.com" or "true" for any)',
)
.action(async (options: StartOptions) => {
await runStart(options);
.addOption(new Option("--allowed-hosts <hosts>").hideHelp())
.action(async (options: RawStartCommandOptions) => {
await runStart({
...options,
hostnames: options.hostnames ?? options.allowedHosts,
});
});
}
+17 -9
View File
@@ -1,5 +1,5 @@
import { cancel, confirm, intro, isCancel, log, note, outro, spinner } from "@clack/prompts";
import { Command } from "commander";
import { Command, Option } from "commander";
import { writeFileSync } from "node:fs";
import path from "node:path";
import {
@@ -24,6 +24,10 @@ interface OnboardOptions extends DaemonStartOptions {
voice?: "ask" | "enable" | "disable";
}
type RawOnboardOptions = OnboardOptions & {
allowedHosts?: string;
};
type OnboardPersistedConfig = PersistedConfig & {
features?: PersistedConfig["features"] & {
dictation?: PersistedConfig["features"] extends { dictation?: infer T }
@@ -64,7 +68,7 @@ function parseTimeoutMs(raw: string | undefined): number {
return Math.ceil(seconds * 1000);
}
function toCliOverrides(options: DaemonStartOptions): CliConfigOverrides {
function toCliOverrides(options: OnboardOptions): CliConfigOverrides {
const cliOverrides: CliConfigOverrides = {};
if (options.listen) {
@@ -77,9 +81,9 @@ function toCliOverrides(options: DaemonStartOptions): CliConfigOverrides {
cliOverrides.relayEnabled = false;
}
if (options.allowedHosts) {
const raw = options.allowedHosts.trim();
cliOverrides.allowedHosts =
if (options.hostnames) {
const raw = options.hostnames.trim();
cliOverrides.hostnames =
raw.toLowerCase() === "true"
? true
: raw
@@ -297,13 +301,17 @@ export function onboardCommand(): Command {
.option("--no-relay", "Disable relay connection")
.option("--no-mcp", "Disable the Agent MCP HTTP endpoint")
.option(
"--allowed-hosts <hosts>",
'Comma-separated Host allowlist values (example: "localhost,.example.com" or "true")',
"--hostnames <hosts>",
'Daemon hostnames (comma-separated, e.g. "myhost,.example.com" or "true" for any)',
)
.addOption(new Option("--allowed-hosts <hosts>").hideHelp())
.option("--timeout <seconds>", "Max time to wait for daemon readiness (default: 600)")
.option("--voice <mode>", "Voice setup mode: ask, enable, disable", "ask")
.action(async (options: OnboardOptions) => {
await runOnboard(options);
.action(async (options: RawOnboardOptions) => {
await runOnboard({
...options,
hostnames: options.hostnames ?? options.allowedHosts,
});
});
}