openpond-code 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.
package/dist/index.js ADDED
@@ -0,0 +1,1346 @@
1
+ // src/api.ts
2
+ async function apiFetch(baseUrl, token, path, init) {
3
+ const headers = new Headers(init?.headers || {});
4
+ headers.set("Content-Type", "application/json");
5
+ const apiKey = process.env.OPENPOND_API_KEY;
6
+ const trimmedToken = token?.trim() || "";
7
+ const tokenIsApiKey = trimmedToken.startsWith("opk_");
8
+ const effectiveApiKey = apiKey || (tokenIsApiKey ? trimmedToken : null);
9
+ if (effectiveApiKey && !headers.has("openpond-api-key")) {
10
+ headers.set("openpond-api-key", effectiveApiKey);
11
+ }
12
+ if (token) {
13
+ headers.set("Authorization", tokenIsApiKey ? `ApiKey ${trimmedToken}` : `Bearer ${token}`);
14
+ } else if (apiKey && !headers.has("Authorization")) {
15
+ headers.set("Authorization", `ApiKey ${apiKey}`);
16
+ }
17
+ return fetch(`${baseUrl}${path}`, {
18
+ ...init,
19
+ headers
20
+ });
21
+ }
22
+ async function startDeviceLogin(baseUrl) {
23
+ const response = await apiFetch(baseUrl, null, "/api/auth/device/start", {
24
+ method: "POST",
25
+ body: JSON.stringify({})
26
+ });
27
+ if (!response.ok) {
28
+ const text = await response.text().catch(() => "");
29
+ throw new Error(`Device login start failed: ${response.status} ${text}`);
30
+ }
31
+ return await response.json();
32
+ }
33
+ async function pollDeviceLogin(baseUrl, deviceCode, userCode) {
34
+ const payload = userCode && typeof userCode === "string" ? { userCode } : { deviceCode };
35
+ const response = await apiFetch(baseUrl, null, "/api/auth/device/poll", {
36
+ method: "POST",
37
+ body: JSON.stringify(payload)
38
+ });
39
+ if (response.status === 202) {
40
+ return {};
41
+ }
42
+ if (!response.ok) {
43
+ const text = await response.text().catch(() => "");
44
+ throw new Error(`Device login poll failed: ${response.status} ${text}`);
45
+ }
46
+ return await response.json();
47
+ }
48
+ async function listApps(apiBase, token, options) {
49
+ const params = new URLSearchParams;
50
+ if (options?.handle) {
51
+ params.set("handle", options.handle);
52
+ }
53
+ const query = params.toString();
54
+ const response = await apiFetch(apiBase, token, `/apps/list${query ? `?${query}` : ""}`, { method: "GET" });
55
+ if (!response.ok) {
56
+ const text = await response.text().catch(() => "");
57
+ throw new Error(`Apps list failed: ${response.status} ${text}`);
58
+ }
59
+ const payload = await response.json().catch(() => ({}));
60
+ return Array.isArray(payload.apps) ? payload.apps : [];
61
+ }
62
+ async function createLocalProject(baseUrl, token, input) {
63
+ const response = await apiFetch(baseUrl, token, "/api/projects/local", {
64
+ method: "POST",
65
+ body: JSON.stringify(input)
66
+ });
67
+ if (!response.ok) {
68
+ const text = await response.text().catch(() => "");
69
+ throw new Error(`Create project failed: ${response.status} ${text}`);
70
+ }
71
+ return await response.json();
72
+ }
73
+ async function createRepo(apiBase, apiKey, input) {
74
+ const response = await apiFetch(apiBase, apiKey, "/apps/repo/create", {
75
+ method: "POST",
76
+ body: JSON.stringify(input)
77
+ });
78
+ if (!response.ok) {
79
+ const text = await response.text().catch(() => "");
80
+ throw new Error(`Repo create failed: ${response.status} ${text}`);
81
+ }
82
+ return await response.json();
83
+ }
84
+ async function createHeadlessApps(baseUrl, token, items) {
85
+ const response = await apiFetch(baseUrl, token, "/v4/apps/headless", {
86
+ method: "POST",
87
+ body: JSON.stringify({ items })
88
+ });
89
+ if (!response.ok) {
90
+ const text = await response.text().catch(() => "");
91
+ throw new Error(`Headless create failed: ${response.status} ${text}`);
92
+ }
93
+ return await response.json();
94
+ }
95
+ async function getTemplateStatus(apiBase, token, appId) {
96
+ const response = await apiFetch(apiBase, token, `/v4/apps/${appId}/template/status`, { method: "GET" });
97
+ if (!response.ok) {
98
+ const text = await response.text().catch(() => "");
99
+ throw new Error(`Template status failed: ${response.status} ${text}`);
100
+ }
101
+ return await response.json();
102
+ }
103
+ async function listTemplateBranches(apiBase, token, appId) {
104
+ const response = await apiFetch(apiBase, token, `/v4/apps/${appId}/template/branches`, { method: "GET" });
105
+ if (!response.ok) {
106
+ const text = await response.text().catch(() => "");
107
+ throw new Error(`Template branches failed: ${response.status} ${text}`);
108
+ }
109
+ return await response.json();
110
+ }
111
+ async function deployLatestTemplate(apiBase, token, appId, input) {
112
+ const response = await apiFetch(apiBase, token, `/v4/apps/${appId}/template/deploy-latest`, {
113
+ method: "POST",
114
+ body: JSON.stringify(input)
115
+ });
116
+ if (!response.ok) {
117
+ const text = await response.text().catch(() => "");
118
+ throw new Error(`Template deploy failed: ${response.status} ${text}`);
119
+ }
120
+ return await response.json();
121
+ }
122
+ async function updateAppEnvironment(apiBase, token, appId, input) {
123
+ const response = await apiFetch(apiBase, token, `/v4/apps/${appId}/environment`, {
124
+ method: "POST",
125
+ body: JSON.stringify(input)
126
+ });
127
+ if (!response.ok) {
128
+ const text = await response.text().catch(() => "");
129
+ throw new Error(`Environment update failed: ${response.status} ${text}`);
130
+ }
131
+ return await response.json();
132
+ }
133
+ async function getAppEnvironment(apiBase, token, appId) {
134
+ const response = await apiFetch(apiBase, token, `/v4/apps/${appId}/environment`, {
135
+ method: "GET"
136
+ });
137
+ if (!response.ok) {
138
+ const text = await response.text().catch(() => "");
139
+ throw new Error(`Environment get failed: ${response.status} ${text}`);
140
+ }
141
+ return await response.json();
142
+ }
143
+ async function fetchToolManifest(baseUrl, token) {
144
+ const response = await apiFetch(baseUrl, token, "/api/tools/manifest", {
145
+ method: "GET"
146
+ });
147
+ if (!response.ok) {
148
+ const text = await response.text().catch(() => "");
149
+ throw new Error(`Manifest fetch failed: ${response.status} ${text}`);
150
+ }
151
+ return await response.json();
152
+ }
153
+ async function listUserTools(baseUrl, token) {
154
+ const response = await apiFetch(baseUrl, token, "/apps/tools", {
155
+ method: "GET"
156
+ });
157
+ if (!response.ok) {
158
+ const text = await response.text().catch(() => "");
159
+ throw new Error(`Tools lookup failed: ${response.status} ${text}`);
160
+ }
161
+ return await response.json();
162
+ }
163
+ async function createAgentFromPrompt(baseUrl, token, payload) {
164
+ return apiFetch(baseUrl, token, "/apps/agent/create", {
165
+ method: "POST",
166
+ body: JSON.stringify(payload)
167
+ });
168
+ }
169
+ async function getUserPerformance(baseUrl, token, options) {
170
+ const params = new URLSearchParams;
171
+ if (options?.appId) {
172
+ params.set("appId", options.appId);
173
+ }
174
+ const qs = params.toString();
175
+ const response = await apiFetch(baseUrl, token, `/apps/performance${qs ? `?${qs}` : ""}`, {
176
+ method: "GET"
177
+ });
178
+ if (!response.ok) {
179
+ const text = await response.text().catch(() => "");
180
+ throw new Error(`Performance lookup failed: ${response.status} ${text}`);
181
+ }
182
+ return await response.json();
183
+ }
184
+ async function postAgentDigest(baseUrl, token, body) {
185
+ const response = await apiFetch(baseUrl, token, "/apps/agent/digest", {
186
+ method: "POST",
187
+ body: JSON.stringify(body)
188
+ });
189
+ if (!response.ok) {
190
+ const text = await response.text().catch(() => "");
191
+ throw new Error(`Agent digest failed: ${response.status} ${text}`);
192
+ }
193
+ return await response.json();
194
+ }
195
+ async function executeUserTool(baseUrl, token, body) {
196
+ const response = await apiFetch(baseUrl, token, "/apps/tools/execute", {
197
+ method: "POST",
198
+ body: JSON.stringify(body)
199
+ });
200
+ const text = await response.text().catch(() => "");
201
+ let payload = null;
202
+ try {
203
+ payload = text ? JSON.parse(text) : null;
204
+ } catch {
205
+ payload = text;
206
+ }
207
+ if (!response.ok) {
208
+ return {
209
+ ok: false,
210
+ status: response.status,
211
+ error: payload && typeof payload === "object" && "error" in payload ? String(payload.error) : text || response.statusText
212
+ };
213
+ }
214
+ return {
215
+ ok: true,
216
+ status: response.status,
217
+ data: payload
218
+ };
219
+ }
220
+ async function submitPositionsTx(baseUrl, token, params) {
221
+ const qs = params.query && Object.keys(params.query).length > 0 ? `?${new URLSearchParams(params.query).toString()}` : "";
222
+ const response = await apiFetch(baseUrl, token, `/apps/positions/tx${qs}`, {
223
+ method: params.method,
224
+ body: params.method === "POST" && params.body !== undefined ? JSON.stringify(params.body) : undefined
225
+ });
226
+ if (!response.ok) {
227
+ const text = await response.text().catch(() => "");
228
+ throw new Error(`Positions request failed: ${response.status} ${text}`);
229
+ }
230
+ return await response.json();
231
+ }
232
+ async function commitFiles(baseUrl, token, appId, files, commitMessage) {
233
+ const response = await apiFetch(baseUrl, token, `/v4/apps/${appId}/commits`, {
234
+ method: "POST",
235
+ body: JSON.stringify({ files, message: commitMessage })
236
+ });
237
+ if (!response.ok) {
238
+ const text = await response.text().catch(() => "");
239
+ throw new Error(`Commit failed: ${response.status} ${text}`);
240
+ }
241
+ return await response.json();
242
+ }
243
+ async function deployApp(baseUrl, token, appId, input) {
244
+ const environment = input?.environment ?? "production";
245
+ const response = await apiFetch(baseUrl, token, `/v4/apps/${appId}/deployments`, {
246
+ method: "POST",
247
+ body: JSON.stringify({
248
+ environment,
249
+ ...input?.commitSha ? { commitSha: input.commitSha } : {},
250
+ ...input?.branch ? { branch: input.branch } : {}
251
+ })
252
+ });
253
+ if (!response.ok) {
254
+ const text = await response.text().catch(() => "");
255
+ throw new Error(`Deploy failed: ${response.status} ${text}`);
256
+ }
257
+ return await response.json();
258
+ }
259
+ async function getDeploymentLogs(apiBase, token, deploymentId) {
260
+ const response = await apiFetch(apiBase, token, `/apps/deployments/${deploymentId}/logs`, { method: "GET" });
261
+ if (!response.ok) {
262
+ const text = await response.text().catch(() => "");
263
+ throw new Error(`Deployment logs failed: ${response.status} ${text}`);
264
+ }
265
+ const payload = await response.json().catch(() => ({}));
266
+ const logs = Array.isArray(payload.logs) ? payload.logs : [];
267
+ return logs.map((log) => {
268
+ const createdAt = typeof log.createdAt === "string" ? log.createdAt : log.createdAt instanceof Date ? log.createdAt.toISOString() : new Date().toISOString();
269
+ return {
270
+ id: typeof log.id === "string" ? log.id : `${Math.random()}`,
271
+ type: typeof log.type === "string" ? log.type : undefined,
272
+ message: typeof log.message === "string" ? log.message : "",
273
+ createdAt
274
+ };
275
+ });
276
+ }
277
+ async function getDeploymentStatus(apiBase, token, deploymentId) {
278
+ const response = await apiFetch(apiBase, token, `/apps/deployments/${deploymentId}/status`, { method: "GET" });
279
+ if (!response.ok) {
280
+ const text = await response.text().catch(() => "");
281
+ throw new Error(`Deployment status failed: ${response.status} ${text}`);
282
+ }
283
+ const payload = await response.json().catch(() => ({}));
284
+ return { status: payload.deployment?.status };
285
+ }
286
+ async function getLatestDeploymentForApp(apiBase, token, appId, options) {
287
+ const params = new URLSearchParams;
288
+ if (options?.status && options.status.length > 0) {
289
+ params.set("status", options.status.join(","));
290
+ }
291
+ if (options?.createdAfter) {
292
+ params.set("createdAfter", options.createdAfter);
293
+ }
294
+ if (options?.branch) {
295
+ params.set("branch", options.branch);
296
+ }
297
+ const query = params.toString();
298
+ const response = await apiFetch(apiBase, token, `/apps/${appId}/deployments/latest${query ? `?${query}` : ""}`, { method: "GET" });
299
+ if (!response.ok) {
300
+ const text = await response.text().catch(() => "");
301
+ throw new Error(`Latest deployment lookup failed: ${response.status} ${text}`);
302
+ }
303
+ const payload = await response.json().catch(() => ({}));
304
+ if (!payload.deployment)
305
+ return null;
306
+ return {
307
+ id: payload.deployment.id,
308
+ status: payload.deployment.status
309
+ };
310
+ }
311
+ async function getDeploymentDetail(apiBase, token, deploymentId) {
312
+ const response = await apiFetch(apiBase, token, `/apps/deployments/${deploymentId}`, { method: "GET" });
313
+ if (!response.ok) {
314
+ const text = await response.text().catch(() => "");
315
+ throw new Error(`Deployment fetch failed: ${response.status} ${text}`);
316
+ }
317
+ const payload = await response.json().catch(() => ({}));
318
+ return payload.deployment ?? null;
319
+ }
320
+ var normalizeToolPathSegment = function(toolName) {
321
+ const trimmed = toolName.trim().replace(/^\/+/, "");
322
+ return encodeURIComponent(trimmed || "tool");
323
+ };
324
+ function resolveWorkerBaseUrl(baseUrl) {
325
+ const trimmed = baseUrl.replace(/\/$/, "");
326
+ const workerEnv = process.env.OPENPOND_TOOL_URL;
327
+ if (workerEnv) {
328
+ return workerEnv.replace(/\/$/, "");
329
+ }
330
+ try {
331
+ const url = new URL(trimmed);
332
+ const host = url.hostname.toLowerCase();
333
+ const mappedHost = (() => {
334
+ if (host === "apps.openpond.live") {
335
+ return null;
336
+ }
337
+ if (host === "api.openpond.ai" || host === "openpond.live" || host === "www.openpond.live") {
338
+ return "https://apps.openpond.live";
339
+ }
340
+ return null;
341
+ })();
342
+ if (mappedHost) {
343
+ return mappedHost;
344
+ }
345
+ const isLocal = host === "localhost" || host === "127.0.0.1";
346
+ const port = url.port || (url.protocol === "https:" ? "443" : "80");
347
+ if (isLocal && port === "3000") {
348
+ return trimmed;
349
+ }
350
+ } catch {
351
+ }
352
+ return trimmed;
353
+ }
354
+ async function executeHostedTool(baseUrl, token, payload) {
355
+ const workerBase = resolveWorkerBaseUrl(baseUrl);
356
+ const toolPath = normalizeToolPathSegment(payload.toolName);
357
+ const deploymentPrefix = payload.deploymentId ? `/${payload.appId}/deployments/${payload.deploymentId}` : `/${payload.appId}`;
358
+ const requestPath = `${deploymentPrefix}/${toolPath}`;
359
+ const headers = new Headers(payload.headers || {});
360
+ const method = payload.method ?? "POST";
361
+ const body = payload.body === undefined || method === "GET" ? undefined : JSON.stringify(payload.body);
362
+ const response = await apiFetch(workerBase, token, requestPath, {
363
+ method,
364
+ body,
365
+ headers
366
+ });
367
+ const text = await response.text().catch(() => "");
368
+ let data = null;
369
+ try {
370
+ data = text ? JSON.parse(text) : null;
371
+ } catch {
372
+ data = text;
373
+ }
374
+ const dataOk = data && typeof data === "object" && "ok" in data ? Boolean(data.ok) : true;
375
+ const ok = response.ok && dataOk;
376
+ const status = data && typeof data === "object" && "status" in data ? Number(data.status) || response.status : response.status;
377
+ const error = data && typeof data === "object" && "error" in data ? String(data.error) : response.ok ? undefined : text || response.statusText;
378
+ const payloadData = data && typeof data === "object" && "data" in data ? data.data : data;
379
+ return { ok, status, data: payloadData, error };
380
+ }
381
+
382
+ // src/cache.ts
383
+ import {promises as fs} from "node:fs";
384
+ import os from "node:os";
385
+ import path from "node:path";
386
+ var getCachePath = function() {
387
+ return path.join(os.homedir(), CACHE_DIR, CACHE_FILENAME);
388
+ };
389
+ var buildCacheKey = function(apiBase, apiKey) {
390
+ const trimmed = apiKey.trim();
391
+ const hint = trimmed.length > 12 ? `${trimmed.slice(0, 8)}_${trimmed.slice(-4)}` : trimmed;
392
+ try {
393
+ const host = new URL(apiBase).host;
394
+ return `${host}:${hint}`;
395
+ } catch {
396
+ return `${apiBase}:${hint}`;
397
+ }
398
+ };
399
+ var isFresh = function(updatedAt, ttlMs) {
400
+ const timestamp = Date.parse(updatedAt);
401
+ if (Number.isNaN(timestamp)) {
402
+ return false;
403
+ }
404
+ return Date.now() - timestamp < ttlMs;
405
+ };
406
+ async function loadCache() {
407
+ try {
408
+ const raw = await fs.readFile(getCachePath(), "utf-8");
409
+ const parsed = JSON.parse(raw);
410
+ if (!parsed || typeof parsed !== "object" || !parsed.byKey) {
411
+ return DEFAULT_STORE;
412
+ }
413
+ return parsed;
414
+ } catch {
415
+ return DEFAULT_STORE;
416
+ }
417
+ }
418
+ async function saveCache(store) {
419
+ const filePath = getCachePath();
420
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
421
+ await fs.writeFile(filePath, JSON.stringify(store, null, 2), "utf-8");
422
+ }
423
+ async function getCachedApps(params) {
424
+ const ttlMs = params.ttlMs ?? DEFAULT_CACHE_TTL_MS;
425
+ const store = await loadCache();
426
+ const cacheKey = buildCacheKey(params.apiBase, params.apiKey);
427
+ const entry = store.byKey[cacheKey]?.apps;
428
+ if (!entry || !isFresh(entry.updatedAt, ttlMs)) {
429
+ return null;
430
+ }
431
+ return Array.isArray(entry.items) ? entry.items : null;
432
+ }
433
+ async function setCachedApps(params) {
434
+ const store = await loadCache();
435
+ const cacheKey = buildCacheKey(params.apiBase, params.apiKey);
436
+ const bucket = store.byKey[cacheKey] || {};
437
+ bucket.apps = {
438
+ items: params.apps,
439
+ updatedAt: new Date().toISOString()
440
+ };
441
+ store.byKey[cacheKey] = bucket;
442
+ await saveCache(store);
443
+ }
444
+ async function getCachedTools(params) {
445
+ const ttlMs = params.ttlMs ?? DEFAULT_CACHE_TTL_MS;
446
+ const store = await loadCache();
447
+ const cacheKey = buildCacheKey(params.apiBase, params.apiKey);
448
+ const entry = store.byKey[cacheKey]?.tools;
449
+ if (!entry || !isFresh(entry.updatedAt, ttlMs)) {
450
+ return null;
451
+ }
452
+ return Array.isArray(entry.items) ? entry.items : null;
453
+ }
454
+ async function setCachedTools(params) {
455
+ const store = await loadCache();
456
+ const cacheKey = buildCacheKey(params.apiBase, params.apiKey);
457
+ const bucket = store.byKey[cacheKey] || {};
458
+ bucket.tools = {
459
+ items: params.tools,
460
+ updatedAt: new Date().toISOString()
461
+ };
462
+ store.byKey[cacheKey] = bucket;
463
+ await saveCache(store);
464
+ }
465
+ var CACHE_DIR = ".openpond";
466
+ var CACHE_FILENAME = "cache.json";
467
+ var DEFAULT_STORE = { version: 1, byKey: {} };
468
+ var DEFAULT_CACHE_TTL_MS = 60 * 60 * 1000;
469
+
470
+ // src/stream.ts
471
+ function normalizeDataFrames(raw) {
472
+ const frames = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.data) ? raw.data : [raw];
473
+ const items = [];
474
+ let conversationId;
475
+ for (const frame of frames) {
476
+ if (!frame || typeof frame !== "object")
477
+ continue;
478
+ const typed = frame;
479
+ const type = typeof typed.type === "string" ? typed.type : undefined;
480
+ if (type === "conversation-created") {
481
+ const cid = typed.conversationId;
482
+ if (typeof cid === "string") {
483
+ conversationId = cid;
484
+ }
485
+ continue;
486
+ }
487
+ if (type === "response_items" && Array.isArray(typed.items)) {
488
+ items.push(...typed.items);
489
+ continue;
490
+ }
491
+ if (type === "response_item" && typed.item) {
492
+ items.push(typed.item);
493
+ continue;
494
+ }
495
+ if (type === "assistant-message" && typeof typed.content === "string") {
496
+ items.push({
497
+ type: "message",
498
+ role: "assistant",
499
+ id: `assistant-${Date.now()}`,
500
+ content: [{ type: "markdown", text: typed.content }],
501
+ createdAt: typeof typed.createdAt === "string" ? typed.createdAt : new Date().toISOString()
502
+ });
503
+ }
504
+ }
505
+ return { conversationId, items };
506
+ }
507
+ var extractUsage = function(raw) {
508
+ const frames = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.data) ? raw.data : [raw];
509
+ for (const frame of frames) {
510
+ if (!frame || typeof frame !== "object")
511
+ continue;
512
+ const typed = frame;
513
+ if (typed.type !== "usage")
514
+ continue;
515
+ const usage = typed.usage;
516
+ if (!usage)
517
+ continue;
518
+ const promptTokens = typeof usage.promptTokens === "number" ? usage.promptTokens : typeof usage.prompt_tokens === "number" ? usage.prompt_tokens : undefined;
519
+ const completionTokens = typeof usage.completionTokens === "number" ? usage.completionTokens : typeof usage.completion_tokens === "number" ? usage.completion_tokens : undefined;
520
+ const totalTokens = typeof usage.totalTokens === "number" ? usage.totalTokens : typeof usage.total_tokens === "number" ? usage.total_tokens : undefined;
521
+ return { promptTokens, completionTokens, totalTokens };
522
+ }
523
+ return null;
524
+ };
525
+ async function consumeStream(response, callbacks) {
526
+ if (!response.body) {
527
+ throw new Error("Missing response body");
528
+ }
529
+ const reader = response.body.getReader();
530
+ const decoder = new TextDecoder;
531
+ let remainder = "";
532
+ const shouldStop = callbacks.shouldStop;
533
+ const stopIfNeeded = async () => {
534
+ if (!shouldStop || !shouldStop()) {
535
+ return false;
536
+ }
537
+ try {
538
+ await reader.cancel();
539
+ } catch {
540
+ }
541
+ callbacks.onStop?.();
542
+ return true;
543
+ };
544
+ while (true) {
545
+ const { done, value } = await reader.read();
546
+ if (done)
547
+ break;
548
+ const chunk = decoder.decode(value, { stream: true });
549
+ const textChunk = remainder + chunk;
550
+ const lines = textChunk.split("\n");
551
+ remainder = lines.pop() || "";
552
+ for (const line of lines) {
553
+ if (!line)
554
+ continue;
555
+ if (line.startsWith("0:")) {
556
+ const payload = line.slice(2).trim();
557
+ if (!payload)
558
+ continue;
559
+ const delta = JSON.parse(payload);
560
+ if (typeof delta === "string") {
561
+ callbacks.onTextDelta?.(delta);
562
+ }
563
+ continue;
564
+ }
565
+ if (line.startsWith("g:")) {
566
+ const payload = line.slice(2).trim();
567
+ if (!payload)
568
+ continue;
569
+ const delta = JSON.parse(payload);
570
+ if (typeof delta === "string") {
571
+ callbacks.onReasoningDelta?.(delta);
572
+ }
573
+ continue;
574
+ }
575
+ if (line.startsWith("d:")) {
576
+ continue;
577
+ }
578
+ if (line.startsWith("3:")) {
579
+ const payload = line.slice(2).trim();
580
+ if (!payload)
581
+ continue;
582
+ try {
583
+ const message = JSON.parse(payload);
584
+ if (typeof message === "string") {
585
+ throw new Error(message);
586
+ }
587
+ } catch {
588
+ }
589
+ continue;
590
+ }
591
+ if (line.startsWith("2:")) {
592
+ const payload = line.slice(2).trim();
593
+ if (!payload)
594
+ continue;
595
+ try {
596
+ const dataItems = JSON.parse(payload);
597
+ const usage = extractUsage(dataItems);
598
+ if (usage) {
599
+ callbacks.onUsage?.(usage);
600
+ }
601
+ const { conversationId, items } = normalizeDataFrames(dataItems);
602
+ if (conversationId) {
603
+ callbacks.onConversationId?.(conversationId);
604
+ }
605
+ if (items.length > 0) {
606
+ await Promise.resolve(callbacks.onItems?.(items));
607
+ }
608
+ if (await stopIfNeeded()) {
609
+ return;
610
+ }
611
+ } catch {
612
+ }
613
+ }
614
+ if (await stopIfNeeded()) {
615
+ return;
616
+ }
617
+ }
618
+ }
619
+ }
620
+ function formatStreamItem(item) {
621
+ if (!item || typeof item !== "object")
622
+ return null;
623
+ const type = item.type;
624
+ if (typeof type !== "string")
625
+ return null;
626
+ if (type === "app_creation_started") {
627
+ const name = item.appName || item.name || item.appId || "app";
628
+ const templateId = typeof item.templateId === "string" ? item.templateId : null;
629
+ const suffix = templateId ? ` template=${templateId}` : "";
630
+ return `app_creation_started: ${name}${suffix}`;
631
+ }
632
+ if (type === "app_created") {
633
+ const appId = typeof item.appId === "string" ? item.appId : "unknown";
634
+ const name = typeof item.appName === "string" ? item.appName : null;
635
+ return name ? `app_created: ${name} (${appId})` : `app_created: ${appId}`;
636
+ }
637
+ if (type.startsWith("tool_creation_")) {
638
+ const message = item.message || item.content || "";
639
+ return message ? `${type}: ${message}` : type;
640
+ }
641
+ return null;
642
+ }
643
+ // src/indicators.ts
644
+ function computeRsi(values, period = 14) {
645
+ if (values.length < period + 1)
646
+ return null;
647
+ let gains = 0;
648
+ let losses = 0;
649
+ for (let i = 1;i <= period; i += 1) {
650
+ const delta = values[i] - values[i - 1];
651
+ if (delta >= 0) {
652
+ gains += delta;
653
+ } else {
654
+ losses -= delta;
655
+ }
656
+ }
657
+ let avgGain = gains / period;
658
+ let avgLoss = losses / period;
659
+ for (let i = period + 1;i < values.length; i += 1) {
660
+ const delta = values[i] - values[i - 1];
661
+ const gain = delta > 0 ? delta : 0;
662
+ const loss = delta < 0 ? -delta : 0;
663
+ avgGain = (avgGain * (period - 1) + gain) / period;
664
+ avgLoss = (avgLoss * (period - 1) + loss) / period;
665
+ }
666
+ if (avgLoss === 0)
667
+ return 100;
668
+ const rs = avgGain / avgLoss;
669
+ return 100 - 100 / (1 + rs);
670
+ }
671
+ function computeSmaSeries(values, period) {
672
+ if (values.length < period)
673
+ return [];
674
+ const series = [];
675
+ let sum = 0;
676
+ for (let i = 0;i < values.length; i += 1) {
677
+ sum += values[i];
678
+ if (i >= period) {
679
+ sum -= values[i - period];
680
+ }
681
+ if (i >= period - 1) {
682
+ series.push(sum / period);
683
+ }
684
+ }
685
+ return series;
686
+ }
687
+ function computeSma(values, period) {
688
+ const series = computeSmaSeries(values, period);
689
+ return series.length > 0 ? series[series.length - 1] : null;
690
+ }
691
+ function computeEmaSeries(values, period) {
692
+ if (values.length < period)
693
+ return [];
694
+ const k = 2 / (period + 1);
695
+ const start = values.slice(0, period);
696
+ let ema = start.reduce((sum, value) => sum + value, 0) / period;
697
+ const series = [ema];
698
+ for (let i = period;i < values.length; i += 1) {
699
+ ema = values[i] * k + ema * (1 - k);
700
+ series.push(ema);
701
+ }
702
+ return series;
703
+ }
704
+ function computeEma(values, period) {
705
+ const series = computeEmaSeries(values, period);
706
+ return series.length > 0 ? series[series.length - 1] : null;
707
+ }
708
+ function computeMacd(values) {
709
+ const emaFast = computeEmaSeries(values, 12);
710
+ const emaSlow = computeEmaSeries(values, 26);
711
+ if (emaFast.length === 0 || emaSlow.length === 0)
712
+ return null;
713
+ const offset = emaFast.length - emaSlow.length;
714
+ const macdSeries = emaSlow.map((value, idx) => emaFast[idx + offset] - value);
715
+ const signalSeries = computeEmaSeries(macdSeries, 9);
716
+ if (signalSeries.length === 0)
717
+ return null;
718
+ const macd = macdSeries[macdSeries.length - 1];
719
+ const signalLine = signalSeries[signalSeries.length - 1];
720
+ return {
721
+ macd,
722
+ signalLine,
723
+ histogram: macd - signalLine
724
+ };
725
+ }
726
+ function computeMaCross(values, type, fastPeriod, slowPeriod) {
727
+ if (values.length < slowPeriod)
728
+ return null;
729
+ const fastSeries = type === "ema" ? computeEmaSeries(values, fastPeriod) : computeSmaSeries(values, fastPeriod);
730
+ const slowSeries = type === "ema" ? computeEmaSeries(values, slowPeriod) : computeSmaSeries(values, slowPeriod);
731
+ if (fastSeries.length === 0 || slowSeries.length === 0)
732
+ return null;
733
+ const offset = fastSeries.length - slowSeries.length;
734
+ if (offset < 0)
735
+ return null;
736
+ const lastIndex = slowSeries.length - 1;
737
+ const fastNow = fastSeries[lastIndex + offset];
738
+ const slowNow = slowSeries[lastIndex];
739
+ const prevIndex = lastIndex - 1;
740
+ const fastPrev = prevIndex >= 0 ? fastSeries[prevIndex + offset] : null;
741
+ const slowPrev = prevIndex >= 0 ? slowSeries[prevIndex] : null;
742
+ let signal = "neutral";
743
+ if (fastPrev != null && slowPrev != null) {
744
+ if (fastPrev <= slowPrev && fastNow > slowNow) {
745
+ signal = "bullish-cross";
746
+ } else if (fastPrev >= slowPrev && fastNow < slowNow) {
747
+ signal = "bearish-cross";
748
+ } else if (fastNow > slowNow) {
749
+ signal = "bullish";
750
+ } else if (fastNow < slowNow) {
751
+ signal = "bearish";
752
+ }
753
+ } else if (fastNow > slowNow) {
754
+ signal = "bullish";
755
+ } else if (fastNow < slowNow) {
756
+ signal = "bearish";
757
+ }
758
+ return { fast: fastNow, slow: slowNow, signal };
759
+ }
760
+ function computeBollinger(values, period = 20, multiplier = 2) {
761
+ if (values.length < period)
762
+ return null;
763
+ const slice = values.slice(-period);
764
+ const mean = slice.reduce((sum, value) => sum + value, 0) / period;
765
+ const variance = slice.reduce((sum, value) => sum + Math.pow(value - mean, 2), 0) / period;
766
+ const stdDev = Math.sqrt(variance);
767
+ return {
768
+ middle: mean,
769
+ upper: mean + multiplier * stdDev,
770
+ lower: mean - multiplier * stdDev
771
+ };
772
+ }
773
+ function computePriceChange(values, lookback = 24) {
774
+ if (values.length < 2)
775
+ return null;
776
+ const current = values[values.length - 1];
777
+ const index = Math.max(0, values.length - 1 - lookback);
778
+ const previous = values[index];
779
+ if (previous === 0)
780
+ return null;
781
+ const percent = (current - previous) / previous * 100;
782
+ return {
783
+ previous,
784
+ percent
785
+ };
786
+ }
787
+ function computeAtr(bars, period = 14) {
788
+ if (bars.length < period + 1)
789
+ return null;
790
+ const ranges = [];
791
+ for (let i = 1;i < bars.length; i += 1) {
792
+ const current = bars[i];
793
+ const prev = bars[i - 1];
794
+ const rangeHighLow = current.high - current.low;
795
+ const rangeHighClose = Math.abs(current.high - prev.close);
796
+ const rangeLowClose = Math.abs(current.low - prev.close);
797
+ ranges.push(Math.max(rangeHighLow, rangeHighClose, rangeLowClose));
798
+ }
799
+ if (ranges.length < period)
800
+ return null;
801
+ const slice = ranges.slice(-period);
802
+ const sum = slice.reduce((total, value) => total + value, 0);
803
+ return sum / period;
804
+ }
805
+ // src/config.ts
806
+ import {promises as fs2} from "node:fs";
807
+ import os2 from "node:os";
808
+ import path2 from "node:path";
809
+ function getConfigPath() {
810
+ return getGlobalConfigPath();
811
+ }
812
+ var getGlobalConfigPath = function() {
813
+ return path2.join(os2.homedir(), GLOBAL_DIRNAME, GLOBAL_CONFIG_FILENAME);
814
+ };
815
+ async function loadConfigFile(filePath) {
816
+ try {
817
+ const raw = await fs2.readFile(filePath, "utf-8");
818
+ return JSON.parse(raw);
819
+ } catch {
820
+ return {};
821
+ }
822
+ }
823
+ async function loadGlobalConfig() {
824
+ return loadConfigFile(getGlobalConfigPath());
825
+ }
826
+ async function loadConfig() {
827
+ return loadGlobalConfig();
828
+ }
829
+ async function saveConfig(next) {
830
+ const filePath = getGlobalConfigPath();
831
+ await fs2.mkdir(path2.dirname(filePath), { recursive: true });
832
+ const payload = JSON.stringify(Object.fromEntries(Object.entries(next).filter(([, value]) => value !== undefined && value !== null)), null, 2);
833
+ await fs2.writeFile(filePath, payload, "utf-8");
834
+ }
835
+ async function saveGlobalConfig(next) {
836
+ const filePath = getGlobalConfigPath();
837
+ await fs2.mkdir(path2.dirname(filePath), { recursive: true });
838
+ const current = await loadGlobalConfig();
839
+ const merged = { ...current };
840
+ for (const [key, value] of Object.entries(next)) {
841
+ if (value === undefined)
842
+ continue;
843
+ if (value === null) {
844
+ delete merged[key];
845
+ } else {
846
+ merged[key] = value;
847
+ }
848
+ }
849
+ const payload = JSON.stringify(merged, null, 2);
850
+ await fs2.writeFile(filePath, payload, "utf-8");
851
+ }
852
+ var GLOBAL_DIRNAME = ".openpond";
853
+ var GLOBAL_CONFIG_FILENAME = "config.json";
854
+
855
+ // src/index.ts
856
+ var resolveUrl = function(value) {
857
+ return value.replace(/\/$/, "");
858
+ };
859
+ var resolveBaseUrl = function(options) {
860
+ const envBase = process.env.OPENPOND_BASE_URL;
861
+ const base = options.baseUrl || envBase || DEFAULT_BASE_URL;
862
+ return resolveUrl(base.trim());
863
+ };
864
+ var resolveApiUrl = function(options) {
865
+ const envBase = process.env.OPENPOND_API_URL;
866
+ const base = options.apiUrl || envBase || DEFAULT_API_URL;
867
+ return resolveUrl(base.trim());
868
+ };
869
+ var resolveToolUrl = function(options, baseUrl) {
870
+ const envBase = process.env.OPENPOND_TOOL_URL;
871
+ const base = options.toolUrl || envBase || baseUrl;
872
+ return resolveUrl(base.trim());
873
+ };
874
+ var resolveApiKey = function(options) {
875
+ const explicit = options.apiKey?.trim();
876
+ if (explicit)
877
+ return explicit;
878
+ const envKey = process.env.OPENPOND_API_KEY?.trim();
879
+ if (envKey)
880
+ return envKey;
881
+ throw new Error("OPENPOND_API_KEY is required");
882
+ };
883
+ var parseHandleRepo = function(value) {
884
+ const parts = value.split("/").filter(Boolean);
885
+ if (parts.length !== 2) {
886
+ throw new Error("expected <handle>/<repo>");
887
+ }
888
+ return { handle: parts[0], repo: parts[1] };
889
+ };
890
+ var normalizeRepoName = function(value) {
891
+ return (value || "").trim().toLowerCase();
892
+ };
893
+ var normalizeToolSummary = function(tool) {
894
+ if (!tool || typeof tool !== "object") {
895
+ return { name: "unknown", raw: tool };
896
+ }
897
+ const record = tool;
898
+ const profile = record.profile || record.function;
899
+ const name = typeof record.name === "string" ? record.name : typeof profile?.name === "string" ? profile.name : "unknown";
900
+ const description = typeof record.description === "string" ? record.description : typeof profile?.description === "string" ? profile.description : undefined;
901
+ return { name, description, raw: tool };
902
+ };
903
+ var extractDeploymentTools = function(detail) {
904
+ if (!detail)
905
+ return [];
906
+ if (Array.isArray(detail.toolsJson)) {
907
+ return detail.toolsJson;
908
+ }
909
+ if (detail.metadataJson && typeof detail.metadataJson === "object") {
910
+ const metadataTools = detail.metadataJson.tools;
911
+ if (Array.isArray(metadataTools)) {
912
+ return metadataTools;
913
+ }
914
+ }
915
+ return [];
916
+ };
917
+ async function resolveAppTarget(params) {
918
+ const { handle, repo } = parseHandleRepo(params.target);
919
+ const apps = await fetchAppsWithCache({
920
+ apiBase: params.apiBase,
921
+ apiKey: params.apiKey,
922
+ useCache: params.useCache,
923
+ cacheTtlMs: params.cacheTtlMs,
924
+ forceRefresh: params.forceRefresh
925
+ });
926
+ const normalizedRepo = normalizeRepoName(repo);
927
+ const match = apps.find((app) => {
928
+ if (app.handle && app.handle !== handle) {
929
+ return false;
930
+ }
931
+ const candidates = [
932
+ app.repo,
933
+ app.gitRepo,
934
+ app.internalToolName,
935
+ app.name,
936
+ app.id
937
+ ].map(normalizeRepoName);
938
+ return candidates.includes(normalizedRepo);
939
+ });
940
+ if (!match) {
941
+ throw new Error(`app not found for ${handle}/${repo}`);
942
+ }
943
+ return { app: match, handle, repo };
944
+ }
945
+ async function fetchAppsWithCache(params) {
946
+ if (params.useCache && !params.forceRefresh) {
947
+ const cached = await getCachedApps({
948
+ apiBase: params.apiBase,
949
+ apiKey: params.apiKey,
950
+ ttlMs: params.cacheTtlMs
951
+ });
952
+ if (cached) {
953
+ return cached;
954
+ }
955
+ }
956
+ const apps = await listApps(params.apiBase, params.apiKey);
957
+ if (params.useCache) {
958
+ await setCachedApps({
959
+ apiBase: params.apiBase,
960
+ apiKey: params.apiKey,
961
+ apps
962
+ });
963
+ }
964
+ return apps;
965
+ }
966
+ async function fetchToolsWithCache(params) {
967
+ if (params.useCache && !params.forceRefresh) {
968
+ const cached = await getCachedTools({
969
+ apiBase: params.apiBase,
970
+ apiKey: params.apiKey,
971
+ ttlMs: params.cacheTtlMs
972
+ });
973
+ if (cached) {
974
+ return cached;
975
+ }
976
+ }
977
+ const result = await listUserTools(params.apiBase, params.apiKey);
978
+ const tools = Array.isArray(result.tools) ? result.tools : [];
979
+ if (params.useCache) {
980
+ await setCachedTools({
981
+ apiBase: params.apiBase,
982
+ apiKey: params.apiKey,
983
+ tools
984
+ });
985
+ }
986
+ return tools;
987
+ }
988
+ var normalizeMethod = function(method) {
989
+ if (!method)
990
+ return "POST";
991
+ const upper = method.toUpperCase();
992
+ switch (upper) {
993
+ case "GET":
994
+ case "POST":
995
+ case "PUT":
996
+ case "DELETE":
997
+ return upper;
998
+ default:
999
+ throw new Error("method must be GET, POST, PUT, or DELETE");
1000
+ }
1001
+ };
1002
+ async function consumeAgentCreateStream(response, callbacks) {
1003
+ let conversationId;
1004
+ let appId;
1005
+ let deploymentId;
1006
+ await consumeStream(response, {
1007
+ ...callbacks,
1008
+ onConversationId: (id) => {
1009
+ conversationId = id;
1010
+ callbacks?.onConversationId?.(id);
1011
+ },
1012
+ onItems: (items) => {
1013
+ for (const item of items) {
1014
+ const typed = item;
1015
+ if (!appId && typeof typed.appId === "string") {
1016
+ appId = typed.appId;
1017
+ callbacks?.onAppId?.(typed.appId);
1018
+ }
1019
+ if (!deploymentId && typeof typed.deploymentId === "string") {
1020
+ deploymentId = typed.deploymentId;
1021
+ callbacks?.onDeploymentId?.(typed.deploymentId);
1022
+ }
1023
+ }
1024
+ callbacks?.onItems?.(items);
1025
+ }
1026
+ });
1027
+ return { conversationId, appId, deploymentId };
1028
+ }
1029
+ function createClient(options) {
1030
+ const apiKey = resolveApiKey(options);
1031
+ const baseUrl = resolveBaseUrl(options);
1032
+ const apiUrl = resolveApiUrl(options);
1033
+ const toolUrl = resolveToolUrl(options, baseUrl);
1034
+ const cacheTtlMs = options.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
1035
+ const useCache = options.useCache !== false;
1036
+ const refreshCache = async () => {
1037
+ if (!useCache)
1038
+ return;
1039
+ await Promise.all([
1040
+ fetchAppsWithCache({
1041
+ apiBase: apiUrl,
1042
+ apiKey,
1043
+ useCache,
1044
+ cacheTtlMs,
1045
+ forceRefresh: true
1046
+ }),
1047
+ fetchToolsWithCache({
1048
+ apiBase: apiUrl,
1049
+ apiKey,
1050
+ useCache,
1051
+ cacheTtlMs,
1052
+ forceRefresh: true
1053
+ })
1054
+ ]);
1055
+ };
1056
+ const resolveLatestDeploymentId = async (appId, branch) => {
1057
+ const latest = await getLatestDeploymentForApp(apiUrl, apiKey, appId, {
1058
+ branch
1059
+ });
1060
+ return latest?.id ?? null;
1061
+ };
1062
+ return {
1063
+ baseUrl,
1064
+ apiUrl,
1065
+ toolUrl,
1066
+ apiKey,
1067
+ tool: {
1068
+ list: async (target, options2) => {
1069
+ const { app } = await resolveAppTarget({
1070
+ apiBase: apiUrl,
1071
+ apiKey,
1072
+ target,
1073
+ useCache,
1074
+ cacheTtlMs,
1075
+ forceRefresh: options2?.forceRefresh
1076
+ });
1077
+ const deploymentId = options2?.deploymentId || await resolveLatestDeploymentId(app.id, options2?.branch);
1078
+ if (!deploymentId) {
1079
+ return { app, deploymentId: null, tools: [] };
1080
+ }
1081
+ const detail = await getDeploymentDetail(apiUrl, apiKey, deploymentId);
1082
+ const rawTools = extractDeploymentTools(detail);
1083
+ const tools = rawTools.map(normalizeToolSummary);
1084
+ return { app, deploymentId, tools };
1085
+ },
1086
+ run: async (target, toolName, options2) => {
1087
+ const { app } = await resolveAppTarget({
1088
+ apiBase: apiUrl,
1089
+ apiKey,
1090
+ target,
1091
+ useCache,
1092
+ cacheTtlMs,
1093
+ forceRefresh: options2?.forceRefresh
1094
+ });
1095
+ const deploymentId = options2?.deploymentId || await resolveLatestDeploymentId(app.id, options2?.branch);
1096
+ if (!deploymentId) {
1097
+ throw new Error("no deployments found");
1098
+ }
1099
+ const method = normalizeMethod(options2?.method);
1100
+ return executeHostedTool(toolUrl, apiKey, {
1101
+ appId: app.id,
1102
+ deploymentId,
1103
+ toolName,
1104
+ method,
1105
+ body: options2?.body,
1106
+ headers: options2?.headers
1107
+ });
1108
+ }
1109
+ },
1110
+ deploy: {
1111
+ watch: async (target, options2) => {
1112
+ const { app } = await resolveAppTarget({
1113
+ apiBase: apiUrl,
1114
+ apiKey,
1115
+ target,
1116
+ useCache,
1117
+ cacheTtlMs,
1118
+ forceRefresh: options2?.forceRefresh
1119
+ });
1120
+ const deploymentId = options2?.deploymentId || await resolveLatestDeploymentId(app.id, options2?.branch);
1121
+ if (!deploymentId) {
1122
+ throw new Error("no deployments found");
1123
+ }
1124
+ const intervalMs = options2?.intervalMs ?? 5000;
1125
+ const timeoutMs = options2?.timeoutMs ?? 4 * 60 * 1000;
1126
+ const logs = [];
1127
+ const seen = new Set;
1128
+ const startedAt = Date.now();
1129
+ let status = null;
1130
+ while (Date.now() - startedAt < timeoutMs) {
1131
+ const batch = await getDeploymentLogs(apiUrl, apiKey, deploymentId);
1132
+ for (const log of batch) {
1133
+ if (seen.has(log.id))
1134
+ continue;
1135
+ seen.add(log.id);
1136
+ logs.push(log);
1137
+ options2?.onLog?.(log);
1138
+ }
1139
+ const statusResponse = await getDeploymentStatus(apiUrl, apiKey, deploymentId);
1140
+ status = statusResponse.status ?? null;
1141
+ options2?.onStatus?.(status);
1142
+ if (status === "failed") {
1143
+ return { deploymentId, status, logs };
1144
+ }
1145
+ if (status === "running" || status === "deployed") {
1146
+ return { deploymentId, status, logs };
1147
+ }
1148
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
1149
+ }
1150
+ return { deploymentId, status: "timeout", logs };
1151
+ }
1152
+ },
1153
+ template: {
1154
+ status: async (target, options2) => {
1155
+ const { app } = await resolveAppTarget({
1156
+ apiBase: apiUrl,
1157
+ apiKey,
1158
+ target,
1159
+ useCache,
1160
+ cacheTtlMs,
1161
+ forceRefresh: options2?.forceRefresh
1162
+ });
1163
+ return getTemplateStatus(apiUrl, apiKey, app.id);
1164
+ },
1165
+ branches: async (target, options2) => {
1166
+ const { app } = await resolveAppTarget({
1167
+ apiBase: apiUrl,
1168
+ apiKey,
1169
+ target,
1170
+ useCache,
1171
+ cacheTtlMs,
1172
+ forceRefresh: options2?.forceRefresh
1173
+ });
1174
+ return listTemplateBranches(apiUrl, apiKey, app.id);
1175
+ },
1176
+ update: async (target, options2) => {
1177
+ const { app } = await resolveAppTarget({
1178
+ apiBase: apiUrl,
1179
+ apiKey,
1180
+ target,
1181
+ useCache,
1182
+ cacheTtlMs,
1183
+ forceRefresh: options2?.forceRefresh
1184
+ });
1185
+ const environment = options2?.environment === "preview" ? "preview" : "production";
1186
+ return deployLatestTemplate(apiUrl, apiKey, app.id, { environment });
1187
+ }
1188
+ },
1189
+ apps: {
1190
+ list: async (options2) => {
1191
+ const apps = await fetchAppsWithCache({
1192
+ apiBase: apiUrl,
1193
+ apiKey,
1194
+ useCache,
1195
+ cacheTtlMs,
1196
+ forceRefresh: options2?.forceRefresh
1197
+ });
1198
+ if (!options2?.handle)
1199
+ return apps;
1200
+ return apps.filter((app) => app.handle === options2.handle);
1201
+ },
1202
+ tools: async (options2) => {
1203
+ return fetchToolsWithCache({
1204
+ apiBase: apiUrl,
1205
+ apiKey,
1206
+ useCache,
1207
+ cacheTtlMs,
1208
+ forceRefresh: options2?.forceRefresh
1209
+ });
1210
+ },
1211
+ performance: async (options2) => {
1212
+ return getUserPerformance(apiUrl, apiKey, { appId: options2?.appId });
1213
+ },
1214
+ agentCreate: async (input, callbacks) => {
1215
+ const { refreshCache: refreshCacheFlag, ...rest } = input;
1216
+ const payload = {
1217
+ ...rest,
1218
+ streamDeployLogs: rest.streamDeployLogs ?? true
1219
+ };
1220
+ const response = await createAgentFromPrompt(apiUrl, apiKey, payload);
1221
+ if (!response.ok) {
1222
+ const text = await response.text().catch(() => "");
1223
+ throw new Error(`agent create failed: ${response.status} ${text}`);
1224
+ }
1225
+ const result = await consumeAgentCreateStream(response, callbacks);
1226
+ if (useCache && refreshCacheFlag !== false) {
1227
+ try {
1228
+ await refreshCache();
1229
+ } catch {
1230
+ }
1231
+ }
1232
+ return result;
1233
+ },
1234
+ toolsExecute: async (input) => {
1235
+ return executeUserTool(apiUrl, apiKey, input);
1236
+ },
1237
+ deploy: async (input) => {
1238
+ return deployApp(apiUrl, apiKey, input.appId, {
1239
+ environment: input.environment,
1240
+ commitSha: input.commitSha,
1241
+ branch: input.branch
1242
+ });
1243
+ },
1244
+ envGet: async (input) => {
1245
+ return getAppEnvironment(apiUrl, apiKey, input.appId);
1246
+ },
1247
+ envSet: async (input) => {
1248
+ return updateAppEnvironment(apiUrl, apiKey, input.appId, {
1249
+ envVars: input.envVars
1250
+ });
1251
+ },
1252
+ positionsTx: async (input) => {
1253
+ const method = input?.method ?? "POST";
1254
+ if (method !== "GET" && method !== "POST") {
1255
+ throw new Error("method must be GET or POST");
1256
+ }
1257
+ let query = input?.query;
1258
+ if (!query && input?.params) {
1259
+ query = {};
1260
+ for (const [key, value] of Object.entries(input.params)) {
1261
+ if (value === undefined)
1262
+ continue;
1263
+ query[key] = typeof value === "string" ? value : JSON.stringify(value);
1264
+ }
1265
+ }
1266
+ return submitPositionsTx(apiUrl, apiKey, {
1267
+ method,
1268
+ body: method === "POST" ? input?.body : undefined,
1269
+ query
1270
+ });
1271
+ }
1272
+ },
1273
+ repo: {
1274
+ create: async (input) => {
1275
+ const { refreshCache: refreshCacheFlag, ...rest } = input;
1276
+ const result = await createRepo(apiUrl, apiKey, rest);
1277
+ if (useCache && refreshCacheFlag !== false) {
1278
+ try {
1279
+ await refreshCache();
1280
+ } catch {
1281
+ }
1282
+ }
1283
+ return result;
1284
+ }
1285
+ },
1286
+ cache: {
1287
+ refresh: refreshCache
1288
+ }
1289
+ };
1290
+ }
1291
+ var DEFAULT_BASE_URL = "https://openpond.ai";
1292
+ var DEFAULT_API_URL = "https://api.openpond.ai";
1293
+ export {
1294
+ updateAppEnvironment,
1295
+ submitPositionsTx,
1296
+ startDeviceLogin,
1297
+ setCachedTools,
1298
+ setCachedApps,
1299
+ saveGlobalConfig,
1300
+ saveConfig,
1301
+ resolveWorkerBaseUrl,
1302
+ postAgentDigest,
1303
+ pollDeviceLogin,
1304
+ normalizeDataFrames,
1305
+ loadGlobalConfig,
1306
+ loadConfig,
1307
+ listUserTools,
1308
+ listTemplateBranches,
1309
+ listApps,
1310
+ getUserPerformance,
1311
+ getTemplateStatus,
1312
+ getLatestDeploymentForApp,
1313
+ getDeploymentStatus,
1314
+ getDeploymentLogs,
1315
+ getDeploymentDetail,
1316
+ getConfigPath,
1317
+ getCachedTools,
1318
+ getCachedApps,
1319
+ getAppEnvironment,
1320
+ formatStreamItem,
1321
+ fetchToolManifest,
1322
+ executeUserTool,
1323
+ executeHostedTool,
1324
+ deployLatestTemplate,
1325
+ deployApp,
1326
+ createRepo,
1327
+ createLocalProject,
1328
+ createHeadlessApps,
1329
+ createClient,
1330
+ createAgentFromPrompt,
1331
+ consumeStream,
1332
+ consumeAgentCreateStream,
1333
+ computeSmaSeries,
1334
+ computeSma,
1335
+ computeRsi,
1336
+ computePriceChange,
1337
+ computeMacd,
1338
+ computeMaCross,
1339
+ computeEmaSeries,
1340
+ computeEma,
1341
+ computeBollinger,
1342
+ computeAtr,
1343
+ commitFiles,
1344
+ apiFetch,
1345
+ DEFAULT_CACHE_TTL_MS
1346
+ };