* fix(ui): enable save button only when config has changes The save button in the Control UI config editor was not properly gating on whether actual changes were made. This adds: - `configRawOriginal` state to track the original raw config for comparison - Change detection for both form mode (via computeDiff) and raw mode - `hasChanges` check in canSave/canApply logic - Set `configFormDirty` when raw mode edits occur - Handle raw mode UI correctly (badge shows "Unsaved changes", no diff panel) Fixes #1609 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(gateway-tool): add config.patch action for safe partial config updates Exposes the existing config.patch server method to agents, allowing safe partial config updates that merge with existing config instead of replacing it. - Add config.patch to GATEWAY_ACTIONS in gateway tool - Add restart + sentinel logic to config.patch server method - Extend ConfigPatchParamsSchema with sessionKey, note, restartDelayMs - Add unit test for config.patch gateway tool action Closes #1617 --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
import { Type } from "@sinclair/typebox";
|
|
|
|
import { NonEmptyString } from "./primitives.js";
|
|
|
|
export const ConfigGetParamsSchema = Type.Object({}, { additionalProperties: false });
|
|
|
|
export const ConfigSetParamsSchema = Type.Object(
|
|
{
|
|
raw: NonEmptyString,
|
|
baseHash: Type.Optional(NonEmptyString),
|
|
},
|
|
{ additionalProperties: false },
|
|
);
|
|
|
|
export const ConfigApplyParamsSchema = Type.Object(
|
|
{
|
|
raw: NonEmptyString,
|
|
baseHash: Type.Optional(NonEmptyString),
|
|
sessionKey: Type.Optional(Type.String()),
|
|
note: Type.Optional(Type.String()),
|
|
restartDelayMs: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
},
|
|
{ additionalProperties: false },
|
|
);
|
|
|
|
export const ConfigPatchParamsSchema = Type.Object(
|
|
{
|
|
raw: NonEmptyString,
|
|
baseHash: Type.Optional(NonEmptyString),
|
|
sessionKey: Type.Optional(Type.String()),
|
|
note: Type.Optional(Type.String()),
|
|
restartDelayMs: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
},
|
|
{ additionalProperties: false },
|
|
);
|
|
|
|
export const ConfigSchemaParamsSchema = Type.Object({}, { additionalProperties: false });
|
|
|
|
export const UpdateRunParamsSchema = Type.Object(
|
|
{
|
|
sessionKey: Type.Optional(Type.String()),
|
|
note: Type.Optional(Type.String()),
|
|
restartDelayMs: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
timeoutMs: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
},
|
|
{ additionalProperties: false },
|
|
);
|
|
|
|
export const ConfigUiHintSchema = Type.Object(
|
|
{
|
|
label: Type.Optional(Type.String()),
|
|
help: Type.Optional(Type.String()),
|
|
group: Type.Optional(Type.String()),
|
|
order: Type.Optional(Type.Integer()),
|
|
advanced: Type.Optional(Type.Boolean()),
|
|
sensitive: Type.Optional(Type.Boolean()),
|
|
placeholder: Type.Optional(Type.String()),
|
|
itemTemplate: Type.Optional(Type.Unknown()),
|
|
},
|
|
{ additionalProperties: false },
|
|
);
|
|
|
|
export const ConfigSchemaResponseSchema = Type.Object(
|
|
{
|
|
schema: Type.Unknown(),
|
|
uiHints: Type.Record(Type.String(), ConfigUiHintSchema),
|
|
version: NonEmptyString,
|
|
generatedAt: NonEmptyString,
|
|
},
|
|
{ additionalProperties: false },
|
|
);
|