@octo-cyber/ai 0.5.1 → 0.5.2
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/dist/ai.module.d.ts +1 -0
- package/dist/ai.module.d.ts.map +1 -1
- package/dist/ai.module.js +21 -2
- package/dist/ai.module.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/skill/controllers/skill.controller.d.ts +33 -0
- package/dist/skill/controllers/skill.controller.d.ts.map +1 -0
- package/dist/skill/controllers/skill.controller.js +264 -0
- package/dist/skill/controllers/skill.controller.js.map +1 -0
- package/dist/skill/entities/octo-skill.entity.d.ts +22 -0
- package/dist/skill/entities/octo-skill.entity.d.ts.map +1 -0
- package/dist/skill/entities/octo-skill.entity.js +91 -0
- package/dist/skill/entities/octo-skill.entity.js.map +1 -0
- package/dist/skill/index.d.ts +7 -0
- package/dist/skill/index.d.ts.map +1 -0
- package/dist/skill/index.js +17 -0
- package/dist/skill/index.js.map +1 -0
- package/dist/skill/services/skill-generator.service.d.ts +47 -0
- package/dist/skill/services/skill-generator.service.d.ts.map +1 -0
- package/dist/skill/services/skill-generator.service.js +232 -0
- package/dist/skill/services/skill-generator.service.js.map +1 -0
- package/dist/skill/services/skill-installer.service.d.ts +38 -0
- package/dist/skill/services/skill-installer.service.d.ts.map +1 -0
- package/dist/skill/services/skill-installer.service.js +150 -0
- package/dist/skill/services/skill-installer.service.js.map +1 -0
- package/dist/skill/services/skill-registry.service.d.ts +60 -0
- package/dist/skill/services/skill-registry.service.d.ts.map +1 -0
- package/dist/skill/services/skill-registry.service.js +147 -0
- package/dist/skill/services/skill-registry.service.js.map +1 -0
- package/dist/skill/types.d.ts +45 -0
- package/dist/skill/types.d.ts.map +1 -0
- package/dist/skill/types.js +6 -0
- package/dist/skill/types.js.map +1 -0
- package/package.json +5 -5
- package/web/components/SkillCard.tsx +139 -0
- package/web/components/SkillEditorDialog.tsx +77 -0
- package/web/components/SkillInstallDialog.tsx +134 -0
- package/web/index.ts +2 -0
- package/web/manifest.ts +1 -0
- package/web/messages/en-US.json +53 -0
- package/web/messages/zh-CN.json +53 -0
- package/web/pages/SkillsPage.tsx +206 -0
- package/web/services/skill-service.ts +89 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-generator.service.d.ts","sourceRoot":"","sources":["../../../src/skill/services/skill-generator.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EAEpB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,qBAAa,qBAAqB;IAChC;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB;IA+BnE;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAOpE;;;OAGG;IACH,OAAO,CAAC,eAAe;IAYvB;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IA+BpB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IAIxB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,gBAAgB;IAYxB;;OAEG;IACH,OAAO,CAAC,aAAa;CA2FtB"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SkillGeneratorService = void 0;
|
|
4
|
+
const core_1 = require("@octo-cyber/core");
|
|
5
|
+
/**
|
|
6
|
+
* Generates SKILL.md content from RouteRegistry metadata.
|
|
7
|
+
*
|
|
8
|
+
* Generation granularity: one module → one Skill file.
|
|
9
|
+
* Handles sparse metadata by inferring summaries from multiple sources.
|
|
10
|
+
*/
|
|
11
|
+
class SkillGeneratorService {
|
|
12
|
+
/**
|
|
13
|
+
* Generate a skill for a specific module.
|
|
14
|
+
*/
|
|
15
|
+
generateForModule(params) {
|
|
16
|
+
const { module, baseUrl, apiKey } = params;
|
|
17
|
+
const routes = core_1.RouteRegistry.getByModule(module);
|
|
18
|
+
if (routes.length === 0) {
|
|
19
|
+
throw new Error(`No routes found for module: ${module}`);
|
|
20
|
+
}
|
|
21
|
+
const endpoints = routes.map((r) => this.routeToEndpoint(r));
|
|
22
|
+
const grouped = this.groupByController(endpoints);
|
|
23
|
+
const moduleName = this.formatModuleName(module);
|
|
24
|
+
const skillName = `octo-${module}-api`;
|
|
25
|
+
const description = this.buildDescription(module, moduleName, endpoints);
|
|
26
|
+
const content = this.renderSkillMd({
|
|
27
|
+
skillName,
|
|
28
|
+
moduleName,
|
|
29
|
+
description,
|
|
30
|
+
baseUrl,
|
|
31
|
+
apiKey,
|
|
32
|
+
grouped,
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
name: skillName,
|
|
36
|
+
description,
|
|
37
|
+
content,
|
|
38
|
+
sourceModule: module,
|
|
39
|
+
version: '1.0',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Generate skills for all registered modules.
|
|
44
|
+
*/
|
|
45
|
+
generateAll(baseUrl, apiKey) {
|
|
46
|
+
const modules = core_1.RouteRegistry.getModules();
|
|
47
|
+
return modules.map((module) => this.generateForModule({ module, baseUrl, apiKey }));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Convert a RegisteredRoute to a simpler EndpointInfo,
|
|
51
|
+
* inferring summary if not present.
|
|
52
|
+
*/
|
|
53
|
+
routeToEndpoint(route) {
|
|
54
|
+
return {
|
|
55
|
+
method: route.method.toUpperCase(),
|
|
56
|
+
path: route.fullPath,
|
|
57
|
+
summary: route.summary || this.inferSummary(route),
|
|
58
|
+
permission: route.permission,
|
|
59
|
+
controller: route.controller,
|
|
60
|
+
controllerName: route.controllerMeta?.name,
|
|
61
|
+
tags: route.tags,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Infer a human-readable summary when route.summary is missing.
|
|
66
|
+
*
|
|
67
|
+
* Priority:
|
|
68
|
+
* 1. controllerMeta.name + HTTP method (e.g. "物料管理" + POST → "创建物料")
|
|
69
|
+
* 2. permission code (e.g. "erp:material:create" → "Create material")
|
|
70
|
+
* 3. handlerName camelCase split (e.g. "createMaterial" → "Create material")
|
|
71
|
+
* 4. HTTP method + path last segment (e.g. POST /materials → "Create materials")
|
|
72
|
+
*/
|
|
73
|
+
inferSummary(route) {
|
|
74
|
+
// Strategy 1: controller name + method verb
|
|
75
|
+
const ctrlName = route.controllerMeta?.name;
|
|
76
|
+
if (ctrlName) {
|
|
77
|
+
const verb = this.methodToChineseVerb(route.method);
|
|
78
|
+
if (verb)
|
|
79
|
+
return `${verb}${ctrlName}`;
|
|
80
|
+
}
|
|
81
|
+
// Strategy 2: permission code
|
|
82
|
+
if (route.permission) {
|
|
83
|
+
const parts = route.permission.split(':');
|
|
84
|
+
const action = parts[parts.length - 1];
|
|
85
|
+
const resource = parts.length >= 2 ? parts[parts.length - 2] : '';
|
|
86
|
+
if (action && resource) {
|
|
87
|
+
return `${this.capitalizeFirst(action)} ${resource}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Strategy 3: handlerName camelCase split
|
|
91
|
+
if (route.handlerName) {
|
|
92
|
+
return this.camelToWords(route.handlerName);
|
|
93
|
+
}
|
|
94
|
+
// Strategy 4: method + path last segment
|
|
95
|
+
const segments = route.fullPath.split('/').filter(Boolean);
|
|
96
|
+
const lastSeg = segments[segments.length - 1] ?? '';
|
|
97
|
+
const cleanSeg = lastSeg.startsWith(':') ? segments[segments.length - 2] ?? '' : lastSeg;
|
|
98
|
+
const verb = this.methodToEnglishVerb(route.method);
|
|
99
|
+
return `${verb} ${cleanSeg}`;
|
|
100
|
+
}
|
|
101
|
+
methodToChineseVerb(method) {
|
|
102
|
+
const map = {
|
|
103
|
+
get: '获取',
|
|
104
|
+
post: '创建',
|
|
105
|
+
put: '更新',
|
|
106
|
+
delete: '删除',
|
|
107
|
+
patch: '更新',
|
|
108
|
+
};
|
|
109
|
+
return map[method.toLowerCase()] ?? null;
|
|
110
|
+
}
|
|
111
|
+
methodToEnglishVerb(method) {
|
|
112
|
+
const map = {
|
|
113
|
+
get: 'Get',
|
|
114
|
+
post: 'Create',
|
|
115
|
+
put: 'Update',
|
|
116
|
+
delete: 'Delete',
|
|
117
|
+
patch: 'Patch',
|
|
118
|
+
};
|
|
119
|
+
return map[method.toLowerCase()] ?? method;
|
|
120
|
+
}
|
|
121
|
+
camelToWords(name) {
|
|
122
|
+
return name
|
|
123
|
+
.replace(/([A-Z])/g, ' $1')
|
|
124
|
+
.replace(/^./, (s) => s.toUpperCase())
|
|
125
|
+
.trim();
|
|
126
|
+
}
|
|
127
|
+
capitalizeFirst(str) {
|
|
128
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
129
|
+
}
|
|
130
|
+
formatModuleName(module) {
|
|
131
|
+
return module.charAt(0).toUpperCase() + module.slice(1);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Group endpoints by controller name for organized output.
|
|
135
|
+
*/
|
|
136
|
+
groupByController(endpoints) {
|
|
137
|
+
const map = new Map();
|
|
138
|
+
for (const ep of endpoints) {
|
|
139
|
+
const key = ep.controllerName || ep.controller || 'General';
|
|
140
|
+
const list = map.get(key) ?? [];
|
|
141
|
+
list.push(ep);
|
|
142
|
+
map.set(key, list);
|
|
143
|
+
}
|
|
144
|
+
return map;
|
|
145
|
+
}
|
|
146
|
+
buildDescription(module, moduleName, endpoints) {
|
|
147
|
+
const actions = endpoints
|
|
148
|
+
.slice(0, 3)
|
|
149
|
+
.map((e) => e.summary.toLowerCase())
|
|
150
|
+
.join(', ');
|
|
151
|
+
return `Octo ${moduleName} API — ${actions}, etc.`;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Render the full SKILL.md content.
|
|
155
|
+
*/
|
|
156
|
+
renderSkillMd(params) {
|
|
157
|
+
const { skillName, moduleName, description, baseUrl, apiKey, grouped } = params;
|
|
158
|
+
const authHeader = apiKey
|
|
159
|
+
? `Bearer ${apiKey}`
|
|
160
|
+
: 'Bearer <YOUR_API_KEY>';
|
|
161
|
+
const lines = [];
|
|
162
|
+
// YAML frontmatter
|
|
163
|
+
lines.push('---');
|
|
164
|
+
lines.push(`name: ${skillName}`);
|
|
165
|
+
lines.push(`description: >-`);
|
|
166
|
+
lines.push(` ${description}`);
|
|
167
|
+
lines.push(` Use when needing to interact with Octo ${moduleName} functionality.`);
|
|
168
|
+
lines.push('metadata:');
|
|
169
|
+
lines.push(' author: octo-system');
|
|
170
|
+
lines.push(' version: "1.0"');
|
|
171
|
+
lines.push(` module: ${params.skillName.replace('octo-', '').replace('-api', '')}`);
|
|
172
|
+
lines.push(' generated: "true"');
|
|
173
|
+
lines.push('---');
|
|
174
|
+
lines.push('');
|
|
175
|
+
// Title
|
|
176
|
+
lines.push(`# Octo ${moduleName} API`);
|
|
177
|
+
lines.push('');
|
|
178
|
+
// Connection
|
|
179
|
+
lines.push('## Connection');
|
|
180
|
+
lines.push(`- **Base URL**: ${baseUrl}`);
|
|
181
|
+
lines.push(`- **Auth Header**: \`Authorization: ${authHeader}\``);
|
|
182
|
+
lines.push('');
|
|
183
|
+
lines.push('Always include the Auth Header in every API request.');
|
|
184
|
+
lines.push('');
|
|
185
|
+
// Endpoints
|
|
186
|
+
lines.push('## Endpoints');
|
|
187
|
+
lines.push('');
|
|
188
|
+
for (const [groupName, endpoints] of grouped) {
|
|
189
|
+
lines.push(`### ${groupName}`);
|
|
190
|
+
lines.push('');
|
|
191
|
+
for (const ep of endpoints) {
|
|
192
|
+
const permNote = ep.permission
|
|
193
|
+
? ` *(requires: ${ep.permission})*`
|
|
194
|
+
: '';
|
|
195
|
+
lines.push(`- \`${ep.method} ${ep.path}\` — ${ep.summary}${permNote}`);
|
|
196
|
+
}
|
|
197
|
+
lines.push('');
|
|
198
|
+
}
|
|
199
|
+
// Response format
|
|
200
|
+
lines.push('## Response Format');
|
|
201
|
+
lines.push('');
|
|
202
|
+
lines.push('All endpoints return JSON in the standard format:');
|
|
203
|
+
lines.push('');
|
|
204
|
+
lines.push('```json');
|
|
205
|
+
lines.push('{');
|
|
206
|
+
lines.push(' "code": 0,');
|
|
207
|
+
lines.push(' "data": "<response data>",');
|
|
208
|
+
lines.push(' "message": "ok"');
|
|
209
|
+
lines.push('}');
|
|
210
|
+
lines.push('```');
|
|
211
|
+
lines.push('');
|
|
212
|
+
lines.push('- `code: 0` means success; non-zero indicates an error.');
|
|
213
|
+
lines.push('- Error responses include `code`, `message`, and optional `details`.');
|
|
214
|
+
lines.push('');
|
|
215
|
+
// Example
|
|
216
|
+
lines.push('## Examples');
|
|
217
|
+
lines.push('');
|
|
218
|
+
const firstEndpoint = [...grouped.values()][0]?.[0];
|
|
219
|
+
if (firstEndpoint) {
|
|
220
|
+
lines.push('```bash');
|
|
221
|
+
lines.push(`curl -X ${firstEndpoint.method} ${baseUrl}${firstEndpoint.path} \\`);
|
|
222
|
+
lines.push(` -H "Authorization: ${authHeader}" \\`);
|
|
223
|
+
lines.push(' -H "Content-Type: application/json"');
|
|
224
|
+
lines.push('```');
|
|
225
|
+
}
|
|
226
|
+
return lines.join('\n');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
exports.SkillGeneratorService = SkillGeneratorService;
|
|
230
|
+
// Register with DI container
|
|
231
|
+
core_1.Container.register(SkillGeneratorService);
|
|
232
|
+
//# sourceMappingURL=skill-generator.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-generator.service.js","sourceRoot":"","sources":["../../../src/skill/services/skill-generator.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { SkillTarget, SkillTargetInfo } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handles installing/uninstalling SKILL.md files to AI tool directories.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SkillInstallerService {
|
|
6
|
+
private readonly logger;
|
|
7
|
+
/**
|
|
8
|
+
* List available installation targets and their status.
|
|
9
|
+
*/
|
|
10
|
+
getTargets(): SkillTargetInfo[];
|
|
11
|
+
/**
|
|
12
|
+
* Install a skill to specified targets.
|
|
13
|
+
* Creates the skills directory and writes SKILL.md.
|
|
14
|
+
*/
|
|
15
|
+
install(skillName: string, content: string, targets: SkillTarget[]): {
|
|
16
|
+
installed: SkillTarget[];
|
|
17
|
+
failed: Array<{
|
|
18
|
+
target: SkillTarget;
|
|
19
|
+
error: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Uninstall a skill from specified targets.
|
|
24
|
+
* Removes the skill directory.
|
|
25
|
+
*/
|
|
26
|
+
uninstall(skillName: string, targets: SkillTarget[]): {
|
|
27
|
+
uninstalled: SkillTarget[];
|
|
28
|
+
failed: Array<{
|
|
29
|
+
target: SkillTarget;
|
|
30
|
+
error: string;
|
|
31
|
+
}>;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Check which targets currently have a specific skill installed.
|
|
35
|
+
*/
|
|
36
|
+
getInstalledTargets(skillName: string): SkillTarget[];
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=skill-installer.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installer.service.d.ts","sourceRoot":"","sources":["../../../src/skill/services/skill-installer.service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAuBhE;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IAEvD;;OAEG;IACH,UAAU,IAAI,eAAe,EAAE;IAU/B;;;OAGG;IACH,OAAO,CACL,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,WAAW,EAAE,GACrB;QAAE,SAAS,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,WAAW,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE;IA4BtF;;;OAGG;IACH,SAAS,CACP,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,WAAW,EAAE,GACrB;QAAE,WAAW,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,WAAW,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE;IA2BxF;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE;CAUtD"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SkillInstallerService = void 0;
|
|
37
|
+
const fs = __importStar(require("node:fs"));
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const os = __importStar(require("node:os"));
|
|
40
|
+
const core_1 = require("@octo-cyber/core");
|
|
41
|
+
/**
|
|
42
|
+
* Default skill directory mappings for each AI tool.
|
|
43
|
+
*/
|
|
44
|
+
const TARGET_CONFIGS = {
|
|
45
|
+
claude: {
|
|
46
|
+
name: 'Claude Code',
|
|
47
|
+
detectDir: path.join(os.homedir(), '.claude'),
|
|
48
|
+
skillsDir: path.join(os.homedir(), '.claude', 'skills'),
|
|
49
|
+
},
|
|
50
|
+
cursor: {
|
|
51
|
+
name: 'Cursor',
|
|
52
|
+
detectDir: path.join(os.homedir(), '.cursor'),
|
|
53
|
+
skillsDir: path.join(os.homedir(), '.cursor', 'skills'),
|
|
54
|
+
},
|
|
55
|
+
codex: {
|
|
56
|
+
name: 'Codex',
|
|
57
|
+
detectDir: path.join(os.homedir(), '.codex'),
|
|
58
|
+
skillsDir: path.join(os.homedir(), '.codex', 'skills'),
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Handles installing/uninstalling SKILL.md files to AI tool directories.
|
|
63
|
+
*/
|
|
64
|
+
class SkillInstallerService {
|
|
65
|
+
logger = core_1.Container.get(core_1.LoggerService);
|
|
66
|
+
/**
|
|
67
|
+
* List available installation targets and their status.
|
|
68
|
+
*/
|
|
69
|
+
getTargets() {
|
|
70
|
+
return Object.entries(TARGET_CONFIGS).map(([id, config]) => ({
|
|
71
|
+
id: id,
|
|
72
|
+
name: config.name,
|
|
73
|
+
skillsDir: config.skillsDir,
|
|
74
|
+
detectDir: config.detectDir,
|
|
75
|
+
isInstalled: fs.existsSync(config.detectDir),
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Install a skill to specified targets.
|
|
80
|
+
* Creates the skills directory and writes SKILL.md.
|
|
81
|
+
*/
|
|
82
|
+
install(skillName, content, targets) {
|
|
83
|
+
const installed = [];
|
|
84
|
+
const failed = [];
|
|
85
|
+
for (const target of targets) {
|
|
86
|
+
try {
|
|
87
|
+
const config = TARGET_CONFIGS[target];
|
|
88
|
+
if (!config) {
|
|
89
|
+
failed.push({ target, error: `Unknown target: ${target}` });
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const skillDir = path.join(config.skillsDir, skillName);
|
|
93
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
94
|
+
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), content, 'utf-8');
|
|
95
|
+
installed.push(target);
|
|
96
|
+
this.logger.info(`Skill "${skillName}" installed to ${config.name} at ${skillDir}`);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
100
|
+
failed.push({ target, error: msg });
|
|
101
|
+
this.logger.error(`Failed to install skill "${skillName}" to ${target}: ${msg}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { installed, failed };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Uninstall a skill from specified targets.
|
|
108
|
+
* Removes the skill directory.
|
|
109
|
+
*/
|
|
110
|
+
uninstall(skillName, targets) {
|
|
111
|
+
const uninstalled = [];
|
|
112
|
+
const failed = [];
|
|
113
|
+
for (const target of targets) {
|
|
114
|
+
try {
|
|
115
|
+
const config = TARGET_CONFIGS[target];
|
|
116
|
+
if (!config) {
|
|
117
|
+
failed.push({ target, error: `Unknown target: ${target}` });
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const skillDir = path.join(config.skillsDir, skillName);
|
|
121
|
+
if (fs.existsSync(skillDir)) {
|
|
122
|
+
fs.rmSync(skillDir, { recursive: true });
|
|
123
|
+
this.logger.info(`Skill "${skillName}" uninstalled from ${config.name}`);
|
|
124
|
+
}
|
|
125
|
+
uninstalled.push(target);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
129
|
+
failed.push({ target, error: msg });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return { uninstalled, failed };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check which targets currently have a specific skill installed.
|
|
136
|
+
*/
|
|
137
|
+
getInstalledTargets(skillName) {
|
|
138
|
+
const installed = [];
|
|
139
|
+
for (const [id, config] of Object.entries(TARGET_CONFIGS)) {
|
|
140
|
+
const skillPath = path.join(config.skillsDir, skillName, 'SKILL.md');
|
|
141
|
+
if (fs.existsSync(skillPath)) {
|
|
142
|
+
installed.push(id);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return installed;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.SkillInstallerService = SkillInstallerService;
|
|
149
|
+
core_1.Container.register(SkillInstallerService);
|
|
150
|
+
//# sourceMappingURL=skill-installer.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installer.service.js","sourceRoot":"","sources":["../../../src/skill/services/skill-installer.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { OctoSkill } from '../entities/octo-skill.entity.js';
|
|
2
|
+
import type { SkillSourceType } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Manages OctoSkill CRUD and orchestrates skill (re)generation.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SkillRegistryService {
|
|
7
|
+
private repo;
|
|
8
|
+
private readonly logger;
|
|
9
|
+
private readonly generator;
|
|
10
|
+
initialize(): void;
|
|
11
|
+
/**
|
|
12
|
+
* Regenerate skills for all modules from RouteRegistry.
|
|
13
|
+
* Skips skills that have been manually edited (isEdited=true).
|
|
14
|
+
*/
|
|
15
|
+
regenerateSkills(baseUrl: string, apiKey?: string): Promise<{
|
|
16
|
+
created: string[];
|
|
17
|
+
updated: string[];
|
|
18
|
+
skipped: string[];
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* List all skills with optional filter.
|
|
22
|
+
*/
|
|
23
|
+
listSkills(filter?: {
|
|
24
|
+
isEnabled?: boolean;
|
|
25
|
+
sourceType?: SkillSourceType;
|
|
26
|
+
}): Promise<OctoSkill[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Get a single skill by ID.
|
|
29
|
+
*/
|
|
30
|
+
getSkill(id: string): Promise<OctoSkill | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Create a custom skill.
|
|
33
|
+
*/
|
|
34
|
+
createCustomSkill(data: {
|
|
35
|
+
name: string;
|
|
36
|
+
description: string;
|
|
37
|
+
content: string;
|
|
38
|
+
}): Promise<OctoSkill>;
|
|
39
|
+
/**
|
|
40
|
+
* Update skill content (marks as edited to prevent auto-overwrite).
|
|
41
|
+
*/
|
|
42
|
+
updateSkillContent(id: string, content: string): Promise<OctoSkill>;
|
|
43
|
+
/**
|
|
44
|
+
* Update skill metadata (name, description).
|
|
45
|
+
*/
|
|
46
|
+
updateSkill(id: string, data: Partial<Pick<OctoSkill, 'name' | 'description' | 'content'>>): Promise<OctoSkill>;
|
|
47
|
+
/**
|
|
48
|
+
* Toggle skill enabled state.
|
|
49
|
+
*/
|
|
50
|
+
toggleSkill(id: string): Promise<OctoSkill>;
|
|
51
|
+
/**
|
|
52
|
+
* Delete a skill.
|
|
53
|
+
*/
|
|
54
|
+
deleteSkill(id: string): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Update install targets for a skill (called by installer).
|
|
57
|
+
*/
|
|
58
|
+
updateInstallTargets(id: string, targets: string[]): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=skill-registry.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-registry.service.d.ts","sourceRoot":"","sources":["../../../src/skill/services/skill-registry.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAElE,UAAU,IAAI,IAAI;IAKlB;;;OAGG;IACG,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAyCvE;;OAEG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE;QACxB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,UAAU,CAAC,EAAE,eAAe,CAAC;KAC9B,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAOxB;;OAEG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAIrD;;OAEG;IACG,iBAAiB,CAAC,IAAI,EAAE;QAC5B,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,SAAS,CAAC;IAYtB;;OAEG;IACG,kBAAkB,CACtB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,SAAS,CAAC;IAQrB;;OAEG;IACG,WAAW,CACf,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC,CAAC,GACjE,OAAO,CAAC,SAAS,CAAC;IAYrB;;OAEG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAOjD;;OAEG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C;;OAEG;IACG,oBAAoB,CACxB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC;CAOjB"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SkillRegistryService = void 0;
|
|
4
|
+
const core_1 = require("@octo-cyber/core");
|
|
5
|
+
const octo_skill_entity_js_1 = require("../entities/octo-skill.entity.js");
|
|
6
|
+
const skill_generator_service_js_1 = require("./skill-generator.service.js");
|
|
7
|
+
/**
|
|
8
|
+
* Manages OctoSkill CRUD and orchestrates skill (re)generation.
|
|
9
|
+
*/
|
|
10
|
+
class SkillRegistryService {
|
|
11
|
+
repo;
|
|
12
|
+
logger = core_1.Container.get(core_1.LoggerService);
|
|
13
|
+
generator = core_1.Container.get(skill_generator_service_js_1.SkillGeneratorService);
|
|
14
|
+
initialize() {
|
|
15
|
+
const db = core_1.Container.get(core_1.DatabaseService);
|
|
16
|
+
this.repo = db.getRepository(octo_skill_entity_js_1.OctoSkill);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Regenerate skills for all modules from RouteRegistry.
|
|
20
|
+
* Skips skills that have been manually edited (isEdited=true).
|
|
21
|
+
*/
|
|
22
|
+
async regenerateSkills(baseUrl, apiKey) {
|
|
23
|
+
const results = this.generator.generateAll(baseUrl, apiKey);
|
|
24
|
+
const created = [];
|
|
25
|
+
const updated = [];
|
|
26
|
+
const skipped = [];
|
|
27
|
+
for (const result of results) {
|
|
28
|
+
const existing = await this.repo.findOneBy({ name: result.name });
|
|
29
|
+
if (existing) {
|
|
30
|
+
if (existing.isEdited) {
|
|
31
|
+
skipped.push(result.name);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
existing.description = result.description;
|
|
35
|
+
existing.content = result.content;
|
|
36
|
+
existing.version = result.version;
|
|
37
|
+
await this.repo.save(existing);
|
|
38
|
+
updated.push(result.name);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const skill = this.repo.create({
|
|
42
|
+
name: result.name,
|
|
43
|
+
description: result.description,
|
|
44
|
+
sourceModule: result.sourceModule,
|
|
45
|
+
sourceType: 'module',
|
|
46
|
+
content: result.content,
|
|
47
|
+
version: result.version,
|
|
48
|
+
isEnabled: true,
|
|
49
|
+
isEdited: false,
|
|
50
|
+
});
|
|
51
|
+
await this.repo.save(skill);
|
|
52
|
+
created.push(result.name);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
this.logger.info(`Skill regeneration: ${created.length} created, ${updated.length} updated, ${skipped.length} skipped`);
|
|
56
|
+
return { created, updated, skipped };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* List all skills with optional filter.
|
|
60
|
+
*/
|
|
61
|
+
async listSkills(filter) {
|
|
62
|
+
const where = {};
|
|
63
|
+
if (filter?.isEnabled !== undefined)
|
|
64
|
+
where.isEnabled = filter.isEnabled;
|
|
65
|
+
if (filter?.sourceType)
|
|
66
|
+
where.sourceType = filter.sourceType;
|
|
67
|
+
return this.repo.find({ where, order: { name: 'ASC' } });
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get a single skill by ID.
|
|
71
|
+
*/
|
|
72
|
+
async getSkill(id) {
|
|
73
|
+
return this.repo.findOneBy({ id });
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a custom skill.
|
|
77
|
+
*/
|
|
78
|
+
async createCustomSkill(data) {
|
|
79
|
+
const skill = this.repo.create({
|
|
80
|
+
...data,
|
|
81
|
+
sourceModule: 'custom',
|
|
82
|
+
sourceType: 'custom',
|
|
83
|
+
version: '1.0',
|
|
84
|
+
isEnabled: true,
|
|
85
|
+
isEdited: true,
|
|
86
|
+
});
|
|
87
|
+
return this.repo.save(skill);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Update skill content (marks as edited to prevent auto-overwrite).
|
|
91
|
+
*/
|
|
92
|
+
async updateSkillContent(id, content) {
|
|
93
|
+
const skill = await this.repo.findOneBy({ id });
|
|
94
|
+
if (!skill)
|
|
95
|
+
throw new Error(`Skill not found: ${id}`);
|
|
96
|
+
skill.content = content;
|
|
97
|
+
skill.isEdited = true;
|
|
98
|
+
return this.repo.save(skill);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Update skill metadata (name, description).
|
|
102
|
+
*/
|
|
103
|
+
async updateSkill(id, data) {
|
|
104
|
+
const skill = await this.repo.findOneBy({ id });
|
|
105
|
+
if (!skill)
|
|
106
|
+
throw new Error(`Skill not found: ${id}`);
|
|
107
|
+
if (data.name !== undefined)
|
|
108
|
+
skill.name = data.name;
|
|
109
|
+
if (data.description !== undefined)
|
|
110
|
+
skill.description = data.description;
|
|
111
|
+
if (data.content !== undefined) {
|
|
112
|
+
skill.content = data.content;
|
|
113
|
+
skill.isEdited = true;
|
|
114
|
+
}
|
|
115
|
+
return this.repo.save(skill);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Toggle skill enabled state.
|
|
119
|
+
*/
|
|
120
|
+
async toggleSkill(id) {
|
|
121
|
+
const skill = await this.repo.findOneBy({ id });
|
|
122
|
+
if (!skill)
|
|
123
|
+
throw new Error(`Skill not found: ${id}`);
|
|
124
|
+
skill.isEnabled = !skill.isEnabled;
|
|
125
|
+
return this.repo.save(skill);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Delete a skill.
|
|
129
|
+
*/
|
|
130
|
+
async deleteSkill(id) {
|
|
131
|
+
await this.repo.delete(id);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Update install targets for a skill (called by installer).
|
|
135
|
+
*/
|
|
136
|
+
async updateInstallTargets(id, targets) {
|
|
137
|
+
const skill = await this.repo.findOneBy({ id });
|
|
138
|
+
if (!skill)
|
|
139
|
+
throw new Error(`Skill not found: ${id}`);
|
|
140
|
+
skill.installTargets = targets.length > 0 ? JSON.stringify(targets) : null;
|
|
141
|
+
skill.lastInstalledAt = new Date();
|
|
142
|
+
await this.repo.save(skill);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.SkillRegistryService = SkillRegistryService;
|
|
146
|
+
core_1.Container.register(SkillRegistryService);
|
|
147
|
+
//# sourceMappingURL=skill-registry.service.js.map
|