@getpaseo/server 0.1.101 → 0.1.102
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +8 -0
- package/dist/scripts/supervisor.js +26 -8
- package/dist/server/server/agent/activity-curator.d.ts +17 -0
- package/dist/server/server/agent/activity-curator.js +101 -24
- package/dist/server/server/agent/agent-manager.js +5 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +7 -2
- package/dist/server/server/agent/provider-registry.js +12 -11
- package/dist/server/server/agent/provider-snapshot-manager.d.ts +8 -1
- package/dist/server/server/agent/provider-snapshot-manager.js +78 -33
- package/dist/server/server/agent/providers/acp-agent.d.ts +13 -0
- package/dist/server/server/agent/providers/acp-agent.js +37 -1
- package/dist/server/server/agent/providers/claude/agent.js +51 -14
- package/dist/server/server/agent/providers/claude/query.d.ts +3 -0
- package/dist/server/server/agent/providers/claude/query.js +4 -2
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +2 -1
- package/dist/server/server/agent/providers/generic-acp-agent.js +2 -1
- package/dist/server/server/agent/providers/kiro-acp-agent.d.ts +17 -0
- package/dist/server/server/agent/providers/kiro-acp-agent.js +78 -0
- package/dist/server/server/agent/providers/mock-load-test-agent.js +8 -0
- package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/paths.js +7 -0
- package/dist/server/server/agent/providers/opencode/server-manager.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/server-manager.js +34 -5
- package/dist/server/server/agent/providers/opencode-agent.d.ts +4 -0
- package/dist/server/server/agent/providers/opencode-agent.js +14 -2
- package/dist/server/server/agent/providers/pi/agent.d.ts +3 -0
- package/dist/server/server/agent/providers/pi/agent.js +9 -3
- package/dist/server/server/agent/providers/provider-image-output.js +11 -6
- package/dist/server/server/agent/tools/paseo-tools.d.ts +1 -1
- package/dist/server/server/agent/tools/paseo-tools.js +0 -2
- package/dist/server/server/bootstrap.d.ts +7 -1
- package/dist/server/server/bootstrap.js +18 -0
- package/dist/server/server/config.d.ts +2 -0
- package/dist/server/server/config.js +57 -1
- package/dist/server/server/daemon-worker.js +19 -7
- package/dist/server/server/lifecycle-reasons.d.ts +4 -0
- package/dist/server/server/lifecycle-reasons.js +6 -0
- package/dist/server/server/persisted-config.d.ts +13 -2
- package/dist/server/server/persisted-config.js +30 -11
- package/dist/server/server/process-diagnostics.d.ts +17 -0
- package/dist/server/server/process-diagnostics.js +22 -0
- package/dist/server/server/relay-transport.js +1 -0
- package/dist/server/server/resolve-worktree-creation-intent.js +3 -1
- package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +32 -0
- package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +88 -0
- package/dist/server/server/session/daemon/daemon-self-updater.d.ts +32 -0
- package/dist/server/server/session/daemon/daemon-self-updater.js +56 -0
- package/dist/server/server/session/daemon/daemon-session.d.ts +12 -0
- package/dist/server/server/session/daemon/daemon-session.js +12 -0
- package/dist/server/server/session/daemon/diagnostics.js +10 -0
- package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
- package/dist/server/server/session/daemon/install-origin.js +64 -0
- package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
- package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
- package/dist/server/server/session/provider/provider-catalog-session.js +8 -4
- package/dist/server/server/session.d.ts +5 -3
- package/dist/server/server/session.js +74 -32
- package/dist/server/server/speech/providers/openai/config.d.ts +0 -2
- package/dist/server/server/speech/providers/openai/config.js +71 -34
- package/dist/server/server/speech/providers/openai/runtime.js +4 -4
- package/dist/server/server/web-ui.d.ts +10 -0
- package/dist/server/server/web-ui.js +205 -0
- package/dist/server/server/websocket/runtime-metrics.d.ts +3 -0
- package/dist/server/server/websocket-server.d.ts +3 -0
- package/dist/server/server/websocket-server.js +190 -32
- package/dist/server/services/quota-fetcher/manifest.js +5 -0
- package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
- package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
- package/dist/server/terminal/agent-hooks/agent-hook-installer.js +2 -2
- package/dist/server/utils/checkout-git.js +156 -3
- package/dist/server/utils/directory-suggestions.js +1 -4
- package/dist/server/utils/path.d.ts +2 -0
- package/dist/server/utils/path.js +13 -0
- package/dist/server/utils/worktree.d.ts +1 -0
- package/dist/server/utils/worktree.js +92 -11
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5fa9347afb28c7d61bbf73684f3bdafa.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5fa9347afb28c7d61bbf73684f3bdafa.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-5fa9347afb28c7d61bbf73684f3bdafa.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-35159ed50cf218b741c5dab5a6f4a889.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-35159ed50cf218b741c5dab5a6f4a889.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-35159ed50cf218b741c5dab5a6f4a889.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-cf63ba3f4de4164d2d9c3738e1b791b2.js +16157 -0
- package/dist/server/web-ui/_expo/static/js/web/index-cf63ba3f4de4164d2d9c3738e1b791b2.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-cf63ba3f4de4164d2d9c3738e1b791b2.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-6a6cfdd9f06d4fd2b05adc1a8771c58c.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-6a6cfdd9f06d4fd2b05adc1a8771c58c.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-6a6cfdd9f06d4fd2b05adc1a8771c58c.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b31888f9a7de4f0c52d6a58fcddbcb20.js +3 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b31888f9a7de4f0c52d6a58fcddbcb20.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b31888f9a7de4f0c52d6a58fcddbcb20.js.gz +0 -0
- package/dist/server/web-ui/apple-touch-icon.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/antigravity.6e91a685c33435e0b466a56db86cf141.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/cursor.c31d6bce4fe9aadc3fe59962f4c4fcf3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/file-explorer.3e15e8f72c825c85ce336bcb0cdef776.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/finder.7f68fc2c475621a672e1be09309d5567.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/vscode.832bdb4c685d930f1c864c793703600b.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/webstorm.aa5dc2cd8c20cc0a155c4c5c5ab3c5f5.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/zed.f3a670b7f9aa226da4fe53fb86f1abbd.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
- package/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
- package/dist/server/web-ui/favicon.ico +0 -0
- package/dist/server/web-ui/index.html +90 -0
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/dist/server/web-ui/manifest.json +27 -0
- package/dist/server/web-ui/manifest.json.br +0 -0
- package/dist/server/web-ui/manifest.json.gz +0 -0
- package/dist/server/web-ui/metadata.json +1 -0
- package/dist/server/web-ui/metadata.json.br +1 -0
- package/dist/server/web-ui/metadata.json.gz +0 -0
- package/dist/server/web-ui/pwa-icon-192.png +0 -0
- package/dist/server/web-ui/pwa-icon-512.png +0 -0
- package/dist/server/web-ui/robots.txt +2 -0
- package/dist/src/server/persisted-config.js +30 -11
- package/package.json +7 -7
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createOpencodeClient, } from "@opencode-ai/sdk/v2/client";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
2
3
|
import { createPathEquivalenceMatcher } from "../../../utils/path.js";
|
|
3
4
|
import pLimit from "p-limit";
|
|
4
5
|
import { z } from "zod";
|
|
@@ -11,6 +12,7 @@ import { execCommand } from "../../../utils/spawn.js";
|
|
|
11
12
|
import { buildToolCallDisplayModel } from "@getpaseo/protocol/tool-call-display";
|
|
12
13
|
import { mapOpencodeToolCall } from "./opencode/tool-call-mapper.js";
|
|
13
14
|
import { OpenCodeServerManager, } from "./opencode/server-manager.js";
|
|
15
|
+
import { resolveOpenCodeHomeDir } from "./opencode/paths.js";
|
|
14
16
|
import { formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
|
|
15
17
|
import { runProviderTurn } from "./provider-runner.js";
|
|
16
18
|
import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
|
|
@@ -847,6 +849,7 @@ export const __openCodeInternals = {
|
|
|
847
849
|
resolveOpenCodeSelectedModelContextWindow,
|
|
848
850
|
isSelectableOpenCodeAgent,
|
|
849
851
|
mapOpenCodeAgentToMode,
|
|
852
|
+
resolveOpenCodeHomeDir,
|
|
850
853
|
get OpenCodeAgentSession() {
|
|
851
854
|
return OpenCodeAgentSession;
|
|
852
855
|
},
|
|
@@ -867,8 +870,10 @@ export class OpenCodeAgentClient {
|
|
|
867
870
|
deps.serverManager ??
|
|
868
871
|
OpenCodeServerManager.getInstance(this.logger, runtimeSettings, {
|
|
869
872
|
managedProcesses: deps.managedProcesses,
|
|
873
|
+
resolveHomeDir: deps.resolveHomeDir,
|
|
870
874
|
});
|
|
871
875
|
this.createOpenCodeClient = deps.createClient ?? createSdkOpenCodeClient;
|
|
876
|
+
this.resolveHomeDir = deps.resolveHomeDir ?? resolveOpenCodeHomeDir;
|
|
872
877
|
}
|
|
873
878
|
async createSession(config, launchContext, options) {
|
|
874
879
|
const openCodeConfig = this.assertConfig(config);
|
|
@@ -930,9 +935,16 @@ export class OpenCodeAgentClient {
|
|
|
930
935
|
? await this.serverManager.acquireNew()
|
|
931
936
|
: await this.serverManager.acquireCurrent();
|
|
932
937
|
const { url } = acquisition.server;
|
|
933
|
-
const
|
|
934
|
-
const client = this.createOpenCodeClient({ baseUrl: url, directory });
|
|
938
|
+
const isGlobalCatalog = options.scope === "global";
|
|
935
939
|
try {
|
|
940
|
+
// OpenCode treats the catalog directory as a workspace. The global catalog
|
|
941
|
+
// is not a project, so use the neutral OpenCode home instead of user home.
|
|
942
|
+
const directory = isGlobalCatalog ? this.resolveHomeDir() : options.cwd;
|
|
943
|
+
if (isGlobalCatalog) {
|
|
944
|
+
await fs.mkdir(directory, { recursive: true });
|
|
945
|
+
this.logger.debug({ directory }, "opencode catalog refresh: using opencode-home for global provider catalog");
|
|
946
|
+
}
|
|
947
|
+
const client = this.createOpenCodeClient({ baseUrl: url, directory });
|
|
936
948
|
const [models, modes] = await Promise.all([
|
|
937
949
|
this.fetchModelsFromClient(client, directory),
|
|
938
950
|
this.fetchModesFromClient(client, directory),
|
|
@@ -6,6 +6,7 @@ import type { PiRuntime, PiRuntimeSession } from "./runtime.js";
|
|
|
6
6
|
import type { PiCommandsRpcType, PiSessionState } from "./rpc-types.js";
|
|
7
7
|
export declare const PiProviderParamsSchema: z.ZodObject<{
|
|
8
8
|
sessionDir: z.ZodOptional<z.ZodString>;
|
|
9
|
+
extensionTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
9
10
|
}, z.core.$strict>;
|
|
10
11
|
interface PiRpcAgentClientOptions {
|
|
11
12
|
logger: Logger;
|
|
@@ -23,6 +24,7 @@ interface PiRpcAgentSessionOptions {
|
|
|
23
24
|
initialState: PiSessionState;
|
|
24
25
|
capabilities: AgentCapabilityFlags;
|
|
25
26
|
cleanup?: () => void;
|
|
27
|
+
extensionTimeoutMs?: number;
|
|
26
28
|
}
|
|
27
29
|
export declare function transformPiModels(models: AgentModelDefinition[]): AgentModelDefinition[];
|
|
28
30
|
export declare class PiRpcAgentSession implements AgentSession {
|
|
@@ -50,6 +52,7 @@ export declare class PiRpcAgentSession implements AgentSession {
|
|
|
50
52
|
private readonly runtimeSession;
|
|
51
53
|
private readonly config;
|
|
52
54
|
private readonly cleanup?;
|
|
55
|
+
private readonly extensionTimeoutMs;
|
|
53
56
|
get id(): string | null;
|
|
54
57
|
run(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<AgentRunResult>;
|
|
55
58
|
startTurn(prompt: AgentPromptInput, _options?: AgentRunOptions): Promise<StartTurnResult>;
|
|
@@ -22,7 +22,7 @@ const PASEO_PI_TREE_EXTENSION_COMMAND = "paseo_tree";
|
|
|
22
22
|
const PASEO_PI_CAPTURE_EXTENSION_COMMAND = "paseo_capture_entries";
|
|
23
23
|
const PASEO_PI_ENTRY_CAPTURE_MARKER = "PASEO_ENTRY_CAPTURE";
|
|
24
24
|
const PASEO_PI_COMMAND_RESULT_MARKER = "PASEO_COMMAND_RESULT";
|
|
25
|
-
const
|
|
25
|
+
const DEFAULT_PI_EXTENSION_RESULT_TIMEOUT_MS = 30000;
|
|
26
26
|
const QUESTION_RESPONSE_HEADER = "Response";
|
|
27
27
|
const QUESTION_COMMENT_HEADER = "Comment";
|
|
28
28
|
const PI_ASK_USER_FREEFORM_SENTINEL = "✏️ Type custom response...";
|
|
@@ -30,6 +30,7 @@ const COMBINED_ASK_USER_METADATA = "ask_user_select_optional_comment";
|
|
|
30
30
|
export const PiProviderParamsSchema = z
|
|
31
31
|
.object({
|
|
32
32
|
sessionDir: z.string().min(1).optional(),
|
|
33
|
+
extensionTimeoutMs: z.number().int().positive().default(DEFAULT_PI_EXTENSION_RESULT_TIMEOUT_MS),
|
|
33
34
|
})
|
|
34
35
|
.strict();
|
|
35
36
|
const PI_HANDLED_BUILTIN_SLASH_COMMANDS = [
|
|
@@ -715,6 +716,7 @@ export class PiRpcAgentSession {
|
|
|
715
716
|
normalizePiThinkingOption(options.config.thinkingOptionId) ??
|
|
716
717
|
this.state.thinkingLevel ??
|
|
717
718
|
null;
|
|
719
|
+
this.extensionTimeoutMs = options.extensionTimeoutMs ?? DEFAULT_PI_EXTENSION_RESULT_TIMEOUT_MS;
|
|
718
720
|
this.runtimeSession.onEvent((event) => {
|
|
719
721
|
this.handleRuntimeEvent(event);
|
|
720
722
|
});
|
|
@@ -1065,7 +1067,7 @@ export class PiRpcAgentSession {
|
|
|
1065
1067
|
const timer = setTimeout(() => {
|
|
1066
1068
|
this.pendingExtensionResults.delete(requestId);
|
|
1067
1069
|
reject(new Error(`Pi extension result timed out for request ${requestId}`));
|
|
1068
|
-
},
|
|
1070
|
+
}, this.extensionTimeoutMs);
|
|
1069
1071
|
this.pendingExtensionResults.set(requestId, { resolve, reject, timer });
|
|
1070
1072
|
});
|
|
1071
1073
|
}
|
|
@@ -1489,6 +1491,7 @@ export class PiRpcAgentClient {
|
|
|
1489
1491
|
initialState: await runtimeSession.getState(),
|
|
1490
1492
|
capabilities: withPiMcpCapability(mcpConfig !== null),
|
|
1491
1493
|
cleanup: combineCleanup([mcpConfig?.cleanup, paseoExtension.cleanup]),
|
|
1494
|
+
extensionTimeoutMs: this.providerParams.extensionTimeoutMs,
|
|
1492
1495
|
});
|
|
1493
1496
|
}
|
|
1494
1497
|
catch (error) {
|
|
@@ -1531,6 +1534,7 @@ export class PiRpcAgentClient {
|
|
|
1531
1534
|
initialState: await runtimeSession.getState(),
|
|
1532
1535
|
capabilities: withPiMcpCapability(mcpConfig !== null),
|
|
1533
1536
|
cleanup: combineCleanup([mcpConfig?.cleanup, paseoExtension.cleanup]),
|
|
1537
|
+
extensionTimeoutMs: this.providerParams.extensionTimeoutMs,
|
|
1534
1538
|
});
|
|
1535
1539
|
}
|
|
1536
1540
|
catch (error) {
|
|
@@ -1541,7 +1545,9 @@ export class PiRpcAgentClient {
|
|
|
1541
1545
|
}
|
|
1542
1546
|
}
|
|
1543
1547
|
async fetchCatalog(options) {
|
|
1544
|
-
const runtimeSession = await this.runtime.startSession({
|
|
1548
|
+
const runtimeSession = await this.runtime.startSession({
|
|
1549
|
+
cwd: options.scope === "global" ? homedir() : options.cwd,
|
|
1550
|
+
});
|
|
1545
1551
|
try {
|
|
1546
1552
|
const models = transformPiModels((await runtimeSession.getAvailableModels(PI_CATALOG_REQUEST_TIMEOUT_MS)).map(mapPiModel));
|
|
1547
1553
|
return { models, modes: [] };
|
|
@@ -44,11 +44,10 @@ export function materializeProviderImage(image) {
|
|
|
44
44
|
fsSync.writeFileSync(filePath, bytes);
|
|
45
45
|
return { path: filePath };
|
|
46
46
|
}
|
|
47
|
-
// Recognizes
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// because on Windows the path uses "\\" and escapeMarkdownImageSource doubles each backslash.
|
|
47
|
+
// Recognizes markdown rendered for a materialized provider image: its source is a content-hashed
|
|
48
|
+
// file in the attachments dir. Matching the full <hash>.<ext> shape (not just a leading "![")
|
|
49
|
+
// keeps user-authored text from being mistaken for a provider image during history replay. The
|
|
50
|
+
// separator still accepts old doubled-backslash Windows history; new Windows output uses file URIs.
|
|
52
51
|
const PROVIDER_IMAGE_MARKDOWN = new RegExp(`^!\\[[^\\]]*\\]\\([^)]*${PROVIDER_IMAGE_ATTACHMENT_DIR}[/\\\\]+[0-9a-f]{64}\\.[a-z0-9]+\\)`);
|
|
53
52
|
export function isProviderImageMarkdown(text) {
|
|
54
53
|
return PROVIDER_IMAGE_MARKDOWN.test(text);
|
|
@@ -63,8 +62,14 @@ function isDataImageSource(source) {
|
|
|
63
62
|
function escapeMarkdownImageAlt(value) {
|
|
64
63
|
return value.replace(/\\/g, "\\\\").replace(/\]/g, "\\]");
|
|
65
64
|
}
|
|
65
|
+
function markdownImageSource(value) {
|
|
66
|
+
if (/^[A-Za-z]:[\\/]/.test(value)) {
|
|
67
|
+
return `file:///${value.replace(/\\/g, "/")}`;
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
66
71
|
function escapeMarkdownImageSource(value) {
|
|
67
|
-
return value.replace(/\\/g, "\\\\").replace(/\)/g, "\\)");
|
|
72
|
+
return markdownImageSource(value).replace(/\\/g, "\\\\").replace(/\)/g, "\\)");
|
|
68
73
|
}
|
|
69
74
|
export function renderProviderImageOutputAsAssistantMarkdown(image, options = {}) {
|
|
70
75
|
const source = nonEmptyString(image.path) ?? nonEmptyString(image.url);
|
|
@@ -6,7 +6,7 @@ import type { VoiceCallerContext, VoiceSpeakHandler } from "../../voice-types.js
|
|
|
6
6
|
import type { TerminalManager } from "../../../terminal/terminal-manager.js";
|
|
7
7
|
import type { CreatePaseoWorktreeWorkflowFn } from "../../worktree-session.js";
|
|
8
8
|
import type { ScheduleService } from "../../schedule/service.js";
|
|
9
|
-
import {
|
|
9
|
+
import type { ProviderSnapshotManager } from "../provider-snapshot-manager.js";
|
|
10
10
|
import type { GitHubService } from "../../../services/github-service.js";
|
|
11
11
|
import type { WorkspaceGitService } from "../../workspace-git-service.js";
|
|
12
12
|
import type { PaseoToolCatalog } from "./types.js";
|
|
@@ -11,7 +11,6 @@ import { WaitForAgentTracker } from "../wait-for-agent-tracker.js";
|
|
|
11
11
|
import { createAgentCommand } from "../create-agent/create.js";
|
|
12
12
|
import { expandUserPath, isSameOrDescendantPath, resolvePathFromBase } from "../../path-utils.js";
|
|
13
13
|
import { ScheduleRunSchema, ScheduleSummarySchema, StoredScheduleSchema, } from "@getpaseo/protocol/schedule/types";
|
|
14
|
-
import { resolveSnapshotCwd } from "../provider-snapshot-manager.js";
|
|
15
14
|
import { AgentModelSchema, AgentProviderEnum, AgentStatusEnum, ProviderModeSchema, ProviderSummarySchema, parseDurationString, resolveRequiredProviderModel, sanitizePermissionRequest, serializeSnapshotWithMetadata, toScheduleSummary, waitForAgentWithTimeout, } from "../mcp-shared.js";
|
|
16
15
|
import { sendPromptToAgent, setupFinishNotification } from "../agent-prompt.js";
|
|
17
16
|
import { respondToAgentPermission } from "../permission-response.js";
|
|
@@ -1760,7 +1759,6 @@ export function createPaseoToolCatalog(options) {
|
|
|
1760
1759
|
},
|
|
1761
1760
|
}, async ({ provider }) => {
|
|
1762
1761
|
const models = await providerSnapshotManager.listModels({
|
|
1763
|
-
cwd: resolveSnapshotCwd(),
|
|
1764
1762
|
provider,
|
|
1765
1763
|
wait: true,
|
|
1766
1764
|
});
|
|
@@ -44,11 +44,12 @@ export type DaemonLifecycleIntent = {
|
|
|
44
44
|
type: "shutdown";
|
|
45
45
|
clientId: string;
|
|
46
46
|
requestId: string;
|
|
47
|
+
reason: string;
|
|
47
48
|
} | {
|
|
48
49
|
type: "restart";
|
|
49
50
|
clientId: string;
|
|
50
51
|
requestId: string;
|
|
51
|
-
reason
|
|
52
|
+
reason: string;
|
|
52
53
|
};
|
|
53
54
|
export interface PaseoDaemonConfig {
|
|
54
55
|
listen: string;
|
|
@@ -57,6 +58,7 @@ export interface PaseoDaemonConfig {
|
|
|
57
58
|
corsAllowedOrigins: string[];
|
|
58
59
|
allowedHosts?: HostnamesConfig;
|
|
59
60
|
hostnames?: HostnamesConfig;
|
|
61
|
+
trustedProxies?: true | string[];
|
|
60
62
|
mcpEnabled?: boolean;
|
|
61
63
|
mcpInjectIntoAgents?: boolean;
|
|
62
64
|
autoArchiveAfterMerge?: boolean;
|
|
@@ -77,6 +79,10 @@ export interface PaseoDaemonConfig {
|
|
|
77
79
|
publicBaseUrl: string | null;
|
|
78
80
|
standaloneListen: string | null;
|
|
79
81
|
};
|
|
82
|
+
webUi?: {
|
|
83
|
+
enabled: boolean;
|
|
84
|
+
distDir: string | null;
|
|
85
|
+
};
|
|
80
86
|
appBaseUrl?: string;
|
|
81
87
|
auth?: DaemonAuthConfig;
|
|
82
88
|
openai?: PaseoOpenAIConfig;
|
|
@@ -113,6 +113,7 @@ import { createManagedProcessRegistry, createSystemManagedProcessTable, } from "
|
|
|
113
113
|
import { terminateWithTreeKill } from "../utils/tree-kill.js";
|
|
114
114
|
import { isHostnameAllowed } from "./hostnames.js";
|
|
115
115
|
import { createRequireBearerMiddleware, isAgentMcpRequestAuthorized, } from "./auth.js";
|
|
116
|
+
import { createWebUiMiddleware } from "./web-ui.js";
|
|
116
117
|
const MAX_MCP_DEBUG_BATCH_ITEMS = 10;
|
|
117
118
|
const REDACTED_LOG_VALUE = "[redacted]";
|
|
118
119
|
const DOWNLOAD_OPEN_FLAGS = process.platform === "win32" ? constants.O_RDONLY : constants.O_RDONLY | constants.O_NOFOLLOW;
|
|
@@ -230,6 +231,17 @@ async function reconcileManagedProcessLedger(managedProcesses, logger) {
|
|
|
230
231
|
logger.info(reapResult, "Managed helper process ledger reconciled");
|
|
231
232
|
}
|
|
232
233
|
}
|
|
234
|
+
function mountWebUi(app, config, logger) {
|
|
235
|
+
app.use(createWebUiMiddleware({
|
|
236
|
+
enabled: config.webUi?.enabled ?? false,
|
|
237
|
+
distDir: config.webUi?.distDir ?? null,
|
|
238
|
+
label: getHostname(),
|
|
239
|
+
logger,
|
|
240
|
+
}));
|
|
241
|
+
}
|
|
242
|
+
function resolveExpressTrustProxySetting(config) {
|
|
243
|
+
return config.trustedProxies ?? ["loopback"];
|
|
244
|
+
}
|
|
233
245
|
export async function createPaseoDaemon(config, rootLogger) {
|
|
234
246
|
const logger = rootLogger.child({ module: "bootstrap" });
|
|
235
247
|
const bootstrapStart = performance.now();
|
|
@@ -279,6 +291,7 @@ export async function createPaseoDaemon(config, rootLogger) {
|
|
|
279
291
|
const agentMcpAuthToken = randomUUID();
|
|
280
292
|
const listenTarget = parseListenString(config.listen);
|
|
281
293
|
const app = express();
|
|
294
|
+
app.set("trust proxy", resolveExpressTrustProxySetting(config));
|
|
282
295
|
let boundListenTarget = null;
|
|
283
296
|
let workspaceRegistry = null;
|
|
284
297
|
const terminalManager = createConfiguredTerminalManager({
|
|
@@ -363,6 +376,11 @@ export async function createPaseoDaemon(config, rootLogger) {
|
|
|
363
376
|
});
|
|
364
377
|
// Local, harmless, and token-gated; deliberately skips daemon auth.
|
|
365
378
|
app.post("/api/terminal-activity", express.json(), createTerminalActivityRouteHandler(terminalManager));
|
|
379
|
+
// Serve the bundled browser web UI when enabled. Mounted after service-proxy
|
|
380
|
+
// classification and host/CORS handling, but before daemon bearer auth, so
|
|
381
|
+
// static app files load without the daemon password while API/WebSocket calls
|
|
382
|
+
// remain protected.
|
|
383
|
+
mountWebUi(app, config, logger);
|
|
366
384
|
app.use(createRequireBearerMiddleware(config.auth, (context) => {
|
|
367
385
|
logger.warn(context, "Rejected HTTP request with invalid daemon password");
|
|
368
386
|
}));
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { PaseoDaemonConfig } from "./bootstrap.js";
|
|
2
2
|
import { type HostnamesConfig } from "./hostnames.js";
|
|
3
|
+
export declare function resolveBundledWebUiDistDir(moduleUrl?: string | URL): string;
|
|
3
4
|
export type CliConfigOverrides = Partial<{
|
|
4
5
|
listen: string;
|
|
5
6
|
relayEnabled: boolean;
|
|
6
7
|
relayUseTls: boolean;
|
|
7
8
|
mcpEnabled: boolean;
|
|
8
9
|
mcpInjectIntoAgents: boolean;
|
|
10
|
+
webUiEnabled: boolean;
|
|
9
11
|
hostnames: HostnamesConfig;
|
|
10
12
|
}>;
|
|
11
13
|
export declare function loadConfig(paseoHome: string, options?: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
2
3
|
import { resolvePaseoNodeEnv } from "./paseo-env.js";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
import { expandTilde } from "../utils/path.js";
|
|
@@ -11,6 +12,20 @@ import { mergeHostnames, parseHostnamesEnv } from "./hostnames.js";
|
|
|
11
12
|
const DEFAULT_PORT = 6767;
|
|
12
13
|
const DEFAULT_RELAY_ENDPOINT = "relay.paseo.sh:443";
|
|
13
14
|
const DEFAULT_APP_BASE_URL = "https://app.paseo.sh";
|
|
15
|
+
const DEFAULT_TRUSTED_PROXIES = ["loopback"];
|
|
16
|
+
export function resolveBundledWebUiDistDir(moduleUrl = import.meta.url) {
|
|
17
|
+
const moduleDir = path.dirname(fileURLToPath(moduleUrl));
|
|
18
|
+
if (path.basename(moduleDir) === "server" && path.basename(path.dirname(moduleDir)) === "src") {
|
|
19
|
+
return path.resolve(moduleDir, "..", "..", "dist", "server", "web-ui");
|
|
20
|
+
}
|
|
21
|
+
if (path.basename(moduleDir) === "server" &&
|
|
22
|
+
path.basename(path.dirname(moduleDir)) === "server" &&
|
|
23
|
+
path.basename(path.dirname(path.dirname(moduleDir))) === "dist") {
|
|
24
|
+
return path.resolve(moduleDir, "..", "web-ui");
|
|
25
|
+
}
|
|
26
|
+
return path.resolve(moduleDir, "web-ui");
|
|
27
|
+
}
|
|
28
|
+
const BUNDLED_WEB_UI_DIST_DIR = resolveBundledWebUiDistDir();
|
|
14
29
|
function parseBooleanEnv(value) {
|
|
15
30
|
if (value === undefined) {
|
|
16
31
|
return undefined;
|
|
@@ -137,6 +152,21 @@ function resolveServiceProxyConfig(env, persisted) {
|
|
|
137
152
|
: null;
|
|
138
153
|
return { publicBaseUrl, standaloneListen };
|
|
139
154
|
}
|
|
155
|
+
function resolveWebUiConfig(paseoHome, env, cli, persisted) {
|
|
156
|
+
const enabled = cli?.webUiEnabled ??
|
|
157
|
+
parseBooleanEnv(env.PASEO_WEB_UI_ENABLED) ??
|
|
158
|
+
persisted.features?.webUi?.enabled ??
|
|
159
|
+
false;
|
|
160
|
+
const rawDistDir = env.PASEO_WEB_UI_DIST_DIR ?? persisted.features?.webUi?.distDir;
|
|
161
|
+
const trimmedDistDir = rawDistDir?.trim();
|
|
162
|
+
const distDir = trimmedDistDir
|
|
163
|
+
? path.resolve(path.isAbsolute(trimmedDistDir) ? trimmedDistDir : paseoHome, trimmedDistDir)
|
|
164
|
+
: BUNDLED_WEB_UI_DIST_DIR;
|
|
165
|
+
return {
|
|
166
|
+
enabled,
|
|
167
|
+
distDir,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
140
170
|
function resolveVoiceLlmConfig(env, persisted) {
|
|
141
171
|
const envVoiceLlmProvider = parseOptionalVoiceLlmProvider(env.PASEO_VOICE_LLM_PROVIDER);
|
|
142
172
|
const persistedVoiceLlmProvider = parseOptionalVoiceLlmProvider(persisted.features?.voiceMode?.llm?.provider);
|
|
@@ -153,6 +183,28 @@ function resolveCorsAllowedOrigins(env, persisted) {
|
|
|
153
183
|
const persistedCorsOrigins = persisted.daemon?.cors?.allowedOrigins ?? [];
|
|
154
184
|
return Array.from(new Set([...persistedCorsOrigins, ...envCorsOrigins].filter((s) => s.length > 0)));
|
|
155
185
|
}
|
|
186
|
+
function parseTrustedProxiesEnv(value) {
|
|
187
|
+
const trimmed = value?.trim();
|
|
188
|
+
if (!trimmed) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
const normalized = trimmed.toLowerCase();
|
|
192
|
+
if (["1", "true", "yes", "on"].includes(normalized)) {
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
if (["0", "false", "no", "off"].includes(normalized)) {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
return trimmed
|
|
199
|
+
.split(",")
|
|
200
|
+
.map((proxy) => proxy.trim())
|
|
201
|
+
.filter((proxy) => proxy.length > 0);
|
|
202
|
+
}
|
|
203
|
+
function resolveTrustedProxiesConfig(env, persisted) {
|
|
204
|
+
return (parseTrustedProxiesEnv(env.PASEO_TRUSTED_PROXIES) ??
|
|
205
|
+
persisted.daemon?.trustedProxies ??
|
|
206
|
+
DEFAULT_TRUSTED_PROXIES);
|
|
207
|
+
}
|
|
156
208
|
// PASEO_LISTEN can be:
|
|
157
209
|
// - host:port (TCP)
|
|
158
210
|
// - /path/to/socket (Unix socket)
|
|
@@ -198,6 +250,7 @@ function resolveStaticLoadConfigSettings(env, cli, persisted) {
|
|
|
198
250
|
parseHostnamesEnv(env.PASEO_HOSTNAMES ?? env.PASEO_ALLOWED_HOSTS),
|
|
199
251
|
cli?.hostnames,
|
|
200
252
|
]),
|
|
253
|
+
trustedProxies: resolveTrustedProxiesConfig(env, persisted),
|
|
201
254
|
appBaseUrl: env.PASEO_APP_BASE_URL ?? persisted.app?.baseUrl ?? DEFAULT_APP_BASE_URL,
|
|
202
255
|
};
|
|
203
256
|
}
|
|
@@ -205,7 +258,7 @@ export function loadConfig(paseoHome, options) {
|
|
|
205
258
|
const env = options?.env ?? process.env;
|
|
206
259
|
const persisted = loadPersistedConfig(paseoHome);
|
|
207
260
|
const listen = resolveListenAddress(env, options?.cli, persisted);
|
|
208
|
-
const { mcpEnabled, mcpInjectIntoAgents, autoArchiveAfterMerge, appendSystemPrompt, terminalProfiles, hostnames, appBaseUrl, } = resolveStaticLoadConfigSettings(env, options?.cli, persisted);
|
|
261
|
+
const { mcpEnabled, mcpInjectIntoAgents, autoArchiveAfterMerge, appendSystemPrompt, terminalProfiles, hostnames, trustedProxies, appBaseUrl, } = resolveStaticLoadConfigSettings(env, options?.cli, persisted);
|
|
209
262
|
const relay = resolveRelayConfig({
|
|
210
263
|
env,
|
|
211
264
|
persisted,
|
|
@@ -213,6 +266,7 @@ export function loadConfig(paseoHome, options) {
|
|
|
213
266
|
cliRelayUseTls: options?.cli?.relayUseTls,
|
|
214
267
|
});
|
|
215
268
|
const serviceProxy = resolveServiceProxyConfig(env, persisted);
|
|
269
|
+
const webUi = resolveWebUiConfig(paseoHome, env, options?.cli, persisted);
|
|
216
270
|
const { openai, speech } = resolveSpeechConfig({
|
|
217
271
|
paseoHome,
|
|
218
272
|
env,
|
|
@@ -226,6 +280,7 @@ export function loadConfig(paseoHome, options) {
|
|
|
226
280
|
worktreesRoot: resolveWorktreesRoot(paseoHome, persisted),
|
|
227
281
|
corsAllowedOrigins: resolveCorsAllowedOrigins(env, persisted),
|
|
228
282
|
hostnames,
|
|
283
|
+
trustedProxies,
|
|
229
284
|
mcpEnabled,
|
|
230
285
|
mcpInjectIntoAgents,
|
|
231
286
|
autoArchiveAfterMerge,
|
|
@@ -243,6 +298,7 @@ export function loadConfig(paseoHome, options) {
|
|
|
243
298
|
relayUseTls: relay.useTls,
|
|
244
299
|
relayPublicUseTls: relay.publicUseTls,
|
|
245
300
|
serviceProxy,
|
|
301
|
+
webUi,
|
|
246
302
|
appBaseUrl,
|
|
247
303
|
auth: resolveAuthConfig(env, persisted),
|
|
248
304
|
openai,
|
|
@@ -4,6 +4,7 @@ import { createPaseoDaemon } from "./bootstrap.js";
|
|
|
4
4
|
import { loadConfig } from "./config.js";
|
|
5
5
|
import { resolvePaseoHome } from "./paseo-home.js";
|
|
6
6
|
import { createRootLogger } from "./logger.js";
|
|
7
|
+
import { getProcessDiagnostics } from "./process-diagnostics.js";
|
|
7
8
|
process.title = "Paseo Daemon";
|
|
8
9
|
function isPidAlive(pid) {
|
|
9
10
|
try {
|
|
@@ -60,6 +61,12 @@ function applyCliFlagOverrides(config) {
|
|
|
60
61
|
if (process.argv.includes("--no-inject-mcp")) {
|
|
61
62
|
config.mcpInjectIntoAgents = false;
|
|
62
63
|
}
|
|
64
|
+
if (process.argv.includes("--web-ui")) {
|
|
65
|
+
config.webUi = { ...(config.webUi ?? { distDir: null }), enabled: true };
|
|
66
|
+
}
|
|
67
|
+
if (process.argv.includes("--no-web-ui")) {
|
|
68
|
+
config.webUi = { ...(config.webUi ?? { distDir: null }), enabled: false };
|
|
69
|
+
}
|
|
63
70
|
}
|
|
64
71
|
async function main() {
|
|
65
72
|
const { paseoHome, logger, config } = bootstrapFromEnvironment();
|
|
@@ -77,11 +84,12 @@ async function main() {
|
|
|
77
84
|
});
|
|
78
85
|
};
|
|
79
86
|
const beginShutdown = (signal, options) => {
|
|
87
|
+
const reason = options?.reason ?? `worker_received_${signal}`;
|
|
80
88
|
if (!shutdownPromise) {
|
|
81
|
-
logger.info(`${signal} received, shutting down gracefully...`);
|
|
89
|
+
logger.info({ signal, reason, ...getProcessDiagnostics() }, `${signal} received, shutting down gracefully...`);
|
|
82
90
|
shutdownPromise = (async () => {
|
|
83
91
|
const forceExit = setTimeout(() => {
|
|
84
|
-
logger.warn("Forcing shutdown - HTTP server didn't close in time");
|
|
92
|
+
logger.warn({ signal, reason, ...getProcessDiagnostics() }, "Forcing shutdown - HTTP server didn't close in time");
|
|
85
93
|
process.exit(1);
|
|
86
94
|
}, 10000);
|
|
87
95
|
try {
|
|
@@ -103,7 +111,7 @@ async function main() {
|
|
|
103
111
|
})();
|
|
104
112
|
}
|
|
105
113
|
else {
|
|
106
|
-
logger.info(`${signal} received while shutdown is already in progress`);
|
|
114
|
+
logger.info({ signal, reason, ...getProcessDiagnostics() }, `${signal} received while shutdown is already in progress`);
|
|
107
115
|
}
|
|
108
116
|
installExitHook();
|
|
109
117
|
};
|
|
@@ -122,11 +130,11 @@ async function main() {
|
|
|
122
130
|
};
|
|
123
131
|
const handleLifecycleIntent = (intent) => {
|
|
124
132
|
if (intent.type === "shutdown") {
|
|
125
|
-
logger.warn({ clientId: intent.clientId, requestId: intent.requestId }, "Shutdown requested via websocket");
|
|
126
|
-
if (sendSupervisorLifecycleMessage({ type: "paseo:shutdown" })) {
|
|
133
|
+
logger.warn({ clientId: intent.clientId, requestId: intent.requestId, reason: intent.reason }, "Shutdown requested via websocket");
|
|
134
|
+
if (sendSupervisorLifecycleMessage({ type: "paseo:shutdown", reason: intent.reason })) {
|
|
127
135
|
return;
|
|
128
136
|
}
|
|
129
|
-
beginShutdown("shutdown lifecycle intent");
|
|
137
|
+
beginShutdown("shutdown lifecycle intent", { reason: intent.reason });
|
|
130
138
|
return;
|
|
131
139
|
}
|
|
132
140
|
logger.warn({ clientId: intent.clientId, requestId: intent.requestId, reason: intent.reason }, "Restart requested via websocket");
|
|
@@ -136,7 +144,10 @@ async function main() {
|
|
|
136
144
|
})) {
|
|
137
145
|
return;
|
|
138
146
|
}
|
|
139
|
-
beginShutdown("restart lifecycle intent", {
|
|
147
|
+
beginShutdown("restart lifecycle intent", {
|
|
148
|
+
reason: intent.reason,
|
|
149
|
+
successExitCode: 0,
|
|
150
|
+
});
|
|
140
151
|
};
|
|
141
152
|
const installSupervisorLivenessGuard = () => {
|
|
142
153
|
if (typeof process.send !== "function") {
|
|
@@ -152,6 +163,7 @@ async function main() {
|
|
|
152
163
|
supervisorExitRequested = true;
|
|
153
164
|
writeWorkerLifecycleLog(paseoHome, "Supervisor liveness lost; worker exiting", {
|
|
154
165
|
reason,
|
|
166
|
+
...getProcessDiagnostics(),
|
|
155
167
|
supervisorPid,
|
|
156
168
|
currentParentPid: process.ppid,
|
|
157
169
|
ipcConnected: typeof process.connected === "boolean" ? process.connected : null,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const CLIENT_SHUTDOWN_RPC_REASON = "client_shutdown_rpc";
|
|
2
|
+
export declare const DEFAULT_CLIENT_RESTART_RPC_REASON = "client_restart_rpc";
|
|
3
|
+
export declare function normalizeClientRestartRpcReason(reason: string | undefined): string;
|
|
4
|
+
//# sourceMappingURL=lifecycle-reasons.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const CLIENT_SHUTDOWN_RPC_REASON = "client_shutdown_rpc";
|
|
2
|
+
export const DEFAULT_CLIENT_RESTART_RPC_REASON = "client_restart_rpc";
|
|
3
|
+
export function normalizeClientRestartRpcReason(reason) {
|
|
4
|
+
return reason?.trim() || DEFAULT_CLIENT_RESTART_RPC_REASON;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=lifecycle-reasons.js.map
|
|
@@ -19,6 +19,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
|
|
|
19
19
|
listen: z.ZodOptional<z.ZodString>;
|
|
20
20
|
hostnames: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
|
|
21
21
|
allowedHosts: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
|
|
22
|
+
trustedProxies: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
|
|
22
23
|
mcp: z.ZodOptional<z.ZodObject<{
|
|
23
24
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
24
25
|
injectIntoAgents: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -54,6 +55,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
|
|
|
54
55
|
}, z.core.$strict>, z.ZodTransform<{
|
|
55
56
|
listen?: string | undefined;
|
|
56
57
|
hostnames?: true | string[] | undefined;
|
|
58
|
+
trustedProxies?: true | string[] | undefined;
|
|
57
59
|
mcp?: {
|
|
58
60
|
[x: string]: unknown;
|
|
59
61
|
enabled?: boolean | undefined;
|
|
@@ -92,6 +94,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
|
|
|
92
94
|
listen?: string | undefined;
|
|
93
95
|
hostnames?: true | string[] | undefined;
|
|
94
96
|
allowedHosts?: true | string[] | undefined;
|
|
97
|
+
trustedProxies?: true | string[] | undefined;
|
|
95
98
|
mcp?: {
|
|
96
99
|
[x: string]: unknown;
|
|
97
100
|
enabled?: boolean | undefined;
|
|
@@ -133,11 +136,15 @@ export declare const PersistedConfigSchema: z.ZodObject<{
|
|
|
133
136
|
providers: z.ZodOptional<z.ZodObject<{
|
|
134
137
|
openai: z.ZodOptional<z.ZodObject<{
|
|
135
138
|
apiKey: z.ZodOptional<z.ZodString>;
|
|
136
|
-
|
|
139
|
+
baseUrl: z.ZodOptional<z.ZodString>;
|
|
140
|
+
stt: z.ZodOptional<z.ZodObject<{
|
|
141
|
+
apiKey: z.ZodOptional<z.ZodString>;
|
|
142
|
+
baseUrl: z.ZodOptional<z.ZodString>;
|
|
143
|
+
}, z.core.$strict>>;
|
|
144
|
+
tts: z.ZodOptional<z.ZodObject<{
|
|
137
145
|
apiKey: z.ZodOptional<z.ZodString>;
|
|
138
146
|
baseUrl: z.ZodOptional<z.ZodString>;
|
|
139
147
|
}, z.core.$strict>>;
|
|
140
|
-
baseUrl: z.ZodOptional<z.ZodString>;
|
|
141
148
|
}, z.core.$strict>>;
|
|
142
149
|
local: z.ZodOptional<z.ZodObject<{
|
|
143
150
|
modelsDir: z.ZodOptional<z.ZodString>;
|
|
@@ -241,6 +248,10 @@ export declare const PersistedConfigSchema: z.ZodObject<{
|
|
|
241
248
|
speed: z.ZodOptional<z.ZodNumber>;
|
|
242
249
|
}, z.core.$strict>>;
|
|
243
250
|
}, z.core.$strict>>;
|
|
251
|
+
webUi: z.ZodOptional<z.ZodObject<{
|
|
252
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
253
|
+
distDir: z.ZodOptional<z.ZodString>;
|
|
254
|
+
}, z.core.$strict>>;
|
|
244
255
|
}, z.core.$strict>>;
|
|
245
256
|
log: z.ZodOptional<z.ZodObject<{
|
|
246
257
|
level: z.ZodOptional<z.ZodEnum<{
|
|
@@ -34,7 +34,7 @@ const LogConfigSchema = z
|
|
|
34
34
|
.optional(),
|
|
35
35
|
})
|
|
36
36
|
.strict();
|
|
37
|
-
const
|
|
37
|
+
const OpenAiSpeechEndpointSchema = z
|
|
38
38
|
.object({
|
|
39
39
|
apiKey: z.string().trim().min(1).optional(),
|
|
40
40
|
baseUrl: z.string().trim().min(1).optional(),
|
|
@@ -43,8 +43,9 @@ const OpenAiVoiceProviderSchema = z
|
|
|
43
43
|
const OpenAiProviderSchema = z
|
|
44
44
|
.object({
|
|
45
45
|
apiKey: z.string().min(1).optional(),
|
|
46
|
-
voice: OpenAiVoiceProviderSchema.optional(),
|
|
47
46
|
baseUrl: z.string().trim().min(1).optional(),
|
|
47
|
+
stt: OpenAiSpeechEndpointSchema.optional(),
|
|
48
|
+
tts: OpenAiSpeechEndpointSchema.optional(),
|
|
48
49
|
})
|
|
49
50
|
.strict();
|
|
50
51
|
const LocalSpeechProviderSchema = z
|
|
@@ -126,6 +127,12 @@ const FeatureVoiceModeSchema = z
|
|
|
126
127
|
.optional(),
|
|
127
128
|
})
|
|
128
129
|
.strict();
|
|
130
|
+
const FeatureWebUiSchema = z
|
|
131
|
+
.object({
|
|
132
|
+
enabled: z.boolean().optional(),
|
|
133
|
+
distDir: z.string().min(1).optional(),
|
|
134
|
+
})
|
|
135
|
+
.strict();
|
|
129
136
|
const StructuredGenerationProviderConfigSchema = z
|
|
130
137
|
.object({
|
|
131
138
|
provider: z.string().min(1),
|
|
@@ -187,6 +194,7 @@ export const PersistedConfigSchema = z
|
|
|
187
194
|
listen: z.string().optional(),
|
|
188
195
|
hostnames: z.union([z.literal(true), z.array(z.string())]).optional(),
|
|
189
196
|
allowedHosts: z.union([z.literal(true), z.array(z.string())]).optional(),
|
|
197
|
+
trustedProxies: z.union([z.literal(true), z.array(z.string())]).optional(),
|
|
190
198
|
mcp: z
|
|
191
199
|
.object({
|
|
192
200
|
enabled: z.boolean().optional(),
|
|
@@ -252,6 +260,7 @@ export const PersistedConfigSchema = z
|
|
|
252
260
|
.object({
|
|
253
261
|
dictation: FeatureDictationSchema.optional(),
|
|
254
262
|
voiceMode: FeatureVoiceModeSchema.optional(),
|
|
263
|
+
webUi: FeatureWebUiSchema.optional(),
|
|
255
264
|
})
|
|
256
265
|
.strict()
|
|
257
266
|
.optional(),
|
|
@@ -280,7 +289,11 @@ function getConfigPath(paseoHome) {
|
|
|
280
289
|
function getLogger(logger) {
|
|
281
290
|
return logger?.child({ module: "config" });
|
|
282
291
|
}
|
|
283
|
-
|
|
292
|
+
// Removed config fields are stripped before parsing so the strict schema does not
|
|
293
|
+
// reject a config written by an older release. The stripped values are discarded,
|
|
294
|
+
// not migrated — there is no back-compat for the removed `providers.openai.voice`
|
|
295
|
+
// block (use `providers.openai.stt` / `providers.openai.tts`).
|
|
296
|
+
function stripRemovedConfigFields(parsed) {
|
|
284
297
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
285
298
|
return parsed;
|
|
286
299
|
}
|
|
@@ -291,15 +304,21 @@ function stripDeprecatedLocalSpeechConfigFields(parsed) {
|
|
|
291
304
|
}
|
|
292
305
|
const providersRecord = { ...providers };
|
|
293
306
|
const local = providersRecord.local;
|
|
294
|
-
if (
|
|
295
|
-
|
|
296
|
-
return root;
|
|
297
|
-
}
|
|
298
|
-
const localRecord = { ...local };
|
|
299
|
-
if ("autoDownload" in localRecord) {
|
|
307
|
+
if (local && typeof local === "object" && !Array.isArray(local)) {
|
|
308
|
+
const localRecord = { ...local };
|
|
300
309
|
delete localRecord.autoDownload;
|
|
310
|
+
providersRecord.local = localRecord;
|
|
311
|
+
}
|
|
312
|
+
const openai = providersRecord.openai;
|
|
313
|
+
if (openai && typeof openai === "object" && !Array.isArray(openai)) {
|
|
314
|
+
const openaiRecord = { ...openai };
|
|
315
|
+
// COMPAT(openaiVoiceConfig): added 2026-06-30, remove after 2026-12-30.
|
|
316
|
+
// Drop a `providers.openai.voice` block left by an older release so the strict
|
|
317
|
+
// schema doesn't reject it. The value is discarded, not migrated — there is no
|
|
318
|
+
// back-compat; configure `providers.openai.stt` / `providers.openai.tts` instead.
|
|
319
|
+
delete openaiRecord.voice;
|
|
320
|
+
providersRecord.openai = openaiRecord;
|
|
301
321
|
}
|
|
302
|
-
providersRecord.local = localRecord;
|
|
303
322
|
root.providers = providersRecord;
|
|
304
323
|
return root;
|
|
305
324
|
}
|
|
@@ -337,7 +356,7 @@ export function loadPersistedConfig(paseoHome, logger) {
|
|
|
337
356
|
cause: err,
|
|
338
357
|
});
|
|
339
358
|
}
|
|
340
|
-
const migrated =
|
|
359
|
+
const migrated = stripRemovedConfigFields(parsed);
|
|
341
360
|
const result = PersistedConfigSchema.safeParse(migrated);
|
|
342
361
|
if (!result.success) {
|
|
343
362
|
const issues = result.error.issues
|