@hyorman/copilot-proxy-core 1.0.0

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.
Files changed (58) hide show
  1. package/out/assistants/index.d.ts +15 -0
  2. package/out/assistants/index.js +16 -0
  3. package/out/assistants/index.js.map +1 -0
  4. package/out/assistants/routes.d.ts +16 -0
  5. package/out/assistants/routes.js +597 -0
  6. package/out/assistants/routes.js.map +1 -0
  7. package/out/assistants/runner.d.ts +48 -0
  8. package/out/assistants/runner.js +851 -0
  9. package/out/assistants/runner.js.map +1 -0
  10. package/out/assistants/state.d.ts +81 -0
  11. package/out/assistants/state.js +351 -0
  12. package/out/assistants/state.js.map +1 -0
  13. package/out/assistants/tools.d.ts +4 -0
  14. package/out/assistants/tools.js +8 -0
  15. package/out/assistants/tools.js.map +1 -0
  16. package/out/assistants/types.d.ts +254 -0
  17. package/out/assistants/types.js +5 -0
  18. package/out/assistants/types.js.map +1 -0
  19. package/out/backend.d.ts +24 -0
  20. package/out/backend.js +12 -0
  21. package/out/backend.js.map +1 -0
  22. package/out/index.d.ts +13 -0
  23. package/out/index.js +21 -0
  24. package/out/index.js.map +1 -0
  25. package/out/server.d.ts +12 -0
  26. package/out/server.js +504 -0
  27. package/out/server.js.map +1 -0
  28. package/out/skills/index.d.ts +3 -0
  29. package/out/skills/index.js +4 -0
  30. package/out/skills/index.js.map +1 -0
  31. package/out/skills/manifest.d.ts +25 -0
  32. package/out/skills/manifest.js +96 -0
  33. package/out/skills/manifest.js.map +1 -0
  34. package/out/skills/resolver.d.ts +22 -0
  35. package/out/skills/resolver.js +66 -0
  36. package/out/skills/resolver.js.map +1 -0
  37. package/out/skills/routes.d.ts +3 -0
  38. package/out/skills/routes.js +191 -0
  39. package/out/skills/routes.js.map +1 -0
  40. package/out/skills/state.d.ts +35 -0
  41. package/out/skills/state.js +155 -0
  42. package/out/skills/state.js.map +1 -0
  43. package/out/skills/storage.d.ts +30 -0
  44. package/out/skills/storage.js +171 -0
  45. package/out/skills/storage.js.map +1 -0
  46. package/out/skills/types.d.ts +141 -0
  47. package/out/skills/types.js +8 -0
  48. package/out/skills/types.js.map +1 -0
  49. package/out/toolConvert.d.ts +24 -0
  50. package/out/toolConvert.js +56 -0
  51. package/out/toolConvert.js.map +1 -0
  52. package/out/types.d.ts +291 -0
  53. package/out/types.js +2 -0
  54. package/out/types.js.map +1 -0
  55. package/out/utils.d.ts +28 -0
  56. package/out/utils.js +81 -0
  57. package/out/utils.js.map +1 -0
  58. package/package.json +36 -0
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Parse a SKILL.md manifest file to extract metadata
3
+ * @param content - Raw string content of a SKILL.md file
4
+ * @returns Parsed SkillManifest object
5
+ * @throws Error if frontmatter is invalid or required fields are missing
6
+ */
7
+ export function parseManifest(content) {
8
+ const lines = content.split('\n');
9
+ // Find opening --- (must be the first non-blank line)
10
+ let openingIndex = -1;
11
+ for (let i = 0; i < lines.length; i++) {
12
+ if (lines[i].trim() === '')
13
+ continue;
14
+ if (lines[i].trim() === '---') {
15
+ openingIndex = i;
16
+ }
17
+ break;
18
+ }
19
+ if (openingIndex === -1) {
20
+ throw new Error('No YAML frontmatter found. SKILL.md must start with --- delimiter.');
21
+ }
22
+ // Find closing ---
23
+ let closingIndex = -1;
24
+ for (let i = openingIndex + 1; i < lines.length; i++) {
25
+ if (lines[i].trim() === '---') {
26
+ closingIndex = i;
27
+ break;
28
+ }
29
+ }
30
+ if (closingIndex === -1) {
31
+ throw new Error('Invalid YAML frontmatter. Missing closing --- delimiter.');
32
+ }
33
+ // Extract frontmatter content
34
+ const frontmatterLines = lines.slice(openingIndex + 1, closingIndex);
35
+ // Parse key-value pairs
36
+ const metadata = {};
37
+ for (const line of frontmatterLines) {
38
+ const trimmedLine = line.trim();
39
+ if (trimmedLine === '')
40
+ continue;
41
+ const colonIndex = trimmedLine.indexOf(':');
42
+ if (colonIndex === -1)
43
+ continue;
44
+ const key = trimmedLine.substring(0, colonIndex).trim();
45
+ const value = trimmedLine.substring(colonIndex + 1).trim();
46
+ metadata[key] = value;
47
+ }
48
+ // Validate required fields
49
+ if (!metadata.name || metadata.name === '') {
50
+ throw new Error('SKILL.md frontmatter must contain a "name" field.');
51
+ }
52
+ if (!metadata.description || metadata.description === '') {
53
+ throw new Error('SKILL.md frontmatter must contain a "description" field.');
54
+ }
55
+ // Extract body (everything after closing ---)
56
+ const body = lines.slice(closingIndex + 1).join('\n').trim();
57
+ return {
58
+ name: metadata.name,
59
+ description: metadata.description,
60
+ body,
61
+ };
62
+ }
63
+ /**
64
+ * Find the SKILL.md manifest file in an array of uploaded files
65
+ * @param files - Array of uploaded files
66
+ * @returns The matching SkillFile
67
+ * @throws Error if no manifest file or multiple manifest files are found
68
+ */
69
+ export function findManifestFile(files) {
70
+ const manifestFiles = files.filter((file) => {
71
+ const basename = file.path.split('/').pop()?.toLowerCase();
72
+ return basename === 'skill.md';
73
+ });
74
+ if (manifestFiles.length === 0) {
75
+ throw new Error('No SKILL.md manifest file found in the uploaded bundle.');
76
+ }
77
+ if (manifestFiles.length > 1) {
78
+ throw new Error('Multiple SKILL.md manifest files found. Only one is allowed.');
79
+ }
80
+ return manifestFiles[0];
81
+ }
82
+ /**
83
+ * Validate and parse a skill bundle
84
+ * @param files - Array of files from the uploaded bundle
85
+ * @returns Object containing parsed manifest and the manifest file reference
86
+ * @throws Error if validation fails
87
+ */
88
+ export function validateBundle(files) {
89
+ const manifestFile = findManifestFile(files);
90
+ const manifest = parseManifest(manifestFile.content.toString('utf-8'));
91
+ return {
92
+ manifest,
93
+ manifestFile,
94
+ };
95
+ }
96
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/skills/manifest.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,sDAAsD;IACtD,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,SAAS;QACrC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;YAC9B,YAAY,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,MAAM;IACR,CAAC;IAED,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;IACxF,CAAC;IAED,mBAAmB;IACnB,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,YAAY,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrD,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;YAC9B,YAAY,GAAG,CAAC,CAAC;YACjB,MAAM;QACR,CAAC;IACH,CAAC;IAED,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,8BAA8B;IAC9B,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC;IAErE,wBAAwB;IACxB,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,WAAW,KAAK,EAAE;YAAE,SAAS;QAEjC,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5C,IAAI,UAAU,KAAK,CAAC,CAAC;YAAE,SAAS;QAEhC,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;QACxD,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE3D,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,2BAA2B;IAC3B,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW,KAAK,EAAE,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,8CAA8C;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAE7D,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,IAAI;KACL,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAkB;IACjD,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;QAC3D,OAAO,QAAQ,KAAK,UAAU,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAkB;IAElB,MAAM,YAAY,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvE,OAAO;QACL,QAAQ;QACR,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { SkillAttachment } from './types.js';
2
+ /**
3
+ * Resolved skill content ready for injection into the model context.
4
+ */
5
+ export interface ResolvedSkill {
6
+ name: string;
7
+ description: string;
8
+ body: string;
9
+ }
10
+ /**
11
+ * Resolve an array of skill attachments into instruction text blocks.
12
+ * - SkillReference: looks up the skill in state and reads the manifest body
13
+ * - InlineSkill: decodes base64 source as a SKILL.md and extracts the body
14
+ *
15
+ * Returns an array of resolved skills. Throws on unresolvable references.
16
+ */
17
+ export declare function resolveSkills(attachments: SkillAttachment[]): ResolvedSkill[];
18
+ /**
19
+ * Build a combined instruction block from resolved skills.
20
+ * Returns a string to prepend/append to the system prompt, or empty string if no skills.
21
+ */
22
+ export declare function buildSkillInstructions(skills: ResolvedSkill[]): string;
@@ -0,0 +1,66 @@
1
+ import { skillsState } from './state.js';
2
+ /**
3
+ * Resolve an array of skill attachments into instruction text blocks.
4
+ * - SkillReference: looks up the skill in state and reads the manifest body
5
+ * - InlineSkill: decodes base64 source as a SKILL.md and extracts the body
6
+ *
7
+ * Returns an array of resolved skills. Throws on unresolvable references.
8
+ */
9
+ export function resolveSkills(attachments) {
10
+ const resolved = [];
11
+ for (const attachment of attachments) {
12
+ if (attachment.type === 'skill_reference') {
13
+ resolved.push(resolveReference(attachment));
14
+ }
15
+ else if (attachment.type === 'inline') {
16
+ resolved.push(resolveInline(attachment));
17
+ }
18
+ }
19
+ return resolved;
20
+ }
21
+ function resolveReference(ref) {
22
+ const skill = skillsState.getSkill(ref.skill_id);
23
+ if (!skill) {
24
+ throw new Error(`Skill not found: ${ref.skill_id}`);
25
+ }
26
+ let version;
27
+ if (ref.version === 'latest') {
28
+ version = skill.versions.find((v) => v.version === skill.latest_version);
29
+ }
30
+ else if (typeof ref.version === 'number') {
31
+ version = skill.versions.find((v) => v.version === ref.version);
32
+ }
33
+ else {
34
+ // Default: use default_version
35
+ version = skill.versions.find((v) => v.version === skill.default_version);
36
+ }
37
+ if (!version) {
38
+ throw new Error(`Version ${ref.version ?? skill.default_version} not found for skill ${ref.skill_id}`);
39
+ }
40
+ return {
41
+ name: version.manifest.name,
42
+ description: version.manifest.description,
43
+ body: version.manifest.body,
44
+ };
45
+ }
46
+ function resolveInline(inline) {
47
+ // Inline skills provide their content as base64-encoded data.
48
+ // For simplicity, treat the decoded content as the skill body directly.
49
+ const decoded = Buffer.from(inline.source.data, 'base64').toString('utf-8');
50
+ return {
51
+ name: inline.name,
52
+ description: inline.description,
53
+ body: decoded,
54
+ };
55
+ }
56
+ /**
57
+ * Build a combined instruction block from resolved skills.
58
+ * Returns a string to prepend/append to the system prompt, or empty string if no skills.
59
+ */
60
+ export function buildSkillInstructions(skills) {
61
+ if (skills.length === 0)
62
+ return '';
63
+ const blocks = skills.map((s) => `<skill name="${s.name}">\n${s.body}\n</skill>`);
64
+ return `\n\n<!-- Attached Skills -->\n${blocks.join('\n\n')}`;
65
+ }
66
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/skills/resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export declare function setSkillStorageDir(dir: string): void;
3
+ export default router;
@@ -0,0 +1,191 @@
1
+ import { Router } from 'express';
2
+ import multer from 'multer';
3
+ import { errorResponse, notFoundError } from '../utils.js';
4
+ import { skillsState } from './state.js';
5
+ import { validateBundle } from './manifest.js';
6
+ import { processMultipartFiles, processZipUpload, saveSkillVersion, deleteSkillStorage, guessContentType, } from './storage.js';
7
+ const router = Router();
8
+ const upload = multer({
9
+ storage: multer.memoryStorage(),
10
+ limits: { fileSize: 50 * 1024 * 1024 },
11
+ });
12
+ let storageDir = '';
13
+ export function setSkillStorageDir(dir) {
14
+ storageDir = dir;
15
+ }
16
+ function parsePaginationParams(query) {
17
+ return {
18
+ limit: query.limit ? Math.min(parseInt(query.limit, 10), 100) : 20,
19
+ order: query.order ?? 'desc',
20
+ after: query.after,
21
+ before: query.before,
22
+ };
23
+ }
24
+ /**
25
+ * Process uploaded multer files into SkillFile[], detecting zip vs multipart.
26
+ */
27
+ async function extractSkillFiles(files) {
28
+ const firstFile = files[0];
29
+ const isZip = firstFile.mimetype === 'application/zip' || firstFile.originalname.endsWith('.zip');
30
+ if (isZip) {
31
+ return processZipUpload(firstFile.buffer);
32
+ }
33
+ return processMultipartFiles(files);
34
+ }
35
+ function buildVersionFiles(files) {
36
+ return files.map((f) => ({
37
+ path: f.path,
38
+ content_type: guessContentType(f.path),
39
+ size: f.size,
40
+ }));
41
+ }
42
+ // POST /v1/skills — create a new skill from file upload
43
+ router.post('/', upload.any(), async (req, res) => {
44
+ try {
45
+ const multerFiles = req.files;
46
+ if (!multerFiles || multerFiles.length === 0) {
47
+ return res.status(400).json(errorResponse('No files provided'));
48
+ }
49
+ let skillFiles;
50
+ try {
51
+ skillFiles = await extractSkillFiles(multerFiles);
52
+ }
53
+ catch (error) {
54
+ return res.status(400).json(errorResponse(error instanceof Error ? error.message : 'Failed to process files'));
55
+ }
56
+ let manifest;
57
+ try {
58
+ const result = validateBundle(skillFiles);
59
+ manifest = result.manifest;
60
+ }
61
+ catch (error) {
62
+ return res.status(400).json(errorResponse(error instanceof Error ? error.message : 'Invalid skill bundle'));
63
+ }
64
+ const now = Math.floor(Date.now() / 1000);
65
+ const skillId = skillsState.generateSkillId();
66
+ const version = {
67
+ version: 1,
68
+ created_at: now,
69
+ files: buildVersionFiles(skillFiles),
70
+ manifest,
71
+ };
72
+ const skill = {
73
+ id: skillId,
74
+ object: 'skill',
75
+ created_at: now,
76
+ name: manifest.name,
77
+ description: manifest.description,
78
+ default_version: 1,
79
+ latest_version: 1,
80
+ versions: [version],
81
+ metadata: {},
82
+ };
83
+ skillsState.createSkill(skill);
84
+ saveSkillVersion(storageDir, skillId, 1, skillFiles);
85
+ return res.status(201).json(skillsState.toSkillResponse(skill));
86
+ }
87
+ catch (error) {
88
+ console.error('Error creating skill:', error);
89
+ return res.status(500).json(errorResponse(error instanceof Error ? error.message : 'Internal server error'));
90
+ }
91
+ });
92
+ // GET /v1/skills — list skills (paginated)
93
+ router.get('/', (req, res) => {
94
+ const pagination = parsePaginationParams(req.query);
95
+ return res.json(skillsState.listSkills(pagination));
96
+ });
97
+ // GET /v1/skills/:skill_id — retrieve a skill
98
+ router.get('/:skill_id', (req, res) => {
99
+ const response = skillsState.getSkillResponse(req.params.skill_id);
100
+ if (!response) {
101
+ return res.status(404).json(notFoundError('skill'));
102
+ }
103
+ return res.json(response);
104
+ });
105
+ // POST /v1/skills/:skill_id — update a skill (default_version, metadata)
106
+ router.post('/:skill_id', (req, res) => {
107
+ const { skill_id } = req.params;
108
+ const body = req.body;
109
+ const skill = skillsState.getSkill(skill_id);
110
+ if (!skill) {
111
+ return res.status(404).json(notFoundError('skill'));
112
+ }
113
+ if (body.default_version !== undefined) {
114
+ const versionExists = skill.versions.some((v) => v.version === body.default_version);
115
+ if (!versionExists) {
116
+ return res.status(400).json(errorResponse(`Version ${body.default_version} does not exist for this skill`));
117
+ }
118
+ }
119
+ const updated = skillsState.updateSkill(skill_id, body);
120
+ if (!updated) {
121
+ return res.status(404).json(notFoundError('skill'));
122
+ }
123
+ return res.json(skillsState.toSkillResponse(updated));
124
+ });
125
+ // DELETE /v1/skills/:skill_id — delete a skill
126
+ router.delete('/:skill_id', (req, res) => {
127
+ const { skill_id } = req.params;
128
+ const deleted = skillsState.deleteSkill(skill_id);
129
+ if (deleted) {
130
+ deleteSkillStorage(storageDir, skill_id);
131
+ }
132
+ return res.json({
133
+ id: skill_id,
134
+ object: 'skill.deleted',
135
+ deleted,
136
+ });
137
+ });
138
+ // POST /v1/skills/:skill_id/versions — upload a new version
139
+ router.post('/:skill_id/versions', upload.any(), async (req, res) => {
140
+ try {
141
+ const { skill_id } = req.params;
142
+ const multerFiles = req.files;
143
+ if (!multerFiles || multerFiles.length === 0) {
144
+ return res.status(400).json(errorResponse('No files provided'));
145
+ }
146
+ const skill = skillsState.getSkill(skill_id);
147
+ if (!skill) {
148
+ return res.status(404).json(notFoundError('skill'));
149
+ }
150
+ let skillFiles;
151
+ try {
152
+ skillFiles = await extractSkillFiles(multerFiles);
153
+ }
154
+ catch (error) {
155
+ return res.status(400).json(errorResponse(error instanceof Error ? error.message : 'Failed to process files'));
156
+ }
157
+ let manifest;
158
+ try {
159
+ const result = validateBundle(skillFiles);
160
+ manifest = result.manifest;
161
+ }
162
+ catch (error) {
163
+ return res.status(400).json(errorResponse(error instanceof Error ? error.message : 'Invalid skill bundle'));
164
+ }
165
+ const newVersionNum = skill.latest_version + 1;
166
+ const now = Math.floor(Date.now() / 1000);
167
+ const version = {
168
+ version: newVersionNum,
169
+ created_at: now,
170
+ files: buildVersionFiles(skillFiles),
171
+ manifest,
172
+ };
173
+ skillsState.addVersion(skill_id, version);
174
+ saveSkillVersion(storageDir, skill_id, newVersionNum, skillFiles);
175
+ // Update skill name/description from new manifest
176
+ const updated = skillsState.updateSkill(skill_id, {
177
+ name: manifest.name,
178
+ description: manifest.description,
179
+ });
180
+ if (!updated) {
181
+ return res.status(404).json(notFoundError('skill'));
182
+ }
183
+ return res.status(201).json(skillsState.toSkillResponse(updated));
184
+ }
185
+ catch (error) {
186
+ console.error('Error creating skill version:', error);
187
+ return res.status(500).json(errorResponse(error instanceof Error ? error.message : 'Internal server error'));
188
+ }
189
+ });
190
+ export default router;
191
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/skills/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { OpenAIListResponse, PaginationParams } from '../assistants/types.js';
2
+ import { Skill, SkillVersion, SkillResponse } from './types.js';
3
+ type PersistCallback = (data: SerializedSkillsState) => void;
4
+ export interface SerializedSkillsState {
5
+ skills: [string, Skill][];
6
+ }
7
+ declare class SkillsState {
8
+ private skills;
9
+ private persistCallback;
10
+ private persistDebounceTimer;
11
+ private persistDebounceMs;
12
+ setPersistCallback(callback: PersistCallback, debounceMs?: number): void;
13
+ private triggerPersist;
14
+ generateSkillId(): string;
15
+ createSkill(skill: Skill): void;
16
+ getSkill(id: string): Skill | undefined;
17
+ getSkillResponse(id: string): SkillResponse | undefined;
18
+ listSkills(params?: PaginationParams): OpenAIListResponse<SkillResponse>;
19
+ updateSkill(id: string, updates: {
20
+ default_version?: number;
21
+ metadata?: Record<string, string>;
22
+ name?: string;
23
+ description?: string;
24
+ }): Skill | undefined;
25
+ deleteSkill(id: string): boolean;
26
+ addVersion(skillId: string, version: SkillVersion): Skill | undefined;
27
+ getVersion(skillId: string, version: number): SkillVersion | undefined;
28
+ deleteVersion(skillId: string, version: number): Skill | undefined;
29
+ toSkillResponse(skill: Skill): SkillResponse;
30
+ serialize(): SerializedSkillsState;
31
+ restore(data: Partial<SerializedSkillsState>): void;
32
+ clear(): void;
33
+ }
34
+ export declare const skillsState: SkillsState;
35
+ export {};
@@ -0,0 +1,155 @@
1
+ import { generateId } from '../utils.js';
2
+ class SkillsState {
3
+ skills = new Map();
4
+ persistCallback = null;
5
+ persistDebounceTimer = null;
6
+ persistDebounceMs = 1000;
7
+ setPersistCallback(callback, debounceMs) {
8
+ this.persistCallback = callback;
9
+ if (debounceMs !== undefined) {
10
+ this.persistDebounceMs = debounceMs;
11
+ }
12
+ }
13
+ triggerPersist() {
14
+ if (!this.persistCallback)
15
+ return;
16
+ if (this.persistDebounceTimer) {
17
+ clearTimeout(this.persistDebounceTimer);
18
+ }
19
+ this.persistDebounceTimer = setTimeout(() => {
20
+ this.persistCallback?.(this.serialize());
21
+ this.persistDebounceTimer = null;
22
+ }, this.persistDebounceMs);
23
+ }
24
+ generateSkillId() {
25
+ return generateId('skill');
26
+ }
27
+ createSkill(skill) {
28
+ this.skills.set(skill.id, skill);
29
+ this.triggerPersist();
30
+ }
31
+ getSkill(id) {
32
+ return this.skills.get(id);
33
+ }
34
+ getSkillResponse(id) {
35
+ const skill = this.skills.get(id);
36
+ if (!skill)
37
+ return undefined;
38
+ return this.toSkillResponse(skill);
39
+ }
40
+ listSkills(params) {
41
+ const order = params?.order ?? 'desc';
42
+ const sortedSkills = Array.from(this.skills.values()).sort((a, b) => order === 'desc' ? b.created_at - a.created_at : a.created_at - b.created_at);
43
+ const limit = Math.min(params?.limit ?? 20, 100);
44
+ const after = params?.after;
45
+ const before = params?.before;
46
+ let items = sortedSkills;
47
+ if (after) {
48
+ const afterIndex = items.findIndex((s) => s.id === after);
49
+ if (afterIndex >= 0) {
50
+ items = items.slice(afterIndex + 1);
51
+ }
52
+ }
53
+ if (before) {
54
+ const beforeIndex = items.findIndex((s) => s.id === before);
55
+ if (beforeIndex >= 0) {
56
+ items = items.slice(0, beforeIndex);
57
+ }
58
+ }
59
+ const paginatedSkills = items.slice(0, limit);
60
+ const hasMore = paginatedSkills.length < items.length;
61
+ return {
62
+ object: 'list',
63
+ data: paginatedSkills.map((s) => this.toSkillResponse(s)),
64
+ first_id: paginatedSkills.length > 0 ? paginatedSkills[0].id : null,
65
+ last_id: paginatedSkills.length > 0 ? paginatedSkills[paginatedSkills.length - 1].id : null,
66
+ has_more: hasMore,
67
+ };
68
+ }
69
+ updateSkill(id, updates) {
70
+ const skill = this.skills.get(id);
71
+ if (!skill)
72
+ return undefined;
73
+ if (updates.default_version !== undefined) {
74
+ skill.default_version = updates.default_version;
75
+ }
76
+ if (updates.metadata !== undefined) {
77
+ skill.metadata = updates.metadata;
78
+ }
79
+ if (updates.name !== undefined) {
80
+ skill.name = updates.name;
81
+ }
82
+ if (updates.description !== undefined) {
83
+ skill.description = updates.description;
84
+ }
85
+ this.triggerPersist();
86
+ return skill;
87
+ }
88
+ deleteSkill(id) {
89
+ const deleted = this.skills.delete(id);
90
+ if (deleted) {
91
+ this.triggerPersist();
92
+ }
93
+ return deleted;
94
+ }
95
+ addVersion(skillId, version) {
96
+ const skill = this.skills.get(skillId);
97
+ if (!skill)
98
+ return undefined;
99
+ skill.versions.push(version);
100
+ skill.latest_version = version.version;
101
+ this.triggerPersist();
102
+ return skill;
103
+ }
104
+ getVersion(skillId, version) {
105
+ const skill = this.skills.get(skillId);
106
+ if (!skill)
107
+ return undefined;
108
+ return skill.versions.find((v) => v.version === version);
109
+ }
110
+ deleteVersion(skillId, version) {
111
+ const skill = this.skills.get(skillId);
112
+ if (!skill)
113
+ return undefined;
114
+ skill.versions = skill.versions.filter((v) => v.version !== version);
115
+ // Recompute latest_version from remaining versions
116
+ if (skill.versions.length > 0) {
117
+ skill.latest_version = Math.max(...skill.versions.map((v) => v.version));
118
+ }
119
+ else {
120
+ skill.latest_version = 0;
121
+ }
122
+ // Reset default_version if it pointed to the deleted version
123
+ if (skill.default_version === version) {
124
+ skill.default_version = skill.latest_version;
125
+ }
126
+ this.triggerPersist();
127
+ return skill;
128
+ }
129
+ toSkillResponse(skill) {
130
+ const { versions, ...response } = skill;
131
+ return response;
132
+ }
133
+ serialize() {
134
+ return {
135
+ skills: Array.from(this.skills.entries()),
136
+ };
137
+ }
138
+ restore(data) {
139
+ if (!data.skills)
140
+ return;
141
+ this.skills.clear();
142
+ for (const [id, skill] of data.skills) {
143
+ this.skills.set(id, skill);
144
+ }
145
+ }
146
+ clear() {
147
+ this.skills.clear();
148
+ if (this.persistDebounceTimer) {
149
+ clearTimeout(this.persistDebounceTimer);
150
+ this.persistDebounceTimer = null;
151
+ }
152
+ }
153
+ }
154
+ export const skillsState = new SkillsState();
155
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/skills/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { SkillFile } from './types.js';
2
+ /**
3
+ * Process multipart files from multer into SkillFile array
4
+ */
5
+ export declare function processMultipartFiles(files: Express.Multer.File[]): SkillFile[];
6
+ /**
7
+ * Parse zip buffer and extract files
8
+ * Implements minimal zip format reader using Node.js built-ins
9
+ */
10
+ export declare function processZipUpload(zipBuffer: Buffer): Promise<SkillFile[]>;
11
+ /**
12
+ * Get the skill storage directory
13
+ */
14
+ export declare function getSkillStorageDir(extensionPath: string): string;
15
+ /**
16
+ * Save a skill version to disk
17
+ */
18
+ export declare function saveSkillVersion(storageDir: string, skillId: string, version: number, files: SkillFile[]): void;
19
+ /**
20
+ * Delete a specific skill version
21
+ */
22
+ export declare function deleteSkillVersion(storageDir: string, skillId: string, version: number): void;
23
+ /**
24
+ * Delete all versions of a skill
25
+ */
26
+ export declare function deleteSkillStorage(storageDir: string, skillId: string): void;
27
+ /**
28
+ * Guess MIME type based on file extension
29
+ */
30
+ export declare function guessContentType(filePath: string): string;