@omercnet/paseo-context-mode 3.1.1-next.353.1 → 3.1.1
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/index.server.ts +1 -1
- package/package.json +1 -1
- package/server/actions.ts +15 -23
- package/server/binary.ts +16 -37
- package/server/handlers.ts +18 -25
- package/server/integration.ts +2 -2
- package/server/knowledge.ts +6 -8
- package/server/mcp-process.ts +1 -4
package/index.server.ts
CHANGED
|
@@ -45,7 +45,7 @@ export default function contribute(server: PluginServerContext) {
|
|
|
45
45
|
server.before("agent.create", async ({ request }, { paseo }) => {
|
|
46
46
|
const current = await settings.read();
|
|
47
47
|
if (current.status !== "ready") return request;
|
|
48
|
-
const binary = await resolveContextModeBinary(current.values
|
|
48
|
+
const binary = await resolveContextModeBinary(current.values);
|
|
49
49
|
if (binary.state !== "found") return request;
|
|
50
50
|
const providers = await readProviderOverrides(paseo);
|
|
51
51
|
return injectContextModeOnCreate(request, current.values, binary.launch, { providers });
|
package/package.json
CHANGED
package/server/actions.ts
CHANGED
|
@@ -6,9 +6,8 @@ import {
|
|
|
6
6
|
type DoctorReport,
|
|
7
7
|
type DoctorStatusRow,
|
|
8
8
|
} from "../shared/actions";
|
|
9
|
-
import type { contextModeSettings } from "../shared/settings";
|
|
9
|
+
import type { ContextModeSettings, contextModeSettings } from "../shared/settings";
|
|
10
10
|
import { type BinaryResolution, type LaunchDescriptor, resolveContextModeBinary } from "./binary";
|
|
11
|
-
import type { ProviderConfigSource } from "./integration";
|
|
12
11
|
import { contextModeEnvironmentFor, contextModePlatformFor } from "./knowledge";
|
|
13
12
|
import {
|
|
14
13
|
callContextModeTool,
|
|
@@ -29,7 +28,7 @@ type ActionToolCaller = (
|
|
|
29
28
|
|
|
30
29
|
export interface ActionHandlerDependencies {
|
|
31
30
|
osPlatform?: NodeJS.Platform;
|
|
32
|
-
resolveBinary?:
|
|
31
|
+
resolveBinary?: (settings: ContextModeSettings) => Promise<BinaryResolution>;
|
|
33
32
|
inspect?: (
|
|
34
33
|
launch: LaunchDescriptor,
|
|
35
34
|
dependencies?: McpProcessDependencies,
|
|
@@ -37,12 +36,10 @@ export interface ActionHandlerDependencies {
|
|
|
37
36
|
callTool?: ActionToolCaller;
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
type ActionContext = { paseo?: ProviderConfigSource };
|
|
41
|
-
|
|
42
39
|
export interface ContextModeActionHandlers {
|
|
43
|
-
doctor(input: ContextModeActionInput
|
|
44
|
-
install(input: ContextModeActionInput
|
|
45
|
-
upgrade(input: ContextModeActionInput
|
|
40
|
+
doctor(input: ContextModeActionInput): Promise<DoctorReport>;
|
|
41
|
+
install(input: ContextModeActionInput): Promise<ContextModeAction>;
|
|
42
|
+
upgrade(input: ContextModeActionInput): Promise<ContextModeAction>;
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
export function parseContextModeDoctorOutput(rawOutput: string): DoctorStatusRow[] {
|
|
@@ -74,24 +71,19 @@ export function createContextModeActionHandlers(
|
|
|
74
71
|
const callTool = dependencies.callTool ?? callContextModeTool;
|
|
75
72
|
const osPlatform = dependencies.osPlatform ?? process.platform;
|
|
76
73
|
|
|
77
|
-
async function resolvedBinary(
|
|
78
|
-
paseo: ProviderConfigSource | undefined,
|
|
79
|
-
): Promise<Extract<BinaryResolution, { state: "found" }>> {
|
|
74
|
+
async function resolvedBinary(): Promise<Extract<BinaryResolution, { state: "found" }>> {
|
|
80
75
|
const settings = await settingsHandle.read();
|
|
81
76
|
if (settings.status !== "ready") {
|
|
82
77
|
throw new Error(`Context Mode settings are invalid: ${settings.error}`.slice(0, 4_096));
|
|
83
78
|
}
|
|
84
|
-
const binary = await resolveBinary(settings.values
|
|
79
|
+
const binary = await resolveBinary(settings.values);
|
|
85
80
|
if (binary.state === "missing") throw new Error(binary.message.slice(0, 4_096));
|
|
86
81
|
return binary;
|
|
87
82
|
}
|
|
88
83
|
|
|
89
|
-
async function currentVersion(
|
|
90
|
-
input: ContextModeActionInput,
|
|
91
|
-
paseo: ProviderConfigSource | undefined,
|
|
92
|
-
): Promise<string | null> {
|
|
84
|
+
async function currentVersion(input: ContextModeActionInput): Promise<string | null> {
|
|
93
85
|
try {
|
|
94
|
-
const binary = await resolvedBinary(
|
|
86
|
+
const binary = await resolvedBinary();
|
|
95
87
|
const inspection = await inspect(binary.launch, {
|
|
96
88
|
env: contextModeEnvironmentFor(input.provider),
|
|
97
89
|
});
|
|
@@ -102,8 +94,8 @@ export function createContextModeActionHandlers(
|
|
|
102
94
|
}
|
|
103
95
|
|
|
104
96
|
return {
|
|
105
|
-
async doctor(input
|
|
106
|
-
const binary = await resolvedBinary(
|
|
97
|
+
async doctor(input) {
|
|
98
|
+
const binary = await resolvedBinary();
|
|
107
99
|
const rawOutput = await callTool(
|
|
108
100
|
binary.launch,
|
|
109
101
|
"ctx_doctor",
|
|
@@ -118,7 +110,7 @@ export function createContextModeActionHandlers(
|
|
|
118
110
|
rawOutput,
|
|
119
111
|
};
|
|
120
112
|
},
|
|
121
|
-
async install(input
|
|
113
|
+
async install(input) {
|
|
122
114
|
const platform = contextModePlatformFor(input.provider);
|
|
123
115
|
return {
|
|
124
116
|
program: osPlatform === "win32" ? "npm.cmd" : "npm",
|
|
@@ -129,15 +121,15 @@ export function createContextModeActionHandlers(
|
|
|
129
121
|
"--no-audit",
|
|
130
122
|
"--no-fund",
|
|
131
123
|
],
|
|
132
|
-
currentVersion: await currentVersion(input
|
|
124
|
+
currentVersion: await currentVersion(input),
|
|
133
125
|
targetVersion: CONTEXT_MODE_TARGET_VERSION,
|
|
134
126
|
platform,
|
|
135
127
|
requiresRestart: true,
|
|
136
128
|
};
|
|
137
129
|
},
|
|
138
|
-
async upgrade(input
|
|
130
|
+
async upgrade(input) {
|
|
139
131
|
const platform = contextModePlatformFor(input.provider);
|
|
140
|
-
const binary = await resolvedBinary(
|
|
132
|
+
const binary = await resolvedBinary();
|
|
141
133
|
const inspection = await inspect(binary.launch, {
|
|
142
134
|
env: contextModeEnvironmentFor(input.provider),
|
|
143
135
|
});
|
package/server/binary.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { constants } from "node:fs";
|
|
2
|
-
import { access,
|
|
2
|
+
import { access, realpath, stat } from "node:fs/promises";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { join, posix, win32 } from "node:path";
|
|
5
5
|
import type { ContextModeSettings } from "../shared";
|
|
6
|
-
import type { ProviderConfigSource } from "./integration";
|
|
7
6
|
|
|
8
7
|
export interface LaunchDescriptor {
|
|
9
8
|
program: string;
|
|
10
9
|
args: string[];
|
|
11
|
-
env?: Record<string, string>;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
export type BinaryResolution =
|
|
@@ -24,32 +22,9 @@ export interface BinaryResolutionDependencies {
|
|
|
24
22
|
env?: NodeJS.ProcessEnv;
|
|
25
23
|
platform?: NodeJS.Platform;
|
|
26
24
|
nodePath?: string;
|
|
27
|
-
electron?: boolean;
|
|
28
25
|
canExecute?: (path: string) => Promise<boolean>;
|
|
29
26
|
isFile?: (path: string) => Promise<boolean>;
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Paseo evaluates the server bundle from the daemon's cwd with an empty `import.meta`, so the
|
|
35
|
-
* bundled runtime is resolved from this plugin's directory in the daemon config instead.
|
|
36
|
-
*/
|
|
37
|
-
async function findBundledCli(paseo: ProviderConfigSource | undefined): Promise<string | null> {
|
|
38
|
-
const { config } = (await paseo?.config.get().catch(() => undefined)) ?? {};
|
|
39
|
-
const plugins = config?.plugins;
|
|
40
|
-
if (typeof plugins !== "object" || plugins === null) return null;
|
|
41
|
-
for (const source of Object.values(plugins)) {
|
|
42
|
-
const directory = (source as { path?: unknown } | null)?.path;
|
|
43
|
-
if (typeof directory !== "string") continue;
|
|
44
|
-
try {
|
|
45
|
-
const manifest = JSON.parse(await readFile(join(directory, "paseo-plugin.json"), "utf8"));
|
|
46
|
-
if (manifest?.id !== "context-mode") continue;
|
|
47
|
-
return createRequire(join(directory, "package.json")).resolve("context-mode/cli");
|
|
48
|
-
} catch {
|
|
49
|
-
// Not this plugin, or its install has no bundled runtime.
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return null;
|
|
27
|
+
bundledCliPath?: () => string | null;
|
|
53
28
|
}
|
|
54
29
|
|
|
55
30
|
async function defaultIsFile(path: string): Promise<boolean> {
|
|
@@ -166,21 +141,25 @@ export async function resolveContextModeBinary(
|
|
|
166
141
|
}
|
|
167
142
|
}
|
|
168
143
|
|
|
169
|
-
const
|
|
170
|
-
|
|
144
|
+
const bundledCandidates: string[] = [];
|
|
145
|
+
const injectedBundledPath = dependencies.bundledCliPath?.();
|
|
146
|
+
if (injectedBundledPath) bundledCandidates.push(injectedBundledPath);
|
|
147
|
+
if (!dependencies.bundledCliPath) {
|
|
148
|
+
bundledCandidates.push(join(process.cwd(), "node_modules", "context-mode", "cli.bundle.mjs"));
|
|
149
|
+
try {
|
|
150
|
+
bundledCandidates.push(createRequire(import.meta.url).resolve("context-mode/cli"));
|
|
151
|
+
} catch {
|
|
152
|
+
// The plugin bundle may run outside the dependency tree; the cwd candidate remains valid.
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
for (const bundledCli of new Set(bundledCandidates)) {
|
|
156
|
+
if (!(await isFile(bundledCli))) continue;
|
|
171
157
|
const canonicalPath = await realpath(bundledCli).catch(() => bundledCli);
|
|
172
|
-
// Under the desktop app `nodePath` is Electron. Paseo strips this variable from agent
|
|
173
|
-
// environments, so an injected MCP server needs it to start as Node.
|
|
174
|
-
const electron = dependencies.electron ?? process.versions.electron !== undefined;
|
|
175
158
|
return {
|
|
176
159
|
state: "found",
|
|
177
160
|
path: canonicalPath,
|
|
178
161
|
source: "bundled",
|
|
179
|
-
launch: {
|
|
180
|
-
program: nodePath,
|
|
181
|
-
args: [canonicalPath],
|
|
182
|
-
...(electron ? { env: { ELECTRON_RUN_AS_NODE: "1" } } : {}),
|
|
183
|
-
},
|
|
162
|
+
launch: { program: nodePath, args: [canonicalPath] },
|
|
184
163
|
};
|
|
185
164
|
}
|
|
186
165
|
|
package/server/handlers.ts
CHANGED
|
@@ -42,7 +42,7 @@ function contextModeProbeOptions(env: NodeJS.ProcessEnv = process.env): ProbeOpt
|
|
|
42
42
|
|
|
43
43
|
export interface ContextModeHandlerDependencies {
|
|
44
44
|
now?: () => Date;
|
|
45
|
-
resolveBinary?:
|
|
45
|
+
resolveBinary?: (settings: ContextModeSettings) => Promise<BinaryResolution>;
|
|
46
46
|
inspect?: (launch: LaunchDescriptor, options: ProbeOptions) => Promise<McpInspection>;
|
|
47
47
|
callTool?: (
|
|
48
48
|
launch: LaunchDescriptor,
|
|
@@ -57,13 +57,14 @@ export interface ContextModeHandlerDependencies {
|
|
|
57
57
|
) => Promise<IntegrationAudit>;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
type HandlerContext = { paseo?: ProviderConfigSource };
|
|
61
|
-
|
|
62
60
|
export interface ContextModeHandlers {
|
|
63
|
-
status(input: ContextModeRefreshInput
|
|
64
|
-
doctor(input: ContextModeRefreshInput
|
|
65
|
-
stats(input: ContextModeRefreshInput
|
|
66
|
-
audit(
|
|
61
|
+
status(input: ContextModeRefreshInput): Promise<BinaryStatus>;
|
|
62
|
+
doctor(input: ContextModeRefreshInput): Promise<CommandReport>;
|
|
63
|
+
stats(input: ContextModeRefreshInput): Promise<CommandReport>;
|
|
64
|
+
audit(
|
|
65
|
+
input: ContextModeRefreshInput,
|
|
66
|
+
context?: { paseo?: ProviderConfigSource },
|
|
67
|
+
): Promise<IntegrationAudit>;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
interface CacheEntry<T> {
|
|
@@ -92,7 +93,7 @@ export function createContextModeHandlers(
|
|
|
92
93
|
const cache = new Map<string, CacheEntry<BinaryStatus | CommandReport>>();
|
|
93
94
|
const probe = contextModeProbeOptions();
|
|
94
95
|
|
|
95
|
-
async function settingsAndBinary(
|
|
96
|
+
async function settingsAndBinary(): Promise<
|
|
96
97
|
| {
|
|
97
98
|
state: "ready";
|
|
98
99
|
settings: ContextModeSettings;
|
|
@@ -114,7 +115,7 @@ export function createContextModeHandlers(
|
|
|
114
115
|
},
|
|
115
116
|
};
|
|
116
117
|
}
|
|
117
|
-
const binary = await resolveBinary(settings.values
|
|
118
|
+
const binary = await resolveBinary(settings.values);
|
|
118
119
|
if (binary.state === "missing") {
|
|
119
120
|
return {
|
|
120
121
|
state: "unavailable",
|
|
@@ -158,11 +159,8 @@ export function createContextModeHandlers(
|
|
|
158
159
|
return result;
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
async function status(
|
|
162
|
-
|
|
163
|
-
context?: HandlerContext,
|
|
164
|
-
): Promise<BinaryStatus> {
|
|
165
|
-
const resolved = await settingsAndBinary(context?.paseo);
|
|
162
|
+
async function status({ fresh }: ContextModeRefreshInput): Promise<BinaryStatus> {
|
|
163
|
+
const resolved = await settingsAndBinary();
|
|
166
164
|
if (resolved.state === "unavailable") return resolved.report;
|
|
167
165
|
const cacheKey = `status:${resolved.binary.source}:${resolved.binary.path}`;
|
|
168
166
|
return cached(cacheKey, 10_000, fresh, async () => {
|
|
@@ -184,13 +182,8 @@ export function createContextModeHandlers(
|
|
|
184
182
|
});
|
|
185
183
|
}
|
|
186
184
|
|
|
187
|
-
async function report(
|
|
188
|
-
|
|
189
|
-
ttlMs: number,
|
|
190
|
-
fresh: boolean,
|
|
191
|
-
context: HandlerContext | undefined,
|
|
192
|
-
): Promise<CommandReport> {
|
|
193
|
-
const resolved = await settingsAndBinary(context?.paseo);
|
|
185
|
+
async function report(name: ToolName, ttlMs: number, fresh: boolean): Promise<CommandReport> {
|
|
186
|
+
const resolved = await settingsAndBinary();
|
|
194
187
|
if (resolved.state === "unavailable") return resolved.report;
|
|
195
188
|
return cached(`${name}:${resolved.binary.path}`, ttlMs, fresh, async () => {
|
|
196
189
|
const checkedAt = now().toISOString();
|
|
@@ -209,9 +202,9 @@ export function createContextModeHandlers(
|
|
|
209
202
|
|
|
210
203
|
async function audit(
|
|
211
204
|
_input: ContextModeRefreshInput,
|
|
212
|
-
context?:
|
|
205
|
+
context?: { paseo?: ProviderConfigSource },
|
|
213
206
|
): Promise<IntegrationAudit> {
|
|
214
|
-
const resolved = await settingsAndBinary(
|
|
207
|
+
const resolved = await settingsAndBinary();
|
|
215
208
|
if (resolved.state === "unavailable") {
|
|
216
209
|
return {
|
|
217
210
|
runtimePath: "",
|
|
@@ -234,8 +227,8 @@ export function createContextModeHandlers(
|
|
|
234
227
|
|
|
235
228
|
return {
|
|
236
229
|
status,
|
|
237
|
-
doctor: ({ fresh }
|
|
238
|
-
stats: ({ fresh }
|
|
230
|
+
doctor: ({ fresh }) => report("ctx_doctor", 10_000, fresh),
|
|
231
|
+
stats: ({ fresh }) => report("ctx_stats", 5_000, fresh),
|
|
239
232
|
audit,
|
|
240
233
|
};
|
|
241
234
|
}
|
package/server/integration.ts
CHANGED
|
@@ -63,7 +63,7 @@ export type ProviderOverrides = Readonly<
|
|
|
63
63
|
|
|
64
64
|
/** Structural slice of the hook/RPC `paseo` API; avoids a client-package import. */
|
|
65
65
|
export interface ProviderConfigSource {
|
|
66
|
-
config: { get(): Promise<{ config: { providers?: unknown
|
|
66
|
+
config: { get(): Promise<{ config: { providers?: unknown } }> };
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
/**
|
|
@@ -483,7 +483,7 @@ export async function injectContextModeOnCreate<T extends CreateRequest>(
|
|
|
483
483
|
type: "stdio",
|
|
484
484
|
command: launch.program,
|
|
485
485
|
args: launch.args,
|
|
486
|
-
env:
|
|
486
|
+
env: serverEnvironment(policy, storageRoot, request.env),
|
|
487
487
|
};
|
|
488
488
|
return {
|
|
489
489
|
...request,
|
package/server/knowledge.ts
CHANGED
|
@@ -10,8 +10,8 @@ import type {
|
|
|
10
10
|
PurgeKnowledgeInput,
|
|
11
11
|
SearchKnowledgeInput,
|
|
12
12
|
} from "../shared/knowledge";
|
|
13
|
-
import type { contextModeSettings } from "../shared/settings";
|
|
14
|
-
import { type LaunchDescriptor, resolveContextModeBinary } from "./binary";
|
|
13
|
+
import type { ContextModeSettings, contextModeSettings } from "../shared/settings";
|
|
14
|
+
import { type BinaryResolution, type LaunchDescriptor, resolveContextModeBinary } from "./binary";
|
|
15
15
|
import {
|
|
16
16
|
contextModeStorageRootFor,
|
|
17
17
|
type ProviderConfigSource,
|
|
@@ -37,7 +37,7 @@ type KnowledgeToolCaller = (
|
|
|
37
37
|
|
|
38
38
|
export interface KnowledgeHandlerDependencies {
|
|
39
39
|
now?: () => Date;
|
|
40
|
-
resolveBinary?:
|
|
40
|
+
resolveBinary?: (settings: ContextModeSettings) => Promise<BinaryResolution>;
|
|
41
41
|
callTool?: KnowledgeToolCaller;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -99,14 +99,12 @@ export function createContextModeKnowledgeHandlers(
|
|
|
99
99
|
const resolveBinary = dependencies.resolveBinary ?? resolveContextModeBinary;
|
|
100
100
|
const callTool = dependencies.callTool ?? callContextModeTool;
|
|
101
101
|
|
|
102
|
-
async function launchDescriptor(
|
|
103
|
-
paseo: ProviderConfigSource | undefined,
|
|
104
|
-
): Promise<LaunchDescriptor> {
|
|
102
|
+
async function launchDescriptor(): Promise<LaunchDescriptor> {
|
|
105
103
|
const settings = await settingsHandle.read();
|
|
106
104
|
if (settings.status !== "ready") {
|
|
107
105
|
throw new Error(`Context Mode settings are invalid: ${settings.error}`.slice(0, 4_096));
|
|
108
106
|
}
|
|
109
|
-
const binary = await resolveBinary(settings.values
|
|
107
|
+
const binary = await resolveBinary(settings.values);
|
|
110
108
|
if (binary.state === "missing") throw new Error(binary.message.slice(0, 4_096));
|
|
111
109
|
return binary.launch;
|
|
112
110
|
}
|
|
@@ -119,7 +117,7 @@ export function createContextModeKnowledgeHandlers(
|
|
|
119
117
|
context: KnowledgeContext | undefined,
|
|
120
118
|
environmentOverrides: NodeJS.ProcessEnv = {},
|
|
121
119
|
): Promise<KnowledgeToolResult> {
|
|
122
|
-
const launch = await launchDescriptor(
|
|
120
|
+
const launch = await launchDescriptor();
|
|
123
121
|
const providers = await readProviderOverrides(context?.paseo);
|
|
124
122
|
const output = await callTool(launch, name, arguments_, {
|
|
125
123
|
env: {
|
package/server/mcp-process.ts
CHANGED
|
@@ -125,10 +125,7 @@ async function exchange(
|
|
|
125
125
|
stdio: ["pipe", "pipe", "pipe"],
|
|
126
126
|
windowsHide: true,
|
|
127
127
|
cwd: dependencies.cwd,
|
|
128
|
-
env:
|
|
129
|
-
launch.env || dependencies.env
|
|
130
|
-
? { ...process.env, ...launch.env, ...dependencies.env }
|
|
131
|
-
: undefined,
|
|
128
|
+
env: dependencies.env ? { ...process.env, ...dependencies.env } : undefined,
|
|
132
129
|
});
|
|
133
130
|
} catch (error) {
|
|
134
131
|
throw new ProcessFailure(
|