crom-agente-sdk 0.1.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.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,66 @@
1
+ export interface CromClientOptions {
2
+ daemonHost?: string;
3
+ daemonPort?: number;
4
+ cloudUrl?: string;
5
+ sessionToken?: string;
6
+ daemonToken?: string;
7
+ onTokenRefreshNeeded?: () => Promise<string | null>;
8
+ onWebSocketClose?: (event: CloseEvent) => void;
9
+ onWebSocketError?: (event: Event) => void;
10
+ WebSocketConstructor?: any;
11
+ }
12
+ export declare class CromClient {
13
+ private options;
14
+ private ws;
15
+ private reconnectTimer;
16
+ private reconnectAttempts;
17
+ private maxReconnectAttempts;
18
+ private baseReconnectDelay;
19
+ private listeners;
20
+ private wsUrl;
21
+ constructor(options?: CromClientOptions);
22
+ updateOptions(options: Partial<CromClientOptions>): void;
23
+ getOptions(): Required<CromClientOptions>;
24
+ on(event: string, callback: (data: any) => void): () => void;
25
+ off(event: string, callback: (data: any) => void): void;
26
+ private emit;
27
+ buildDaemonUrl(path: string, params?: Record<string, string>): string;
28
+ private buildCloudUrl;
29
+ private getCloudHeaders;
30
+ getDaemonToken(): Promise<string>;
31
+ getSystemInfo(): Promise<any>;
32
+ getTags(): Promise<any>;
33
+ getTerminals(): Promise<any>;
34
+ closeTerminal(terminalId: string): Promise<any>;
35
+ stopDaemon(workspace?: string): Promise<any>;
36
+ getScheduledTasks(): Promise<any[]>;
37
+ addScheduledTask(task: {
38
+ name: string;
39
+ cron: string;
40
+ workspace: string;
41
+ task: string;
42
+ }): Promise<any>;
43
+ deleteScheduledTask(id: string): Promise<any>;
44
+ runScheduledTask(id: string): Promise<any>;
45
+ getScreenDevices(): Promise<any>;
46
+ getAudioDevices(): Promise<any>;
47
+ startRecording(type: "audio" | "screen", params?: Record<string, string>): Promise<any>;
48
+ stopRecording(type: "audio" | "screen"): Promise<Blob>;
49
+ transcribeAudio(audioBlob: Blob): Promise<{
50
+ text: string;
51
+ }>;
52
+ listFiles(dirPath: string): Promise<any[]>;
53
+ readFile(filePath: string): Promise<string>;
54
+ writeFile(filePath: string, content: string, encoding?: string): Promise<any>;
55
+ getCloudUser(): Promise<any>;
56
+ getCloudModels(): Promise<any>;
57
+ getLatestRelease(repo?: string): Promise<any>;
58
+ getOpenRouterModels(): Promise<any>;
59
+ connectWebSocket(workspacePath: string, activeSessionId?: string, initialPrompt?: string, defaultProvider?: string, defaultModel?: string): void;
60
+ private scheduleReconnect;
61
+ disconnectWebSocket(): void;
62
+ sendRun(workspacePath: string, sessionId: string, task: string, provider?: string, model?: string, autoApprove?: boolean): void;
63
+ sendStop(workspacePath: string): void;
64
+ sendAutoApprove(workspacePath: string, enabled: boolean): void;
65
+ sendPermissionResponse(workspacePath: string, approved: boolean): void;
66
+ }
@@ -0,0 +1,367 @@
1
+ var g = Object.defineProperty;
2
+ var S = (s, e, t) => e in s ? g(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
+ var u = (s, e, t) => S(s, typeof e != "symbol" ? e + "" : e, t);
4
+ function A(s) {
5
+ return s && typeof s.event == "string" && typeof s.timestamp == "string";
6
+ }
7
+ function U(s) {
8
+ return s && typeof s.type == "string" && !s.event;
9
+ }
10
+ const $ = {
11
+ ERR_LLM_RATE_LIMIT: "Aguarde o cooldown ou troque de provedor/chave.",
12
+ ERR_LLM_AUTHENTICATION: "Verifique e atualize sua chave de API nas configurações.",
13
+ ERR_LLM_EMPTY_RESPONSE: "O modelo retornou vazio. Tente novamente ou troque de modelo.",
14
+ ERR_TOOL_NOT_FOUND: "Ferramenta não registrada. Verifique as ferramentas disponíveis.",
15
+ ERR_TOOL_EXECUTION: "Erro na execução da ferramenta. Verifique os logs.",
16
+ ERR_TOOL_TIMEOUT: "A ferramenta excedeu o tempo limite. Aumente o timeout ou simplifique a operação.",
17
+ ERR_PERMISSION_DENIED: "A ação foi rejeitada. Altere as permissões ou aprove manualmente.",
18
+ ERR_SANDBOX_VIOLATION: "Tentativa de acessar recurso fora do sandbox do workspace.",
19
+ ERR_MAX_ITERATIONS: "O agente atingiu o limite de iterações. Aumente o limite ou simplifique a tarefa.",
20
+ ERR_CONSECUTIVE_FAILURES: "Muitas falhas consecutivas. Verifique a configuração e os logs.",
21
+ ERR_CONTEXT_CANCELED: "A execução foi cancelada pelo usuário ou pelo sistema."
22
+ };
23
+ function R(s) {
24
+ if (!s) return null;
25
+ if (typeof s == "string")
26
+ try {
27
+ return JSON.parse(s);
28
+ } catch {
29
+ return s;
30
+ }
31
+ if (typeof s == "object" && !Array.isArray(s)) {
32
+ const e = Object.keys(s);
33
+ if (!(e.length > 0 && e.every((o) => !isNaN(Number(o)))))
34
+ return s;
35
+ try {
36
+ const o = new Uint8Array(Object.values(s)), r = new TextDecoder().decode(o);
37
+ return JSON.parse(r);
38
+ } catch {
39
+ return s;
40
+ }
41
+ }
42
+ return s;
43
+ }
44
+ class v {
45
+ constructor(e = {}) {
46
+ u(this, "options");
47
+ u(this, "ws", null);
48
+ u(this, "reconnectTimer", null);
49
+ u(this, "reconnectAttempts", 0);
50
+ u(this, "maxReconnectAttempts", 5);
51
+ u(this, "baseReconnectDelay", 2e3);
52
+ u(this, "listeners", /* @__PURE__ */ new Map());
53
+ u(this, "wsUrl", "");
54
+ this.options = {
55
+ daemonHost: e.daemonHost || "127.0.0.1",
56
+ daemonPort: e.daemonPort || 9090,
57
+ cloudUrl: e.cloudUrl || "https://cloud.ia.crom.run",
58
+ sessionToken: e.sessionToken || "",
59
+ daemonToken: e.daemonToken || "",
60
+ onTokenRefreshNeeded: e.onTokenRefreshNeeded || (async () => null),
61
+ onWebSocketClose: e.onWebSocketClose || (() => {
62
+ }),
63
+ onWebSocketError: e.onWebSocketError || (() => {
64
+ }),
65
+ WebSocketConstructor: e.WebSocketConstructor || null
66
+ };
67
+ }
68
+ updateOptions(e) {
69
+ this.options = { ...this.options, ...e };
70
+ }
71
+ getOptions() {
72
+ return this.options;
73
+ }
74
+ // --- Listener management ---
75
+ on(e, t) {
76
+ return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(t), () => this.off(e, t);
77
+ }
78
+ off(e, t) {
79
+ const o = this.listeners.get(e);
80
+ o && o.delete(t);
81
+ }
82
+ emit(e, t) {
83
+ const o = this.listeners.get(e);
84
+ if (o)
85
+ for (const r of o)
86
+ try {
87
+ r(t);
88
+ } catch (i) {
89
+ console.error("Error in CromClient event listener:", i);
90
+ }
91
+ }
92
+ // --- HTTP Helpers ---
93
+ buildDaemonUrl(e, t = {}) {
94
+ const o = this.options.daemonHost, r = this.options.daemonPort, i = new URL(`http://${o}:${r}${e}`), d = this.options.daemonToken || this.options.sessionToken;
95
+ d && i.searchParams.set("token", d);
96
+ for (const [w, p] of Object.entries(t))
97
+ p != null && i.searchParams.set(w, p);
98
+ return i.toString();
99
+ }
100
+ buildCloudUrl(e) {
101
+ return `${this.options.cloudUrl.replace(/\/$/, "")}${e}`;
102
+ }
103
+ getCloudHeaders() {
104
+ const e = {};
105
+ return this.options.sessionToken && (e.Authorization = `Bearer ${this.options.sessionToken}`), e;
106
+ }
107
+ // --- HTTP REST API methods ---
108
+ async getDaemonToken() {
109
+ const e = `http://${this.options.daemonHost}:${this.options.daemonPort}/api/token`, t = await fetch(e);
110
+ if (!t.ok) throw new Error(`Failed to fetch daemon token: ${t.statusText}`);
111
+ const o = await t.json();
112
+ if (o && o.token)
113
+ return this.options.daemonToken = o.token, o.token;
114
+ throw new Error("No token returned from daemon");
115
+ }
116
+ async getSystemInfo() {
117
+ const e = this.buildDaemonUrl("/api/system/info"), t = await fetch(e);
118
+ if (!t.ok) throw new Error(`Failed to fetch system info: ${t.statusText}`);
119
+ return t.json();
120
+ }
121
+ async getTags() {
122
+ const e = this.buildDaemonUrl("/api/tags"), t = await fetch(e);
123
+ if (!t.ok) throw new Error(`Failed to fetch tags: ${t.statusText}`);
124
+ return t.json();
125
+ }
126
+ async getTerminals() {
127
+ const e = this.buildDaemonUrl("/api/terminal/list"), t = await fetch(e);
128
+ if (!t.ok) throw new Error(`Failed to fetch terminal list: ${t.statusText}`);
129
+ return t.json();
130
+ }
131
+ async closeTerminal(e) {
132
+ const t = this.buildDaemonUrl("/api/terminal/close", { id: e }), o = await fetch(t, {
133
+ method: "POST"
134
+ });
135
+ if (!o.ok) throw new Error(`Failed to close terminal: ${o.statusText}`);
136
+ return o.json();
137
+ }
138
+ async stopDaemon(e) {
139
+ const t = this.buildDaemonUrl("/stop"), o = e ? JSON.stringify({ workspace: e }) : void 0, r = await fetch(t, {
140
+ method: "POST",
141
+ headers: o ? { "Content-Type": "application/json" } : {},
142
+ body: o
143
+ });
144
+ if (!r.ok) throw new Error(`Failed to stop daemon: ${r.statusText}`);
145
+ return r.json();
146
+ }
147
+ async getScheduledTasks() {
148
+ const e = this.buildDaemonUrl("/api/schedule"), t = await fetch(e);
149
+ if (!t.ok) throw new Error(`Failed to fetch scheduled tasks: ${t.statusText}`);
150
+ return t.json();
151
+ }
152
+ async addScheduledTask(e) {
153
+ const t = this.buildDaemonUrl("/api/schedule"), o = await fetch(t, {
154
+ method: "POST",
155
+ headers: { "Content-Type": "application/json" },
156
+ body: JSON.stringify(e)
157
+ });
158
+ if (!o.ok) throw new Error(`Failed to add scheduled task: ${o.statusText}`);
159
+ return o.json();
160
+ }
161
+ async deleteScheduledTask(e) {
162
+ const t = this.buildDaemonUrl("/api/schedule", { id: e }), o = await fetch(t, { method: "DELETE" });
163
+ if (!o.ok) throw new Error(`Failed to delete scheduled task: ${o.statusText}`);
164
+ return o.json();
165
+ }
166
+ async runScheduledTask(e) {
167
+ const t = this.buildDaemonUrl("/api/schedule/run", { id: e }), o = await fetch(t, { method: "POST" });
168
+ if (!o.ok) throw new Error(`Failed to run scheduled task: ${o.statusText}`);
169
+ return o.json();
170
+ }
171
+ async getScreenDevices() {
172
+ const e = this.buildDaemonUrl("/api/devices/screens"), t = await fetch(e);
173
+ if (!t.ok) throw new Error(`Failed to fetch screen devices: ${t.statusText}`);
174
+ return t.json();
175
+ }
176
+ async getAudioDevices() {
177
+ const e = this.buildDaemonUrl("/api/devices/audio"), t = await fetch(e);
178
+ if (!t.ok) throw new Error(`Failed to fetch audio devices: ${t.statusText}`);
179
+ return t.json();
180
+ }
181
+ async startRecording(e, t = {}) {
182
+ const o = this.buildDaemonUrl("/api/record/start", { type: e, ...t }), r = await fetch(o);
183
+ if (!r.ok) throw new Error(`Failed to start recording: ${r.statusText}`);
184
+ return r.json();
185
+ }
186
+ async stopRecording(e) {
187
+ const t = this.buildDaemonUrl("/api/record/stop", { type: e }), o = await fetch(t);
188
+ if (!o.ok) throw new Error(`Failed to stop recording: ${o.statusText}`);
189
+ return o.blob();
190
+ }
191
+ async transcribeAudio(e) {
192
+ const t = this.buildDaemonUrl("/api/transcribe"), o = await fetch(t, {
193
+ method: "POST",
194
+ body: e,
195
+ headers: {
196
+ "Content-Type": "audio/wav"
197
+ }
198
+ });
199
+ if (!o.ok) throw new Error(`Failed to transcribe audio: ${o.statusText}`);
200
+ return o.json();
201
+ }
202
+ // --- Filesystem API methods ---
203
+ async listFiles(e) {
204
+ const t = this.buildDaemonUrl("/api/files", { path: e }), o = await fetch(t);
205
+ if (!o.ok) throw new Error(`Failed to list files: ${o.statusText}`);
206
+ return o.json();
207
+ }
208
+ async readFile(e) {
209
+ const t = this.buildDaemonUrl("/api/file", { path: e }), o = await fetch(t);
210
+ if (!o.ok) throw new Error(`Failed to read file: ${o.statusText}`);
211
+ return o.text();
212
+ }
213
+ async writeFile(e, t, o) {
214
+ const r = this.buildDaemonUrl("/api/file"), i = await fetch(r, {
215
+ method: "POST",
216
+ headers: {
217
+ "Content-Type": "application/json"
218
+ },
219
+ body: JSON.stringify({
220
+ path: e,
221
+ content: t,
222
+ encoding: o
223
+ })
224
+ });
225
+ if (!i.ok) throw new Error(`Failed to write file: ${i.statusText}`);
226
+ return i.json();
227
+ }
228
+ // --- Cloud & Models REST API ---
229
+ async getCloudUser() {
230
+ const e = this.buildCloudUrl("/api/v1/admin/me"), t = await fetch(e, {
231
+ headers: this.getCloudHeaders()
232
+ });
233
+ if (!t.ok) throw new Error(`Failed to fetch cloud user: ${t.statusText}`);
234
+ return t.json();
235
+ }
236
+ async getCloudModels() {
237
+ const e = this.buildCloudUrl("/api/v1/models"), t = await fetch(e, {
238
+ headers: this.getCloudHeaders()
239
+ });
240
+ if (!t.ok) throw new Error(`Failed to fetch cloud models: ${t.statusText}`);
241
+ return t.json();
242
+ }
243
+ async getLatestRelease(e = "crom-agente") {
244
+ const t = this.buildCloudUrl(`/api/v1/github/releases?repo=${e}`), o = await fetch(t);
245
+ if (!o.ok) throw new Error(`Failed to fetch latest release: ${o.statusText}`);
246
+ return o.json();
247
+ }
248
+ async getOpenRouterModels() {
249
+ const t = await fetch("https://openrouter.ai/api/v1/models");
250
+ if (!t.ok) throw new Error(`Failed to fetch OpenRouter models: ${t.statusText}`);
251
+ return t.json();
252
+ }
253
+ // --- WebSocket Connection ---
254
+ connectWebSocket(e, t, o, r, i) {
255
+ var E;
256
+ this.disconnectWebSocket();
257
+ const d = this.options.daemonHost, w = this.options.daemonPort, p = this.options.sessionToken || this.options.daemonToken, y = `${typeof window < "u" && ((E = window.location) == null ? void 0 : E.protocol) === "https:" ? "wss:" : "ws:"}//${d}:${w}/ws${p ? `?token=${encodeURIComponent(p)}` : ""}`;
258
+ this.wsUrl = y;
259
+ const k = this.options.WebSocketConstructor || (typeof window < "u" ? window.WebSocket : null);
260
+ if (!k)
261
+ throw new Error("No WebSocket constructor available. Pass one in options for Node environment.");
262
+ const h = new k(y);
263
+ this.ws = h, h.onopen = () => {
264
+ this.reconnectAttempts = 0, this.emit("open", { url: y }), h.send(JSON.stringify({ type: "subscribe", workspace: e }));
265
+ const c = typeof localStorage < "u" ? localStorage.getItem("crom_auto_approve_enabled") === "true" : !1;
266
+ h.send(JSON.stringify({ type: "set_auto_approve", workspace: e, auto_approve: c })), o && o.trim() && (h.send(JSON.stringify({
267
+ type: "run",
268
+ workspace: e,
269
+ session: t,
270
+ task: o,
271
+ provider: r,
272
+ model: i
273
+ })), this.emit("prompt_sent", { prompt: o }));
274
+ }, h.onmessage = (c) => {
275
+ try {
276
+ const a = R(c.data);
277
+ if (!a) return;
278
+ const m = Array.isArray(a) ? a : [a];
279
+ for (const T of m) {
280
+ let n = T.data;
281
+ if (typeof n == "string")
282
+ try {
283
+ n = JSON.parse(n);
284
+ } catch {
285
+ }
286
+ let l = "", b = 0, f = null;
287
+ if (n && typeof n == "object" && ("event" in n ? (l = n.event, b = n.iteration || 0, f = n.data) : "type" in n && (n.type === "status" ? (l = "status_change", f = { status: n.status }) : n.type === "ask_permission" ? (l = "permission_request", f = { action: n.action, target: n.target }) : n.type === "message" ? (l = "message", f = n) : (l = n.type, f = n))), !l)
288
+ if (T.error)
289
+ l = "error", f = { error: { code: "ERR_DAEMON", message: T.error } };
290
+ else
291
+ continue;
292
+ this.emit(l, {
293
+ event: l,
294
+ iteration: b,
295
+ data: f
296
+ });
297
+ }
298
+ } catch (a) {
299
+ this.emit("error", { error: a });
300
+ }
301
+ }, h.onerror = (c) => {
302
+ this.emit("error", { error: c }), this.options.onWebSocketError && this.options.onWebSocketError(c);
303
+ }, h.onclose = (c) => {
304
+ if (this.emit("close", c), this.options.onWebSocketClose && this.options.onWebSocketClose(c), this.reconnectAttempts < this.maxReconnectAttempts) {
305
+ const a = this.baseReconnectDelay * Math.pow(2, this.reconnectAttempts);
306
+ this.reconnectAttempts += 1, this.options.onTokenRefreshNeeded ? this.options.onTokenRefreshNeeded().then((m) => {
307
+ m && (this.options.sessionToken = m), this.scheduleReconnect(e, t, o, r, i, a);
308
+ }).catch(() => {
309
+ this.scheduleReconnect(e, t, o, r, i, a);
310
+ }) : this.scheduleReconnect(e, t, o, r, i, a);
311
+ }
312
+ };
313
+ }
314
+ scheduleReconnect(e, t, o, r, i, d = 2e3) {
315
+ this.reconnectTimer && clearTimeout(this.reconnectTimer), this.reconnectTimer = setTimeout(() => {
316
+ this.connectWebSocket(e, t, o, r, i);
317
+ }, d);
318
+ }
319
+ disconnectWebSocket() {
320
+ this.reconnectTimer && (clearTimeout(this.reconnectTimer), this.reconnectTimer = null), this.ws && (this.ws.onopen = null, this.ws.onmessage = null, this.ws.onerror = null, this.ws.onclose = null, this.ws.close(), this.ws = null);
321
+ }
322
+ sendRun(e, t, o, r, i, d) {
323
+ if (!this.ws || this.ws.readyState !== 1) throw new Error("WebSocket not connected");
324
+ this.ws.send(JSON.stringify({
325
+ type: "run",
326
+ workspace: e,
327
+ session: t,
328
+ task: o,
329
+ provider: r,
330
+ model: i,
331
+ auto_approve: d
332
+ }));
333
+ }
334
+ sendStop(e) {
335
+ if (!this.ws || this.ws.readyState !== 1) throw new Error("WebSocket not connected");
336
+ this.ws.send(JSON.stringify({
337
+ type: "stop",
338
+ workspace: e
339
+ }));
340
+ }
341
+ sendAutoApprove(e, t) {
342
+ if (!this.ws || this.ws.readyState !== 1) throw new Error("WebSocket not connected");
343
+ this.ws.send(JSON.stringify({
344
+ type: "set_auto_approve",
345
+ workspace: e,
346
+ auto_approve: t
347
+ }));
348
+ }
349
+ sendPermissionResponse(e, t) {
350
+ if (!this.ws || this.ws.readyState !== 1) throw new Error("WebSocket not connected");
351
+ this.ws.send(JSON.stringify({
352
+ type: "permission_response",
353
+ workspace: e,
354
+ payload: {
355
+ approved: t,
356
+ remember: !1
357
+ }
358
+ }));
359
+ }
360
+ }
361
+ export {
362
+ v as CromClient,
363
+ $ as ERROR_ACTIONS,
364
+ A as isAgentEvent,
365
+ U as isLegacyEvent,
366
+ R as parseDaemonPayload
367
+ };
@@ -0,0 +1 @@
1
+ (function(a,c){typeof exports=="object"&&typeof module<"u"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(a=typeof globalThis<"u"?globalThis:a||self,c(a.CromAgenteSDK={}))})(this,function(a){"use strict";var N=Object.defineProperty;var v=(a,c,w)=>c in a?N(a,c,{enumerable:!0,configurable:!0,writable:!0,value:w}):a[c]=w;var h=(a,c,w)=>v(a,typeof c!="symbol"?c+"":c,w);function c(n){return n&&typeof n.event=="string"&&typeof n.timestamp=="string"}function w(n){return n&&typeof n.type=="string"&&!n.event}const _={ERR_LLM_RATE_LIMIT:"Aguarde o cooldown ou troque de provedor/chave.",ERR_LLM_AUTHENTICATION:"Verifique e atualize sua chave de API nas configurações.",ERR_LLM_EMPTY_RESPONSE:"O modelo retornou vazio. Tente novamente ou troque de modelo.",ERR_TOOL_NOT_FOUND:"Ferramenta não registrada. Verifique as ferramentas disponíveis.",ERR_TOOL_EXECUTION:"Erro na execução da ferramenta. Verifique os logs.",ERR_TOOL_TIMEOUT:"A ferramenta excedeu o tempo limite. Aumente o timeout ou simplifique a operação.",ERR_PERMISSION_DENIED:"A ação foi rejeitada. Altere as permissões ou aprove manualmente.",ERR_SANDBOX_VIOLATION:"Tentativa de acessar recurso fora do sandbox do workspace.",ERR_MAX_ITERATIONS:"O agente atingiu o limite de iterações. Aumente o limite ou simplifique a tarefa.",ERR_CONSECUTIVE_FAILURES:"Muitas falhas consecutivas. Verifique a configuração e os logs.",ERR_CONTEXT_CANCELED:"A execução foi cancelada pelo usuário ou pelo sistema."};function g(n){if(!n)return null;if(typeof n=="string")try{return JSON.parse(n)}catch{return n}if(typeof n=="object"&&!Array.isArray(n)){const e=Object.keys(n);if(!(e.length>0&&e.every(o=>!isNaN(Number(o)))))return n;try{const o=new Uint8Array(Object.values(n)),s=new TextDecoder().decode(o);return JSON.parse(s)}catch{return n}}return n}class A{constructor(e={}){h(this,"options");h(this,"ws",null);h(this,"reconnectTimer",null);h(this,"reconnectAttempts",0);h(this,"maxReconnectAttempts",5);h(this,"baseReconnectDelay",2e3);h(this,"listeners",new Map);h(this,"wsUrl","");this.options={daemonHost:e.daemonHost||"127.0.0.1",daemonPort:e.daemonPort||9090,cloudUrl:e.cloudUrl||"https://cloud.ia.crom.run",sessionToken:e.sessionToken||"",daemonToken:e.daemonToken||"",onTokenRefreshNeeded:e.onTokenRefreshNeeded||(async()=>null),onWebSocketClose:e.onWebSocketClose||(()=>{}),onWebSocketError:e.onWebSocketError||(()=>{}),WebSocketConstructor:e.WebSocketConstructor||null}}updateOptions(e){this.options={...this.options,...e}}getOptions(){return this.options}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}off(e,t){const o=this.listeners.get(e);o&&o.delete(t)}emit(e,t){const o=this.listeners.get(e);if(o)for(const s of o)try{s(t)}catch(i){console.error("Error in CromClient event listener:",i)}}buildDaemonUrl(e,t={}){const o=this.options.daemonHost,s=this.options.daemonPort,i=new URL(`http://${o}:${s}${e}`),f=this.options.daemonToken||this.options.sessionToken;f&&i.searchParams.set("token",f);for(const[k,y]of Object.entries(t))y!=null&&i.searchParams.set(k,y);return i.toString()}buildCloudUrl(e){return`${this.options.cloudUrl.replace(/\/$/,"")}${e}`}getCloudHeaders(){const e={};return this.options.sessionToken&&(e.Authorization=`Bearer ${this.options.sessionToken}`),e}async getDaemonToken(){const e=`http://${this.options.daemonHost}:${this.options.daemonPort}/api/token`,t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch daemon token: ${t.statusText}`);const o=await t.json();if(o&&o.token)return this.options.daemonToken=o.token,o.token;throw new Error("No token returned from daemon")}async getSystemInfo(){const e=this.buildDaemonUrl("/api/system/info"),t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch system info: ${t.statusText}`);return t.json()}async getTags(){const e=this.buildDaemonUrl("/api/tags"),t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch tags: ${t.statusText}`);return t.json()}async getTerminals(){const e=this.buildDaemonUrl("/api/terminal/list"),t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch terminal list: ${t.statusText}`);return t.json()}async closeTerminal(e){const t=this.buildDaemonUrl("/api/terminal/close",{id:e}),o=await fetch(t,{method:"POST"});if(!o.ok)throw new Error(`Failed to close terminal: ${o.statusText}`);return o.json()}async stopDaemon(e){const t=this.buildDaemonUrl("/stop"),o=e?JSON.stringify({workspace:e}):void 0,s=await fetch(t,{method:"POST",headers:o?{"Content-Type":"application/json"}:{},body:o});if(!s.ok)throw new Error(`Failed to stop daemon: ${s.statusText}`);return s.json()}async getScheduledTasks(){const e=this.buildDaemonUrl("/api/schedule"),t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch scheduled tasks: ${t.statusText}`);return t.json()}async addScheduledTask(e){const t=this.buildDaemonUrl("/api/schedule"),o=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!o.ok)throw new Error(`Failed to add scheduled task: ${o.statusText}`);return o.json()}async deleteScheduledTask(e){const t=this.buildDaemonUrl("/api/schedule",{id:e}),o=await fetch(t,{method:"DELETE"});if(!o.ok)throw new Error(`Failed to delete scheduled task: ${o.statusText}`);return o.json()}async runScheduledTask(e){const t=this.buildDaemonUrl("/api/schedule/run",{id:e}),o=await fetch(t,{method:"POST"});if(!o.ok)throw new Error(`Failed to run scheduled task: ${o.statusText}`);return o.json()}async getScreenDevices(){const e=this.buildDaemonUrl("/api/devices/screens"),t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch screen devices: ${t.statusText}`);return t.json()}async getAudioDevices(){const e=this.buildDaemonUrl("/api/devices/audio"),t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch audio devices: ${t.statusText}`);return t.json()}async startRecording(e,t={}){const o=this.buildDaemonUrl("/api/record/start",{type:e,...t}),s=await fetch(o);if(!s.ok)throw new Error(`Failed to start recording: ${s.statusText}`);return s.json()}async stopRecording(e){const t=this.buildDaemonUrl("/api/record/stop",{type:e}),o=await fetch(t);if(!o.ok)throw new Error(`Failed to stop recording: ${o.statusText}`);return o.blob()}async transcribeAudio(e){const t=this.buildDaemonUrl("/api/transcribe"),o=await fetch(t,{method:"POST",body:e,headers:{"Content-Type":"audio/wav"}});if(!o.ok)throw new Error(`Failed to transcribe audio: ${o.statusText}`);return o.json()}async listFiles(e){const t=this.buildDaemonUrl("/api/files",{path:e}),o=await fetch(t);if(!o.ok)throw new Error(`Failed to list files: ${o.statusText}`);return o.json()}async readFile(e){const t=this.buildDaemonUrl("/api/file",{path:e}),o=await fetch(t);if(!o.ok)throw new Error(`Failed to read file: ${o.statusText}`);return o.text()}async writeFile(e,t,o){const s=this.buildDaemonUrl("/api/file"),i=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e,content:t,encoding:o})});if(!i.ok)throw new Error(`Failed to write file: ${i.statusText}`);return i.json()}async getCloudUser(){const e=this.buildCloudUrl("/api/v1/admin/me"),t=await fetch(e,{headers:this.getCloudHeaders()});if(!t.ok)throw new Error(`Failed to fetch cloud user: ${t.statusText}`);return t.json()}async getCloudModels(){const e=this.buildCloudUrl("/api/v1/models"),t=await fetch(e,{headers:this.getCloudHeaders()});if(!t.ok)throw new Error(`Failed to fetch cloud models: ${t.statusText}`);return t.json()}async getLatestRelease(e="crom-agente"){const t=this.buildCloudUrl(`/api/v1/github/releases?repo=${e}`),o=await fetch(t);if(!o.ok)throw new Error(`Failed to fetch latest release: ${o.statusText}`);return o.json()}async getOpenRouterModels(){const t=await fetch("https://openrouter.ai/api/v1/models");if(!t.ok)throw new Error(`Failed to fetch OpenRouter models: ${t.statusText}`);return t.json()}connectWebSocket(e,t,o,s,i){var R;this.disconnectWebSocket();const f=this.options.daemonHost,k=this.options.daemonPort,y=this.options.sessionToken||this.options.daemonToken,E=`${typeof window<"u"&&((R=window.location)==null?void 0:R.protocol)==="https:"?"wss:":"ws:"}//${f}:${k}/ws${y?`?token=${encodeURIComponent(y)}`:""}`;this.wsUrl=E;const S=this.options.WebSocketConstructor||(typeof window<"u"?window.WebSocket:null);if(!S)throw new Error("No WebSocket constructor available. Pass one in options for Node environment.");const p=new S(E);this.ws=p,p.onopen=()=>{this.reconnectAttempts=0,this.emit("open",{url:E}),p.send(JSON.stringify({type:"subscribe",workspace:e}));const u=typeof localStorage<"u"?localStorage.getItem("crom_auto_approve_enabled")==="true":!1;p.send(JSON.stringify({type:"set_auto_approve",workspace:e,auto_approve:u})),o&&o.trim()&&(p.send(JSON.stringify({type:"run",workspace:e,session:t,task:o,provider:s,model:i})),this.emit("prompt_sent",{prompt:o}))},p.onmessage=u=>{try{const l=g(u.data);if(!l)return;const T=Array.isArray(l)?l:[l];for(const b of T){let r=b.data;if(typeof r=="string")try{r=JSON.parse(r)}catch{}let d="",O=0,m=null;if(r&&typeof r=="object"&&("event"in r?(d=r.event,O=r.iteration||0,m=r.data):"type"in r&&(r.type==="status"?(d="status_change",m={status:r.status}):r.type==="ask_permission"?(d="permission_request",m={action:r.action,target:r.target}):r.type==="message"?(d="message",m=r):(d=r.type,m=r))),!d)if(b.error)d="error",m={error:{code:"ERR_DAEMON",message:b.error}};else continue;this.emit(d,{event:d,iteration:O,data:m})}}catch(l){this.emit("error",{error:l})}},p.onerror=u=>{this.emit("error",{error:u}),this.options.onWebSocketError&&this.options.onWebSocketError(u)},p.onclose=u=>{if(this.emit("close",u),this.options.onWebSocketClose&&this.options.onWebSocketClose(u),this.reconnectAttempts<this.maxReconnectAttempts){const l=this.baseReconnectDelay*Math.pow(2,this.reconnectAttempts);this.reconnectAttempts+=1,this.options.onTokenRefreshNeeded?this.options.onTokenRefreshNeeded().then(T=>{T&&(this.options.sessionToken=T),this.scheduleReconnect(e,t,o,s,i,l)}).catch(()=>{this.scheduleReconnect(e,t,o,s,i,l)}):this.scheduleReconnect(e,t,o,s,i,l)}}}scheduleReconnect(e,t,o,s,i,f=2e3){this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=setTimeout(()=>{this.connectWebSocket(e,t,o,s,i)},f)}disconnectWebSocket(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws&&(this.ws.onopen=null,this.ws.onmessage=null,this.ws.onerror=null,this.ws.onclose=null,this.ws.close(),this.ws=null)}sendRun(e,t,o,s,i,f){if(!this.ws||this.ws.readyState!==1)throw new Error("WebSocket not connected");this.ws.send(JSON.stringify({type:"run",workspace:e,session:t,task:o,provider:s,model:i,auto_approve:f}))}sendStop(e){if(!this.ws||this.ws.readyState!==1)throw new Error("WebSocket not connected");this.ws.send(JSON.stringify({type:"stop",workspace:e}))}sendAutoApprove(e,t){if(!this.ws||this.ws.readyState!==1)throw new Error("WebSocket not connected");this.ws.send(JSON.stringify({type:"set_auto_approve",workspace:e,auto_approve:t}))}sendPermissionResponse(e,t){if(!this.ws||this.ws.readyState!==1)throw new Error("WebSocket not connected");this.ws.send(JSON.stringify({type:"permission_response",workspace:e,payload:{approved:t,remember:!1}}))}}a.CromClient=A,a.ERROR_ACTIONS=_,a.isAgentEvent=c,a.isLegacyEvent=w,a.parseDaemonPayload=g,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})});
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export * from "./utils.js";
3
+ export * from "./client.js";
4
+ export { ERROR_ACTIONS } from "./types.js";
@@ -0,0 +1,120 @@
1
+ /**
2
+ * crom-agente SDK — Tipos do Protocolo de Eventos Estruturados
3
+ *
4
+ * Estes tipos definem o protocolo JSON que o daemon do crom-agente emite via WebSocket/IPC.
5
+ * Use-os para consumir eventos do agente de forma tipada em qualquer aplicação TypeScript.
6
+ */
7
+ /** Tipos de evento possíveis emitidos pelo AgenticLoop */
8
+ export type AgentEventType = "thinking" | "message" | "tool_call" | "tool_result" | "error" | "finished";
9
+ /** Evento estruturado emitido pelo agente em tempo real */
10
+ export interface AgentEvent {
11
+ /** Timestamp ISO 8601 do momento da emissão */
12
+ timestamp: string;
13
+ /** Tipo do evento */
14
+ event: AgentEventType;
15
+ /** Número da iteração atual do loop ReAct (1-indexed) */
16
+ iteration?: number;
17
+ /** Dados específicos do evento */
18
+ data?: Record<string, any>;
19
+ }
20
+ /** Dados do evento "thinking" */
21
+ export interface ThinkingEventData {
22
+ provider: string;
23
+ model: string;
24
+ }
25
+ /** Dados do evento "message" */
26
+ export interface MessageEventData {
27
+ role: "assistant" | "system" | "user" | "tool";
28
+ content: string;
29
+ usage: TokenUsage;
30
+ has_tool_calls: boolean;
31
+ }
32
+ /** Dados do evento "tool_call" */
33
+ export interface ToolCallEventData {
34
+ tool_call_id: string;
35
+ tool: string;
36
+ arguments: Record<string, any>;
37
+ }
38
+ /** Dados do evento "tool_result" */
39
+ export interface ToolResultEventData {
40
+ tool_call_id: string;
41
+ tool: string;
42
+ success: boolean;
43
+ output?: string;
44
+ error?: string;
45
+ error_code?: AgentErrorCode;
46
+ }
47
+ /** Dados do evento "error" */
48
+ export interface ErrorEventData {
49
+ error: AgentError;
50
+ }
51
+ /** Dados do evento "finished" */
52
+ export interface FinishedEventData {
53
+ reason: "completed" | "max_iterations" | "consecutive_failures" | "canceled";
54
+ total_iterations: number;
55
+ }
56
+ /** Erro tipado emitido pelo agente para tratamento programático */
57
+ export interface AgentError {
58
+ /** Código identificador do erro */
59
+ code: AgentErrorCode;
60
+ /** Mensagem legível do erro */
61
+ message: string;
62
+ /** Detalhes adicionais específicos do erro */
63
+ details?: Record<string, any>;
64
+ }
65
+ /** Códigos de erro padronizados do agente */
66
+ export type AgentErrorCode = "ERR_LLM_RATE_LIMIT" | "ERR_LLM_AUTHENTICATION" | "ERR_LLM_EMPTY_RESPONSE" | "ERR_TOOL_NOT_FOUND" | "ERR_TOOL_EXECUTION" | "ERR_TOOL_TIMEOUT" | "ERR_PERMISSION_DENIED" | "ERR_SANDBOX_VIOLATION" | "ERR_MAX_ITERATIONS" | "ERR_CONSECUTIVE_FAILURES" | "ERR_CONTEXT_CANCELED";
67
+ /** Informações de consumo de tokens de uma chamada ao LLM */
68
+ export interface TokenUsage {
69
+ prompt_tokens: number;
70
+ completion_tokens: number;
71
+ total_tokens: number;
72
+ }
73
+ /** Estado atual de um servidor MCP */
74
+ export interface MCPServerStatus {
75
+ name: string;
76
+ mode: "subprocess" | "sse";
77
+ tool_count: number;
78
+ tools: string[];
79
+ running: boolean;
80
+ }
81
+ /** Mensagem enviada pelo cliente ao daemon */
82
+ export interface IPCMessage {
83
+ type: "run" | "status" | "stop" | "ping" | "subscribe" | "permission_response";
84
+ workspace?: string;
85
+ task?: string;
86
+ session?: string;
87
+ payload?: any;
88
+ }
89
+ /** Resposta enviada pelo daemon ao cliente */
90
+ export interface IPCResponse {
91
+ success: boolean;
92
+ data?: AgentEvent | LegacyEvent;
93
+ error?: string;
94
+ stream: boolean;
95
+ }
96
+ /** Evento legado de status */
97
+ export interface LegacyStatusEvent {
98
+ type: "status";
99
+ status: string;
100
+ }
101
+ /** Evento legado de mensagem */
102
+ export interface LegacyMessageEvent {
103
+ type: "message";
104
+ role: string;
105
+ content: string;
106
+ }
107
+ /** Evento legado de permissão */
108
+ export interface LegacyPermissionEvent {
109
+ type: "ask_permission";
110
+ action: string;
111
+ target: string;
112
+ }
113
+ /** União de todos os eventos legados */
114
+ export type LegacyEvent = LegacyStatusEvent | LegacyMessageEvent | LegacyPermissionEvent;
115
+ /** Type guard para verificar se um payload é um AgentEvent estruturado */
116
+ export declare function isAgentEvent(data: any): data is AgentEvent;
117
+ /** Type guard para verificar se um payload é um evento legado */
118
+ export declare function isLegacyEvent(data: any): data is LegacyEvent;
119
+ /** Tabela de ações recomendadas para cada código de erro */
120
+ export declare const ERROR_ACTIONS: Record<AgentErrorCode, string>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Decodifica e faz o parsing de dados recebidos pelo daemon.
3
+ * Lida com strings JSON normais e também com objetos Uint8Array serializados.
4
+ */
5
+ export declare function parseDaemonPayload(responseData: any): any;
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "crom-agente-sdk",
3
+ "version": "0.1.0",
4
+ "description": "SDK oficial em TypeScript para integração com o ecossistema crom-agente",
5
+ "type": "module",
6
+ "main": "./dist/crom-agente-sdk.umd.cjs",
7
+ "module": "./dist/crom-agente-sdk.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/crom-agente-sdk.js",
12
+ "require": "./dist/crom-agente-sdk.umd.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "vite build && tsc --emitDeclarationOnly",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest"
23
+ },
24
+ "keywords": [
25
+ "crom",
26
+ "agente",
27
+ "sdk",
28
+ "typescript"
29
+ ],
30
+ "author": "CromIA",
31
+ "license": "CUSTOM",
32
+ "devDependencies": {
33
+ "@types/ws": "^8.18.1",
34
+ "typescript": "^5.3.3",
35
+ "vite": "^5.1.4",
36
+ "vite-plugin-dts": "^3.7.3",
37
+ "vitest": "^1.3.1"
38
+ },
39
+ "dependencies": {
40
+ "axios": "^1.18.0",
41
+ "ws": "^8.21.0"
42
+ }
43
+ }