@matimo/core 0.1.0-alpha.12.1 → 0.1.0-alpha.14

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 (118) hide show
  1. package/README.md +169 -8
  2. package/dist/approval/approval-handler.d.ts +5 -1
  3. package/dist/approval/approval-handler.d.ts.map +1 -1
  4. package/dist/approval/approval-handler.js +6 -0
  5. package/dist/approval/approval-handler.js.map +1 -1
  6. package/dist/core/schema.d.ts +29 -8
  7. package/dist/core/schema.d.ts.map +1 -1
  8. package/dist/core/schema.js +10 -3
  9. package/dist/core/schema.js.map +1 -1
  10. package/dist/core/skill-content-parser.d.ts +91 -0
  11. package/dist/core/skill-content-parser.d.ts.map +1 -0
  12. package/dist/core/skill-content-parser.js +248 -0
  13. package/dist/core/skill-content-parser.js.map +1 -0
  14. package/dist/core/skill-loader.d.ts +46 -0
  15. package/dist/core/skill-loader.d.ts.map +1 -0
  16. package/dist/core/skill-loader.js +310 -0
  17. package/dist/core/skill-loader.js.map +1 -0
  18. package/dist/core/skill-registry.d.ts +131 -0
  19. package/dist/core/skill-registry.d.ts.map +1 -0
  20. package/dist/core/skill-registry.js +316 -0
  21. package/dist/core/skill-registry.js.map +1 -0
  22. package/dist/core/tfidf-embedding.d.ts +45 -0
  23. package/dist/core/tfidf-embedding.d.ts.map +1 -0
  24. package/dist/core/tfidf-embedding.js +199 -0
  25. package/dist/core/tfidf-embedding.js.map +1 -0
  26. package/dist/core/types.d.ts +155 -6
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/errors/matimo-error.d.ts +3 -1
  29. package/dist/errors/matimo-error.d.ts.map +1 -1
  30. package/dist/errors/matimo-error.js +2 -0
  31. package/dist/errors/matimo-error.js.map +1 -1
  32. package/dist/executors/command-executor.d.ts.map +1 -1
  33. package/dist/executors/command-executor.js +13 -2
  34. package/dist/executors/command-executor.js.map +1 -1
  35. package/dist/executors/function-executor.d.ts.map +1 -1
  36. package/dist/executors/function-executor.js +33 -20
  37. package/dist/executors/function-executor.js.map +1 -1
  38. package/dist/index.d.ts +20 -3
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +14 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/integrations/langchain.d.ts +55 -0
  43. package/dist/integrations/langchain.d.ts.map +1 -1
  44. package/dist/integrations/langchain.js +66 -0
  45. package/dist/integrations/langchain.js.map +1 -1
  46. package/dist/logging/winston-logger.d.ts.map +1 -1
  47. package/dist/logging/winston-logger.js +9 -1
  48. package/dist/logging/winston-logger.js.map +1 -1
  49. package/dist/matimo-instance.d.ts +171 -6
  50. package/dist/matimo-instance.d.ts.map +1 -1
  51. package/dist/matimo-instance.js +602 -13
  52. package/dist/matimo-instance.js.map +1 -1
  53. package/dist/mcp/mcp-server.d.ts +25 -0
  54. package/dist/mcp/mcp-server.d.ts.map +1 -1
  55. package/dist/mcp/mcp-server.js +128 -21
  56. package/dist/mcp/mcp-server.js.map +1 -1
  57. package/dist/mcp/tool-converter.d.ts.map +1 -1
  58. package/dist/mcp/tool-converter.js +10 -1
  59. package/dist/mcp/tool-converter.js.map +1 -1
  60. package/dist/policy/approval-manifest.d.ts +74 -0
  61. package/dist/policy/approval-manifest.d.ts.map +1 -0
  62. package/dist/policy/approval-manifest.js +183 -0
  63. package/dist/policy/approval-manifest.js.map +1 -0
  64. package/dist/policy/content-validator.d.ts +19 -0
  65. package/dist/policy/content-validator.d.ts.map +1 -0
  66. package/dist/policy/content-validator.js +196 -0
  67. package/dist/policy/content-validator.js.map +1 -0
  68. package/dist/policy/default-policy.d.ts +46 -0
  69. package/dist/policy/default-policy.d.ts.map +1 -0
  70. package/dist/policy/default-policy.js +241 -0
  71. package/dist/policy/default-policy.js.map +1 -0
  72. package/dist/policy/events.d.ts +71 -0
  73. package/dist/policy/events.d.ts.map +1 -0
  74. package/dist/policy/events.js +8 -0
  75. package/dist/policy/events.js.map +1 -0
  76. package/dist/policy/index.d.ts +13 -0
  77. package/dist/policy/index.d.ts.map +1 -0
  78. package/dist/policy/index.js +9 -0
  79. package/dist/policy/index.js.map +1 -0
  80. package/dist/policy/integrity-tracker.d.ts +62 -0
  81. package/dist/policy/integrity-tracker.d.ts.map +1 -0
  82. package/dist/policy/integrity-tracker.js +79 -0
  83. package/dist/policy/integrity-tracker.js.map +1 -0
  84. package/dist/policy/policy-loader.d.ts +58 -0
  85. package/dist/policy/policy-loader.d.ts.map +1 -0
  86. package/dist/policy/policy-loader.js +153 -0
  87. package/dist/policy/policy-loader.js.map +1 -0
  88. package/dist/policy/risk-classifier.d.ts +18 -0
  89. package/dist/policy/risk-classifier.d.ts.map +1 -0
  90. package/dist/policy/risk-classifier.js +43 -0
  91. package/dist/policy/risk-classifier.js.map +1 -0
  92. package/dist/policy/types.d.ts +126 -0
  93. package/dist/policy/types.d.ts.map +1 -0
  94. package/dist/policy/types.js +8 -0
  95. package/dist/policy/types.js.map +1 -0
  96. package/package.json +5 -5
  97. package/tools/matimo_approve_tool/definition.yaml +36 -0
  98. package/tools/matimo_approve_tool/matimo_approve_tool.ts +90 -0
  99. package/tools/matimo_create_skill/definition.yaml +46 -0
  100. package/tools/matimo_create_skill/matimo_create_skill.ts +75 -0
  101. package/tools/matimo_create_tool/definition.yaml +48 -0
  102. package/tools/matimo_create_tool/matimo_create_tool.ts +137 -0
  103. package/tools/matimo_get_skill/definition.yaml +60 -0
  104. package/tools/matimo_get_skill/matimo_get_skill.ts +182 -0
  105. package/tools/matimo_get_tool_status/definition.yaml +42 -0
  106. package/tools/matimo_get_tool_status/matimo_get_tool_status.ts +101 -0
  107. package/tools/matimo_list_skills/definition.yaml +52 -0
  108. package/tools/matimo_list_skills/matimo_list_skills.ts +138 -0
  109. package/tools/matimo_list_user_tools/definition.yaml +32 -0
  110. package/tools/matimo_list_user_tools/matimo_list_user_tools.ts +74 -0
  111. package/tools/matimo_reload_tools/definition.yaml +35 -0
  112. package/tools/matimo_reload_tools/matimo_reload_tools.ts +29 -0
  113. package/tools/matimo_validate_skill/definition.yaml +43 -0
  114. package/tools/matimo_validate_skill/matimo_validate_skill.ts +137 -0
  115. package/tools/matimo_validate_tool/definition.yaml +34 -0
  116. package/tools/matimo_validate_tool/matimo_validate_tool.ts +168 -0
  117. package/tools/shared/skill-validation.ts +335 -0
  118. package/LICENSE +0 -21
