@ottocode/server 0.1.265 → 0.1.267
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/routes/auth/copilot.ts +699 -0
- package/src/routes/auth/oauth.ts +578 -0
- package/src/routes/auth/onboarding.ts +45 -0
- package/src/routes/auth/providers.ts +189 -0
- package/src/routes/auth/service.ts +167 -0
- package/src/routes/auth/state.ts +23 -0
- package/src/routes/auth/status.ts +203 -0
- package/src/routes/auth/wallet.ts +229 -0
- package/src/routes/auth.ts +12 -2080
- package/src/routes/config/models-service.ts +411 -0
- package/src/routes/config/models.ts +6 -426
- package/src/routes/config/providers-service.ts +237 -0
- package/src/routes/config/providers.ts +10 -242
- package/src/routes/files/handlers.ts +297 -0
- package/src/routes/files/service.ts +313 -0
- package/src/routes/files.ts +12 -608
- package/src/routes/git/commit-service.ts +207 -0
- package/src/routes/git/commit.ts +6 -220
- package/src/routes/git/remote-service.ts +116 -0
- package/src/routes/git/remote.ts +8 -115
- package/src/routes/git/staging-service.ts +111 -0
- package/src/routes/git/staging.ts +10 -205
- package/src/routes/mcp/auth.ts +338 -0
- package/src/routes/mcp/lifecycle.ts +263 -0
- package/src/routes/mcp/servers.ts +212 -0
- package/src/routes/mcp/service.ts +664 -0
- package/src/routes/mcp/state.ts +13 -0
- package/src/routes/mcp.ts +6 -1233
- package/src/routes/ottorouter/billing.ts +593 -0
- package/src/routes/ottorouter/service.ts +92 -0
- package/src/routes/ottorouter/topup.ts +301 -0
- package/src/routes/ottorouter/wallet.ts +370 -0
- package/src/routes/ottorouter.ts +6 -1319
- package/src/routes/research/service.ts +339 -0
- package/src/routes/research.ts +12 -390
- package/src/routes/sessions/crud.ts +563 -0
- package/src/routes/sessions/queue.ts +242 -0
- package/src/routes/sessions/retry.ts +121 -0
- package/src/routes/sessions/service.ts +768 -0
- package/src/routes/sessions/share.ts +434 -0
- package/src/routes/sessions.ts +8 -1977
- package/src/routes/skills/service.ts +221 -0
- package/src/routes/skills/spec.ts +309 -0
- package/src/routes/skills.ts +31 -909
- package/src/routes/terminals/service.ts +326 -0
- package/src/routes/terminals.ts +19 -295
- package/src/routes/tunnel/service.ts +217 -0
- package/src/routes/tunnel.ts +29 -219
- package/src/runtime/agent/registry-prompts.ts +147 -0
- package/src/runtime/agent/registry.ts +6 -124
- package/src/runtime/agent/runner-errors.ts +116 -0
- package/src/runtime/agent/runner-reminders.ts +45 -0
- package/src/runtime/agent/runner-setup-model.ts +75 -0
- package/src/runtime/agent/runner-setup-prompt.ts +185 -0
- package/src/runtime/agent/runner-setup-tools.ts +103 -0
- package/src/runtime/agent/runner-setup-utils.ts +21 -0
- package/src/runtime/agent/runner-setup.ts +54 -288
- package/src/runtime/agent/runner-telemetry.ts +112 -0
- package/src/runtime/agent/runner-text.ts +108 -0
- package/src/runtime/agent/runner-tool-observer.ts +86 -0
- package/src/runtime/agent/runner.ts +79 -378
- package/src/runtime/prompt/builder.ts +5 -1
- package/src/runtime/prompt/capabilities.ts +13 -8
- package/src/runtime/provider/custom.ts +73 -0
- package/src/runtime/provider/index.ts +2 -85
- package/src/runtime/provider/reasoning-builders.ts +280 -0
- package/src/runtime/provider/reasoning.ts +67 -264
- package/src/tools/adapter/events.ts +116 -0
- package/src/tools/adapter/execution.ts +160 -0
- package/src/tools/adapter/pending.ts +37 -0
- package/src/tools/adapter/persistence.ts +166 -0
- package/src/tools/adapter/results.ts +97 -0
- package/src/tools/adapter.ts +124 -451
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
import {
|
|
3
|
+
discoverSkillFiles,
|
|
4
|
+
discoverSkills,
|
|
5
|
+
filterDiscoveredSkills,
|
|
6
|
+
findGitRoot,
|
|
7
|
+
loadConfig,
|
|
8
|
+
loadSkill,
|
|
9
|
+
loadSkillFile,
|
|
10
|
+
logger,
|
|
11
|
+
parseSkillFile,
|
|
12
|
+
validateSkillName,
|
|
13
|
+
writeSkillSettings,
|
|
14
|
+
} from '@ottocode/sdk';
|
|
15
|
+
import { serializeError } from '../../runtime/errors/api-error.ts';
|
|
16
|
+
|
|
17
|
+
function dedupeSkillsByName<T extends { name: string }>(skills: T[]): T[] {
|
|
18
|
+
const seen = new Set<string>();
|
|
19
|
+
return skills.filter((skill) => {
|
|
20
|
+
const key = skill.name.trim();
|
|
21
|
+
if (!key || seen.has(key)) return false;
|
|
22
|
+
seen.add(key);
|
|
23
|
+
return true;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function sortSkillsByName<T extends { name: string }>(skills: T[]): T[] {
|
|
28
|
+
return [...skills].sort((a, b) => a.name.localeCompare(b.name));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function mapSkillsWithEnabled(
|
|
32
|
+
discovered: Array<{
|
|
33
|
+
name: string;
|
|
34
|
+
description: string;
|
|
35
|
+
scope: string;
|
|
36
|
+
path: string;
|
|
37
|
+
}>,
|
|
38
|
+
cfg: Awaited<ReturnType<typeof loadConfig>>,
|
|
39
|
+
) {
|
|
40
|
+
return discovered.map((skill) => ({
|
|
41
|
+
name: skill.name,
|
|
42
|
+
description: skill.description,
|
|
43
|
+
scope: skill.scope,
|
|
44
|
+
path: skill.path,
|
|
45
|
+
enabled: cfg.skills?.items?.[skill.name]?.enabled !== false,
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function loadProjectSkills(projectRoot: string) {
|
|
50
|
+
const cfg = await loadConfig(projectRoot);
|
|
51
|
+
const repoRoot = (await findGitRoot(projectRoot)) ?? projectRoot;
|
|
52
|
+
const discovered = sortSkillsByName(
|
|
53
|
+
dedupeSkillsByName(await discoverSkills(projectRoot, repoRoot)),
|
|
54
|
+
);
|
|
55
|
+
const filtered = sortSkillsByName(
|
|
56
|
+
filterDiscoveredSkills(discovered, cfg.skills),
|
|
57
|
+
);
|
|
58
|
+
return { cfg, discovered, filtered };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function ensureSkillsDiscovered(projectRoot: string): Promise<void> {
|
|
62
|
+
const repoRoot = (await findGitRoot(projectRoot)) ?? projectRoot;
|
|
63
|
+
await discoverSkills(projectRoot, repoRoot);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function projectRootFromQuery(c: Context): string {
|
|
67
|
+
return c.req.query('project') || process.cwd();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function jsonError(c: Context, message: string, error: unknown) {
|
|
71
|
+
logger.error(message, error);
|
|
72
|
+
const errorResponse = serializeError(error);
|
|
73
|
+
return c.json(errorResponse, (errorResponse.error.status || 500) as 500);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function listSkills(c: Context) {
|
|
77
|
+
try {
|
|
78
|
+
const projectRoot = projectRootFromQuery(c);
|
|
79
|
+
const cfg = await loadConfig(projectRoot);
|
|
80
|
+
const repoRoot = (await findGitRoot(projectRoot)) ?? projectRoot;
|
|
81
|
+
const discovered = sortSkillsByName(
|
|
82
|
+
await discoverSkills(projectRoot, repoRoot),
|
|
83
|
+
);
|
|
84
|
+
const filtered = filterDiscoveredSkills(discovered, cfg.skills);
|
|
85
|
+
const unique = sortSkillsByName(dedupeSkillsByName(filtered));
|
|
86
|
+
return c.json({
|
|
87
|
+
skills: mapSkillsWithEnabled(unique, cfg),
|
|
88
|
+
});
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return jsonError(c, 'Failed to list skills', error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function getSkillsConfig(c: Context) {
|
|
95
|
+
try {
|
|
96
|
+
const { cfg, discovered, filtered } = await loadProjectSkills(
|
|
97
|
+
projectRootFromQuery(c),
|
|
98
|
+
);
|
|
99
|
+
return c.json({
|
|
100
|
+
enabled: cfg.skills?.enabled !== false,
|
|
101
|
+
totalCount: discovered.length,
|
|
102
|
+
enabledCount: filtered.length,
|
|
103
|
+
items: mapSkillsWithEnabled(discovered, cfg),
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return jsonError(c, 'Failed to get skills config', error);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function updateSkillsConfig(c: Context) {
|
|
111
|
+
try {
|
|
112
|
+
const projectRoot = projectRootFromQuery(c);
|
|
113
|
+
const body = await c.req.json<{
|
|
114
|
+
enabled?: boolean;
|
|
115
|
+
items?: Record<string, { enabled?: boolean }>;
|
|
116
|
+
}>();
|
|
117
|
+
await writeSkillSettings(
|
|
118
|
+
'global',
|
|
119
|
+
{
|
|
120
|
+
...(body.enabled !== undefined ? { enabled: body.enabled } : {}),
|
|
121
|
+
...(body.items ? { items: body.items } : {}),
|
|
122
|
+
},
|
|
123
|
+
projectRoot,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const { cfg, discovered, filtered } = await loadProjectSkills(projectRoot);
|
|
127
|
+
return c.json({
|
|
128
|
+
success: true,
|
|
129
|
+
enabled: cfg.skills?.enabled !== false,
|
|
130
|
+
totalCount: discovered.length,
|
|
131
|
+
enabledCount: filtered.length,
|
|
132
|
+
items: mapSkillsWithEnabled(discovered, cfg),
|
|
133
|
+
});
|
|
134
|
+
} catch (error) {
|
|
135
|
+
return jsonError(c, 'Failed to update skills config', error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function getSkill(c: Context) {
|
|
140
|
+
try {
|
|
141
|
+
const name = c.req.param('name');
|
|
142
|
+
await ensureSkillsDiscovered(projectRootFromQuery(c));
|
|
143
|
+
|
|
144
|
+
const skill = await loadSkill(name);
|
|
145
|
+
if (!skill) {
|
|
146
|
+
return c.json({ error: `Skill '${name}' not found` }, 404);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return c.json({
|
|
150
|
+
name: skill.metadata.name,
|
|
151
|
+
description: skill.metadata.description,
|
|
152
|
+
license: skill.metadata.license ?? null,
|
|
153
|
+
compatibility: skill.metadata.compatibility ?? null,
|
|
154
|
+
metadata: skill.metadata.metadata ?? null,
|
|
155
|
+
allowedTools: skill.metadata.allowedTools ?? null,
|
|
156
|
+
path: skill.path,
|
|
157
|
+
scope: skill.scope,
|
|
158
|
+
content: skill.content,
|
|
159
|
+
});
|
|
160
|
+
} catch (error) {
|
|
161
|
+
return jsonError(c, 'Failed to load skill', error);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function listSkillFiles(c: Context) {
|
|
166
|
+
try {
|
|
167
|
+
const name = c.req.param('name');
|
|
168
|
+
await ensureSkillsDiscovered(projectRootFromQuery(c));
|
|
169
|
+
const files = await discoverSkillFiles(name);
|
|
170
|
+
return c.json({ files });
|
|
171
|
+
} catch (error) {
|
|
172
|
+
return jsonError(c, 'Failed to list skill files', error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function getSkillFile(c: Context) {
|
|
177
|
+
try {
|
|
178
|
+
const name = c.req.param('name');
|
|
179
|
+
const filePath = c.req.path.replace(`/v1/skills/${name}/files/`, '');
|
|
180
|
+
await ensureSkillsDiscovered(projectRootFromQuery(c));
|
|
181
|
+
|
|
182
|
+
const result = await loadSkillFile(name, filePath);
|
|
183
|
+
if (!result) {
|
|
184
|
+
return c.json(
|
|
185
|
+
{ error: `File '${filePath}' not found in skill '${name}'` },
|
|
186
|
+
404,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return c.json({ content: result.content, path: result.resolvedPath });
|
|
190
|
+
} catch (error) {
|
|
191
|
+
return jsonError(c, 'Failed to load skill file', error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export async function validateSkill(c: Context) {
|
|
196
|
+
try {
|
|
197
|
+
const body = await c.req.json<{ content: string; path?: string }>();
|
|
198
|
+
if (!body.content) {
|
|
199
|
+
return c.json({ error: 'content is required' }, 400);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const skillPath = body.path ?? 'SKILL.md';
|
|
203
|
+
const skill = parseSkillFile(body.content, skillPath, 'cwd');
|
|
204
|
+
return c.json({
|
|
205
|
+
valid: true,
|
|
206
|
+
name: skill.metadata.name,
|
|
207
|
+
description: skill.metadata.description,
|
|
208
|
+
license: skill.metadata.license ?? null,
|
|
209
|
+
});
|
|
210
|
+
} catch (error) {
|
|
211
|
+
return c.json({
|
|
212
|
+
valid: false,
|
|
213
|
+
error: (error as Error).message,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function validateSkillNameRoute(c: Context) {
|
|
219
|
+
const name = c.req.param('name');
|
|
220
|
+
return c.json({ valid: validateSkillName(name) });
|
|
221
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
const projectQueryParameter = {
|
|
2
|
+
in: 'query',
|
|
3
|
+
name: 'project',
|
|
4
|
+
required: false,
|
|
5
|
+
schema: { type: 'string' },
|
|
6
|
+
description: 'Project root override (defaults to current working directory).',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const skillNamePathParameter = {
|
|
10
|
+
in: 'path',
|
|
11
|
+
name: 'name',
|
|
12
|
+
required: true,
|
|
13
|
+
schema: { type: 'string' },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const errorResponse = {
|
|
17
|
+
description: 'Bad Request',
|
|
18
|
+
content: {
|
|
19
|
+
'application/json': {
|
|
20
|
+
schema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
error: { type: 'string' },
|
|
24
|
+
},
|
|
25
|
+
required: ['error'],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const skillListItemSchema = {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
name: { type: 'string' },
|
|
35
|
+
description: { type: 'string' },
|
|
36
|
+
scope: { type: 'string' },
|
|
37
|
+
path: { type: 'string' },
|
|
38
|
+
},
|
|
39
|
+
required: ['name', 'description', 'scope', 'path'],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const skillConfigItemSchema = {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {
|
|
45
|
+
name: { type: 'string' },
|
|
46
|
+
description: { type: 'string' },
|
|
47
|
+
scope: { type: 'string' },
|
|
48
|
+
path: { type: 'string' },
|
|
49
|
+
enabled: { type: 'boolean' },
|
|
50
|
+
},
|
|
51
|
+
required: ['name', 'description', 'scope', 'path', 'enabled'],
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const skillConfigSchema = {
|
|
55
|
+
type: 'object',
|
|
56
|
+
properties: {
|
|
57
|
+
enabled: { type: 'boolean' },
|
|
58
|
+
totalCount: { type: 'number' },
|
|
59
|
+
enabledCount: { type: 'number' },
|
|
60
|
+
items: {
|
|
61
|
+
type: 'array',
|
|
62
|
+
items: skillConfigItemSchema,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
required: ['enabled', 'totalCount', 'enabledCount', 'items'],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const skillConfigUpdateSchema = {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
enabled: { type: 'boolean' },
|
|
72
|
+
items: {
|
|
73
|
+
type: 'object',
|
|
74
|
+
additionalProperties: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {
|
|
77
|
+
enabled: { type: 'boolean' },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const skillConfigUpdateResponseSchema = {
|
|
85
|
+
type: 'object',
|
|
86
|
+
properties: {
|
|
87
|
+
success: { type: 'boolean' },
|
|
88
|
+
...skillConfigSchema.properties,
|
|
89
|
+
},
|
|
90
|
+
required: ['success', 'enabled', 'totalCount', 'enabledCount', 'items'],
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const skillDetailSchema = {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
name: { type: 'string' },
|
|
97
|
+
description: { type: 'string' },
|
|
98
|
+
license: { type: 'string', nullable: true },
|
|
99
|
+
compatibility: { type: 'string', nullable: true },
|
|
100
|
+
metadata: { type: 'object', nullable: true },
|
|
101
|
+
allowedTools: {
|
|
102
|
+
type: 'array',
|
|
103
|
+
items: { type: 'string' },
|
|
104
|
+
nullable: true,
|
|
105
|
+
},
|
|
106
|
+
path: { type: 'string' },
|
|
107
|
+
scope: { type: 'string' },
|
|
108
|
+
content: { type: 'string' },
|
|
109
|
+
},
|
|
110
|
+
required: ['name', 'description', 'path', 'scope', 'content'],
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const skillFileListSchema = {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: {
|
|
116
|
+
files: {
|
|
117
|
+
type: 'array',
|
|
118
|
+
items: {
|
|
119
|
+
type: 'object',
|
|
120
|
+
properties: {
|
|
121
|
+
relativePath: { type: 'string' },
|
|
122
|
+
size: { type: 'number' },
|
|
123
|
+
},
|
|
124
|
+
required: ['relativePath', 'size'],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
required: ['files'],
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const skillFileSchema = {
|
|
132
|
+
type: 'object',
|
|
133
|
+
properties: {
|
|
134
|
+
content: { type: 'string' },
|
|
135
|
+
path: { type: 'string' },
|
|
136
|
+
},
|
|
137
|
+
required: ['content', 'path'],
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const validateSkillRequestSchema = {
|
|
141
|
+
type: 'object',
|
|
142
|
+
properties: {
|
|
143
|
+
content: { type: 'string' },
|
|
144
|
+
path: { type: 'string' },
|
|
145
|
+
},
|
|
146
|
+
required: ['content'],
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const validateSkillResponseSchema = {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
valid: { type: 'boolean' },
|
|
153
|
+
name: { type: 'string' },
|
|
154
|
+
description: { type: 'string' },
|
|
155
|
+
license: { type: 'string', nullable: true },
|
|
156
|
+
error: { type: 'string' },
|
|
157
|
+
},
|
|
158
|
+
required: ['valid'],
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const validateNameResponseSchema = {
|
|
162
|
+
type: 'object',
|
|
163
|
+
properties: {
|
|
164
|
+
valid: { type: 'boolean' },
|
|
165
|
+
},
|
|
166
|
+
required: ['valid'],
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
function jsonResponse(schema: object, description = 'OK') {
|
|
170
|
+
return {
|
|
171
|
+
description,
|
|
172
|
+
content: {
|
|
173
|
+
'application/json': { schema },
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export const listSkillsSpec = {
|
|
179
|
+
method: 'get',
|
|
180
|
+
path: '/v1/skills',
|
|
181
|
+
tags: ['config'],
|
|
182
|
+
operationId: 'listSkills',
|
|
183
|
+
summary: 'List discovered skills',
|
|
184
|
+
parameters: [projectQueryParameter],
|
|
185
|
+
responses: {
|
|
186
|
+
'200': jsonResponse({
|
|
187
|
+
type: 'object',
|
|
188
|
+
properties: {
|
|
189
|
+
skills: {
|
|
190
|
+
type: 'array',
|
|
191
|
+
items: skillListItemSchema,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
required: ['skills'],
|
|
195
|
+
}),
|
|
196
|
+
'500': errorResponse,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const getSkillsConfigSpec = {
|
|
201
|
+
method: 'get',
|
|
202
|
+
path: '/v1/config/skills',
|
|
203
|
+
tags: ['config'],
|
|
204
|
+
operationId: 'getSkillsConfig',
|
|
205
|
+
summary: 'Get skills enable/disable config and counts',
|
|
206
|
+
parameters: [projectQueryParameter],
|
|
207
|
+
responses: {
|
|
208
|
+
'200': jsonResponse(skillConfigSchema),
|
|
209
|
+
'500': errorResponse,
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export const updateSkillsConfigSpec = {
|
|
214
|
+
method: 'put',
|
|
215
|
+
path: '/v1/config/skills',
|
|
216
|
+
tags: ['config'],
|
|
217
|
+
operationId: 'updateSkillsConfig',
|
|
218
|
+
summary: 'Update skills enable/disable config',
|
|
219
|
+
parameters: [projectQueryParameter],
|
|
220
|
+
requestBody: {
|
|
221
|
+
required: true,
|
|
222
|
+
content: {
|
|
223
|
+
'application/json': { schema: skillConfigUpdateSchema },
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
responses: {
|
|
227
|
+
'200': jsonResponse(skillConfigUpdateResponseSchema),
|
|
228
|
+
'500': errorResponse,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
export const getSkillSpec = {
|
|
233
|
+
method: 'get',
|
|
234
|
+
path: '/v1/skills/{name}',
|
|
235
|
+
tags: ['config'],
|
|
236
|
+
operationId: 'getSkill',
|
|
237
|
+
summary: 'Get a skill by name',
|
|
238
|
+
parameters: [skillNamePathParameter, projectQueryParameter],
|
|
239
|
+
responses: {
|
|
240
|
+
'200': jsonResponse(skillDetailSchema),
|
|
241
|
+
'404': errorResponse,
|
|
242
|
+
'500': errorResponse,
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
export const listSkillFilesSpec = {
|
|
247
|
+
method: 'get',
|
|
248
|
+
path: '/v1/skills/{name}/files',
|
|
249
|
+
tags: ['config'],
|
|
250
|
+
operationId: 'listSkillFiles',
|
|
251
|
+
summary: 'List files in a skill directory',
|
|
252
|
+
parameters: [skillNamePathParameter, projectQueryParameter],
|
|
253
|
+
responses: {
|
|
254
|
+
'200': jsonResponse(skillFileListSchema),
|
|
255
|
+
'500': errorResponse,
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export const getSkillFileSpec = {
|
|
260
|
+
method: 'get',
|
|
261
|
+
path: '/v1/skills/{name}/files/{filePath}',
|
|
262
|
+
tags: ['config'],
|
|
263
|
+
operationId: 'getSkillFile',
|
|
264
|
+
summary: 'Read a specific file from a skill directory',
|
|
265
|
+
parameters: [
|
|
266
|
+
skillNamePathParameter,
|
|
267
|
+
{
|
|
268
|
+
in: 'path',
|
|
269
|
+
name: 'filePath',
|
|
270
|
+
required: true,
|
|
271
|
+
schema: { type: 'string' },
|
|
272
|
+
},
|
|
273
|
+
projectQueryParameter,
|
|
274
|
+
],
|
|
275
|
+
responses: {
|
|
276
|
+
'200': jsonResponse(skillFileSchema),
|
|
277
|
+
'404': errorResponse,
|
|
278
|
+
'500': errorResponse,
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export const validateSkillSpec = {
|
|
283
|
+
method: 'post',
|
|
284
|
+
path: '/v1/skills/validate',
|
|
285
|
+
tags: ['config'],
|
|
286
|
+
operationId: 'validateSkill',
|
|
287
|
+
summary: 'Validate a SKILL.md content',
|
|
288
|
+
requestBody: {
|
|
289
|
+
required: true,
|
|
290
|
+
content: {
|
|
291
|
+
'application/json': { schema: validateSkillRequestSchema },
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
responses: {
|
|
295
|
+
'200': jsonResponse(validateSkillResponseSchema),
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export const validateSkillNameSpec = {
|
|
300
|
+
method: 'get',
|
|
301
|
+
path: '/v1/skills/validate-name/{name}',
|
|
302
|
+
tags: ['config'],
|
|
303
|
+
operationId: 'validateSkillName',
|
|
304
|
+
summary: 'Check if a skill name is valid',
|
|
305
|
+
parameters: [skillNamePathParameter],
|
|
306
|
+
responses: {
|
|
307
|
+
'200': jsonResponse(validateNameResponseSchema),
|
|
308
|
+
},
|
|
309
|
+
};
|