@matimo/core 0.1.0-alpha.8 → 0.1.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 (173) hide show
  1. package/README.md +341 -14
  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 +41 -10
  7. package/dist/core/schema.d.ts.map +1 -1
  8. package/dist/core/schema.js +40 -4
  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/tool-loader.d.ts +3 -1
  27. package/dist/core/tool-loader.d.ts.map +1 -1
  28. package/dist/core/tool-loader.js +33 -10
  29. package/dist/core/tool-loader.js.map +1 -1
  30. package/dist/core/types.d.ts +203 -6
  31. package/dist/core/types.d.ts.map +1 -1
  32. package/dist/encodings/parameter-encoding.d.ts +1 -1
  33. package/dist/encodings/parameter-encoding.d.ts.map +1 -1
  34. package/dist/encodings/parameter-encoding.js +9 -4
  35. package/dist/encodings/parameter-encoding.js.map +1 -1
  36. package/dist/errors/matimo-error.d.ts +11 -2
  37. package/dist/errors/matimo-error.d.ts.map +1 -1
  38. package/dist/errors/matimo-error.js +25 -1
  39. package/dist/errors/matimo-error.js.map +1 -1
  40. package/dist/executors/command-executor.d.ts +9 -2
  41. package/dist/executors/command-executor.d.ts.map +1 -1
  42. package/dist/executors/command-executor.js +29 -5
  43. package/dist/executors/command-executor.js.map +1 -1
  44. package/dist/executors/function-executor.d.ts +10 -3
  45. package/dist/executors/function-executor.d.ts.map +1 -1
  46. package/dist/executors/function-executor.js +44 -24
  47. package/dist/executors/function-executor.js.map +1 -1
  48. package/dist/executors/http-executor.d.ts +79 -4
  49. package/dist/executors/http-executor.d.ts.map +1 -1
  50. package/dist/executors/http-executor.js +232 -28
  51. package/dist/executors/http-executor.js.map +1 -1
  52. package/dist/index.d.ts +25 -3
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +19 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/integrations/langchain.d.ts +55 -0
  57. package/dist/integrations/langchain.d.ts.map +1 -1
  58. package/dist/integrations/langchain.js +71 -4
  59. package/dist/integrations/langchain.js.map +1 -1
  60. package/dist/logging/logger.d.ts +8 -2
  61. package/dist/logging/logger.d.ts.map +1 -1
  62. package/dist/logging/logger.js.map +1 -1
  63. package/dist/logging/winston-logger.d.ts.map +1 -1
  64. package/dist/logging/winston-logger.js +9 -1
  65. package/dist/logging/winston-logger.js.map +1 -1
  66. package/dist/matimo-instance.d.ts +230 -18
  67. package/dist/matimo-instance.d.ts.map +1 -1
  68. package/dist/matimo-instance.js +739 -40
  69. package/dist/matimo-instance.js.map +1 -1
  70. package/dist/mcp/index.d.ts +18 -0
  71. package/dist/mcp/index.d.ts.map +1 -0
  72. package/dist/mcp/index.js +24 -0
  73. package/dist/mcp/index.js.map +1 -0
  74. package/dist/mcp/mcp-server.d.ts +141 -0
  75. package/dist/mcp/mcp-server.d.ts.map +1 -0
  76. package/dist/mcp/mcp-server.js +754 -0
  77. package/dist/mcp/mcp-server.js.map +1 -0
  78. package/dist/mcp/secrets/aws-resolver.d.ts +41 -0
  79. package/dist/mcp/secrets/aws-resolver.d.ts.map +1 -0
  80. package/dist/mcp/secrets/aws-resolver.js +141 -0
  81. package/dist/mcp/secrets/aws-resolver.js.map +1 -0
  82. package/dist/mcp/secrets/dotenv-resolver.d.ts +23 -0
  83. package/dist/mcp/secrets/dotenv-resolver.d.ts.map +1 -0
  84. package/dist/mcp/secrets/dotenv-resolver.js +94 -0
  85. package/dist/mcp/secrets/dotenv-resolver.js.map +1 -0
  86. package/dist/mcp/secrets/env-resolver.d.ts +14 -0
  87. package/dist/mcp/secrets/env-resolver.d.ts.map +1 -0
  88. package/dist/mcp/secrets/env-resolver.js +27 -0
  89. package/dist/mcp/secrets/env-resolver.js.map +1 -0
  90. package/dist/mcp/secrets/index.d.ts +14 -0
  91. package/dist/mcp/secrets/index.d.ts.map +1 -0
  92. package/dist/mcp/secrets/index.js +13 -0
  93. package/dist/mcp/secrets/index.js.map +1 -0
  94. package/dist/mcp/secrets/resolver-chain.d.ts +34 -0
  95. package/dist/mcp/secrets/resolver-chain.d.ts.map +1 -0
  96. package/dist/mcp/secrets/resolver-chain.js +141 -0
  97. package/dist/mcp/secrets/resolver-chain.js.map +1 -0
  98. package/dist/mcp/secrets/types.d.ts +73 -0
  99. package/dist/mcp/secrets/types.d.ts.map +1 -0
  100. package/dist/mcp/secrets/types.js +8 -0
  101. package/dist/mcp/secrets/types.js.map +1 -0
  102. package/dist/mcp/secrets/vault-resolver.d.ts +43 -0
  103. package/dist/mcp/secrets/vault-resolver.d.ts.map +1 -0
  104. package/dist/mcp/secrets/vault-resolver.js +127 -0
  105. package/dist/mcp/secrets/vault-resolver.js.map +1 -0
  106. package/dist/mcp/tool-converter.d.ts +40 -0
  107. package/dist/mcp/tool-converter.d.ts.map +1 -0
  108. package/dist/mcp/tool-converter.js +185 -0
  109. package/dist/mcp/tool-converter.js.map +1 -0
  110. package/dist/policy/approval-manifest.d.ts +76 -0
  111. package/dist/policy/approval-manifest.d.ts.map +1 -0
  112. package/dist/policy/approval-manifest.js +197 -0
  113. package/dist/policy/approval-manifest.js.map +1 -0
  114. package/dist/policy/content-validator.d.ts +19 -0
  115. package/dist/policy/content-validator.d.ts.map +1 -0
  116. package/dist/policy/content-validator.js +196 -0
  117. package/dist/policy/content-validator.js.map +1 -0
  118. package/dist/policy/default-policy.d.ts +46 -0
  119. package/dist/policy/default-policy.d.ts.map +1 -0
  120. package/dist/policy/default-policy.js +241 -0
  121. package/dist/policy/default-policy.js.map +1 -0
  122. package/dist/policy/events.d.ts +71 -0
  123. package/dist/policy/events.d.ts.map +1 -0
  124. package/dist/policy/events.js +8 -0
  125. package/dist/policy/events.js.map +1 -0
  126. package/dist/policy/index.d.ts +13 -0
  127. package/dist/policy/index.d.ts.map +1 -0
  128. package/dist/policy/index.js +9 -0
  129. package/dist/policy/index.js.map +1 -0
  130. package/dist/policy/integrity-tracker.d.ts +62 -0
  131. package/dist/policy/integrity-tracker.d.ts.map +1 -0
  132. package/dist/policy/integrity-tracker.js +79 -0
  133. package/dist/policy/integrity-tracker.js.map +1 -0
  134. package/dist/policy/policy-loader.d.ts +58 -0
  135. package/dist/policy/policy-loader.d.ts.map +1 -0
  136. package/dist/policy/policy-loader.js +156 -0
  137. package/dist/policy/policy-loader.js.map +1 -0
  138. package/dist/policy/risk-classifier.d.ts +18 -0
  139. package/dist/policy/risk-classifier.d.ts.map +1 -0
  140. package/dist/policy/risk-classifier.js +47 -0
  141. package/dist/policy/risk-classifier.js.map +1 -0
  142. package/dist/policy/types.d.ts +131 -0
  143. package/dist/policy/types.d.ts.map +1 -0
  144. package/dist/policy/types.js +8 -0
  145. package/dist/policy/types.js.map +1 -0
  146. package/package.json +22 -6
  147. package/tools/matimo_approve_tool/definition.yaml +36 -0
  148. package/tools/matimo_approve_tool/matimo_approve_tool.ts +90 -0
  149. package/tools/matimo_create_skill/definition.yaml +46 -0
  150. package/tools/matimo_create_skill/matimo_create_skill.ts +75 -0
  151. package/tools/matimo_create_tool/definition.yaml +48 -0
  152. package/tools/matimo_create_tool/matimo_create_tool.ts +137 -0
  153. package/tools/matimo_get_skill/definition.yaml +60 -0
  154. package/tools/matimo_get_skill/matimo_get_skill.ts +182 -0
  155. package/tools/matimo_get_tool/definition.yaml +36 -0
  156. package/tools/matimo_get_tool/matimo_get_tool.ts +56 -0
  157. package/tools/matimo_get_tool_status/definition.yaml +42 -0
  158. package/tools/matimo_get_tool_status/matimo_get_tool_status.ts +101 -0
  159. package/tools/matimo_list_skills/definition.yaml +52 -0
  160. package/tools/matimo_list_skills/matimo_list_skills.ts +138 -0
  161. package/tools/matimo_list_user_tools/definition.yaml +32 -0
  162. package/tools/matimo_list_user_tools/matimo_list_user_tools.ts +74 -0
  163. package/tools/matimo_reload_tools/definition.yaml +35 -0
  164. package/tools/matimo_reload_tools/matimo_reload_tools.ts +29 -0
  165. package/tools/matimo_search_tools/definition.yaml +32 -0
  166. package/tools/matimo_search_tools/matimo_search_tools.ts +82 -0
  167. package/tools/matimo_validate_skill/definition.yaml +43 -0
  168. package/tools/matimo_validate_skill/matimo_validate_skill.ts +137 -0
  169. package/tools/matimo_validate_tool/definition.yaml +34 -0
  170. package/tools/matimo_validate_tool/matimo_validate_tool.ts +168 -0
  171. package/tools/read/read.ts +0 -2
  172. package/tools/shared/skill-validation.ts +335 -0
  173. package/LICENSE +0 -21
