@getpaseo/server 0.1.90 → 0.1.91-beta.2
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/dist/server/server/agent/agent-sdk-types.d.ts +15 -0
- package/dist/server/server/agent/provider-registry.js +1 -1
- package/dist/server/server/agent/provider-snapshot-manager.js +19 -1
- package/dist/server/server/agent/providers/claude/agent.d.ts +5 -2
- package/dist/server/server/agent/providers/claude/agent.js +9 -9
- package/dist/server/server/agent/providers/claude/models.d.ts +1 -1
- package/dist/server/server/agent/providers/claude/models.js +6 -6
- package/dist/server/server/agent/providers/claude/project-dir.d.ts +1 -0
- package/dist/server/server/agent/providers/claude/project-dir.js +14 -0
- package/dist/server/server/auth.js +16 -1
- package/dist/server/server/persisted-config.d.ts +3 -0
- package/dist/server/server/persisted-config.js +1 -0
- package/dist/server/utils/directory-suggestions.js +10 -5
- package/dist/server/utils/worktree.d.ts +4 -0
- package/dist/server/utils/worktree.js +19 -2
- package/dist/src/server/persisted-config.js +1 -0
- package/package.json +5 -5
|
@@ -12,6 +12,11 @@ export interface McpStdioServerConfig {
|
|
|
12
12
|
command: string;
|
|
13
13
|
args?: string[];
|
|
14
14
|
env?: Record<string, string>;
|
|
15
|
+
/**
|
|
16
|
+
* When true, all tools from this server are always included in the prompt
|
|
17
|
+
* and never deferred behind tool search. Honored by the Claude provider.
|
|
18
|
+
*/
|
|
19
|
+
alwaysLoad?: boolean;
|
|
15
20
|
}
|
|
16
21
|
/**
|
|
17
22
|
* HTTP-based MCP server.
|
|
@@ -20,6 +25,11 @@ export interface McpHttpServerConfig {
|
|
|
20
25
|
type: "http";
|
|
21
26
|
url: string;
|
|
22
27
|
headers?: Record<string, string>;
|
|
28
|
+
/**
|
|
29
|
+
* When true, all tools from this server are always included in the prompt
|
|
30
|
+
* and never deferred behind tool search. Honored by the Claude provider.
|
|
31
|
+
*/
|
|
32
|
+
alwaysLoad?: boolean;
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* SSE-based MCP server (Server-Sent Events over HTTP).
|
|
@@ -28,6 +38,11 @@ export interface McpSseServerConfig {
|
|
|
28
38
|
type: "sse";
|
|
29
39
|
url: string;
|
|
30
40
|
headers?: Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* When true, all tools from this server are always included in the prompt
|
|
43
|
+
* and never deferred behind tool search. Honored by the Claude provider.
|
|
44
|
+
*/
|
|
45
|
+
alwaysLoad?: boolean;
|
|
31
46
|
}
|
|
32
47
|
/**
|
|
33
48
|
* Canonical MCP server configuration.
|
|
@@ -292,7 +292,7 @@ function buildResolvedBuiltinProviders(providerOverrides, runtimeSettings, optio
|
|
|
292
292
|
runtimeSettings: mergedRuntimeSettings,
|
|
293
293
|
profileModels: override?.models ?? [],
|
|
294
294
|
additionalModels: override?.additionalModels ?? [],
|
|
295
|
-
profileModelsAreAdditive:
|
|
295
|
+
profileModelsAreAdditive: false,
|
|
296
296
|
enabled: override?.enabled !== false,
|
|
297
297
|
derivedFromProviderId: null,
|
|
298
298
|
createBaseClient: (logger) => factory(logger, mergedRuntimeSettings, {
|
|
@@ -6,6 +6,24 @@ import { withTimeout } from "../../utils/promise-timeout.js";
|
|
|
6
6
|
import { buildProviderRegistry, shutdownAgentClients, } from "./provider-registry.js";
|
|
7
7
|
import { applyMutableProviderConfigToOverrides } from "../daemon-config-store.js";
|
|
8
8
|
const DEFAULT_REFRESH_TIMEOUT_MS = 30000;
|
|
9
|
+
const REFRESH_TIMEOUT_ENV_VAR = "PASEO_PROVIDER_REFRESH_TIMEOUT_MS";
|
|
10
|
+
// Provider refresh probes can be slow on cold starts (e.g. Copilot's first
|
|
11
|
+
// `copilot --acp` invocation, OpenCode workspace probes with many MCP servers).
|
|
12
|
+
// Allow operators to bump the ceiling via env var without rebuilding.
|
|
13
|
+
function resolveRefreshTimeoutMs(option) {
|
|
14
|
+
if (typeof option === "number" && Number.isFinite(option) && option > 0) {
|
|
15
|
+
return option;
|
|
16
|
+
}
|
|
17
|
+
const fromEnv = process.env[REFRESH_TIMEOUT_ENV_VAR];
|
|
18
|
+
if (fromEnv) {
|
|
19
|
+
// Number() handles scientific notation (e.g. "6e4") which parseInt would silently truncate.
|
|
20
|
+
const parsed = Number(fromEnv);
|
|
21
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return DEFAULT_REFRESH_TIMEOUT_MS;
|
|
26
|
+
}
|
|
9
27
|
export class ProviderSnapshotManager {
|
|
10
28
|
constructor(options) {
|
|
11
29
|
this.snapshots = new Map();
|
|
@@ -19,7 +37,7 @@ export class ProviderSnapshotManager {
|
|
|
19
37
|
this.runtimeSettings = options.runtimeSettings;
|
|
20
38
|
this.providerOverrides = options.providerOverrides;
|
|
21
39
|
this.baseProviderOverrides = options.providerOverrides;
|
|
22
|
-
this.refreshTimeoutMs = options.refreshTimeoutMs
|
|
40
|
+
this.refreshTimeoutMs = resolveRefreshTimeoutMs(options.refreshTimeoutMs);
|
|
23
41
|
this.providerRegistry = this.buildRegistry();
|
|
24
42
|
this.providerClients = { ...this.extraClients };
|
|
25
43
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type AgentDefinition, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
1
|
+
import { type AgentDefinition, type McpServerConfig as ClaudeSdkMcpServerConfig, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
2
2
|
import type { Logger } from "pino";
|
|
3
3
|
import { type ClaudeQueryFactory } from "./query.js";
|
|
4
|
-
import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMetadata, type AgentModelDefinition, type AgentPersistenceHandle, type AgentSession, type AgentSessionConfig, type AgentTimelineItem, type ListModelsOptions, type ListPersistedAgentsOptions, type PersistedAgentDescriptor } from "../../agent-sdk-types.js";
|
|
4
|
+
import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMetadata, type AgentModelDefinition, type AgentPersistenceHandle, type AgentSession, type AgentSessionConfig, type AgentTimelineItem, type ListModelsOptions, type ListPersistedAgentsOptions, type McpServerConfig, type PersistedAgentDescriptor } from "../../agent-sdk-types.js";
|
|
5
5
|
import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
|
|
6
6
|
export declare function normalizeClaudeAskUserQuestionUpdatedInput(updatedInput: AgentMetadata | undefined, fallbackInput: AgentMetadata | undefined): AgentMetadata;
|
|
7
7
|
interface EventIdentifiers {
|
|
@@ -21,8 +21,10 @@ interface ClaudeAgentClientOptions {
|
|
|
21
21
|
runtimeSettings?: ProviderRuntimeSettings;
|
|
22
22
|
queryFactory?: ClaudeQueryFactory;
|
|
23
23
|
resolveBinary?: () => Promise<string>;
|
|
24
|
+
configDir?: string;
|
|
24
25
|
}
|
|
25
26
|
export declare function extractUserMessageText(content: unknown): string | null;
|
|
27
|
+
export declare function toClaudeSdkMcpConfig(config: McpServerConfig): ClaudeSdkMcpServerConfig;
|
|
26
28
|
export declare function readEventIdentifiers(message: SDKMessage): EventIdentifiers;
|
|
27
29
|
export declare class ClaudeAgentClient implements AgentClient {
|
|
28
30
|
readonly provider: "claude";
|
|
@@ -32,6 +34,7 @@ export declare class ClaudeAgentClient implements AgentClient {
|
|
|
32
34
|
private readonly runtimeSettings?;
|
|
33
35
|
private readonly queryFactory?;
|
|
34
36
|
private readonly resolveBinary;
|
|
37
|
+
private readonly configDir?;
|
|
35
38
|
constructor(options: ClaudeAgentClientOptions);
|
|
36
39
|
createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext, options?: AgentCreateSessionOptions): Promise<AgentSession>;
|
|
37
40
|
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
|
|
@@ -15,6 +15,7 @@ import { renderPromptAttachmentAsText } from "../../prompt-attachments.js";
|
|
|
15
15
|
import { claudeQuery } from "./query.js";
|
|
16
16
|
import { realClaudeRewindSdk, revertClaudeConversation, revertClaudeFiles } from "./rewind.js";
|
|
17
17
|
import { normalizeProviderReplayTimestamp } from "../../provider-history-timestamps.js";
|
|
18
|
+
import { claudeProjectDirSync } from "./project-dir.js";
|
|
18
19
|
import { getAgentStreamEventTurnId, } from "../../agent-sdk-types.js";
|
|
19
20
|
import { checkProviderLaunchAvailable, createProviderEnv, createProviderEnvSpec, resolveProviderLaunch, } from "../../provider-launch-config.js";
|
|
20
21
|
import { withTimeout } from "../../../../utils/promise-timeout.js";
|
|
@@ -171,9 +172,6 @@ function isClaudeThinkingEffort(value) {
|
|
|
171
172
|
value === "xhigh" ||
|
|
172
173
|
value === "max");
|
|
173
174
|
}
|
|
174
|
-
function sanitizeClaudeProjectPath(cwd) {
|
|
175
|
-
return cwd.replace(/[\\/._:]/g, "-");
|
|
176
|
-
}
|
|
177
175
|
const MAX_RECENT_STDERR_CHARS = 4000;
|
|
178
176
|
const STDERR_FLUSH_WAIT_MS = 150;
|
|
179
177
|
const STDERR_FLUSH_POLL_INTERVAL_MS = 10;
|
|
@@ -541,7 +539,7 @@ function coerceSessionMetadata(metadata) {
|
|
|
541
539
|
}
|
|
542
540
|
return result;
|
|
543
541
|
}
|
|
544
|
-
function toClaudeSdkMcpConfig(config) {
|
|
542
|
+
export function toClaudeSdkMcpConfig(config) {
|
|
545
543
|
switch (config.type) {
|
|
546
544
|
case "stdio":
|
|
547
545
|
return {
|
|
@@ -549,18 +547,21 @@ function toClaudeSdkMcpConfig(config) {
|
|
|
549
547
|
command: config.command,
|
|
550
548
|
args: config.args,
|
|
551
549
|
env: config.env,
|
|
550
|
+
alwaysLoad: config.alwaysLoad,
|
|
552
551
|
};
|
|
553
552
|
case "http":
|
|
554
553
|
return {
|
|
555
554
|
type: "http",
|
|
556
555
|
url: config.url,
|
|
557
556
|
headers: config.headers,
|
|
557
|
+
alwaysLoad: config.alwaysLoad,
|
|
558
558
|
};
|
|
559
559
|
case "sse":
|
|
560
560
|
return {
|
|
561
561
|
type: "sse",
|
|
562
562
|
url: config.url,
|
|
563
563
|
headers: config.headers,
|
|
564
|
+
alwaysLoad: config.alwaysLoad,
|
|
564
565
|
};
|
|
565
566
|
}
|
|
566
567
|
throw new Error("Unhandled MCP server config type");
|
|
@@ -924,6 +925,7 @@ export class ClaudeAgentClient {
|
|
|
924
925
|
this.runtimeSettings = options.runtimeSettings;
|
|
925
926
|
this.queryFactory = options.queryFactory;
|
|
926
927
|
this.resolveBinary = options.resolveBinary ?? (() => resolveClaudeBinary(this.runtimeSettings));
|
|
928
|
+
this.configDir = options.configDir;
|
|
927
929
|
}
|
|
928
930
|
async createSession(config, launchContext, options) {
|
|
929
931
|
const claudeConfig = this.assertConfig(config);
|
|
@@ -963,7 +965,7 @@ export class ClaudeAgentClient {
|
|
|
963
965
|
}
|
|
964
966
|
async listModels(_options) {
|
|
965
967
|
// Claude exposes a global catalog here; cwd/force are intentionally irrelevant.
|
|
966
|
-
return await getClaudeModelsWithSettings(this.logger);
|
|
968
|
+
return await getClaudeModelsWithSettings(this.logger, this.configDir);
|
|
967
969
|
}
|
|
968
970
|
async listFeatures(config) {
|
|
969
971
|
const claudeConfig = this.assertConfig(config);
|
|
@@ -3188,14 +3190,12 @@ class ClaudeAgentSession {
|
|
|
3188
3190
|
// Fall back to the configured cwd when the path has already disappeared.
|
|
3189
3191
|
}
|
|
3190
3192
|
for (const candidate of candidates) {
|
|
3191
|
-
const
|
|
3192
|
-
const historyPath = path.join(configDir, "projects", sanitized, `${sessionId}.jsonl`);
|
|
3193
|
+
const historyPath = path.join(claudeProjectDirSync(candidate, { configDir }), `${sessionId}.jsonl`);
|
|
3193
3194
|
if (fs.existsSync(historyPath)) {
|
|
3194
3195
|
return historyPath;
|
|
3195
3196
|
}
|
|
3196
3197
|
}
|
|
3197
|
-
|
|
3198
|
-
return path.join(configDir, "projects", sanitized, `${sessionId}.jsonl`);
|
|
3198
|
+
return path.join(claudeProjectDirSync(cwd, { configDir }), `${sessionId}.jsonl`);
|
|
3199
3199
|
}
|
|
3200
3200
|
convertHistoryEntry(entry) {
|
|
3201
3201
|
return convertClaudeHistoryEntry(entry, (content) => this.mapBlocksToTimeline(content));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
2
|
import type { AgentModelDefinition } from "../../agent-sdk-types.js";
|
|
3
3
|
export declare function getClaudeModels(): AgentModelDefinition[];
|
|
4
|
-
export declare function getClaudeModelsWithSettings(logger: Logger): Promise<AgentModelDefinition[]>;
|
|
4
|
+
export declare function getClaudeModelsWithSettings(logger: Logger, configDir?: string): Promise<AgentModelDefinition[]>;
|
|
5
5
|
/**
|
|
6
6
|
* Normalize a runtime model string (from SDK init message) to a known model ID.
|
|
7
7
|
* Handles the `[1m]` suffix that the SDK appends for 1M context sessions.
|
|
@@ -89,9 +89,9 @@ const CLAUDE_SETTINGS_MODEL_ENV_KEYS = [
|
|
|
89
89
|
export function getClaudeModels() {
|
|
90
90
|
return CLAUDE_MODELS.map((model) => ({ ...model }));
|
|
91
91
|
}
|
|
92
|
-
export async function getClaudeModelsWithSettings(logger) {
|
|
92
|
+
export async function getClaudeModelsWithSettings(logger, configDir) {
|
|
93
93
|
const hardcodedModels = getClaudeModels();
|
|
94
|
-
const settingsModels = await readClaudeSettingsModels(logger);
|
|
94
|
+
const settingsModels = await readClaudeSettingsModels(logger, configDir);
|
|
95
95
|
if (settingsModels.length === 0) {
|
|
96
96
|
return hardcodedModels;
|
|
97
97
|
}
|
|
@@ -106,8 +106,8 @@ export async function getClaudeModelsWithSettings(logger) {
|
|
|
106
106
|
}
|
|
107
107
|
return models;
|
|
108
108
|
}
|
|
109
|
-
async function readClaudeSettingsModels(logger) {
|
|
110
|
-
const settingsPath = path.join(resolveClaudeConfigDir(), "settings.json");
|
|
109
|
+
async function readClaudeSettingsModels(logger, configDir) {
|
|
110
|
+
const settingsPath = path.join(resolveClaudeConfigDir(configDir), "settings.json");
|
|
111
111
|
let parsed;
|
|
112
112
|
try {
|
|
113
113
|
const rawSettings = await fs.readFile(settingsPath, "utf8");
|
|
@@ -136,8 +136,8 @@ async function readClaudeSettingsModels(logger) {
|
|
|
136
136
|
}
|
|
137
137
|
return models;
|
|
138
138
|
}
|
|
139
|
-
function resolveClaudeConfigDir() {
|
|
140
|
-
return process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
|
|
139
|
+
function resolveClaudeConfigDir(configDir) {
|
|
140
|
+
return configDir ?? process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
|
|
141
141
|
}
|
|
142
142
|
function addSettingsModel(models, value, settingsKey) {
|
|
143
143
|
if (typeof value !== "string") {
|
|
@@ -2,4 +2,5 @@ export interface ClaudeProjectDirOptions {
|
|
|
2
2
|
configDir?: string;
|
|
3
3
|
}
|
|
4
4
|
export declare function claudeProjectDir(cwd: string, options?: ClaudeProjectDirOptions): Promise<string>;
|
|
5
|
+
export declare function claudeProjectDirSync(cwd: string, options?: ClaudeProjectDirOptions): string;
|
|
5
6
|
//# sourceMappingURL=project-dir.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
1
2
|
import { realpath } from "node:fs/promises";
|
|
2
3
|
import { homedir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
@@ -12,6 +13,11 @@ export async function claudeProjectDir(cwd, options) {
|
|
|
12
13
|
const projectsRoot = join(resolveConfigDir(options), "projects");
|
|
13
14
|
return join(projectsRoot, encode(canonical));
|
|
14
15
|
}
|
|
16
|
+
export function claudeProjectDirSync(cwd, options) {
|
|
17
|
+
const canonical = canonicalizeSync(cwd);
|
|
18
|
+
const projectsRoot = join(resolveConfigDir(options), "projects");
|
|
19
|
+
return join(projectsRoot, encode(canonical));
|
|
20
|
+
}
|
|
15
21
|
async function canonicalize(input) {
|
|
16
22
|
try {
|
|
17
23
|
return (await realpath(input)).normalize("NFC");
|
|
@@ -20,6 +26,14 @@ async function canonicalize(input) {
|
|
|
20
26
|
return input.normalize("NFC");
|
|
21
27
|
}
|
|
22
28
|
}
|
|
29
|
+
function canonicalizeSync(input) {
|
|
30
|
+
try {
|
|
31
|
+
return realpathSync.native(input).normalize("NFC");
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return input.normalize("NFC");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
23
37
|
function encode(input) {
|
|
24
38
|
const replaced = input.replace(/[^a-zA-Z0-9]/g, "-");
|
|
25
39
|
if (replaced.length <= PROJECT_DIR_LENGTH_CAP) {
|
|
@@ -84,10 +84,25 @@ export function createRequireBearerMiddleware(auth, onReject) {
|
|
|
84
84
|
})();
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
|
+
// Routes that authenticate via their own capability and therefore must not be
|
|
88
|
+
// gated a second time behind the daemon password.
|
|
89
|
+
const BEARER_AUTH_BYPASS_PATHS = new Set([
|
|
90
|
+
// Unauthenticated liveness probe.
|
|
91
|
+
"/api/health",
|
|
92
|
+
// Guarded by a single-use download token (crypto-random UUID, 60s TTL,
|
|
93
|
+
// consumed on first use) that is only ever issued over the
|
|
94
|
+
// already-authenticated WebSocket. The token IS the capability for this
|
|
95
|
+
// route. Requiring the daemon password on top of it breaks browser and
|
|
96
|
+
// Electron downloads: those trigger the download via an anchor navigation,
|
|
97
|
+
// which cannot attach an `Authorization` header. The download endpoint still
|
|
98
|
+
// rejects requests without a valid token (400/403), so dropping the bearer
|
|
99
|
+
// here does not make the route unauthenticated.
|
|
100
|
+
"/api/files/download",
|
|
101
|
+
]);
|
|
87
102
|
export function shouldBypassBearerAuth(method, path) {
|
|
88
103
|
if (method === "OPTIONS") {
|
|
89
104
|
return true;
|
|
90
105
|
}
|
|
91
|
-
return path
|
|
106
|
+
return BEARER_AUTH_BYPASS_PATHS.has(path);
|
|
92
107
|
}
|
|
93
108
|
//# sourceMappingURL=auth.js.map
|
|
@@ -3,6 +3,7 @@ import type { AgentProviderRuntimeSettingsMap } from "./agent/provider-launch-co
|
|
|
3
3
|
export declare const LogLevelSchema: z.ZodEnum<["trace", "debug", "info", "warn", "error", "fatal"]>;
|
|
4
4
|
export declare const LogFormatSchema: z.ZodEnum<["pretty", "json"]>;
|
|
5
5
|
export declare const PersistedConfigSchema: z.ZodObject<{
|
|
6
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
6
7
|
version: z.ZodOptional<z.ZodLiteral<1>>;
|
|
7
8
|
daemon: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
8
9
|
listen: z.ZodOptional<z.ZodString>;
|
|
@@ -957,6 +958,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
|
|
|
957
958
|
order?: number | undefined;
|
|
958
959
|
}> | undefined;
|
|
959
960
|
} | undefined;
|
|
961
|
+
$schema?: string | undefined;
|
|
960
962
|
app?: {
|
|
961
963
|
baseUrl?: string | undefined;
|
|
962
964
|
} | undefined;
|
|
@@ -1061,6 +1063,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
|
|
|
1061
1063
|
} | undefined;
|
|
1062
1064
|
providers?: unknown;
|
|
1063
1065
|
} | undefined;
|
|
1066
|
+
$schema?: string | undefined;
|
|
1064
1067
|
app?: {
|
|
1065
1068
|
baseUrl?: string | undefined;
|
|
1066
1069
|
} | undefined;
|
|
@@ -12,8 +12,11 @@ const NO_SEGMENT_INDEX = Number.MAX_SAFE_INTEGER;
|
|
|
12
12
|
const NO_MATCH_OFFSET = Number.MAX_SAFE_INTEGER;
|
|
13
13
|
const NO_FUZZY_SCORE = Number.MAX_SAFE_INTEGER;
|
|
14
14
|
const NO_WORKSPACE_MATCH_TIER = 5;
|
|
15
|
-
const
|
|
15
|
+
const IGNORED_SUGGESTION_DIRECTORY_NAMES = new Set([
|
|
16
16
|
"node_modules",
|
|
17
|
+
"venv",
|
|
18
|
+
"env",
|
|
19
|
+
"virtualenv",
|
|
17
20
|
"dist",
|
|
18
21
|
"build",
|
|
19
22
|
"target",
|
|
@@ -589,7 +592,9 @@ async function listChildDirectories(input) {
|
|
|
589
592
|
return cached.entries;
|
|
590
593
|
}
|
|
591
594
|
const dirents = await readdir(input.directory, { withFileTypes: true }).catch(() => []);
|
|
592
|
-
const candidates = dirents.filter((dirent) => !isHiddenDirectoryName(dirent.name) &&
|
|
595
|
+
const candidates = dirents.filter((dirent) => !isHiddenDirectoryName(dirent.name) &&
|
|
596
|
+
!isIgnoredSuggestionDirectoryName(dirent.name) &&
|
|
597
|
+
(dirent.isDirectory() || dirent.isSymbolicLink()));
|
|
593
598
|
const resolved = await Promise.all(candidates.map(async (dirent) => {
|
|
594
599
|
const candidatePath = path.join(input.directory, dirent.name);
|
|
595
600
|
const absolutePath = await resolveDirectoryCandidate({
|
|
@@ -613,7 +618,7 @@ async function listWorkspaceChildEntries(input) {
|
|
|
613
618
|
return cached.entries;
|
|
614
619
|
}
|
|
615
620
|
const dirents = await readdir(input.directory, { withFileTypes: true }).catch(() => []);
|
|
616
|
-
const candidates = dirents.filter((dirent) => !isHiddenDirectoryName(dirent.name) && !
|
|
621
|
+
const candidates = dirents.filter((dirent) => !isHiddenDirectoryName(dirent.name) && !isIgnoredSuggestionDirectoryName(dirent.name));
|
|
617
622
|
const resolved = await Promise.all(candidates.map(async (dirent) => {
|
|
618
623
|
const candidatePath = path.join(input.directory, dirent.name);
|
|
619
624
|
const entry = await resolveWorkspaceCandidate({
|
|
@@ -682,8 +687,8 @@ async function resolveWorkspaceCandidate(input) {
|
|
|
682
687
|
function isHiddenDirectoryName(name) {
|
|
683
688
|
return name.startsWith(".");
|
|
684
689
|
}
|
|
685
|
-
function
|
|
686
|
-
return
|
|
690
|
+
function isIgnoredSuggestionDirectoryName(name) {
|
|
691
|
+
return IGNORED_SUGGESTION_DIRECTORY_NAMES.has(name);
|
|
687
692
|
}
|
|
688
693
|
function setDirectoryListCache(cacheKey, entry) {
|
|
689
694
|
directoryListCache.set(cacheKey, entry);
|
|
@@ -128,6 +128,10 @@ export declare class UnknownBranchError extends Error {
|
|
|
128
128
|
cwd: string;
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
|
+
export declare class InvalidGitBranchNameError extends Error {
|
|
132
|
+
readonly branchName: string;
|
|
133
|
+
constructor(branchName: string);
|
|
134
|
+
}
|
|
131
135
|
export type ReadPaseoConfigResult = {
|
|
132
136
|
ok: true;
|
|
133
137
|
config: PaseoConfig | null;
|
|
@@ -55,6 +55,13 @@ export class UnknownBranchError extends Error {
|
|
|
55
55
|
this.cwd = params.cwd;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
export class InvalidGitBranchNameError extends Error {
|
|
59
|
+
constructor(branchName) {
|
|
60
|
+
super(`Invalid branch name: Git rejected ref name '${branchName}'`);
|
|
61
|
+
this.name = "InvalidGitBranchNameError";
|
|
62
|
+
this.branchName = branchName;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
58
65
|
export function readPaseoConfig(repoRoot) {
|
|
59
66
|
try {
|
|
60
67
|
const json = readPaseoConfigJson(repoRoot);
|
|
@@ -898,7 +905,7 @@ async function resolveWorktreeSourcePlan({ cwd, source, desiredSlug, }) {
|
|
|
898
905
|
};
|
|
899
906
|
}
|
|
900
907
|
case "checkout-branch": {
|
|
901
|
-
|
|
908
|
+
await validateExistingWorktreeBranchName(cwd, source.branchName);
|
|
902
909
|
if (!(await localBranchExists(cwd, source.branchName))) {
|
|
903
910
|
try {
|
|
904
911
|
await runGitCommand(["fetch", "origin", `${source.branchName}:${source.branchName}`], {
|
|
@@ -921,7 +928,7 @@ async function resolveWorktreeSourcePlan({ cwd, source, desiredSlug, }) {
|
|
|
921
928
|
}
|
|
922
929
|
case "checkout-github-pr": {
|
|
923
930
|
const localBranchCandidate = source.localBranchName ?? source.headRef;
|
|
924
|
-
|
|
931
|
+
await validateExistingWorktreeBranchName(cwd, localBranchCandidate);
|
|
925
932
|
const localBranchName = await resolveUniqueLocalBranchName(cwd, localBranchCandidate);
|
|
926
933
|
const normalizedBaseRefName = normalizeRequiredBaseBranch(source.baseRefName);
|
|
927
934
|
await runGitCommand([
|
|
@@ -966,6 +973,16 @@ function validateWorktreeBranchName(branchName) {
|
|
|
966
973
|
throw new Error(`Invalid branch name: ${validation.error}`);
|
|
967
974
|
}
|
|
968
975
|
}
|
|
976
|
+
async function validateExistingWorktreeBranchName(cwd, branchName) {
|
|
977
|
+
const result = await runGitCommand(["check-ref-format", "--branch", branchName], {
|
|
978
|
+
cwd,
|
|
979
|
+
timeout: 30000,
|
|
980
|
+
acceptExitCodes: [0, 1, 128],
|
|
981
|
+
});
|
|
982
|
+
if (result.exitCode !== 0) {
|
|
983
|
+
throw new InvalidGitBranchNameError(branchName);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
969
986
|
function normalizeRequiredBaseBranch(baseBranch) {
|
|
970
987
|
const normalizedBaseBranch = normalizeBaseRefName(baseBranch);
|
|
971
988
|
if (!normalizedBaseBranch) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpaseo/server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.91-beta.2",
|
|
4
4
|
"description": "Paseo backend server",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/server",
|
|
@@ -59,10 +59,10 @@
|
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@agentclientprotocol/sdk": "^0.17.1",
|
|
61
61
|
"@anthropic-ai/claude-agent-sdk": "^0.2.133",
|
|
62
|
-
"@getpaseo/client": "0.1.
|
|
63
|
-
"@getpaseo/highlight": "0.1.
|
|
64
|
-
"@getpaseo/protocol": "0.1.
|
|
65
|
-
"@getpaseo/relay": "0.1.
|
|
62
|
+
"@getpaseo/client": "0.1.91-beta.2",
|
|
63
|
+
"@getpaseo/highlight": "0.1.91-beta.2",
|
|
64
|
+
"@getpaseo/protocol": "0.1.91-beta.2",
|
|
65
|
+
"@getpaseo/relay": "0.1.91-beta.2",
|
|
66
66
|
"@isaacs/ttlcache": "^2.1.4",
|
|
67
67
|
"@modelcontextprotocol/sdk": "^1.20.1",
|
|
68
68
|
"@opencode-ai/sdk": "1.14.46",
|