248 lines
6.7 KiB
TypeScript
248 lines
6.7 KiB
TypeScript
|
|
/**
|
||
|
|
* Frontend mirror of the Rust typed RPC contract in
|
||
|
|
* `server/src/crdt_sync/rpc_contract.rs`.
|
||
|
|
*
|
||
|
|
* Every typed write method declared on the backend has matching TypeScript
|
||
|
|
* params/result types here. The `CONTRACT_FIXTURES` table also exposes the
|
||
|
|
* same canonical example payloads as the Rust `CONTRACT_METHODS` slice — the
|
||
|
|
* `rpcContract.test.ts` test compares them against the committed
|
||
|
|
* `rpcContract.snapshot.json` that the Rust test regenerates. If the Rust
|
||
|
|
* shapes drift from the TS shapes, the snapshot drifts and one side fails in
|
||
|
|
* CI — surfacing the mismatch as a compile / test error instead of a runtime
|
||
|
|
* one.
|
||
|
|
*
|
||
|
|
* When adding a method on the backend:
|
||
|
|
* 1. Add the params + result type here.
|
||
|
|
* 2. Add the entry to `CONTRACT_FIXTURES` with a canonical example.
|
||
|
|
* 3. Re-run `UPDATE_RPC_CONTRACT_SNAPSHOT=1 cargo test` to refresh
|
||
|
|
* `rpcContract.snapshot.json`.
|
||
|
|
*/
|
||
|
|
|
||
|
|
// ── Params types ────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
/** Params for `model.set_preference`. */
|
||
|
|
export interface SetModelPreferenceParams {
|
||
|
|
model: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Params for `anthropic.set_api_key`. */
|
||
|
|
export interface SetAnthropicApiKeyParams {
|
||
|
|
api_key: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Params for `settings.put_editor`. */
|
||
|
|
export interface PutEditorParams {
|
||
|
|
editor_command: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Params for `settings.open_file`. */
|
||
|
|
export interface OpenFileParams {
|
||
|
|
path: string;
|
||
|
|
line: number | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Params for `project.open`. */
|
||
|
|
export interface OpenProjectParams {
|
||
|
|
path: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Params for `project.forget`. */
|
||
|
|
export interface ForgetProjectParams {
|
||
|
|
path: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Payload for `bot_config.save` (and result of `bot_config.get`). */
|
||
|
|
export interface BotConfigPayload {
|
||
|
|
transport: string | null;
|
||
|
|
enabled: boolean | null;
|
||
|
|
homeserver: string | null;
|
||
|
|
username: string | null;
|
||
|
|
password: string | null;
|
||
|
|
room_ids: string[] | null;
|
||
|
|
slack_bot_token: string | null;
|
||
|
|
slack_signing_secret: string | null;
|
||
|
|
slack_channel_ids: string[] | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Payload for `settings.put_project` (also returned by `settings.get_project`). */
|
||
|
|
export interface ProjectSettingsPayload {
|
||
|
|
default_qa: string;
|
||
|
|
default_coder_model: string | null;
|
||
|
|
max_coders: number | null;
|
||
|
|
max_retries: number;
|
||
|
|
base_branch: string | null;
|
||
|
|
rate_limit_notifications: boolean;
|
||
|
|
timezone: string | null;
|
||
|
|
rendezvous: string | null;
|
||
|
|
watcher_sweep_interval_secs: number;
|
||
|
|
watcher_done_retention_secs: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Result types ────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
/** Result envelope for write methods that simply succeed or fail. */
|
||
|
|
export interface OkResult {
|
||
|
|
ok: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Result for `settings.put_editor`. */
|
||
|
|
export interface EditorSettingsResult {
|
||
|
|
editor_command: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Result for `project.open`. */
|
||
|
|
export interface OpenProjectResult {
|
||
|
|
path: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Method → params/result mapping ──────────────────────────────────────────
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Compile-time mapping from typed RPC method name to its params + result
|
||
|
|
* shapes. Used by `callTypedRpc` to enforce that callers pass the right
|
||
|
|
* params and receive the right return type for a method.
|
||
|
|
*/
|
||
|
|
export interface TypedRpcMethods {
|
||
|
|
"model.set_preference": {
|
||
|
|
params: SetModelPreferenceParams;
|
||
|
|
result: OkResult;
|
||
|
|
};
|
||
|
|
"anthropic.set_api_key": {
|
||
|
|
params: SetAnthropicApiKeyParams;
|
||
|
|
result: OkResult;
|
||
|
|
};
|
||
|
|
"settings.put_editor": {
|
||
|
|
params: PutEditorParams;
|
||
|
|
result: EditorSettingsResult;
|
||
|
|
};
|
||
|
|
"settings.open_file": {
|
||
|
|
params: OpenFileParams;
|
||
|
|
result: OkResult;
|
||
|
|
};
|
||
|
|
"settings.put_project": {
|
||
|
|
params: ProjectSettingsPayload;
|
||
|
|
result: ProjectSettingsPayload;
|
||
|
|
};
|
||
|
|
"project.open": {
|
||
|
|
params: OpenProjectParams;
|
||
|
|
result: OpenProjectResult;
|
||
|
|
};
|
||
|
|
"project.close": {
|
||
|
|
params: Record<string, never>;
|
||
|
|
result: OkResult;
|
||
|
|
};
|
||
|
|
"project.forget": {
|
||
|
|
params: ForgetProjectParams;
|
||
|
|
result: OkResult;
|
||
|
|
};
|
||
|
|
"bot_config.save": {
|
||
|
|
params: BotConfigPayload;
|
||
|
|
result: BotConfigPayload;
|
||
|
|
};
|
||
|
|
"chat.cancel": {
|
||
|
|
params: Record<string, never>;
|
||
|
|
result: OkResult;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Union of all typed RPC method names declared in the contract. */
|
||
|
|
export type TypedRpcMethodName = keyof TypedRpcMethods;
|
||
|
|
|
||
|
|
// ── Canonical fixtures (mirror of Rust `CONTRACT_METHODS`) ──────────────────
|
||
|
|
|
||
|
|
/**
|
||
|
|
* One canonical example payload per typed RPC method. The shape *must*
|
||
|
|
* match the corresponding Rust `CONTRACT_METHODS` entry. Drift between this
|
||
|
|
* table and `rpcContract.snapshot.json` (regenerated by the Rust side) fails
|
||
|
|
* the `rpcContract.test.ts` snapshot check.
|
||
|
|
*/
|
||
|
|
export const CONTRACT_FIXTURES: {
|
||
|
|
[K in TypedRpcMethodName]: {
|
||
|
|
params: TypedRpcMethods[K]["params"];
|
||
|
|
result: TypedRpcMethods[K]["result"];
|
||
|
|
};
|
||
|
|
} = {
|
||
|
|
"model.set_preference": {
|
||
|
|
params: { model: "claude-sonnet-4-6" },
|
||
|
|
result: { ok: true },
|
||
|
|
},
|
||
|
|
"anthropic.set_api_key": {
|
||
|
|
params: { api_key: "sk-ant-..." },
|
||
|
|
result: { ok: true },
|
||
|
|
},
|
||
|
|
"settings.put_editor": {
|
||
|
|
params: { editor_command: "zed" },
|
||
|
|
result: { editor_command: "zed" },
|
||
|
|
},
|
||
|
|
"settings.open_file": {
|
||
|
|
params: { path: "src/main.rs", line: 42 },
|
||
|
|
result: { ok: true },
|
||
|
|
},
|
||
|
|
"settings.put_project": {
|
||
|
|
params: {
|
||
|
|
default_qa: "server",
|
||
|
|
default_coder_model: null,
|
||
|
|
max_coders: null,
|
||
|
|
max_retries: 2,
|
||
|
|
base_branch: null,
|
||
|
|
rate_limit_notifications: true,
|
||
|
|
timezone: null,
|
||
|
|
rendezvous: null,
|
||
|
|
watcher_sweep_interval_secs: 60,
|
||
|
|
watcher_done_retention_secs: 86_400,
|
||
|
|
},
|
||
|
|
result: {
|
||
|
|
default_qa: "server",
|
||
|
|
default_coder_model: null,
|
||
|
|
max_coders: null,
|
||
|
|
max_retries: 2,
|
||
|
|
base_branch: null,
|
||
|
|
rate_limit_notifications: true,
|
||
|
|
timezone: null,
|
||
|
|
rendezvous: null,
|
||
|
|
watcher_sweep_interval_secs: 60,
|
||
|
|
watcher_done_retention_secs: 86_400,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
"project.open": {
|
||
|
|
params: { path: "/path/to/project" },
|
||
|
|
result: { path: "/path/to/project" },
|
||
|
|
},
|
||
|
|
"project.close": {
|
||
|
|
params: {},
|
||
|
|
result: { ok: true },
|
||
|
|
},
|
||
|
|
"project.forget": {
|
||
|
|
params: { path: "/path/to/project" },
|
||
|
|
result: { ok: true },
|
||
|
|
},
|
||
|
|
"bot_config.save": {
|
||
|
|
params: {
|
||
|
|
transport: "matrix",
|
||
|
|
enabled: true,
|
||
|
|
homeserver: "https://matrix.example",
|
||
|
|
username: "bot",
|
||
|
|
password: "secret",
|
||
|
|
room_ids: ["!room:example"],
|
||
|
|
slack_bot_token: null,
|
||
|
|
slack_signing_secret: null,
|
||
|
|
slack_channel_ids: null,
|
||
|
|
},
|
||
|
|
result: {
|
||
|
|
transport: "matrix",
|
||
|
|
enabled: true,
|
||
|
|
homeserver: "https://matrix.example",
|
||
|
|
username: "bot",
|
||
|
|
password: "secret",
|
||
|
|
room_ids: ["!room:example"],
|
||
|
|
slack_bot_token: null,
|
||
|
|
slack_signing_secret: null,
|
||
|
|
slack_channel_ids: null,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
"chat.cancel": {
|
||
|
|
params: {},
|
||
|
|
result: { ok: true },
|
||
|
|
},
|
||
|
|
};
|