@signaliz/sdk 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # @signaliz/sdk
2
+
3
+ The official Signaliz SDK for JavaScript/TypeScript — GTM intelligence for AI agents.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @signaliz/sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { Signaliz } from '@signaliz/sdk';
15
+
16
+ const signaliz = new Signaliz({
17
+ apiKey: process.env.SIGNALIZ_API_KEY,
18
+ });
19
+
20
+ // Find and verify an email
21
+ const email = await signaliz.emails.find({
22
+ fullName: 'Jane Smith',
23
+ companyDomain: 'stripe.com',
24
+ });
25
+ console.log(email);
26
+ // → { email: 'jane.smith@stripe.com', verificationStatus: 'valid', confidence: 0.95 }
27
+
28
+ // Verify an email
29
+ const result = await signaliz.emails.verify('jane@stripe.com');
30
+ // → { isValid: true, isDeliverable: true, isCatchAll: false, confidenceScore: 0.98 }
31
+
32
+ // Company signals
33
+ const signals = await signaliz.signals.enrich({
34
+ companyName: 'Stripe',
35
+ researchPrompt: 'Find recent hiring activities',
36
+ });
37
+
38
+ // Systems (pipelines)
39
+ const system = await signaliz.systems.create({
40
+ name: 'Email Pipeline',
41
+ capabilities: ['mcp_input', 'find_emails_with_verification', 'mcp_output'],
42
+ });
43
+ const run = await signaliz.systems.run(system.id, { data: [...] });
44
+
45
+ // Stream progress
46
+ for await (const event of signaliz.runs.stream(run.runId)) {
47
+ console.log(`${event.completedRows}/${event.totalRows} — ${event.status}`);
48
+ }
49
+
50
+ // HTTP proxy
51
+ const response = await signaliz.http.request({
52
+ url: 'https://api.example.com/data',
53
+ method: 'GET',
54
+ });
55
+ ```
56
+
57
+ ## MCP Setup
58
+
59
+ Connect Signaliz to your AI agent in one command:
60
+
61
+ ```bash
62
+ npx @signaliz/mcp
63
+ ```
64
+
65
+ ## Authentication
66
+
67
+ ### API Key (simplest)
68
+ ```typescript
69
+ const signaliz = new Signaliz({ apiKey: 'sk_...' });
70
+ ```
71
+
72
+ ### M2M OAuth
73
+ ```typescript
74
+ const signaliz = new Signaliz({
75
+ clientId: process.env.SIGNALIZ_CLIENT_ID,
76
+ clientSecret: process.env.SIGNALIZ_CLIENT_SECRET,
77
+ });
78
+ ```
79
+
80
+ ## Error Handling
81
+
82
+ ```typescript
83
+ import { Signaliz, SignalizError } from '@signaliz/sdk';
84
+
85
+ try {
86
+ await signaliz.emails.find({ fullName: 'Test', companyDomain: 'example.com' });
87
+ } catch (e) {
88
+ if (e instanceof SignalizError) {
89
+ console.log(e.errorType); // 'rate_limited' | 'validation' | 'timeout' | ...
90
+ console.log(e.retryAfter); // seconds to wait (for 429s)
91
+ console.log(e.isRetryable); // boolean
92
+ }
93
+ }
94
+ ```
95
+
96
+ ## License
97
+
98
+ MIT
@@ -0,0 +1,543 @@
1
+ // src/errors.ts
2
+ var SignalizError = class extends Error {
3
+ constructor(data) {
4
+ super(data.message);
5
+ this.name = "SignalizError";
6
+ this.code = data.code;
7
+ this.errorType = data.errorType;
8
+ this.retryAfter = data.retryAfter;
9
+ this.details = data.details;
10
+ }
11
+ get isRetryable() {
12
+ return this.errorType === "rate_limited" || this.errorType === "timeout" || this.errorType === "provider_error";
13
+ }
14
+ };
15
+ function parseError(status, body) {
16
+ if (body?.error && typeof body.error === "object") {
17
+ return new SignalizError({
18
+ code: body.error.code || `HTTP_${status}`,
19
+ message: body.error.message || `Request failed with status ${status}`,
20
+ errorType: mapErrorType(body.error.code, status),
21
+ retryAfter: body.error.retry_after,
22
+ details: body.error.details
23
+ });
24
+ }
25
+ return new SignalizError({
26
+ code: `HTTP_${status}`,
27
+ message: body?.message || body?.error || `Request failed with status ${status}`,
28
+ errorType: mapErrorType(void 0, status)
29
+ });
30
+ }
31
+ function mapErrorType(code, status) {
32
+ if (code === "RATE_LIMITED" || status === 429) return "rate_limited";
33
+ if (code === "VALIDATION_ERROR" || status === 400) return "validation";
34
+ if (code === "NOT_FOUND" || status === 404) return "not_found";
35
+ if (code === "AUTH_EXPIRED" || status === 401) return "auth_expired";
36
+ if (code === "INSUFFICIENT_CREDITS" || status === 402) return "insufficient_credits";
37
+ if (code === "TIMEOUT" || status === 504) return "timeout";
38
+ if (status >= 500) return "provider_error";
39
+ return "unknown";
40
+ }
41
+
42
+ // src/client.ts
43
+ var DEFAULT_BASE_URL = "https://api.signaliz.com/functions/v1";
44
+ var DEFAULT_TIMEOUT = 12e4;
45
+ var DEFAULT_MAX_RETRIES = 3;
46
+ var HttpClient = class {
47
+ constructor(config) {
48
+ this.baseUrl = config.baseUrl?.replace(/\/$/, "") || DEFAULT_BASE_URL;
49
+ this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
50
+ this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
51
+ this.apiKey = config.apiKey;
52
+ this.clientId = config.clientId;
53
+ this.clientSecret = config.clientSecret;
54
+ if (!this.apiKey && !(this.clientId && this.clientSecret)) {
55
+ throw new Error("Signaliz: provide either apiKey or clientId + clientSecret");
56
+ }
57
+ }
58
+ async request(functionName, body, method = "POST") {
59
+ let lastError;
60
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
61
+ try {
62
+ const token = await this.getToken();
63
+ const url = `${this.baseUrl}/${functionName}`;
64
+ const controller = new AbortController();
65
+ const timer = setTimeout(() => controller.abort(), this.timeout);
66
+ const init = {
67
+ method,
68
+ headers: {
69
+ "Content-Type": "application/json",
70
+ Authorization: `Bearer ${token}`
71
+ },
72
+ signal: controller.signal
73
+ };
74
+ if (method === "POST") {
75
+ init.body = JSON.stringify(body);
76
+ }
77
+ const res = await fetch(url, init);
78
+ clearTimeout(timer);
79
+ if (!res.ok) {
80
+ const errBody = await res.json().catch(() => ({}));
81
+ const err = parseError(res.status, errBody);
82
+ if (err.isRetryable && attempt < this.maxRetries) {
83
+ const wait = err.retryAfter ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4);
84
+ await sleep(wait);
85
+ lastError = err;
86
+ continue;
87
+ }
88
+ throw err;
89
+ }
90
+ return await res.json();
91
+ } catch (e) {
92
+ if (e instanceof SignalizError) throw e;
93
+ if (e.name === "AbortError") {
94
+ const timeout = new SignalizError({
95
+ code: "TIMEOUT",
96
+ message: `Request timed out after ${this.timeout}ms`,
97
+ errorType: "timeout"
98
+ });
99
+ if (attempt < this.maxRetries) {
100
+ lastError = timeout;
101
+ await sleep(1e3 * Math.pow(2, attempt));
102
+ continue;
103
+ }
104
+ throw timeout;
105
+ }
106
+ lastError = e;
107
+ if (attempt < this.maxRetries) {
108
+ await sleep(1e3 * Math.pow(2, attempt));
109
+ continue;
110
+ }
111
+ }
112
+ }
113
+ throw lastError || new Error("Request failed after retries");
114
+ }
115
+ /** Convenience wrapper for POST-based edge function calls */
116
+ async post(functionName, body) {
117
+ return this.request(functionName, body, "POST");
118
+ }
119
+ /** JSON-RPC call to the MCP server */
120
+ async mcp(method, params = {}) {
121
+ const token = await this.getToken();
122
+ const url = `${this.baseUrl}/signaliz-mcp`;
123
+ const res = await fetch(url, {
124
+ method: "POST",
125
+ headers: {
126
+ "Content-Type": "application/json",
127
+ Authorization: `Bearer ${token}`
128
+ },
129
+ body: JSON.stringify({
130
+ jsonrpc: "2.0",
131
+ id: Date.now(),
132
+ method,
133
+ params
134
+ })
135
+ });
136
+ const data = await res.json();
137
+ if (data.error) {
138
+ throw new SignalizError({
139
+ code: data.error.code?.toString() || "MCP_ERROR",
140
+ message: data.error.message || "MCP request failed",
141
+ errorType: "unknown"
142
+ });
143
+ }
144
+ if (data.result?.content?.[0]?.text) {
145
+ try {
146
+ return JSON.parse(data.result.content[0].text);
147
+ } catch {
148
+ return data.result.content[0].text;
149
+ }
150
+ }
151
+ if (data.result?.structuredContent) {
152
+ return data.result.structuredContent;
153
+ }
154
+ return data.result;
155
+ }
156
+ async getToken() {
157
+ if (this.apiKey) return this.apiKey;
158
+ if (this.accessToken) return this.accessToken;
159
+ const res = await fetch("https://api.signaliz.com/token", {
160
+ method: "POST",
161
+ headers: { "Content-Type": "application/json" },
162
+ body: JSON.stringify({
163
+ grant_type: "client_credentials",
164
+ client_id: this.clientId,
165
+ client_secret: this.clientSecret
166
+ })
167
+ });
168
+ if (!res.ok) {
169
+ throw new SignalizError({
170
+ code: "AUTH_FAILED",
171
+ message: "Failed to obtain access token",
172
+ errorType: "auth_expired"
173
+ });
174
+ }
175
+ const data = await res.json();
176
+ this.accessToken = data.access_token;
177
+ return this.accessToken;
178
+ }
179
+ };
180
+ function sleep(ms) {
181
+ return new Promise((r) => setTimeout(r, ms));
182
+ }
183
+
184
+ // src/resources/emails.ts
185
+ var Emails = class {
186
+ constructor(client) {
187
+ this.client = client;
188
+ }
189
+ /** Find and verify an email address for a person at a company */
190
+ async find(params) {
191
+ const body = {
192
+ company_domain: params.companyDomain
193
+ };
194
+ if (params.fullName) body.full_name = params.fullName;
195
+ if (params.firstName) body.first_name = params.firstName;
196
+ if (params.lastName) body.last_name = params.lastName;
197
+ if (params.linkedinUrl) body.linkedin_url = params.linkedinUrl;
198
+ if (params.companyName) body.company_name = params.companyName;
199
+ const data = await this.client.mcp("tools/call", {
200
+ name: "find_emails_with_verification",
201
+ arguments: body
202
+ });
203
+ return {
204
+ email: data.email,
205
+ firstName: data.first_name,
206
+ lastName: data.last_name,
207
+ confidence: data.confidence ?? data.confidence_score ?? 0,
208
+ verificationStatus: data.verification_status ?? "unknown",
209
+ providerUsed: data.provider_used ?? data.source ?? "unknown"
210
+ };
211
+ }
212
+ /** Verify a single email address */
213
+ async verify(email) {
214
+ const data = await this.client.mcp("tools/call", {
215
+ name: "verify_email",
216
+ arguments: { email }
217
+ });
218
+ return {
219
+ email: data.email ?? email,
220
+ isValid: data.is_valid ?? false,
221
+ isDeliverable: data.is_deliverable ?? false,
222
+ isCatchAll: data.is_catch_all ?? false,
223
+ provider: data.provider,
224
+ confidenceScore: data.confidence_score ?? 0,
225
+ verificationSource: data.verification_source
226
+ };
227
+ }
228
+ };
229
+
230
+ // src/resources/signals.ts
231
+ var Signals = class {
232
+ constructor(client) {
233
+ this.client = client;
234
+ }
235
+ /** Enrich a company with actionable signals (V1) */
236
+ async enrich(params) {
237
+ const args = {
238
+ company_name: params.companyName
239
+ };
240
+ if (params.domain) args.domain = params.domain;
241
+ if (params.researchPrompt) args.research_prompt = params.researchPrompt;
242
+ if (params.signalTypes) args.signal_types = params.signalTypes;
243
+ const data = await this.client.mcp("tools/call", {
244
+ name: "enrich_company_signals",
245
+ arguments: args
246
+ });
247
+ return {
248
+ companyName: data.company_name ?? params.companyName,
249
+ signals: (data.signals ?? []).map((s) => ({
250
+ title: s.title,
251
+ signalType: s.signal_type,
252
+ confidenceScore: s.confidence_score ?? 0,
253
+ detectedAt: s.detected_at ?? "",
254
+ url: s.url,
255
+ content: s.content ?? ""
256
+ })),
257
+ totalSignals: data.total_signals ?? data.signals?.length ?? 0,
258
+ fromCache: data.from_cache ?? false
259
+ };
260
+ }
261
+ /** Enrich a company with actionable signals (V2 — clean response + online mode) */
262
+ async enrichV2(params) {
263
+ const args = {};
264
+ if (params.companyName) args.company_name = params.companyName;
265
+ if (params.domain) args.domain = params.domain;
266
+ if (params.companyDomain) args.company_domain = params.companyDomain;
267
+ if (params.researchPrompt) args.research_prompt = params.researchPrompt;
268
+ if (params.signalTypes) args.signal_types = params.signalTypes;
269
+ if (params.online !== void 0) args.online = params.online;
270
+ if (params.targetSignalCount) args.target_signal_count = params.targetSignalCount;
271
+ if (params.lookbackDays) args.lookback_days = params.lookbackDays;
272
+ if (params.model) args.model = params.model;
273
+ if (params.enableDeepSearch) args.enable_deep_search = params.enableDeepSearch;
274
+ if (params.enableOutreachIntelligence) args.enable_outreach_intelligence = params.enableOutreachIntelligence;
275
+ if (params.enablePredictiveIntelligence) args.enable_predictive_intelligence = params.enablePredictiveIntelligence;
276
+ if (params.icpId) args.icp_id = params.icpId;
277
+ if (params.cacheTtlHours !== void 0) args.cache_ttl_hours = params.cacheTtlHours;
278
+ if (params.skipCache) args.skip_cache = params.skipCache;
279
+ const data = await this.client.post("company-signal-enrichment-v2", args);
280
+ return {
281
+ success: data.success ?? false,
282
+ company: {
283
+ name: data.company?.name ?? null,
284
+ domain: data.company?.domain ?? null
285
+ },
286
+ signals: (data.signals ?? []).map((s) => ({
287
+ id: s.id,
288
+ title: s.title,
289
+ type: s.type,
290
+ content: s.content ?? "",
291
+ date: s.date ?? null,
292
+ sourceUrl: s.source_url ?? null,
293
+ sourceType: s.source_type ?? "unknown",
294
+ confidence: s.confidence ?? null
295
+ })),
296
+ signalCount: data.signal_count ?? 0,
297
+ intelligence: data.intelligence ? {
298
+ executiveSummary: data.intelligence.executive_summary ?? null,
299
+ keyThemes: data.intelligence.key_themes ?? [],
300
+ relevanceScore: data.intelligence.relevance_score ?? null,
301
+ outreach: data.intelligence.outreach ? {
302
+ urgencyScore: data.intelligence.outreach.urgency_score ?? null,
303
+ bestTiming: data.intelligence.outreach.best_timing ?? null,
304
+ primaryAngle: data.intelligence.outreach.primary_angle ?? null,
305
+ ctas: data.intelligence.outreach.ctas ? {
306
+ soft: data.intelligence.outreach.ctas.soft,
307
+ direct: data.intelligence.outreach.ctas.direct,
308
+ valueFirst: data.intelligence.outreach.ctas.value_first
309
+ } : null,
310
+ conversationStarters: data.intelligence.outreach.conversation_starters ?? []
311
+ } : null,
312
+ predictions: (data.intelligence.predictions ?? []).map((p) => ({
313
+ prediction: p.prediction,
314
+ confidence: p.confidence,
315
+ targetPersona: p.target_persona ?? null,
316
+ recommendedAction: p.recommended_action ?? null
317
+ }))
318
+ } : null,
319
+ credits: {
320
+ charged: data.credits?.charged ?? 0,
321
+ billingType: data.credits?.billing_type ?? "unknown",
322
+ breakdown: {
323
+ signalCredits: data.credits?.breakdown?.signal_credits ?? 0,
324
+ modelCostUsd: data.credits?.breakdown?.model_cost_usd ?? 0,
325
+ modelCredits: data.credits?.breakdown?.model_credits ?? 0,
326
+ explanation: data.credits?.breakdown?.explanation ?? ""
327
+ }
328
+ },
329
+ metadata: {
330
+ version: data.metadata?.version ?? "",
331
+ model: data.metadata?.model ?? "",
332
+ online: data.metadata?.online ?? false,
333
+ processingTimeMs: data.metadata?.processing_time_ms ?? 0
334
+ }
335
+ };
336
+ }
337
+ };
338
+
339
+ // src/resources/systems.ts
340
+ var Systems = class {
341
+ constructor(client) {
342
+ this.client = client;
343
+ }
344
+ /** Create a new pipeline/system */
345
+ async create(params) {
346
+ const data = await this.client.mcp("tools/call", {
347
+ name: "create_system",
348
+ arguments: {
349
+ name: params.name,
350
+ description: params.description,
351
+ capabilities: params.capabilities,
352
+ field_mappings: params.fieldMappings
353
+ }
354
+ });
355
+ return {
356
+ id: data.system_id ?? data.id,
357
+ name: data.name ?? params.name,
358
+ status: data.status ?? "created",
359
+ nodeCount: data.node_count ?? params.capabilities.length,
360
+ createdAt: data.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
361
+ };
362
+ }
363
+ /** Run a system with input data */
364
+ async run(systemId, params) {
365
+ const data = await this.client.mcp("tools/call", {
366
+ name: "run_system",
367
+ arguments: {
368
+ system_id: systemId,
369
+ input_data: params.data,
370
+ async: params.async ?? false
371
+ }
372
+ });
373
+ return {
374
+ runId: data.run_id ?? data.id,
375
+ status: data.status ?? "running",
376
+ totalRows: data.total_rows,
377
+ completedRows: data.completed_rows ?? 0,
378
+ creditsUsed: data.credits_used ?? 0
379
+ };
380
+ }
381
+ /** Get a system by ID */
382
+ async get(systemId) {
383
+ const data = await this.client.mcp("tools/call", {
384
+ name: "get_system",
385
+ arguments: { system_id: systemId }
386
+ });
387
+ return {
388
+ id: data.id ?? systemId,
389
+ name: data.name,
390
+ status: data.status,
391
+ nodeCount: data.node_count ?? 0,
392
+ createdAt: data.created_at
393
+ };
394
+ }
395
+ /** List all systems */
396
+ async list() {
397
+ const data = await this.client.mcp("tools/call", {
398
+ name: "list_systems",
399
+ arguments: {}
400
+ });
401
+ return (data.systems ?? data ?? []).map((s) => ({
402
+ id: s.id,
403
+ name: s.name,
404
+ status: s.status,
405
+ nodeCount: s.node_count ?? 0,
406
+ createdAt: s.created_at
407
+ }));
408
+ }
409
+ };
410
+
411
+ // src/resources/runs.ts
412
+ var Runs = class {
413
+ constructor(client) {
414
+ this.client = client;
415
+ }
416
+ /** Get run status */
417
+ async get(runId) {
418
+ const data = await this.client.mcp("tools/call", {
419
+ name: "get_run_results",
420
+ arguments: { run_id: runId }
421
+ });
422
+ return {
423
+ runId: data.run_id ?? runId,
424
+ status: data.status,
425
+ totalRows: data.total_rows,
426
+ completedRows: data.completed_rows ?? 0,
427
+ creditsUsed: data.credits_used ?? 0
428
+ };
429
+ }
430
+ /** Poll until a run completes. Returns final result. */
431
+ async waitForCompletion(runId, pollIntervalMs = 2e3) {
432
+ while (true) {
433
+ const run = await this.get(runId);
434
+ if (["completed", "failed", "cancelled", "crashed", "timed_out", "interrupted", "system_failure"].includes(run.status)) {
435
+ return run;
436
+ }
437
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
438
+ }
439
+ }
440
+ /**
441
+ * Stream run progress as an async iterator.
442
+ * Usage: for await (const event of signaliz.runs.stream(runId)) { ... }
443
+ */
444
+ async *stream(runId, pollIntervalMs = 1500) {
445
+ let lastCompleted = -1;
446
+ while (true) {
447
+ const run = await this.get(runId);
448
+ const event = {
449
+ runId,
450
+ status: run.status,
451
+ completedRows: run.completedRows ?? 0,
452
+ totalRows: run.totalRows ?? 0,
453
+ creditsUsed: run.creditsUsed ?? 0
454
+ };
455
+ if (event.completedRows !== lastCompleted) {
456
+ lastCompleted = event.completedRows;
457
+ yield event;
458
+ }
459
+ if (["completed", "failed", "cancelled"].includes(run.status)) {
460
+ return;
461
+ }
462
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
463
+ }
464
+ }
465
+ };
466
+
467
+ // src/resources/http.ts
468
+ var Http = class {
469
+ constructor(client) {
470
+ this.client = client;
471
+ }
472
+ /** Proxy an HTTP request through Signaliz */
473
+ async request(params) {
474
+ const data = await this.client.mcp("tools/call", {
475
+ name: "http_request",
476
+ arguments: {
477
+ url: params.url,
478
+ method: params.method,
479
+ headers: params.headers,
480
+ body: params.body ? JSON.stringify(params.body) : void 0
481
+ }
482
+ });
483
+ return {
484
+ statusCode: data.status_code ?? data.statusCode ?? 200,
485
+ headers: data.headers ?? {},
486
+ body: data.body ?? data.response ?? data
487
+ };
488
+ }
489
+ };
490
+
491
+ // src/index.ts
492
+ var Signaliz = class {
493
+ constructor(config) {
494
+ this.client = new HttpClient(config);
495
+ this.emails = new Emails(this.client);
496
+ this.signals = new Signals(this.client);
497
+ this.systems = new Systems(this.client);
498
+ this.runs = new Runs(this.client);
499
+ this.http = new Http(this.client);
500
+ }
501
+ /** Get current workspace info including credits */
502
+ async getWorkspace() {
503
+ const data = await this.client.mcp("tools/call", {
504
+ name: "get_workspace",
505
+ arguments: {}
506
+ });
507
+ return {
508
+ id: data.workspace_id ?? data.id,
509
+ name: data.workspace_name ?? data.name ?? "Unknown",
510
+ creditsRemaining: data.credits_remaining ?? data.credits ?? 0,
511
+ plan: data.plan ?? "unknown"
512
+ };
513
+ }
514
+ /** List all available MCP tools */
515
+ async listTools() {
516
+ const data = await this.client.mcp("tools/list", {});
517
+ const tools = data?.tools ?? data ?? [];
518
+ return tools.map((t) => ({
519
+ name: t.name,
520
+ description: (t.description ?? "").slice(0, 120),
521
+ category: t.annotations?.category,
522
+ costCredits: t.annotations?.cost_credits
523
+ }));
524
+ }
525
+ /** Discover tools by natural language query */
526
+ async discover(query, category) {
527
+ const data = await this.client.mcp("tools/call", {
528
+ name: "discover_capabilities",
529
+ arguments: { query, category }
530
+ });
531
+ return (data.matches ?? []).map((m) => ({
532
+ name: m.tool,
533
+ description: m.description,
534
+ category: m.category,
535
+ costCredits: m.cost_credits
536
+ }));
537
+ }
538
+ };
539
+
540
+ export {
541
+ SignalizError,
542
+ Signaliz
543
+ };
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node