@tankpkg/mcp-server 0.4.2 → 0.5.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 +41 -33
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +6 -5
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +6 -6
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/packer.d.ts +20 -0
- package/dist/lib/packer.d.ts.map +1 -1
- package/dist/lib/packer.js +85 -0
- package/dist/lib/packer.js.map +1 -1
- package/dist/tools/audit-skill.d.ts +3 -0
- package/dist/tools/audit-skill.d.ts.map +1 -0
- package/dist/tools/audit-skill.js +213 -0
- package/dist/tools/audit-skill.js.map +1 -0
- package/dist/tools/doctor.d.ts +3 -0
- package/dist/tools/doctor.d.ts.map +1 -0
- package/dist/tools/doctor.js +158 -0
- package/dist/tools/doctor.js.map +1 -0
- package/dist/tools/init-skill.d.ts +3 -0
- package/dist/tools/init-skill.d.ts.map +1 -0
- package/dist/tools/init-skill.js +72 -0
- package/dist/tools/init-skill.js.map +1 -0
- package/dist/tools/install-skill.d.ts +3 -0
- package/dist/tools/install-skill.d.ts.map +1 -0
- package/dist/tools/install-skill.js +206 -0
- package/dist/tools/install-skill.js.map +1 -0
- package/dist/tools/link-skill.d.ts +3 -0
- package/dist/tools/link-skill.d.ts.map +1 -0
- package/dist/tools/link-skill.js +81 -0
- package/dist/tools/link-skill.js.map +1 -0
- package/dist/tools/logout.d.ts +3 -0
- package/dist/tools/logout.d.ts.map +1 -0
- package/dist/tools/logout.js +19 -0
- package/dist/tools/logout.js.map +1 -0
- package/dist/tools/remove-skill.d.ts +3 -0
- package/dist/tools/remove-skill.d.ts.map +1 -0
- package/dist/tools/remove-skill.js +110 -0
- package/dist/tools/remove-skill.js.map +1 -0
- package/dist/tools/scan-skill.d.ts.map +1 -1
- package/dist/tools/scan-skill.js +41 -18
- package/dist/tools/scan-skill.js.map +1 -1
- package/dist/tools/skill-permissions.d.ts +3 -0
- package/dist/tools/skill-permissions.d.ts.map +1 -0
- package/dist/tools/skill-permissions.js +311 -0
- package/dist/tools/skill-permissions.js.map +1 -0
- package/dist/tools/unlink-skill.d.ts +3 -0
- package/dist/tools/unlink-skill.d.ts.map +1 -0
- package/dist/tools/unlink-skill.js +72 -0
- package/dist/tools/unlink-skill.js.map +1 -0
- package/dist/tools/update-skill.d.ts +3 -0
- package/dist/tools/update-skill.d.ts.map +1 -0
- package/dist/tools/update-skill.js +317 -0
- package/dist/tools/update-skill.js.map +1 -0
- package/dist/tools/verify-skills.d.ts +3 -0
- package/dist/tools/verify-skills.d.ts.map +1 -0
- package/dist/tools/verify-skills.js +121 -0
- package/dist/tools/verify-skills.js.map +1 -0
- package/dist/tools/whoami.d.ts +3 -0
- package/dist/tools/whoami.d.ts.map +1 -0
- package/dist/tools/whoami.js +29 -0
- package/dist/tools/whoami.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { getConfigPath, getConfig } from '../lib/config.js';
|
|
3
|
+
import { TankApiClient } from '../lib/api-client.js';
|
|
4
|
+
const MIN_NODE_MAJOR = 24;
|
|
5
|
+
function checkConfigFile() {
|
|
6
|
+
const configPath = getConfigPath();
|
|
7
|
+
if (!fs.existsSync(configPath)) {
|
|
8
|
+
return {
|
|
9
|
+
name: 'Configuration File',
|
|
10
|
+
status: 'FAIL',
|
|
11
|
+
message: `Configuration file not found at ${configPath}. Run the login tool to create it.`,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
16
|
+
JSON.parse(raw);
|
|
17
|
+
return {
|
|
18
|
+
name: 'Configuration File',
|
|
19
|
+
status: 'PASS',
|
|
20
|
+
message: `Configuration file exists and is valid JSON (${configPath}).`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
25
|
+
return {
|
|
26
|
+
name: 'Configuration File',
|
|
27
|
+
status: 'FAIL',
|
|
28
|
+
message: `Configuration file at ${configPath} is malformed: ${detail}`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function checkAuthentication() {
|
|
33
|
+
const client = new TankApiClient();
|
|
34
|
+
if (!client.isAuthenticated) {
|
|
35
|
+
return {
|
|
36
|
+
name: 'Authentication',
|
|
37
|
+
status: 'FAIL',
|
|
38
|
+
message: 'Not authenticated. Use the login tool to authenticate with Tank.',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const authCheck = await client.verifyAuth();
|
|
42
|
+
if (authCheck.valid) {
|
|
43
|
+
const name = authCheck.user.name ?? 'unknown';
|
|
44
|
+
return {
|
|
45
|
+
name: 'Authentication',
|
|
46
|
+
status: 'PASS',
|
|
47
|
+
message: `Authenticated as ${name}.`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (authCheck.reason === 'network-error') {
|
|
51
|
+
return {
|
|
52
|
+
name: 'Authentication',
|
|
53
|
+
status: 'FAIL',
|
|
54
|
+
message: `Could not verify credentials (network error). ${authCheck.error ?? ''}`.trim(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
name: 'Authentication',
|
|
59
|
+
status: 'FAIL',
|
|
60
|
+
message: 'Credentials are expired or invalid. Use the login tool to re-authenticate.',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function checkRegistryConnectivity() {
|
|
64
|
+
const config = getConfig();
|
|
65
|
+
const registryUrl = config.registry;
|
|
66
|
+
try {
|
|
67
|
+
const healthUrl = `${registryUrl}/api/health`;
|
|
68
|
+
const response = await fetch(healthUrl, {
|
|
69
|
+
signal: AbortSignal.timeout(10_000),
|
|
70
|
+
});
|
|
71
|
+
if (response.ok) {
|
|
72
|
+
return {
|
|
73
|
+
name: 'Registry Connectivity',
|
|
74
|
+
status: 'PASS',
|
|
75
|
+
message: `Registry at ${registryUrl} is reachable.`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
name: 'Registry Connectivity',
|
|
80
|
+
status: 'FAIL',
|
|
81
|
+
message: `Registry at ${registryUrl} returned HTTP ${response.status}.`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return {
|
|
86
|
+
name: 'Registry Connectivity',
|
|
87
|
+
status: 'FAIL',
|
|
88
|
+
message: `Cannot reach registry at ${registryUrl}. Check your network connection.`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function checkNodeVersion() {
|
|
93
|
+
const raw = process.version;
|
|
94
|
+
const match = raw.match(/^v(\d+)/);
|
|
95
|
+
const major = match ? parseInt(match[1], 10) : 0;
|
|
96
|
+
if (major >= MIN_NODE_MAJOR) {
|
|
97
|
+
return {
|
|
98
|
+
name: 'Node.js Version',
|
|
99
|
+
status: 'PASS',
|
|
100
|
+
message: `Node.js ${raw} meets the minimum requirement (v${MIN_NODE_MAJOR}.0.0).`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
name: 'Node.js Version',
|
|
105
|
+
status: 'FAIL',
|
|
106
|
+
message: `Node.js ${raw} is below the minimum required version v${MIN_NODE_MAJOR}.0.0. Please upgrade Node.js.`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function formatChecks(checks) {
|
|
110
|
+
const lines = [];
|
|
111
|
+
lines.push('Tank Doctor Report');
|
|
112
|
+
lines.push('==================');
|
|
113
|
+
lines.push('');
|
|
114
|
+
for (const check of checks) {
|
|
115
|
+
const icon = check.status === 'PASS' ? 'PASS' : 'FAIL';
|
|
116
|
+
lines.push(`[${icon}] ${check.name}`);
|
|
117
|
+
lines.push(` ${check.message}`);
|
|
118
|
+
}
|
|
119
|
+
lines.push('');
|
|
120
|
+
const failedChecks = checks.filter((c) => c.status === 'FAIL');
|
|
121
|
+
const allPassed = failedChecks.length === 0;
|
|
122
|
+
if (allPassed) {
|
|
123
|
+
lines.push('All checks passed. Your Tank environment is ready to use.');
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
lines.push('Suggestions:');
|
|
127
|
+
for (const check of failedChecks) {
|
|
128
|
+
if (check.name === 'Authentication') {
|
|
129
|
+
lines.push(' - Use the login tool to authenticate with Tank.');
|
|
130
|
+
}
|
|
131
|
+
else if (check.name === 'Registry Connectivity') {
|
|
132
|
+
lines.push(' - Check your network connection and verify the registry URL.');
|
|
133
|
+
}
|
|
134
|
+
else if (check.name === 'Node.js Version') {
|
|
135
|
+
lines.push(` - Upgrade Node.js to v${MIN_NODE_MAJOR}.0.0 or later.`);
|
|
136
|
+
}
|
|
137
|
+
else if (check.name === 'Configuration File') {
|
|
138
|
+
lines.push(' - Use the login tool to create a valid configuration file.');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
lines.push('');
|
|
142
|
+
lines.push('The environment is not healthy. Please address the issues above.');
|
|
143
|
+
}
|
|
144
|
+
return lines.join('\n');
|
|
145
|
+
}
|
|
146
|
+
export function registerDoctorTool(server) {
|
|
147
|
+
server.tool('doctor', 'Diagnose Tank setup and environment.', {}, async () => {
|
|
148
|
+
const checks = [];
|
|
149
|
+
checks.push(checkConfigFile());
|
|
150
|
+
checks.push(await checkAuthentication());
|
|
151
|
+
checks.push(await checkRegistryConnectivity());
|
|
152
|
+
checks.push(checkNodeVersion());
|
|
153
|
+
return {
|
|
154
|
+
content: [{ type: 'text', text: formatChecks(checks) }],
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/tools/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-skill.d.ts","sourceRoot":"","sources":["../../src/tools/init-skill.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+E7D"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { skillsJsonSchema } from '@tank/shared';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
const SCOPED_NAME_PATTERN = /^@[a-z0-9-]+\/[a-z0-9][a-z0-9-]*$/;
|
|
6
|
+
const SEMVER_PATTERN = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
|
|
7
|
+
export function registerInitSkillTool(server) {
|
|
8
|
+
server.tool('init-skill', 'Create a new skills.json and SKILL.md template for a Tank skill.', {
|
|
9
|
+
name: z.string().regex(SCOPED_NAME_PATTERN, 'Name must be in @org/name format'),
|
|
10
|
+
version: z.string().regex(SEMVER_PATTERN, 'Version must be valid semver').optional().default('0.1.0'),
|
|
11
|
+
description: z.string().optional().default(''),
|
|
12
|
+
directory: z.string().optional().default('.'),
|
|
13
|
+
}, async ({ name, version = '0.1.0', description = '', directory = '.' }) => {
|
|
14
|
+
const targetDir = path.resolve(directory);
|
|
15
|
+
if (!fs.existsSync(targetDir)) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: 'text', text: `Directory does not exist: ${targetDir}` }],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (!fs.statSync(targetDir).isDirectory()) {
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: `Path is not a directory: ${targetDir}` }],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const skillsJsonPath = path.join(targetDir, 'skills.json');
|
|
26
|
+
if (fs.existsSync(skillsJsonPath)) {
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: 'text', text: `skills.json already exists at ${skillsJsonPath}. Aborting to avoid overwrite.` }],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const manifest = {
|
|
32
|
+
name,
|
|
33
|
+
version,
|
|
34
|
+
description,
|
|
35
|
+
skills: {},
|
|
36
|
+
permissions: {
|
|
37
|
+
network: { outbound: [] },
|
|
38
|
+
filesystem: { read: [], write: [] },
|
|
39
|
+
subprocess: false,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const parseResult = skillsJsonSchema.safeParse(manifest);
|
|
43
|
+
if (!parseResult.success) {
|
|
44
|
+
const details = parseResult.error.issues
|
|
45
|
+
.map((issue) => `${issue.path.join('.') || 'root'}: ${issue.message}`)
|
|
46
|
+
.join('; ');
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: 'text', text: `Failed to create skills.json: ${details}` }],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
fs.writeFileSync(skillsJsonPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
52
|
+
const skillMdPath = path.join(targetDir, 'SKILL.md');
|
|
53
|
+
let createdSkillMd = false;
|
|
54
|
+
if (!fs.existsSync(skillMdPath)) {
|
|
55
|
+
const skillMd = `# ${name}\n\n${description || 'Description here.'}\n`;
|
|
56
|
+
fs.writeFileSync(skillMdPath, skillMd, 'utf-8');
|
|
57
|
+
createdSkillMd = true;
|
|
58
|
+
}
|
|
59
|
+
const skillMdLine = createdSkillMd
|
|
60
|
+
? `Created: ${skillMdPath}`
|
|
61
|
+
: `Skipped existing: ${skillMdPath}`;
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: 'text',
|
|
66
|
+
text: `Initialized skill in ${targetDir}\nCreated: ${skillsJsonPath}\n${skillMdLine}`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=init-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-skill.js","sourceRoot":"","sources":["../../src/tools/init-skill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-skill.d.ts","sourceRoot":"","sources":["../../src/tools/install-skill.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2CzE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4NhE"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import { resolve, LOCKFILE_VERSION } from '@tank/shared';
|
|
5
|
+
import { extract } from 'tar';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { TankApiClient } from '../lib/api-client.js';
|
|
8
|
+
const SCOPED_NAME_PATTERN = /^@[a-z0-9-]+\/[a-z0-9][a-z0-9-]*$/;
|
|
9
|
+
function textResult(text, isError) {
|
|
10
|
+
return {
|
|
11
|
+
content: [{ type: 'text', text }],
|
|
12
|
+
...(isError ? { isError: true } : {}),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function getSkillDir(projectDir, skillName) {
|
|
16
|
+
if (skillName.startsWith('@')) {
|
|
17
|
+
const [scope, name] = skillName.split('/');
|
|
18
|
+
return path.join(projectDir, '.tank', 'skills', scope, name);
|
|
19
|
+
}
|
|
20
|
+
return path.join(projectDir, '.tank', 'skills', skillName);
|
|
21
|
+
}
|
|
22
|
+
export function registerInstallSkillTool(server) {
|
|
23
|
+
server.tool('install-skill', 'Install a skill from the Tank registry. Resolves version, downloads tarball, verifies SHA-512 integrity, extracts files, and updates skills.json + skills.lock.', {
|
|
24
|
+
name: z.string().describe('Skill name in @org/name format'),
|
|
25
|
+
version: z.string().optional().describe('Specific version or semver range (default: latest)'),
|
|
26
|
+
directory: z.string().optional().describe('Project directory (defaults to current working directory)'),
|
|
27
|
+
}, async ({ name, version: versionRange, directory }) => {
|
|
28
|
+
// 1. Validate scoped name
|
|
29
|
+
if (!SCOPED_NAME_PATTERN.test(name)) {
|
|
30
|
+
return textResult(`Validation error: Skill name "${name}" must use the @org/name format (e.g. @acme/my-skill).`, true);
|
|
31
|
+
}
|
|
32
|
+
const client = new TankApiClient();
|
|
33
|
+
// 2. Check authentication
|
|
34
|
+
if (!client.isAuthenticated) {
|
|
35
|
+
return textResult('Not authenticated. Use the "login" tool first to authenticate with Tank.', true);
|
|
36
|
+
}
|
|
37
|
+
const dir = directory ? path.resolve(directory) : process.cwd();
|
|
38
|
+
const range = versionRange ?? '*';
|
|
39
|
+
// 3. Read or create skills.json
|
|
40
|
+
const skillsJsonPath = path.join(dir, 'skills.json');
|
|
41
|
+
let skillsJson = { skills: {} };
|
|
42
|
+
if (fs.existsSync(skillsJsonPath)) {
|
|
43
|
+
try {
|
|
44
|
+
const raw = fs.readFileSync(skillsJsonPath, 'utf-8');
|
|
45
|
+
skillsJson = JSON.parse(raw);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return textResult('Failed to read or parse skills.json.', true);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
skillsJson = { skills: {} };
|
|
53
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
54
|
+
fs.writeFileSync(skillsJsonPath, JSON.stringify(skillsJson, null, 2) + '\n');
|
|
55
|
+
}
|
|
56
|
+
// 4. Read existing lockfile
|
|
57
|
+
const lockPath = path.join(dir, 'skills.lock');
|
|
58
|
+
let lock = { lockfileVersion: LOCKFILE_VERSION, skills: {} };
|
|
59
|
+
if (fs.existsSync(lockPath)) {
|
|
60
|
+
try {
|
|
61
|
+
const raw = fs.readFileSync(lockPath, 'utf-8');
|
|
62
|
+
lock = JSON.parse(raw);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
lock = { lockfileVersion: LOCKFILE_VERSION, skills: {} };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// 5. Fetch available versions
|
|
69
|
+
const encodedName = encodeURIComponent(name);
|
|
70
|
+
const versionsResult = await client.fetch(`/api/v1/skills/${encodedName}/versions`);
|
|
71
|
+
if (!versionsResult.ok) {
|
|
72
|
+
if (versionsResult.status === 401 || versionsResult.status === 403) {
|
|
73
|
+
return textResult('Authentication failed. Use the "login" tool to authenticate with Tank.', true);
|
|
74
|
+
}
|
|
75
|
+
if (versionsResult.status === 404) {
|
|
76
|
+
return textResult(`Skill not found: "${name}" does not exist in the Tank registry.`, true);
|
|
77
|
+
}
|
|
78
|
+
if (versionsResult.status === 0) {
|
|
79
|
+
return textResult(`Cannot reach the Tank registry. Check your network connection and try again.\nError: ${versionsResult.error}`, true);
|
|
80
|
+
}
|
|
81
|
+
return textResult(`Failed to fetch versions for ${name}: ${versionsResult.error}`, true);
|
|
82
|
+
}
|
|
83
|
+
const availableVersions = versionsResult.data.versions.map((v) => v.version);
|
|
84
|
+
// 6. Resolve best version
|
|
85
|
+
const resolved = resolve(range, availableVersions);
|
|
86
|
+
if (!resolved) {
|
|
87
|
+
return textResult(`No version of ${name} satisfies range "${range}". Available versions: ${availableVersions.join(', ')}`, true);
|
|
88
|
+
}
|
|
89
|
+
// 7. Check if already installed
|
|
90
|
+
const lockKey = `${name}@${resolved}`;
|
|
91
|
+
if (lock.skills[lockKey]) {
|
|
92
|
+
return textResult(`${name}@${resolved} is already installed. No changes needed.`);
|
|
93
|
+
}
|
|
94
|
+
// 8. Fetch version metadata
|
|
95
|
+
const metaResult = await client.fetch(`/api/v1/skills/${encodedName}/${resolved}`);
|
|
96
|
+
if (!metaResult.ok) {
|
|
97
|
+
if (metaResult.status === 404) {
|
|
98
|
+
return textResult(`Version ${resolved} of ${name} not found in the registry.`, true);
|
|
99
|
+
}
|
|
100
|
+
return textResult(`Failed to fetch metadata for ${name}@${resolved}: ${metaResult.error}`, true);
|
|
101
|
+
}
|
|
102
|
+
const metadata = metaResult.data;
|
|
103
|
+
// 9. Download tarball
|
|
104
|
+
let tarballBuffer;
|
|
105
|
+
try {
|
|
106
|
+
const downloadRes = await fetch(metadata.downloadUrl);
|
|
107
|
+
if (!downloadRes.ok) {
|
|
108
|
+
return textResult(`Failed to download tarball for ${name}@${resolved}: ${downloadRes.status} ${downloadRes.statusText}`, true);
|
|
109
|
+
}
|
|
110
|
+
tarballBuffer = Buffer.from(await downloadRes.arrayBuffer());
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
return textResult(`Network error downloading tarball for ${name}@${resolved}: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
114
|
+
}
|
|
115
|
+
// 10. Verify SHA-512 integrity
|
|
116
|
+
const hash = crypto.createHash('sha512').update(tarballBuffer).digest('base64');
|
|
117
|
+
const computedIntegrity = `sha512-${hash}`;
|
|
118
|
+
if (computedIntegrity !== metadata.integrity) {
|
|
119
|
+
return textResult(`Integrity verification failed for ${name}@${resolved}.\n` +
|
|
120
|
+
`Expected: ${metadata.integrity}\n` +
|
|
121
|
+
`Got: ${computedIntegrity}\n\n` +
|
|
122
|
+
'The tarball may have been tampered with. No files were extracted.', true);
|
|
123
|
+
}
|
|
124
|
+
// 11. Extract tarball safely
|
|
125
|
+
const extractDir = getSkillDir(dir, name);
|
|
126
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
127
|
+
try {
|
|
128
|
+
await extractSafely(tarballBuffer, extractDir);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
// Clean up on extraction failure
|
|
132
|
+
fs.rmSync(extractDir, { recursive: true, force: true });
|
|
133
|
+
return textResult(`Failed to extract tarball for ${name}@${resolved}: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
134
|
+
}
|
|
135
|
+
// 12. Update skills.json
|
|
136
|
+
const skills = (skillsJson.skills ?? {});
|
|
137
|
+
skills[name] = range === '*' ? `^${resolved}` : range;
|
|
138
|
+
skillsJson.skills = skills;
|
|
139
|
+
fs.writeFileSync(skillsJsonPath, JSON.stringify(skillsJson, null, 2) + '\n');
|
|
140
|
+
// 13. Update skills.lock
|
|
141
|
+
lock.skills[lockKey] = {
|
|
142
|
+
resolved: metadata.downloadUrl,
|
|
143
|
+
integrity: computedIntegrity,
|
|
144
|
+
permissions: metadata.permissions ?? {},
|
|
145
|
+
audit_score: metadata.auditScore ?? null,
|
|
146
|
+
};
|
|
147
|
+
// Sort keys alphabetically for determinism
|
|
148
|
+
const sortedSkills = {};
|
|
149
|
+
for (const key of Object.keys(lock.skills).sort()) {
|
|
150
|
+
sortedSkills[key] = lock.skills[key];
|
|
151
|
+
}
|
|
152
|
+
lock.skills = sortedSkills;
|
|
153
|
+
fs.mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
154
|
+
fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2) + '\n');
|
|
155
|
+
// Build response
|
|
156
|
+
const score = metadata.auditScore !== null && metadata.auditScore !== undefined
|
|
157
|
+
? `${metadata.auditScore.toFixed(1)}/10`
|
|
158
|
+
: 'pending';
|
|
159
|
+
const lines = [
|
|
160
|
+
`## Installed ${name}@${resolved}`,
|
|
161
|
+
'',
|
|
162
|
+
`**Integrity:** SHA-512 verified`,
|
|
163
|
+
`**Audit Score:** ${score}`,
|
|
164
|
+
`**Extracted to:** ${extractDir}`,
|
|
165
|
+
'',
|
|
166
|
+
'### Updated files',
|
|
167
|
+
`- skills.json: added "${name}": "${skills[name]}"`,
|
|
168
|
+
`- skills.lock: added ${lockKey}`,
|
|
169
|
+
];
|
|
170
|
+
return textResult(lines.join('\n'));
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Extract a tarball safely with security checks.
|
|
175
|
+
* Rejects: absolute paths, path traversal (..), symlinks/hardlinks.
|
|
176
|
+
*/
|
|
177
|
+
async function extractSafely(tarball, destDir) {
|
|
178
|
+
const tmpTarball = path.join(destDir, '.tmp-tarball.tgz');
|
|
179
|
+
fs.writeFileSync(tmpTarball, tarball);
|
|
180
|
+
try {
|
|
181
|
+
await extract({
|
|
182
|
+
file: tmpTarball,
|
|
183
|
+
cwd: destDir,
|
|
184
|
+
filter: (entryPath) => {
|
|
185
|
+
if (path.isAbsolute(entryPath)) {
|
|
186
|
+
throw new Error(`Absolute path in tarball: ${entryPath}`);
|
|
187
|
+
}
|
|
188
|
+
if (entryPath.split('/').includes('..') || entryPath.split(path.sep).includes('..')) {
|
|
189
|
+
throw new Error(`Path traversal in tarball: ${entryPath}`);
|
|
190
|
+
}
|
|
191
|
+
return true;
|
|
192
|
+
},
|
|
193
|
+
onReadEntry: (entry) => {
|
|
194
|
+
if (entry.type === 'SymbolicLink' || entry.type === 'Link') {
|
|
195
|
+
throw new Error(`Symlink/hardlink in tarball: ${entry.path}`);
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
if (fs.existsSync(tmpTarball)) {
|
|
202
|
+
fs.unlinkSync(tmpTarball);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=install-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-skill.js","sourceRoot":"","sources":["../../src/tools/install-skill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-skill.d.ts","sourceRoot":"","sources":["../../src/tools/link-skill.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiF7D"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
const SCOPED_NAME_PATTERN = /^@[a-z0-9-]+\/[a-z0-9][a-z0-9-]*$/;
|
|
5
|
+
export function registerLinkSkillTool(server) {
|
|
6
|
+
server.tool('link-skill', 'Link an installed skill into an agent workspace. Creates a symlink from the workspace .skills directory to the installed skill.', {
|
|
7
|
+
name: z.string().describe('Skill name in @org/name format'),
|
|
8
|
+
workspace: z.string().describe('Agent workspace directory path'),
|
|
9
|
+
directory: z.string().optional().describe('Project directory where skills are installed (defaults to current working directory)'),
|
|
10
|
+
}, async ({ name, workspace, directory }) => {
|
|
11
|
+
if (!SCOPED_NAME_PATTERN.test(name)) {
|
|
12
|
+
return {
|
|
13
|
+
content: [{
|
|
14
|
+
type: 'text',
|
|
15
|
+
text: `Validation error: Skill name "${name}" must use the @org/name format (e.g. @acme/my-skill).`,
|
|
16
|
+
}],
|
|
17
|
+
isError: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const projectDir = directory ? path.resolve(directory) : process.cwd();
|
|
21
|
+
const workspaceDir = path.resolve(workspace);
|
|
22
|
+
if (!fs.existsSync(workspaceDir)) {
|
|
23
|
+
return {
|
|
24
|
+
content: [{
|
|
25
|
+
type: 'text',
|
|
26
|
+
text: `Error: Workspace directory does not exist: ${workspaceDir}`,
|
|
27
|
+
}],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const skillDir = getSkillDir(projectDir, name);
|
|
32
|
+
if (!fs.existsSync(skillDir)) {
|
|
33
|
+
return {
|
|
34
|
+
content: [{
|
|
35
|
+
type: 'text',
|
|
36
|
+
text: `Skill "${name}" is not installed. Install it first with "install-skill" before linking.`,
|
|
37
|
+
}],
|
|
38
|
+
isError: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const [scope, skillName] = name.split('/');
|
|
42
|
+
const skillsLinkDir = path.join(workspaceDir, '.skills', scope);
|
|
43
|
+
const symlinkPath = path.join(skillsLinkDir, skillName);
|
|
44
|
+
try {
|
|
45
|
+
const stats = fs.lstatSync(symlinkPath);
|
|
46
|
+
if (stats.isSymbolicLink()) {
|
|
47
|
+
const currentTarget = fs.readlinkSync(symlinkPath);
|
|
48
|
+
const resolvedTarget = path.isAbsolute(currentTarget)
|
|
49
|
+
? currentTarget
|
|
50
|
+
: path.resolve(path.dirname(symlinkPath), currentTarget);
|
|
51
|
+
if (path.resolve(resolvedTarget) === path.resolve(skillDir)) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: 'text',
|
|
55
|
+
text: `Skill "${name}" is already linked in ${workspaceDir}.`,
|
|
56
|
+
}],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
fs.unlinkSync(symlinkPath);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
}
|
|
64
|
+
fs.mkdirSync(skillsLinkDir, { recursive: true });
|
|
65
|
+
fs.symlinkSync(skillDir, symlinkPath, 'dir');
|
|
66
|
+
return {
|
|
67
|
+
content: [{
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: `Successfully linked "${name}" into ${workspaceDir}.\nSymlink: ${symlinkPath} → ${skillDir}`,
|
|
70
|
+
}],
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function getSkillDir(projectDir, skillName) {
|
|
75
|
+
if (skillName.startsWith('@')) {
|
|
76
|
+
const [scope, name] = skillName.split('/');
|
|
77
|
+
return path.join(projectDir, '.tank', 'skills', scope, name);
|
|
78
|
+
}
|
|
79
|
+
return path.join(projectDir, '.tank', 'skills', skillName);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=link-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-skill.js","sourceRoot":"","sources":["../../src/tools/link-skill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/tools/logout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0B1D"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getConfig, setConfig } from '../lib/config.js';
|
|
2
|
+
export function registerLogoutTool(server) {
|
|
3
|
+
server.tool('logout', 'Log out of Tank by clearing local credentials.', {}, async () => {
|
|
4
|
+
const config = getConfig();
|
|
5
|
+
if (!config.token) {
|
|
6
|
+
return {
|
|
7
|
+
content: [{ type: 'text', text: 'Not logged in. No credentials to clear.' }],
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
setConfig({ token: undefined, user: undefined });
|
|
11
|
+
// Also clear env-based token so subsequent tool calls in this
|
|
12
|
+
// process don't re-read it via getConfig().
|
|
13
|
+
delete process.env.TANK_TOKEN;
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: 'text', text: 'Successfully logged out.' }],
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/tools/logout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,QAAQ,EACR,gDAAgD,EAChD,EAAE,EACF,KAAK,IAAI,EAAE;QAET,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAE3B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,yCAAyC,EAAE,CAAC;aACtF,CAAC;QACJ,CAAC;QAED,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAEjD,8DAA8D;QAC9D,4CAA4C;QAC5C,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QAE9B,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC;SACvE,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-skill.d.ts","sourceRoot":"","sources":["../../src/tools/remove-skill.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4G/D"}
|