diff --git a/README.md b/README.md index ddeb90f..5d018fc 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@

A local-first control center for AI extensions.
- Use, review, scan, and discover Skills, MCP servers, slash commands, and CLI tools across agent harnesses. + Use, review, scan, and discover Skills, MCP servers, slash commands, hooks, and CLI tools across agent harnesses.

@@ -40,6 +40,7 @@ AI extensions are scattered across harness-specific folders, MCP config files, s - Scan Skills with a saved LLM provider configuration and review findings before use. - Install or adopt MCP server configs, resolve differences, and enable them where supported. - Manage reusable slash commands once, then sync them to supported harnesses. +- Manage hooks as normalized records, then sync them into supported harness settings with drift detection and review for unmanaged entries. - Discover Skills, MCP servers, and preview-only CLI tools from marketplace sources. ## Product tour @@ -164,16 +165,22 @@ The npm wrapper downloads the native release artifact for the current platform a OpenClaw
Docs + + Antigravity CLI
+ Antigravity (agy)
+ Docs + -| Harness | Skills | MCP servers | Slash commands | -|---|---:|---:|---:| -| Codex CLI | Yes | Yes | Yes | -| Claude Code | Yes | Yes | Yes | -| Cursor | Yes | Yes | Yes | -| OpenCode | Yes | Yes | Yes | -| OpenClaw | Yes | Not Yet | Not Yet | +| Harness | Skills | MCP servers | Slash commands | Hooks | +|---|---:|---:|---:|---:| +| Codex CLI | Yes | Yes | Yes | Yes | +| Claude Code | Yes | Yes | Yes | Yes | +| Cursor | Yes | Yes | Yes | Yes | +| OpenCode | Yes | Yes | Yes | Partial | +| OpenClaw | Yes | Not Yet | Not Yet | Not Yet | +| Antigravity (agy) | Yes | Yes | Not Yet | Partial | ## Local-first safety @@ -191,6 +198,7 @@ Actions that can change local state include: - adopting an existing MCP config - enabling, disabling, resolving, or uninstalling an MCP server - creating, updating, syncing, importing, or deleting a slash command +- creating, enabling, disabling, resolving, or deleting a hook binding - changing harness support settings App-owned files live under `~/Library/Application Support/skill-manager` on macOS and XDG base directories on Linux. @@ -218,6 +226,7 @@ MCP servers are stored as normalized Skill Manager records, then translated into - Codex uses TOML under `mcp_servers`. - Claude Code and Cursor use `mcpServers` JSON entries. - OpenCode uses typed local/remote MCP entries. +- Antigravity (agy) uses `mcpServers` JSON entries with `serverUrl` for HTTP transports and `command`/`args`/`env` for stdio. - OpenClaw MCP writes are not yet supported. When Skill Manager finds different configs for the same MCP server, it asks you to resolve the source of truth first. @@ -232,10 +241,24 @@ Slash commands are stored as TOML records under Skill Manager app storage, then - Claude Code writes Markdown command files under `~/.claude/commands` and invokes them with `/`. - Cursor writes plain text command files under `~/.cursor/commands` and invokes them with `/`. - Codex writes prompt files under `~/.codex/prompts` and invokes them with `/prompts:`. -- OpenClaw slash command writes are not yet supported. +- OpenClaw and Antigravity (agy) slash command writes are not yet supported. Skill Manager tracks target ownership with sync state and content hashes. It will not overwrite an untracked command file automatically, and it reports managed files as changed or missing when the target no longer matches the last synced hash. Review actions let you adopt unmanaged commands, restore managed content, adopt a changed harness command as the new source, or remove a broken binding while leaving the harness file untouched. +### Hooks + +Hooks are stored as normalized Skill Manager records using **canonical events** (`pre_tool_use`, `post_tool_use`, `user_prompt_submit`, `session_start`, `stop`, `pre_compact`) and **canonical tool categories** (`shell`, `file_read`, `file_write`, `mcp`, `web`, `any`). Each harness codec translates a canonical record into that harness's native event names and config shape, and merges it into the harness's hook config: + +- Claude Code writes hook entries into `~/.claude/settings.json` under the `hooks` key. +- Codex writes inline `[hooks]` tables into `~/.codex/config.toml` (same event schema as Claude). +- Cursor writes `~/.cursor/hooks.json`, expressing each tool category as its dedicated event (`beforeShellExecution`, `afterFileEdit`, `beforeMCPExecution`, and so on). +- OpenCode writes `experimental.hook` entries in `opencode.json` — limited to `file_edited` (post-edit on write) and `session_completed` (stop), so coverage is partial. +- Antigravity (agy) writes a name-keyed `~/.gemini/config/hooks.json`, matching against its own tool names (`run_command`, `view_file`, …); it covers tool, stop, and (via `PreInvocation`) prompt-submit hooks, so coverage is partial. + +Because harnesses differ, not every canonical event maps to every harness. Skill Manager exposes a **representability matrix** showing where each hook can sync and where it cannot, including caveats — for example, an Antigravity `user_prompt_submit` hook maps to `PreInvocation`, which fires before every model invocation rather than only on prompt submit. + +Skill Manager owns only the specific hook entries it writes. It merges into each harness's config without disturbing hooks or other keys it does not manage, and it tracks ownership with content hashes. When a managed hook is edited outside Skill Manager it is reported as drifted, and hooks found in a harness that Skill Manager does not manage are reported as unmanaged for review. + ### CLIs CLI marketplace entries are preview-only. @@ -248,6 +271,7 @@ Useful macOS paths: - shared skills store: `~/Library/Application Support/skill-manager/shared` - MCP manifest: `~/Library/Application Support/skill-manager/mcp/manifest.json` +- hooks manifest: `~/Library/Application Support/skill-manager/hooks/manifest.json` - slash command library: `~/Library/Application Support/skill-manager/slash-commands/commands` - slash command sync state: `~/Library/Application Support/skill-manager/slash-commands/sync-state.json` - marketplace cache: `~/Library/Application Support/skill-manager/marketplace` @@ -258,6 +282,7 @@ Useful Linux paths: - shared skills store: `${XDG_DATA_HOME:-~/.local/share}/skill-manager/shared` - MCP manifest: `${XDG_DATA_HOME:-~/.local/share}/skill-manager/mcp/manifest.json` +- hooks manifest: `${XDG_DATA_HOME:-~/.local/share}/skill-manager/hooks/manifest.json` - slash command library: `${XDG_DATA_HOME:-~/.local/share}/skill-manager/slash-commands/commands` - slash command sync state: `${XDG_DATA_HOME:-~/.local/share}/skill-manager/slash-commands/sync-state.json` - marketplace cache: `${XDG_DATA_HOME:-~/.local/share}/skill-manager/marketplace` @@ -273,6 +298,7 @@ Most users do not need to change these locations. If you manage skills in a cust | Cursor | `SKILL_MANAGER_CURSOR_ROOT` | `~/.cursor/skills` | | OpenCode | `SKILL_MANAGER_OPENCODE_ROOT` | `~/.config/opencode/skills` | | OpenClaw | `n/a` | `~/.openclaw/skills` | +| Antigravity (agy) | `SKILL_MANAGER_AGY_ROOT` | `~/.gemini/antigravity-cli/skills` | MCP config locations are harness-owned. Skill Manager writes only to verified config paths and skips unsupported harness writes. @@ -337,7 +363,7 @@ npm run build ### Extension families -- [ ] Hook support +- [x] Hook support - [x] Slash command support - [ ] Plugin support diff --git a/assets/harness-logos/agy-logo.svg b/assets/harness-logos/agy-logo.svg new file mode 100644 index 0000000..fe5fd4c --- /dev/null +++ b/assets/harness-logos/agy-logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d94b43d..266b368 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -21,6 +21,8 @@ const SlashCommandsPage = lazy(() => import("./features/slash-commands/screens/S const SlashCommandsReviewPage = lazy(() => import("./features/slash-commands/screens/SlashCommandsReviewPage")); const McpNeedsReviewPage = lazy(() => import("./features/mcp/screens/McpNeedsReviewPage")); const McpInUsePage = lazy(() => import("./features/mcp/screens/McpInUsePage")); +const HooksInUsePage = lazy(() => import("./features/hooks/screens/HooksInUsePage")); +const HooksNeedsReviewPage = lazy(() => import("./features/hooks/screens/HooksNeedsReviewPage")); export function App() { const [queryClient] = useState( @@ -105,6 +107,24 @@ function AppContent() { } /> } /> + } /> + }> + + + } + /> + }> + + + } + /> + ; export interface components { schemas: { + /** AddHookRequest */ + AddHookRequest: { + /** Command */ + command: string; + /** + * Description + * @default + */ + description: string; + /** Event */ + event: string; + /** Id */ + id: string; + /** Match */ + match?: string | null; + /** Timeout */ + timeout?: number | null; + }; /** AddMcpServerRequest */ AddMcpServerRequest: { /** Qualifiedname */ @@ -948,6 +1070,14 @@ export interface components { /** Provider */ provider: string; }; + /** DisableHookRequest */ + DisableHookRequest: { + /** + * Harness + * @description Harness identifier + */ + harness: string; + }; /** DisableMcpServerRequest */ DisableMcpServerRequest: { /** @@ -964,6 +1094,14 @@ export interface components { */ harness: string; }; + /** EnableHookRequest */ + EnableHookRequest: { + /** + * Harness + * @description Harness identifier + */ + harness: string; + }; /** EnableMcpServerRequest */ EnableMcpServerRequest: { /** Config */ @@ -1016,6 +1154,129 @@ export interface components { /** Logokey */ logoKey?: string | null; }; + /** HookApplyConfigResponse */ + HookApplyConfigResponse: { + /** Failed */ + failed: components["schemas"]["HookMutationFailureResponse"][]; + hook: components["schemas"]["HookSpecResponse"]; + /** Ok */ + ok: boolean; + /** Succeeded */ + succeeded: string[]; + }; + /** HookBindingResponse */ + HookBindingResponse: { + /** Caveat */ + caveat?: string | null; + /** Driftdetail */ + driftDetail?: string | null; + /** Harness */ + harness: string; + /** + * State + * @enum {string} + */ + state: "managed" | "drifted" | "unmanaged" | "missing" | "unsupported"; + }; + /** HookInventoryColumnResponse */ + HookInventoryColumnResponse: { + /** Configpresent */ + configPresent: boolean; + /** Harness */ + harness: string; + /** Hooksunavailablereason */ + hooksUnavailableReason?: string | null; + /** + * Hookswritable + * @default true + */ + hooksWritable: boolean; + /** Installed */ + installed: boolean; + /** Label */ + label: string; + /** Logokey */ + logoKey?: string | null; + }; + /** HookInventoryEntryResponse */ + HookInventoryEntryResponse: { + /** Canenable */ + canEnable: boolean; + /** Displayname */ + displayName: string; + /** + * Enabledstatus + * @enum {string} + */ + enabledStatus: "enabled" | "disabled"; + /** Id */ + id: string; + /** + * Kind + * @enum {string} + */ + kind: "managed" | "unmanaged"; + /** Sightings */ + sightings: components["schemas"]["HookBindingResponse"][]; + spec?: components["schemas"]["HookSpecResponse"] | null; + }; + /** HookInventoryIssueResponse */ + HookInventoryIssueResponse: { + /** Name */ + name: string; + /** Reason */ + reason: string; + }; + /** HookInventoryResponse */ + HookInventoryResponse: { + /** Columns */ + columns: components["schemas"]["HookInventoryColumnResponse"][]; + /** Entries */ + entries: components["schemas"]["HookInventoryEntryResponse"][]; + /** Issues */ + issues?: components["schemas"]["HookInventoryIssueResponse"][]; + }; + /** HookMutationFailureResponse */ + HookMutationFailureResponse: { + /** Error */ + error: string; + /** Harness */ + harness: string; + }; + /** HookMutationResponse */ + HookMutationResponse: { + hook: components["schemas"]["HookSpecResponse"]; + /** Ok */ + ok: boolean; + }; + /** HookSetHarnessesResultResponse */ + HookSetHarnessesResultResponse: { + /** Failed */ + failed: components["schemas"]["HookMutationFailureResponse"][]; + /** Ok */ + ok: boolean; + /** Succeeded */ + succeeded: string[]; + }; + /** HookSpecResponse */ + HookSpecResponse: { + /** Command */ + command: string; + /** Description */ + description: string; + /** Event */ + event: string; + /** Id */ + id: string; + /** Installedat */ + installedAt: string; + /** Match */ + match?: string | null; + /** Revision */ + revision: string; + /** Timeout */ + timeout?: number | null; + }; /** InstallMarketplaceSkillRequest */ InstallMarketplaceSkillRequest: { /** Installtoken */ @@ -1614,6 +1875,18 @@ export interface components { /** Ok */ ok: boolean; }; + /** ReconcileHookRequest */ + ReconcileHookRequest: { + /** Harnesses */ + harnesses?: string[] | null; + /** Observed harness */ + observedHarness?: string | null; + /** + * Sourcekind + * @enum {string} + */ + sourceKind: "managed" | "harness"; + }; /** ReconcileMcpServerRequest */ ReconcileMcpServerRequest: { /** Harnesses */ @@ -1874,6 +2147,14 @@ export interface components { /** Enabled */ enabled: boolean; }; + /** SetHookHarnessesRequest */ + SetHookHarnessesRequest: { + /** + * Target + * @enum {string} + */ + target: "enabled" | "disabled"; + }; /** SetMcpServerHarnessesRequest */ SetMcpServerHarnessesRequest: { /** Config */ @@ -2293,6 +2574,261 @@ export interface operations { }; }; }; + list_hooks_api_hooks_get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HookInventoryResponse"]; + }; + }; + }; + }; + create_hook_api_hooks_post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["AddHookRequest"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HookMutationResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + get_hook_api_hooks__id__get: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HookInventoryEntryResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + delete_hook_api_hooks__id__delete: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HookSetHarnessesResultResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + disable_hook_api_hooks__id__disable_post: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DisableHookRequest"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["OkResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + enable_hook_api_hooks__id__enable_post: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["EnableHookRequest"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["OkResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + reconcile_hook_api_hooks__id__reconcile_post: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ReconcileHookRequest"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HookApplyConfigResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + set_hook_harnesses_api_hooks__id__set_harnesses_post: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["SetHookHarnessesRequest"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HookSetHarnessesResultResponse"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; get_cli_marketplace_detail_api_marketplace_clis_items__slug__get: { parameters: { query?: never; diff --git a/frontend/src/api/openapi.json b/frontend/src/api/openapi.json index 2697179..293745c 100644 --- a/frontend/src/api/openapi.json +++ b/frontend/src/api/openapi.json @@ -1,6 +1,60 @@ { "components": { "schemas": { + "AddHookRequest": { + "additionalProperties": false, + "properties": { + "command": { + "minLength": 1, + "title": "Command", + "type": "string" + }, + "description": { + "default": "", + "title": "Description", + "type": "string" + }, + "event": { + "minLength": 1, + "title": "Event", + "type": "string" + }, + "id": { + "minLength": 1, + "title": "Id", + "type": "string" + }, + "match": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Match" + }, + "timeout": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Timeout" + } + }, + "required": [ + "id", + "event", + "command" + ], + "title": "AddHookRequest", + "type": "object" + }, "AddMcpServerRequest": { "additionalProperties": false, "properties": { @@ -491,6 +545,21 @@ "title": "DetectedProviderResponse", "type": "object" }, + "DisableHookRequest": { + "properties": { + "harness": { + "description": "Harness identifier", + "minLength": 1, + "title": "Harness", + "type": "string" + } + }, + "required": [ + "harness" + ], + "title": "DisableHookRequest", + "type": "object" + }, "DisableMcpServerRequest": { "properties": { "harness": { @@ -521,6 +590,21 @@ "title": "DisableSkillRequest", "type": "object" }, + "EnableHookRequest": { + "properties": { + "harness": { + "description": "Harness identifier", + "minLength": 1, + "title": "Harness", + "type": "string" + } + }, + "required": [ + "harness" + ], + "title": "EnableHookRequest", + "type": "object" + }, "EnableMcpServerRequest": { "properties": { "config": { @@ -655,23 +739,42 @@ "title": "HarnessColumnResponse", "type": "object" }, - "InstallMarketplaceSkillRequest": { + "HookApplyConfigResponse": { "properties": { - "installToken": { - "minLength": 1, - "title": "Installtoken", - "type": "string" + "failed": { + "items": { + "$ref": "#/components/schemas/HookMutationFailureResponse" + }, + "title": "Failed", + "type": "array" + }, + "hook": { + "$ref": "#/components/schemas/HookSpecResponse" + }, + "ok": { + "title": "Ok", + "type": "boolean" + }, + "succeeded": { + "items": { + "type": "string" + }, + "title": "Succeeded", + "type": "array" } }, "required": [ - "installToken" + "ok", + "hook", + "succeeded", + "failed" ], - "title": "InstallMarketplaceSkillRequest", + "title": "HookApplyConfigResponse", "type": "object" }, - "LLMDetectionResponse": { + "HookBindingResponse": { "properties": { - "defaultModel": { + "caveat": { "anyOf": [ { "type": "string" @@ -680,9 +783,9 @@ "type": "null" } ], - "title": "Defaultmodel" + "title": "Caveat" }, - "defaultProvider": { + "driftDetail": { "anyOf": [ { "type": "string" @@ -691,30 +794,42 @@ "type": "null" } ], - "title": "Defaultprovider" + "title": "Driftdetail" }, - "hasAnyAvailable": { - "title": "Hasanyavailable", - "type": "boolean" + "harness": { + "title": "Harness", + "type": "string" }, - "providers": { - "items": { - "$ref": "#/components/schemas/DetectedProviderResponse" - }, - "title": "Providers", - "type": "array" + "state": { + "enum": [ + "managed", + "drifted", + "unmanaged", + "missing", + "unsupported" + ], + "title": "State", + "type": "string" } }, "required": [ - "providers", - "hasAnyAvailable" + "harness", + "state" ], - "title": "LLMDetectionResponse", + "title": "HookBindingResponse", "type": "object" }, - "McpAdoptionIssueResponse": { + "HookInventoryColumnResponse": { "properties": { - "configPath": { + "configPresent": { + "title": "Configpresent", + "type": "boolean" + }, + "harness": { + "title": "Harness", + "type": "string" + }, + "hooksUnavailableReason": { "anyOf": [ { "type": "string" @@ -723,11 +838,16 @@ "type": "null" } ], - "title": "Configpath" + "title": "Hooksunavailablereason" }, - "harness": { - "title": "Harness", - "type": "string" + "hooksWritable": { + "default": true, + "title": "Hookswritable", + "type": "boolean" + }, + "installed": { + "title": "Installed", + "type": "boolean" }, "label": { "title": "Label", @@ -743,22 +863,81 @@ } ], "title": "Logokey" + } + }, + "required": [ + "harness", + "label", + "installed", + "configPresent" + ], + "title": "HookInventoryColumnResponse", + "type": "object" + }, + "HookInventoryEntryResponse": { + "properties": { + "canEnable": { + "title": "Canenable", + "type": "boolean" }, - "name": { - "title": "Name", + "displayName": { + "title": "Displayname", "type": "string" }, - "payloadPreview": { + "enabledStatus": { + "enum": [ + "enabled", + "disabled" + ], + "title": "Enabledstatus", + "type": "string" + }, + "id": { + "title": "Id", + "type": "string" + }, + "kind": { + "enum": [ + "managed", + "unmanaged" + ], + "title": "Kind", + "type": "string" + }, + "sightings": { + "items": { + "$ref": "#/components/schemas/HookBindingResponse" + }, + "title": "Sightings", + "type": "array" + }, + "spec": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "$ref": "#/components/schemas/HookSpecResponse" }, { "type": "null" } - ], - "title": "Payloadpreview" + ] + } + }, + "required": [ + "id", + "displayName", + "kind", + "canEnable", + "enabledStatus", + "sightings" + ], + "title": "HookInventoryEntryResponse", + "type": "object" + }, + "HookInventoryIssueResponse": { + "properties": { + "name": { + "title": "Name", + "type": "string" }, "reason": { "title": "Reason", @@ -766,71 +945,65 @@ } }, "required": [ - "harness", - "label", "name", "reason" ], - "title": "McpAdoptionIssueResponse", + "title": "HookInventoryIssueResponse", "type": "object" }, - "McpApplyConfigResponse": { + "HookInventoryResponse": { "properties": { - "failed": { + "columns": { "items": { - "$ref": "#/components/schemas/McpMutationFailureResponse" + "$ref": "#/components/schemas/HookInventoryColumnResponse" }, - "title": "Failed", + "title": "Columns", "type": "array" }, - "ok": { - "title": "Ok", - "type": "boolean" - }, - "server": { - "$ref": "#/components/schemas/McpServerSpecResponse" + "entries": { + "items": { + "$ref": "#/components/schemas/HookInventoryEntryResponse" + }, + "title": "Entries", + "type": "array" }, - "succeeded": { + "issues": { "items": { - "type": "string" + "$ref": "#/components/schemas/HookInventoryIssueResponse" }, - "title": "Succeeded", + "title": "Issues", "type": "array" } }, "required": [ - "ok", - "server", - "succeeded", - "failed" + "columns", + "entries" ], - "title": "McpApplyConfigResponse", + "title": "HookInventoryResponse", "type": "object" }, - "McpAvailabilityCheckResponse": { + "HookMutationFailureResponse": { "properties": { - "availabilityReason": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Availabilityreason" - }, - "availabilityStatus": { - "enum": [ - "available", - "unavailable" - ], - "title": "Availabilitystatus", + "error": { + "title": "Error", "type": "string" }, - "name": { - "title": "Name", + "harness": { + "title": "Harness", "type": "string" + } + }, + "required": [ + "harness", + "error" + ], + "title": "HookMutationFailureResponse", + "type": "object" + }, + "HookMutationResponse": { + "properties": { + "hook": { + "$ref": "#/components/schemas/HookSpecResponse" }, "ok": { "title": "Ok", @@ -839,76 +1012,63 @@ }, "required": [ "ok", - "name", - "availabilityStatus" + "hook" ], - "title": "McpAvailabilityCheckResponse", + "title": "HookMutationResponse", "type": "object" }, - "McpBindingResponse": { + "HookSetHarnessesResultResponse": { "properties": { - "driftDetail": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Driftdetail" + "failed": { + "items": { + "$ref": "#/components/schemas/HookMutationFailureResponse" + }, + "title": "Failed", + "type": "array" }, - "harness": { - "title": "Harness", - "type": "string" + "ok": { + "title": "Ok", + "type": "boolean" }, - "state": { - "enum": [ - "managed", - "drifted", - "unmanaged", - "missing" - ], - "title": "State", - "type": "string" + "succeeded": { + "items": { + "type": "string" + }, + "title": "Succeeded", + "type": "array" } }, "required": [ - "harness", - "state" + "ok", + "succeeded", + "failed" ], - "title": "McpBindingResponse", + "title": "HookSetHarnessesResultResponse", "type": "object" }, - "McpConfigChoiceResponse": { + "HookSpecResponse": { "properties": { - "configPath": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Configpath" + "command": { + "title": "Command", + "type": "string" }, - "env": { - "items": { - "$ref": "#/components/schemas/McpEnvEntryResponse" - }, - "title": "Env", - "type": "array" + "description": { + "title": "Description", + "type": "string" + }, + "event": { + "title": "Event", + "type": "string" }, "id": { "title": "Id", "type": "string" }, - "label": { - "title": "Label", + "installedAt": { + "title": "Installedat", "type": "string" }, - "logoKey": { + "match": { "anyOf": [ { "type": "string" @@ -917,127 +1077,93 @@ "type": "null" } ], - "title": "Logokey" + "title": "Match" }, - "observedHarness": { + "revision": { + "title": "Revision", + "type": "string" + }, + "timeout": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "title": "Observed harness" - }, - "payloadPreview": { - "additionalProperties": true, - "title": "Payloadpreview", - "type": "object" - }, - "recommended": { - "default": false, - "title": "Recommended", - "type": "boolean" - }, - "sourceKind": { - "enum": [ - "managed", - "harness" - ], - "title": "Sourcekind", - "type": "string" - }, - "spec": { - "$ref": "#/components/schemas/McpServerSpecResponse" + "title": "Timeout" } }, "required": [ "id", - "sourceKind", - "label", - "payloadPreview", - "spec" + "event", + "command", + "description", + "installedAt", + "revision" ], - "title": "McpConfigChoiceResponse", + "title": "HookSpecResponse", "type": "object" }, - "McpEnvEntryResponse": { + "InstallMarketplaceSkillRequest": { "properties": { - "isEnvRef": { - "title": "Isenvref", - "type": "boolean" - }, - "key": { - "title": "Key", + "installToken": { + "minLength": 1, + "title": "Installtoken", "type": "string" - }, - "value": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Value" } }, "required": [ - "key", - "isEnvRef" + "installToken" ], - "title": "McpEnvEntryResponse", + "title": "InstallMarketplaceSkillRequest", "type": "object" }, - "McpIdentityGroupResponse": { + "LLMDetectionResponse": { "properties": { - "canonicalSpec": { + "defaultModel": { "anyOf": [ { - "$ref": "#/components/schemas/McpServerSpecResponse" + "type": "string" }, { "type": "null" } - ] - }, - "identical": { - "title": "Identical", - "type": "boolean" + ], + "title": "Defaultmodel" }, - "marketplaceLink": { + "defaultProvider": { "anyOf": [ { - "$ref": "#/components/schemas/McpMarketplaceLinkResponse" + "type": "string" }, { "type": "null" } - ] + ], + "title": "Defaultprovider" }, - "name": { - "title": "Name", - "type": "string" + "hasAnyAvailable": { + "title": "Hasanyavailable", + "type": "boolean" }, - "sightings": { + "providers": { "items": { - "$ref": "#/components/schemas/McpIdentitySightingResponse" + "$ref": "#/components/schemas/DetectedProviderResponse" }, - "title": "Sightings", + "title": "Providers", "type": "array" } }, "required": [ - "name", - "identical", - "sightings" + "providers", + "hasAnyAvailable" ], - "title": "McpIdentityGroupResponse", + "title": "LLMDetectionResponse", "type": "object" }, - "McpIdentitySightingResponse": { + "McpAdoptionIssueResponse": { "properties": { "configPath": { "anyOf": [ @@ -1050,13 +1176,6 @@ ], "title": "Configpath" }, - "env": { - "items": { - "$ref": "#/components/schemas/McpEnvEntryResponse" - }, - "title": "Env", - "type": "array" - }, "harness": { "title": "Harness", "type": "string" @@ -1076,39 +1195,72 @@ ], "title": "Logokey" }, - "payloadPreview": { - "additionalProperties": true, - "title": "Payloadpreview", - "type": "object" + "name": { + "title": "Name", + "type": "string" }, - "recommended": { - "default": false, - "title": "Recommended", - "type": "boolean" + "payloadPreview": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Payloadpreview" }, - "spec": { - "$ref": "#/components/schemas/McpServerSpecResponse" + "reason": { + "title": "Reason", + "type": "string" } }, "required": [ "harness", "label", - "payloadPreview", - "spec" + "name", + "reason" ], - "title": "McpIdentitySightingResponse", + "title": "McpAdoptionIssueResponse", "type": "object" }, - "McpInstallConfigFieldResponse": { + "McpApplyConfigResponse": { "properties": { - "choices": { + "failed": { "items": { - "type": "string" + "$ref": "#/components/schemas/McpMutationFailureResponse" }, - "title": "Choices", + "title": "Failed", "type": "array" }, - "default": { + "ok": { + "title": "Ok", + "type": "boolean" + }, + "server": { + "$ref": "#/components/schemas/McpServerSpecResponse" + }, + "succeeded": { + "items": { + "type": "string" + }, + "title": "Succeeded", + "type": "array" + } + }, + "required": [ + "ok", + "server", + "succeeded", + "failed" + ], + "title": "McpApplyConfigResponse", + "type": "object" + }, + "McpAvailabilityCheckResponse": { + "properties": { + "availabilityReason": { "anyOf": [ { "type": "string" @@ -1117,31 +1269,36 @@ "type": "null" } ], - "title": "Default" - }, - "description": { - "title": "Description", - "type": "string" + "title": "Availabilityreason" }, - "format": { + "availabilityStatus": { "enum": [ - "string", - "number", - "boolean", - "filepath" + "available", + "unavailable" ], - "title": "Format", - "type": "string" - }, - "label": { - "title": "Label", + "title": "Availabilitystatus", "type": "string" }, "name": { "title": "Name", "type": "string" }, - "placeholder": { + "ok": { + "title": "Ok", + "type": "boolean" + } + }, + "required": [ + "ok", + "name", + "availabilityStatus" + ], + "title": "McpAvailabilityCheckResponse", + "type": "object" + }, + "McpBindingResponse": { + "properties": { + "driftDetail": { "anyOf": [ { "type": "string" @@ -1150,100 +1307,54 @@ "type": "null" } ], - "title": "Placeholder" - }, - "required": { - "title": "Required", - "type": "boolean" + "title": "Driftdetail" }, - "secret": { - "title": "Secret", - "type": "boolean" + "harness": { + "title": "Harness", + "type": "string" }, - "target": { + "state": { "enum": [ - "env", - "header", - "urlVariable", - "packageArgument", - "runtimeArgument" + "managed", + "drifted", + "unmanaged", + "missing" ], - "title": "Target", + "title": "State", "type": "string" } }, "required": [ - "name", - "label", - "description", - "format", - "required", - "secret", - "target" - ], - "title": "McpInstallConfigFieldResponse", - "type": "object" - }, - "McpInstallConfigResponse": { - "properties": { - "fields": { - "items": { - "$ref": "#/components/schemas/McpInstallConfigFieldResponse" - }, - "title": "Fields", - "type": "array" - }, - "required": { - "title": "Required", - "type": "boolean" - } - }, - "required": [ - "required" + "harness", + "state" ], - "title": "McpInstallConfigResponse", + "title": "McpBindingResponse", "type": "object" }, - "McpInstallConfigStatusResponse": { + "McpConfigChoiceResponse": { "properties": { - "configured": { - "title": "Configured", - "type": "boolean" - }, - "hasFields": { - "title": "Hasfields", - "type": "boolean" + "configPath": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Configpath" }, - "missingRequired": { + "env": { "items": { - "type": "string" + "$ref": "#/components/schemas/McpEnvEntryResponse" }, - "title": "Missingrequired", + "title": "Env", "type": "array" - } - }, - "required": [ - "hasFields", - "missingRequired", - "configured" - ], - "title": "McpInstallConfigStatusResponse", - "type": "object" - }, - "McpInventoryColumnResponse": { - "properties": { - "configPresent": { - "title": "Configpresent", - "type": "boolean" }, - "harness": { - "title": "Harness", + "id": { + "title": "Id", "type": "string" }, - "installed": { - "title": "Installed", - "type": "boolean" - }, "label": { "title": "Label", "type": "string" @@ -1259,7 +1370,7 @@ ], "title": "Logokey" }, - "mcpUnavailableReason": { + "observedHarness": { "anyOf": [ { "type": "string" @@ -1268,26 +1379,51 @@ "type": "null" } ], - "title": "Mcpunavailablereason" + "title": "Observed harness" }, - "mcpWritable": { - "default": true, - "title": "Mcpwritable", + "payloadPreview": { + "additionalProperties": true, + "title": "Payloadpreview", + "type": "object" + }, + "recommended": { + "default": false, + "title": "Recommended", "type": "boolean" + }, + "sourceKind": { + "enum": [ + "managed", + "harness" + ], + "title": "Sourcekind", + "type": "string" + }, + "spec": { + "$ref": "#/components/schemas/McpServerSpecResponse" } }, "required": [ - "harness", + "id", + "sourceKind", "label", - "installed", - "configPresent" + "payloadPreview", + "spec" ], - "title": "McpInventoryColumnResponse", + "title": "McpConfigChoiceResponse", "type": "object" }, - "McpInventoryEntryResponse": { + "McpEnvEntryResponse": { "properties": { - "availabilityReason": { + "isEnvRef": { + "title": "Isenvref", + "type": "boolean" + }, + "key": { + "title": "Key", + "type": "string" + }, + "value": { "anyOf": [ { "type": "string" @@ -1296,159 +1432,65 @@ "type": "null" } ], - "description": "Deprecated compatibility field; use mcpStatus.reason instead.", - "title": "Availabilityreason" - }, - "availabilityStatus": { - "description": "Deprecated compatibility field; use mcpStatus instead.", - "enum": [ - "available", - "unavailable" - ], - "title": "Availabilitystatus", - "type": "string" + "title": "Value" + } + }, + "required": [ + "key", + "isEnvRef" + ], + "title": "McpEnvEntryResponse", + "type": "object" + }, + "McpIdentityGroupResponse": { + "properties": { + "canonicalSpec": { + "anyOf": [ + { + "$ref": "#/components/schemas/McpServerSpecResponse" + }, + { + "type": "null" + } + ] }, - "canEnable": { - "title": "Canenable", + "identical": { + "title": "Identical", "type": "boolean" }, - "displayName": { - "title": "Displayname", - "type": "string" - }, - "enabledStatus": { - "enum": [ - "enabled", - "disabled" - ], - "title": "Enabledstatus", - "type": "string" - }, - "installConfigStatus": { - "$ref": "#/components/schemas/McpInstallConfigStatusResponse" - }, - "kind": { - "enum": [ - "managed", - "unmanaged" - ], - "title": "Kind", - "type": "string" - }, - "mcpStatus": { - "$ref": "#/components/schemas/McpStatusResponse" - }, - "name": { - "title": "Name", - "type": "string" - }, - "sightings": { - "items": { - "$ref": "#/components/schemas/McpBindingResponse" - }, - "title": "Sightings", - "type": "array" - }, - "spec": { + "marketplaceLink": { "anyOf": [ { - "$ref": "#/components/schemas/McpServerSpecResponse" + "$ref": "#/components/schemas/McpMarketplaceLinkResponse" }, { "type": "null" } ] - } - }, - "required": [ - "name", - "displayName", - "kind", - "canEnable", - "enabledStatus", - "availabilityStatus", - "mcpStatus", - "installConfigStatus", - "sightings" - ], - "title": "McpInventoryEntryResponse", - "type": "object" - }, - "McpInventoryIssueResponse": { - "properties": { + }, "name": { "title": "Name", "type": "string" }, - "reason": { - "title": "Reason", - "type": "string" - } - }, - "required": [ - "name", - "reason" - ], - "title": "McpInventoryIssueResponse", - "type": "object" - }, - "McpInventoryResponse": { - "properties": { - "columns": { - "items": { - "$ref": "#/components/schemas/McpInventoryColumnResponse" - }, - "title": "Columns", - "type": "array" - }, - "entries": { - "items": { - "$ref": "#/components/schemas/McpInventoryEntryResponse" - }, - "title": "Entries", - "type": "array" - }, - "issues": { + "sightings": { "items": { - "$ref": "#/components/schemas/McpInventoryIssueResponse" + "$ref": "#/components/schemas/McpIdentitySightingResponse" }, - "title": "Issues", + "title": "Sightings", "type": "array" } }, "required": [ - "columns", - "entries" - ], - "title": "McpInventoryResponse", - "type": "object" - }, - "McpMarketplaceCapabilityCountsResponse": { - "properties": { - "prompts": { - "title": "Prompts", - "type": "integer" - }, - "resources": { - "title": "Resources", - "type": "integer" - }, - "tools": { - "title": "Tools", - "type": "integer" - } - }, - "required": [ - "tools", - "resources", - "prompts" + "name", + "identical", + "sightings" ], - "title": "McpMarketplaceCapabilityCountsResponse", + "title": "McpIdentityGroupResponse", "type": "object" }, - "McpMarketplaceConnectionResponse": { + "McpIdentitySightingResponse": { "properties": { - "bundleUrl": { + "configPath": { "anyOf": [ { "type": "string" @@ -1457,36 +1499,24 @@ "type": "null" } ], - "title": "Bundleurl" + "title": "Configpath" }, - "configSchema": { - "anyOf": [ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "null" - } - ], - "title": "Configschema" + "env": { + "items": { + "$ref": "#/components/schemas/McpEnvEntryResponse" + }, + "title": "Env", + "type": "array" }, - "deploymentUrl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Deploymenturl" + "harness": { + "title": "Harness", + "type": "string" }, - "kind": { - "title": "Kind", + "label": { + "title": "Label", "type": "string" }, - "runtime": { + "logoKey": { "anyOf": [ { "type": "string" @@ -1495,64 +1525,41 @@ "type": "null" } ], - "title": "Runtime" + "title": "Logokey" }, - "stdioArgs": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Stdioargs" + "payloadPreview": { + "additionalProperties": true, + "title": "Payloadpreview", + "type": "object" }, - "stdioCommand": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Stdiocommand" + "recommended": { + "default": false, + "title": "Recommended", + "type": "boolean" }, - "stdioFunction": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Stdiofunction" + "spec": { + "$ref": "#/components/schemas/McpServerSpecResponse" } }, "required": [ - "kind" + "harness", + "label", + "payloadPreview", + "spec" ], - "title": "McpMarketplaceConnectionResponse", + "title": "McpIdentitySightingResponse", "type": "object" }, - "McpMarketplaceDetailResponse": { + "McpInstallConfigFieldResponse": { "properties": { - "capabilityCounts": { - "$ref": "#/components/schemas/McpMarketplaceCapabilityCountsResponse" - }, - "connections": { + "choices": { "items": { - "$ref": "#/components/schemas/McpMarketplaceConnectionResponse" + "type": "string" }, - "title": "Connections", + "title": "Choices", "type": "array" }, - "deploymentUrl": { + "default": { "anyOf": [ { "type": "string" @@ -1561,21 +1568,31 @@ "type": "null" } ], - "title": "Deploymenturl" + "title": "Default" }, "description": { "title": "Description", "type": "string" }, - "displayName": { - "title": "Displayname", + "format": { + "enum": [ + "string", + "number", + "boolean", + "filepath" + ], + "title": "Format", "type": "string" }, - "externalUrl": { - "title": "Externalurl", + "label": { + "title": "Label", "type": "string" }, - "githubUrl": { + "name": { + "title": "Name", + "type": "string" + }, + "placeholder": { "anyOf": [ { "type": "string" @@ -1584,109 +1601,105 @@ "type": "null" } ], - "title": "Githuburl" + "title": "Placeholder" }, - "iconUrl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Iconurl" - }, - "installConfig": { - "$ref": "#/components/schemas/McpInstallConfigResponse" + "required": { + "title": "Required", + "type": "boolean" }, - "isRemote": { - "title": "Isremote", + "secret": { + "title": "Secret", "type": "boolean" }, - "managedName": { - "title": "Managedname", + "target": { + "enum": [ + "env", + "header", + "urlVariable", + "packageArgument", + "runtimeArgument" + ], + "title": "Target", "type": "string" - }, - "prompts": { + } + }, + "required": [ + "name", + "label", + "description", + "format", + "required", + "secret", + "target" + ], + "title": "McpInstallConfigFieldResponse", + "type": "object" + }, + "McpInstallConfigResponse": { + "properties": { + "fields": { "items": { - "$ref": "#/components/schemas/McpMarketplacePromptResponse" + "$ref": "#/components/schemas/McpInstallConfigFieldResponse" }, - "title": "Prompts", + "title": "Fields", "type": "array" }, - "qualifiedName": { - "title": "Qualifiedname", - "type": "string" + "required": { + "title": "Required", + "type": "boolean" + } + }, + "required": [ + "required" + ], + "title": "McpInstallConfigResponse", + "type": "object" + }, + "McpInstallConfigStatusResponse": { + "properties": { + "configured": { + "title": "Configured", + "type": "boolean" }, - "resources": { - "items": { - "$ref": "#/components/schemas/McpMarketplaceResourceResponse" - }, - "title": "Resources", - "type": "array" + "hasFields": { + "title": "Hasfields", + "type": "boolean" }, - "tools": { + "missingRequired": { "items": { - "$ref": "#/components/schemas/McpMarketplaceToolResponse" + "type": "string" }, - "title": "Tools", + "title": "Missingrequired", "type": "array" - }, - "websiteUrl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Websiteurl" } }, "required": [ - "qualifiedName", - "managedName", - "displayName", - "description", - "isRemote", - "connections", - "tools", - "resources", - "prompts", - "capabilityCounts", - "externalUrl" + "hasFields", + "missingRequired", + "configured" ], - "title": "McpMarketplaceDetailResponse", + "title": "McpInstallConfigStatusResponse", "type": "object" }, - "McpMarketplaceItemResponse": { + "McpInventoryColumnResponse": { "properties": { - "createdAt": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Createdat" + "configPresent": { + "title": "Configpresent", + "type": "boolean" }, - "description": { - "title": "Description", + "harness": { + "title": "Harness", "type": "string" }, - "displayName": { - "title": "Displayname", - "type": "string" + "installed": { + "title": "Installed", + "type": "boolean" }, - "externalUrl": { - "title": "Externalurl", + "label": { + "title": "Label", "type": "string" }, - "githubUrl": { + "logoKey": { "anyOf": [ { "type": "string" @@ -1695,9 +1708,9 @@ "type": "null" } ], - "title": "Githuburl" + "title": "Logokey" }, - "homepage": { + "mcpUnavailableReason": { "anyOf": [ { "type": "string" @@ -1706,9 +1719,26 @@ "type": "null" } ], - "title": "Homepage" + "title": "Mcpunavailablereason" }, - "iconUrl": { + "mcpWritable": { + "default": true, + "title": "Mcpwritable", + "type": "boolean" + } + }, + "required": [ + "harness", + "label", + "installed", + "configPresent" + ], + "title": "McpInventoryColumnResponse", + "type": "object" + }, + "McpInventoryEntryResponse": { + "properties": { + "availabilityReason": { "anyOf": [ { "type": "string" @@ -1717,338 +1747,286 @@ "type": "null" } ], - "title": "Iconurl" + "description": "Deprecated compatibility field; use mcpStatus.reason instead.", + "title": "Availabilityreason" }, - "isDeployed": { - "title": "Isdeployed", - "type": "boolean" + "availabilityStatus": { + "description": "Deprecated compatibility field; use mcpStatus instead.", + "enum": [ + "available", + "unavailable" + ], + "title": "Availabilitystatus", + "type": "string" }, - "isRemote": { - "title": "Isremote", + "canEnable": { + "title": "Canenable", "type": "boolean" }, - "isVerified": { - "title": "Isverified", - "type": "boolean" + "displayName": { + "title": "Displayname", + "type": "string" }, - "namespace": { - "title": "Namespace", + "enabledStatus": { + "enum": [ + "enabled", + "disabled" + ], + "title": "Enabledstatus", "type": "string" }, - "qualifiedName": { - "title": "Qualifiedname", + "installConfigStatus": { + "$ref": "#/components/schemas/McpInstallConfigStatusResponse" + }, + "kind": { + "enum": [ + "managed", + "unmanaged" + ], + "title": "Kind", "type": "string" }, - "useCount": { - "title": "Usecount", - "type": "integer" + "mcpStatus": { + "$ref": "#/components/schemas/McpStatusResponse" }, - "websiteUrl": { + "name": { + "title": "Name", + "type": "string" + }, + "sightings": { + "items": { + "$ref": "#/components/schemas/McpBindingResponse" + }, + "title": "Sightings", + "type": "array" + }, + "spec": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/McpServerSpecResponse" }, { "type": "null" } - ], - "title": "Websiteurl" + ] } }, "required": [ - "qualifiedName", - "namespace", + "name", "displayName", - "description", - "isVerified", - "isRemote", - "isDeployed", - "useCount", - "externalUrl" + "kind", + "canEnable", + "enabledStatus", + "availabilityStatus", + "mcpStatus", + "installConfigStatus", + "sightings" ], - "title": "McpMarketplaceItemResponse", + "title": "McpInventoryEntryResponse", "type": "object" }, - "McpMarketplaceLinkResponse": { + "McpInventoryIssueResponse": { "properties": { - "description": { - "title": "Description", + "name": { + "title": "Name", "type": "string" }, - "displayName": { - "title": "Displayname", - "type": "string" - }, - "externalUrl": { - "title": "Externalurl", - "type": "string" - }, - "githubUrl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Githuburl" - }, - "iconUrl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Iconurl" - }, - "isRemote": { - "title": "Isremote", - "type": "boolean" - }, - "isVerified": { - "title": "Isverified", - "type": "boolean" - }, - "qualifiedName": { - "title": "Qualifiedname", + "reason": { + "title": "Reason", "type": "string" - }, - "websiteUrl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Websiteurl" } }, "required": [ - "qualifiedName", - "displayName", - "externalUrl", - "description", - "isRemote", - "isVerified" + "name", + "reason" ], - "title": "McpMarketplaceLinkResponse", + "title": "McpInventoryIssueResponse", "type": "object" }, - "McpMarketplacePageResponse": { + "McpInventoryResponse": { "properties": { - "hasMore": { - "title": "Hasmore", - "type": "boolean" + "columns": { + "items": { + "$ref": "#/components/schemas/McpInventoryColumnResponse" + }, + "title": "Columns", + "type": "array" }, - "items": { + "entries": { "items": { - "$ref": "#/components/schemas/McpMarketplaceItemResponse" + "$ref": "#/components/schemas/McpInventoryEntryResponse" }, - "title": "Items", + "title": "Entries", "type": "array" }, - "nextOffset": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Nextoffset" + "issues": { + "items": { + "$ref": "#/components/schemas/McpInventoryIssueResponse" + }, + "title": "Issues", + "type": "array" } }, "required": [ - "items", - "hasMore" + "columns", + "entries" ], - "title": "McpMarketplacePageResponse", + "title": "McpInventoryResponse", "type": "object" }, - "McpMarketplaceParameterResponse": { + "McpMarketplaceCapabilityCountsResponse": { "properties": { - "default": { - "anyOf": [ - {}, - { - "type": "null" - } - ], - "title": "Default" + "prompts": { + "title": "Prompts", + "type": "integer" }, - "description": { - "title": "Description", - "type": "string" + "resources": { + "title": "Resources", + "type": "integer" }, - "enum": { + "tools": { + "title": "Tools", + "type": "integer" + } + }, + "required": [ + "tools", + "resources", + "prompts" + ], + "title": "McpMarketplaceCapabilityCountsResponse", + "type": "object" + }, + "McpMarketplaceConnectionResponse": { + "properties": { + "bundleUrl": { "anyOf": [ { - "items": {}, - "type": "array" + "type": "string" }, { "type": "null" } ], - "title": "Enum" + "title": "Bundleurl" }, - "maxItems": { + "configSchema": { "anyOf": [ { - "type": "integer" + "additionalProperties": true, + "type": "object" }, { "type": "null" } ], - "title": "Maxitems" + "title": "Configschema" }, - "maxLength": { + "deploymentUrl": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Maxlength" + "title": "Deploymenturl" }, - "maximum": { + "kind": { + "title": "Kind", + "type": "string" + }, + "runtime": { "anyOf": [ { - "type": "number" - }, - { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Maximum" + "title": "Runtime" }, - "minItems": { + "stdioArgs": { "anyOf": [ { - "type": "integer" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "title": "Minitems" + "title": "Stdioargs" }, - "minLength": { + "stdioCommand": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Minlength" + "title": "Stdiocommand" }, - "minimum": { + "stdioFunction": { "anyOf": [ { - "type": "number" - }, - { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Minimum" - }, - "name": { - "title": "Name", - "type": "string" - }, - "required": { - "title": "Required", - "type": "boolean" - }, - "type": { - "title": "Type", - "type": "string" + "title": "Stdiofunction" } }, "required": [ - "name", - "type", - "description", - "required" + "kind" ], - "title": "McpMarketplaceParameterResponse", + "title": "McpMarketplaceConnectionResponse", "type": "object" }, - "McpMarketplacePromptArgumentResponse": { + "McpMarketplaceDetailResponse": { "properties": { - "description": { - "title": "Description", - "type": "string" - }, - "name": { - "title": "Name", - "type": "string" + "capabilityCounts": { + "$ref": "#/components/schemas/McpMarketplaceCapabilityCountsResponse" }, - "required": { - "title": "Required", - "type": "boolean" - } - }, - "required": [ - "name", - "description", - "required" - ], - "title": "McpMarketplacePromptArgumentResponse", - "type": "object" - }, - "McpMarketplacePromptResponse": { - "properties": { - "arguments": { + "connections": { "items": { - "$ref": "#/components/schemas/McpMarketplacePromptArgumentResponse" + "$ref": "#/components/schemas/McpMarketplaceConnectionResponse" }, - "title": "Arguments", + "title": "Connections", "type": "array" }, + "deploymentUrl": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Deploymenturl" + }, "description": { "title": "Description", "type": "string" }, - "name": { - "title": "Name", + "displayName": { + "title": "Displayname", "type": "string" - } - }, - "required": [ - "name", - "description", - "arguments" - ], - "title": "McpMarketplacePromptResponse", - "type": "object" - }, - "McpMarketplaceResourceResponse": { - "properties": { - "description": { - "title": "Description", + }, + "externalUrl": { + "title": "Externalurl", "type": "string" }, - "mimeType": { + "githubUrl": { "anyOf": [ { "type": "string" @@ -2057,72 +2035,9 @@ "type": "null" } ], - "title": "Mimetype" - }, - "name": { - "title": "Name", - "type": "string" - }, - "uri": { - "title": "Uri", - "type": "string" - } - }, - "required": [ - "name", - "uri", - "description" - ], - "title": "McpMarketplaceResourceResponse", - "type": "object" - }, - "McpMarketplaceToolResponse": { - "properties": { - "description": { - "title": "Description", - "type": "string" - }, - "name": { - "title": "Name", - "type": "string" - }, - "parameters": { - "items": { - "$ref": "#/components/schemas/McpMarketplaceParameterResponse" - }, - "title": "Parameters", - "type": "array" - } - }, - "required": [ - "name", - "description", - "parameters" - ], - "title": "McpMarketplaceToolResponse", - "type": "object" - }, - "McpMutationFailureResponse": { - "properties": { - "error": { - "title": "Error", - "type": "string" + "title": "Githuburl" }, - "harness": { - "title": "Harness", - "type": "string" - } - }, - "required": [ - "harness", - "error" - ], - "title": "McpMutationFailureResponse", - "type": "object" - }, - "McpServerDetailResponse": { - "properties": { - "availabilityReason": { + "iconUrl": { "anyOf": [ { "type": "string" @@ -2131,142 +2046,75 @@ "type": "null" } ], - "description": "Deprecated compatibility field; use mcpStatus.reason instead.", - "title": "Availabilityreason" + "title": "Iconurl" }, - "availabilityStatus": { - "description": "Deprecated compatibility field; use mcpStatus instead.", - "enum": [ - "available", - "unavailable" - ], - "title": "Availabilitystatus", - "type": "string" + "installConfig": { + "$ref": "#/components/schemas/McpInstallConfigResponse" }, - "canEnable": { - "title": "Canenable", + "isRemote": { + "title": "Isremote", "type": "boolean" }, - "configChoices": { + "managedName": { + "title": "Managedname", + "type": "string" + }, + "prompts": { "items": { - "$ref": "#/components/schemas/McpConfigChoiceResponse" + "$ref": "#/components/schemas/McpMarketplacePromptResponse" }, - "title": "Configchoices", + "title": "Prompts", "type": "array" }, - "displayName": { - "title": "Displayname", - "type": "string" - }, - "enabledStatus": { - "enum": [ - "enabled", - "disabled" - ], - "title": "Enabledstatus", + "qualifiedName": { + "title": "Qualifiedname", "type": "string" }, - "env": { + "resources": { "items": { - "$ref": "#/components/schemas/McpEnvEntryResponse" + "$ref": "#/components/schemas/McpMarketplaceResourceResponse" }, - "title": "Env", + "title": "Resources", "type": "array" }, - "installConfigStatus": { - "$ref": "#/components/schemas/McpInstallConfigStatusResponse" - }, - "kind": { - "enum": [ - "managed", - "unmanaged" - ], - "title": "Kind", - "type": "string" - }, - "marketplaceLink": { - "anyOf": [ - { - "$ref": "#/components/schemas/McpMarketplaceLinkResponse" - }, - { - "type": "null" - } - ] - }, - "mcpStatus": { - "$ref": "#/components/schemas/McpStatusResponse" - }, - "name": { - "title": "Name", - "type": "string" - }, - "sightings": { + "tools": { "items": { - "$ref": "#/components/schemas/McpBindingResponse" + "$ref": "#/components/schemas/McpMarketplaceToolResponse" }, - "title": "Sightings", + "title": "Tools", "type": "array" }, - "spec": { + "websiteUrl": { "anyOf": [ { - "$ref": "#/components/schemas/McpServerSpecResponse" + "type": "string" }, { "type": "null" } - ] + ], + "title": "Websiteurl" } }, "required": [ - "name", + "qualifiedName", + "managedName", "displayName", - "kind", - "canEnable", - "enabledStatus", - "availabilityStatus", - "mcpStatus", - "installConfigStatus", - "sightings" - ], - "title": "McpServerDetailResponse", - "type": "object" - }, - "McpServerMutationResponse": { - "properties": { - "ok": { - "title": "Ok", - "type": "boolean" - }, - "server": { - "$ref": "#/components/schemas/McpServerSpecResponse" - } - }, - "required": [ - "ok", - "server" + "description", + "isRemote", + "connections", + "tools", + "resources", + "prompts", + "capabilityCounts", + "externalUrl" ], - "title": "McpServerMutationResponse", + "title": "McpMarketplaceDetailResponse", "type": "object" }, - "McpServerSpecResponse": { + "McpMarketplaceItemResponse": { "properties": { - "args": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Args" - }, - "command": { + "createdAt": { "anyOf": [ { "type": "string" @@ -2275,65 +2123,78 @@ "type": "null" } ], - "title": "Command" + "title": "Createdat" + }, + "description": { + "title": "Description", + "type": "string" }, "displayName": { "title": "Displayname", "type": "string" }, - "env": { + "externalUrl": { + "title": "Externalurl", + "type": "string" + }, + "githubUrl": { "anyOf": [ { - "additionalProperties": { - "type": "string" - }, - "type": "object" + "type": "string" }, { "type": "null" } ], - "title": "Env" + "title": "Githuburl" }, - "headers": { + "homepage": { "anyOf": [ { - "additionalProperties": { - "type": "string" - }, - "type": "object" + "type": "string" }, { "type": "null" } ], - "title": "Headers" + "title": "Homepage" }, - "installedAt": { - "title": "Installedat", - "type": "string" + "iconUrl": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Iconurl" }, - "name": { - "title": "Name", - "type": "string" + "isDeployed": { + "title": "Isdeployed", + "type": "boolean" }, - "revision": { - "title": "Revision", - "type": "string" + "isRemote": { + "title": "Isremote", + "type": "boolean" }, - "source": { - "$ref": "#/components/schemas/McpSourceResponse" + "isVerified": { + "title": "Isverified", + "type": "boolean" }, - "transport": { - "enum": [ - "stdio", - "http", - "sse" - ], - "title": "Transport", + "namespace": { + "title": "Namespace", "type": "string" }, - "url": { + "qualifiedName": { + "title": "Qualifiedname", + "type": "string" + }, + "useCount": { + "title": "Usecount", + "type": "integer" + }, + "websiteUrl": { "anyOf": [ { "type": "string" @@ -2342,85 +2203,72 @@ "type": "null" } ], - "title": "Url" + "title": "Websiteurl" } }, "required": [ - "name", + "qualifiedName", + "namespace", "displayName", - "source", - "transport", - "installedAt", - "revision" + "description", + "isVerified", + "isRemote", + "isDeployed", + "useCount", + "externalUrl" ], - "title": "McpServerSpecResponse", + "title": "McpMarketplaceItemResponse", "type": "object" }, - "McpSetHarnessesResultResponse": { + "McpMarketplaceLinkResponse": { "properties": { - "failed": { - "items": { - "$ref": "#/components/schemas/McpMutationFailureResponse" - }, - "title": "Failed", - "type": "array" - }, - "ok": { - "title": "Ok", - "type": "boolean" + "description": { + "title": "Description", + "type": "string" }, - "succeeded": { - "items": { - "type": "string" - }, - "title": "Succeeded", - "type": "array" - } - }, - "required": [ - "ok", - "succeeded", - "failed" - ], - "title": "McpSetHarnessesResultResponse", - "type": "object" - }, - "McpSourceResponse": { - "properties": { - "kind": { - "enum": [ - "marketplace", - "adopted", - "manual" - ], - "title": "Kind", + "displayName": { + "title": "Displayname", "type": "string" }, - "locator": { - "title": "Locator", + "externalUrl": { + "title": "Externalurl", "type": "string" - } - }, - "required": [ - "kind", - "locator" - ], - "title": "McpSourceResponse", - "type": "object" - }, - "McpStatusResponse": { - "properties": { - "kind": { - "enum": [ - "available", - "needs_config", - "connection_issue", - "unchecked" + }, + "githubUrl": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } ], - "title": "Kind", + "title": "Githuburl" + }, + "iconUrl": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Iconurl" + }, + "isRemote": { + "title": "Isremote", + "type": "boolean" + }, + "isVerified": { + "title": "Isverified", + "type": "boolean" + }, + "qualifiedName": { + "title": "Qualifiedname", "type": "string" }, - "reason": { + "websiteUrl": { "anyOf": [ { "type": "string" @@ -2429,216 +2277,229 @@ "type": "null" } ], - "title": "Reason" + "title": "Websiteurl" } }, "required": [ - "kind" + "qualifiedName", + "displayName", + "externalUrl", + "description", + "isRemote", + "isVerified" ], - "title": "McpStatusResponse", + "title": "McpMarketplaceLinkResponse", "type": "object" }, - "McpUnmanagedByServerResponse": { + "McpMarketplacePageResponse": { "properties": { - "harnesses": { - "items": { - "$ref": "#/components/schemas/McpUnmanagedHarnessResponse" - }, - "title": "Harnesses", - "type": "array" + "hasMore": { + "title": "Hasmore", + "type": "boolean" }, - "issues": { + "items": { "items": { - "$ref": "#/components/schemas/McpAdoptionIssueResponse" + "$ref": "#/components/schemas/McpMarketplaceItemResponse" }, - "title": "Issues", + "title": "Items", "type": "array" }, - "servers": { - "items": { - "$ref": "#/components/schemas/McpIdentityGroupResponse" - }, - "title": "Servers", - "type": "array" + "nextOffset": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Nextoffset" } }, "required": [ - "harnesses", - "servers" + "items", + "hasMore" ], - "title": "McpUnmanagedByServerResponse", + "title": "McpMarketplacePageResponse", "type": "object" }, - "McpUnmanagedHarnessResponse": { + "McpMarketplaceParameterResponse": { "properties": { - "configPath": { + "default": { "anyOf": [ - { - "type": "string" - }, + {}, { "type": "null" } ], - "title": "Configpath" - }, - "configPresent": { - "title": "Configpresent", - "type": "boolean" - }, - "harness": { - "title": "Harness", - "type": "string" - }, - "installed": { - "title": "Installed", - "type": "boolean" + "title": "Default" }, - "label": { - "title": "Label", + "description": { + "title": "Description", "type": "string" }, - "logoKey": { + "enum": { "anyOf": [ { - "type": "string" + "items": {}, + "type": "array" }, { "type": "null" } ], - "title": "Logokey" + "title": "Enum" }, - "mcpUnavailableReason": { + "maxItems": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "title": "Mcpunavailablereason" + "title": "Maxitems" }, - "mcpWritable": { - "default": true, - "title": "Mcpwritable", - "type": "boolean" - } - }, - "required": [ - "harness", - "label", - "installed", - "configPresent" - ], - "title": "McpUnmanagedHarnessResponse", - "type": "object" - }, - "OkResponse": { - "properties": { - "ok": { - "title": "Ok", - "type": "boolean" - } - }, - "required": [ - "ok" - ], - "title": "OkResponse", - "type": "object" - }, - "ReconcileMcpServerRequest": { - "additionalProperties": false, - "properties": { - "harnesses": { + "maxLength": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "type": "integer" }, { "type": "null" } ], - "title": "Harnesses" + "title": "Maxlength" }, - "observedHarness": { + "maximum": { "anyOf": [ { - "type": "string" + "type": "number" + }, + { + "type": "integer" }, { "type": "null" } ], - "title": "Observed harness" + "title": "Maximum" }, - "sourceKind": { - "enum": [ - "managed", - "harness" + "minItems": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } ], - "title": "Sourcekind", + "title": "Minitems" + }, + "minLength": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Minlength" + }, + "minimum": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Minimum" + }, + "name": { + "title": "Name", + "type": "string" + }, + "required": { + "title": "Required", + "type": "boolean" + }, + "type": { + "title": "Type", "type": "string" } }, "required": [ - "sourceKind" + "name", + "type", + "description", + "required" ], - "title": "ReconcileMcpServerRequest", + "title": "McpMarketplaceParameterResponse", "type": "object" }, - "ScanAvailabilityResponse": { + "McpMarketplacePromptArgumentResponse": { "properties": { - "available": { - "title": "Available", + "description": { + "title": "Description", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "required": { + "title": "Required", "type": "boolean" } }, "required": [ - "available" + "name", + "description", + "required" ], - "title": "ScanAvailabilityResponse", + "title": "McpMarketplacePromptArgumentResponse", "type": "object" }, - "ScanConfigItem": { + "McpMarketplacePromptResponse": { "properties": { - "apiKeyMasked": { - "title": "Apikeymasked", - "type": "string" - }, - "apiVersion": { - "title": "Apiversion", - "type": "string" + "arguments": { + "items": { + "$ref": "#/components/schemas/McpMarketplacePromptArgumentResponse" + }, + "title": "Arguments", + "type": "array" }, - "awsProfile": { - "title": "Awsprofile", + "description": { + "title": "Description", "type": "string" }, - "awsRegion": { - "title": "Awsregion", + "name": { + "title": "Name", "type": "string" - }, - "baseUrl": { - "title": "Baseurl", + } + }, + "required": [ + "name", + "description", + "arguments" + ], + "title": "McpMarketplacePromptResponse", + "type": "object" + }, + "McpMarketplaceResourceResponse": { + "properties": { + "description": { + "title": "Description", "type": "string" }, - "consensusRuns": { - "title": "Consensusruns", - "type": "integer" - }, - "id": { - "title": "Id", - "type": "integer" - }, - "isActive": { - "title": "Isactive", - "type": "boolean" - }, - "lastValidatedAt": { + "mimeType": { "anyOf": [ { "type": "string" @@ -2647,239 +2508,216 @@ "type": "null" } ], - "title": "Lastvalidatedat" - }, - "lastValidationError": { - "default": "", - "title": "Lastvalidationerror", - "type": "string" - }, - "maxTokens": { - "title": "Maxtokens", - "type": "integer" - }, - "model": { - "title": "Model", - "type": "string" + "title": "Mimetype" }, "name": { "title": "Name", "type": "string" }, - "provider": { - "title": "Provider", + "uri": { + "title": "Uri", "type": "string" } }, "required": [ - "id", "name", - "baseUrl", - "apiKeyMasked", - "model", - "provider", - "apiVersion", - "awsRegion", - "awsProfile", - "maxTokens", - "consensusRuns", - "isActive" + "uri", + "description" ], - "title": "ScanConfigItem", + "title": "McpMarketplaceResourceResponse", "type": "object" }, - "ScanConfigListResponse": { + "McpMarketplaceToolResponse": { "properties": { - "activeId": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Activeid" + "description": { + "title": "Description", + "type": "string" }, - "configs": { + "name": { + "title": "Name", + "type": "string" + }, + "parameters": { "items": { - "$ref": "#/components/schemas/ScanConfigItem" + "$ref": "#/components/schemas/McpMarketplaceParameterResponse" }, - "title": "Configs", + "title": "Parameters", "type": "array" } }, "required": [ - "configs", - "activeId" + "name", + "description", + "parameters" ], - "title": "ScanConfigListResponse", + "title": "McpMarketplaceToolResponse", "type": "object" }, - "ScanConfigSaveRequest": { + "McpMutationFailureResponse": { "properties": { - "apiKey": { - "title": "Apikey", + "error": { + "title": "Error", "type": "string" }, - "apiVersion": { - "default": "", - "title": "Apiversion", - "type": "string" - }, - "awsProfile": { - "default": "", - "title": "Awsprofile", - "type": "string" - }, - "awsRegion": { - "default": "", - "title": "Awsregion", - "type": "string" - }, - "awsSessionToken": { - "default": "", - "title": "Awssessiontoken", - "type": "string" - }, - "baseUrl": { - "title": "Baseurl", - "type": "string" - }, - "consensusRuns": { - "default": 1, - "title": "Consensusruns", - "type": "integer" - }, - "maxTokens": { - "default": 8192, - "title": "Maxtokens", - "type": "integer" - }, - "model": { - "title": "Model", - "type": "string" - }, - "name": { - "title": "Name", - "type": "string" - }, - "provider": { - "default": "", - "title": "Provider", - "type": "string" - } - }, - "required": [ - "name", - "baseUrl", - "apiKey", - "model" - ], - "title": "ScanConfigSaveRequest", - "type": "object" - }, - "ScanConfigSecretResponse": { - "properties": { - "apiKey": { - "title": "Apikey", + "harness": { + "title": "Harness", "type": "string" } }, "required": [ - "apiKey" + "harness", + "error" ], - "title": "ScanConfigSecretResponse", + "title": "McpMutationFailureResponse", "type": "object" }, - "ScanConfigValidateRequest": { + "McpServerDetailResponse": { "properties": { - "apiKey": { - "title": "Apikey", - "type": "string" + "availabilityReason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Deprecated compatibility field; use mcpStatus.reason instead.", + "title": "Availabilityreason" }, - "apiVersion": { - "default": "", - "title": "Apiversion", + "availabilityStatus": { + "description": "Deprecated compatibility field; use mcpStatus instead.", + "enum": [ + "available", + "unavailable" + ], + "title": "Availabilitystatus", "type": "string" }, - "awsProfile": { - "default": "", - "title": "Awsprofile", - "type": "string" + "canEnable": { + "title": "Canenable", + "type": "boolean" }, - "awsRegion": { - "default": "", - "title": "Awsregion", - "type": "string" + "configChoices": { + "items": { + "$ref": "#/components/schemas/McpConfigChoiceResponse" + }, + "title": "Configchoices", + "type": "array" }, - "awsSessionToken": { - "default": "", - "title": "Awssessiontoken", + "displayName": { + "title": "Displayname", "type": "string" }, - "baseUrl": { - "title": "Baseurl", + "enabledStatus": { + "enum": [ + "enabled", + "disabled" + ], + "title": "Enabledstatus", "type": "string" }, - "consensusRuns": { - "default": 1, - "title": "Consensusruns", - "type": "integer" + "env": { + "items": { + "$ref": "#/components/schemas/McpEnvEntryResponse" + }, + "title": "Env", + "type": "array" }, - "existingConfigId": { + "installConfigStatus": { + "$ref": "#/components/schemas/McpInstallConfigStatusResponse" + }, + "kind": { + "enum": [ + "managed", + "unmanaged" + ], + "title": "Kind", + "type": "string" + }, + "marketplaceLink": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/McpMarketplaceLinkResponse" }, { "type": "null" } - ], - "title": "Existingconfigid" - }, - "maxTokens": { - "default": 8192, - "title": "Maxtokens", - "type": "integer" + ] }, - "model": { - "title": "Model", - "type": "string" + "mcpStatus": { + "$ref": "#/components/schemas/McpStatusResponse" }, "name": { "title": "Name", "type": "string" }, - "provider": { - "default": "", - "title": "Provider", - "type": "string" + "sightings": { + "items": { + "$ref": "#/components/schemas/McpBindingResponse" + }, + "title": "Sightings", + "type": "array" + }, + "spec": { + "anyOf": [ + { + "$ref": "#/components/schemas/McpServerSpecResponse" + }, + { + "type": "null" + } + ] } }, "required": [ "name", - "baseUrl", - "apiKey", - "model" + "displayName", + "kind", + "canEnable", + "enabledStatus", + "availabilityStatus", + "mcpStatus", + "installConfigStatus", + "sightings" ], - "title": "ScanConfigValidateRequest", + "title": "McpServerDetailResponse", "type": "object" }, - "ScanConfigValidationResponse": { + "McpServerMutationResponse": { "properties": { - "durationMs": { + "ok": { + "title": "Ok", + "type": "boolean" + }, + "server": { + "$ref": "#/components/schemas/McpServerSpecResponse" + } + }, + "required": [ + "ok", + "server" + ], + "title": "McpServerMutationResponse", + "type": "object" + }, + "McpServerSpecResponse": { + "properties": { + "args": { "anyOf": [ { - "type": "integer" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "title": "Durationms" + "title": "Args" }, - "errorCode": { + "command": { "anyOf": [ { "type": "string" @@ -2888,49 +2726,65 @@ "type": "null" } ], - "title": "Errorcode" + "title": "Command" }, - "message": { - "title": "Message", + "displayName": { + "title": "Displayname", "type": "string" }, - "model": { + "env": { "anyOf": [ { - "type": "string" + "additionalProperties": { + "type": "string" + }, + "type": "object" }, { "type": "null" } ], - "title": "Model" - }, - "ok": { - "title": "Ok", - "type": "boolean" + "title": "Env" }, - "provider": { + "headers": { "anyOf": [ { - "type": "string" + "additionalProperties": { + "type": "string" + }, + "type": "object" }, { "type": "null" } ], - "title": "Provider" - } - }, - "required": [ - "ok", - "message" - ], - "title": "ScanConfigValidationResponse", - "type": "object" - }, - "ScanFindingResponse": { - "properties": { - "analyzer": { + "title": "Headers" + }, + "installedAt": { + "title": "Installedat", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "revision": { + "title": "Revision", + "type": "string" + }, + "source": { + "$ref": "#/components/schemas/McpSourceResponse" + }, + "transport": { + "enum": [ + "stdio", + "http", + "sse" + ], + "title": "Transport", + "type": "string" + }, + "url": { "anyOf": [ { "type": "string" @@ -2939,17 +2793,85 @@ "type": "null" } ], - "title": "Analyzer" + "title": "Url" + } + }, + "required": [ + "name", + "displayName", + "source", + "transport", + "installedAt", + "revision" + ], + "title": "McpServerSpecResponse", + "type": "object" + }, + "McpSetHarnessesResultResponse": { + "properties": { + "failed": { + "items": { + "$ref": "#/components/schemas/McpMutationFailureResponse" + }, + "title": "Failed", + "type": "array" }, - "category": { - "title": "Category", + "ok": { + "title": "Ok", + "type": "boolean" + }, + "succeeded": { + "items": { + "type": "string" + }, + "title": "Succeeded", + "type": "array" + } + }, + "required": [ + "ok", + "succeeded", + "failed" + ], + "title": "McpSetHarnessesResultResponse", + "type": "object" + }, + "McpSourceResponse": { + "properties": { + "kind": { + "enum": [ + "marketplace", + "adopted", + "manual" + ], + "title": "Kind", "type": "string" }, - "description": { - "title": "Description", + "locator": { + "title": "Locator", + "type": "string" + } + }, + "required": [ + "kind", + "locator" + ], + "title": "McpSourceResponse", + "type": "object" + }, + "McpStatusResponse": { + "properties": { + "kind": { + "enum": [ + "available", + "needs_config", + "connection_issue", + "unchecked" + ], + "title": "Kind", "type": "string" }, - "filePath": { + "reason": { "anyOf": [ { "type": "string" @@ -2958,30 +2880,76 @@ "type": "null" } ], - "title": "Filepath" + "title": "Reason" + } + }, + "required": [ + "kind" + ], + "title": "McpStatusResponse", + "type": "object" + }, + "McpUnmanagedByServerResponse": { + "properties": { + "harnesses": { + "items": { + "$ref": "#/components/schemas/McpUnmanagedHarnessResponse" + }, + "title": "Harnesses", + "type": "array" }, - "id": { - "title": "Id", - "type": "string" + "issues": { + "items": { + "$ref": "#/components/schemas/McpAdoptionIssueResponse" + }, + "title": "Issues", + "type": "array" }, - "lineNumber": { + "servers": { + "items": { + "$ref": "#/components/schemas/McpIdentityGroupResponse" + }, + "title": "Servers", + "type": "array" + } + }, + "required": [ + "harnesses", + "servers" + ], + "title": "McpUnmanagedByServerResponse", + "type": "object" + }, + "McpUnmanagedHarnessResponse": { + "properties": { + "configPath": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Linenumber" + "title": "Configpath" }, - "metadata": { - "additionalProperties": true, - "default": {}, - "title": "Metadata", - "type": "object" + "configPresent": { + "title": "Configpresent", + "type": "boolean" }, - "remediation": { + "harness": { + "title": "Harness", + "type": "string" + }, + "installed": { + "title": "Installed", + "type": "boolean" + }, + "label": { + "title": "Label", + "type": "string" + }, + "logoKey": { "anyOf": [ { "type": "string" @@ -2990,17 +2958,9 @@ "type": "null" } ], - "title": "Remediation" - }, - "ruleId": { - "title": "Ruleid", - "type": "string" - }, - "severity": { - "title": "Severity", - "type": "string" + "title": "Logokey" }, - "snippet": { + "mcpUnavailableReason": { "anyOf": [ { "type": "string" @@ -3009,38 +2969,54 @@ "type": "null" } ], - "title": "Snippet" + "title": "Mcpunavailablereason" }, - "title": { - "title": "Title", - "type": "string" + "mcpWritable": { + "default": true, + "title": "Mcpwritable", + "type": "boolean" } }, "required": [ - "id", - "ruleId", - "category", - "severity", - "title", - "description" + "harness", + "label", + "installed", + "configPresent" ], - "title": "ScanFindingResponse", + "title": "McpUnmanagedHarnessResponse", "type": "object" }, - "ScanOptionsRequest": { + "OkResponse": { "properties": { - "awsProfile": { + "ok": { + "title": "Ok", + "type": "boolean" + } + }, + "required": [ + "ok" + ], + "title": "OkResponse", + "type": "object" + }, + "ReconcileHookRequest": { + "additionalProperties": false, + "properties": { + "harnesses": { "anyOf": [ { - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "title": "Awsprofile" + "title": "Harnesses" }, - "awsRegion": { + "observedHarness": { "anyOf": [ { "type": "string" @@ -3049,31 +3025,41 @@ "type": "null" } ], - "title": "Awsregion" + "title": "Observed harness" }, - "awsSessionToken": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } + "sourceKind": { + "enum": [ + "managed", + "harness" ], - "title": "Awssessiontoken" - }, - "llmApiKey": { + "title": "Sourcekind", + "type": "string" + } + }, + "required": [ + "sourceKind" + ], + "title": "ReconcileHookRequest", + "type": "object" + }, + "ReconcileMcpServerRequest": { + "additionalProperties": false, + "properties": { + "harnesses": { "anyOf": [ { - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "title": "Llmapikey" + "title": "Harnesses" }, - "llmApiVersion": { + "observedHarness": { "anyOf": [ { "type": "string" @@ -3082,30 +3068,71 @@ "type": "null" } ], - "title": "Llmapiversion" + "title": "Observed harness" }, - "llmBaseUrl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } + "sourceKind": { + "enum": [ + "managed", + "harness" ], - "title": "Llmbaseurl" + "title": "Sourcekind", + "type": "string" + } + }, + "required": [ + "sourceKind" + ], + "title": "ReconcileMcpServerRequest", + "type": "object" + }, + "ScanAvailabilityResponse": { + "properties": { + "available": { + "title": "Available", + "type": "boolean" + } + }, + "required": [ + "available" + ], + "title": "ScanAvailabilityResponse", + "type": "object" + }, + "ScanConfigItem": { + "properties": { + "apiKeyMasked": { + "title": "Apikeymasked", + "type": "string" }, - "llmConsensusRuns": { - "default": 1, - "title": "Llmconsensusruns", + "apiVersion": { + "title": "Apiversion", + "type": "string" + }, + "awsProfile": { + "title": "Awsprofile", + "type": "string" + }, + "awsRegion": { + "title": "Awsregion", + "type": "string" + }, + "baseUrl": { + "title": "Baseurl", + "type": "string" + }, + "consensusRuns": { + "title": "Consensusruns", "type": "integer" }, - "llmMaxTokens": { - "default": 8192, - "title": "Llmmaxtokens", + "id": { + "title": "Id", "type": "integer" }, - "llmModel": { + "isActive": { + "title": "Isactive", + "type": "boolean" + }, + "lastValidatedAt": { "anyOf": [ { "type": "string" @@ -3114,199 +3141,341 @@ "type": "null" } ], - "title": "Llmmodel" + "title": "Lastvalidatedat" }, - "llmProvider": { + "lastValidationError": { + "default": "", + "title": "Lastvalidationerror", + "type": "string" + }, + "maxTokens": { + "title": "Maxtokens", + "type": "integer" + }, + "model": { + "title": "Model", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "provider": { + "title": "Provider", + "type": "string" + } + }, + "required": [ + "id", + "name", + "baseUrl", + "apiKeyMasked", + "model", + "provider", + "apiVersion", + "awsRegion", + "awsProfile", + "maxTokens", + "consensusRuns", + "isActive" + ], + "title": "ScanConfigItem", + "type": "object" + }, + "ScanConfigListResponse": { + "properties": { + "activeId": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "title": "Llmprovider" + "title": "Activeid" }, - "useLlm": { - "default": true, - "title": "Usellm", - "type": "boolean" + "configs": { + "items": { + "$ref": "#/components/schemas/ScanConfigItem" + }, + "title": "Configs", + "type": "array" } }, - "title": "ScanOptionsRequest", + "required": [ + "configs", + "activeId" + ], + "title": "ScanConfigListResponse", "type": "object" }, - "ScanResultResponse": { + "ScanConfigSaveRequest": { "properties": { - "analyzersUsed": { - "items": { - "type": "string" - }, - "title": "Analyzersused", - "type": "array" + "apiKey": { + "title": "Apikey", + "type": "string" }, - "durationSeconds": { - "title": "Durationseconds", - "type": "number" + "apiVersion": { + "default": "", + "title": "Apiversion", + "type": "string" }, - "findings": { - "items": { - "$ref": "#/components/schemas/ScanFindingResponse" - }, - "title": "Findings", - "type": "array" + "awsProfile": { + "default": "", + "title": "Awsprofile", + "type": "string" }, - "findingsCount": { - "title": "Findingscount", + "awsRegion": { + "default": "", + "title": "Awsregion", + "type": "string" + }, + "awsSessionToken": { + "default": "", + "title": "Awssessiontoken", + "type": "string" + }, + "baseUrl": { + "title": "Baseurl", + "type": "string" + }, + "consensusRuns": { + "default": 1, + "title": "Consensusruns", "type": "integer" }, - "isSafe": { - "title": "Issafe", - "type": "boolean" + "maxTokens": { + "default": 8192, + "title": "Maxtokens", + "type": "integer" }, - "maxSeverity": { - "title": "Maxseverity", + "model": { + "title": "Model", "type": "string" }, - "skillName": { - "title": "Skillname", + "name": { + "title": "Name", + "type": "string" + }, + "provider": { + "default": "", + "title": "Provider", "type": "string" } }, "required": [ - "skillName", - "isSafe", - "maxSeverity", - "findingsCount", - "findings", - "analyzersUsed", - "durationSeconds" + "name", + "baseUrl", + "apiKey", + "model" ], - "title": "ScanResultResponse", + "title": "ScanConfigSaveRequest", "type": "object" }, - "SetHarnessSupportRequest": { + "ScanConfigSecretResponse": { "properties": { - "enabled": { - "title": "Enabled", - "type": "boolean" + "apiKey": { + "title": "Apikey", + "type": "string" } }, "required": [ - "enabled" + "apiKey" ], - "title": "SetHarnessSupportRequest", + "title": "ScanConfigSecretResponse", "type": "object" }, - "SetMcpServerHarnessesRequest": { + "ScanConfigValidateRequest": { "properties": { - "config": { + "apiKey": { + "title": "Apikey", + "type": "string" + }, + "apiVersion": { + "default": "", + "title": "Apiversion", + "type": "string" + }, + "awsProfile": { + "default": "", + "title": "Awsprofile", + "type": "string" + }, + "awsRegion": { + "default": "", + "title": "Awsregion", + "type": "string" + }, + "awsSessionToken": { + "default": "", + "title": "Awssessiontoken", + "type": "string" + }, + "baseUrl": { + "title": "Baseurl", + "type": "string" + }, + "consensusRuns": { + "default": 1, + "title": "Consensusruns", + "type": "integer" + }, + "existingConfigId": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "type": "integer" }, { "type": "null" } ], - "title": "Config" + "title": "Existingconfigid" }, - "target": { - "enum": [ - "enabled", - "disabled" - ], - "title": "Target", + "maxTokens": { + "default": 8192, + "title": "Maxtokens", + "type": "integer" + }, + "model": { + "title": "Model", "type": "string" - } - }, - "required": [ - "target" - ], - "title": "SetMcpServerHarnessesRequest", - "type": "object" - }, - "SetSkillHarnessesFailureResponse": { - "properties": { - "error": { - "title": "Error", + }, + "name": { + "title": "Name", "type": "string" }, - "harness": { - "title": "Harness", + "provider": { + "default": "", + "title": "Provider", "type": "string" } }, "required": [ - "harness", - "error" + "name", + "baseUrl", + "apiKey", + "model" ], - "title": "SetSkillHarnessesFailureResponse", + "title": "ScanConfigValidateRequest", "type": "object" }, - "SetSkillHarnessesRequest": { + "ScanConfigValidationResponse": { "properties": { - "target": { - "description": "Target state to apply to every interactive harness cell on this skill", - "enum": [ - "enabled", - "disabled" + "durationMs": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } ], - "title": "Target", + "title": "Durationms" + }, + "errorCode": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Errorcode" + }, + "message": { + "title": "Message", "type": "string" - } - }, - "required": [ - "target" - ], - "title": "SetSkillHarnessesRequest", - "type": "object" - }, - "SetSkillHarnessesResultResponse": { - "properties": { - "failed": { - "items": { - "$ref": "#/components/schemas/SetSkillHarnessesFailureResponse" - }, - "title": "Failed", - "type": "array" + }, + "model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Model" }, "ok": { "title": "Ok", "type": "boolean" }, - "succeeded": { - "items": { - "type": "string" - }, - "title": "Succeeded", - "type": "array" + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Provider" } }, "required": [ "ok", - "succeeded", - "failed" + "message" ], - "title": "SetSkillHarnessesResultResponse", + "title": "ScanConfigValidationResponse", "type": "object" }, - "SettingsHarnessResponse": { + "ScanFindingResponse": { "properties": { - "harness": { - "title": "Harness", + "analyzer": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Analyzer" + }, + "category": { + "title": "Category", "type": "string" }, - "installed": { - "title": "Installed", - "type": "boolean" + "description": { + "title": "Description", + "type": "string" }, - "label": { - "title": "Label", + "filePath": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Filepath" + }, + "id": { + "title": "Id", "type": "string" }, - "logoKey": { + "lineNumber": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Linenumber" + }, + "metadata": { + "additionalProperties": true, + "default": {}, + "title": "Metadata", + "type": "object" + }, + "remediation": { "anyOf": [ { "type": "string" @@ -3315,9 +3484,17 @@ "type": "null" } ], - "title": "Logokey" + "title": "Remediation" }, - "managedLocation": { + "ruleId": { + "title": "Ruleid", + "type": "string" + }, + "severity": { + "title": "Severity", + "type": "string" + }, + "snippet": { "anyOf": [ { "type": "string" @@ -3326,146 +3503,38 @@ "type": "null" } ], - "title": "Managedlocation" + "title": "Snippet" }, - "supportEnabled": { - "title": "Supportenabled", - "type": "boolean" + "title": { + "title": "Title", + "type": "string" } }, "required": [ - "harness", - "label", - "supportEnabled", - "installed", - "managedLocation" + "id", + "ruleId", + "category", + "severity", + "title", + "description" ], - "title": "SettingsHarnessResponse", + "title": "ScanFindingResponse", "type": "object" }, - "SettingsResponse": { + "ScanOptionsRequest": { "properties": { - "harnesses": { - "items": { - "$ref": "#/components/schemas/SettingsHarnessResponse" - }, - "title": "Harnesses", - "type": "array" - }, - "storage": { - "$ref": "#/components/schemas/SettingsStorageResponse" - } - }, - "required": [ - "storage", - "harnesses" - ], - "title": "SettingsResponse", - "type": "object" - }, - "SettingsStorageResponse": { - "properties": { - "configDir": { - "title": "Configdir", - "type": "string" - }, - "dataDir": { - "title": "Datadir", - "type": "string" - }, - "marketplaceCachePath": { - "title": "Marketplacecachepath", - "type": "string" - }, - "platform": { - "enum": [ - "macos", - "linux" - ], - "title": "Platform", - "type": "string" - }, - "settingsPath": { - "title": "Settingspath", - "type": "string" - }, - "skillsStorePath": { - "title": "Skillsstorepath", - "type": "string" - }, - "stateDir": { - "title": "Statedir", - "type": "string" - } - }, - "required": [ - "platform", - "configDir", - "dataDir", - "stateDir", - "skillsStorePath", - "marketplaceCachePath", - "settingsPath" - ], - "title": "SettingsStorageResponse", - "type": "object" - }, - "SkillDetailActionsResponse": { - "properties": { - "canDelete": { - "title": "Candelete", - "type": "boolean" - }, - "canManage": { - "title": "Canmanage", - "type": "boolean" - }, - "deleteHarnessLabels": { - "items": { - "type": "string" - }, - "title": "Deleteharnesslabels", - "type": "array" - }, - "stopManagingHarnessLabels": { - "items": { - "type": "string" - }, - "title": "Stopmanagingharnesslabels", - "type": "array" - }, - "stopManagingStatus": { + "awsProfile": { "anyOf": [ { - "enum": [ - "available", - "disabled_no_enabled" - ], "type": "string" }, { "type": "null" } ], - "title": "Stopmanagingstatus" - } - }, - "required": [ - "canManage", - "stopManagingStatus", - "stopManagingHarnessLabels", - "canDelete", - "deleteHarnessLabels" - ], - "title": "SkillDetailActionsResponse", - "type": "object" - }, - "SkillDetailResponse": { - "properties": { - "actions": { - "$ref": "#/components/schemas/SkillDetailActionsResponse" + "title": "Awsprofile" }, - "attentionMessage": { + "awsRegion": { "anyOf": [ { "type": "string" @@ -3474,21 +3543,9 @@ "type": "null" } ], - "title": "Attentionmessage" - }, - "description": { - "title": "Description", - "type": "string" - }, - "displayStatus": { - "enum": [ - "Managed", - "Unmanaged" - ], - "title": "Displaystatus", - "type": "string" + "title": "Awsregion" }, - "documentMarkdown": { + "awsSessionToken": { "anyOf": [ { "type": "string" @@ -3497,59 +3554,9 @@ "type": "null" } ], - "title": "Documentmarkdown" - }, - "harnessCells": { - "items": { - "$ref": "#/components/schemas/HarnessCellResponse" - }, - "title": "Harnesscells", - "type": "array" - }, - "locations": { - "items": { - "$ref": "#/components/schemas/SkillLocationResponse" - }, - "title": "Locations", - "type": "array" - }, - "name": { - "title": "Name", - "type": "string" - }, - "skillRef": { - "title": "Skillref", - "type": "string" + "title": "Awssessiontoken" }, - "sourceLinks": { - "anyOf": [ - { - "$ref": "#/components/schemas/SkillSourceLinksResponse" - }, - { - "type": "null" - } - ] - } - }, - "required": [ - "skillRef", - "name", - "description", - "displayStatus", - "attentionMessage", - "actions", - "harnessCells", - "locations", - "sourceLinks", - "documentMarkdown" - ], - "title": "SkillDetailResponse", - "type": "object" - }, - "SkillLocationResponse": { - "properties": { - "detail": { + "llmApiKey": { "anyOf": [ { "type": "string" @@ -3558,9 +3565,9 @@ "type": "null" } ], - "title": "Detail" + "title": "Llmapikey" }, - "harness": { + "llmApiVersion": { "anyOf": [ { "type": "string" @@ -3569,21 +3576,9 @@ "type": "null" } ], - "title": "Harness" - }, - "kind": { - "enum": [ - "shared", - "harness" - ], - "title": "Kind", - "type": "string" - }, - "label": { - "title": "Label", - "type": "string" + "title": "Llmapiversion" }, - "path": { + "llmBaseUrl": { "anyOf": [ { "type": "string" @@ -3592,9 +3587,19 @@ "type": "null" } ], - "title": "Path" + "title": "Llmbaseurl" }, - "revision": { + "llmConsensusRuns": { + "default": 1, + "title": "Llmconsensusruns", + "type": "integer" + }, + "llmMaxTokens": { + "default": 8192, + "title": "Llmmaxtokens", + "type": "integer" + }, + "llmModel": { "anyOf": [ { "type": "string" @@ -3603,9 +3608,9 @@ "type": "null" } ], - "title": "Revision" + "title": "Llmmodel" }, - "scope": { + "llmProvider": { "anyOf": [ { "type": "string" @@ -3614,583 +3619,448 @@ "type": "null" } ], - "title": "Scope" - }, - "sourceKind": { - "title": "Sourcekind", - "type": "string" + "title": "Llmprovider" }, - "sourceLocator": { - "title": "Sourcelocator", - "type": "string" + "useLlm": { + "default": true, + "title": "Usellm", + "type": "boolean" } }, - "required": [ - "kind", - "harness", - "label", - "scope", - "path", - "revision", - "sourceKind", - "sourceLocator", - "detail" - ], - "title": "SkillLocationResponse", + "title": "ScanOptionsRequest", "type": "object" }, - "SkillRowActionsResponse": { + "ScanResultResponse": { "properties": { - "canDelete": { - "title": "Candelete", - "type": "boolean" - }, - "canManage": { - "title": "Canmanage", - "type": "boolean" - }, - "canStopManaging": { - "title": "Canstopmanaging", + "analyzersUsed": { + "items": { + "type": "string" + }, + "title": "Analyzersused", + "type": "array" + }, + "durationSeconds": { + "title": "Durationseconds", + "type": "number" + }, + "findings": { + "items": { + "$ref": "#/components/schemas/ScanFindingResponse" + }, + "title": "Findings", + "type": "array" + }, + "findingsCount": { + "title": "Findingscount", + "type": "integer" + }, + "isSafe": { + "title": "Issafe", "type": "boolean" + }, + "maxSeverity": { + "title": "Maxseverity", + "type": "string" + }, + "skillName": { + "title": "Skillname", + "type": "string" } }, "required": [ - "canManage", - "canStopManaging", - "canDelete" + "skillName", + "isSafe", + "maxSeverity", + "findingsCount", + "findings", + "analyzersUsed", + "durationSeconds" ], - "title": "SkillRowActionsResponse", + "title": "ScanResultResponse", "type": "object" }, - "SkillSourceLinksResponse": { + "SetHarnessSupportRequest": { "properties": { - "folderUrl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } + "enabled": { + "title": "Enabled", + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "title": "SetHarnessSupportRequest", + "type": "object" + }, + "SetHookHarnessesRequest": { + "properties": { + "target": { + "enum": [ + "enabled", + "disabled" ], - "title": "Folderurl" - }, - "repoLabel": { - "title": "Repolabel", - "type": "string" - }, - "repoUrl": { - "title": "Repourl", + "title": "Target", "type": "string" } }, "required": [ - "repoLabel", - "repoUrl", - "folderUrl" + "target" ], - "title": "SkillSourceLinksResponse", + "title": "SetHookHarnessesRequest", "type": "object" }, - "SkillSourceStatusResponse": { + "SetMcpServerHarnessesRequest": { "properties": { - "updateStatus": { + "config": { "anyOf": [ { - "enum": [ - "update_available", - "no_update_available", - "no_source_available", - "local_changes_detected" - ], - "type": "string" + "additionalProperties": true, + "type": "object" }, { "type": "null" } ], - "title": "Updatestatus" - } - }, - "required": [ - "updateStatus" - ], - "title": "SkillSourceStatusResponse", - "type": "object" - }, - "SkillTableRowResponse": { - "properties": { - "actions": { - "$ref": "#/components/schemas/SkillRowActionsResponse" - }, - "cells": { - "items": { - "$ref": "#/components/schemas/HarnessCellResponse" - }, - "title": "Cells", - "type": "array" - }, - "description": { - "title": "Description", - "type": "string" + "title": "Config" }, - "displayStatus": { + "target": { "enum": [ - "Managed", - "Unmanaged" + "enabled", + "disabled" ], - "title": "Displaystatus", - "type": "string" - }, - "name": { - "title": "Name", - "type": "string" - }, - "skillRef": { - "title": "Skillref", + "title": "Target", "type": "string" } }, "required": [ - "skillRef", - "name", - "description", - "displayStatus", - "actions", - "cells" + "target" ], - "title": "SkillTableRowResponse", + "title": "SetMcpServerHarnessesRequest", "type": "object" }, - "SkillsPageResponse": { + "SetSkillHarnessesFailureResponse": { "properties": { - "harnessColumns": { - "items": { - "$ref": "#/components/schemas/HarnessColumnResponse" - }, - "title": "Harnesscolumns", - "type": "array" - }, - "rows": { - "items": { - "$ref": "#/components/schemas/SkillTableRowResponse" - }, - "title": "Rows", - "type": "array" + "error": { + "title": "Error", + "type": "string" }, - "summary": { - "$ref": "#/components/schemas/SkillsSummaryResponse" + "harness": { + "title": "Harness", + "type": "string" } }, "required": [ - "summary", - "harnessColumns", - "rows" + "harness", + "error" ], - "title": "SkillsPageResponse", + "title": "SetSkillHarnessesFailureResponse", "type": "object" }, - "SkillsSummaryResponse": { + "SetSkillHarnessesRequest": { "properties": { - "managed": { - "title": "Managed", - "type": "integer" - }, - "unmanaged": { - "title": "Unmanaged", - "type": "integer" + "target": { + "description": "Target state to apply to every interactive harness cell on this skill", + "enum": [ + "enabled", + "disabled" + ], + "title": "Target", + "type": "string" } }, "required": [ - "managed", - "unmanaged" + "target" ], - "title": "SkillsSummaryResponse", + "title": "SetSkillHarnessesRequest", "type": "object" }, - "SlashCommandDeleteResponse": { + "SetSkillHarnessesResultResponse": { "properties": { + "failed": { + "items": { + "$ref": "#/components/schemas/SetSkillHarnessesFailureResponse" + }, + "title": "Failed", + "type": "array" + }, "ok": { "title": "Ok", "type": "boolean" }, - "sync": { + "succeeded": { "items": { - "$ref": "#/components/schemas/SlashSyncEntryResponse" + "type": "string" }, - "title": "Sync", + "title": "Succeeded", "type": "array" } }, "required": [ "ok", - "sync" + "succeeded", + "failed" ], - "title": "SlashCommandDeleteResponse", + "title": "SetSkillHarnessesResultResponse", "type": "object" }, - "SlashCommandImportRequest": { + "SettingsHarnessResponse": { "properties": { - "name": { - "minLength": 1, - "title": "Name", + "harness": { + "title": "Harness", "type": "string" }, - "target": { - "enum": [ - "opencode", - "claude", - "cursor", - "codex" - ], - "title": "Target", - "type": "string" - } - }, - "required": [ - "target", - "name" - ], - "title": "SlashCommandImportRequest", - "type": "object" - }, - "SlashCommandListResponse": { - "properties": { - "commands": { - "items": { - "$ref": "#/components/schemas/SlashCommandResponse" - }, - "title": "Commands", - "type": "array" - }, - "defaultTargets": { - "items": { - "enum": [ - "opencode", - "claude", - "cursor", - "codex" - ], - "type": "string" - }, - "title": "Defaulttargets", - "type": "array" - }, - "reviewCommands": { - "items": { - "$ref": "#/components/schemas/SlashCommandReviewResponse" - }, - "title": "Reviewcommands", - "type": "array" - }, - "storePath": { - "title": "Storepath", - "type": "string" - }, - "syncStatePath": { - "title": "Syncstatepath", - "type": "string" - }, - "targets": { - "items": { - "$ref": "#/components/schemas/SlashTargetResponse" - }, - "title": "Targets", - "type": "array" - } - }, - "required": [ - "storePath", - "syncStatePath", - "targets", - "defaultTargets", - "commands", - "reviewCommands" - ], - "title": "SlashCommandListResponse", - "type": "object" - }, - "SlashCommandMutationRequest": { - "properties": { - "description": { - "minLength": 1, - "title": "Description", - "type": "string" - }, - "name": { - "minLength": 1, - "title": "Name", - "type": "string" - }, - "prompt": { - "minLength": 1, - "title": "Prompt", + "installed": { + "title": "Installed", + "type": "boolean" + }, + "label": { + "title": "Label", "type": "string" }, - "targets": { + "logoKey": { "anyOf": [ { - "items": { - "enum": [ - "opencode", - "claude", - "cursor", - "codex" - ], - "type": "string" - }, - "type": "array" + "type": "string" }, { "type": "null" } ], - "title": "Targets" - } - }, - "required": [ - "name", - "description", - "prompt" - ], - "title": "SlashCommandMutationRequest", - "type": "object" - }, - "SlashCommandMutationResponse": { - "properties": { - "command": { + "title": "Logokey" + }, + "managedLocation": { "anyOf": [ { - "$ref": "#/components/schemas/SlashCommandResponse" + "type": "string" }, { "type": "null" } - ] + ], + "title": "Managedlocation" }, - "ok": { - "title": "Ok", + "supportEnabled": { + "title": "Supportenabled", "type": "boolean" - }, - "sync": { + } + }, + "required": [ + "harness", + "label", + "supportEnabled", + "installed", + "managedLocation" + ], + "title": "SettingsHarnessResponse", + "type": "object" + }, + "SettingsResponse": { + "properties": { + "harnesses": { "items": { - "$ref": "#/components/schemas/SlashSyncEntryResponse" + "$ref": "#/components/schemas/SettingsHarnessResponse" }, - "title": "Sync", + "title": "Harnesses", "type": "array" + }, + "storage": { + "$ref": "#/components/schemas/SettingsStorageResponse" } }, "required": [ - "ok", - "command", - "sync" + "storage", + "harnesses" ], - "title": "SlashCommandMutationResponse", + "title": "SettingsResponse", "type": "object" }, - "SlashCommandResolveRequest": { + "SettingsStorageResponse": { "properties": { - "action": { - "enum": [ - "restore_managed", - "adopt_target", - "remove_binding" - ], - "title": "Action", + "configDir": { + "title": "Configdir", "type": "string" }, - "name": { - "minLength": 1, - "title": "Name", + "dataDir": { + "title": "Datadir", "type": "string" }, - "target": { + "marketplaceCachePath": { + "title": "Marketplacecachepath", + "type": "string" + }, + "platform": { "enum": [ - "opencode", - "claude", - "cursor", - "codex" + "macos", + "linux" ], - "title": "Target", - "type": "string" - } - }, - "required": [ - "target", - "name", - "action" - ], - "title": "SlashCommandResolveRequest", - "type": "object" - }, - "SlashCommandResponse": { - "properties": { - "description": { - "title": "Description", + "title": "Platform", "type": "string" }, - "name": { - "title": "Name", + "settingsPath": { + "title": "Settingspath", "type": "string" }, - "prompt": { - "title": "Prompt", + "skillsStorePath": { + "title": "Skillsstorepath", "type": "string" }, - "syncTargets": { - "items": { - "$ref": "#/components/schemas/SlashSyncEntryResponse" - }, - "title": "Synctargets", - "type": "array" + "stateDir": { + "title": "Statedir", + "type": "string" } }, "required": [ - "name", - "description", - "prompt", - "syncTargets" + "platform", + "configDir", + "dataDir", + "stateDir", + "skillsStorePath", + "marketplaceCachePath", + "settingsPath" ], - "title": "SlashCommandResponse", + "title": "SettingsStorageResponse", "type": "object" }, - "SlashCommandReviewResponse": { + "SkillDetailActionsResponse": { "properties": { - "actions": { + "canDelete": { + "title": "Candelete", + "type": "boolean" + }, + "canManage": { + "title": "Canmanage", + "type": "boolean" + }, + "deleteHarnessLabels": { "items": { - "enum": [ - "import", - "restore_managed", - "adopt_target", - "remove_binding" - ], "type": "string" }, - "title": "Actions", + "title": "Deleteharnesslabels", "type": "array" }, - "canImport": { - "title": "Canimport", - "type": "boolean" - }, - "commandExists": { - "title": "Commandexists", - "type": "boolean" - }, - "description": { - "title": "Description", - "type": "string" + "stopManagingHarnessLabels": { + "items": { + "type": "string" + }, + "title": "Stopmanagingharnesslabels", + "type": "array" }, - "error": { + "stopManagingStatus": { "anyOf": [ { + "enum": [ + "available", + "disabled_no_enabled" + ], "type": "string" }, { "type": "null" } ], - "title": "Error" - }, - "kind": { - "enum": [ - "unmanaged", - "drifted", - "missing" - ], - "title": "Kind", - "type": "string" - }, - "name": { - "title": "Name", - "type": "string" - }, - "path": { - "title": "Path", - "type": "string" - }, - "prompt": { - "title": "Prompt", - "type": "string" - }, - "reviewRef": { - "title": "Reviewref", - "type": "string" - }, - "target": { - "enum": [ - "opencode", - "claude", - "cursor", - "codex" - ], - "title": "Target", - "type": "string" - }, - "targetLabel": { - "title": "Targetlabel", - "type": "string" + "title": "Stopmanagingstatus" } }, "required": [ - "reviewRef", - "kind", - "target", - "targetLabel", - "name", - "path", - "description", - "prompt", - "commandExists", - "canImport", - "actions" + "canManage", + "stopManagingStatus", + "stopManagingHarnessLabels", + "canDelete", + "deleteHarnessLabels" ], - "title": "SlashCommandReviewResponse", + "title": "SkillDetailActionsResponse", "type": "object" }, - "SlashCommandUpdateRequest": { + "SkillDetailResponse": { "properties": { + "actions": { + "$ref": "#/components/schemas/SkillDetailActionsResponse" + }, + "attentionMessage": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Attentionmessage" + }, "description": { - "minLength": 1, "title": "Description", "type": "string" }, - "prompt": { - "minLength": 1, - "title": "Prompt", + "displayStatus": { + "enum": [ + "Managed", + "Unmanaged" + ], + "title": "Displaystatus", "type": "string" }, - "targets": { + "documentMarkdown": { "anyOf": [ { - "items": { - "enum": [ - "opencode", - "claude", - "cursor", - "codex" - ], - "type": "string" - }, - "type": "array" + "type": "string" }, { "type": "null" } ], - "title": "Targets" + "title": "Documentmarkdown" + }, + "harnessCells": { + "items": { + "$ref": "#/components/schemas/HarnessCellResponse" + }, + "title": "Harnesscells", + "type": "array" + }, + "locations": { + "items": { + "$ref": "#/components/schemas/SkillLocationResponse" + }, + "title": "Locations", + "type": "array" + }, + "name": { + "title": "Name", + "type": "string" + }, + "skillRef": { + "title": "Skillref", + "type": "string" + }, + "sourceLinks": { + "anyOf": [ + { + "$ref": "#/components/schemas/SkillSourceLinksResponse" + }, + { + "type": "null" + } + ] } }, "required": [ + "skillRef", + "name", "description", - "prompt" + "displayStatus", + "attentionMessage", + "actions", + "harnessCells", + "locations", + "sourceLinks", + "documentMarkdown" ], - "title": "SlashCommandUpdateRequest", + "title": "SkillDetailResponse", "type": "object" }, - "SlashSyncEntryResponse": { + "SkillLocationResponse": { "properties": { - "error": { + "detail": { "anyOf": [ { "type": "string" @@ -4199,235 +4069,1202 @@ "type": "null" } ], - "title": "Error" - }, - "path": { - "title": "Path", - "type": "string" - }, - "status": { - "enum": [ - "synced", - "removed", - "not_selected", - "blocked_manual_file", - "blocked_modified_file", - "missing", - "drifted", - "failed" - ], - "title": "Status", - "type": "string" + "title": "Detail" }, - "target": { - "enum": [ - "opencode", - "claude", - "cursor", - "codex" - ], - "title": "Target", - "type": "string" - } - }, - "required": [ - "target", - "path", - "status" - ], - "title": "SlashSyncEntryResponse", - "type": "object" - }, - "SlashSyncRequest": { - "properties": { - "targets": { + "harness": { "anyOf": [ { - "items": { - "enum": [ - "opencode", - "claude", - "cursor", - "codex" - ], - "type": "string" - }, - "type": "array" + "type": "string" }, { "type": "null" } ], - "title": "Targets" - } - }, - "title": "SlashSyncRequest", - "type": "object" - }, - "SlashTargetResponse": { - "properties": { - "available": { - "title": "Available", - "type": "boolean" - }, - "defaultSelected": { - "title": "Defaultselected", - "type": "boolean" - }, - "docsUrl": { - "title": "Docsurl", - "type": "string" - }, - "enabled": { - "title": "Enabled", - "type": "boolean" - }, - "fileGlob": { - "title": "Fileglob", - "type": "string" + "title": "Harness" }, - "id": { + "kind": { "enum": [ - "opencode", - "claude", - "cursor", - "codex" + "shared", + "harness" ], - "title": "Id", - "type": "string" - }, - "invocationPrefix": { - "title": "Invocationprefix", + "title": "Kind", "type": "string" }, "label": { "title": "Label", "type": "string" }, - "outputDir": { - "title": "Outputdir", - "type": "string" + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Path" }, - "renderFormat": { - "enum": [ - "frontmatter_markdown", - "cursor_plaintext" + "revision": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } ], - "title": "Renderformat", + "title": "Revision" + }, + "scope": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Scope" + }, + "sourceKind": { + "title": "Sourcekind", "type": "string" }, - "rootPath": { - "title": "Rootpath", + "sourceLocator": { + "title": "Sourcelocator", "type": "string" + } + }, + "required": [ + "kind", + "harness", + "label", + "scope", + "path", + "revision", + "sourceKind", + "sourceLocator", + "detail" + ], + "title": "SkillLocationResponse", + "type": "object" + }, + "SkillRowActionsResponse": { + "properties": { + "canDelete": { + "title": "Candelete", + "type": "boolean" }, - "scope": { - "enum": [ - "global", - "project" + "canManage": { + "title": "Canmanage", + "type": "boolean" + }, + "canStopManaging": { + "title": "Canstopmanaging", + "type": "boolean" + } + }, + "required": [ + "canManage", + "canStopManaging", + "canDelete" + ], + "title": "SkillRowActionsResponse", + "type": "object" + }, + "SkillSourceLinksResponse": { + "properties": { + "folderUrl": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } ], - "title": "Scope", + "title": "Folderurl" + }, + "repoLabel": { + "title": "Repolabel", "type": "string" }, - "supportNote": { + "repoUrl": { + "title": "Repourl", + "type": "string" + } + }, + "required": [ + "repoLabel", + "repoUrl", + "folderUrl" + ], + "title": "SkillSourceLinksResponse", + "type": "object" + }, + "SkillSourceStatusResponse": { + "properties": { + "updateStatus": { "anyOf": [ { + "enum": [ + "update_available", + "no_update_available", + "no_source_available", + "local_changes_detected" + ], "type": "string" }, { "type": "null" } ], - "title": "Supportnote" - }, - "supportsFrontmatter": { - "title": "Supportsfrontmatter", - "type": "boolean" + "title": "Updatestatus" } }, "required": [ - "id", - "label", - "rootPath", - "outputDir", - "invocationPrefix", - "renderFormat", - "scope", - "docsUrl", - "fileGlob", - "supportsFrontmatter", - "defaultSelected", - "enabled", - "available" + "updateStatus" ], - "title": "SlashTargetResponse", + "title": "SkillSourceStatusResponse", "type": "object" }, - "ValidationError": { + "SkillTableRowResponse": { "properties": { - "ctx": { - "title": "Context", - "type": "object" - }, - "input": { - "title": "Input" + "actions": { + "$ref": "#/components/schemas/SkillRowActionsResponse" }, - "loc": { + "cells": { "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "integer" - } - ] + "$ref": "#/components/schemas/HarnessCellResponse" }, - "title": "Location", + "title": "Cells", "type": "array" }, - "msg": { - "title": "Message", + "description": { + "title": "Description", "type": "string" }, - "type": { - "title": "Error Type", + "displayStatus": { + "enum": [ + "Managed", + "Unmanaged" + ], + "title": "Displaystatus", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "skillRef": { + "title": "Skillref", "type": "string" } }, "required": [ - "loc", - "msg", - "type" + "skillRef", + "name", + "description", + "displayStatus", + "actions", + "cells" ], - "title": "ValidationError", + "title": "SkillTableRowResponse", "type": "object" - } - } - }, - "info": { - "title": "skill-manager", - "version": "0.1.0" - }, - "openapi": "3.1.0", - "paths": { - "/api/health": { - "get": { - "operationId": "health_api_health_get", - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "additionalProperties": true, - "title": "Response Health Api Health Get", - "type": "object" - } - } + }, + "SkillsPageResponse": { + "properties": { + "harnessColumns": { + "items": { + "$ref": "#/components/schemas/HarnessColumnResponse" }, - "description": "Successful Response" + "title": "Harnesscolumns", + "type": "array" + }, + "rows": { + "items": { + "$ref": "#/components/schemas/SkillTableRowResponse" + }, + "title": "Rows", + "type": "array" + }, + "summary": { + "$ref": "#/components/schemas/SkillsSummaryResponse" } }, - "summary": "Health" + "required": [ + "summary", + "harnessColumns", + "rows" + ], + "title": "SkillsPageResponse", + "type": "object" + }, + "SkillsSummaryResponse": { + "properties": { + "managed": { + "title": "Managed", + "type": "integer" + }, + "unmanaged": { + "title": "Unmanaged", + "type": "integer" + } + }, + "required": [ + "managed", + "unmanaged" + ], + "title": "SkillsSummaryResponse", + "type": "object" + }, + "SlashCommandDeleteResponse": { + "properties": { + "ok": { + "title": "Ok", + "type": "boolean" + }, + "sync": { + "items": { + "$ref": "#/components/schemas/SlashSyncEntryResponse" + }, + "title": "Sync", + "type": "array" + } + }, + "required": [ + "ok", + "sync" + ], + "title": "SlashCommandDeleteResponse", + "type": "object" + }, + "SlashCommandImportRequest": { + "properties": { + "name": { + "minLength": 1, + "title": "Name", + "type": "string" + }, + "target": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "title": "Target", + "type": "string" + } + }, + "required": [ + "target", + "name" + ], + "title": "SlashCommandImportRequest", + "type": "object" + }, + "SlashCommandListResponse": { + "properties": { + "commands": { + "items": { + "$ref": "#/components/schemas/SlashCommandResponse" + }, + "title": "Commands", + "type": "array" + }, + "defaultTargets": { + "items": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "type": "string" + }, + "title": "Defaulttargets", + "type": "array" + }, + "reviewCommands": { + "items": { + "$ref": "#/components/schemas/SlashCommandReviewResponse" + }, + "title": "Reviewcommands", + "type": "array" + }, + "storePath": { + "title": "Storepath", + "type": "string" + }, + "syncStatePath": { + "title": "Syncstatepath", + "type": "string" + }, + "targets": { + "items": { + "$ref": "#/components/schemas/SlashTargetResponse" + }, + "title": "Targets", + "type": "array" + } + }, + "required": [ + "storePath", + "syncStatePath", + "targets", + "defaultTargets", + "commands", + "reviewCommands" + ], + "title": "SlashCommandListResponse", + "type": "object" + }, + "SlashCommandMutationRequest": { + "properties": { + "description": { + "minLength": 1, + "title": "Description", + "type": "string" + }, + "name": { + "minLength": 1, + "title": "Name", + "type": "string" + }, + "prompt": { + "minLength": 1, + "title": "Prompt", + "type": "string" + }, + "targets": { + "anyOf": [ + { + "items": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Targets" + } + }, + "required": [ + "name", + "description", + "prompt" + ], + "title": "SlashCommandMutationRequest", + "type": "object" + }, + "SlashCommandMutationResponse": { + "properties": { + "command": { + "anyOf": [ + { + "$ref": "#/components/schemas/SlashCommandResponse" + }, + { + "type": "null" + } + ] + }, + "ok": { + "title": "Ok", + "type": "boolean" + }, + "sync": { + "items": { + "$ref": "#/components/schemas/SlashSyncEntryResponse" + }, + "title": "Sync", + "type": "array" + } + }, + "required": [ + "ok", + "command", + "sync" + ], + "title": "SlashCommandMutationResponse", + "type": "object" + }, + "SlashCommandResolveRequest": { + "properties": { + "action": { + "enum": [ + "restore_managed", + "adopt_target", + "remove_binding" + ], + "title": "Action", + "type": "string" + }, + "name": { + "minLength": 1, + "title": "Name", + "type": "string" + }, + "target": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "title": "Target", + "type": "string" + } + }, + "required": [ + "target", + "name", + "action" + ], + "title": "SlashCommandResolveRequest", + "type": "object" + }, + "SlashCommandResponse": { + "properties": { + "description": { + "title": "Description", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "prompt": { + "title": "Prompt", + "type": "string" + }, + "syncTargets": { + "items": { + "$ref": "#/components/schemas/SlashSyncEntryResponse" + }, + "title": "Synctargets", + "type": "array" + } + }, + "required": [ + "name", + "description", + "prompt", + "syncTargets" + ], + "title": "SlashCommandResponse", + "type": "object" + }, + "SlashCommandReviewResponse": { + "properties": { + "actions": { + "items": { + "enum": [ + "import", + "restore_managed", + "adopt_target", + "remove_binding" + ], + "type": "string" + }, + "title": "Actions", + "type": "array" + }, + "canImport": { + "title": "Canimport", + "type": "boolean" + }, + "commandExists": { + "title": "Commandexists", + "type": "boolean" + }, + "description": { + "title": "Description", + "type": "string" + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + }, + "kind": { + "enum": [ + "unmanaged", + "drifted", + "missing" + ], + "title": "Kind", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "path": { + "title": "Path", + "type": "string" + }, + "prompt": { + "title": "Prompt", + "type": "string" + }, + "reviewRef": { + "title": "Reviewref", + "type": "string" + }, + "target": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "title": "Target", + "type": "string" + }, + "targetLabel": { + "title": "Targetlabel", + "type": "string" + } + }, + "required": [ + "reviewRef", + "kind", + "target", + "targetLabel", + "name", + "path", + "description", + "prompt", + "commandExists", + "canImport", + "actions" + ], + "title": "SlashCommandReviewResponse", + "type": "object" + }, + "SlashCommandUpdateRequest": { + "properties": { + "description": { + "minLength": 1, + "title": "Description", + "type": "string" + }, + "prompt": { + "minLength": 1, + "title": "Prompt", + "type": "string" + }, + "targets": { + "anyOf": [ + { + "items": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Targets" + } + }, + "required": [ + "description", + "prompt" + ], + "title": "SlashCommandUpdateRequest", + "type": "object" + }, + "SlashSyncEntryResponse": { + "properties": { + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + }, + "path": { + "title": "Path", + "type": "string" + }, + "status": { + "enum": [ + "synced", + "removed", + "not_selected", + "blocked_manual_file", + "blocked_modified_file", + "missing", + "drifted", + "failed" + ], + "title": "Status", + "type": "string" + }, + "target": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "title": "Target", + "type": "string" + } + }, + "required": [ + "target", + "path", + "status" + ], + "title": "SlashSyncEntryResponse", + "type": "object" + }, + "SlashSyncRequest": { + "properties": { + "targets": { + "anyOf": [ + { + "items": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Targets" + } + }, + "title": "SlashSyncRequest", + "type": "object" + }, + "SlashTargetResponse": { + "properties": { + "available": { + "title": "Available", + "type": "boolean" + }, + "defaultSelected": { + "title": "Defaultselected", + "type": "boolean" + }, + "docsUrl": { + "title": "Docsurl", + "type": "string" + }, + "enabled": { + "title": "Enabled", + "type": "boolean" + }, + "fileGlob": { + "title": "Fileglob", + "type": "string" + }, + "id": { + "enum": [ + "opencode", + "claude", + "cursor", + "codex" + ], + "title": "Id", + "type": "string" + }, + "invocationPrefix": { + "title": "Invocationprefix", + "type": "string" + }, + "label": { + "title": "Label", + "type": "string" + }, + "outputDir": { + "title": "Outputdir", + "type": "string" + }, + "renderFormat": { + "enum": [ + "frontmatter_markdown", + "cursor_plaintext" + ], + "title": "Renderformat", + "type": "string" + }, + "rootPath": { + "title": "Rootpath", + "type": "string" + }, + "scope": { + "enum": [ + "global", + "project" + ], + "title": "Scope", + "type": "string" + }, + "supportNote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Supportnote" + }, + "supportsFrontmatter": { + "title": "Supportsfrontmatter", + "type": "boolean" + } + }, + "required": [ + "id", + "label", + "rootPath", + "outputDir", + "invocationPrefix", + "renderFormat", + "scope", + "docsUrl", + "fileGlob", + "supportsFrontmatter", + "defaultSelected", + "enabled", + "available" + ], + "title": "SlashTargetResponse", + "type": "object" + }, + "ValidationError": { + "properties": { + "ctx": { + "title": "Context", + "type": "object" + }, + "input": { + "title": "Input" + }, + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "title": "Location", + "type": "array" + }, + "msg": { + "title": "Message", + "type": "string" + }, + "type": { + "title": "Error Type", + "type": "string" + } + }, + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError", + "type": "object" + } + } + }, + "info": { + "title": "skill-manager", + "version": "0.1.0" + }, + "openapi": "3.1.0", + "paths": { + "/api/health": { + "get": { + "operationId": "health_api_health_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Response Health Api Health Get", + "type": "object" + } + } + }, + "description": "Successful Response" + } + }, + "summary": "Health" + } + }, + "/api/hooks": { + "get": { + "operationId": "list_hooks_api_hooks_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HookInventoryResponse" + } + } + }, + "description": "Successful Response" + } + }, + "summary": "List Hooks" + }, + "post": { + "operationId": "create_hook_api_hooks_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddHookRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HookMutationResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Create Hook" + } + }, + "/api/hooks/{id}": { + "delete": { + "operationId": "delete_hook_api_hooks__id__delete", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HookSetHarnessesResultResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Delete Hook" + }, + "get": { + "operationId": "get_hook_api_hooks__id__get", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HookInventoryEntryResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Get Hook" + } + }, + "/api/hooks/{id}/disable": { + "post": { + "operationId": "disable_hook_api_hooks__id__disable_post", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisableHookRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Disable Hook" + } + }, + "/api/hooks/{id}/enable": { + "post": { + "operationId": "enable_hook_api_hooks__id__enable_post", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableHookRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Enable Hook" + } + }, + "/api/hooks/{id}/reconcile": { + "post": { + "operationId": "reconcile_hook_api_hooks__id__reconcile_post", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReconcileHookRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HookApplyConfigResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Reconcile Hook" + } + }, + "/api/hooks/{id}/set-harnesses": { + "post": { + "operationId": "set_hook_harnesses_api_hooks__id__set_harnesses_post", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetHookHarnessesRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HookSetHarnessesResultResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Set Hook Harnesses" } }, "/api/marketplace/clis/items/{slug}": { diff --git a/frontend/src/app/capability-registry/invalidation.ts b/frontend/src/app/capability-registry/invalidation.ts index 209845e..27e209d 100644 --- a/frontend/src/app/capability-registry/invalidation.ts +++ b/frontend/src/app/capability-registry/invalidation.ts @@ -5,6 +5,7 @@ import { invalidateMcpQueries } from "../../features/mcp/public"; import { invalidateSettingsQueries } from "../../features/settings/public"; import { invalidateSkillsQueries } from "../../features/skills/public"; import { invalidateSlashCommandQueries } from "../../features/slash-commands/public"; +import { invalidateHooksQueries } from "../../features/hooks/public"; export async function invalidateCapabilityQueries(queryClient: QueryClient): Promise { await Promise.all([ @@ -13,5 +14,6 @@ export async function invalidateCapabilityQueries(queryClient: QueryClient): Pro invalidateSettingsQueries(queryClient), invalidateMarketplaceQueries(queryClient), invalidateSlashCommandQueries(queryClient), + invalidateHooksQueries(queryClient), ]); } diff --git a/frontend/src/app/capability-registry/overview.test.ts b/frontend/src/app/capability-registry/overview.test.ts index c08d0ce..85017d5 100644 --- a/frontend/src/app/capability-registry/overview.test.ts +++ b/frontend/src/app/capability-registry/overview.test.ts @@ -73,9 +73,10 @@ describe("capability overview model", () => { ], issues: [], }, + null, ); - expect(model.extensions.map((entry) => entry.key)).toEqual(["skills", "slash-commands", "mcp"]); + expect(model.extensions.map((entry) => entry.key)).toEqual(["skills", "slash-commands", "mcp", "hooks"]); expect(model.marketplaceEntries.map((entry) => entry.key)).toEqual(["skills", "mcp", "clis"]); expect(model.marketplaceEntries.find((entry) => entry.key === "clis")).toMatchObject({ badge: "Preview only", diff --git a/frontend/src/app/capability-registry/overview.ts b/frontend/src/app/capability-registry/overview.ts index bbbd895..f358833 100644 --- a/frontend/src/app/capability-registry/overview.ts +++ b/frontend/src/app/capability-registry/overview.ts @@ -22,6 +22,12 @@ import { } from "../../features/slash-commands/public"; import { marketplaceRoutes } from "../../features/marketplace/public"; import { overviewCopy, useOverviewCopy, type OverviewCopy } from "../../features/overview/i18n"; +import { + invalidateHooksQueries, + hooksRoutes, + useHooksInventoryQuery, + type HookInventoryDto, +} from "../../features/hooks/public"; export interface OverviewStatMetric { value: number | null; @@ -47,7 +53,7 @@ export interface OverviewExtensionFact { } export interface OverviewExtensionKind { - key: "skills" | "slash-commands" | "mcp"; + key: "skills" | "slash-commands" | "mcp" | "hooks"; label: string; iconKey: "skills" | "slash-commands" | "mcp"; facts: OverviewExtensionFact[]; @@ -104,12 +110,19 @@ export function useOverviewData() { const skillsQuery = useSkillsListQuery(); const slashCommandsQuery = useSlashCommandsQuery(); const mcpQuery = useMcpInventoryQuery(); - const model = useOverviewModel(skillsQuery.data, slashCommandsQuery.data, mcpQuery.data); + const hooksQuery = useHooksInventoryQuery(); + const model = useOverviewModel( + skillsQuery.data, + slashCommandsQuery.data, + mcpQuery.data, + hooksQuery.data, + ); return { skillsQuery, slashCommandsQuery, mcpQuery, + hooksQuery, model, }; } @@ -119,6 +132,7 @@ export async function invalidateOverviewData(queryClient: QueryClient): Promise< invalidateSkillsQueries(queryClient), invalidateSlashCommandQueries(queryClient), invalidateMcpQueries(queryClient), + invalidateHooksQueries(queryClient), ]); } @@ -130,31 +144,37 @@ export function useOverviewModel( skills: SkillsWorkspaceData | null | undefined, slashCommands: SlashCommandListDto | null | undefined, mcp: McpInventoryDto | null | undefined, + hooks: HookInventoryDto | null | undefined, ): OverviewModel { const copy = useOverviewCopy(); - return useMemo(() => buildOverviewModel(skills, slashCommands, mcp, copy), [skills, slashCommands, mcp, copy]); + return useMemo( + () => buildOverviewModel(skills, slashCommands, mcp, hooks, copy), + [skills, slashCommands, mcp, hooks, copy], + ); } export function buildOverviewModel( skills: SkillsWorkspaceData | null | undefined, slashCommands: SlashCommandListDto | null | undefined, mcp: McpInventoryDto | null | undefined, + hooks: HookInventoryDto | null | undefined, copy: OverviewCopy = overviewCopy.en, ): OverviewModel { const inUseSkills = skills?.summary.managed ?? null; const skillsToReview = skills?.summary.unmanaged ?? null; const inUseSlashCommands = slashCommands?.commands?.length ?? null; const slashCommandsToReview = slashCommands?.reviewCommands?.length ?? null; - const inUseMcpServers = mcp?.entries.filter((entry) => entry.kind === "managed").length ?? null; - const mcpConfigsToReview = mcp?.entries.filter((entry) => entry.kind === "unmanaged").length ?? null; + const inUseMcpServers = mcp?.entries?.filter((entry) => entry.kind === "managed").length ?? null; + const mcpConfigsToReview = mcp?.entries?.filter((entry) => entry.kind === "unmanaged").length ?? null; + const inUseHooks = hooks?.entries?.filter((entry) => entry.kind === "managed").length ?? null; const differentConfigMcpServers = - mcp?.entries.filter( + mcp?.entries?.filter( (entry) => entry.kind === "managed" && entry.sightings.some((sighting) => sighting.state === "drifted"), ).length ?? null; const inventoryIssues = mcp?.issues?.length ?? null; - const unavailableHarnesses = mcp?.columns.filter((column) => column.mcpWritable === false).length ?? null; + const unavailableHarnesses = mcp?.columns?.filter((column) => column.mcpWritable === false).length ?? null; const reviewItems = buildReviewItems({ skillsToReview, slashCommandsToReview, @@ -165,13 +185,14 @@ export function buildOverviewModel( copy, }); const harnessRows = buildHarnessRows(skills, mcp); - const hasOverviewData = Boolean(skills || slashCommands || mcp); + const hasOverviewData = Boolean(skills || slashCommands || mcp || hooks); return { stats: buildStats({ inUseSkills, inUseSlashCommands, inUseMcpServers, + inUseHooks, needsReview: hasOverviewData ? reviewItems.reduce((total, item) => total + item.count, 0) : null, harnesses: hasOverviewData ? harnessRows.length : null, copy, @@ -186,6 +207,7 @@ export function buildOverviewModel( differentConfigMcpServers, inventoryIssues, unavailableHarnesses, + inUseHooks, copy, }), marketplaceEntries: buildMarketplaceEntries(copy), @@ -198,6 +220,7 @@ function buildStats({ inUseSkills, inUseSlashCommands, inUseMcpServers, + inUseHooks, needsReview, harnesses, copy, @@ -205,13 +228,14 @@ function buildStats({ inUseSkills: number | null; inUseSlashCommands: number | null; inUseMcpServers: number | null; + inUseHooks: number | null; needsReview: number | null; harnesses: number | null; copy: OverviewCopy; }): OverviewStats { return { inUse: { - value: sumKnown(inUseSkills, inUseSlashCommands, inUseMcpServers), + value: sumKnown(inUseSkills, inUseSlashCommands, inUseMcpServers, inUseHooks), detail: copy.stats.inUseDetail(inUseSkills, inUseSlashCommands, inUseMcpServers), }, needsReview: { @@ -243,6 +267,7 @@ function buildExtensions({ differentConfigMcpServers, inventoryIssues, unavailableHarnesses, + inUseHooks, copy, }: { inUseSkills: number | null; @@ -254,6 +279,7 @@ function buildExtensions({ differentConfigMcpServers: number | null; inventoryIssues: number | null; unavailableHarnesses: number | null; + inUseHooks: number | null; copy: OverviewCopy; }): OverviewExtensionKind[] { return [ @@ -305,6 +331,17 @@ function buildExtensions({ { label: copy.stats.needsReview, to: mcpRoutes.needsReview }, ], }, + { + key: "hooks", + label: "Hooks", + iconKey: "mcp", + facts: [ + { label: copy.extensions.inUseFact, value: inUseHooks }, + ], + actions: [ + { label: copy.stats.inUse, to: hooksRoutes.inUse, primary: true }, + ], + }, ]; } diff --git a/frontend/src/app/capability-registry/sidebar.ts b/frontend/src/app/capability-registry/sidebar.ts index f92baab..7691b23 100644 --- a/frontend/src/app/capability-registry/sidebar.ts +++ b/frontend/src/app/capability-registry/sidebar.ts @@ -5,9 +5,10 @@ import { useSkillsCopy } from "../../features/skills/i18n"; import { skillsRoutes, useSkillsListQuery } from "../../features/skills/public"; import { slashCommandRoutes, useSlashCommandsQuery } from "../../features/slash-commands/public"; import { marketplaceRoutes } from "../../features/marketplace/public"; +import { hooksRoutes, useHooksInventoryQuery } from "../../features/hooks/public"; import { useCommonCopy } from "../../i18n"; -export type SidebarIconKey = "overview" | "skills" | "slash-commands" | "mcp" | "marketplace"; +export type SidebarIconKey = "overview" | "skills" | "slash-commands" | "mcp" | "marketplace" | "hooks"; export interface SidebarLinkModel { key: string; @@ -41,6 +42,8 @@ export function useSidebarModel(): SidebarModel { const slashCommandCount = slashCommandsQuery.data?.commands.length ?? null; const slashCommandReviewCount = slashCommandsQuery.data?.reviewCommands.length ?? null; const mcpCounts = mcpSidebarCounts(mcpQuery.data); + const hooksQuery = useHooksInventoryQuery(); + const hooksCounts = hooksSidebarCounts(hooksQuery.data); return useMemo( () => ({ @@ -103,6 +106,21 @@ export function useSidebarModel(): SidebarModel { }, ], }, + { + key: "hooks", + label: "Hooks", + iconKey: "mcp", + count: hooksCounts.total, + links: [ + { key: "hooks-use", to: hooksRoutes.inUse, label: common.productLanguage.inUse, count: hooksCounts.inUse }, + { + key: "hooks-review", + to: hooksRoutes.needsReview, + label: common.productLanguage.needsReview, + count: hooksCounts.needsReview, + }, + ], + }, { key: "marketplace", label: common.nav.marketplace, @@ -120,6 +138,9 @@ export function useSidebarModel(): SidebarModel { mcpCounts.inUse, mcpCounts.needsReview, mcpCounts.total, + hooksCounts.inUse, + hooksCounts.needsReview, + hooksCounts.total, needsReviewSkills, slashCommandCount, slashCommandReviewCount, @@ -145,7 +166,24 @@ function mcpSidebarCounts(inventory: ReturnType["da needsReview: number | null; total: number | null; } { - if (!inventory) { + if (!inventory || !inventory.entries) { + return { inUse: null, needsReview: null, total: null }; + } + const inUse = inventory.entries.filter((entry) => entry.kind === "managed").length; + const needsReview = inventory.entries.filter((entry) => entry.kind === "unmanaged").length; + return { + inUse, + needsReview, + total: sumLoadedCounts(inUse, needsReview), + }; +} + +function hooksSidebarCounts(inventory: ReturnType["data"]): { + inUse: number | null; + needsReview: number | null; + total: number | null; +} { + if (!inventory || !inventory.entries) { return { inUse: null, needsReview: null, total: null }; } const inUse = inventory.entries.filter((entry) => entry.kind === "managed").length; diff --git a/frontend/src/assets/harness-logos/agy-logo.svg b/frontend/src/assets/harness-logos/agy-logo.svg new file mode 100644 index 0000000..fe5fd4c --- /dev/null +++ b/frontend/src/assets/harness-logos/agy-logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/components/harness/harnessPresentation.ts b/frontend/src/components/harness/harnessPresentation.ts index 7abbca7..6730320 100644 --- a/frontend/src/components/harness/harnessPresentation.ts +++ b/frontend/src/components/harness/harnessPresentation.ts @@ -3,8 +3,9 @@ import codexLogo from "../../assets/harness-logos/codex-logo.svg"; import cursorLogo from "../../assets/harness-logos/cursor-logo.svg"; import openclawLogo from "../../assets/harness-logos/openclaw-logo.svg"; import opencodeLogo from "../../assets/harness-logos/opencode-logo.svg"; +import agyLogo from "../../assets/harness-logos/agy-logo.svg"; -export type HarnessLogoKey = "claude" | "codex" | "cursor" | "opencode" | "openclaw"; +export type HarnessLogoKey = "claude" | "codex" | "cursor" | "opencode" | "openclaw" | "agy"; interface HarnessPresentation { logoSrc: string; @@ -32,6 +33,10 @@ const HARNESS_LOGO_ASSETS: Record = { logoSrc: openclawLogo, variant: "openclaw", }, + agy: { + logoSrc: agyLogo, + variant: "agy", + }, }; export function getHarnessPresentation(logoKey: string | null | undefined): HarnessPresentation | null { @@ -40,3 +45,4 @@ export function getHarnessPresentation(logoKey: string | null | undefined): Harn } return HARNESS_LOGO_ASSETS[logoKey as HarnessLogoKey] ?? null; } + diff --git a/frontend/src/features/hooks/api/invalidation.ts b/frontend/src/features/hooks/api/invalidation.ts new file mode 100644 index 0000000..0fdc4c5 --- /dev/null +++ b/frontend/src/features/hooks/api/invalidation.ts @@ -0,0 +1,7 @@ +import type { QueryClient } from "@tanstack/react-query"; + +import { hooksManagementKeys } from "./keys"; + +export async function invalidateHooksQueries(queryClient: QueryClient): Promise { + await queryClient.invalidateQueries({ queryKey: hooksManagementKeys.all }); +} diff --git a/frontend/src/features/hooks/api/keys.ts b/frontend/src/features/hooks/api/keys.ts new file mode 100644 index 0000000..51c37a1 --- /dev/null +++ b/frontend/src/features/hooks/api/keys.ts @@ -0,0 +1,9 @@ +export const HOOKS_STALE_TIME_MS = 30_000; +export const HOOKS_GC_TIME_MS = 5 * 60_000; +export const HOOKS_INVENTORY_REFETCH_INTERVAL_MS = 5_000; + +export const hooksManagementKeys = { + all: ["hooks"] as const, + inventory: () => ["hooks", "inventory"] as const, + detail: (id: string) => ["hooks", "detail", id] as const, +}; diff --git a/frontend/src/features/hooks/api/management-client.ts b/frontend/src/features/hooks/api/management-client.ts new file mode 100644 index 0000000..ff9ab2f --- /dev/null +++ b/frontend/src/features/hooks/api/management-client.ts @@ -0,0 +1,76 @@ +import { deleteJson, fetchJson, postJson } from "../../../api/http"; + +import type { + HookApplyConfigResponseDto, + HookInventoryDto, + HookInventoryEntryDto, + HookMutationResponseDto, + HookSetHarnessesResponseDto, +} from "./management-types"; + +export async function fetchHooksInventory(): Promise { + return fetchJson("/hooks"); +} + +export async function enableHook(args: { + id: string; + harness: string; +}): Promise<{ ok: boolean }> { + return postJson<{ ok: boolean }>(`/hooks/${encodeURIComponent(args.id)}/enable`, { + harness: args.harness, + }); +} + +export async function disableHook(args: { + id: string; + harness: string; +}): Promise<{ ok: boolean }> { + return postJson<{ ok: boolean }>(`/hooks/${encodeURIComponent(args.id)}/disable`, { + harness: args.harness, + }); +} + +export async function setHookHarnesses(args: { + id: string; + target: "enabled" | "disabled"; +}): Promise { + return postJson( + `/hooks/${encodeURIComponent(args.id)}/set-harnesses`, + { target: args.target }, + ); +} + +export async function uninstallHook(id: string): Promise { + return deleteJson(`/hooks/${encodeURIComponent(id)}`); +} + +export async function fetchHookDetail(id: string): Promise { + return fetchJson(`/hooks/${encodeURIComponent(id)}`); +} + +export async function createHook(body: { + id: string; + event: string; + command: string; + match?: string | null; + timeout?: number | null; + description?: string; +}): Promise { + return postJson("/hooks", body); +} + +export async function reconcileHook(args: { + id: string; + sourceKind: "managed" | "harness"; + observedHarness?: string | null; + harnesses?: string[]; +}): Promise { + return postJson( + `/hooks/${encodeURIComponent(args.id)}/reconcile`, + { + sourceKind: args.sourceKind, + observedHarness: args.observedHarness ?? null, + harnesses: args.harnesses, + }, + ); +} diff --git a/frontend/src/features/hooks/api/management-queries.ts b/frontend/src/features/hooks/api/management-queries.ts new file mode 100644 index 0000000..4b617b4 --- /dev/null +++ b/frontend/src/features/hooks/api/management-queries.ts @@ -0,0 +1,88 @@ +import { + useMutation, + useQuery, + useQueryClient, +} from "@tanstack/react-query"; + +import { queryPolicy } from "../../../lib/query"; +import { + createHook, + disableHook, + enableHook, + fetchHooksInventory, + fetchHookDetail, + reconcileHook, + setHookHarnesses, + uninstallHook, +} from "./management-client"; +import { invalidateHooksQueries } from "./invalidation"; +import { HOOKS_GC_TIME_MS, HOOKS_INVENTORY_REFETCH_INTERVAL_MS, HOOKS_STALE_TIME_MS, hooksManagementKeys } from "./keys"; + +export { invalidateHooksQueries } from "./invalidation"; +export { hooksManagementKeys } from "./keys"; + +export function useHooksInventoryQuery() { + return useQuery({ + queryKey: hooksManagementKeys.inventory(), + queryFn: fetchHooksInventory, + refetchInterval: HOOKS_INVENTORY_REFETCH_INTERVAL_MS, + ...queryPolicy(HOOKS_STALE_TIME_MS, HOOKS_GC_TIME_MS), + }); +} + +export function useEnableHookMutation() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: enableHook, + onSettled: () => invalidateHooksQueries(queryClient), + }); +} + +export function useDisableHookMutation() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: disableHook, + onSettled: () => invalidateHooksQueries(queryClient), + }); +} + +export function useSetHookHarnessesMutation() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: setHookHarnesses, + onSettled: () => invalidateHooksQueries(queryClient), + }); +} + +export function useUninstallHookMutation() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: uninstallHook, + onSettled: () => invalidateHooksQueries(queryClient), + }); +} + +export function useHookDetailQuery(id: string | null) { + return useQuery({ + queryKey: hooksManagementKeys.detail(id ?? "__none__"), + queryFn: () => fetchHookDetail(id!), + enabled: Boolean(id), + ...queryPolicy(HOOKS_STALE_TIME_MS, HOOKS_GC_TIME_MS), + }); +} + +export function useCreateHookMutation() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: createHook, + onSettled: () => invalidateHooksQueries(queryClient), + }); +} + +export function useReconcileHookMutation() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: reconcileHook, + onSettled: () => invalidateHooksQueries(queryClient), + }); +} diff --git a/frontend/src/features/hooks/api/management-types.ts b/frontend/src/features/hooks/api/management-types.ts new file mode 100644 index 0000000..dcfc140 --- /dev/null +++ b/frontend/src/features/hooks/api/management-types.ts @@ -0,0 +1,13 @@ +import type { components } from "../../../api/generated"; + +export type HookBindingState = components["schemas"]["HookBindingResponse"]["state"]; + +export type HookInventoryColumnDto = components["schemas"]["HookInventoryColumnResponse"]; +export type HookBindingDto = components["schemas"]["HookBindingResponse"]; +export type HookSpecDto = components["schemas"]["HookSpecResponse"]; +export type HookInventoryEntryDto = components["schemas"]["HookInventoryEntryResponse"]; +export type HookInventoryDto = components["schemas"]["HookInventoryResponse"]; +export type HookMutationFailureDto = components["schemas"]["HookMutationFailureResponse"]; +export type HookSetHarnessesResponseDto = components["schemas"]["HookSetHarnessesResultResponse"]; +export type HookApplyConfigResponseDto = components["schemas"]["HookApplyConfigResponse"]; +export type HookMutationResponseDto = components["schemas"]["HookMutationResponse"]; diff --git a/frontend/src/features/hooks/components/HookCard.tsx b/frontend/src/features/hooks/components/HookCard.tsx new file mode 100644 index 0000000..b3dc6ce --- /dev/null +++ b/frontend/src/features/hooks/components/HookCard.tsx @@ -0,0 +1,147 @@ +import { useMemo } from "react"; +import { Loader2, Power, Trash2 } from "lucide-react"; + +import { CardMenu, type CardMenuItem } from "../../../components/cards/CardMenu"; +import { CardSelectCheckbox } from "../../../components/cards/CardSelectCheckbox"; +import { OverflowTooltipText } from "../../../components/ui/OverflowTooltipText"; +import type { HookInventoryColumnDto, HookInventoryEntryDto } from "../../hooks/api/management-types"; +import { useHooksCopy } from "../../hooks/i18n"; +import { isHooksHarnessAddressable } from "../model/selectors"; +import { HooksHarnessLogoStack } from "./HooksHarnessLogoStack"; +import { HooksStatusChip } from "./HooksStatusChip"; + +interface HookCardProps { + entry: HookInventoryEntryDto; + columns: HookInventoryColumnDto[]; + pending: boolean; + checked: boolean; + onOpenDetail: (id: string) => void; + onToggleChecked: (id: string) => void; + onSetHarnesses: (id: string, target: "enabled" | "disabled") => void; + onRequestUninstall: (id: string) => void; +} + +function managedCount( + entry: HookInventoryEntryDto, + addressable: ReadonlySet, +): number { + return entry.sightings.filter( + (b) => addressable.has(b.harness) && b.state === "managed", + ).length; +} + +function hasDifferentConfig( + entry: HookInventoryEntryDto, + addressable: ReadonlySet, +): boolean { + return entry.sightings.some( + (b) => addressable.has(b.harness) && b.state === "drifted", + ); +} + +export function HookCard({ + entry, + columns, + pending, + checked, + onOpenDetail, + onToggleChecked, + onSetHarnesses, + onRequestUninstall, +}: HookCardProps) { + const copy = useHooksCopy(); + const addressableHarnesses = useMemo( + () => new Set(columns.filter(isHooksHarnessAddressable).map((c) => c.harness)), + [columns], + ); + const enabled = managedCount(entry, addressableHarnesses); + const total = addressableHarnesses.size; + const differentConfig = hasDifferentConfig(entry, addressableHarnesses); + const allEnabled = total > 0 && enabled === total; + const target: "enabled" | "disabled" = allEnabled ? "disabled" : "enabled"; + + const menuItems = useMemo( + () => [ + { + key: "uninstall", + label: copy.detail.uninstall, + icon:

