@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 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/commands/link.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface LoginOptions {
2
+ configDir?: string;
3
+ timeout?: number;
4
+ pollInterval?: number;
5
+ }
6
+ /**
7
+ * Start the CLI login flow:
8
+ * 1. Generate random state
9
+ * 2. POST /api/v1/cli-auth/start → get authUrl + sessionCode
10
+ * 3. Open browser to authUrl
11
+ * 4. Poll POST /api/v1/cli-auth/exchange until authorized or timeout
12
+ * 5. Write token + user to config
13
+ */
14
+ export declare function loginCommand(options?: LoginOptions): Promise<void>;
@@ -0,0 +1,87 @@
1
+ import open from 'open';
2
+ import { getConfig, setConfig } from '../lib/config.js';
3
+ import { logger } from '../lib/logger.js';
4
+ import { authFlowLog } from '../lib/debug-logger.js';
5
+ const DEFAULT_POLL_INTERVAL_MS = 2000;
6
+ const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
7
+ /**
8
+ * Start the CLI login flow:
9
+ * 1. Generate random state
10
+ * 2. POST /api/v1/cli-auth/start → get authUrl + sessionCode
11
+ * 3. Open browser to authUrl
12
+ * 4. Poll POST /api/v1/cli-auth/exchange until authorized or timeout
13
+ * 5. Write token + user to config
14
+ */
15
+ export async function loginCommand(options = {}) {
16
+ const { configDir, timeout = DEFAULT_TIMEOUT_MS, pollInterval = DEFAULT_POLL_INTERVAL_MS, } = options;
17
+ const config = getConfig(configDir);
18
+ const baseUrl = config.registry;
19
+ // Step 1: Generate random state for CSRF protection
20
+ const state = crypto.randomUUID();
21
+ authFlowLog.info({ state: state.slice(0, 8) + '...' }, 'Login flow started');
22
+ // Step 2: Start auth session
23
+ logger.info('Starting login...');
24
+ const startRes = await fetch(`${baseUrl}/api/v1/cli-auth/start`, {
25
+ method: 'POST',
26
+ headers: { 'Content-Type': 'application/json' },
27
+ body: JSON.stringify({ state }),
28
+ });
29
+ if (!startRes.ok) {
30
+ const body = await startRes.json().catch(() => ({}));
31
+ authFlowLog.error({ status: startRes.status, error: body.error }, 'Start request failed');
32
+ throw new Error(`Failed to start auth session: ${body.error ?? startRes.statusText}`);
33
+ }
34
+ authFlowLog.info({ ok: startRes.ok, status: startRes.status }, 'Start response received');
35
+ const { authUrl, sessionCode } = (await startRes.json());
36
+ authFlowLog.info({ authUrl, sessionCode: sessionCode.slice(0, 8) + '...' }, 'Session created, opening browser');
37
+ // Step 3: Open browser
38
+ try {
39
+ await open(authUrl);
40
+ logger.info('Opened browser for authentication.');
41
+ }
42
+ catch {
43
+ // Browser failed to open — print URL for manual copy
44
+ logger.warn('Could not open browser automatically.');
45
+ logger.info(`Open this URL in your browser:\n ${authUrl}`);
46
+ }
47
+ logger.info('Waiting for authorization...');
48
+ // Step 4: Poll exchange endpoint
49
+ const deadline = Date.now() + timeout;
50
+ while (Date.now() < deadline) {
51
+ try {
52
+ const exchangeRes = await fetch(`${baseUrl}/api/v1/cli-auth/exchange`, {
53
+ method: 'POST',
54
+ headers: { 'Content-Type': 'application/json' },
55
+ body: JSON.stringify({ sessionCode, state }),
56
+ });
57
+ authFlowLog.debug({ status: exchangeRes.status, ok: exchangeRes.ok }, 'Exchange poll response');
58
+ if (exchangeRes.ok) {
59
+ const { token, user } = (await exchangeRes.json());
60
+ authFlowLog.info({ userName: user.name, userEmail: user.email }, 'Login successful, saving config');
61
+ // Step 5: Write to config
62
+ setConfig({ token, user: user }, configDir);
63
+ const displayName = user.name ?? user.email ?? 'unknown';
64
+ logger.success(`Logged in as ${displayName}`);
65
+ return;
66
+ }
67
+ // 400 means session not yet authorized — keep polling
68
+ // Any other error is unexpected
69
+ if (exchangeRes.status !== 400) {
70
+ const body = await exchangeRes.json().catch(() => ({}));
71
+ throw new Error(`Exchange failed: ${body.error ?? exchangeRes.statusText}`);
72
+ }
73
+ }
74
+ catch (err) {
75
+ authFlowLog.warn({ error: err instanceof Error ? err.message : String(err) }, 'Exchange poll error');
76
+ // If it's our own thrown error, re-throw
77
+ if (err instanceof Error && err.message.startsWith('Exchange failed:')) {
78
+ throw err;
79
+ }
80
+ // Network errors during polling are transient — keep trying
81
+ }
82
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
83
+ }
84
+ authFlowLog.error({}, 'Login timed out');
85
+ throw new Error('Login timed out. Please try again.');
86
+ }
87
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,wBAAwB,GAAG,IAAI,CAAC;AACtC,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAQtD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAwB,EAAE;IAC3D,MAAM,EACJ,SAAS,EACT,OAAO,GAAG,kBAAkB,EAC5B,YAAY,GAAG,wBAAwB,GACxC,GAAG,OAAO,CAAC;IACZ,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC;IAEhC,oDAAoD;IACpD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAClC,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAE7E,6BAA6B;IAC7B,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAEjC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,wBAAwB,EAAE;QAC/D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;KAChC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrD,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAG,IAA2B,CAAC,KAAK,EAAE,EAAE,sBAAsB,CAAC,CAAC;QAClH,MAAM,IAAI,KAAK,CACb,iCAAkC,IAA2B,CAAC,KAAK,IAAI,QAAQ,CAAC,UAAU,EAAE,CAC7F,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC;IAE1F,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAGtD,CAAC;IACF,WAAW,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,EAAE,EAAE,kCAAkC,CAAC,CAAC;IAEhH,uBAAuB;IACvB,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,qDAAqD;QACrD,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,qCAAqC,OAAO,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAE5C,iCAAiC;IACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;IAEtC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,2BAA2B,EAAE;gBACrE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;aAC7C,CAAC,CAAC;YACH,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,wBAAwB,CAAC,CAAC;YAEhG,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC;gBACnB,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,WAAW,CAAC,IAAI,EAAE,CAGhD,CAAC;gBAEF,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,iCAAiC,CAAC,CAAC;gBAEpG,0BAA0B;gBAC1B,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAuC,EAAE,EAAE,SAAS,CAAC,CAAC;gBAE/E,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;gBACzD,MAAM,CAAC,OAAO,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,sDAAsD;YACtD,gCAAgC;YAChC,IAAI,WAAW,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC/B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACxD,MAAM,IAAI,KAAK,CACb,oBAAqB,IAA2B,CAAC,KAAK,IAAI,WAAW,CAAC,UAAU,EAAE,CACnF,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC;YACrG,yCAAyC;YACzC,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACvE,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,4DAA4D;QAC9D,CAAC;QAED,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;IACzC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface LogoutOptions {
2
+ configDir?: string;
3
+ }
4
+ /**
5
+ * Logout command: Remove token and user from config.
6
+ * If not logged in, prints "Not logged in" and returns.
7
+ * If logged in, removes token and user, prints success message.
8
+ */
9
+ export declare function logoutCommand(options?: LogoutOptions): Promise<void>;
@@ -0,0 +1,20 @@
1
+ import { getConfig, setConfig } from '../lib/config.js';
2
+ import { logger } from '../lib/logger.js';
3
+ /**
4
+ * Logout command: Remove token and user from config.
5
+ * If not logged in, prints "Not logged in" and returns.
6
+ * If logged in, removes token and user, prints success message.
7
+ */
8
+ export async function logoutCommand(options = {}) {
9
+ const { configDir } = options;
10
+ const config = getConfig(configDir);
11
+ // Check if logged in
12
+ if (!config.token) {
13
+ logger.warn('Not logged in. Run: tank login');
14
+ return;
15
+ }
16
+ // Remove token and user from config
17
+ setConfig({ token: undefined, user: undefined }, configDir);
18
+ logger.success('Logged out');
19
+ }
20
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAM1C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAyB,EAAE;IAC7D,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC9B,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAEpC,qBAAqB;IACrB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,oCAAoC;IACpC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,CAAC,CAAC;IAE5D,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export interface PermissionsOptions {
2
+ directory?: string;
3
+ }
4
+ export declare function permissionsCommand(options?: PermissionsOptions): Promise<void>;
@@ -0,0 +1,199 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import chalk from 'chalk';
4
+ /**
5
+ * Parse a lockfile key like "@org/skill@1.0.0" into the skill name "@org/skill".
6
+ */
7
+ function parseSkillName(key) {
8
+ const lastAt = key.lastIndexOf('@');
9
+ // For scoped packages, lastIndexOf('@') finds the version separator
10
+ // e.g. "@org/skill@1.0.0" → lastAt = 10, name = "@org/skill"
11
+ if (lastAt > 0) {
12
+ return key.slice(0, lastAt);
13
+ }
14
+ return key;
15
+ }
16
+ function collectPermissions(lockfile) {
17
+ const networkMap = new Map();
18
+ const fsReadMap = new Map();
19
+ const fsWriteMap = new Map();
20
+ const subprocessSkills = [];
21
+ for (const [key, entry] of Object.entries(lockfile.skills)) {
22
+ const skillName = parseSkillName(key);
23
+ const perms = entry.permissions;
24
+ if (perms.network?.outbound) {
25
+ for (const domain of perms.network.outbound) {
26
+ const existing = networkMap.get(domain) ?? [];
27
+ existing.push(skillName);
28
+ networkMap.set(domain, existing);
29
+ }
30
+ }
31
+ if (perms.filesystem?.read) {
32
+ for (const p of perms.filesystem.read) {
33
+ const existing = fsReadMap.get(p) ?? [];
34
+ existing.push(skillName);
35
+ fsReadMap.set(p, existing);
36
+ }
37
+ }
38
+ if (perms.filesystem?.write) {
39
+ for (const p of perms.filesystem.write) {
40
+ const existing = fsWriteMap.get(p) ?? [];
41
+ existing.push(skillName);
42
+ fsWriteMap.set(p, existing);
43
+ }
44
+ }
45
+ if (perms.subprocess === true) {
46
+ subprocessSkills.push(skillName);
47
+ }
48
+ }
49
+ const toEntries = (map) => Array.from(map.entries()).map(([value, skills]) => ({ value, skills }));
50
+ return {
51
+ networkOutbound: toEntries(networkMap),
52
+ filesystemRead: toEntries(fsReadMap),
53
+ filesystemWrite: toEntries(fsWriteMap),
54
+ subprocess: subprocessSkills,
55
+ };
56
+ }
57
+ /**
58
+ * Check if a domain is allowed by the budget's domain list.
59
+ * Supports wildcard matching: *.example.com matches sub.example.com
60
+ */
61
+ function isDomainAllowed(domain, allowedDomains) {
62
+ for (const allowed of allowedDomains) {
63
+ if (allowed === domain)
64
+ return true;
65
+ if (allowed.startsWith('*.')) {
66
+ const suffix = allowed.slice(1);
67
+ if (domain.endsWith(suffix) || domain === allowed.slice(2)) {
68
+ return true;
69
+ }
70
+ if (domain === allowed)
71
+ return true;
72
+ }
73
+ }
74
+ return false;
75
+ }
76
+ /**
77
+ * Check if a path is allowed by the budget's path list.
78
+ */
79
+ function isPathAllowed(requestedPath, allowedPaths) {
80
+ for (const allowed of allowedPaths) {
81
+ if (allowed === requestedPath)
82
+ return true;
83
+ if (allowed.endsWith('/**')) {
84
+ const prefix = allowed.slice(0, -3);
85
+ if (requestedPath.startsWith(prefix))
86
+ return true;
87
+ }
88
+ }
89
+ return false;
90
+ }
91
+ function checkBudget(resolved, budget) {
92
+ const violations = [];
93
+ const budgetDomains = budget.network?.outbound ?? [];
94
+ for (const entry of resolved.networkOutbound) {
95
+ if (!isDomainAllowed(entry.value, budgetDomains)) {
96
+ violations.push({
97
+ category: 'network outbound',
98
+ value: entry.value,
99
+ skills: entry.skills,
100
+ });
101
+ }
102
+ }
103
+ const budgetReadPaths = budget.filesystem?.read ?? [];
104
+ for (const entry of resolved.filesystemRead) {
105
+ if (!isPathAllowed(entry.value, budgetReadPaths)) {
106
+ violations.push({
107
+ category: 'filesystem read',
108
+ value: entry.value,
109
+ skills: entry.skills,
110
+ });
111
+ }
112
+ }
113
+ const budgetWritePaths = budget.filesystem?.write ?? [];
114
+ for (const entry of resolved.filesystemWrite) {
115
+ if (!isPathAllowed(entry.value, budgetWritePaths)) {
116
+ violations.push({
117
+ category: 'filesystem write',
118
+ value: entry.value,
119
+ skills: entry.skills,
120
+ });
121
+ }
122
+ }
123
+ if (resolved.subprocess.length > 0 && budget.subprocess !== true) {
124
+ violations.push({
125
+ category: 'subprocess',
126
+ value: 'subprocess access',
127
+ skills: resolved.subprocess,
128
+ });
129
+ }
130
+ return violations;
131
+ }
132
+ function formatAttribution(skills) {
133
+ return chalk.gray('← ' + skills.join(', '));
134
+ }
135
+ function printPermissionSection(title, entries) {
136
+ console.log(`\n${chalk.bold(title)}:`);
137
+ if (entries.length === 0) {
138
+ console.log(' none');
139
+ }
140
+ else {
141
+ for (const entry of entries) {
142
+ console.log(` ${entry.value} ${formatAttribution(entry.skills)}`);
143
+ }
144
+ }
145
+ }
146
+ export async function permissionsCommand(options) {
147
+ const dir = options?.directory ?? process.cwd();
148
+ const lockfilePath = path.join(dir, 'skills.lock');
149
+ // 1. Read lockfile
150
+ if (!fs.existsSync(lockfilePath)) {
151
+ console.log('No skills installed.');
152
+ return;
153
+ }
154
+ const lockfileContent = fs.readFileSync(lockfilePath, 'utf-8');
155
+ const lockfile = JSON.parse(lockfileContent);
156
+ if (!lockfile.skills || Object.keys(lockfile.skills).length === 0) {
157
+ console.log('No skills installed.');
158
+ return;
159
+ }
160
+ // 2. Collect permissions
161
+ const resolved = collectPermissions(lockfile);
162
+ // 3. Display
163
+ console.log('\nResolved permissions for this project:\n');
164
+ printPermissionSection('Network (outbound)', resolved.networkOutbound);
165
+ printPermissionSection('Filesystem (read)', resolved.filesystemRead);
166
+ printPermissionSection('Filesystem (write)', resolved.filesystemWrite);
167
+ // Subprocess section
168
+ console.log(`\n${chalk.bold('Subprocess')}:`);
169
+ if (resolved.subprocess.length === 0) {
170
+ console.log(' none');
171
+ }
172
+ else {
173
+ console.log(` allowed ${formatAttribution(resolved.subprocess)}`);
174
+ }
175
+ // 4. Budget check
176
+ const skillsJsonPath = path.join(dir, 'skills.json');
177
+ let budget;
178
+ if (fs.existsSync(skillsJsonPath)) {
179
+ const skillsJsonContent = fs.readFileSync(skillsJsonPath, 'utf-8');
180
+ const skillsJson = JSON.parse(skillsJsonContent);
181
+ budget = skillsJson.permissions;
182
+ }
183
+ console.log('');
184
+ if (!budget) {
185
+ console.log(`Budget status: ${chalk.yellow('⚠ No budget defined')}`);
186
+ return;
187
+ }
188
+ const violations = checkBudget(resolved, budget);
189
+ if (violations.length === 0) {
190
+ console.log(`Budget status: ${chalk.green('✓ PASS')} (all within budget)`);
191
+ }
192
+ else {
193
+ console.log(`Budget status: ${chalk.red('✗ FAIL')}`);
194
+ for (const v of violations) {
195
+ console.log(chalk.red(` - ${v.category}: "${v.value}" not in budget (requested by ${v.skills.join(', ')})`));
196
+ }
197
+ }
198
+ }
199
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/commands/permissions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export interface PublishOptions {
2
+ directory?: string;
3
+ configDir?: string;
4
+ dryRun?: boolean;
5
+ private?: boolean;
6
+ visibility?: string;
7
+ }
8
+ /**
9
+ * Format bytes into a human-readable size string.
10
+ */
11
+ export declare function formatSize(bytes: number): string;
12
+ /**
13
+ * Publish a skill package to the Tank registry.
14
+ *
15
+ * Flow:
16
+ * 1. Check auth (token exists)
17
+ * 2. Read skills.json from directory
18
+ * 3. Pack directory into tarball
19
+ * 4. If --dry-run: print summary and exit
20
+ * 5. POST /api/v1/skills with manifest → get uploadUrl, skillId, versionId
21
+ * 6. PUT tarball to uploadUrl
22
+ * 7. POST /api/v1/skills/confirm with integrity data
23
+ * 8. Print success
24
+ */
25
+ export declare function publishCommand(options?: PublishOptions): Promise<void>;
@@ -0,0 +1,166 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import ora from 'ora';
4
+ import { getConfig } from '../lib/config.js';
5
+ import { logger } from '../lib/logger.js';
6
+ import { pack } from '../lib/packer.js';
7
+ import { USER_AGENT } from '../version.js';
8
+ /**
9
+ * Format bytes into a human-readable size string.
10
+ */
11
+ export function formatSize(bytes) {
12
+ if (bytes < 1024)
13
+ return `${bytes} B`;
14
+ if (bytes < 1024 * 1024)
15
+ return `${(bytes / 1024).toFixed(1)} KB`;
16
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
17
+ }
18
+ /**
19
+ * Publish a skill package to the Tank registry.
20
+ *
21
+ * Flow:
22
+ * 1. Check auth (token exists)
23
+ * 2. Read skills.json from directory
24
+ * 3. Pack directory into tarball
25
+ * 4. If --dry-run: print summary and exit
26
+ * 5. POST /api/v1/skills with manifest → get uploadUrl, skillId, versionId
27
+ * 6. PUT tarball to uploadUrl
28
+ * 7. POST /api/v1/skills/confirm with integrity data
29
+ * 8. Print success
30
+ */
31
+ export async function publishCommand(options = {}) {
32
+ const { directory = process.cwd(), configDir, dryRun = false, private: privateFlag, visibility } = options;
33
+ // 1. Check auth
34
+ const config = getConfig(configDir);
35
+ if (!config.token) {
36
+ throw new Error('Not logged in. Run: tank login');
37
+ }
38
+ // 2. Read skills.json
39
+ const skillsJsonPath = path.join(directory, 'skills.json');
40
+ if (!fs.existsSync(skillsJsonPath)) {
41
+ throw new Error(`No skills.json found in ${directory}. Run: tank init`);
42
+ }
43
+ let manifest;
44
+ try {
45
+ const raw = fs.readFileSync(skillsJsonPath, 'utf-8');
46
+ manifest = JSON.parse(raw);
47
+ }
48
+ catch {
49
+ throw new Error('Failed to read or parse skills.json');
50
+ }
51
+ if (visibility && visibility !== 'public' && visibility !== 'private') {
52
+ throw new Error("Invalid visibility. Use 'public' or 'private'");
53
+ }
54
+ const effectiveVisibility = visibility ?? (privateFlag ? 'private' : undefined);
55
+ if (effectiveVisibility) {
56
+ manifest.visibility = effectiveVisibility;
57
+ }
58
+ const name = manifest.name;
59
+ const version = manifest.version;
60
+ // 3. Pack
61
+ const spinner = ora('Packing...').start();
62
+ let packResult;
63
+ try {
64
+ packResult = await pack(directory);
65
+ }
66
+ catch (err) {
67
+ spinner.fail('Packing failed');
68
+ throw err;
69
+ }
70
+ const { tarball, integrity, fileCount, totalSize, readme, files } = packResult;
71
+ // 4. Dry run — print summary, verify auth with server, and exit
72
+ if (dryRun) {
73
+ spinner.stop();
74
+ logger.info(`name: ${name}`);
75
+ logger.info(`version: ${version}`);
76
+ logger.info(`visibility: ${String(manifest.visibility ?? 'default')}`);
77
+ logger.info(`size: ${formatSize(totalSize)} (${fileCount} files)`);
78
+ logger.info(`tarball: ${formatSize(tarball.length)} (compressed)`);
79
+ // Verify token with server to catch stale auth before real publish
80
+ try {
81
+ const verifyRes = await fetch(`${config.registry}/api/v1/auth/whoami`, {
82
+ method: 'GET',
83
+ headers: {
84
+ 'Authorization': `Bearer ${config.token}`,
85
+ 'User-Agent': USER_AGENT,
86
+ },
87
+ });
88
+ if (verifyRes.status === 401) {
89
+ logger.warn('Token is invalid or expired. Run: tank login');
90
+ }
91
+ else if (!verifyRes.ok) {
92
+ logger.warn('Could not verify token with server. Publish may fail.');
93
+ }
94
+ else {
95
+ logger.success('Auth verified with server.');
96
+ }
97
+ }
98
+ catch {
99
+ logger.warn('Could not reach server to verify token. Publish may fail.');
100
+ }
101
+ logger.success('Dry run complete — no files were uploaded.');
102
+ return;
103
+ }
104
+ // 5. Step 1: POST /api/v1/skills
105
+ spinner.text = 'Publishing...';
106
+ const headers = {
107
+ 'Authorization': `Bearer ${config.token}`,
108
+ 'Content-Type': 'application/json',
109
+ 'User-Agent': USER_AGENT,
110
+ };
111
+ const step1Res = await fetch(`${config.registry}/api/v1/skills`, {
112
+ method: 'POST',
113
+ headers,
114
+ body: JSON.stringify({ manifest, readme, files }),
115
+ });
116
+ if (!step1Res.ok) {
117
+ spinner.fail('Publish failed');
118
+ const body = await step1Res.json().catch(() => ({}));
119
+ const errorMsg = body.error ?? step1Res.statusText;
120
+ if (step1Res.status === 401) {
121
+ throw new Error('Authentication failed. Your token may be expired or invalid. Run: tank login');
122
+ }
123
+ if (step1Res.status === 403) {
124
+ throw new Error(`Publish failed: ${errorMsg}`);
125
+ }
126
+ if (step1Res.status === 404) {
127
+ throw new Error(`Publish failed: ${errorMsg}`);
128
+ }
129
+ if (step1Res.status === 409) {
130
+ throw new Error('Version already exists. Bump the version in skills.json');
131
+ }
132
+ throw new Error(errorMsg);
133
+ }
134
+ const { uploadUrl, versionId } = (await step1Res.json());
135
+ // 6. Step 2: Upload tarball to signed URL
136
+ spinner.text = 'Uploading...';
137
+ const uploadRes = await fetch(uploadUrl, {
138
+ method: 'PUT',
139
+ headers: { 'Content-Type': 'application/octet-stream' },
140
+ body: new Uint8Array(tarball),
141
+ });
142
+ if (!uploadRes.ok) {
143
+ spinner.fail('Upload failed');
144
+ throw new Error(`Failed to upload tarball: ${uploadRes.status} ${uploadRes.statusText}`);
145
+ }
146
+ // 7. Step 3: Confirm publish
147
+ spinner.text = 'Confirming...';
148
+ const confirmRes = await fetch(`${config.registry}/api/v1/skills/confirm`, {
149
+ method: 'POST',
150
+ headers,
151
+ body: JSON.stringify({
152
+ versionId,
153
+ integrity,
154
+ fileCount,
155
+ tarballSize: totalSize,
156
+ readme,
157
+ }),
158
+ });
159
+ if (!confirmRes.ok) {
160
+ spinner.fail('Publish confirmation failed');
161
+ const body = await confirmRes.json().catch(() => ({}));
162
+ throw new Error(`Failed to confirm publish: ${body.error ?? confirmRes.statusText}`);
163
+ }
164
+ spinner.succeed(`Published ${name}@${version} (${formatSize(totalSize)}, ${fileCount} files)`);
165
+ }
166
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface RemoveOptions {
2
+ name: string;
3
+ directory?: string;
4
+ global?: boolean;
5
+ homedir?: string;
6
+ }
7
+ export declare function removeCommand(options: RemoveOptions): Promise<void>;