@tpmjs/cli 0.1.4 → 0.1.5

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +18 -0
  3. package/bin/run.js +0 -0
  4. package/dist/commands/agent/chat.js +7 -7
  5. package/dist/commands/agent/chat.js.map +1 -1
  6. package/dist/commands/agent/create.js +6 -6
  7. package/dist/commands/agent/create.js.map +1 -1
  8. package/dist/commands/agent/delete.js +9 -7
  9. package/dist/commands/agent/delete.js.map +1 -1
  10. package/dist/commands/agent/list.js +6 -6
  11. package/dist/commands/agent/list.js.map +1 -1
  12. package/dist/commands/agent/update.js +6 -6
  13. package/dist/commands/agent/update.js.map +1 -1
  14. package/dist/commands/auth/login.js +6 -6
  15. package/dist/commands/auth/login.js.map +1 -1
  16. package/dist/commands/auth/logout.js +4 -4
  17. package/dist/commands/auth/logout.js.map +1 -1
  18. package/dist/commands/auth/status.js +12 -9
  19. package/dist/commands/auth/status.js.map +1 -1
  20. package/dist/commands/auth/whoami.js +6 -6
  21. package/dist/commands/auth/whoami.js.map +1 -1
  22. package/dist/commands/collection/add.js +6 -6
  23. package/dist/commands/collection/add.js.map +1 -1
  24. package/dist/commands/collection/create.js +6 -6
  25. package/dist/commands/collection/create.js.map +1 -1
  26. package/dist/commands/collection/delete.js +7 -7
  27. package/dist/commands/collection/delete.js.map +1 -1
  28. package/dist/commands/collection/import.js +7 -7
  29. package/dist/commands/collection/import.js.map +1 -1
  30. package/dist/commands/collection/info.d.ts +17 -0
  31. package/dist/commands/collection/info.js +358 -0
  32. package/dist/commands/collection/info.js.map +1 -0
  33. package/dist/commands/collection/list.js +6 -6
  34. package/dist/commands/collection/list.js.map +1 -1
  35. package/dist/commands/collection/remove.js +7 -9
  36. package/dist/commands/collection/remove.js.map +1 -1
  37. package/dist/commands/collection/update.js +6 -6
  38. package/dist/commands/collection/update.js.map +1 -1
  39. package/dist/commands/doctor.js +7 -7
  40. package/dist/commands/doctor.js.map +1 -1
  41. package/dist/commands/mcp/config.js +4 -4
  42. package/dist/commands/mcp/config.js.map +1 -1
  43. package/dist/commands/mcp/serve.js +7 -7
  44. package/dist/commands/mcp/serve.js.map +1 -1
  45. package/dist/commands/playground.js +7 -7
  46. package/dist/commands/playground.js.map +1 -1
  47. package/dist/commands/publish/check.js +11 -11
  48. package/dist/commands/publish/check.js.map +1 -1
  49. package/dist/commands/publish/preview.js +4 -4
  50. package/dist/commands/publish/preview.js.map +1 -1
  51. package/dist/commands/run.d.ts +24 -0
  52. package/dist/commands/run.js +454 -0
  53. package/dist/commands/run.js.map +1 -0
  54. package/dist/commands/scenario/generate.js +6 -6
  55. package/dist/commands/scenario/generate.js.map +1 -1
  56. package/dist/commands/scenario/info.js +6 -6
  57. package/dist/commands/scenario/info.js.map +1 -1
  58. package/dist/commands/scenario/list.js +11 -11
  59. package/dist/commands/scenario/list.js.map +1 -1
  60. package/dist/commands/scenario/run.js +7 -7
  61. package/dist/commands/scenario/run.js.map +1 -1
  62. package/dist/commands/scenario/test.js +8 -8
  63. package/dist/commands/scenario/test.js.map +1 -1
  64. package/dist/commands/tool/execute.js +9 -7
  65. package/dist/commands/tool/execute.js.map +1 -1
  66. package/dist/commands/tool/info.js +16 -9
  67. package/dist/commands/tool/info.js.map +1 -1
  68. package/dist/commands/tool/init.js +7 -13
  69. package/dist/commands/tool/init.js.map +1 -1
  70. package/dist/commands/tool/search.js +7 -11
  71. package/dist/commands/tool/search.js.map +1 -1
  72. package/dist/commands/tool/trending.js +6 -6
  73. package/dist/commands/tool/trending.js.map +1 -1
  74. package/dist/commands/tool/validate.js +15 -9
  75. package/dist/commands/tool/validate.js.map +1 -1
  76. package/dist/commands/update.js +4 -4
  77. package/dist/commands/update.js.map +1 -1
  78. package/dist/hooks/init.js +1 -1
  79. package/dist/hooks/init.js.map +1 -1
  80. package/dist/index.js +6 -6
  81. package/dist/index.js.map +1 -1
  82. package/oclif.manifest.json +146 -1
  83. package/package.json +10 -12
