@tankpkg/mcp-server 0.4.2
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/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +44 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +78 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/config.d.ts +25 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +59 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/packer.d.ts +14 -0
- package/dist/lib/packer.d.ts.map +1 -0
- package/dist/lib/packer.js +191 -0
- package/dist/lib/packer.js.map +1 -0
- package/dist/tools/login.d.ts +3 -0
- package/dist/tools/login.d.ts.map +1 -0
- package/dist/tools/login.js +104 -0
- package/dist/tools/login.js.map +1 -0
- package/dist/tools/publish-skill.d.ts +3 -0
- package/dist/tools/publish-skill.d.ts.map +1 -0
- package/dist/tools/publish-skill.js +166 -0
- package/dist/tools/publish-skill.js.map +1 -0
- package/dist/tools/scan-skill.d.ts +3 -0
- package/dist/tools/scan-skill.d.ts.map +1 -0
- package/dist/tools/scan-skill.js +148 -0
- package/dist/tools/scan-skill.js.map +1 -0
- package/dist/tools/search-skills.d.ts +3 -0
- package/dist/tools/search-skills.d.ts.map +1 -0
- package/dist/tools/search-skills.js +54 -0
- package/dist/tools/search-skills.js.map +1 -0
- package/dist/tools/skill-info.d.ts +3 -0
- package/dist/tools/skill-info.d.ts.map +1 -0
- package/dist/tools/skill-info.js +88 -0
- package/dist/tools/skill-info.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tank Contributors
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# @tankpkg/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for Tank - scan and publish AI agent skills directly from your editor.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **scan-skill** - Scan a skill directory for security issues
|
|
8
|
+
- **publish-skill** - Publish a skill to the Tank registry (with dry-run support)
|
|
9
|
+
- **search-skills** - Search the Tank registry for skills
|
|
10
|
+
- **skill-info** - Get detailed information about a specific skill
|
|
11
|
+
- **login** - Authenticate with Tank via GitHub OAuth
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### Claude Code
|
|
16
|
+
|
|
17
|
+
Add to `.claude/settings.json` or your project's `.mcp.json`:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"tank": {
|
|
23
|
+
"command": "npx",
|
|
24
|
+
"args": ["-y", "@tankpkg/mcp-server"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Cursor
|
|
31
|
+
|
|
32
|
+
Add to `~/.cursor/mcp.json`:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"tank": {
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "@tankpkg/mcp-server"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### VS Code (Copilot)
|
|
46
|
+
|
|
47
|
+
Add to `.vscode/mcp.json`:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"servers": {
|
|
52
|
+
"tank": {
|
|
53
|
+
"command": "npx",
|
|
54
|
+
"args": ["-y", "@tankpkg/mcp-server"]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Authentication
|
|
61
|
+
|
|
62
|
+
The MCP server shares authentication with the Tank CLI. If you've already run `tank login`, you're authenticated!
|
|
63
|
+
|
|
64
|
+
Alternatively, set the `TANK_TOKEN` environment variable:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"mcpServers": {
|
|
69
|
+
"tank": {
|
|
70
|
+
"command": "npx",
|
|
71
|
+
"args": ["-y", "@tankpkg/mcp-server"],
|
|
72
|
+
"env": {
|
|
73
|
+
"TANK_TOKEN": "tank_your_token_here"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Usage Examples
|
|
81
|
+
|
|
82
|
+
Once configured, talk to your AI agent naturally:
|
|
83
|
+
|
|
84
|
+
### Scan a skill for security issues
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
"Scan my skill in the ./my-skill folder for security issues"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Publish a skill
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
"Publish my-skill as a public package"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Dry run before publishing
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
"Do a dry run publish of my skill to check if everything looks good"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Search for skills
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
"Search Tank for code review skills"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Get skill info
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
"Get info about @tank/code-review skill"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Install dependencies
|
|
118
|
+
pnpm install
|
|
119
|
+
|
|
120
|
+
# Build
|
|
121
|
+
pnpm build
|
|
122
|
+
|
|
123
|
+
# Run tests
|
|
124
|
+
pnpm test
|
|
125
|
+
|
|
126
|
+
# Start the server (stdio mode)
|
|
127
|
+
pnpm start
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
// Import tools
|
|
5
|
+
import { registerLoginTool } from './tools/login.js';
|
|
6
|
+
import { registerSearchSkillsTool } from './tools/search-skills.js';
|
|
7
|
+
import { registerSkillInfoTool } from './tools/skill-info.js';
|
|
8
|
+
import { registerScanSkillTool } from './tools/scan-skill.js';
|
|
9
|
+
import { registerPublishSkillTool } from './tools/publish-skill.js';
|
|
10
|
+
// Create MCP server instance
|
|
11
|
+
const server = new McpServer({
|
|
12
|
+
name: 'tank',
|
|
13
|
+
version: '0.1.0',
|
|
14
|
+
});
|
|
15
|
+
// Register all tools
|
|
16
|
+
registerLoginTool(server);
|
|
17
|
+
registerSearchSkillsTool(server);
|
|
18
|
+
registerSkillInfoTool(server);
|
|
19
|
+
registerScanSkillTool(server);
|
|
20
|
+
registerPublishSkillTool(server);
|
|
21
|
+
// Start stdio transport
|
|
22
|
+
async function main() {
|
|
23
|
+
const transport = new StdioServerTransport();
|
|
24
|
+
await server.connect(transport);
|
|
25
|
+
}
|
|
26
|
+
main().catch((error) => {
|
|
27
|
+
console.error('MCP server error:', error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,6BAA6B;AAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,qBAAqB;AACrB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACjC,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,wBAAwB,CAAC,MAAM,CAAC,CAAC;AAEjC,wBAAwB;AACxB,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface ApiClientOptions {
|
|
2
|
+
configDir?: string;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Tank API client for MCP server.
|
|
6
|
+
*/
|
|
7
|
+
export declare class TankApiClient {
|
|
8
|
+
private config;
|
|
9
|
+
constructor(options?: ApiClientOptions);
|
|
10
|
+
/**
|
|
11
|
+
* Get the base URL for the Tank API.
|
|
12
|
+
*/
|
|
13
|
+
get baseUrl(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get the auth token (if available).
|
|
16
|
+
*/
|
|
17
|
+
get token(): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Check if authenticated.
|
|
20
|
+
*/
|
|
21
|
+
get isAuthenticated(): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Make an authenticated API request.
|
|
24
|
+
*/
|
|
25
|
+
fetch<T>(path: string, options?: RequestInit): Promise<{
|
|
26
|
+
data: T;
|
|
27
|
+
ok: true;
|
|
28
|
+
} | {
|
|
29
|
+
error: string;
|
|
30
|
+
status: number;
|
|
31
|
+
ok: false;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Verify current auth token is valid.
|
|
35
|
+
*/
|
|
36
|
+
verifyAuth(): Promise<{
|
|
37
|
+
valid: boolean;
|
|
38
|
+
user?: {
|
|
39
|
+
name: string | null;
|
|
40
|
+
email: string | null;
|
|
41
|
+
};
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAa;gBAEf,OAAO,GAAE,gBAAqB;IAI1C;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,GAAG,SAAS,CAE9B;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED;;OAEG;IACG,KAAK,CAAC,CAAC,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,KAAK,CAAA;KAAE,CAAC;IAqChF;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAA;KAAE,CAAC;CAetG"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { getConfig } from './config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Tank API client for MCP server.
|
|
4
|
+
*/
|
|
5
|
+
export class TankApiClient {
|
|
6
|
+
config;
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.config = getConfig(options.configDir);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get the base URL for the Tank API.
|
|
12
|
+
*/
|
|
13
|
+
get baseUrl() {
|
|
14
|
+
return this.config.registry;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get the auth token (if available).
|
|
18
|
+
*/
|
|
19
|
+
get token() {
|
|
20
|
+
return this.config.token;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if authenticated.
|
|
24
|
+
*/
|
|
25
|
+
get isAuthenticated() {
|
|
26
|
+
return !!this.config.token;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Make an authenticated API request.
|
|
30
|
+
*/
|
|
31
|
+
async fetch(path, options = {}) {
|
|
32
|
+
const url = `${this.baseUrl}${path}`;
|
|
33
|
+
const headers = {
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
...options.headers,
|
|
36
|
+
};
|
|
37
|
+
if (this.config.token) {
|
|
38
|
+
headers['Authorization'] = `Bearer ${this.config.token}`;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const response = await fetch(url, {
|
|
42
|
+
...options,
|
|
43
|
+
headers,
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
const body = await response.json().catch(() => ({}));
|
|
47
|
+
return {
|
|
48
|
+
error: body.error ?? response.statusText,
|
|
49
|
+
status: response.status,
|
|
50
|
+
ok: false,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const data = await response.json();
|
|
54
|
+
return { data, ok: true };
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
return {
|
|
58
|
+
error: err instanceof Error ? err.message : 'Network error',
|
|
59
|
+
status: 0,
|
|
60
|
+
ok: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Verify current auth token is valid.
|
|
66
|
+
*/
|
|
67
|
+
async verifyAuth() {
|
|
68
|
+
if (!this.config.token) {
|
|
69
|
+
return { valid: false };
|
|
70
|
+
}
|
|
71
|
+
const result = await this.fetch('/api/v1/auth/whoami');
|
|
72
|
+
if (result.ok) {
|
|
73
|
+
return { valid: true, user: result.data.user };
|
|
74
|
+
}
|
|
75
|
+
return { valid: false };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AAMzD;;GAEG;AACH,MAAM,OAAO,aAAa;IAChB,MAAM,CAAa;IAE3B,YAAY,UAA4B,EAAE;QACxC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,IAAI,eAAe;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CACT,IAAY,EACZ,UAAuB,EAAE;QAEzB,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QACrC,MAAM,OAAO,GAA2B;YACtC,cAAc,EAAE,kBAAkB;YAClC,GAAI,OAAO,CAAC,OAAkC;SAC/C,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC3D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,GAAG,OAAO;gBACV,OAAO;aACR,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACrD,OAAO;oBACL,KAAK,EAAG,IAA2B,CAAC,KAAK,IAAI,QAAQ,CAAC,UAAU;oBAChE,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,EAAE,EAAE,KAAK;iBACV,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAO,CAAC;YACxC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;gBAC3D,MAAM,EAAE,CAAC;gBACT,EAAE,EAAE,KAAK;aACV,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,qBAAqB,CACtB,CAAC;QAEF,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACjD,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface TankConfig {
|
|
2
|
+
token?: string;
|
|
3
|
+
user?: {
|
|
4
|
+
name: string;
|
|
5
|
+
email: string;
|
|
6
|
+
};
|
|
7
|
+
registry: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Get the path to the tank config directory.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getConfigDir(configDir?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get the path to the tank config file.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getConfigPath(configDir?: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Read the tank config file. Returns defaults if file doesn't exist.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getConfig(configDir?: string): TankConfig;
|
|
21
|
+
/**
|
|
22
|
+
* Write config to disk. Merges with existing config.
|
|
23
|
+
*/
|
|
24
|
+
export declare function setConfig(partial: Partial<TankConfig>, configDir?: string): void;
|
|
25
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAoBxD;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CAeN"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
registry: 'https://tankpkg.dev',
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Get the path to the tank config directory.
|
|
9
|
+
*/
|
|
10
|
+
export function getConfigDir(configDir) {
|
|
11
|
+
return configDir ?? path.join(os.homedir(), '.tank');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get the path to the tank config file.
|
|
15
|
+
*/
|
|
16
|
+
export function getConfigPath(configDir) {
|
|
17
|
+
return path.join(getConfigDir(configDir), 'config.json');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read the tank config file. Returns defaults if file doesn't exist.
|
|
21
|
+
*/
|
|
22
|
+
export function getConfig(configDir) {
|
|
23
|
+
const configPath = getConfigPath(configDir);
|
|
24
|
+
try {
|
|
25
|
+
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
26
|
+
const parsed = JSON.parse(raw);
|
|
27
|
+
const merged = { ...DEFAULT_CONFIG, ...parsed };
|
|
28
|
+
// TANK_TOKEN env var takes priority
|
|
29
|
+
const envToken = process.env.TANK_TOKEN?.trim();
|
|
30
|
+
if (envToken) {
|
|
31
|
+
merged.token = envToken;
|
|
32
|
+
}
|
|
33
|
+
return merged;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
const envToken = process.env.TANK_TOKEN?.trim();
|
|
37
|
+
return {
|
|
38
|
+
...DEFAULT_CONFIG,
|
|
39
|
+
...(envToken ? { token: envToken } : {}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Write config to disk. Merges with existing config.
|
|
45
|
+
*/
|
|
46
|
+
export function setConfig(partial, configDir) {
|
|
47
|
+
const dir = getConfigDir(configDir);
|
|
48
|
+
const configPath = getConfigPath(configDir);
|
|
49
|
+
if (!fs.existsSync(dir)) {
|
|
50
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
51
|
+
}
|
|
52
|
+
const existing = getConfig(configDir);
|
|
53
|
+
const merged = { ...existing, ...partial };
|
|
54
|
+
fs.writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\n', {
|
|
55
|
+
encoding: 'utf-8',
|
|
56
|
+
mode: 0o600,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAQzB,MAAM,cAAc,GAAe;IACjC,QAAQ,EAAE,qBAAqB;CAChC,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,SAAkB;IAC7C,OAAO,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAkB;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,SAAkB;IAC1C,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAE5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;QACtD,MAAM,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;QAChD,oCAAoC;QACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;QAChD,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC;QAC1B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;QAChD,OAAO;YACL,GAAG,cAAc;YACjB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CACvB,OAA4B,EAC5B,SAAkB;IAElB,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAE5C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;IAE3C,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE;QACnE,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PackResult {
|
|
2
|
+
tarball: Buffer;
|
|
3
|
+
integrity: string;
|
|
4
|
+
fileCount: number;
|
|
5
|
+
totalSize: number;
|
|
6
|
+
readme: string;
|
|
7
|
+
files: string[];
|
|
8
|
+
manifest: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Pack a skill directory into a .tgz tarball with integrity hashing.
|
|
12
|
+
*/
|
|
13
|
+
export declare function pack(directory: string): Promise<PackResult>;
|
|
14
|
+
//# sourceMappingURL=packer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packer.d.ts","sourceRoot":"","sources":["../../src/lib/packer.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,wBAAsB,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAkGjE"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import { create } from 'tar';
|
|
5
|
+
import ignore from 'ignore';
|
|
6
|
+
import { skillsJsonSchema } from '@tank/shared';
|
|
7
|
+
// Limits
|
|
8
|
+
const MAX_PACKAGE_SIZE = 50 * 1024 * 1024; // 50MB
|
|
9
|
+
const MAX_FILE_COUNT = 1000;
|
|
10
|
+
// Default ignore patterns
|
|
11
|
+
const DEFAULT_IGNORES = [
|
|
12
|
+
'node_modules',
|
|
13
|
+
'.git',
|
|
14
|
+
'.env*',
|
|
15
|
+
'*.log',
|
|
16
|
+
'.tank',
|
|
17
|
+
'.DS_Store',
|
|
18
|
+
];
|
|
19
|
+
// Always ignored regardless of ignore file contents
|
|
20
|
+
const ALWAYS_IGNORED = ['node_modules', '.git'];
|
|
21
|
+
// Ignore file names (not packed into tarball)
|
|
22
|
+
const IGNORE_FILES = ['.tankignore', '.gitignore'];
|
|
23
|
+
/**
|
|
24
|
+
* Pack a skill directory into a .tgz tarball with integrity hashing.
|
|
25
|
+
*/
|
|
26
|
+
export async function pack(directory) {
|
|
27
|
+
const absDir = path.resolve(directory);
|
|
28
|
+
// 1. Verify directory exists
|
|
29
|
+
if (!fs.existsSync(absDir)) {
|
|
30
|
+
throw new Error(`Directory does not exist: ${absDir}`);
|
|
31
|
+
}
|
|
32
|
+
const stat = fs.statSync(absDir);
|
|
33
|
+
if (!stat.isDirectory()) {
|
|
34
|
+
throw new Error(`Not a directory: ${absDir}`);
|
|
35
|
+
}
|
|
36
|
+
// 2. Verify skills.json exists and is valid
|
|
37
|
+
const skillsJsonPath = path.join(absDir, 'skills.json');
|
|
38
|
+
if (!fs.existsSync(skillsJsonPath)) {
|
|
39
|
+
throw new Error('Missing required file: skills.json');
|
|
40
|
+
}
|
|
41
|
+
let skillsJsonContent;
|
|
42
|
+
try {
|
|
43
|
+
skillsJsonContent = fs.readFileSync(skillsJsonPath, 'utf-8');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new Error('Failed to read skills.json');
|
|
47
|
+
}
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(skillsJsonContent);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new Error('Invalid skills.json: not valid JSON');
|
|
54
|
+
}
|
|
55
|
+
const validation = skillsJsonSchema.safeParse(parsed);
|
|
56
|
+
if (!validation.success) {
|
|
57
|
+
const issues = validation.error.issues
|
|
58
|
+
.map((i) => ` - ${i.path.join('.')}: ${i.message}`)
|
|
59
|
+
.join('\n');
|
|
60
|
+
throw new Error(`Invalid skills.json:\n${issues}`);
|
|
61
|
+
}
|
|
62
|
+
// 3. Verify SKILL.md exists and read its content
|
|
63
|
+
const skillMdPath = path.join(absDir, 'SKILL.md');
|
|
64
|
+
if (!fs.existsSync(skillMdPath)) {
|
|
65
|
+
throw new Error('Missing required file: SKILL.md');
|
|
66
|
+
}
|
|
67
|
+
let readmeContent;
|
|
68
|
+
try {
|
|
69
|
+
readmeContent = fs.readFileSync(skillMdPath, 'utf-8');
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw new Error('Failed to read SKILL.md');
|
|
73
|
+
}
|
|
74
|
+
// 4. Build ignore filter
|
|
75
|
+
const ig = buildIgnoreFilter(absDir);
|
|
76
|
+
// 5. Collect files with validation
|
|
77
|
+
const files = collectFiles(absDir, absDir, ig);
|
|
78
|
+
// 6. Enforce file count limit
|
|
79
|
+
if (files.length > MAX_FILE_COUNT) {
|
|
80
|
+
throw new Error(`Too many files: ${files.length} exceeds maximum of ${MAX_FILE_COUNT}`);
|
|
81
|
+
}
|
|
82
|
+
// 7. Calculate total size of source files
|
|
83
|
+
let totalSize = 0;
|
|
84
|
+
for (const file of files) {
|
|
85
|
+
const filePath = path.join(absDir, file);
|
|
86
|
+
const fileStat = fs.statSync(filePath);
|
|
87
|
+
totalSize += fileStat.size;
|
|
88
|
+
}
|
|
89
|
+
// 8. Create tarball
|
|
90
|
+
const tarball = await createTarball(absDir, files);
|
|
91
|
+
// 9. Enforce tarball size limit
|
|
92
|
+
if (tarball.length > MAX_PACKAGE_SIZE) {
|
|
93
|
+
throw new Error(`Tarball too large: ${tarball.length} bytes exceeds maximum of ${MAX_PACKAGE_SIZE} bytes (50MB)`);
|
|
94
|
+
}
|
|
95
|
+
// 10. Compute integrity hash
|
|
96
|
+
const hash = crypto.createHash('sha512').update(tarball).digest('base64');
|
|
97
|
+
const integrity = `sha512-${hash}`;
|
|
98
|
+
return {
|
|
99
|
+
tarball,
|
|
100
|
+
integrity,
|
|
101
|
+
fileCount: files.length,
|
|
102
|
+
totalSize,
|
|
103
|
+
readme: readmeContent,
|
|
104
|
+
files,
|
|
105
|
+
manifest: validation.data,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Build an ignore filter from .tankignore, .gitignore, or defaults.
|
|
110
|
+
*/
|
|
111
|
+
function buildIgnoreFilter(dir) {
|
|
112
|
+
const ig = ignore();
|
|
113
|
+
ig.add(ALWAYS_IGNORED);
|
|
114
|
+
const tankIgnorePath = path.join(dir, '.tankignore');
|
|
115
|
+
const gitIgnorePath = path.join(dir, '.gitignore');
|
|
116
|
+
if (fs.existsSync(tankIgnorePath)) {
|
|
117
|
+
const content = fs.readFileSync(tankIgnorePath, 'utf-8');
|
|
118
|
+
ig.add(content);
|
|
119
|
+
ig.add(IGNORE_FILES);
|
|
120
|
+
}
|
|
121
|
+
else if (fs.existsSync(gitIgnorePath)) {
|
|
122
|
+
const content = fs.readFileSync(gitIgnorePath, 'utf-8');
|
|
123
|
+
ig.add(content);
|
|
124
|
+
ig.add(IGNORE_FILES);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
ig.add(DEFAULT_IGNORES);
|
|
128
|
+
}
|
|
129
|
+
return ig;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Recursively collect files from a directory.
|
|
133
|
+
*/
|
|
134
|
+
function collectFiles(baseDir, currentDir, ig) {
|
|
135
|
+
const files = [];
|
|
136
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
137
|
+
for (const entry of entries) {
|
|
138
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
139
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
140
|
+
// Security: check for path traversal
|
|
141
|
+
if (relativePath.split(path.sep).includes('..')) {
|
|
142
|
+
throw new Error(`Path traversal detected: "${relativePath}" contains ".." component`);
|
|
143
|
+
}
|
|
144
|
+
// Security: check for absolute paths
|
|
145
|
+
if (path.isAbsolute(relativePath)) {
|
|
146
|
+
throw new Error(`Absolute path detected: "${relativePath}"`);
|
|
147
|
+
}
|
|
148
|
+
// Security: check for symlinks
|
|
149
|
+
const lstatResult = fs.lstatSync(fullPath);
|
|
150
|
+
if (lstatResult.isSymbolicLink()) {
|
|
151
|
+
throw new Error(`Symlink detected: "${relativePath}" — symlinks are not allowed`);
|
|
152
|
+
}
|
|
153
|
+
const pathForIgnore = lstatResult.isDirectory()
|
|
154
|
+
? relativePath + '/'
|
|
155
|
+
: relativePath;
|
|
156
|
+
if (ig.ignores(pathForIgnore)) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (lstatResult.isDirectory()) {
|
|
160
|
+
const subFiles = collectFiles(baseDir, fullPath, ig);
|
|
161
|
+
files.push(...subFiles);
|
|
162
|
+
}
|
|
163
|
+
else if (lstatResult.isFile()) {
|
|
164
|
+
files.push(relativePath);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return files;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Create a gzipped tarball from the given files.
|
|
171
|
+
*/
|
|
172
|
+
async function createTarball(cwd, files) {
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
174
|
+
const chunks = [];
|
|
175
|
+
const stream = create({
|
|
176
|
+
gzip: true,
|
|
177
|
+
cwd,
|
|
178
|
+
portable: true,
|
|
179
|
+
}, files);
|
|
180
|
+
stream.on('data', (chunk) => {
|
|
181
|
+
chunks.push(chunk);
|
|
182
|
+
});
|
|
183
|
+
stream.on('end', () => {
|
|
184
|
+
resolve(Buffer.concat(chunks));
|
|
185
|
+
});
|
|
186
|
+
stream.on('error', (err) => {
|
|
187
|
+
reject(err);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=packer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packer.js","sourceRoot":"","sources":["../../src/lib/packer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/tools/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwHzD"}
|