huskies: merge 949
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* 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 },
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user