@tankpkg/cli 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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bin/tank.d.ts +2 -0
  3. package/dist/bin/tank.js +279 -0
  4. package/dist/bin/tank.js.map +1 -0
  5. package/dist/commands/audit.d.ts +5 -0
  6. package/dist/commands/audit.js +185 -0
  7. package/dist/commands/audit.js.map +1 -0
  8. package/dist/commands/doctor.d.ts +5 -0
  9. package/dist/commands/doctor.js +164 -0
  10. package/dist/commands/doctor.js.map +1 -0
  11. package/dist/commands/info.d.ts +5 -0
  12. package/dist/commands/info.js +102 -0
  13. package/dist/commands/info.js.map +1 -0
  14. package/dist/commands/init.d.ts +1 -0
  15. package/dist/commands/init.js +92 -0
  16. package/dist/commands/init.js.map +1 -0
  17. package/dist/commands/install.d.ts +39 -0
  18. package/dist/commands/install.js +550 -0
  19. package/dist/commands/install.js.map +1 -0
  20. package/dist/commands/link.d.ts +5 -0
  21. package/dist/commands/link.js +79 -0
  22. package/dist/commands/link.js.map +1 -0
  23. package/dist/commands/login.d.ts +14 -0
  24. package/dist/commands/login.js +87 -0
  25. package/dist/commands/login.js.map +1 -0
  26. package/dist/commands/logout.d.ts +9 -0
  27. package/dist/commands/logout.js +20 -0
  28. package/dist/commands/logout.js.map +1 -0
  29. package/dist/commands/permissions.d.ts +4 -0
  30. package/dist/commands/permissions.js +199 -0
  31. package/dist/commands/permissions.js.map +1 -0
  32. package/dist/commands/publish.d.ts +25 -0
  33. package/dist/commands/publish.js +166 -0
  34. package/dist/commands/publish.js.map +1 -0
  35. package/dist/commands/remove.d.ts +7 -0
  36. package/dist/commands/remove.js +163 -0
  37. package/dist/commands/remove.js.map +1 -0
  38. package/dist/commands/search.d.ts +5 -0
  39. package/dist/commands/search.js +67 -0
  40. package/dist/commands/search.js.map +1 -0
  41. package/dist/commands/unlink.d.ts +5 -0
  42. package/dist/commands/unlink.js +42 -0
  43. package/dist/commands/unlink.js.map +1 -0
  44. package/dist/commands/update.d.ts +8 -0
  45. package/dist/commands/update.js +337 -0
  46. package/dist/commands/update.js.map +1 -0
  47. package/dist/commands/upgrade.d.ts +6 -0
  48. package/dist/commands/upgrade.js +100 -0
  49. package/dist/commands/upgrade.js.map +1 -0
  50. package/dist/commands/verify.d.ts +22 -0
  51. package/dist/commands/verify.js +63 -0
  52. package/dist/commands/verify.js.map +1 -0
  53. package/dist/commands/whoami.d.ts +4 -0
  54. package/dist/commands/whoami.js +57 -0
  55. package/dist/commands/whoami.js.map +1 -0
  56. package/dist/index.d.ts +5 -0
  57. package/dist/index.js +5 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/lib/agents.d.ts +19 -0
  60. package/dist/lib/agents.js +84 -0
  61. package/dist/lib/agents.js.map +1 -0
  62. package/dist/lib/api-client.d.ts +14 -0
  63. package/dist/lib/api-client.js +63 -0
  64. package/dist/lib/api-client.js.map +1 -0
  65. package/dist/lib/config.d.ts +29 -0
  66. package/dist/lib/config.js +66 -0
  67. package/dist/lib/config.js.map +1 -0
  68. package/dist/lib/debug-logger.d.ts +9 -0
  69. package/dist/lib/debug-logger.js +77 -0
  70. package/dist/lib/debug-logger.js.map +1 -0
  71. package/dist/lib/frontmatter.d.ts +11 -0
  72. package/dist/lib/frontmatter.js +89 -0
  73. package/dist/lib/frontmatter.js.map +1 -0
  74. package/dist/lib/linker.d.ts +45 -0
  75. package/dist/lib/linker.js +137 -0
  76. package/dist/lib/linker.js.map +1 -0
  77. package/dist/lib/links.d.ts +20 -0
  78. package/dist/lib/links.js +105 -0
  79. package/dist/lib/links.js.map +1 -0
  80. package/dist/lib/lockfile.d.ts +24 -0
  81. package/dist/lib/lockfile.js +135 -0
  82. package/dist/lib/lockfile.js.map +1 -0
  83. package/dist/lib/logger.d.ts +6 -0
  84. package/dist/lib/logger.js +8 -0
  85. package/dist/lib/logger.js.map +1 -0
  86. package/dist/lib/packer.d.ts +21 -0
  87. package/dist/lib/packer.js +210 -0
  88. package/dist/lib/packer.js.map +1 -0
  89. package/dist/lib/upgrade-check.d.ts +1 -0
  90. package/dist/lib/upgrade-check.js +52 -0
  91. package/dist/lib/upgrade-check.js.map +1 -0
  92. package/dist/version.d.ts +2 -0
  93. package/dist/version.js +4 -0
  94. package/dist/version.js.map +1 -0
  95. package/package.json +40 -0
