@hasna/connectors 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/bin/index.js +126 -2
  2. package/bin/mcp.js +113 -1
  3. package/bin/serve.js +112 -0
  4. package/connectors/connect-assemblyai/.env.example +11 -0
  5. package/connectors/connect-assemblyai/CLAUDE.md +128 -0
  6. package/connectors/connect-assemblyai/README.md +193 -0
  7. package/connectors/connect-assemblyai/package.json +50 -0
  8. package/connectors/connect-assemblyai/src/api/client.ts +192 -0
  9. package/connectors/connect-assemblyai/src/api/index.ts +71 -0
  10. package/connectors/connect-assemblyai/src/cli/index.ts +384 -0
  11. package/connectors/connect-assemblyai/src/index.ts +19 -0
  12. package/connectors/connect-assemblyai/src/types/index.ts +277 -0
  13. package/connectors/connect-assemblyai/src/utils/config.ts +103 -0
  14. package/connectors/connect-assemblyai/src/utils/output.ts +119 -0
  15. package/connectors/connect-assemblyai/tsconfig.json +16 -0
  16. package/connectors/connect-baseten/.env.example +11 -0
  17. package/connectors/connect-baseten/CLAUDE.md +128 -0
  18. package/connectors/connect-baseten/README.md +193 -0
  19. package/connectors/connect-baseten/package.json +51 -0
  20. package/connectors/connect-baseten/src/api/client.ts +71 -0
  21. package/connectors/connect-baseten/src/api/index.ts +40 -0
  22. package/connectors/connect-baseten/src/cli/index.ts +244 -0
  23. package/connectors/connect-baseten/src/index.ts +19 -0
  24. package/connectors/connect-baseten/src/types/index.ts +55 -0
  25. package/connectors/connect-baseten/src/utils/config.ts +103 -0
  26. package/connectors/connect-baseten/src/utils/output.ts +119 -0
  27. package/connectors/connect-baseten/tsconfig.json +16 -0
  28. package/connectors/connect-cerebras/.env.example +11 -0
  29. package/connectors/connect-cerebras/CLAUDE.md +128 -0
  30. package/connectors/connect-cerebras/README.md +193 -0
  31. package/connectors/connect-cerebras/package.json +51 -0
  32. package/connectors/connect-cerebras/src/api/client.ts +64 -0
  33. package/connectors/connect-cerebras/src/api/index.ts +32 -0
  34. package/connectors/connect-cerebras/src/cli/index.ts +244 -0
  35. package/connectors/connect-cerebras/src/index.ts +19 -0
  36. package/connectors/connect-cerebras/src/types/index.ts +65 -0
  37. package/connectors/connect-cerebras/src/utils/config.ts +103 -0
  38. package/connectors/connect-cerebras/src/utils/output.ts +119 -0
  39. package/connectors/connect-cerebras/tsconfig.json +16 -0
  40. package/connectors/connect-cohere/.env.example +11 -0
  41. package/connectors/connect-cohere/CLAUDE.md +128 -0
  42. package/connectors/connect-cohere/README.md +193 -0
  43. package/connectors/connect-cohere/package.json +53 -0
  44. package/connectors/connect-cohere/src/api/client.ts +109 -0
  45. package/connectors/connect-cohere/src/api/index.ts +59 -0
  46. package/connectors/connect-cohere/src/cli/index.ts +255 -0
  47. package/connectors/connect-cohere/src/index.ts +19 -0
  48. package/connectors/connect-cohere/src/types/index.ts +132 -0
  49. package/connectors/connect-cohere/src/utils/config.ts +197 -0
  50. package/connectors/connect-cohere/src/utils/output.ts +119 -0
  51. package/connectors/connect-cohere/tsconfig.json +16 -0
  52. package/connectors/connect-deepgram/.env.example +11 -0
  53. package/connectors/connect-deepgram/CLAUDE.md +128 -0
  54. package/connectors/connect-deepgram/README.md +193 -0
  55. package/connectors/connect-deepgram/package.json +51 -0
  56. package/connectors/connect-deepgram/src/api/client.ts +235 -0
  57. package/connectors/connect-deepgram/src/api/index.ts +57 -0
  58. package/connectors/connect-deepgram/src/cli/index.ts +339 -0
  59. package/connectors/connect-deepgram/src/index.ts +19 -0
  60. package/connectors/connect-deepgram/src/types/index.ts +232 -0
  61. package/connectors/connect-deepgram/src/utils/config.ts +103 -0
  62. package/connectors/connect-deepgram/src/utils/output.ts +119 -0
  63. package/connectors/connect-deepgram/tsconfig.json +16 -0
  64. package/connectors/connect-deepseek/.env.example +11 -0
  65. package/connectors/connect-deepseek/CLAUDE.md +128 -0
  66. package/connectors/connect-deepseek/README.md +193 -0
  67. package/connectors/connect-deepseek/package.json +51 -0
  68. package/connectors/connect-deepseek/src/api/client.ts +108 -0
  69. package/connectors/connect-deepseek/src/api/index.ts +36 -0
  70. package/connectors/connect-deepseek/src/cli/index.ts +167 -0
  71. package/connectors/connect-deepseek/src/index.ts +19 -0
  72. package/connectors/connect-deepseek/src/types/index.ts +72 -0
  73. package/connectors/connect-deepseek/src/utils/config.ts +103 -0
  74. package/connectors/connect-deepseek/src/utils/output.ts +119 -0
  75. package/connectors/connect-deepseek/tsconfig.json +16 -0
  76. package/connectors/connect-fal/.env.example +11 -0
  77. package/connectors/connect-fal/CLAUDE.md +128 -0
  78. package/connectors/connect-fal/README.md +193 -0
  79. package/connectors/connect-fal/package.json +51 -0
  80. package/connectors/connect-fal/src/api/client.ts +172 -0
  81. package/connectors/connect-fal/src/api/index.ts +55 -0
  82. package/connectors/connect-fal/src/cli/index.ts +341 -0
  83. package/connectors/connect-fal/src/index.ts +19 -0
  84. package/connectors/connect-fal/src/types/index.ts +135 -0
  85. package/connectors/connect-fal/src/utils/config.ts +103 -0
  86. package/connectors/connect-fal/src/utils/output.ts +119 -0
  87. package/connectors/connect-fal/tsconfig.json +16 -0
  88. package/connectors/connect-fireworks/.env.example +11 -0
  89. package/connectors/connect-fireworks/CLAUDE.md +128 -0
  90. package/connectors/connect-fireworks/README.md +193 -0
  91. package/connectors/connect-fireworks/package.json +51 -0
  92. package/connectors/connect-fireworks/src/api/client.ts +63 -0
  93. package/connectors/connect-fireworks/src/api/index.ts +36 -0
  94. package/connectors/connect-fireworks/src/cli/index.ts +244 -0
  95. package/connectors/connect-fireworks/src/index.ts +19 -0
  96. package/connectors/connect-fireworks/src/types/index.ts +70 -0
  97. package/connectors/connect-fireworks/src/utils/config.ts +103 -0
  98. package/connectors/connect-fireworks/src/utils/output.ts +119 -0
  99. package/connectors/connect-fireworks/tsconfig.json +16 -0
  100. package/connectors/connect-groq/.env.example +11 -0
  101. package/connectors/connect-groq/CLAUDE.md +128 -0
  102. package/connectors/connect-groq/README.md +193 -0
  103. package/connectors/connect-groq/package.json +52 -0
  104. package/connectors/connect-groq/src/api/client.ts +108 -0
  105. package/connectors/connect-groq/src/api/index.ts +36 -0
  106. package/connectors/connect-groq/src/cli/index.ts +171 -0
  107. package/connectors/connect-groq/src/index.ts +19 -0
  108. package/connectors/connect-groq/src/types/index.ts +69 -0
  109. package/connectors/connect-groq/src/utils/config.ts +103 -0
  110. package/connectors/connect-groq/src/utils/output.ts +119 -0
  111. package/connectors/connect-groq/tsconfig.json +16 -0
  112. package/connectors/connect-luma/.env.example +11 -0
  113. package/connectors/connect-luma/CLAUDE.md +128 -0
  114. package/connectors/connect-luma/README.md +193 -0
  115. package/connectors/connect-luma/package.json +53 -0
  116. package/connectors/connect-luma/src/api/client.ts +85 -0
  117. package/connectors/connect-luma/src/api/index.ts +44 -0
  118. package/connectors/connect-luma/src/cli/index.ts +300 -0
  119. package/connectors/connect-luma/src/index.ts +19 -0
  120. package/connectors/connect-luma/src/types/index.ts +60 -0
  121. package/connectors/connect-luma/src/utils/config.ts +103 -0
  122. package/connectors/connect-luma/src/utils/output.ts +119 -0
  123. package/connectors/connect-luma/tsconfig.json +16 -0
  124. package/connectors/connect-modal/.env.example +11 -0
  125. package/connectors/connect-modal/CLAUDE.md +128 -0
  126. package/connectors/connect-modal/README.md +193 -0
  127. package/connectors/connect-modal/package.json +51 -0
  128. package/connectors/connect-modal/src/api/client.ts +119 -0
  129. package/connectors/connect-modal/src/api/index.ts +69 -0
  130. package/connectors/connect-modal/src/cli/index.ts +224 -0
  131. package/connectors/connect-modal/src/index.ts +21 -0
  132. package/connectors/connect-modal/src/types/index.ts +60 -0
  133. package/connectors/connect-modal/src/utils/config.ts +114 -0
  134. package/connectors/connect-modal/src/utils/output.ts +119 -0
  135. package/connectors/connect-modal/tsconfig.json +16 -0
  136. package/connectors/connect-perplexity/.env.example +4 -0
  137. package/connectors/connect-perplexity/CLAUDE.md +156 -0
  138. package/connectors/connect-perplexity/README.md +184 -0
  139. package/connectors/connect-perplexity/package.json +58 -0
  140. package/connectors/connect-perplexity/scripts/publish.ts +210 -0
  141. package/connectors/connect-perplexity/src/api/client.ts +119 -0
  142. package/connectors/connect-perplexity/src/api/example.ts +118 -0
  143. package/connectors/connect-perplexity/src/api/index.ts +48 -0
  144. package/connectors/connect-perplexity/src/cli/index.ts +421 -0
  145. package/connectors/connect-perplexity/src/index.ts +24 -0
  146. package/connectors/connect-perplexity/src/types/index.ts +140 -0
  147. package/connectors/connect-perplexity/src/utils/config.ts +208 -0
  148. package/connectors/connect-perplexity/src/utils/output.ts +119 -0
  149. package/connectors/connect-perplexity/tsconfig.json +16 -0
  150. package/connectors/connect-replicate/.env.example +11 -0
  151. package/connectors/connect-replicate/CLAUDE.md +128 -0
  152. package/connectors/connect-replicate/README.md +193 -0
  153. package/connectors/connect-replicate/package.json +51 -0
  154. package/connectors/connect-replicate/src/api/client.ts +109 -0
  155. package/connectors/connect-replicate/src/api/index.ts +71 -0
  156. package/connectors/connect-replicate/src/cli/index.ts +250 -0
  157. package/connectors/connect-replicate/src/index.ts +19 -0
  158. package/connectors/connect-replicate/src/types/index.ts +85 -0
  159. package/connectors/connect-replicate/src/utils/config.ts +103 -0
  160. package/connectors/connect-replicate/src/utils/output.ts +119 -0
  161. package/connectors/connect-replicate/tsconfig.json +16 -0
  162. package/connectors/connect-roboflow/.env.example +11 -0
  163. package/connectors/connect-roboflow/CLAUDE.md +272 -0
  164. package/connectors/connect-roboflow/README.md +193 -0
  165. package/connectors/connect-roboflow/package.json +51 -0
  166. package/connectors/connect-roboflow/scripts/release.ts +179 -0
  167. package/connectors/connect-roboflow/src/api/client.ts +213 -0
  168. package/connectors/connect-roboflow/src/api/example.ts +48 -0
  169. package/connectors/connect-roboflow/src/api/index.ts +51 -0
  170. package/connectors/connect-roboflow/src/cli/index.ts +254 -0
  171. package/connectors/connect-roboflow/src/index.ts +103 -0
  172. package/connectors/connect-roboflow/src/types/index.ts +237 -0
  173. package/connectors/connect-roboflow/src/utils/auth.ts +274 -0
  174. package/connectors/connect-roboflow/src/utils/bulk.ts +212 -0
  175. package/connectors/connect-roboflow/src/utils/config.ts +326 -0
  176. package/connectors/connect-roboflow/src/utils/output.ts +175 -0
  177. package/connectors/connect-roboflow/src/utils/settings.ts +114 -0
  178. package/connectors/connect-roboflow/src/utils/storage.ts +198 -0
  179. package/connectors/connect-roboflow/tsconfig.json +16 -0
  180. package/connectors/connect-runway/.env.example +11 -0
  181. package/connectors/connect-runway/CLAUDE.md +128 -0
  182. package/connectors/connect-runway/README.md +193 -0
  183. package/connectors/connect-runway/package.json +52 -0
  184. package/connectors/connect-runway/src/api/client.ts +78 -0
  185. package/connectors/connect-runway/src/api/index.ts +40 -0
  186. package/connectors/connect-runway/src/cli/index.ts +283 -0
  187. package/connectors/connect-runway/src/index.ts +19 -0
  188. package/connectors/connect-runway/src/types/index.ts +52 -0
  189. package/connectors/connect-runway/src/utils/config.ts +103 -0
  190. package/connectors/connect-runway/src/utils/output.ts +119 -0
  191. package/connectors/connect-runway/tsconfig.json +16 -0
  192. package/connectors/connect-together/.env.example +11 -0
  193. package/connectors/connect-together/CLAUDE.md +128 -0
  194. package/connectors/connect-together/README.md +193 -0
  195. package/connectors/connect-together/package.json +52 -0
  196. package/connectors/connect-together/src/api/client.ts +106 -0
  197. package/connectors/connect-together/src/api/index.ts +47 -0
  198. package/connectors/connect-together/src/cli/index.ts +228 -0
  199. package/connectors/connect-together/src/index.ts +19 -0
  200. package/connectors/connect-together/src/types/index.ts +91 -0
  201. package/connectors/connect-together/src/utils/config.ts +142 -0
  202. package/connectors/connect-together/src/utils/output.ts +119 -0
  203. package/connectors/connect-together/tsconfig.json +16 -0
  204. package/dist/index.js +112 -0
  205. package/package.json +1 -1
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@hasna/connect-replicate",
3
+ "version": "0.0.1",
4
+ "description": "Replicate connector CLI - Run ML models in the cloud with multi-profile support",
5
+ "type": "module",
6
+ "bin": {
7
+ "connect-replicate": "./bin/index.js"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "scripts": {
18
+ "build": "bun build ./src/index.ts --outdir ./dist --target bun && bun build ./src/cli/index.ts --outdir ./bin --target bun",
19
+ "dev": "bun run ./src/cli/index.ts",
20
+ "typecheck": "tsc --noEmit",
21
+ "prepublishOnly": "bun run build"
22
+ },
23
+ "keywords": [
24
+ "replicate",
25
+ "ai",
26
+ "ml",
27
+ "api",
28
+ "connector",
29
+ "cli",
30
+ "typescript",
31
+ "bun",
32
+ "machine-learning"
33
+ ],
34
+ "author": "Hasna",
35
+ "license": "Apache-2.0",
36
+ "devDependencies": {
37
+ "@types/bun": "latest",
38
+ "typescript": "^5"
39
+ },
40
+ "dependencies": {
41
+ "commander": "^12.1.0",
42
+ "chalk": "^5.3.0"
43
+ },
44
+ "engines": {
45
+ "bun": ">=1.0.0"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/hasna/connectors.git"
50
+ }
51
+ }
@@ -0,0 +1,109 @@
1
+ import type { ReplicateConfig } from '../types';
2
+ import { ReplicateApiError } from '../types';
3
+
4
+ const DEFAULT_BASE_URL = 'https://api.replicate.com/v1';
5
+
6
+ export interface RequestOptions {
7
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
8
+ params?: Record<string, string | number | boolean | undefined>;
9
+ body?: Record<string, unknown> | unknown[] | string;
10
+ headers?: Record<string, string>;
11
+ }
12
+
13
+ export class ReplicateClient {
14
+ private readonly apiKey: string;
15
+ private readonly baseUrl: string;
16
+
17
+ constructor(config: ReplicateConfig) {
18
+ if (!config.apiKey) {
19
+ throw new Error('API key is required');
20
+ }
21
+ this.apiKey = config.apiKey;
22
+ this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
23
+ }
24
+
25
+ private buildUrl(path: string, params?: Record<string, string | number | boolean | undefined>): string {
26
+ const url = new URL(`${this.baseUrl}${path}`);
27
+ if (params) {
28
+ Object.entries(params).forEach(([key, value]) => {
29
+ if (value !== undefined && value !== null && value !== '') {
30
+ url.searchParams.append(key, String(value));
31
+ }
32
+ });
33
+ }
34
+ return url.toString();
35
+ }
36
+
37
+ async request<T>(path: string, options: RequestOptions = {}): Promise<T> {
38
+ const { method = 'GET', params, body, headers = {} } = options;
39
+ const url = this.buildUrl(path, params);
40
+
41
+ // Replicate uses Token auth instead of Bearer
42
+ const requestHeaders: Record<string, string> = {
43
+ 'Authorization': `Token ${this.apiKey}`,
44
+ 'Accept': 'application/json',
45
+ ...headers,
46
+ };
47
+
48
+ if (body && ['POST', 'PUT', 'PATCH'].includes(method)) {
49
+ requestHeaders['Content-Type'] = 'application/json';
50
+ }
51
+
52
+ const fetchOptions: RequestInit = {
53
+ method,
54
+ headers: requestHeaders,
55
+ };
56
+
57
+ if (body && ['POST', 'PUT', 'PATCH'].includes(method)) {
58
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
59
+ }
60
+
61
+ const response = await fetch(url, fetchOptions);
62
+
63
+ if (response.status === 204) {
64
+ return {} as T;
65
+ }
66
+
67
+ let data: unknown;
68
+ const contentType = response.headers.get('content-type') || '';
69
+
70
+ if (contentType.includes('application/json')) {
71
+ const text = await response.text();
72
+ if (text) {
73
+ try {
74
+ data = JSON.parse(text);
75
+ } catch {
76
+ data = text;
77
+ }
78
+ }
79
+ } else {
80
+ data = await response.text();
81
+ }
82
+
83
+ if (!response.ok) {
84
+ let errorMessage = String(data || response.statusText);
85
+ if (typeof data === 'object' && data !== null) {
86
+ const errorObj = data as { detail?: string; error?: string; message?: string };
87
+ errorMessage = errorObj.detail || errorObj.error || errorObj.message || JSON.stringify(data);
88
+ }
89
+ throw new ReplicateApiError(errorMessage, response.status);
90
+ }
91
+
92
+ return data as T;
93
+ }
94
+
95
+ async get<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T> {
96
+ return this.request<T>(path, { method: 'GET', params });
97
+ }
98
+
99
+ async post<T>(path: string, body?: Record<string, unknown> | unknown[] | string | object): Promise<T> {
100
+ return this.request<T>(path, { method: 'POST', body: body as Record<string, unknown> });
101
+ }
102
+
103
+ getApiKeyPreview(): string {
104
+ if (this.apiKey.length > 10) {
105
+ return `${this.apiKey.substring(0, 6)}...${this.apiKey.substring(this.apiKey.length - 4)}`;
106
+ }
107
+ return '***';
108
+ }
109
+ }
@@ -0,0 +1,71 @@
1
+ import type {
2
+ ReplicateConfig,
3
+ ReplicateModel,
4
+ ModelsListResponse,
5
+ Prediction,
6
+ PredictionsListResponse,
7
+ CreatePredictionRequest
8
+ } from '../types';
9
+ import { ReplicateClient } from './client';
10
+
11
+ export class Replicate {
12
+ private readonly client: ReplicateClient;
13
+
14
+ constructor(config: ReplicateConfig) {
15
+ this.client = new ReplicateClient(config);
16
+ }
17
+
18
+ static fromEnv(): Replicate {
19
+ const apiKey = process.env.REPLICATE_API_TOKEN;
20
+ if (!apiKey) {
21
+ throw new Error('REPLICATE_API_TOKEN environment variable is required');
22
+ }
23
+ return new Replicate({ apiKey });
24
+ }
25
+
26
+ getApiKeyPreview(): string {
27
+ return this.client.getApiKeyPreview();
28
+ }
29
+
30
+ async getModel(owner: string, name: string): Promise<ReplicateModel> {
31
+ return this.client.get<ReplicateModel>(`/models/${owner}/${name}`);
32
+ }
33
+
34
+ async listModels(cursor?: string): Promise<ModelsListResponse> {
35
+ return this.client.get<ModelsListResponse>('/models', { cursor });
36
+ }
37
+
38
+ async createPrediction(request: CreatePredictionRequest): Promise<Prediction> {
39
+ return this.client.post<Prediction>('/predictions', request);
40
+ }
41
+
42
+ async getPrediction(id: string): Promise<Prediction> {
43
+ return this.client.get<Prediction>(`/predictions/${id}`);
44
+ }
45
+
46
+ async listPredictions(cursor?: string): Promise<PredictionsListResponse> {
47
+ return this.client.get<PredictionsListResponse>('/predictions', { cursor });
48
+ }
49
+
50
+ async cancelPrediction(id: string): Promise<Prediction> {
51
+ return this.client.post<Prediction>(`/predictions/${id}/cancel`);
52
+ }
53
+
54
+ async waitForPrediction(id: string, maxWaitMs = 300000, pollIntervalMs = 1000): Promise<Prediction> {
55
+ const startTime = Date.now();
56
+ while (Date.now() - startTime < maxWaitMs) {
57
+ const prediction = await this.getPrediction(id);
58
+ if (['succeeded', 'failed', 'canceled'].includes(prediction.status)) {
59
+ return prediction;
60
+ }
61
+ await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
62
+ }
63
+ throw new Error(`Prediction ${id} did not complete within ${maxWaitMs}ms`);
64
+ }
65
+
66
+ getClient(): ReplicateClient {
67
+ return this.client;
68
+ }
69
+ }
70
+
71
+ export { ReplicateClient } from './client';
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env bun
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import { Replicate } from '../api';
5
+ import {
6
+ getApiKey, setApiKey, clearConfig, getConfigDir, setProfileOverride,
7
+ getCurrentProfile, setCurrentProfile, listProfiles, createProfile,
8
+ deleteProfile, profileExists, loadProfile,
9
+ } from '../utils/config';
10
+ import type { OutputFormat } from '../utils/output';
11
+ import { success, error, info, print } from '../utils/output';
12
+
13
+ const CONNECTOR_NAME = 'connect-replicate';
14
+ const VERSION = '0.0.1';
15
+
16
+ const program = new Command();
17
+
18
+ program
19
+ .name(CONNECTOR_NAME)
20
+ .description('Replicate connector CLI - Run ML models in the cloud')
21
+ .version(VERSION)
22
+ .option('-f, --format <format>', 'Output format (json, pretty)', 'pretty')
23
+ .option('-p, --profile <profile>', 'Use a specific profile')
24
+ .hook('preAction', (thisCommand) => {
25
+ const opts = thisCommand.opts();
26
+ if (opts.profile) {
27
+ if (!profileExists(opts.profile)) {
28
+ error(`Profile "${opts.profile}" does not exist`);
29
+ process.exit(1);
30
+ }
31
+ setProfileOverride(opts.profile);
32
+ }
33
+ });
34
+
35
+ function getFormat(cmd: Command): OutputFormat {
36
+ const parent = cmd.parent;
37
+ return (parent?.opts().format || 'pretty') as OutputFormat;
38
+ }
39
+
40
+ function getClient(): Replicate {
41
+ const apiKey = getApiKey();
42
+ if (!apiKey) {
43
+ error(`No API token configured. Run "${CONNECTOR_NAME} config set-key <token>" or set REPLICATE_API_TOKEN`);
44
+ process.exit(1);
45
+ }
46
+ return new Replicate({ apiKey });
47
+ }
48
+
49
+ // Profile Commands
50
+ const profileCmd = program.command('profile').description('Manage profiles');
51
+
52
+ profileCmd.command('list').description('List profiles').action(() => {
53
+ const profiles = listProfiles();
54
+ const current = getCurrentProfile();
55
+ if (profiles.length === 0) { info('No profiles found'); return; }
56
+ profiles.forEach(p => {
57
+ console.log(` ${p}${p === current ? chalk.green(' (active)') : ''}`);
58
+ });
59
+ });
60
+
61
+ profileCmd.command('use <name>').description('Switch profile').action((name: string) => {
62
+ if (!profileExists(name)) { error(`Profile "${name}" does not exist`); process.exit(1); }
63
+ setCurrentProfile(name);
64
+ success(`Switched to profile: ${name}`);
65
+ });
66
+
67
+ profileCmd.command('create <name>').description('Create profile')
68
+ .option('--api-key <key>', 'API token')
69
+ .option('--use', 'Switch to this profile')
70
+ .action((name: string, opts) => {
71
+ if (profileExists(name)) { error(`Profile "${name}" already exists`); process.exit(1); }
72
+ createProfile(name, { apiKey: opts.apiKey });
73
+ success(`Profile "${name}" created`);
74
+ if (opts.use) { setCurrentProfile(name); info(`Switched to profile: ${name}`); }
75
+ });
76
+
77
+ profileCmd.command('delete <name>').description('Delete profile').action((name: string) => {
78
+ if (name === 'default') { error('Cannot delete default profile'); process.exit(1); }
79
+ if (deleteProfile(name)) { success(`Profile "${name}" deleted`); }
80
+ else { error(`Profile "${name}" not found`); process.exit(1); }
81
+ });
82
+
83
+ profileCmd.command('show [name]').description('Show profile').action((name?: string) => {
84
+ const profileName = name || getCurrentProfile();
85
+ const config = loadProfile(profileName);
86
+ console.log(chalk.bold(`Profile: ${profileName}`));
87
+ info(`API Token: ${config.apiKey ? config.apiKey.substring(0, 8) + '...' : chalk.gray('not set')}`);
88
+ });
89
+
90
+ // Config Commands
91
+ const configCmd = program.command('config').description('Manage configuration');
92
+
93
+ configCmd.command('set-key <apiToken>').description('Set API token').action((apiToken: string) => {
94
+ setApiKey(apiToken);
95
+ success(`API token saved`);
96
+ });
97
+
98
+ configCmd.command('show').description('Show config').action(() => {
99
+ console.log(chalk.bold(`Profile: ${getCurrentProfile()}`));
100
+ info(`Config dir: ${getConfigDir()}`);
101
+ const apiKey = getApiKey();
102
+ info(`API Token: ${apiKey ? apiKey.substring(0, 8) + '...' : chalk.gray('not set')}`);
103
+ });
104
+
105
+ configCmd.command('clear').description('Clear config').action(() => {
106
+ clearConfig();
107
+ success('Config cleared');
108
+ });
109
+
110
+ // Models Commands
111
+ const modelsCmd = program.command('models').description('Manage models');
112
+
113
+ modelsCmd.command('get <owner> <name>')
114
+ .description('Get a model')
115
+ .action(async (owner: string, name: string) => {
116
+ try {
117
+ const client = getClient();
118
+ const result = await client.getModel(owner, name);
119
+ if (getFormat(modelsCmd) === 'json') {
120
+ print(result, 'json');
121
+ } else {
122
+ console.log(chalk.cyan(`\n${result.owner}/${result.name}`));
123
+ if (result.description) console.log(` ${result.description}`);
124
+ console.log(` Visibility: ${result.visibility}`);
125
+ if (result.run_count) console.log(` Runs: ${result.run_count.toLocaleString()}`);
126
+ if (result.latest_version) console.log(` Latest version: ${result.latest_version.id}`);
127
+ }
128
+ } catch (err) {
129
+ error(String(err));
130
+ process.exit(1);
131
+ }
132
+ });
133
+
134
+ modelsCmd.command('list')
135
+ .description('List models')
136
+ .action(async () => {
137
+ try {
138
+ const client = getClient();
139
+ const result = await client.listModels();
140
+ if (getFormat(modelsCmd) === 'json') {
141
+ print(result.results, 'json');
142
+ } else {
143
+ result.results.forEach(m => {
144
+ console.log(chalk.cyan(`\n${m.owner}/${m.name}`));
145
+ if (m.description) console.log(` ${m.description.substring(0, 80)}${m.description.length > 80 ? '...' : ''}`);
146
+ });
147
+ }
148
+ } catch (err) {
149
+ error(String(err));
150
+ process.exit(1);
151
+ }
152
+ });
153
+
154
+ // Predictions Commands
155
+ const predictCmd = program.command('predict').description('Manage predictions');
156
+
157
+ predictCmd.command('create <version>')
158
+ .description('Create a prediction')
159
+ .requiredOption('-i, --input <json>', 'Input JSON')
160
+ .option('--wait', 'Wait for prediction to complete')
161
+ .action(async (version: string, opts) => {
162
+ try {
163
+ const client = getClient();
164
+ const input = JSON.parse(opts.input);
165
+ const prediction = await client.createPrediction({ version, input });
166
+
167
+ if (opts.wait) {
168
+ info(`Waiting for prediction ${prediction.id}...`);
169
+ const result = await client.waitForPrediction(prediction.id);
170
+ if (getFormat(predictCmd) === 'json') {
171
+ print(result, 'json');
172
+ } else {
173
+ console.log(chalk.cyan(`\nPrediction ${result.id}`));
174
+ console.log(` Status: ${result.status}`);
175
+ if (result.output) console.log(` Output: ${JSON.stringify(result.output)}`);
176
+ if (result.error) console.log(chalk.red(` Error: ${result.error}`));
177
+ }
178
+ } else {
179
+ if (getFormat(predictCmd) === 'json') {
180
+ print(prediction, 'json');
181
+ } else {
182
+ success(`Prediction created: ${prediction.id}`);
183
+ console.log(` Status: ${prediction.status}`);
184
+ console.log(` Get status: ${CONNECTOR_NAME} predict get ${prediction.id}`);
185
+ }
186
+ }
187
+ } catch (err) {
188
+ error(String(err));
189
+ process.exit(1);
190
+ }
191
+ });
192
+
193
+ predictCmd.command('get <id>')
194
+ .description('Get a prediction')
195
+ .action(async (id: string) => {
196
+ try {
197
+ const client = getClient();
198
+ const result = await client.getPrediction(id);
199
+ if (getFormat(predictCmd) === 'json') {
200
+ print(result, 'json');
201
+ } else {
202
+ console.log(chalk.cyan(`\nPrediction ${result.id}`));
203
+ console.log(` Status: ${result.status}`);
204
+ console.log(` Created: ${result.created_at}`);
205
+ if (result.completed_at) console.log(` Completed: ${result.completed_at}`);
206
+ if (result.output) console.log(` Output: ${JSON.stringify(result.output)}`);
207
+ if (result.error) console.log(chalk.red(` Error: ${result.error}`));
208
+ if (result.metrics?.predict_time) console.log(` Predict time: ${result.metrics.predict_time.toFixed(2)}s`);
209
+ }
210
+ } catch (err) {
211
+ error(String(err));
212
+ process.exit(1);
213
+ }
214
+ });
215
+
216
+ predictCmd.command('list')
217
+ .description('List predictions')
218
+ .action(async () => {
219
+ try {
220
+ const client = getClient();
221
+ const result = await client.listPredictions();
222
+ if (getFormat(predictCmd) === 'json') {
223
+ print(result.results, 'json');
224
+ } else {
225
+ result.results.forEach(p => {
226
+ console.log(chalk.cyan(`\n${p.id}`));
227
+ console.log(` Status: ${p.status}`);
228
+ console.log(` Created: ${p.created_at}`);
229
+ });
230
+ }
231
+ } catch (err) {
232
+ error(String(err));
233
+ process.exit(1);
234
+ }
235
+ });
236
+
237
+ predictCmd.command('cancel <id>')
238
+ .description('Cancel a prediction')
239
+ .action(async (id: string) => {
240
+ try {
241
+ const client = getClient();
242
+ await client.cancelPrediction(id);
243
+ success(`Prediction ${id} canceled`);
244
+ } catch (err) {
245
+ error(String(err));
246
+ process.exit(1);
247
+ }
248
+ });
249
+
250
+ program.parse();
@@ -0,0 +1,19 @@
1
+ // Replicate Connector
2
+ // TypeScript wrapper for Replicate API
3
+
4
+ export { Replicate } from './api';
5
+ export * from './types';
6
+ export { ReplicateClient } from './api';
7
+
8
+ export {
9
+ getApiKey,
10
+ setApiKey,
11
+ getCurrentProfile,
12
+ setCurrentProfile,
13
+ listProfiles,
14
+ createProfile,
15
+ deleteProfile,
16
+ loadProfile,
17
+ saveProfile,
18
+ clearConfig,
19
+ } from './utils/config';
@@ -0,0 +1,85 @@
1
+ // Replicate API Types
2
+
3
+ export interface ReplicateConfig {
4
+ apiKey: string;
5
+ baseUrl?: string;
6
+ }
7
+
8
+ // Model Types
9
+ export interface ReplicateModel {
10
+ url: string;
11
+ owner: string;
12
+ name: string;
13
+ description?: string;
14
+ visibility: string;
15
+ github_url?: string;
16
+ paper_url?: string;
17
+ license_url?: string;
18
+ run_count?: number;
19
+ cover_image_url?: string;
20
+ default_example?: object;
21
+ latest_version?: ModelVersion;
22
+ }
23
+
24
+ export interface ModelVersion {
25
+ id: string;
26
+ created_at: string;
27
+ cog_version?: string;
28
+ openapi_schema?: object;
29
+ }
30
+
31
+ export interface ModelsListResponse {
32
+ results: ReplicateModel[];
33
+ next?: string;
34
+ previous?: string;
35
+ }
36
+
37
+ // Prediction Types
38
+ export interface PredictionInput {
39
+ [key: string]: unknown;
40
+ }
41
+
42
+ export interface CreatePredictionRequest {
43
+ version: string;
44
+ input: PredictionInput;
45
+ webhook?: string;
46
+ webhook_events_filter?: string[];
47
+ }
48
+
49
+ export interface Prediction {
50
+ id: string;
51
+ version: string;
52
+ status: 'starting' | 'processing' | 'succeeded' | 'failed' | 'canceled';
53
+ input: PredictionInput;
54
+ output?: unknown;
55
+ error?: string;
56
+ logs?: string;
57
+ metrics?: {
58
+ predict_time?: number;
59
+ };
60
+ created_at: string;
61
+ started_at?: string;
62
+ completed_at?: string;
63
+ urls: {
64
+ get: string;
65
+ cancel: string;
66
+ };
67
+ }
68
+
69
+ export interface PredictionsListResponse {
70
+ results: Prediction[];
71
+ next?: string;
72
+ previous?: string;
73
+ }
74
+
75
+ // Error Types
76
+ export class ReplicateApiError extends Error {
77
+ constructor(
78
+ message: string,
79
+ public readonly status: number,
80
+ public readonly detail?: string
81
+ ) {
82
+ super(message);
83
+ this.name = 'ReplicateApiError';
84
+ }
85
+ }
@@ -0,0 +1,103 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join } from 'path';
4
+
5
+ const CONNECTOR_NAME = 'connect-replicate';
6
+ const DEFAULT_PROFILE = 'default';
7
+
8
+ export interface ProfileConfig {
9
+ apiKey?: string;
10
+ }
11
+
12
+ let profileOverride: string | undefined;
13
+
14
+ const CONFIG_DIR = join(homedir(), '.connect', CONNECTOR_NAME);
15
+ const PROFILES_DIR = join(CONFIG_DIR, 'profiles');
16
+ const CURRENT_PROFILE_FILE = join(CONFIG_DIR, 'current_profile');
17
+
18
+ export function setProfileOverride(profile: string | undefined): void {
19
+ profileOverride = profile;
20
+ }
21
+
22
+ export function ensureConfigDir(): void {
23
+ if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
24
+ if (!existsSync(PROFILES_DIR)) mkdirSync(PROFILES_DIR, { recursive: true });
25
+ }
26
+
27
+ function getProfilePath(profile: string): string {
28
+ return join(PROFILES_DIR, `${profile}.json`);
29
+ }
30
+
31
+ export function getCurrentProfile(): string {
32
+ if (profileOverride) return profileOverride;
33
+ ensureConfigDir();
34
+ if (existsSync(CURRENT_PROFILE_FILE)) {
35
+ try {
36
+ const profile = readFileSync(CURRENT_PROFILE_FILE, 'utf-8').trim();
37
+ if (profile && profileExists(profile)) return profile;
38
+ } catch { /* fall through */ }
39
+ }
40
+ return DEFAULT_PROFILE;
41
+ }
42
+
43
+ export function setCurrentProfile(profile: string): void {
44
+ ensureConfigDir();
45
+ if (!profileExists(profile) && profile !== DEFAULT_PROFILE) {
46
+ throw new Error(`Profile "${profile}" does not exist`);
47
+ }
48
+ writeFileSync(CURRENT_PROFILE_FILE, profile);
49
+ }
50
+
51
+ export function profileExists(profile: string): boolean {
52
+ return existsSync(getProfilePath(profile));
53
+ }
54
+
55
+ export function listProfiles(): string[] {
56
+ ensureConfigDir();
57
+ if (!existsSync(PROFILES_DIR)) return [];
58
+ return readdirSync(PROFILES_DIR).filter(f => f.endsWith('.json')).map(f => f.replace('.json', '')).sort();
59
+ }
60
+
61
+ export function createProfile(profile: string, config: ProfileConfig = {}): boolean {
62
+ ensureConfigDir();
63
+ if (profileExists(profile)) return false;
64
+ if (!/^[a-zA-Z0-9_-]+$/.test(profile)) {
65
+ throw new Error('Profile name can only contain letters, numbers, hyphens, and underscores');
66
+ }
67
+ writeFileSync(getProfilePath(profile), JSON.stringify(config, null, 2));
68
+ return true;
69
+ }
70
+
71
+ export function deleteProfile(profile: string): boolean {
72
+ if (profile === DEFAULT_PROFILE) return false;
73
+ if (!profileExists(profile)) return false;
74
+ if (getCurrentProfile() === profile) setCurrentProfile(DEFAULT_PROFILE);
75
+ rmSync(getProfilePath(profile));
76
+ return true;
77
+ }
78
+
79
+ export function loadProfile(profile?: string): ProfileConfig {
80
+ ensureConfigDir();
81
+ const profilePath = getProfilePath(profile || getCurrentProfile());
82
+ if (!existsSync(profilePath)) return {};
83
+ try { return JSON.parse(readFileSync(profilePath, 'utf-8')); } catch { return {}; }
84
+ }
85
+
86
+ export function saveProfile(config: ProfileConfig, profile?: string): void {
87
+ ensureConfigDir();
88
+ writeFileSync(getProfilePath(profile || getCurrentProfile()), JSON.stringify(config, null, 2));
89
+ }
90
+
91
+ export function getApiKey(): string | undefined {
92
+ return process.env.REPLICATE_API_TOKEN || loadProfile().apiKey;
93
+ }
94
+
95
+ export function setApiKey(apiKey: string): void {
96
+ const config = loadProfile();
97
+ config.apiKey = apiKey;
98
+ saveProfile(config);
99
+ }
100
+
101
+ export function clearConfig(): void { saveProfile({}); }
102
+ export function getConfigDir(): string { return CONFIG_DIR; }
103
+ export function getActiveProfileName(): string { return getCurrentProfile(); }