@@ -0,0 +1,358 @@
1
+ import { Command, Args, Flags } from '@oclif/core';
2
+ import * as fs from 'fs';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ import Conf from 'conf';
6
+ import Table from 'cli-table3';
7
+ import ora from 'ora';
8
+ import pc from 'picocolors';
9
+
10
+ // src/commands/collection/info.ts
11
+ var CONFIG_DIR = path.join(os.homedir(), ".tpmjs");
12
+ var CREDENTIALS_FILE = path.join(CONFIG_DIR, "credentials.json");
13
+ path.join(CONFIG_DIR, "history");
14
+ function ensureConfigDir() {
15
+ if (!fs.existsSync(CONFIG_DIR)) {
16
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
17
+ }
18
+ }
19
+ var configStore = new Conf({
20
+ projectName: "tpmjs",
21
+ cwd: CONFIG_DIR,
22
+ configName: "config",
23
+ defaults: {
24
+ apiUrl: "https://tpmjs.com/api",
25
+ defaultOutput: "human",
26
+ verbose: false,
27
+ analytics: false
28
+ }
29
+ });
30
+ function getConfigValue(key) {
31
+ return configStore.get(key);
32
+ }
33
+ function loadCredentials() {
34
+ ensureConfigDir();
35
+ if (!fs.existsSync(CREDENTIALS_FILE)) {
36
+ return null;
37
+ }
38
+ try {
39
+ const content = fs.readFileSync(CREDENTIALS_FILE, "utf-8");
40
+ return JSON.parse(content);
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+ function getApiKey() {
46
+ if (process.env.TPMJS_API_KEY) {
47
+ return process.env.TPMJS_API_KEY;
48
+ }
49
+ const creds = loadCredentials();
50
+ if (creds?.apiKey) {
51
+ return creds.apiKey;
52
+ }
53
+ return void 0;
54
+ }
55
+ function getApiUrl() {
56
+ return process.env.TPMJS_API_URL ?? getConfigValue("apiUrl") ?? "https://tpmjs.com/api";
57
+ }
58
+ var OutputFormatter = class {
59
+ options;
60
+ constructor(options = {}) {
61
+ this.options = options;
62
+ }
63
+ // Output as JSON
64
+ json(data) {
65
+ console.log(JSON.stringify(data, null, 2));
66
+ }
67
+ // Output a table
68
+ table(data, columns) {
69
+ if (this.options.json) {
70
+ this.json(data);
71
+ return;
72
+ }
73
+ const table = new Table({
74
+ head: columns.map((col) => pc.bold(col.header)),
75
+ colWidths: columns.map((col) => col.width ?? null),
76
+ style: {
77
+ head: [],
78
+ border: []
79
+ }
80
+ });
81
+ for (const row of data) {
82
+ table.push(columns.map((col) => String(row[col.key] ?? "")));
83
+ }
84
+ console.log(table.toString());
85
+ }
86
+ // Success message
87
+ success(message) {
88
+ if (this.options.json) return;
89
+ console.log(pc.green("\u2713"), message);
90
+ }
91
+ // Error message
92
+ error(message, details) {
93
+ if (this.options.json) {
94
+ this.json({ error: message, details });
95
+ return;
96
+ }
97
+ console.error(pc.red("\u2717"), message);
98
+ if (details && this.options.verbose) {
99
+ console.error(pc.dim(details));
100
+ }
101
+ }
102
+ // Warning message
103
+ warning(message) {
104
+ if (this.options.json) return;
105
+ console.log(pc.yellow("\u26A0"), message);
106
+ }
107
+ // Info message
108
+ info(message) {
109
+ if (this.options.json) return;
110
+ console.log(pc.blue("\u2139"), message);
111
+ }
112
+ // Debug message (only in verbose mode)
113
+ debug(message) {
114
+ if (this.options.json) return;
115
+ if (this.options.verbose) {
116
+ console.log(pc.dim(`[debug] ${message}`));
117
+ }
118
+ }
119
+ // Plain text output
120
+ text(message) {
121
+ if (this.options.json) return;
122
+ console.log(message);
123
+ }
124
+ // Heading
125
+ heading(text) {
126
+ if (this.options.json) return;
127
+ console.log();
128
+ console.log(pc.bold(pc.underline(text)));
129
+ console.log();
130
+ }
131
+ // Subheading
132
+ subheading(text) {
133
+ if (this.options.json) return;
134
+ console.log(pc.bold(text));
135
+ }
136
+ // Key-value pair
137
+ keyValue(key, value) {
138
+ if (this.options.json) return;
139
+ console.log(`${pc.dim(`${key}:`)} ${value ?? pc.dim("(not set)")}`);
140
+ }
141
+ // List item
142
+ listItem(text, indent = 0) {
143
+ if (this.options.json) return;
144
+ const prefix = `${" ".repeat(indent)}\u2022`;
145
+ console.log(`${prefix} ${text}`);
146
+ }
147
+ // Spinner
148
+ spinner(message) {
149
+ return ora({
150
+ text: message,
151
+ isSilent: this.options.json
152
+ }).start();
153
+ }
154
+ // Blank line
155
+ newLine() {
156
+ if (this.options.json) return;
157
+ console.log();
158
+ }
159
+ // Horizontal rule
160
+ hr() {
161
+ if (this.options.json) return;
162
+ console.log(pc.dim("\u2500".repeat(50)));
163
+ }
164
+ // Alias for hr
165
+ divider() {
166
+ this.hr();
167
+ }
168
+ // Code block
169
+ code(text, language) {
170
+ if (this.options.json) {
171
+ this.json({ code: text, language });
172
+ return;
173
+ }
174
+ console.log(pc.dim(`\`\`\`${language ?? ""}`));
175
+ console.log(text);
176
+ console.log(pc.dim("```"));
177
+ }
178
+ // Highlight text
179
+ highlight(text) {
180
+ return pc.cyan(text);
181
+ }
182
+ // Dim text
183
+ dim(text) {
184
+ return pc.dim(text);
185
+ }
186
+ // Bold text
187
+ bold(text) {
188
+ return pc.bold(text);
189
+ }
190
+ // Link (just returns text in terminal)
191
+ link(text, url) {
192
+ return `\x1B]8;;${url}\x07${pc.underline(pc.blue(text))}\x1B]8;;\x07`;
193
+ }
194
+ // Color helpers
195
+ green(text) {
196
+ return pc.green(text);
197
+ }
198
+ red(text) {
199
+ return pc.red(text);
200
+ }
201
+ yellow(text) {
202
+ return pc.yellow(text);
203
+ }
204
+ blue(text) {
205
+ return pc.blue(text);
206
+ }
207
+ cyan(text) {
208
+ return pc.cyan(text);
209
+ }
210
+ };
211
+ function createOutput(flags) {
212
+ return new OutputFormatter({
213
+ json: flags.json,
214
+ verbose: flags.verbose
215
+ });
216
+ }
217
+
218
+ // src/commands/collection/info.ts
219
+ var CollectionInfo = class _CollectionInfo extends Command {
220
+ static description = "Show collection details and list all available tools";
221
+ static examples = [
222
+ "<%= config.bin %> collection info ajax/unsandbox",
223
+ "<%= config.bin %> collection info ajax/unsandbox --json",
224
+ "<%= config.bin %> collection info ajax/unsandbox --verbose"
225
+ ];
226
+ static args = {
227
+ collection: Args.string({
228
+ description: "Collection identifier (username/slug)",
229
+ required: true
230
+ })
231
+ };
232
+ static flags = {
233
+ json: Flags.boolean({
234
+ description: "Output in JSON format",
235
+ default: false
236
+ }),
237
+ verbose: Flags.boolean({
238
+ char: "v",
239
+ description: "Show tool input schemas",
240
+ default: false
241
+ })
242
+ };
243
+ async run() {
244
+ const { args, flags } = await this.parse(_CollectionInfo);
245
+ const output = createOutput(flags);
246
+ const parts = args.collection.split("/");
247
+ if (parts.length !== 2) {
248
+ output.error("Invalid collection format. Use: username/slug");
249
+ return;
250
+ }
251
+ const [username, slug] = parts;
252
+ const baseUrl = getApiUrl().replace(/\/api$/, "");
253
+ const mcpUrl = `${baseUrl}/api/mcp/${username}/${slug}/http`;
254
+ const spinner = output.spinner(`Fetching tools from ${args.collection}...`);
255
+ try {
256
+ const apiKey = getApiKey();
257
+ const headers = {
258
+ "Content-Type": "application/json"
259
+ };
260
+ if (apiKey) {
261
+ headers["Authorization"] = `Bearer ${apiKey}`;
262
+ }
263
+ const response = await fetch(mcpUrl, {
264
+ method: "POST",
265
+ headers,
266
+ body: JSON.stringify({
267
+ jsonrpc: "2.0",
268
+ id: 1,
269
+ method: "tools/list"
270
+ })
271
+ });
272
+ if (!response.ok) {
273
+ spinner.fail("Failed to fetch collection");
274
+ output.error(`HTTP ${response.status}: ${await response.text()}`);
275
+ return;
276
+ }
277
+ const data = await response.json();
278
+ if (data.error) {
279
+ spinner.fail("Failed to fetch tools");
280
+ output.error(data.error.message);
281
+ return;
282
+ }
283
+ const tools = data.result?.tools || [];
284
+ spinner.stop();
285
+ if (flags.json) {
286
+ output.json({
287
+ collection: args.collection,
288
+ mcpUrl,
289
+ toolCount: tools.length,
290
+ tools: tools.map((t) => ({
291
+ name: t.name,
292
+ description: t.description,
293
+ ...flags.verbose ? { inputSchema: t.inputSchema } : {}
294
+ }))
295
+ });
296
+ return;
297
+ }
298
+ output.success(`Collection: ${args.collection}`);
299
+ output.text(`MCP URL: ${mcpUrl}`);
300
+ output.text(`Tools: ${tools.length}`);
301
+ output.divider();
302
+ if (tools.length === 0) {
303
+ output.info("No tools in this collection");
304
+ return;
305
+ }
306
+ output.table(
307
+ tools.map((tool) => ({
308
+ name: tool.name,
309
+ description: truncate(tool.description, 60)
310
+ })),
311
+ [
312
+ { key: "name", header: "Tool Name", width: 40 },
313
+ { key: "description", header: "Description", width: 60 }
314
+ ]
315
+ );
316
+ if (flags.verbose) {
317
+ output.newLine();
318
+ output.divider();
319
+ output.text("Tool Details:");
320
+ output.newLine();
321
+ for (const tool of tools) {
322
+ output.text(`${output.bold(tool.name)}`);
323
+ output.text(` ${tool.description}`);
324
+ if (tool.inputSchema?.properties) {
325
+ const props = tool.inputSchema.properties;
326
+ const required = tool.inputSchema.required || [];
327
+ output.text(" Parameters:");
328
+ for (const [name, schema] of Object.entries(props)) {
329
+ const req = required.includes(name) ? " (required)" : "";
330
+ output.text(` - ${name}: ${schema.type}${req}`);
331
+ if (schema.description) {
332
+ output.text(` ${output.dim(schema.description)}`);
333
+ }
334
+ }
335
+ }
336
+ output.newLine();
337
+ }
338
+ }
339
+ output.newLine();
340
+ output.text(output.dim("Usage example:"));
341
+ const exampleTool = tools[0]?.name || "toolName";
342
+ output.text(
343
+ output.dim(` tpm run -c ${args.collection} -t ${exampleTool} --args '{}'`)
344
+ );
345
+ } catch (error) {
346
+ spinner.fail("Failed to fetch collection");
347
+ output.error(error instanceof Error ? error.message : "Unknown error");
348
+ }
349
+ }
350
+ };
351
+ function truncate(str, maxLen) {
352
+ if (str.length <= maxLen) return str;
353
+ return str.slice(0, maxLen - 3) + "...";
354
+ }
355
+
356
+ export { CollectionInfo as default };
357
+ //# sourceMappingURL=info.js.map
358
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/config.ts","../../../src/lib/output.ts","../../../src/commands/collection/info.ts"],"names":[],"mappings":"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","file":"info.js","sourcesContent":["import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport Conf from 'conf';\n\nexport interface TpmConfig {\n apiUrl?: string;\n defaultOutput?: 'human' | 'json';\n verbose?: boolean;\n analytics?: boolean;\n env?: Record<string, string>;\n}\n\nexport interface TpmCredentials {\n apiKey?: string;\n refreshToken?: string;\n expiresAt?: string;\n}\n\nconst CONFIG_DIR = path.join(os.homedir(), '.tpmjs');\nconst CREDENTIALS_FILE = path.join(CONFIG_DIR, 'credentials.json');\nconst HISTORY_DIR = path.join(CONFIG_DIR, 'history');\n\n// Ensure config directory exists\nfunction ensureConfigDir(): void {\n if (!fs.existsSync(CONFIG_DIR)) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n }\n}\n\n// Config store using Conf\nconst configStore = new Conf<TpmConfig>({\n projectName: 'tpmjs',\n cwd: CONFIG_DIR,\n configName: 'config',\n defaults: {\n apiUrl: 'https://tpmjs.com/api',\n defaultOutput: 'human',\n verbose: false,\n analytics: false,\n },\n});\n\nexport function getConfig(): TpmConfig {\n return configStore.store;\n}\n\nexport function setConfig(config: Partial<TpmConfig>): void {\n for (const [key, value] of Object.entries(config)) {\n if (value !== undefined) {\n configStore.set(key, value);\n }\n }\n}\n\nexport function getConfigValue<K extends keyof TpmConfig>(key: K): TpmConfig[K] {\n return configStore.get(key);\n}\n\nexport function setConfigValue<K extends keyof TpmConfig>(key: K, value: TpmConfig[K]): void {\n configStore.set(key, value);\n}\n\nexport function resetConfig(): void {\n configStore.clear();\n}\n\n// Credentials management with secure file permissions\nexport function loadCredentials(): TpmCredentials | null {\n ensureConfigDir();\n\n if (!fs.existsSync(CREDENTIALS_FILE)) {\n return null;\n }\n\n try {\n const content = fs.readFileSync(CREDENTIALS_FILE, 'utf-8');\n return JSON.parse(content) as TpmCredentials;\n } catch {\n return null;\n }\n}\n\nexport function saveCredentials(credentials: TpmCredentials): void {\n ensureConfigDir();\n\n const content = JSON.stringify(credentials, null, 2);\n fs.writeFileSync(CREDENTIALS_FILE, content, { mode: 0o600 });\n}\n\nexport function deleteCredentials(): void {\n if (fs.existsSync(CREDENTIALS_FILE)) {\n fs.unlinkSync(CREDENTIALS_FILE);\n }\n}\n\nexport function hasCredentials(): boolean {\n const creds = loadCredentials();\n return creds !== null && !!creds.apiKey;\n}\n\n// Get API key from multiple sources (priority order)\nexport function getApiKey(): string | undefined {\n // 1. Environment variable\n if (process.env.TPMJS_API_KEY) {\n return process.env.TPMJS_API_KEY;\n }\n\n // 2. Credentials file\n const creds = loadCredentials();\n if (creds?.apiKey) {\n return creds.apiKey;\n }\n\n return undefined;\n}\n\n// Get API URL\nexport function getApiUrl(): string {\n return process.env.TPMJS_API_URL ?? getConfigValue('apiUrl') ?? 'https://tpmjs.com/api';\n}\n\n// History directory for conversation caching\nexport function getHistoryDir(): string {\n if (!fs.existsSync(HISTORY_DIR)) {\n fs.mkdirSync(HISTORY_DIR, { recursive: true, mode: 0o700 });\n }\n return HISTORY_DIR;\n}\n\n// Config directory path\nexport function getConfigDir(): string {\n ensureConfigDir();\n return CONFIG_DIR;\n}\n","import Table from 'cli-table3';\nimport ora, { type Ora } from 'ora';\nimport pc from 'picocolors';\n\nexport interface OutputOptions {\n json?: boolean;\n verbose?: boolean;\n noColor?: boolean;\n}\n\nexport class OutputFormatter {\n private options: OutputOptions;\n\n constructor(options: OutputOptions = {}) {\n this.options = options;\n }\n\n // Output as JSON\n json(data: unknown): void {\n console.log(JSON.stringify(data, null, 2));\n }\n\n // Output a table\n table<T extends Record<string, unknown>>(\n data: T[],\n columns: { key: keyof T; header: string; width?: number }[]\n ): void {\n if (this.options.json) {\n this.json(data);\n return;\n }\n\n const table = new Table({\n head: columns.map((col) => pc.bold(col.header)),\n colWidths: columns.map((col) => col.width ?? null),\n style: {\n head: [],\n border: [],\n },\n });\n\n for (const row of data) {\n table.push(columns.map((col) => String(row[col.key] ?? '')));\n }\n\n console.log(table.toString());\n }\n\n // Success message\n success(message: string): void {\n if (this.options.json) return;\n console.log(pc.green('✓'), message);\n }\n\n // Error message\n error(message: string, details?: string): void {\n if (this.options.json) {\n this.json({ error: message, details });\n return;\n }\n console.error(pc.red('✗'), message);\n if (details && this.options.verbose) {\n console.error(pc.dim(details));\n }\n }\n\n // Warning message\n warning(message: string): void {\n if (this.options.json) return;\n console.log(pc.yellow('⚠'), message);\n }\n\n // Info message\n info(message: string): void {\n if (this.options.json) return;\n console.log(pc.blue('ℹ'), message);\n }\n\n // Debug message (only in verbose mode)\n debug(message: string): void {\n if (this.options.json) return;\n if (this.options.verbose) {\n console.log(pc.dim(`[debug] ${message}`));\n }\n }\n\n // Plain text output\n text(message: string): void {\n if (this.options.json) return;\n console.log(message);\n }\n\n // Heading\n heading(text: string): void {\n if (this.options.json) return;\n console.log();\n console.log(pc.bold(pc.underline(text)));\n console.log();\n }\n\n // Subheading\n subheading(text: string): void {\n if (this.options.json) return;\n console.log(pc.bold(text));\n }\n\n // Key-value pair\n keyValue(key: string, value: string | number | boolean | undefined): void {\n if (this.options.json) return;\n console.log(`${pc.dim(`${key}:`)} ${value ?? pc.dim('(not set)')}`);\n }\n\n // List item\n listItem(text: string, indent = 0): void {\n if (this.options.json) return;\n const prefix = `${' '.repeat(indent)}•`;\n console.log(`${prefix} ${text}`);\n }\n\n // Spinner\n spinner(message: string): Ora {\n return ora({\n text: message,\n isSilent: this.options.json,\n }).start();\n }\n\n // Blank line\n newLine(): void {\n if (this.options.json) return;\n console.log();\n }\n\n // Horizontal rule\n hr(): void {\n if (this.options.json) return;\n console.log(pc.dim('─'.repeat(50)));\n }\n\n // Alias for hr\n divider(): void {\n this.hr();\n }\n\n // Code block\n code(text: string, language?: string): void {\n if (this.options.json) {\n this.json({ code: text, language });\n return;\n }\n console.log(pc.dim(`\\`\\`\\`${language ?? ''}`));\n console.log(text);\n console.log(pc.dim('```'));\n }\n\n // Highlight text\n highlight(text: string): string {\n return pc.cyan(text);\n }\n\n // Dim text\n dim(text: string): string {\n return pc.dim(text);\n }\n\n // Bold text\n bold(text: string): string {\n return pc.bold(text);\n }\n\n // Link (just returns text in terminal)\n link(text: string, url: string): string {\n // OSC 8 hyperlink support for modern terminals\n return `\\x1b]8;;${url}\\x07${pc.underline(pc.blue(text))}\\x1b]8;;\\x07`;\n }\n\n // Color helpers\n green(text: string): string {\n return pc.green(text);\n }\n\n red(text: string): string {\n return pc.red(text);\n }\n\n yellow(text: string): string {\n return pc.yellow(text);\n }\n\n blue(text: string): string {\n return pc.blue(text);\n }\n\n cyan(text: string): string {\n return pc.cyan(text);\n }\n}\n\n// Convenience function to create formatter from command flags\nexport function createOutput(flags: { json?: boolean; verbose?: boolean }): OutputFormatter {\n return new OutputFormatter({\n json: flags.json,\n verbose: flags.verbose,\n });\n}\n","import { Args, Command, Flags } from '@oclif/core';\n\nimport { getApiKey, getApiUrl } from '../../lib/config.js';\nimport { createOutput } from '../../lib/output.js';\n\ninterface McpTool {\n name: string;\n description: string;\n inputSchema?: {\n type: string;\n required?: string[];\n properties?: Record<string, { type: string; description?: string }>;\n };\n}\n\ninterface McpListToolsResponse {\n jsonrpc: '2.0';\n id: number;\n result?: {\n tools: McpTool[];\n };\n error?: {\n code: number;\n message: string;\n };\n}\n\nexport default class CollectionInfo extends Command {\n static description = 'Show collection details and list all available tools';\n\n static examples = [\n '<%= config.bin %> collection info ajax/unsandbox',\n '<%= config.bin %> collection info ajax/unsandbox --json',\n '<%= config.bin %> collection info ajax/unsandbox --verbose',\n ];\n\n static args = {\n collection: Args.string({\n description: 'Collection identifier (username/slug)',\n required: true,\n }),\n };\n\n static flags = {\n json: Flags.boolean({\n description: 'Output in JSON format',\n default: false,\n }),\n verbose: Flags.boolean({\n char: 'v',\n description: 'Show tool input schemas',\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(CollectionInfo);\n const output = createOutput(flags);\n\n // Parse collection identifier\n const parts = args.collection.split('/');\n if (parts.length !== 2) {\n output.error('Invalid collection format. Use: username/slug');\n return;\n }\n\n const [username, slug] = parts;\n const baseUrl = getApiUrl().replace(/\\/api$/, '');\n const mcpUrl = `${baseUrl}/api/mcp/${username}/${slug}/http`;\n\n const spinner = output.spinner(`Fetching tools from ${args.collection}...`);\n\n try {\n // Get API key for authentication\n const apiKey = getApiKey();\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (apiKey) {\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n // Call MCP tools/list to get all tools\n const response = await fetch(mcpUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'tools/list',\n }),\n });\n\n if (!response.ok) {\n spinner.fail('Failed to fetch collection');\n output.error(`HTTP ${response.status}: ${await response.text()}`);\n return;\n }\n\n const data = (await response.json()) as McpListToolsResponse;\n\n if (data.error) {\n spinner.fail('Failed to fetch tools');\n output.error(data.error.message);\n return;\n }\n\n const tools = data.result?.tools || [];\n spinner.stop();\n\n if (flags.json) {\n output.json({\n collection: args.collection,\n mcpUrl,\n toolCount: tools.length,\n tools: tools.map((t) => ({\n name: t.name,\n description: t.description,\n ...(flags.verbose ? { inputSchema: t.inputSchema } : {}),\n })),\n });\n return;\n }\n\n // Display collection info\n output.success(`Collection: ${args.collection}`);\n output.text(`MCP URL: ${mcpUrl}`);\n output.text(`Tools: ${tools.length}`);\n output.divider();\n\n if (tools.length === 0) {\n output.info('No tools in this collection');\n return;\n }\n\n // Display tools table\n output.table(\n tools.map((tool) => ({\n name: tool.name,\n description: truncate(tool.description, 60),\n })),\n [\n { key: 'name', header: 'Tool Name', width: 40 },\n { key: 'description', header: 'Description', width: 60 },\n ]\n );\n\n // Show verbose tool details\n if (flags.verbose) {\n output.newLine();\n output.divider();\n output.text('Tool Details:');\n output.newLine();\n\n for (const tool of tools) {\n output.text(`${output.bold(tool.name)}`);\n output.text(` ${tool.description}`);\n\n if (tool.inputSchema?.properties) {\n const props = tool.inputSchema.properties;\n const required = tool.inputSchema.required || [];\n output.text(' Parameters:');\n for (const [name, schema] of Object.entries(props)) {\n const req = required.includes(name) ? ' (required)' : '';\n output.text(` - ${name}: ${schema.type}${req}`);\n if (schema.description) {\n output.text(` ${output.dim(schema.description)}`);\n }\n }\n }\n output.newLine();\n }\n }\n\n // Usage hints\n output.newLine();\n output.text(output.dim('Usage example:'));\n const exampleTool = tools[0]?.name || 'toolName';\n output.text(\n output.dim(` tpm run -c ${args.collection} -t ${exampleTool} --args '{}'`)\n );\n } catch (error) {\n spinner.fail('Failed to fetch collection');\n output.error(error instanceof Error ? error.message : 'Unknown error');\n }\n }\n}\n\nfunction truncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen - 3) + '...';\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  import { Command, Flags } from '@oclif/core';
2
- import Conf from 'conf';
3
2
  import * as fs from 'fs';
4
3
  import * as os from 'os';
5
4
  import * as path from 'path';
5
+ import Conf from 'conf';
6
6
  import Table from 'cli-table3';
7
7
  import ora from 'ora';
8
8
  import pc from 'picocolors';
@@ -73,7 +73,7 @@ var TpmClient = class {
73
73
  ...options.headers
74
74
  };
75
75
  if (this.apiKey) {
76
- headers["Authorization"] = `Bearer ${this.apiKey}`;
76
+ headers.Authorization = `Bearer ${this.apiKey}`;
77
77
  }
78
78
  const controller = new AbortController();
79
79
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
@@ -155,7 +155,7 @@ var TpmClient = class {
155
155
  Accept: "text/event-stream"
156
156
  };
157
157
  if (this.apiKey) {
158
- headers["Authorization"] = `Bearer ${this.apiKey}`;
158
+ headers.Authorization = `Bearer ${this.apiKey}`;
159
159
  }
160
160
  const response = await fetch(url, {
161
161
  method: "POST",
@@ -429,12 +429,12 @@ var OutputFormatter = class {
429
429
  // Key-value pair
430
430
  keyValue(key, value) {
431
431
  if (this.options.json) return;
432
- console.log(`${pc.dim(key + ":")} ${value ?? pc.dim("(not set)")}`);
432
+ console.log(`${pc.dim(`${key}:`)} ${value ?? pc.dim("(not set)")}`);
433
433
  }
434
434
  // List item
435
435
  listItem(text, indent = 0) {
436
436
  if (this.options.json) return;
437
- const prefix = " ".repeat(indent) + "\u2022";
437
+ const prefix = `${" ".repeat(indent)}\u2022`;
438
438
  console.log(`${prefix} ${text}`);
439
439
  }
440
440
  // Spinner
@@ -464,7 +464,7 @@ var OutputFormatter = class {
464
464
  this.json({ code: text, language });
465
465
  return;
466
466
  }
467
- console.log(pc.dim("```" + (language ?? "")));
467
+ console.log(pc.dim(`\`\`\`${language ?? ""}`));
468
468
  console.log(text);
469
469
  console.log(pc.dim("```"));
470
470
  }