@@ -0,0 +1,335 @@
1
+ /**
2
+ * Shared validation utilities for Agent Skills — aligned with the official
3
+ * Agent Skills specification (https://agentskills.io/specification).
4
+ *
5
+ * Covers: name rules, description rules, frontmatter parsing/validation,
6
+ * and bundled resource discovery.
7
+ */
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+
11
+ // ── Name Validation ──────────────────────────────────────────────────────────
12
+
13
+ /** Spec: lowercase letters, numbers, hyphens only. */
14
+ const VALID_NAME_PATTERN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
15
+
16
+ /** Consecutive hyphens are not allowed. */
17
+ const CONSECUTIVE_HYPHENS = /--/;
18
+
19
+ /** Max length for skill name. */
20
+ const MAX_NAME_LENGTH = 64;
21
+
22
+ /** Max length for description. */
23
+ const MAX_DESCRIPTION_LENGTH = 1024;
24
+
25
+ /** Max length for compatibility field. */
26
+ const MAX_COMPATIBILITY_LENGTH = 500;
27
+
28
+ /** Path traversal detection — kept for defense-in-depth. */
29
+ const UNSAFE_NAME_PATTERN = /[/\\]|\.\.|[\x00-\x1f]/;
30
+
31
+ export interface NameValidationResult {
32
+ valid: boolean;
33
+ error?: string;
34
+ }
35
+
36
+ /**
37
+ * Validate a skill name against the Agent Skills spec.
38
+ *
39
+ * Rules:
40
+ * - 1–64 characters
41
+ * - Lowercase letters, numbers, hyphens only
42
+ * - Must not start or end with a hyphen
43
+ * - Must not contain consecutive hyphens (--)
44
+ * - Must not contain path traversal characters
45
+ */
46
+ export function validateSkillName(name: string): NameValidationResult {
47
+ if (!name || name.trim().length === 0) {
48
+ return { valid: false, error: 'Skill name is required' };
49
+ }
50
+
51
+ if (UNSAFE_NAME_PATTERN.test(name)) {
52
+ return { valid: false, error: 'Skill name contains invalid characters' };
53
+ }
54
+
55
+ if (name.length > MAX_NAME_LENGTH) {
56
+ return { valid: false, error: `Skill name must be at most ${MAX_NAME_LENGTH} characters (got ${name.length})` };
57
+ }
58
+
59
+ if (!VALID_NAME_PATTERN.test(name)) {
60
+ return {
61
+ valid: false,
62
+ error: 'Skill name must contain only lowercase letters, numbers, and hyphens, and must not start or end with a hyphen',
63
+ };
64
+ }
65
+
66
+ if (CONSECUTIVE_HYPHENS.test(name)) {
67
+ return { valid: false, error: 'Skill name must not contain consecutive hyphens (--)' };
68
+ }
69
+
70
+ return { valid: true };
71
+ }
72
+
73
+ // ── Frontmatter Parsing ──────────────────────────────────────────────────────
74
+
75
+ export interface SkillFrontmatter {
76
+ name: string;
77
+ description: string;
78
+ license?: string;
79
+ compatibility?: string;
80
+ 'allowed-tools'?: string | string[];
81
+ metadata?: Record<string, string>;
82
+ }
83
+
84
+ export interface ParsedSkill {
85
+ frontmatter: SkillFrontmatter;
86
+ body: string;
87
+ raw: string;
88
+ }
89
+
90
+ export interface ParseResult {
91
+ success: boolean;
92
+ error?: string;
93
+ parsed?: ParsedSkill;
94
+ }
95
+
96
+ /**
97
+ * Parse YAML frontmatter from SKILL.md content.
98
+ *
99
+ * Handles the spec's required fields (name, description) and optional fields
100
+ * (license, compatibility, metadata, allowed-tools).
101
+ */
102
+ export function parseSkillContent(content: string): ParseResult {
103
+ if (!content || !content.startsWith('---')) {
104
+ return { success: false, error: 'Skill content must start with YAML frontmatter (---)' };
105
+ }
106
+
107
+ const endIndex = content.indexOf('---', 3);
108
+ if (endIndex === -1) {
109
+ return { success: false, error: 'Skill content must have closing YAML frontmatter (---)' };
110
+ }
111
+
112
+ const frontmatterBlock = content.substring(3, endIndex).trim();
113
+ const body = content.substring(endIndex + 3).trim();
114
+
115
+ // Parse frontmatter lines
116
+ const fields: Record<string, unknown> = {};
117
+ let currentMetadata: Record<string, string> | null = null;
118
+ let currentArray: string[] | null = null;
119
+ let currentArrayKey: string | null = null;
120
+
121
+ for (const line of frontmatterBlock.split('\n')) {
122
+ // Detect array elements (prefixed with "- ")
123
+ if (currentArray !== null && /^\s*- /.test(line)) {
124
+ const item = line.trim().substring(2).trim();
125
+ if (item) {
126
+ currentArray.push(item.replace(/^["']|["']$/g, ''));
127
+ }
128
+ continue;
129
+ }
130
+
131
+ // Detect metadata sub-keys (indented with spaces under "metadata:")
132
+ if (currentMetadata !== null && /^\s+\S/.test(line)) {
133
+ const colonIndex = line.indexOf(':');
134
+ if (colonIndex !== -1) {
135
+ const key = line.substring(0, colonIndex).trim();
136
+ const value = line.substring(colonIndex + 1).trim();
137
+ if (key && value) {
138
+ currentMetadata[key] = value.replace(/^["']|["']$/g, '');
139
+ }
140
+ }
141
+ continue;
142
+ }
143
+
144
+ // Top-level keys
145
+ currentMetadata = null;
146
+ currentArray = null;
147
+ currentArrayKey = null;
148
+ const colonIndex = line.indexOf(':');
149
+ if (colonIndex === -1) continue;
150
+
151
+ const key = line.substring(0, colonIndex).trim();
152
+ const value = line.substring(colonIndex + 1).trim();
153
+
154
+ if (key === 'metadata' && !value) {
155
+ // Start collecting metadata sub-keys
156
+ currentMetadata = {};
157
+ fields['__metadata__'] = 'MAP';
158
+ continue;
159
+ }
160
+
161
+ // Check for array start (value is empty, array items follow on next lines)
162
+ if (key === 'allowed-tools' && !value) {
163
+ currentArray = [];
164
+ currentArrayKey = 'allowed-tools';
165
+ continue;
166
+ }
167
+
168
+ if (key && value) {
169
+ // Strip surrounding quotes (YAML style)
170
+ fields[key] = value.replace(/^["']|["']$/g, '');
171
+ }
172
+ }
173
+
174
+ // Store any pending array
175
+ if (currentArray !== null && currentArrayKey) {
176
+ fields[currentArrayKey] = currentArray;
177
+ }
178
+
179
+ // Build frontmatter object
180
+ const frontmatter: SkillFrontmatter = {
181
+ name: fields.name as string || '',
182
+ description: fields.description as string || '',
183
+ };
184
+
185
+ if (fields.license) frontmatter.license = fields.license as string;
186
+ if (fields.compatibility) frontmatter.compatibility = fields.compatibility as string;
187
+ if (fields['allowed-tools']) {
188
+ frontmatter['allowed-tools'] = Array.isArray(fields['allowed-tools'])
189
+ ? (fields['allowed-tools'] as string[])
190
+ : (fields['allowed-tools'] as string);
191
+ }
192
+ if (currentMetadata && Object.keys(currentMetadata).length > 0) {
193
+ frontmatter.metadata = currentMetadata;
194
+ }
195
+
196
+ return {
197
+ success: true,
198
+ parsed: { frontmatter, body, raw: content },
199
+ };
200
+ }
201
+
202
+ // ── Frontmatter Validation ───────────────────────────────────────────────────
203
+
204
+ export interface ValidationIssue {
205
+ field: string;
206
+ message: string;
207
+ severity: 'error' | 'warning';
208
+ }
209
+
210
+ export interface ValidationResult {
211
+ valid: boolean;
212
+ issues: ValidationIssue[];
213
+ }
214
+
215
+ /**
216
+ * Validate parsed frontmatter against the Agent Skills spec.
217
+ *
218
+ * Checks: name rules, description rules, optional field constraints,
219
+ * and name/directory consistency (if directoryName provided).
220
+ */
221
+ export function validateFrontmatter(
222
+ frontmatter: SkillFrontmatter,
223
+ directoryName?: string,
224
+ ): ValidationResult {
225
+ const issues: ValidationIssue[] = [];
226
+
227
+ // Required: name
228
+ if (!frontmatter.name) {
229
+ issues.push({ field: 'name', message: 'YAML frontmatter must include a "name" field', severity: 'error' });
230
+ } else {
231
+ const nameResult = validateSkillName(frontmatter.name);
232
+ if (!nameResult.valid) {
233
+ issues.push({ field: 'name', message: nameResult.error!, severity: 'error' });
234
+ }
235
+ }
236
+
237
+ // Required: description
238
+ if (!frontmatter.description) {
239
+ issues.push({ field: 'description', message: 'YAML frontmatter must include a "description" field', severity: 'error' });
240
+ } else if (frontmatter.description.length > MAX_DESCRIPTION_LENGTH) {
241
+ issues.push({
242
+ field: 'description',
243
+ message: `Description must be at most ${MAX_DESCRIPTION_LENGTH} characters (got ${frontmatter.description.length})`,
244
+ severity: 'error',
245
+ });
246
+ }
247
+
248
+ // Optional: compatibility
249
+ if (frontmatter.compatibility && frontmatter.compatibility.length > MAX_COMPATIBILITY_LENGTH) {
250
+ issues.push({
251
+ field: 'compatibility',
252
+ message: `Compatibility must be at most ${MAX_COMPATIBILITY_LENGTH} characters (got ${frontmatter.compatibility.length})`,
253
+ severity: 'error',
254
+ });
255
+ }
256
+
257
+ // name must match directory name (if provided)
258
+ if (directoryName && frontmatter.name && frontmatter.name !== directoryName) {
259
+ issues.push({
260
+ field: 'name',
261
+ message: `Skill name "${frontmatter.name}" must match its directory name "${directoryName}"`,
262
+ severity: 'error',
263
+ });
264
+ }
265
+
266
+ return {
267
+ valid: issues.filter(i => i.severity === 'error').length === 0,
268
+ issues,
269
+ };
270
+ }
271
+
272
+ // ── Bundled Resources (Level 3) ──────────────────────────────────────────────
273
+
274
+ export interface BundledResources {
275
+ scripts: string[];
276
+ references: string[];
277
+ assets: string[];
278
+ other: string[];
279
+ }
280
+
281
+ /**
282
+ * List bundled resources in a skill directory.
283
+ *
284
+ * The spec recognizes three standard subdirectories:
285
+ * - scripts/ — executable code
286
+ * - references/ — additional documentation
287
+ * - assets/ — templates, resources
288
+ *
289
+ * Any other files (besides SKILL.md) are listed under "other".
290
+ */
291
+ export function listBundledResources(skillDir: string): BundledResources {
292
+ const resources: BundledResources = {
293
+ scripts: [],
294
+ references: [],
295
+ assets: [],
296
+ other: [],
297
+ };
298
+
299
+ if (!fs.existsSync(skillDir)) return resources;
300
+
301
+ const KNOWN_DIRS: Record<string, keyof Pick<BundledResources, 'scripts' | 'references' | 'assets'>> = {
302
+ scripts: 'scripts',
303
+ references: 'references',
304
+ assets: 'assets',
305
+ };
306
+
307
+ const entries = fs.readdirSync(skillDir, { withFileTypes: true });
308
+ for (const entry of entries) {
309
+ if (entry.name === 'SKILL.md') continue;
310
+
311
+ if (entry.isDirectory()) {
312
+ const category = KNOWN_DIRS[entry.name];
313
+ if (category) {
314
+ // List files inside the known subdirectory
315
+ const subDir = path.join(skillDir, entry.name);
316
+ const subEntries = fs.readdirSync(subDir);
317
+ for (const sub of subEntries) {
318
+ resources[category].push(`${entry.name}/${sub}`);
319
+ }
320
+ } else {
321
+ // Unknown directory — list contents under "other"
322
+ const subDir = path.join(skillDir, entry.name);
323
+ const subEntries = fs.readdirSync(subDir);
324
+ for (const sub of subEntries) {
325
+ resources.other.push(`${entry.name}/${sub}`);
326
+ }
327
+ }
328
+ } else {
329
+ // Top-level file (not SKILL.md)
330
+ resources.other.push(entry.name);
331
+ }
332
+ }
333
+
334
+ return resources;
335
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 tallclub
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.