onOpenDetail(entry.id)} + onKeyDown={(event) => { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + onOpenDetail(entry.id); + } + }} + aria-label={copy.detail.openDetail(entry.displayName)} + > +
+ + {entry.displayName} + + {entry.spec && } +
+ + onToggleChecked(entry.id)} + label={checked ? copy.detail.deselect(entry.displayName) : copy.detail.select(entry.displayName)} + disabled={pending} + /> +
+
+ +

+ {entry.spec?.command ?? "—"} +

+ + {entry.spec?.description ? ( + + {entry.spec.description} + + ) : null} + +
+ + +
+
+ ); +} diff --git a/frontend/src/features/hooks/components/HookCardList.tsx b/frontend/src/features/hooks/components/HookCardList.tsx new file mode 100644 index 0000000..7a7b62a --- /dev/null +++ b/frontend/src/features/hooks/components/HookCardList.tsx @@ -0,0 +1,44 @@ +import type { HookInventoryColumnDto, HookInventoryEntryDto } from "../api/management-types"; +import { HookCard } from "./HookCard"; + +interface HookCardListProps { + entries: HookInventoryEntryDto[]; + columns: HookInventoryColumnDto[]; + pendingHookKeys: ReadonlySet; + checkedIds: ReadonlySet; + onOpenDetail: (id: string) => void; + onToggleChecked: (id: string) => void; + onSetHarnesses: (id: string, target: "enabled" | "disabled") => void; + onRequestUninstall: (id: string) => void; + ariaLabel?: string; +} + +export function HookCardList({ + entries, + columns, + pendingHookKeys, + checkedIds, + onOpenDetail, + onToggleChecked, + onSetHarnesses, + onRequestUninstall, + ariaLabel, +}: HookCardListProps) { + return ( +
+ {entries.map((entry) => ( + + ))} +
+ ); +} diff --git a/frontend/src/features/hooks/components/HooksFilterMenu.tsx b/frontend/src/features/hooks/components/HooksFilterMenu.tsx new file mode 100644 index 0000000..ae26f59 --- /dev/null +++ b/frontend/src/features/hooks/components/HooksFilterMenu.tsx @@ -0,0 +1,38 @@ +import { SelectionMenu } from "../../../components/ui/SelectionMenu"; +import type { InUsePillValue } from "../model/selectors"; +import { useHooksCopy } from "../i18n"; + +const OPTIONS: InUsePillValue[] = ["all", "enabled", "all-harnesses", "unbound", "drifted"]; + +interface HooksFilterMenuProps { + pill: InUsePillValue; + counts: Record; + onChange: (next: InUsePillValue) => void; +} + +export function HooksFilterMenu({ pill, counts, onChange }: HooksFilterMenuProps) { + const copy = useHooksCopy(); + const options = OPTIONS.map((value) => ({ + value, + label: pillLabel(copy, value), + meta: counts[value], + })); + + return ( + + ); +} + +function pillLabel(copy: ReturnType, value: InUsePillValue): string { + if (value === "all") return copy.inUse.filters.all; + if (value === "enabled") return copy.inUse.filters.enabled; + if (value === "all-harnesses") return copy.inUse.filters.allHarnesses; + if (value === "unbound") return copy.inUse.filters.unbound; + return copy.inUse.filters.drifted; +} diff --git a/frontend/src/features/hooks/components/HooksHarnessLogoStack.tsx b/frontend/src/features/hooks/components/HooksHarnessLogoStack.tsx new file mode 100644 index 0000000..a3b34c3 --- /dev/null +++ b/frontend/src/features/hooks/components/HooksHarnessLogoStack.tsx @@ -0,0 +1,57 @@ +import { UiTooltip } from "../../../components/ui/UiTooltip"; +import { getHarnessPresentation } from "../../../components/harness/harnessPresentation"; +import type { HookBindingDto, HookInventoryColumnDto } from "../../hooks/api/management-types"; +import { isHooksHarnessAddressable } from "../model/selectors"; + +interface HooksHarnessLogoStackProps { + bindings: HookBindingDto[]; + columns: HookInventoryColumnDto[]; +} + +export function HooksHarnessLogoStack({ bindings, columns }: HooksHarnessLogoStackProps) { + const labelByHarness = new Map(columns.map((c) => [c.harness, c.label])); + const logoByHarness = new Map(columns.map((c) => [c.harness, c.logoKey ?? c.harness])); + const addressable = new Set(columns.filter(isHooksHarnessAddressable).map((c) => c.harness)); + + const visible = bindings.filter( + (b) => addressable.has(b.harness) && (b.state === "managed" || b.state === "drifted"), + ); + const managedCount = bindings.filter( + (b) => addressable.has(b.harness) && b.state === "managed", + ).length; + const totalCount = addressable.size; + const ariaLabel = `Bound to ${managedCount} of ${totalCount} harnesses`; + + return ( +
+
+ {visible.map((binding, index) => { + const presentation = getHarnessPresentation(logoByHarness.get(binding.harness) ?? null); + const label = labelByHarness.get(binding.harness) ?? binding.harness; + const title = + binding.state === "drifted" + ? `${label} — Different config${binding.driftDetail ? ` (${binding.driftDetail})` : ""}` + : label; + return ( + + + {presentation ? ( + + ) : ( + {label.slice(0, 1)} + )} + + + ); + })} +
+ + {managedCount}/{totalCount} + +
+ ); +} diff --git a/frontend/src/features/hooks/components/HooksMatrixView.tsx b/frontend/src/features/hooks/components/HooksMatrixView.tsx new file mode 100644 index 0000000..fd56f6b --- /dev/null +++ b/frontend/src/features/hooks/components/HooksMatrixView.tsx @@ -0,0 +1,243 @@ +import { AlertTriangle } from "lucide-react"; + +import { CardSelectCheckbox } from "../../../components/cards/CardSelectCheckbox"; +import { + MatrixHarnessCellTarget, + MatrixHarnessHeader, + MatrixHarnessIcon, + MatrixTable, +} from "../../../components/matrix"; +import { UiTooltip } from "../../../components/ui/UiTooltip"; +import type { HookInventoryColumnDto, HookInventoryEntryDto } from "../api/management-types"; +import { useHooksCopy, type HooksCopy } from "../i18n"; +import { + matrixCellFor, + matrixColumns, + matrixCoverage, + type HooksMatrixCellModel, +} from "../model/selectors"; +import { HooksHarnessLogoStack } from "./HooksHarnessLogoStack"; + +interface HooksMatrixViewProps { + entries: HookInventoryEntryDto[]; + columns: HookInventoryColumnDto[]; + pendingHookKeys: ReadonlySet; + pendingPerHarnessKeys: ReadonlySet; + checkedIds: ReadonlySet; + onOpenDetail: (id: string) => void; + onToggleChecked: (id: string) => void; + onEnableHarness: (id: string, harness: string) => void; + onDisableHarness: (id: string, harness: string) => void; +} + +export function HooksMatrixView({ + entries, + columns, + pendingHookKeys, + pendingPerHarnessKeys, + checkedIds, + onOpenDetail, + onToggleChecked, + onEnableHarness, + onDisableHarness, +}: HooksMatrixViewProps) { + const copy = useHooksCopy(); + const displayColumns = matrixColumns({ columns }); + + return ( + + + + + Hook ID + {displayColumns.map((column) => ( + + ))} + + Harnesses + + Enabled + + + + {entries.map((entry) => ( + + ))} + + + ); +} + +function HooksMatrixRow({ + entry, + columns, + pendingHook, + pendingPerHarnessKeys, + checked, + onOpenDetail, + onToggleChecked, + onEnableHarness, + onDisableHarness, + copy, +}: { + entry: HookInventoryEntryDto; + columns: HookInventoryColumnDto[]; + pendingHook: boolean; + pendingPerHarnessKeys: ReadonlySet; + checked: boolean; + onOpenDetail: (id: string) => void; + onToggleChecked: (id: string) => void; + onEnableHarness: (id: string, harness: string) => void; + onDisableHarness: (id: string, harness: string) => void; + copy: HooksCopy; +}) { + const coverage = matrixCoverage(entry, columns); + + return ( + + + onToggleChecked(entry.id)} + disabled={pendingHook} + /> + + + + + {columns.map((column) => { + const cell = matrixCellFor(entry, column, copy); + return ( + + + + ); + })} + + + + + + {coverage.enabled} + + + + + ); +} + +function HooksMatrixHarnessCell({ + entry, + column, + cell, + pending, + onOpenDetail, + onEnableHarness, + onDisableHarness, +}: { + entry: HookInventoryEntryDto; + column: HookInventoryColumnDto; + cell: HooksMatrixCellModel; + pending: boolean; + onOpenDetail: (id: string) => void; + onEnableHarness: (id: string, harness: string) => void; + onDisableHarness: (id: string, harness: string) => void; +}) { + const content = cellContent(column, cell); + const disabled = pending || cell.action === null; + + const control = cell.action === null ? ( + + {content} + + ) : ( + { + if (cell.action === "enable") { + onEnableHarness(entry.id, column.harness); + } else if (cell.action === "disable") { + onDisableHarness(entry.id, column.harness); + } else { + onOpenDetail(entry.id); + } + }} + > + {content} + + ); + + return {control}; +} + +function cellContent(column: HookInventoryColumnDto, cell: HooksMatrixCellModel) { + if (cell.state === "unavailable") { + return