@@ -0,0 +1,135 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * Read and parse the lockfile from the given directory.
5
+ * Returns null if the file doesn't exist or is corrupt.
6
+ */
7
+ export function readLockfile(directory) {
8
+ const dir = directory ?? process.cwd();
9
+ const lockPath = path.join(dir, 'skills.lock');
10
+ if (!fs.existsSync(lockPath)) {
11
+ return null;
12
+ }
13
+ try {
14
+ const raw = fs.readFileSync(lockPath, 'utf-8');
15
+ return JSON.parse(raw);
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ /**
22
+ * Write a lockfile deterministically: sorted keys, consistent formatting, trailing newline.
23
+ */
24
+ export function writeLockfile(lock, directory) {
25
+ const dir = directory ?? process.cwd();
26
+ const lockPath = path.join(dir, 'skills.lock');
27
+ // Sort skill keys alphabetically for determinism
28
+ const sortedSkills = {};
29
+ for (const key of Object.keys(lock.skills).sort()) {
30
+ sortedSkills[key] = lock.skills[key];
31
+ }
32
+ const output = {
33
+ lockfileVersion: lock.lockfileVersion,
34
+ skills: sortedSkills,
35
+ };
36
+ fs.writeFileSync(lockPath, JSON.stringify(output, null, 2) + '\n');
37
+ }
38
+ /**
39
+ * Compute the union of all skill permissions from a lockfile.
40
+ * Merges network outbound, filesystem read/write (deduped), and subprocess (OR).
41
+ */
42
+ export function computeResolvedPermissions(lock) {
43
+ const entries = Object.values(lock.skills);
44
+ if (entries.length === 0) {
45
+ return {};
46
+ }
47
+ const outbound = new Set();
48
+ const fsRead = new Set();
49
+ const fsWrite = new Set();
50
+ let subprocess = false;
51
+ for (const entry of entries) {
52
+ const perms = entry.permissions;
53
+ if (perms.network?.outbound) {
54
+ for (const domain of perms.network.outbound) {
55
+ outbound.add(domain);
56
+ }
57
+ }
58
+ if (perms.filesystem?.read) {
59
+ for (const pattern of perms.filesystem.read) {
60
+ fsRead.add(pattern);
61
+ }
62
+ }
63
+ if (perms.filesystem?.write) {
64
+ for (const pattern of perms.filesystem.write) {
65
+ fsWrite.add(pattern);
66
+ }
67
+ }
68
+ if (perms.subprocess === true) {
69
+ subprocess = true;
70
+ }
71
+ }
72
+ const result = {};
73
+ if (outbound.size > 0) {
74
+ result.network = { outbound: [...outbound].sort() };
75
+ }
76
+ if (fsRead.size > 0 || fsWrite.size > 0) {
77
+ result.filesystem = {};
78
+ if (fsRead.size > 0) {
79
+ result.filesystem.read = [...fsRead].sort();
80
+ }
81
+ if (fsWrite.size > 0) {
82
+ result.filesystem.write = [...fsWrite].sort();
83
+ }
84
+ }
85
+ if (subprocess) {
86
+ result.subprocess = true;
87
+ }
88
+ return result;
89
+ }
90
+ /**
91
+ * Check if resolved permissions fit within the project's permission budget.
92
+ *
93
+ * Returns:
94
+ * - 'pass' if all resolved permissions are within budget
95
+ * - 'fail' if any resolved permission exceeds budget
96
+ * - 'no_budget' if no project permissions are defined
97
+ */
98
+ export function computeBudgetCheck(resolvedPermissions, projectPermissions) {
99
+ if (projectPermissions === undefined) {
100
+ return 'no_budget';
101
+ }
102
+ // Check subprocess
103
+ if (resolvedPermissions.subprocess === true && projectPermissions.subprocess === false) {
104
+ return 'fail';
105
+ }
106
+ // Check network outbound
107
+ if (resolvedPermissions.network?.outbound) {
108
+ const budgetOutbound = new Set(projectPermissions.network?.outbound ?? []);
109
+ for (const domain of resolvedPermissions.network.outbound) {
110
+ if (!budgetOutbound.has(domain)) {
111
+ return 'fail';
112
+ }
113
+ }
114
+ }
115
+ // Check filesystem read
116
+ if (resolvedPermissions.filesystem?.read) {
117
+ const budgetRead = new Set(projectPermissions.filesystem?.read ?? []);
118
+ for (const pattern of resolvedPermissions.filesystem.read) {
119
+ if (!budgetRead.has(pattern)) {
120
+ return 'fail';
121
+ }
122
+ }
123
+ }
124
+ // Check filesystem write
125
+ if (resolvedPermissions.filesystem?.write) {
126
+ const budgetWrite = new Set(projectPermissions.filesystem?.write ?? []);
127
+ for (const pattern of resolvedPermissions.filesystem.write) {
128
+ if (!budgetWrite.has(pattern)) {
129
+ return 'fail';
130
+ }
131
+ }
132
+ }
133
+ return 'pass';
134
+ }
135
+ //# sourceMappingURL=lockfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../../src/lib/lockfile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const logger: {
2
+ info: (msg: string) => void;
3
+ success: (msg: string) => void;
4
+ warn: (msg: string) => void;
5
+ error: (msg: string) => void;
6
+ };
@@ -0,0 +1,8 @@
1
+ import chalk from 'chalk';
2
+ export const logger = {
3
+ info: (msg) => console.log(chalk.blue('ℹ'), msg),
4
+ success: (msg) => console.log(chalk.green('✓'), msg),
5
+ warn: (msg) => console.log(chalk.yellow('⚠'), msg),
6
+ error: (msg) => console.error(chalk.red('✗'), msg),
7
+ };
8
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACxD,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC5D,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC1D,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;CAC3D,CAAC"}
@@ -0,0 +1,21 @@
1
+ export interface PackResult {
2
+ tarball: Buffer;
3
+ integrity: string;
4
+ fileCount: number;
5
+ totalSize: number;
6
+ readme: string;
7
+ files: string[];
8
+ }
9
+ /**
10
+ * Pack a skill directory into a .tgz tarball with integrity hashing.
11
+ *
12
+ * Validates:
13
+ * - skills.json exists and is valid
14
+ * - SKILL.md exists
15
+ * - No symlinks or hardlinks
16
+ * - No path traversal (.. components)
17
+ * - No absolute paths
18
+ * - File count <= 1000
19
+ * - Tarball size <= 50MB
20
+ */
21
+ export declare function pack(directory: string): Promise<PackResult>;
@@ -0,0 +1,210 @@
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 (used when no .tankignore or .gitignore exists)
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 = [
21
+ 'node_modules',
22
+ '.git',
23
+ ];
24
+ // Ignore file names (not packed into tarball)
25
+ const IGNORE_FILES = ['.tankignore', '.gitignore'];
26
+ /**
27
+ * Pack a skill directory into a .tgz tarball with integrity hashing.
28
+ *
29
+ * Validates:
30
+ * - skills.json exists and is valid
31
+ * - SKILL.md exists
32
+ * - No symlinks or hardlinks
33
+ * - No path traversal (.. components)
34
+ * - No absolute paths
35
+ * - File count <= 1000
36
+ * - Tarball size <= 50MB
37
+ */
38
+ export async function pack(directory) {
39
+ const absDir = path.resolve(directory);
40
+ // 1. Verify directory exists
41
+ if (!fs.existsSync(absDir)) {
42
+ throw new Error(`Directory does not exist: ${absDir}`);
43
+ }
44
+ const stat = fs.statSync(absDir);
45
+ if (!stat.isDirectory()) {
46
+ throw new Error(`Not a directory: ${absDir}`);
47
+ }
48
+ // 2. Verify skills.json exists and is valid
49
+ const skillsJsonPath = path.join(absDir, 'skills.json');
50
+ if (!fs.existsSync(skillsJsonPath)) {
51
+ throw new Error('Missing required file: skills.json');
52
+ }
53
+ let skillsJsonContent;
54
+ try {
55
+ skillsJsonContent = fs.readFileSync(skillsJsonPath, 'utf-8');
56
+ }
57
+ catch {
58
+ throw new Error('Failed to read skills.json');
59
+ }
60
+ let parsed;
61
+ try {
62
+ parsed = JSON.parse(skillsJsonContent);
63
+ }
64
+ catch {
65
+ throw new Error('Invalid skills.json: not valid JSON');
66
+ }
67
+ const validation = skillsJsonSchema.safeParse(parsed);
68
+ if (!validation.success) {
69
+ const issues = validation.error.issues
70
+ .map((i) => ` - ${i.path.join('.')}: ${i.message}`)
71
+ .join('\n');
72
+ throw new Error(`Invalid skills.json:\n${issues}`);
73
+ }
74
+ // 3. Verify SKILL.md exists and read its content
75
+ const skillMdPath = path.join(absDir, 'SKILL.md');
76
+ if (!fs.existsSync(skillMdPath)) {
77
+ throw new Error('Missing required file: SKILL.md');
78
+ }
79
+ let readmeContent;
80
+ try {
81
+ readmeContent = fs.readFileSync(skillMdPath, 'utf-8');
82
+ }
83
+ catch {
84
+ throw new Error('Failed to read SKILL.md');
85
+ }
86
+ // 4. Build ignore filter
87
+ const ig = buildIgnoreFilter(absDir);
88
+ // 5. Collect files with validation
89
+ const files = collectFiles(absDir, absDir, ig);
90
+ // 6. Enforce file count limit
91
+ if (files.length > MAX_FILE_COUNT) {
92
+ throw new Error(`Too many files: ${files.length} exceeds maximum of ${MAX_FILE_COUNT}`);
93
+ }
94
+ // 7. Calculate total size of source files
95
+ let totalSize = 0;
96
+ for (const file of files) {
97
+ const filePath = path.join(absDir, file);
98
+ const fileStat = fs.statSync(filePath);
99
+ totalSize += fileStat.size;
100
+ }
101
+ // 8. Create tarball
102
+ const tarball = await createTarball(absDir, files);
103
+ // 9. Enforce tarball size limit
104
+ if (tarball.length > MAX_PACKAGE_SIZE) {
105
+ throw new Error(`Tarball too large: ${tarball.length} bytes exceeds maximum of ${MAX_PACKAGE_SIZE} bytes (50MB)`);
106
+ }
107
+ // 10. Compute integrity hash
108
+ const hash = crypto.createHash('sha512').update(tarball).digest('base64');
109
+ const integrity = `sha512-${hash}`;
110
+ return {
111
+ tarball,
112
+ integrity,
113
+ fileCount: files.length,
114
+ totalSize,
115
+ readme: readmeContent,
116
+ files,
117
+ };
118
+ }
119
+ /**
120
+ * Build an ignore filter from .tankignore, .gitignore, or defaults.
121
+ */
122
+ function buildIgnoreFilter(dir) {
123
+ const ig = ignore();
124
+ // Always add the forced ignores
125
+ ig.add(ALWAYS_IGNORED);
126
+ // Check for .tankignore first, then .gitignore, then defaults
127
+ const tankIgnorePath = path.join(dir, '.tankignore');
128
+ const gitIgnorePath = path.join(dir, '.gitignore');
129
+ if (fs.existsSync(tankIgnorePath)) {
130
+ const content = fs.readFileSync(tankIgnorePath, 'utf-8');
131
+ ig.add(content);
132
+ // Also ignore the ignore files themselves
133
+ ig.add(IGNORE_FILES);
134
+ }
135
+ else if (fs.existsSync(gitIgnorePath)) {
136
+ const content = fs.readFileSync(gitIgnorePath, 'utf-8');
137
+ ig.add(content);
138
+ ig.add(IGNORE_FILES);
139
+ }
140
+ else {
141
+ ig.add(DEFAULT_IGNORES);
142
+ }
143
+ return ig;
144
+ }
145
+ /**
146
+ * Recursively collect files from a directory, applying ignore rules and security checks.
147
+ */
148
+ function collectFiles(baseDir, currentDir, ig) {
149
+ const files = [];
150
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
151
+ for (const entry of entries) {
152
+ const fullPath = path.join(currentDir, entry.name);
153
+ const relativePath = path.relative(baseDir, fullPath);
154
+ // Security: check for path traversal
155
+ if (relativePath.split(path.sep).includes('..')) {
156
+ throw new Error(`Path traversal detected: "${relativePath}" contains ".." component`);
157
+ }
158
+ // Security: check for absolute paths
159
+ if (path.isAbsolute(relativePath)) {
160
+ throw new Error(`Absolute path detected: "${relativePath}"`);
161
+ }
162
+ // Security: check for symlinks using lstat (not stat which follows symlinks)
163
+ const lstatResult = fs.lstatSync(fullPath);
164
+ if (lstatResult.isSymbolicLink()) {
165
+ throw new Error(`Symlink detected: "${relativePath}" — symlinks are not allowed in skill packages`);
166
+ }
167
+ // Check if this path should be ignored
168
+ // For directories, append '/' so ignore patterns like 'dir/' work correctly
169
+ const pathForIgnore = lstatResult.isDirectory()
170
+ ? relativePath + '/'
171
+ : relativePath;
172
+ if (ig.ignores(pathForIgnore)) {
173
+ continue;
174
+ }
175
+ if (lstatResult.isDirectory()) {
176
+ // Recurse into subdirectory
177
+ const subFiles = collectFiles(baseDir, fullPath, ig);
178
+ files.push(...subFiles);
179
+ }
180
+ else if (lstatResult.isFile()) {
181
+ files.push(relativePath);
182
+ }
183
+ // Skip other types (block devices, character devices, FIFOs, sockets)
184
+ }
185
+ return files;
186
+ }
187
+ /**
188
+ * Create a gzipped tarball from the given files in the directory.
189
+ */
190
+ async function createTarball(cwd, files) {
191
+ return new Promise((resolve, reject) => {
192
+ const chunks = [];
193
+ // tar.create without `file` returns a readable stream
194
+ const stream = create({
195
+ gzip: true,
196
+ cwd,
197
+ portable: true, // Omit system-specific metadata
198
+ }, files);
199
+ stream.on('data', (chunk) => {
200
+ chunks.push(chunk);
201
+ });
202
+ stream.on('end', () => {
203
+ resolve(Buffer.concat(chunks));
204
+ });
205
+ stream.on('error', (err) => {
206
+ reject(err);
207
+ });
208
+ });
209
+ }
210
+ //# 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
+ export declare function checkForUpgrade(configDir?: string): Promise<void>;
@@ -0,0 +1,52 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { getConfigDir } from './config.js';
5
+ import { VERSION } from '../version.js';
6
+ export async function checkForUpgrade(configDir) {
7
+ try {
8
+ if (process.env.TANK_NO_UPDATE_CHECK || process.env.CI) {
9
+ return;
10
+ }
11
+ const cacheDir = getConfigDir(configDir);
12
+ const cachePath = path.join(cacheDir, 'upgrade_check.json');
13
+ let cache = null;
14
+ try {
15
+ const raw = fs.readFileSync(cachePath, 'utf-8');
16
+ cache = JSON.parse(raw);
17
+ }
18
+ catch {
19
+ // File doesn't exist or invalid JSON — treat as stale
20
+ }
21
+ const isFresh = cache !== null && (Date.now() - cache.lastCheck) < 24 * 60 * 60 * 1000;
22
+ if (isFresh && cache !== null) {
23
+ if (cache.latestVersion !== VERSION) {
24
+ console.error(`\n ${chalk.cyan('ℹ')} New version available: ${chalk.gray(VERSION)} → ${chalk.green(cache.latestVersion)}`);
25
+ console.error(` Run ${chalk.cyan('`tank upgrade`')} to update.\n`);
26
+ }
27
+ return;
28
+ }
29
+ const res = await fetch('https://api.github.com/repos/tankpkg/tank/releases/latest', {
30
+ headers: { 'User-Agent': `tank-cli/${VERSION}` },
31
+ signal: AbortSignal.timeout(3000),
32
+ });
33
+ if (!res.ok) {
34
+ return;
35
+ }
36
+ const data = (await res.json());
37
+ const latestVersion = data.tag_name.replace(/^v/, '');
38
+ if (!fs.existsSync(cacheDir)) {
39
+ fs.mkdirSync(cacheDir, { recursive: true });
40
+ }
41
+ const newCache = { lastCheck: Date.now(), latestVersion };
42
+ fs.writeFileSync(cachePath, JSON.stringify(newCache, null, 2) + '\n');
43
+ if (latestVersion !== VERSION) {
44
+ console.error(`\n ${chalk.cyan('ℹ')} New version available: ${chalk.gray(VERSION)} → ${chalk.green(latestVersion)}`);
45
+ console.error(` Run ${chalk.cyan('`tank upgrade`')} to update.\n`);
46
+ }
47
+ }
48
+ catch {
49
+ // Silently swallow ALL errors — background check must never cause CLI to fail
50
+ }
51
+ }
52
+ //# sourceMappingURL=upgrade-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade-check.js","sourceRoot":"","sources":["../../src/lib/upgrade-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const VERSION: string;
2
+ export declare const USER_AGENT: string;
@@ -0,0 +1,4 @@
1
+ import pkg from '../package.json' with { type: 'json' };
2
+ export const VERSION = pkg.version ?? '0.0.0';
3
+ export const USER_AGENT = `tank-cli/${VERSION}`;
4
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAExD,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;AAC9C,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,OAAO,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@tankpkg/cli",
3
+ "version": "0.4.2",
4
+ "description": "Security-first package manager for AI agent skills",
5
+ "type": "module",
6
+ "bin": {
7
+ "tank": "dist/bin/tank.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "devDependencies": {
16
+ "@types/node": "^22.19.11",
17
+ "@types/tar": "^6.1.13",
18
+ "esbuild": "^0.25.9",
19
+ "vitest": "^3"
20
+ },
21
+ "dependencies": {
22
+ "@inquirer/prompts": "^8.2.0",
23
+ "chalk": "^5.6.2",
24
+ "commander": "^14.0.3",
25
+ "ignore": "^7.0.5",
26
+ "open": "^11.0.0",
27
+ "ora": "^9.3.0",
28
+ "pino": "^10.3.1",
29
+ "pino-loki": "^3.0.0",
30
+ "tar": "^7.5.8",
31
+ "@tank/shared": "0.1.0"
32
+ },
33
+ "scripts": {
34
+ "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc",
35
+ "build:bundle": "esbuild dist/bin/tank.js --bundle --platform=node --format=esm --outfile=build/tank-bundle.mjs --external:fsevents",
36
+ "build:sea": "bash scripts/build-binary.sh",
37
+ "build:binary": "pnpm run build && pnpm run build:bundle && pnpm run build:sea",
38
+ "test": "vitest run"
39
+ }
40
+ }