Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions nodejs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"zod": "^4.3.6"
},
"devDependencies": {
"@platformatic/vfs": "^0.3.0",
"@types/node": "^25.2.0",
"@typescript-eslint/eslint-plugin": "^8.54.0",
"@typescript-eslint/parser": "^8.54.0",
Expand Down
34 changes: 32 additions & 2 deletions nodejs/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
StreamMessageReader,
StreamMessageWriter,
} from "vscode-jsonrpc/node.js";
import { createServerRpc } from "./generated/rpc.js";
import { createServerRpc, registerClientSessionApiHandlers } from "./generated/rpc.js";
import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
import { CopilotSession, NO_RESULT_PERMISSION_V2_ERROR } from "./session.js";
import { getTraceContext } from "./telemetry.js";
Expand All @@ -40,6 +40,7 @@ import type {
SessionConfig,
SessionContext,
SessionEvent,
SessionFsConfig,
SessionLifecycleEvent,
SessionLifecycleEventType,
SessionLifecycleHandler,
Expand Down Expand Up @@ -216,6 +217,7 @@ export class CopilotClient {
| "onListModels"
| "telemetry"
| "onGetTraceContext"
| "sessionFs"
>
> & {
cliPath?: string;
Expand All @@ -238,6 +240,8 @@ export class CopilotClient {
private _rpc: ReturnType<typeof createServerRpc> | null = null;
private processExitPromise: Promise<never> | null = null; // Rejects when CLI process exits
private negotiatedProtocolVersion: number | null = null;
/** Connection-level session filesystem config, set via constructor option. */
private sessionFsConfig: SessionFsConfig | null = null;

/**
* Typed server-scoped RPC methods.
Expand Down Expand Up @@ -307,6 +311,7 @@ export class CopilotClient {

this.onListModels = options.onListModels;
this.onGetTraceContext = options.onGetTraceContext;
this.sessionFsConfig = options.sessionFs ?? null;

const effectiveEnv = options.env ?? process.env;
this.options = {
Expand Down Expand Up @@ -399,6 +404,15 @@ export class CopilotClient {
// Verify protocol version compatibility
await this.verifyProtocolVersion();

// If a session filesystem provider was configured, register it
if (this.sessionFsConfig) {
await this.connection!.sendRequest("sessionFs.setProvider", {
initialCwd: this.sessionFsConfig.initialCwd,
sessionStatePath: this.sessionFsConfig.sessionStatePath,
conventions: this.sessionFsConfig.conventions,
});
}

this.state = "connected";
} catch (error) {
this.state = "error";
Expand Down Expand Up @@ -663,6 +677,9 @@ export class CopilotClient {
session.on(config.onEvent);
}
this.sessions.set(sessionId, session);
if (this.sessionFsConfig) {
session.clientSessionApis.sessionFs = this.sessionFsConfig.createHandler(session);
}

try {
const response = await this.connection!.sendRequest("session.create", {
Expand Down Expand Up @@ -785,6 +802,9 @@ export class CopilotClient {
session.on(config.onEvent);
}
this.sessions.set(sessionId, session);
if (this.sessionFsConfig) {
session.clientSessionApis.sessionFs = this.sessionFsConfig.createHandler(session);
}

try {
const response = await this.connection!.sendRequest("session.resume", {
Expand Down Expand Up @@ -1069,7 +1089,9 @@ export class CopilotClient {
throw new Error("Client not connected");
}

const response = await this.connection.sendRequest("session.list", { filter });
const response = await this.connection.sendRequest("session.list", {
filter,
});
const { sessions } = response as {
sessions: Array<{
sessionId: string;
Expand Down Expand Up @@ -1562,6 +1584,14 @@ export class CopilotClient {
await this.handleSystemMessageTransform(params)
);

// Register client session API handlers.
const sessions = this.sessions;
registerClientSessionApiHandlers(this.connection, (sessionId) => {
const session = sessions.get(sessionId);
if (!session) throw new Error(`No session found for sessionId: ${sessionId}`);
return session.clientSessionApis;
});

this.connection.onClose(() => {
this.state = "disconnected";
});
Expand Down
Loading
Loading