@@ -0,0 +1,101 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import yaml from 'js-yaml';
4
+ import {
5
+ validateToolDefinition,
6
+ classifyRisk,
7
+ getTierForTool,
8
+ ApprovalManifest,
9
+ getGlobalMatimoLogger,
10
+ } from '@matimo/core';
11
+
12
+ interface StatusParams {
13
+ name: string;
14
+ tool_dir?: string;
15
+ }
16
+
17
+ interface StatusResult {
18
+ found: boolean;
19
+ name?: string;
20
+ status?: string;
21
+ riskLevel?: string;
22
+ approvalState?: 'pending' | 'auto-approved' | 'approved' | 'rejected';
23
+ approvedAt?: string;
24
+ approvedBy?: string;
25
+ message: string;
26
+ }
27
+
28
+ export default async function matimoGetToolStatus(
29
+ params: StatusParams,
30
+ context?: { credentials?: Record<string, string> },
31
+ ): Promise<StatusResult> {
32
+ const logger = getGlobalMatimoLogger();
33
+ const toolDir = params.tool_dir || './matimo-tools';
34
+
35
+ const defPath = path.join(toolDir, params.name, 'definition.yaml');
36
+ if (!fs.existsSync(defPath)) {
37
+ logger.warn('matimo_get_tool_status: tool not found', { name: params.name, path: defPath });
38
+ return { found: false, message: `Tool "${params.name}" not found at ${defPath}` };
39
+ }
40
+
41
+ const yamlContent = fs.readFileSync(defPath, 'utf-8');
42
+
43
+ let tool;
44
+ try {
45
+ const parsed = yaml.load(yamlContent);
46
+ tool = validateToolDefinition(parsed);
47
+ } catch (err) {
48
+ return {
49
+ found: true,
50
+ name: params.name,
51
+ message: `Tool YAML is invalid: ${(err as Error).message}`,
52
+ };
53
+ }
54
+
55
+ const riskLevel = classifyRisk(tool);
56
+ const tier = getTierForTool(tool);
57
+
58
+ // Determine approval state from manifest
59
+ const approvalDir = path.resolve(toolDir);
60
+ const manifest = new ApprovalManifest(
61
+ approvalDir,
62
+ context?.credentials?.MATIMO_APPROVAL_SECRET,
63
+ );
64
+
65
+ const hash = manifest.computeHash(yamlContent);
66
+ const approvalRecord = manifest.getApproval(params.name);
67
+ const isApproved = approvalRecord ? manifest.isApproved(params.name, hash) : false;
68
+ const pendingTools = manifest.getPendingTools();
69
+
70
+ let approvalState: StatusResult['approvalState'];
71
+ if (tool.status === 'deprecated') {
72
+ approvalState = 'rejected';
73
+ } else if (isApproved) {
74
+ approvalState = 'approved';
75
+ } else if (tier === 'auto') {
76
+ approvalState = 'auto-approved';
77
+ } else if (pendingTools.includes(params.name)) {
78
+ approvalState = 'pending';
79
+ } else {
80
+ // Tool exists on disk but no pending record and not approved — treat as pending
81
+ approvalState = 'pending';
82
+ }
83
+
84
+ logger.debug('matimo_get_tool_status: status retrieved', {
85
+ name: params.name,
86
+ status: tool.status,
87
+ riskLevel,
88
+ approvalState,
89
+ });
90
+
91
+ return {
92
+ found: true,
93
+ name: params.name,
94
+ status: tool.status ?? 'draft',
95
+ riskLevel,
96
+ approvalState,
97
+ approvedAt: approvalRecord?.approvedAt,
98
+ approvedBy: approvalRecord?.approvedBy,
99
+ message: `Tool "${params.name}" is ${approvalState} (${riskLevel} risk)`,
100
+ };
101
+ }
@@ -0,0 +1,52 @@
1
+ name: matimo_list_skills
2
+ version: '1.0.0'
3
+ description: >-
4
+ Level 1 metadata discovery — list all skills available to the system.
5
+
6
+ Skills are auto-discovered in this order (priority):
7
+ 1. From global Matimo instance (if initialized)
8
+ 2. From @matimo/* packages in node_modules (auto-discovery like tools)
9
+ 3. From core skills bundled with @matimo/core
10
+ 4. From optional explicit skills_dir (if provided)
11
+
12
+ Returns each skill's name, description, and optional frontmatter fields
13
+ (license, compatibility, metadata) per the Agent Skills specification.
14
+
15
+ requires_approval: false
16
+ tags:
17
+ - matimo
18
+ - meta
19
+ - skill
20
+ - discovery
21
+
22
+ parameters:
23
+ skills_dir:
24
+ type: string
25
+ required: false
26
+ description: >-
27
+ Optional directory to scan for skills. If provided, loads skills directly
28
+ from this path (each skill is a subdirectory containing a SKILL.md file
29
+ with YAML frontmatter).
30
+
31
+ Paths are resolved relative to the current working directory where the tool
32
+ is executed. For reliability, use absolute paths or verify relative paths
33
+ are correct from the execution context.
34
+
35
+ If not provided, returns skills from the global Matimo instance with
36
+ auto-discovered @matimo/*/skills and user-created skills.
37
+
38
+ execution:
39
+ type: function
40
+ code: './matimo_list_skills.ts'
41
+
42
+ output_schema:
43
+ type: object
44
+ properties:
45
+ skills:
46
+ type: array
47
+ description: >-
48
+ List of discovered skills with name, description, path, and optional
49
+ fields (license, compatibility, metadata)
50
+ total:
51
+ type: number
52
+ description: Total number of skills found
@@ -0,0 +1,138 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { getGlobalMatimoLogger, getGlobalMatimoInstance, extractSkillMetadata, ToolLoader } from '@matimo/core';
4
+
5
+ interface ListSkillsParams {
6
+ skills_dir?: string;
7
+ }
8
+
9
+ interface SkillSummary {
10
+ name: string;
11
+ description: string;
12
+ version?: string;
13
+ license?: string;
14
+ metadata?: Record<string, string>;
15
+ source: 'builtin' | 'user' | 'catalog';
16
+ }
17
+
18
+ interface ListSkillsResult {
19
+ skills: SkillSummary[];
20
+ total: number;
21
+ }
22
+
23
+ /**
24
+ * Helper: Load SKILL.md files from a directory and extract metadata.
25
+ */
26
+ function loadSkillsFromPath(
27
+ skillsPath: string,
28
+ source: 'builtin' | 'user',
29
+ logger: ReturnType<typeof getGlobalMatimoLogger>,
30
+ ): SkillSummary[] {
31
+ const skills: SkillSummary[] = [];
32
+
33
+ if (!fs.existsSync(skillsPath)) return skills;
34
+
35
+ try {
36
+ const entries = fs.readdirSync(skillsPath, { withFileTypes: true });
37
+ for (const entry of entries) {
38
+ if (!entry.isDirectory()) continue;
39
+ const skillFilePath = path.join(skillsPath, entry.name, 'SKILL.md');
40
+ if (!fs.existsSync(skillFilePath)) continue;
41
+
42
+ try {
43
+ const content = fs.readFileSync(skillFilePath, 'utf-8');
44
+ const result = extractSkillMetadata(content, source);
45
+ if (result.success && result.metadata) {
46
+ skills.push(result.metadata);
47
+ }
48
+ } catch (err) {
49
+ logger.debug('matimo_list_skills: failed to extract metadata', {
50
+ skill: entry.name,
51
+ error: (err as Error).message,
52
+ });
53
+ }
54
+ }
55
+ } catch (err) {
56
+ logger.debug('matimo_list_skills: failed to read directory', {
57
+ path: skillsPath,
58
+ error: (err as Error).message,
59
+ });
60
+ }
61
+
62
+ return skills;
63
+ }
64
+
65
+
66
+
67
+ /**
68
+ * List all skills available in the current Matimo instance.
69
+ *
70
+ * Skills are discovered in this order (priority):
71
+ * 1. Global MatimoInstance (if initialized) — includes auto-discovered @matimo/* skills
72
+ * 2. Auto-discover from @matimo/* packages in node_modules (like tools do)
73
+ * 3. Explicit skills_dir if provided
74
+ *
75
+ * Returns METADATA ONLY: name, description, license, version, metadata, source.
76
+ * Full body content is available via matimo_get_skill when explicitly requested.
77
+ *
78
+ * Uses lightweight YAML-only extraction (no body/sections parsing) for efficiency.
79
+ * This avoids the overhead of parsing skill markdown sections and keeps responses small.
80
+ */
81
+ export default async function matimoListSkills(
82
+ params: ListSkillsParams,
83
+ ): Promise<ListSkillsResult> {
84
+ const logger = getGlobalMatimoLogger();
85
+ const allSkills = new Map<string, SkillSummary>();
86
+
87
+ try {
88
+ // Try global MatimoInstance first
89
+ try {
90
+ const matimo = getGlobalMatimoInstance();
91
+ if (matimo) {
92
+ const matimoSkills = matimo.listSkills();
93
+ if (matimoSkills?.length > 0) {
94
+ logger.debug('matimo_list_skills: from MatimoInstance', { count: matimoSkills.length });
95
+ matimoSkills.forEach((s) => allSkills.set(s.name, s));
96
+ return { skills: Array.from(allSkills.values()), total: allSkills.size };
97
+ }
98
+ }
99
+ } catch (err) {
100
+ logger.debug('matimo_list_skills: MatimoInstance unavailable', {
101
+ error: (err as Error).message,
102
+ });
103
+ }
104
+
105
+ // Auto-discover from @matimo/* packages
106
+ try {
107
+ const toolLoader = new ToolLoader();
108
+ const discoveredPaths = toolLoader.autoDiscoverPackages();
109
+
110
+ for (const toolPath of discoveredPaths) {
111
+ const pkgDir = path.dirname(toolPath);
112
+ const skillsPath = path.join(pkgDir, 'skills');
113
+ const discovered = loadSkillsFromPath(skillsPath, 'builtin', logger);
114
+ discovered.forEach((s) => allSkills.set(s.name, s));
115
+ }
116
+ } catch (err) {
117
+ logger.debug('matimo_list_skills: auto-discovery failed', {
118
+ error: (err as Error).message,
119
+ });
120
+ }
121
+
122
+ // Load from explicit skills_dir if provided
123
+ if (params.skills_dir) {
124
+ const skillsDir = path.resolve(params.skills_dir);
125
+ const discovered = loadSkillsFromPath(skillsDir, 'user', logger);
126
+ discovered.forEach((s) => allSkills.set(s.name, s));
127
+ }
128
+
129
+ const results = Array.from(allSkills.values());
130
+ logger.debug('matimo_list_skills: complete', { total: results.length });
131
+ return { skills: results, total: results.length };
132
+ } catch (err) {
133
+ logger.error('matimo_list_skills: failed', {
134
+ error: (err as Error).message,
135
+ });
136
+ return { skills: [], total: 0 };
137
+ }
138
+ }
@@ -0,0 +1,32 @@
1
+ name: matimo_list_user_tools
2
+ version: '1.0.0'
3
+ description: List all user-created tools in a directory with risk classification, approval status, and metadata.
4
+ requires_approval: false
5
+ tags:
6
+ - matimo
7
+ - meta
8
+ - discovery
9
+
10
+ parameters:
11
+ tool_dir:
12
+ type: string
13
+ required: false
14
+ description: Directory to scan for tools (default ./matimo-tools)
15
+ include_drafts:
16
+ type: boolean
17
+ required: false
18
+ description: Whether to include draft tools in the listing (default true)
19
+
20
+ execution:
21
+ type: function
22
+ code: './matimo_list_user_tools.ts'
23
+
24
+ output_schema:
25
+ type: object
26
+ properties:
27
+ tools:
28
+ type: array
29
+ description: List of discovered tools
30
+ total:
31
+ type: number
32
+ description: Total number of tools found
@@ -0,0 +1,74 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import yaml from 'js-yaml';
4
+ import {
5
+ validateToolDefinition,
6
+ classifyRisk,
7
+ getGlobalMatimoLogger,
8
+ } from '@matimo/core';
9
+
10
+ interface ListParams {
11
+ tool_dir?: string;
12
+ include_drafts?: boolean;
13
+ }
14
+
15
+ interface ToolSummary {
16
+ name: string;
17
+ description: string;
18
+ version: string;
19
+ status: string;
20
+ riskLevel: string;
21
+ tags: string[];
22
+ }
23
+
24
+ interface ListResult {
25
+ tools: ToolSummary[];
26
+ total: number;
27
+ }
28
+
29
+ export default async function matimoListUserTools(
30
+ params: ListParams,
31
+ ): Promise<ListResult> {
32
+ const logger = getGlobalMatimoLogger();
33
+ const toolDir = params.tool_dir || './matimo-tools';
34
+ const includeDrafts = params.include_drafts !== false;
35
+
36
+ const tools: ToolSummary[] = [];
37
+
38
+ if (!fs.existsSync(toolDir)) {
39
+ return { tools: [], total: 0 };
40
+ }
41
+
42
+ const entries = fs.readdirSync(toolDir, { withFileTypes: true });
43
+ for (const entry of entries) {
44
+ if (!entry.isDirectory()) continue;
45
+
46
+ const defPath = path.join(toolDir, entry.name, 'definition.yaml');
47
+ if (!fs.existsSync(defPath)) continue;
48
+
49
+ try {
50
+ const content = fs.readFileSync(defPath, 'utf-8');
51
+ const parsed = yaml.load(content);
52
+ const tool = validateToolDefinition(parsed);
53
+
54
+ const status = tool.status || 'approved';
55
+ if (!includeDrafts && status === 'draft') continue;
56
+
57
+ tools.push({
58
+ name: tool.name,
59
+ description: tool.description,
60
+ version: tool.version,
61
+ status,
62
+ riskLevel: classifyRisk(tool),
63
+ tags: tool.tags || [],
64
+ });
65
+ } catch (err) {
66
+ logger.warn('matimo_list_user_tools: failed to parse tool', {
67
+ dir: entry.name,
68
+ error: (err as Error).message,
69
+ });
70
+ }
71
+ }
72
+
73
+ return { tools, total: tools.length };
74
+ }
@@ -0,0 +1,35 @@
1
+ name: matimo_reload_tools
2
+ version: '1.0.0'
3
+ description: >-
4
+ Hot-reload all tools from configured toolPaths. Clears the registry, re-reads
5
+ YAML definitions from disk, re-validates untrusted tools against the active
6
+ policy, and returns a summary of loaded, removed, revalidated, and rejected
7
+ tools. Use after matimo_create_tool + matimo_approve_tool to bring new tools
8
+ into the live registry without restarting the process.
9
+ requires_approval: true
10
+ tags:
11
+ - matimo
12
+ - meta
13
+ - lifecycle
14
+
15
+ parameters: {}
16
+
17
+ execution:
18
+ type: function
19
+ code: './matimo_reload_tools.ts'
20
+
21
+ output_schema:
22
+ type: object
23
+ properties:
24
+ success:
25
+ type: boolean
26
+ loaded:
27
+ type: number
28
+ removed:
29
+ type: number
30
+ revalidated:
31
+ type: number
32
+ rejected:
33
+ type: array
34
+ message:
35
+ type: string
@@ -0,0 +1,29 @@
1
+ import { getGlobalMatimoLogger } from '@matimo/core';
2
+
3
+ /**
4
+ * matimo_reload_tools — Hot-reload all tools from configured toolPaths.
5
+ *
6
+ * NOTE: This function is a placeholder. The actual reload logic is intercepted
7
+ * and handled directly by MatimoInstance.execute() because reloadTools() is a
8
+ * method on the instance itself (it clears the registry, re-reads YAML from
9
+ * disk, re-validates untrusted tools, etc.). The function executor cannot do
10
+ * this because it doesn't have a reference to the MatimoInstance.
11
+ *
12
+ * If this file is ever reached (e.g., in tests without the interception),
13
+ * it returns an error instructing the caller to use matimo.reloadTools() directly.
14
+ */
15
+ export default async function matimoReloadTools(): Promise<{
16
+ success: boolean;
17
+ message: string;
18
+ }> {
19
+ const logger = getGlobalMatimoLogger();
20
+ logger.warn(
21
+ 'matimo_reload_tools: reached fallback implementation — this should be intercepted by MatimoInstance.execute()',
22
+ );
23
+
24
+ return {
25
+ success: false,
26
+ message:
27
+ 'Reload must be handled by MatimoInstance. If you see this, the interception in execute() is not active.',
28
+ };
29
+ }
@@ -0,0 +1,32 @@
1
+ name: matimo_search_tools
2
+ version: '1.0.0'
3
+ description: Search the loaded tool registry by keyword. Returns matching tool names, descriptions, and tags. Use to discover available tools before calling them.
4
+ requires_approval: false
5
+ tags:
6
+ - matimo
7
+ - meta
8
+ - discovery
9
+
10
+ parameters:
11
+ query:
12
+ type: string
13
+ required: true
14
+ description: Search keyword — matched against tool names, descriptions, and tags
15
+ limit:
16
+ type: number
17
+ required: false
18
+ description: Maximum number of results to return (default 20)
19
+
20
+ execution:
21
+ type: function
22
+ code: './matimo_search_tools.ts'
23
+
24
+ output_schema:
25
+ type: object
26
+ properties:
27
+ results:
28
+ type: array
29
+ total:
30
+ type: number
31
+ query:
32
+ type: string
@@ -0,0 +1,82 @@
1
+ import { getGlobalMatimoInstance, getGlobalMatimoLogger, validateToolDefinition, classifyRisk } from '@matimo/core';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import yaml from 'js-yaml';
5
+
6
+ interface SearchParams {
7
+ query: string;
8
+ limit?: number;
9
+ }
10
+
11
+ interface ToolSummary {
12
+ name: string;
13
+ description: string;
14
+ version: string;
15
+ tags: string[];
16
+ riskLevel: string;
17
+ }
18
+
19
+ interface SearchResult {
20
+ results: ToolSummary[];
21
+ total: number;
22
+ query: string;
23
+ }
24
+
25
+ export default async function matimoSearchTools(params: SearchParams): Promise<SearchResult> {
26
+ const logger = getGlobalMatimoLogger();
27
+ const query = params.query ?? '';
28
+ const limit = params.limit ?? 20;
29
+
30
+ const toSummary = (tool: { name: string; description: string; version: string; tags?: string[] }): ToolSummary => ({
31
+ name: tool.name,
32
+ description: tool.description,
33
+ version: tool.version,
34
+ tags: tool.tags ?? [],
35
+ riskLevel: classifyRisk(tool as Parameters<typeof classifyRisk>[0]),
36
+ });
37
+
38
+ // Prefer registry search via the global instance (has all loaded tools)
39
+ try {
40
+ const instance = getGlobalMatimoInstance();
41
+ const found = instance.searchTools(query).slice(0, limit);
42
+ logger.debug('matimo_search_tools: registry search', { query, count: found.length });
43
+ return {
44
+ results: found.map(toSummary),
45
+ total: found.length,
46
+ query,
47
+ };
48
+ } catch {
49
+ // Global instance not set — fall through to disk-based scan below
50
+ logger.debug('matimo_search_tools: no global instance, falling back to disk scan');
51
+ }
52
+
53
+ // Fallback: scan the default tools directory
54
+ const toolDir = './matimo-tools';
55
+ if (!fs.existsSync(toolDir)) {
56
+ return { results: [], total: 0, query };
57
+ }
58
+
59
+ const lowerQuery = query.toLowerCase();
60
+ const results: ToolSummary[] = [];
61
+
62
+ for (const entry of fs.readdirSync(toolDir, { withFileTypes: true })) {
63
+ if (!entry.isDirectory()) continue;
64
+ const defPath = path.join(toolDir, entry.name, 'definition.yaml');
65
+ if (!fs.existsSync(defPath)) continue;
66
+
67
+ try {
68
+ const tool = validateToolDefinition(yaml.load(fs.readFileSync(defPath, 'utf-8')));
69
+ const matches =
70
+ tool.name.toLowerCase().includes(lowerQuery) ||
71
+ tool.description.toLowerCase().includes(lowerQuery) ||
72
+ (tool.tags ?? []).some((t) => t.toLowerCase().includes(lowerQuery));
73
+
74
+ if (matches) results.push(toSummary(tool));
75
+ } catch {
76
+ // Skip invalid definitions silently
77
+ }
78
+ if (results.length >= limit) break;
79
+ }
80
+
81
+ return { results, total: results.length, query };
82
+ }
@@ -0,0 +1,43 @@
1
+ name: matimo_validate_skill
2
+ version: '1.0.0'
3
+ description: >-
4
+ Validate an existing skill against the Agent Skills specification
5
+ (https://agentskills.io/specification). Checks SKILL.md frontmatter, naming
6
+ rules, directory structure, and best practices.
7
+ requires_approval: false
8
+ tags:
9
+ - matimo
10
+ - meta
11
+ - skill
12
+ - validation
13
+
14
+ parameters:
15
+ name:
16
+ type: string
17
+ required: true
18
+ description: Name of the skill directory to validate
19
+ skills_dir:
20
+ type: string
21
+ required: false
22
+ description: Directory containing skills (default ./matimo-tools/skills)
23
+
24
+ execution:
25
+ type: function
26
+ code: './matimo_validate_skill.ts'
27
+
28
+ output_schema:
29
+ type: object
30
+ properties:
31
+ valid:
32
+ type: boolean
33
+ description: Whether the skill passes all validation checks
34
+ name:
35
+ type: string
36
+ issues:
37
+ type: array
38
+ description: List of validation issues (errors and warnings)
39
+ structure:
40
+ type: object
41
+ description: Skill directory structure analysis
42
+ message:
43
+ type: string