fcfebe44f1
Settings → Dashboard gains an AI Tools section (installed tools with Enabled/Disabled and Set default, available ones with a homepage link, Refresh). useAiTools shares one catalog copy across the app and replaces LANE_TOOL_LABEL. The Add-lane modal picks Default (<tool>) or Other…; the router row reads Native (<tool>) and disables AI Router profiles for tools that cannot use one. The run form gives catalog tools resume and a red per-run Bypass permissions switch (Codex too). Claude Code / Codex settings tabs hide while that tool is disabled. The Workspace probes each lane tool's CLI fresh. Docs: CLAUDE.md tool/bypass rule, AGENTS.md, LANES.md, API.md, CLI.md, server/README.md, OpenAPI fragment + regenerated openapi.yaml.
129 lines
4.5 KiB
JavaScript
129 lines
4.5 KiB
JavaScript
/**
|
|
* @file Supplementary OpenAPI 3.0 fragments for the AI Tools routes mounted at
|
|
* `/api/ai-tools` (see server/routes/ai-tools.js + server/lib/ai-tools.js):
|
|
* list the catalog with detection, re-detect after hydrating PATH, and
|
|
* enable/disable a tool or make it the default. Exports `{ tags, schemas,
|
|
* paths }` for server/openapi-extra.js; schemas are prefixed `AiTools`.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
const tags = [
|
|
{
|
|
name: "AI Tools",
|
|
description:
|
|
"The catalog of AI coding CLIs a lane can run (server/data/ai-tools/*.json + DASHBOARD_AI_TOOLS_DIR), what is installed on PATH, and the user's enable/default choice",
|
|
},
|
|
];
|
|
|
|
const errorRef = { $ref: "#/components/schemas/AiToolsError" };
|
|
|
|
const schemas = {
|
|
AiToolsTool: {
|
|
type: "object",
|
|
required: ["id", "label", "installed", "enabled", "source"],
|
|
properties: {
|
|
id: { type: "string", example: "antigravity" },
|
|
label: { type: "string", example: "Antigravity" },
|
|
command: { type: "string", nullable: true, example: "agy" },
|
|
homepageUrl: { type: "string", nullable: true },
|
|
installed: { type: "boolean" },
|
|
path: { type: "string", nullable: true, example: "/home/u/.local/bin/agy" },
|
|
enabled: { type: "boolean" },
|
|
source: { type: "string", enum: ["builtin", "custom"] },
|
|
launcher: { type: "string", nullable: true, enum: ["claude", "codex", null] },
|
|
prompt: {
|
|
type: "object",
|
|
nullable: true,
|
|
properties: { mode: { type: "string", enum: ["argv", "flag", "after-start"] } },
|
|
},
|
|
resume: { type: "boolean", description: "Offers Resume last session" },
|
|
bypass: { type: "boolean", description: "Offers the per-run Bypass permissions switch" },
|
|
routerCapable: { type: "boolean", description: "Can use an AI Router profile" },
|
|
},
|
|
},
|
|
AiToolsView: {
|
|
type: "object",
|
|
required: ["tools", "default"],
|
|
properties: {
|
|
tools: { type: "array", items: { $ref: "#/components/schemas/AiToolsTool" } },
|
|
default: { type: "string", nullable: true, description: "Effective default tool id" },
|
|
},
|
|
},
|
|
AiToolsError: {
|
|
type: "object",
|
|
properties: {
|
|
error: {
|
|
type: "object",
|
|
properties: { code: { type: "string" }, message: { type: "string" } },
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
const ok = {
|
|
200: {
|
|
description: "The catalog with detection and the effective default",
|
|
content: { "application/json": { schema: { $ref: "#/components/schemas/AiToolsView" } } },
|
|
},
|
|
};
|
|
|
|
const paths = {
|
|
"/api/ai-tools": {
|
|
get: {
|
|
tags: ["AI Tools"],
|
|
summary: "List the AI Tools catalog",
|
|
description:
|
|
"Every catalog tool with whether it was found on PATH, whether it is enabled, and the effective default (stored default if installed+enabled, else claude, else the first installed enabled tool, else null). Arg arrays are never returned.",
|
|
operationId: "aiToolsList",
|
|
responses: ok,
|
|
},
|
|
},
|
|
"/api/ai-tools/refresh": {
|
|
post: {
|
|
tags: ["AI Tools"],
|
|
summary: "Re-detect installed tools",
|
|
description:
|
|
"Merges the login shell's PATH ($SHELL -ilc, 5 s timeout, off with AGENTHUB_SHELL_PATH=0) into the server's, re-reads the catalog and re-detects. Same-origin only.",
|
|
operationId: "aiToolsRefresh",
|
|
responses: ok,
|
|
},
|
|
},
|
|
"/api/ai-tools/{id}": {
|
|
put: {
|
|
tags: ["AI Tools"],
|
|
summary: "Enable/disable a tool or make it the default",
|
|
description:
|
|
"A disabled tool is hidden from Add lane and a NEW lane for it answers 400 EDISABLED; existing lanes keep working. Disabling the default clears it. Same-origin only.",
|
|
operationId: "aiToolsUpdate",
|
|
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
|
|
requestBody: {
|
|
required: true,
|
|
content: {
|
|
"application/json": {
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
enabled: { type: "boolean" },
|
|
default: { type: "boolean", enum: [true] },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
responses: {
|
|
...ok,
|
|
400: {
|
|
description: "EBADDEFAULT (not installed or disabled) or EBADFIELD",
|
|
content: { "application/json": { schema: errorRef } },
|
|
},
|
|
404: {
|
|
description: "ENOTOOL — unknown id",
|
|
content: { "application/json": { schema: errorRef } },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
module.exports = { tags, schemas, paths };
|