@matimo/core 0.1.0-alpha.9 → 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.
- package/README.md +341 -14
- package/dist/approval/approval-handler.d.ts +5 -1
- package/dist/approval/approval-handler.d.ts.map +1 -1
- package/dist/approval/approval-handler.js +6 -0
- package/dist/approval/approval-handler.js.map +1 -1
- package/dist/core/schema.d.ts +41 -10
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +40 -4
- package/dist/core/schema.js.map +1 -1
- package/dist/core/skill-content-parser.d.ts +91 -0
- package/dist/core/skill-content-parser.d.ts.map +1 -0
- package/dist/core/skill-content-parser.js +248 -0
- package/dist/core/skill-content-parser.js.map +1 -0
- package/dist/core/skill-loader.d.ts +46 -0
- package/dist/core/skill-loader.d.ts.map +1 -0
- package/dist/core/skill-loader.js +310 -0
- package/dist/core/skill-loader.js.map +1 -0
- package/dist/core/skill-registry.d.ts +131 -0
- package/dist/core/skill-registry.d.ts.map +1 -0
- package/dist/core/skill-registry.js +316 -0
- package/dist/core/skill-registry.js.map +1 -0
- package/dist/core/tfidf-embedding.d.ts +45 -0
- package/dist/core/tfidf-embedding.d.ts.map +1 -0
- package/dist/core/tfidf-embedding.js +199 -0
- package/dist/core/tfidf-embedding.js.map +1 -0
- package/dist/core/tool-loader.d.ts +3 -1
- package/dist/core/tool-loader.d.ts.map +1 -1
- package/dist/core/tool-loader.js +33 -10
- package/dist/core/tool-loader.js.map +1 -1
- package/dist/core/types.d.ts +203 -6
- package/dist/core/types.d.ts.map +1 -1
- package/dist/encodings/parameter-encoding.d.ts +1 -1
- package/dist/encodings/parameter-encoding.d.ts.map +1 -1
- package/dist/encodings/parameter-encoding.js +9 -4
- package/dist/encodings/parameter-encoding.js.map +1 -1
- package/dist/errors/matimo-error.d.ts +11 -2
- package/dist/errors/matimo-error.d.ts.map +1 -1
- package/dist/errors/matimo-error.js +25 -1
- package/dist/errors/matimo-error.js.map +1 -1
- package/dist/executors/command-executor.d.ts +9 -2
- package/dist/executors/command-executor.d.ts.map +1 -1
- package/dist/executors/command-executor.js +29 -5
- package/dist/executors/command-executor.js.map +1 -1
- package/dist/executors/function-executor.d.ts +10 -3
- package/dist/executors/function-executor.d.ts.map +1 -1
- package/dist/executors/function-executor.js +44 -24
- package/dist/executors/function-executor.js.map +1 -1
- package/dist/executors/http-executor.d.ts +79 -4
- package/dist/executors/http-executor.d.ts.map +1 -1
- package/dist/executors/http-executor.js +232 -28
- package/dist/executors/http-executor.js.map +1 -1
- package/dist/index.d.ts +25 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/langchain.d.ts +55 -0
- package/dist/integrations/langchain.d.ts.map +1 -1
- package/dist/integrations/langchain.js +71 -4
- package/dist/integrations/langchain.js.map +1 -1
- package/dist/logging/winston-logger.d.ts.map +1 -1
- package/dist/logging/winston-logger.js +9 -1
- package/dist/logging/winston-logger.js.map +1 -1
- package/dist/matimo-instance.d.ts +230 -18
- package/dist/matimo-instance.d.ts.map +1 -1
- package/dist/matimo-instance.js +739 -40
- package/dist/matimo-instance.js.map +1 -1
- package/dist/mcp/index.d.ts +18 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +24 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/mcp-server.d.ts +141 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -0
- package/dist/mcp/mcp-server.js +754 -0
- package/dist/mcp/mcp-server.js.map +1 -0
- package/dist/mcp/secrets/aws-resolver.d.ts +41 -0
- package/dist/mcp/secrets/aws-resolver.d.ts.map +1 -0
- package/dist/mcp/secrets/aws-resolver.js +141 -0
- package/dist/mcp/secrets/aws-resolver.js.map +1 -0
- package/dist/mcp/secrets/dotenv-resolver.d.ts +23 -0
- package/dist/mcp/secrets/dotenv-resolver.d.ts.map +1 -0
- package/dist/mcp/secrets/dotenv-resolver.js +94 -0
- package/dist/mcp/secrets/dotenv-resolver.js.map +1 -0
- package/dist/mcp/secrets/env-resolver.d.ts +14 -0
- package/dist/mcp/secrets/env-resolver.d.ts.map +1 -0
- package/dist/mcp/secrets/env-resolver.js +27 -0
- package/dist/mcp/secrets/env-resolver.js.map +1 -0
- package/dist/mcp/secrets/index.d.ts +14 -0
- package/dist/mcp/secrets/index.d.ts.map +1 -0
- package/dist/mcp/secrets/index.js +13 -0
- package/dist/mcp/secrets/index.js.map +1 -0
- package/dist/mcp/secrets/resolver-chain.d.ts +34 -0
- package/dist/mcp/secrets/resolver-chain.d.ts.map +1 -0
- package/dist/mcp/secrets/resolver-chain.js +141 -0
- package/dist/mcp/secrets/resolver-chain.js.map +1 -0
- package/dist/mcp/secrets/types.d.ts +73 -0
- package/dist/mcp/secrets/types.d.ts.map +1 -0
- package/dist/mcp/secrets/types.js +8 -0
- package/dist/mcp/secrets/types.js.map +1 -0
- package/dist/mcp/secrets/vault-resolver.d.ts +43 -0
- package/dist/mcp/secrets/vault-resolver.d.ts.map +1 -0
- package/dist/mcp/secrets/vault-resolver.js +127 -0
- package/dist/mcp/secrets/vault-resolver.js.map +1 -0
- package/dist/mcp/tool-converter.d.ts +40 -0
- package/dist/mcp/tool-converter.d.ts.map +1 -0
- package/dist/mcp/tool-converter.js +185 -0
- package/dist/mcp/tool-converter.js.map +1 -0
- package/dist/policy/approval-manifest.d.ts +76 -0
- package/dist/policy/approval-manifest.d.ts.map +1 -0
- package/dist/policy/approval-manifest.js +197 -0
- package/dist/policy/approval-manifest.js.map +1 -0
- package/dist/policy/content-validator.d.ts +19 -0
- package/dist/policy/content-validator.d.ts.map +1 -0
- package/dist/policy/content-validator.js +196 -0
- package/dist/policy/content-validator.js.map +1 -0
- package/dist/policy/default-policy.d.ts +46 -0
- package/dist/policy/default-policy.d.ts.map +1 -0
- package/dist/policy/default-policy.js +241 -0
- package/dist/policy/default-policy.js.map +1 -0
- package/dist/policy/events.d.ts +71 -0
- package/dist/policy/events.d.ts.map +1 -0
- package/dist/policy/events.js +8 -0
- package/dist/policy/events.js.map +1 -0
- package/dist/policy/index.d.ts +13 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +9 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/integrity-tracker.d.ts +62 -0
- package/dist/policy/integrity-tracker.d.ts.map +1 -0
- package/dist/policy/integrity-tracker.js +79 -0
- package/dist/policy/integrity-tracker.js.map +1 -0
- package/dist/policy/policy-loader.d.ts +58 -0
- package/dist/policy/policy-loader.d.ts.map +1 -0
- package/dist/policy/policy-loader.js +156 -0
- package/dist/policy/policy-loader.js.map +1 -0
- package/dist/policy/risk-classifier.d.ts +18 -0
- package/dist/policy/risk-classifier.d.ts.map +1 -0
- package/dist/policy/risk-classifier.js +47 -0
- package/dist/policy/risk-classifier.js.map +1 -0
- package/dist/policy/types.d.ts +131 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/policy/types.js +8 -0
- package/dist/policy/types.js.map +1 -0
- package/package.json +22 -6
- package/tools/matimo_approve_tool/definition.yaml +36 -0
- package/tools/matimo_approve_tool/matimo_approve_tool.ts +90 -0
- package/tools/matimo_create_skill/definition.yaml +46 -0
- package/tools/matimo_create_skill/matimo_create_skill.ts +75 -0
- package/tools/matimo_create_tool/definition.yaml +48 -0
- package/tools/matimo_create_tool/matimo_create_tool.ts +137 -0
- package/tools/matimo_get_skill/definition.yaml +60 -0
- package/tools/matimo_get_skill/matimo_get_skill.ts +182 -0
- package/tools/matimo_get_tool/definition.yaml +36 -0
- package/tools/matimo_get_tool/matimo_get_tool.ts +56 -0
- package/tools/matimo_get_tool_status/definition.yaml +42 -0
- package/tools/matimo_get_tool_status/matimo_get_tool_status.ts +101 -0
- package/tools/matimo_list_skills/definition.yaml +52 -0
- package/tools/matimo_list_skills/matimo_list_skills.ts +138 -0
- package/tools/matimo_list_user_tools/definition.yaml +32 -0
- package/tools/matimo_list_user_tools/matimo_list_user_tools.ts +74 -0
- package/tools/matimo_reload_tools/definition.yaml +35 -0
- package/tools/matimo_reload_tools/matimo_reload_tools.ts +29 -0
- package/tools/matimo_search_tools/definition.yaml +32 -0
- package/tools/matimo_search_tools/matimo_search_tools.ts +82 -0
- package/tools/matimo_validate_skill/definition.yaml +43 -0
- package/tools/matimo_validate_skill/matimo_validate_skill.ts +137 -0
- package/tools/matimo_validate_tool/definition.yaml +34 -0
- package/tools/matimo_validate_tool/matimo_validate_tool.ts +168 -0
- package/tools/shared/skill-validation.ts +335 -0
- 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
|