paseo-smart-session 3.5.0 → 3.6.0
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/README.md +1 -1
- package/hooks/ask.mjs +10 -5
- package/hooks/asks.mjs +2 -164
- package/hooks/context-threshold.mjs +4 -1
- package/hooks/context.mjs +2 -247
- package/hooks/pointer.mjs +2 -149
- package/index.server.ts +30 -3
- package/mcp.mjs +49 -468
- package/package.json +3 -2
- package/server/agent-tools.d.mts +15 -0
- package/server/agent-tools.mjs +472 -0
- package/server/hooklib/asks.mjs +163 -0
- package/server/hooklib/context.mjs +284 -0
- package/server/hooklib/pointer.mjs +149 -0
- package/server/install-on-load.ts +15 -1
- package/server/mcp-registrations.ts +126 -0
- package/server/native-tools.ts +60 -0
- package/server/session-mcp.ts +54 -17
- package/shared/chat.ts +6 -2
package/server/session-mcp.ts
CHANGED
|
@@ -1,26 +1,63 @@
|
|
|
1
|
-
import type { PluginServerContext } from "@getpaseo/plugin/server";
|
|
1
|
+
import type { PluginServerContext, PluginSessionOpenRequest } from "@getpaseo/plugin/server";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
5
|
import { homedir } from "node:os";
|
|
3
6
|
import { join } from "node:path";
|
|
4
7
|
import { mcpDefinition, resolvePluginDir } from "./install.ts";
|
|
8
|
+
import { type Invoke, nativeTools, nativeToolsAvailable } from "./native-tools.ts";
|
|
5
9
|
import { readSettings } from "./settings.ts";
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
const paseoHome = () => process.env.PASEO_HOME ?? join(homedir(), ".paseo");
|
|
12
|
+
|
|
13
|
+
async function paseoConfig(): Promise<Record<string, any> | null> {
|
|
14
|
+
try { return JSON.parse(await readFile(join(paseoHome(), "config.json"), "utf8")); } catch { return null; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Providers whose sessions get the tools. A test harness may widen it to its fixture provider. */
|
|
18
|
+
const providers = () => (process.env.SMART_SESSION_TOOL_PROVIDERS ?? "claude,codex").split(",").map((name) => name.trim());
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The agent tools are a launch contribution, so nothing global is written. On Paseo 0.15+ they go
|
|
22
|
+
* on `request.tools` and the daemon serves them through the agent's own Paseo MCP; otherwise this
|
|
23
|
+
* launch alone gets `mcp.mjs` as a stdio server. `SMART_SESSION_TOOLS` tells the hooks which names
|
|
24
|
+
* the agent has (`smart_checkpoint` or `checkpoint`).
|
|
25
|
+
*/
|
|
26
|
+
export function contributeSessionMcp(server: PluginServerContext, invoke: Invoke) {
|
|
27
|
+
// A reload or update detaches native tools from open sessions until each reopens. This worker's instance, and the
|
|
28
|
+
// instance that attached each session, let the hooks tell a detached session how to reach the tools meanwhile
|
|
29
|
+
// (hooks/context.mjs toolsMode). Written synchronously, before any session can open.
|
|
30
|
+
const instance = randomUUID();
|
|
31
|
+
const data = join(paseoHome(), "plugin-data", "smart-session");
|
|
32
|
+
try {
|
|
33
|
+
mkdirSync(join(data, "tools"), { recursive: true });
|
|
34
|
+
writeFileSync(join(data, `tools-instance.json.${instance}`), JSON.stringify({ instance }));
|
|
35
|
+
renameSync(join(data, `tools-instance.json.${instance}`), join(data, "tools-instance.json"));
|
|
36
|
+
} catch { /* Without it the hooks assume the tools are attached. */ }
|
|
9
37
|
return server.before("agent.session_open", async ({ request }) => {
|
|
10
|
-
if (request.purpose !== "interactive" || !
|
|
38
|
+
if (request.purpose !== "interactive" || !providers().includes(request.provider)
|
|
11
39
|
|| request.labels["plugin-tools/enabled"] === "false" || !(await readSettings()).enabled) return;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
mcpServers: { ...request.mcpServers, "smart-session": { ...definition, env: {
|
|
18
|
-
...definition.env, PASEO_AGENT_ID: request.agentId,
|
|
19
|
-
PASEO_HOME: process.env.PASEO_HOME ?? join(homedir(), ".paseo"), SMART_SESSION_MCP_SCOPE: "paseo",
|
|
20
|
-
...(process.env.PASEO_DAEMON_URL ? { PASEO_DAEMON_URL: process.env.PASEO_DAEMON_URL } : {}),
|
|
21
|
-
...(process.env.PASEO_PASSWORD ? { PASEO_PASSWORD: process.env.PASEO_PASSWORD } : {}),
|
|
22
|
-
...(process.env.PASEO_PASSWORD_FILE ? { PASEO_PASSWORD_FILE: process.env.PASEO_PASSWORD_FILE } : {}),
|
|
23
|
-
} } },
|
|
24
|
-
};
|
|
40
|
+
if (process.env.SMART_SESSION_FORCE_STDIO !== "1" && nativeToolsAvailable(request, await paseoConfig())) {
|
|
41
|
+
await writeFile(join(data, "tools", `native-${request.agentId.replace(/[^A-Za-z0-9_-]/g, "_")}.json`), JSON.stringify({ instance })).catch(() => undefined);
|
|
42
|
+
return { ...request, env: { ...request.env, SMART_SESSION_TOOLS: "native" }, tools: [...request.tools, ...nativeTools(invoke)] };
|
|
43
|
+
}
|
|
44
|
+
return withStdio(request);
|
|
25
45
|
});
|
|
26
46
|
}
|
|
47
|
+
|
|
48
|
+
async function withStdio(request: PluginSessionOpenRequest): Promise<PluginSessionOpenRequest | void> {
|
|
49
|
+
const directory = await resolvePluginDir();
|
|
50
|
+
if (!directory) return;
|
|
51
|
+
const definition = mcpDefinition(directory);
|
|
52
|
+
return {
|
|
53
|
+
...request,
|
|
54
|
+
env: { ...request.env, SMART_SESSION_TOOLS: "stdio" },
|
|
55
|
+
mcpServers: { ...request.mcpServers, "smart-session": { ...definition, env: {
|
|
56
|
+
...definition.env, PASEO_AGENT_ID: request.agentId,
|
|
57
|
+
PASEO_HOME: paseoHome(), SMART_SESSION_MCP_SCOPE: "paseo",
|
|
58
|
+
...(process.env.PASEO_DAEMON_URL ? { PASEO_DAEMON_URL: process.env.PASEO_DAEMON_URL } : {}),
|
|
59
|
+
...(process.env.PASEO_PASSWORD ? { PASEO_PASSWORD: process.env.PASEO_PASSWORD } : {}),
|
|
60
|
+
...(process.env.PASEO_PASSWORD_FILE ? { PASEO_PASSWORD_FILE: process.env.PASEO_PASSWORD_FILE } : {}),
|
|
61
|
+
} } },
|
|
62
|
+
};
|
|
63
|
+
}
|
package/shared/chat.ts
CHANGED
|
@@ -31,9 +31,13 @@ export const PromptCardSchema = z.object({
|
|
|
31
31
|
});
|
|
32
32
|
export type PromptCard = z.infer<typeof PromptCardSchema>;
|
|
33
33
|
|
|
34
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Claude records mcp__smart-session__context_status and Codex smart-session.context_status from the
|
|
36
|
+
* stdio server; served natively through Paseo's MCP they are mcp__paseo__smart_context_status and
|
|
37
|
+
* paseo.smart_context_status.
|
|
38
|
+
*/
|
|
35
39
|
export function smartSessionTool(name: string): SmartSessionTool | null {
|
|
36
|
-
const match = /^(?:mcp__)?smart-session(?:__|\.|\/|:)([a-z_]+)$/.exec(name);
|
|
40
|
+
const match = /^(?:mcp__)?(?:smart-session(?:__|\.|\/|:)|paseo(?:__|\.|\/|:)smart_)([a-z_]+)$/.exec(name);
|
|
37
41
|
return match && (SMART_SESSION_TOOLS as readonly string[]).includes(match[1]!) ? (match[1] as SmartSessionTool) : null;
|
|
38
42
|
}
|
|
39
43
|
|