twelveai 0.3.1 → 0.4.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.
- package/README.md +37 -0
- package/dist/chunk-6RZKLIGP.js +248 -0
- package/dist/cli.cjs +471 -0
- package/dist/cli.d.cts +13 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +204 -0
- package/dist/client-C5vzks2N.d.cts +325 -0
- package/dist/client-C5vzks2N.d.ts +325 -0
- package/dist/index.cjs +85 -6
- package/dist/index.d.cts +2 -201
- package/dist/index.d.ts +2 -201
- package/dist/index.js +5 -166
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,203 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
interface TwelveAIOptions {
|
|
3
|
-
/** Your workspace API key (sk_live_... / sk_test_...). */
|
|
4
|
-
apiKey: string;
|
|
5
|
-
/** Engine base URL. Defaults to the hosted platform. */
|
|
6
|
-
baseUrl?: string;
|
|
7
|
-
/**
|
|
8
|
-
* Auth your server adds when the SDK performs client-fetch hand-offs against
|
|
9
|
-
* YOUR OWN API (the engine hands the resolved request back without any
|
|
10
|
-
* credentials). Static headers, or a function returning them per request.
|
|
11
|
-
*/
|
|
12
|
-
clientAuth?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
13
|
-
/** Custom fetch implementation (tests, polyfills). Defaults to global fetch. */
|
|
14
|
-
fetch?: typeof globalThis.fetch;
|
|
15
|
-
/** Max auto-resume rounds for client-fetch hand-offs per chat() call. Default 3. */
|
|
16
|
-
maxHandoffRounds?: number;
|
|
17
|
-
}
|
|
18
|
-
interface Attachment {
|
|
19
|
-
/** Public URL, or a data: URL. */
|
|
20
|
-
url?: string;
|
|
21
|
-
/** Base64 content (alternative to url). */
|
|
22
|
-
data?: string;
|
|
23
|
-
mediaType?: string;
|
|
24
|
-
/** A WhatsApp media id, if the engine should fetch it via your connected WhatsApp. */
|
|
25
|
-
whatsappMediaId?: string;
|
|
26
|
-
}
|
|
27
|
-
interface ChatInput {
|
|
28
|
-
/** The end user's message. Optional when resuming or sending only attachments. */
|
|
29
|
-
message?: string;
|
|
30
|
-
/** Your id for this end user (alias: userId). Required for customer-scoped agents. */
|
|
31
|
-
customerId?: string;
|
|
32
|
-
/** Continue an existing conversation with the token from the previous turn. */
|
|
33
|
-
continuation?: string;
|
|
34
|
-
/** The user approved a pending action (PIN/OTP collected on your side). */
|
|
35
|
-
confirmed?: boolean;
|
|
36
|
-
/** Sandbox: tools return sample data; nothing real is called or moved. */
|
|
37
|
-
sandbox?: boolean;
|
|
38
|
-
channel?: string;
|
|
39
|
-
/** Force a specific agent instead of routing. */
|
|
40
|
-
intent?: string;
|
|
41
|
-
/** Customer tier to sync for this turn's caps. */
|
|
42
|
-
tier?: string;
|
|
43
|
-
/**
|
|
44
|
-
* Short-lived end-user session token, forwarded verbatim on tool bindings
|
|
45
|
-
* with auth type 'customer_token'. Never stored by the engine.
|
|
46
|
-
*/
|
|
47
|
-
customerToken?: string;
|
|
48
|
-
/** Images / voice notes attached to this turn. */
|
|
49
|
-
attachments?: Attachment[];
|
|
50
|
-
metadata?: Record<string, unknown>;
|
|
51
|
-
}
|
|
52
|
-
interface ToolCall {
|
|
53
|
-
name: string;
|
|
54
|
-
arguments: Record<string, unknown>;
|
|
55
|
-
result: unknown;
|
|
56
|
-
}
|
|
57
|
-
interface HandoffRequest {
|
|
58
|
-
method: string;
|
|
59
|
-
url: string;
|
|
60
|
-
headers?: Record<string, string>;
|
|
61
|
-
body?: Record<string, unknown>;
|
|
62
|
-
}
|
|
63
|
-
interface PendingToolCall {
|
|
64
|
-
id: string;
|
|
65
|
-
name: string;
|
|
66
|
-
arguments: Record<string, unknown>;
|
|
67
|
-
/** Client-fetch hand-off: the resolved request your server should perform. */
|
|
68
|
-
request?: HandoffRequest;
|
|
69
|
-
}
|
|
70
|
-
interface ToolResult {
|
|
71
|
-
id: string;
|
|
72
|
-
result: unknown;
|
|
73
|
-
}
|
|
74
|
-
interface ChatResponse {
|
|
75
|
-
ok: boolean;
|
|
76
|
-
sandbox?: boolean;
|
|
77
|
-
/** The assistant's reply to show the user. */
|
|
78
|
-
message: string | null;
|
|
79
|
-
intent: string | null;
|
|
80
|
-
toolCalls: ToolCall[];
|
|
81
|
-
/** A write awaiting the user's confirmation (resend with confirmed: true). */
|
|
82
|
-
pendingConfirmation: {
|
|
83
|
-
tool: string;
|
|
84
|
-
arguments: Record<string, unknown>;
|
|
85
|
-
} | null;
|
|
86
|
-
/**
|
|
87
|
-
* Client-executed tool calls YOUR system must run. With auto-execution on
|
|
88
|
-
* (the default), read hand-offs are already completed by the SDK; anything
|
|
89
|
-
* left here is yours to handle (typically a money move awaiting PIN).
|
|
90
|
-
*/
|
|
91
|
-
pendingToolCalls: PendingToolCall[] | null;
|
|
92
|
-
/** Pass this back on the next turn to continue the conversation. */
|
|
93
|
-
continuation: string | null;
|
|
94
|
-
escalated?: boolean;
|
|
95
|
-
policy?: string | null;
|
|
96
|
-
autonomy?: string | null;
|
|
97
|
-
fee?: {
|
|
98
|
-
feeNgn: number;
|
|
99
|
-
amountNgn: number;
|
|
100
|
-
totalNgn: number;
|
|
101
|
-
} | null;
|
|
102
|
-
usage?: {
|
|
103
|
-
inputTokens: number;
|
|
104
|
-
outputTokens: number;
|
|
105
|
-
};
|
|
106
|
-
billing?: Record<string, unknown>;
|
|
107
|
-
latencyMs?: number;
|
|
108
|
-
metadata?: Record<string, unknown>;
|
|
109
|
-
error?: string;
|
|
110
|
-
/** HTTP status of the underlying call. */
|
|
111
|
-
status: number;
|
|
112
|
-
/** Hand-offs the SDK auto-executed to complete this turn (for observability). */
|
|
113
|
-
executedHandoffs?: Array<{
|
|
114
|
-
name: string;
|
|
115
|
-
method: string;
|
|
116
|
-
url: string;
|
|
117
|
-
ok: boolean;
|
|
118
|
-
}>;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Executor for one client-fetch hand-off. Return the tool result the engine
|
|
122
|
-
* resumes with. The default executor performs `call.request` with your
|
|
123
|
-
* `clientAuth` headers and returns `{ ok, data }`.
|
|
124
|
-
*/
|
|
125
|
-
type HandoffExecutor = (call: PendingToolCall) => Promise<unknown>;
|
|
126
|
-
interface ClassifyResponse {
|
|
127
|
-
ok: boolean;
|
|
128
|
-
/** The winning agent intent, or null when nothing matched. */
|
|
129
|
-
intent: string | null;
|
|
130
|
-
label: string | null;
|
|
131
|
-
/** Deterministic confidence in [0, 0.95]; 0 = no match. */
|
|
132
|
-
confidence: number;
|
|
133
|
-
alternatives: Array<{
|
|
134
|
-
intent: string;
|
|
135
|
-
label: string;
|
|
136
|
-
}>;
|
|
137
|
-
/** Cheap extracted entities: amount, account_number, phone (when present). */
|
|
138
|
-
entities: Record<string, unknown>;
|
|
139
|
-
status: number;
|
|
140
|
-
error?: string;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* The TwelveAI client. One call does the whole conversation protocol:
|
|
145
|
-
*
|
|
146
|
-
* const twelve = new TwelveAI({ apiKey: process.env.TWELVE_API_KEY! })
|
|
147
|
-
* const res = await twelve.chat({ message: "what's my balance?", customerId: 'cus_123' })
|
|
148
|
-
* console.log(res.message)
|
|
149
|
-
*
|
|
150
|
-
* Client-fetch hand-offs (tools configured as "my app calls it") are executed
|
|
151
|
-
* automatically against your own API - the engine never holds your credentials;
|
|
152
|
-
* you supply them once via `clientAuth` and the SDK completes the loop. Money
|
|
153
|
-
* moves are never auto-executed: they surface in `pendingToolCalls` /
|
|
154
|
-
* `pendingConfirmation` for your PIN flow, then you call `confirm()` or
|
|
155
|
-
* `resume()`.
|
|
156
|
-
*/
|
|
157
|
-
declare class TwelveAI {
|
|
158
|
-
private readonly apiKey;
|
|
159
|
-
private readonly baseUrl;
|
|
160
|
-
private readonly fetchImpl;
|
|
161
|
-
private readonly clientAuth;
|
|
162
|
-
private readonly maxHandoffRounds;
|
|
163
|
-
constructor(options: TwelveAIOptions);
|
|
164
|
-
/**
|
|
165
|
-
* Send one chat turn and return the completed result. Read hand-offs are
|
|
166
|
-
* auto-executed (see class docs); pass `autoExecute: false` to get the raw
|
|
167
|
-
* paused response instead, or `onHandoff` to execute them yourself.
|
|
168
|
-
*/
|
|
169
|
-
chat(input: ChatInput, opts?: {
|
|
170
|
-
autoExecute?: boolean;
|
|
171
|
-
onHandoff?: HandoffExecutor;
|
|
172
|
-
}): Promise<ChatResponse>;
|
|
173
|
-
/** Resume a paused turn with tool results your system produced. */
|
|
174
|
-
resume(continuation: string, toolResults: ToolResult[], input?: Pick<ChatInput, 'customerId' | 'channel' | 'sandbox' | 'customerToken'>): Promise<ChatResponse>;
|
|
175
|
-
/**
|
|
176
|
-
* Approve a pending action (after your PIN/OTP step) - resends the turn with
|
|
177
|
-
* `confirmed: true` so the engine proceeds.
|
|
178
|
-
*/
|
|
179
|
-
confirm(continuation: string, input?: Omit<ChatInput, 'continuation' | 'confirmed'>): Promise<ChatResponse>;
|
|
180
|
-
/**
|
|
181
|
-
* Level-0 integration: classify a message WITHOUT running the conversation.
|
|
182
|
-
* Returns the intent, a deterministic confidence score, and cheap extracted
|
|
183
|
-
* entities (amount / account number / phone) - you keep your existing flows
|
|
184
|
-
* and make the call yourself. Free: no tools run, nothing is stored.
|
|
185
|
-
*/
|
|
186
|
-
classify(input: {
|
|
187
|
-
message: string;
|
|
188
|
-
}): Promise<ClassifyResponse>;
|
|
189
|
-
private chatBody;
|
|
190
|
-
private post;
|
|
191
|
-
/**
|
|
192
|
-
* Execute client-fetch hand-offs and resume until the turn completes. Only
|
|
193
|
-
* calls that carry a resolved `request` are auto-executed - a hand-off
|
|
194
|
-
* without one (e.g. a money move awaiting your PIN flow) stops the loop and
|
|
195
|
-
* is returned to you untouched.
|
|
196
|
-
*/
|
|
197
|
-
private completeHandoffs;
|
|
198
|
-
/** Default hand-off executor: perform the request with your clientAuth headers. */
|
|
199
|
-
private performHandoff;
|
|
200
|
-
}
|
|
1
|
+
export { A as Attachment, B as BindToolInput, C as ChatInput, a as ChatResponse, b as ClassifyResponse, c as CreateAgentInput, d as CreateToolInput, H as HandoffExecutor, e as HandoffRequest, M as Manage, f as ManageResult, P as PendingToolCall, g as ToolCall, h as ToolResult, T as TwelveAI, i as TwelveAIOptions, j as buildManage } from './client-C5vzks2N.js';
|
|
201
2
|
|
|
202
3
|
/** Verify a TwelveAI webhook delivery: the x-webhook-secret header must match your secret. */
|
|
203
4
|
declare function verifyWebhook(secret: string, headers: Record<string, string | string[] | undefined>): boolean;
|
|
@@ -252,4 +53,4 @@ declare function createJwksVerifier(options?: JwksVerifierOptions): (input: JwtR
|
|
|
252
53
|
claims?: Record<string, unknown>;
|
|
253
54
|
}>;
|
|
254
55
|
|
|
255
|
-
export { type
|
|
56
|
+
export { type JwksVerifierOptions, type JwtRequestInput, type SignedRequestInput, createJwksVerifier, verifySignedRequest, verifyWebhook };
|
package/dist/index.js
CHANGED
|
@@ -1,169 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
baseUrl;
|
|
6
|
-
fetchImpl;
|
|
7
|
-
clientAuth;
|
|
8
|
-
maxHandoffRounds;
|
|
9
|
-
constructor(options) {
|
|
10
|
-
if (!options?.apiKey) throw new Error("TwelveAI: apiKey is required.");
|
|
11
|
-
this.apiKey = options.apiKey;
|
|
12
|
-
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
13
|
-
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
14
|
-
this.clientAuth = options.clientAuth;
|
|
15
|
-
this.maxHandoffRounds = options.maxHandoffRounds ?? 3;
|
|
16
|
-
if (typeof this.fetchImpl !== "function") {
|
|
17
|
-
throw new Error("TwelveAI: global fetch is unavailable - pass options.fetch (Node 18+ has fetch built in).");
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Send one chat turn and return the completed result. Read hand-offs are
|
|
22
|
-
* auto-executed (see class docs); pass `autoExecute: false` to get the raw
|
|
23
|
-
* paused response instead, or `onHandoff` to execute them yourself.
|
|
24
|
-
*/
|
|
25
|
-
async chat(input, opts = {}) {
|
|
26
|
-
let res = await this.post("/v1/chat", this.chatBody(input));
|
|
27
|
-
if (opts.autoExecute === false) return res;
|
|
28
|
-
return this.completeHandoffs(res, input, opts.onHandoff);
|
|
29
|
-
}
|
|
30
|
-
/** Resume a paused turn with tool results your system produced. */
|
|
31
|
-
async resume(continuation, toolResults, input = {}) {
|
|
32
|
-
return this.post("/v1/chat", { ...this.chatBody(input), continuation, toolResults });
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Approve a pending action (after your PIN/OTP step) - resends the turn with
|
|
36
|
-
* `confirmed: true` so the engine proceeds.
|
|
37
|
-
*/
|
|
38
|
-
async confirm(continuation, input = {}) {
|
|
39
|
-
return this.chat({ message: "yes", ...input, continuation, confirmed: true });
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Level-0 integration: classify a message WITHOUT running the conversation.
|
|
43
|
-
* Returns the intent, a deterministic confidence score, and cheap extracted
|
|
44
|
-
* entities (amount / account number / phone) - you keep your existing flows
|
|
45
|
-
* and make the call yourself. Free: no tools run, nothing is stored.
|
|
46
|
-
*/
|
|
47
|
-
async classify(input) {
|
|
48
|
-
try {
|
|
49
|
-
const res = await this.fetchImpl(`${this.baseUrl}/v1/classify`, {
|
|
50
|
-
method: "POST",
|
|
51
|
-
headers: { "content-type": "application/json", "x-api-key": this.apiKey },
|
|
52
|
-
body: JSON.stringify({ message: input.message })
|
|
53
|
-
});
|
|
54
|
-
const data = await res.json().catch(() => ({}));
|
|
55
|
-
return {
|
|
56
|
-
ok: res.ok && data.ok !== false,
|
|
57
|
-
intent: data.intent ?? null,
|
|
58
|
-
label: data.label ?? null,
|
|
59
|
-
confidence: data.confidence ?? 0,
|
|
60
|
-
alternatives: data.alternatives ?? [],
|
|
61
|
-
entities: data.entities ?? {},
|
|
62
|
-
status: res.status,
|
|
63
|
-
...res.ok ? {} : { error: data.error ?? `Engine returned ${res.status}` }
|
|
64
|
-
};
|
|
65
|
-
} catch (error) {
|
|
66
|
-
return { ok: false, intent: null, label: null, confidence: 0, alternatives: [], entities: {}, status: 0, error: error?.message || "Could not reach the engine." };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/* ------------------------------ internals ------------------------------ */
|
|
70
|
-
chatBody(input) {
|
|
71
|
-
const body = {};
|
|
72
|
-
if (input.message !== void 0) body.message = input.message;
|
|
73
|
-
if (input.customerId !== void 0) body.customerId = input.customerId;
|
|
74
|
-
if (input.continuation) body.continuation = input.continuation;
|
|
75
|
-
if (input.confirmed !== void 0) body.confirmed = input.confirmed;
|
|
76
|
-
if (input.sandbox !== void 0) body.sandbox = input.sandbox;
|
|
77
|
-
if (input.channel) body.channel = input.channel;
|
|
78
|
-
if (input.intent) body.intent = input.intent;
|
|
79
|
-
if (input.tier) body.tier = input.tier;
|
|
80
|
-
if (input.customerToken) body.customerToken = input.customerToken;
|
|
81
|
-
if (input.attachments?.length) body.attachments = input.attachments;
|
|
82
|
-
if (input.metadata) body.metadata = input.metadata;
|
|
83
|
-
return body;
|
|
84
|
-
}
|
|
85
|
-
async post(path, body) {
|
|
86
|
-
try {
|
|
87
|
-
const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
88
|
-
method: "POST",
|
|
89
|
-
headers: { "content-type": "application/json", "x-api-key": this.apiKey },
|
|
90
|
-
body: JSON.stringify(body)
|
|
91
|
-
});
|
|
92
|
-
const data = await res.json().catch(() => ({}));
|
|
93
|
-
return {
|
|
94
|
-
ok: res.ok && data.ok !== false,
|
|
95
|
-
message: data.message ?? null,
|
|
96
|
-
intent: data.intent ?? null,
|
|
97
|
-
toolCalls: data.toolCalls ?? [],
|
|
98
|
-
pendingConfirmation: data.pendingConfirmation ?? null,
|
|
99
|
-
pendingToolCalls: data.pendingToolCalls ?? null,
|
|
100
|
-
continuation: data.continuation ?? null,
|
|
101
|
-
...data,
|
|
102
|
-
status: res.status,
|
|
103
|
-
...res.ok ? {} : { error: data.error ?? `Engine returned ${res.status}` }
|
|
104
|
-
};
|
|
105
|
-
} catch (error) {
|
|
106
|
-
return {
|
|
107
|
-
ok: false,
|
|
108
|
-
status: 0,
|
|
109
|
-
message: null,
|
|
110
|
-
intent: null,
|
|
111
|
-
toolCalls: [],
|
|
112
|
-
pendingConfirmation: null,
|
|
113
|
-
pendingToolCalls: null,
|
|
114
|
-
continuation: null,
|
|
115
|
-
error: error?.message || "Could not reach the engine."
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Execute client-fetch hand-offs and resume until the turn completes. Only
|
|
121
|
-
* calls that carry a resolved `request` are auto-executed - a hand-off
|
|
122
|
-
* without one (e.g. a money move awaiting your PIN flow) stops the loop and
|
|
123
|
-
* is returned to you untouched.
|
|
124
|
-
*/
|
|
125
|
-
async completeHandoffs(res, input, onHandoff) {
|
|
126
|
-
const executed = [];
|
|
127
|
-
for (let round = 0; round < this.maxHandoffRounds; round++) {
|
|
128
|
-
const calls = res.pendingToolCalls ?? [];
|
|
129
|
-
if (!calls.length || !res.continuation) break;
|
|
130
|
-
if (!calls.every((c) => c.request?.url)) break;
|
|
131
|
-
const results = [];
|
|
132
|
-
for (const call of calls) {
|
|
133
|
-
const result = onHandoff ? await onHandoff(call) : await this.performHandoff(call);
|
|
134
|
-
executed.push({
|
|
135
|
-
name: call.name,
|
|
136
|
-
method: call.request.method,
|
|
137
|
-
url: call.request.url,
|
|
138
|
-
ok: result?.ok !== false
|
|
139
|
-
});
|
|
140
|
-
results.push({ id: call.id, result });
|
|
141
|
-
}
|
|
142
|
-
const next = await this.resume(res.continuation, results, input);
|
|
143
|
-
if (next.error) break;
|
|
144
|
-
res = next;
|
|
145
|
-
}
|
|
146
|
-
if (executed.length) res.executedHandoffs = executed;
|
|
147
|
-
return res;
|
|
148
|
-
}
|
|
149
|
-
/** Default hand-off executor: perform the request with your clientAuth headers. */
|
|
150
|
-
async performHandoff(call) {
|
|
151
|
-
const req = call.request;
|
|
152
|
-
try {
|
|
153
|
-
const extra = typeof this.clientAuth === "function" ? await this.clientAuth() : this.clientAuth ?? {};
|
|
154
|
-
const res = await this.fetchImpl(req.url, {
|
|
155
|
-
method: req.method,
|
|
156
|
-
headers: { "content-type": "application/json", ...req.headers ?? {}, ...extra },
|
|
157
|
-
...req.body !== void 0 ? { body: JSON.stringify(req.body) } : {}
|
|
158
|
-
});
|
|
159
|
-
const body = await res.json().catch(() => ({}));
|
|
160
|
-
if (!res.ok) return { ok: false, error: `Endpoint returned ${res.status}` };
|
|
161
|
-
return { ok: true, data: body.data ?? body };
|
|
162
|
-
} catch (error) {
|
|
163
|
-
return { ok: false, error: error?.message || "Request failed." };
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
TwelveAI,
|
|
3
|
+
buildManage
|
|
4
|
+
} from "./chunk-6RZKLIGP.js";
|
|
167
5
|
|
|
168
6
|
// src/verify.ts
|
|
169
7
|
import { createHash, createHmac, createPublicKey, createVerify, timingSafeEqual } from "crypto";
|
|
@@ -238,6 +76,7 @@ function header(headers, name) {
|
|
|
238
76
|
}
|
|
239
77
|
export {
|
|
240
78
|
TwelveAI,
|
|
79
|
+
buildManage,
|
|
241
80
|
createJwksVerifier,
|
|
242
81
|
verifySignedRequest,
|
|
243
82
|
verifyWebhook
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twelveai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Official SDK for TwelveAI - AI infrastructure for conversational banking. One call runs the whole chat protocol: routing, grounded tool calls, client-fetch hand-offs, confirmations, and request verification.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "TwelveAI",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"node": ">=18"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
|
-
"build": "tsup src/index.ts src/mcp.ts --format esm,cjs --dts --clean",
|
|
41
|
+
"build": "tsup src/index.ts src/mcp.ts src/cli.ts --format esm,cjs --dts --clean",
|
|
42
42
|
"test": "vitest run",
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
44
44
|
"prepublishOnly": "npm run typecheck && npm run test && npm run build"
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"access": "public"
|
|
57
57
|
},
|
|
58
58
|
"bin": {
|
|
59
|
-
"twelveai-mcp": "./dist/mcp.js"
|
|
59
|
+
"twelveai-mcp": "./dist/mcp.js",
|
|
60
|
+
"twelveai": "./dist/cli.js"
|
|
60
61
|
}
|
|
61
62
|
}
|