openpond-code 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +13 -2
- package/dist/cli.js +370 -44
- package/dist/config.d.ts +20 -1
- package/dist/index.js +289 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -20,11 +20,15 @@ Login (stores key in `~/.openpond/config.json`):
|
|
|
20
20
|
openpond login
|
|
21
21
|
# or (non-interactive)
|
|
22
22
|
openpond login --api-key opk_...
|
|
23
|
+
# or save under an account profile
|
|
24
|
+
openpond login --account production --api-key opk_prod_...
|
|
25
|
+
openpond login --account secondary --api-key opk_secondary_...
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
Commands:
|
|
26
29
|
|
|
27
30
|
```bash
|
|
31
|
+
openpond --account production apps list
|
|
28
32
|
openpond tool list <handle>/<repo>
|
|
29
33
|
openpond tool run <handle>/<repo> <tool> --body '{"foo":"bar"}'
|
|
30
34
|
openpond deploy watch <handle>/<repo> --branch main
|
|
@@ -45,6 +49,13 @@ openpond apps positions tx --method GET --params '{"status":"open"}'
|
|
|
45
49
|
openpond opentool init --dir .
|
|
46
50
|
```
|
|
47
51
|
|
|
52
|
+
Global account selection:
|
|
53
|
+
|
|
54
|
+
- `--account <name>` (alias `--profile <name>`) selects which stored account/API key to use.
|
|
55
|
+
- `--base-url <url>` (alias `--baseurl`) selects the account entry matching that base URL when duplicate handles exist (for example, staging vs production).
|
|
56
|
+
- `OPENPOND_ACCOUNT=<name>` sets the default selected account for a shell/session.
|
|
57
|
+
- If omitted, CLI uses the last active stored account.
|
|
58
|
+
|
|
48
59
|
Command reference:
|
|
49
60
|
|
|
50
61
|
- `openpond login`: prompt for API key and save to `~/.openpond/config.json`.
|
|
@@ -99,8 +110,8 @@ await client.apps.agentCreate(
|
|
|
99
110
|
);
|
|
100
111
|
```
|
|
101
112
|
|
|
102
|
-
You can override hosts with `
|
|
103
|
-
via `
|
|
113
|
+
You can override hosts with `apiUrl` and `toolUrl` in `createClient`, or
|
|
114
|
+
via `OPENPOND_API_URL` and `OPENPOND_TOOL_URL`.
|
|
104
115
|
|
|
105
116
|
Examples live in `examples`.
|
|
106
117
|
|
package/dist/cli.js
CHANGED
|
@@ -296,9 +296,15 @@ function resolveWorkerBaseUrl(baseUrl) {
|
|
|
296
296
|
if (host === "apps.openpond.live") {
|
|
297
297
|
return null;
|
|
298
298
|
}
|
|
299
|
-
if (host === "
|
|
299
|
+
if (host === "apps.staging.openpond.live") {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
if (host === "api.openpond.ai" || host === "openpond.ai" || host === "openpond.live" || host === "www.openpond.live") {
|
|
300
303
|
return "https://apps.openpond.live";
|
|
301
304
|
}
|
|
305
|
+
if (host === "api.staging-api.openpond.ai" || host === "staging.openpond.ai") {
|
|
306
|
+
return "https://apps.staging.openpond.live";
|
|
307
|
+
}
|
|
302
308
|
return null;
|
|
303
309
|
})();
|
|
304
310
|
if (mappedHost) {
|
|
@@ -434,6 +440,15 @@ import os2 from "node:os";
|
|
|
434
440
|
import path2 from "node:path";
|
|
435
441
|
var GLOBAL_DIRNAME = ".openpond";
|
|
436
442
|
var GLOBAL_CONFIG_FILENAME = "config.json";
|
|
443
|
+
var DEFAULT_ACCOUNT_HANDLE = "default";
|
|
444
|
+
var ACCOUNT_SCOPED_KEYS = [
|
|
445
|
+
"apiKey",
|
|
446
|
+
"baseUrl",
|
|
447
|
+
"token",
|
|
448
|
+
"deviceCode",
|
|
449
|
+
"appId",
|
|
450
|
+
"conversationId"
|
|
451
|
+
];
|
|
437
452
|
function getGlobalConfigPath() {
|
|
438
453
|
return path2.join(os2.homedir(), GLOBAL_DIRNAME, GLOBAL_CONFIG_FILENAME);
|
|
439
454
|
}
|
|
@@ -445,29 +460,282 @@ async function loadConfigFile(filePath) {
|
|
|
445
460
|
return {};
|
|
446
461
|
}
|
|
447
462
|
}
|
|
448
|
-
|
|
449
|
-
return
|
|
463
|
+
function hasOwn(value, key) {
|
|
464
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
450
465
|
}
|
|
451
|
-
|
|
452
|
-
|
|
466
|
+
function normalizeHandle(value) {
|
|
467
|
+
if (typeof value !== "string")
|
|
468
|
+
return null;
|
|
469
|
+
const trimmed = value.trim();
|
|
470
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
453
471
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
472
|
+
function normalizeBaseUrl(value) {
|
|
473
|
+
if (typeof value !== "string")
|
|
474
|
+
return null;
|
|
475
|
+
const trimmed = value.trim();
|
|
476
|
+
if (!trimmed)
|
|
477
|
+
return null;
|
|
478
|
+
return trimmed.replace(/\/$/, "");
|
|
479
|
+
}
|
|
480
|
+
function handleEquals(left, right) {
|
|
481
|
+
return left.trim().toLowerCase() === right.trim().toLowerCase();
|
|
482
|
+
}
|
|
483
|
+
function findAccountIndex(accounts, handle, baseUrl) {
|
|
484
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
485
|
+
return accounts.findIndex((candidate) => {
|
|
486
|
+
if (!handleEquals(candidate.handle, handle))
|
|
487
|
+
return false;
|
|
488
|
+
if (!normalizedBaseUrl)
|
|
489
|
+
return true;
|
|
490
|
+
return normalizeBaseUrl(candidate.baseUrl) === normalizedBaseUrl;
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
function sanitizeSession(value) {
|
|
494
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
const input = value;
|
|
498
|
+
const out = {};
|
|
499
|
+
if (typeof input.token === "string")
|
|
500
|
+
out.token = input.token;
|
|
501
|
+
if (typeof input.deviceCode === "string" || input.deviceCode === null) {
|
|
502
|
+
out.deviceCode = input.deviceCode;
|
|
503
|
+
}
|
|
504
|
+
if (typeof input.appId === "string" || input.appId === null) {
|
|
505
|
+
out.appId = input.appId;
|
|
506
|
+
}
|
|
507
|
+
if (typeof input.conversationId === "string" || input.conversationId === null) {
|
|
508
|
+
out.conversationId = input.conversationId;
|
|
509
|
+
}
|
|
510
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
511
|
+
}
|
|
512
|
+
function sanitizeAccount(value) {
|
|
513
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
514
|
+
return null;
|
|
515
|
+
const input = value;
|
|
516
|
+
const handle = normalizeHandle(typeof input.handle === "string" ? input.handle : undefined);
|
|
517
|
+
if (!handle)
|
|
518
|
+
return null;
|
|
519
|
+
const out = { handle };
|
|
520
|
+
if (typeof input.apiKey === "string")
|
|
521
|
+
out.apiKey = input.apiKey;
|
|
522
|
+
if (typeof input.baseUrl === "string")
|
|
523
|
+
out.baseUrl = input.baseUrl;
|
|
524
|
+
if (typeof input.environment === "string")
|
|
525
|
+
out.environment = input.environment;
|
|
526
|
+
const session = sanitizeSession(input.session);
|
|
527
|
+
if (session)
|
|
528
|
+
out.session = session;
|
|
529
|
+
return out;
|
|
530
|
+
}
|
|
531
|
+
function extractLegacySession(raw) {
|
|
532
|
+
const session = {};
|
|
533
|
+
if (typeof raw.token === "string")
|
|
534
|
+
session.token = raw.token;
|
|
535
|
+
if (typeof raw.deviceCode === "string" || raw.deviceCode === null) {
|
|
536
|
+
session.deviceCode = raw.deviceCode;
|
|
537
|
+
}
|
|
538
|
+
if (typeof raw.appId === "string" || raw.appId === null) {
|
|
539
|
+
session.appId = raw.appId;
|
|
540
|
+
}
|
|
541
|
+
if (typeof raw.conversationId === "string" || raw.conversationId === null) {
|
|
542
|
+
session.conversationId = raw.conversationId;
|
|
543
|
+
}
|
|
544
|
+
return Object.keys(session).length > 0 ? session : undefined;
|
|
545
|
+
}
|
|
546
|
+
function extractLegacyAccount(raw, handle) {
|
|
547
|
+
const out = { handle };
|
|
548
|
+
if (typeof raw.apiKey === "string")
|
|
549
|
+
out.apiKey = raw.apiKey;
|
|
550
|
+
if (typeof raw.baseUrl === "string")
|
|
551
|
+
out.baseUrl = raw.baseUrl;
|
|
552
|
+
const session = extractLegacySession(raw);
|
|
553
|
+
if (session)
|
|
554
|
+
out.session = session;
|
|
555
|
+
return out;
|
|
556
|
+
}
|
|
557
|
+
function normalizeGlobalConfig(raw) {
|
|
558
|
+
const normalized = {};
|
|
559
|
+
if (typeof raw.lspEnabled === "boolean")
|
|
560
|
+
normalized.lspEnabled = raw.lspEnabled;
|
|
561
|
+
if (raw.executionMode === "local" || raw.executionMode === "hosted") {
|
|
562
|
+
normalized.executionMode = raw.executionMode;
|
|
563
|
+
}
|
|
564
|
+
if (raw.mode === "general" || raw.mode === "builder") {
|
|
565
|
+
normalized.mode = raw.mode;
|
|
566
|
+
}
|
|
567
|
+
const accounts = [];
|
|
568
|
+
const sourceAccounts = Array.isArray(raw.accounts) ? raw.accounts : [];
|
|
569
|
+
for (const candidate of sourceAccounts) {
|
|
570
|
+
const account = sanitizeAccount(candidate);
|
|
571
|
+
if (!account)
|
|
461
572
|
continue;
|
|
462
|
-
if (
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
573
|
+
if (findAccountIndex(accounts, account.handle, account.baseUrl) !== -1)
|
|
574
|
+
continue;
|
|
575
|
+
accounts.push(account);
|
|
576
|
+
}
|
|
577
|
+
if (accounts.length === 0) {
|
|
578
|
+
const legacyHandle = normalizeHandle(raw.activeHandle) || DEFAULT_ACCOUNT_HANDLE;
|
|
579
|
+
accounts.push(extractLegacyAccount(raw, legacyHandle));
|
|
580
|
+
}
|
|
581
|
+
const requested = normalizeHandle(raw.activeHandle);
|
|
582
|
+
const resolvedHandle = requested && findAccountIndex(accounts, requested) !== -1 ? accounts[findAccountIndex(accounts, requested)].handle : accounts[0].handle;
|
|
583
|
+
normalized.accounts = accounts;
|
|
584
|
+
normalized.activeHandle = resolvedHandle;
|
|
585
|
+
return normalized;
|
|
586
|
+
}
|
|
587
|
+
function resolveRequestedHandle(global, explicitAccount) {
|
|
588
|
+
const accounts = global.accounts ?? [];
|
|
589
|
+
const requested = normalizeHandle(explicitAccount) || normalizeHandle(process.env.OPENPOND_ACCOUNT) || normalizeHandle(global.activeHandle) || accounts[0]?.handle || DEFAULT_ACCOUNT_HANDLE;
|
|
590
|
+
const idx = findAccountIndex(accounts, requested);
|
|
591
|
+
return idx === -1 ? requested : accounts[idx].handle;
|
|
592
|
+
}
|
|
593
|
+
function ensureAccount(accounts, handle, baseUrl) {
|
|
594
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
595
|
+
const idx = findAccountIndex(accounts, handle, normalizedBaseUrl);
|
|
596
|
+
if (idx !== -1) {
|
|
597
|
+
return accounts[idx];
|
|
598
|
+
}
|
|
599
|
+
if (!normalizedBaseUrl) {
|
|
600
|
+
const firstByHandle = findAccountIndex(accounts, handle);
|
|
601
|
+
if (firstByHandle !== -1) {
|
|
602
|
+
return accounts[firstByHandle];
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
const next = { handle };
|
|
606
|
+
if (normalizedBaseUrl) {
|
|
607
|
+
next.baseUrl = normalizedBaseUrl;
|
|
608
|
+
}
|
|
609
|
+
accounts.push(next);
|
|
610
|
+
return next;
|
|
611
|
+
}
|
|
612
|
+
function cleanupAccount(account) {
|
|
613
|
+
if (account.session && Object.keys(account.session).length === 0) {
|
|
614
|
+
delete account.session;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
function applyScopedKey(account, key, value, options) {
|
|
618
|
+
const shouldDelete = value === null || value === undefined && options.undefinedDeletes;
|
|
619
|
+
switch (key) {
|
|
620
|
+
case "apiKey": {
|
|
621
|
+
if (shouldDelete) {
|
|
622
|
+
delete account.apiKey;
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
if (typeof value === "string") {
|
|
626
|
+
account.apiKey = value;
|
|
627
|
+
}
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
case "baseUrl": {
|
|
631
|
+
if (shouldDelete) {
|
|
632
|
+
delete account.baseUrl;
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
if (typeof value === "string") {
|
|
636
|
+
account.baseUrl = value;
|
|
637
|
+
}
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
case "token":
|
|
641
|
+
case "deviceCode":
|
|
642
|
+
case "appId":
|
|
643
|
+
case "conversationId": {
|
|
644
|
+
if (!account.session)
|
|
645
|
+
account.session = {};
|
|
646
|
+
if (shouldDelete) {
|
|
647
|
+
delete account.session[key];
|
|
648
|
+
cleanupAccount(account);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (typeof value === "string" || value === null) {
|
|
652
|
+
account.session[key] = value;
|
|
653
|
+
}
|
|
654
|
+
cleanupAccount(account);
|
|
655
|
+
return;
|
|
466
656
|
}
|
|
467
657
|
}
|
|
468
|
-
|
|
658
|
+
}
|
|
659
|
+
function applyAccountPatch(global, source, options) {
|
|
660
|
+
const hasScopedPatch = ACCOUNT_SCOPED_KEYS.some((key) => hasOwn(source, key));
|
|
661
|
+
if (!hasScopedPatch)
|
|
662
|
+
return false;
|
|
663
|
+
const accounts = global.accounts ?? [];
|
|
664
|
+
const handle = resolveRequestedHandle(global, source.activeHandle);
|
|
665
|
+
const requestedBaseUrl = normalizeBaseUrl(hasOwn(source, "baseUrl") ? source.baseUrl ?? null : process.env.OPENPOND_BASE_URL);
|
|
666
|
+
const account = ensureAccount(accounts, handle, requestedBaseUrl);
|
|
667
|
+
for (const key of ACCOUNT_SCOPED_KEYS) {
|
|
668
|
+
if (!hasOwn(source, key))
|
|
669
|
+
continue;
|
|
670
|
+
applyScopedKey(account, key, source[key], options);
|
|
671
|
+
}
|
|
672
|
+
global.accounts = accounts;
|
|
673
|
+
global.activeHandle = handle;
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
676
|
+
function applyTopLevelPatch(global, source) {
|
|
677
|
+
if (hasOwn(source, "lspEnabled")) {
|
|
678
|
+
if (typeof source.lspEnabled === "boolean") {
|
|
679
|
+
global.lspEnabled = source.lspEnabled;
|
|
680
|
+
} else if (source.lspEnabled === null) {
|
|
681
|
+
delete global.lspEnabled;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
if (hasOwn(source, "executionMode")) {
|
|
685
|
+
if (source.executionMode === "local" || source.executionMode === "hosted") {
|
|
686
|
+
global.executionMode = source.executionMode;
|
|
687
|
+
} else if (source.executionMode === null) {
|
|
688
|
+
delete global.executionMode;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
if (hasOwn(source, "mode")) {
|
|
692
|
+
if (source.mode === "general" || source.mode === "builder") {
|
|
693
|
+
global.mode = source.mode;
|
|
694
|
+
} else if (source.mode === null) {
|
|
695
|
+
delete global.mode;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
if (typeof source.activeHandle === "string" && source.activeHandle.trim().length > 0) {
|
|
699
|
+
const requested = resolveRequestedHandle(global, source.activeHandle);
|
|
700
|
+
global.activeHandle = requested;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
async function writeGlobalConfig(next) {
|
|
704
|
+
const filePath = getGlobalConfigPath();
|
|
705
|
+
await fs2.mkdir(path2.dirname(filePath), { recursive: true });
|
|
706
|
+
const payload = JSON.stringify(next, null, 2);
|
|
469
707
|
await fs2.writeFile(filePath, payload, "utf-8");
|
|
470
708
|
}
|
|
709
|
+
async function loadGlobalConfig() {
|
|
710
|
+
const raw = await loadConfigFile(getGlobalConfigPath());
|
|
711
|
+
return normalizeGlobalConfig(raw);
|
|
712
|
+
}
|
|
713
|
+
async function loadConfig(options = {}) {
|
|
714
|
+
const global = await loadGlobalConfig();
|
|
715
|
+
const accounts = global.accounts ?? [];
|
|
716
|
+
const requested = resolveRequestedHandle(global, options.account);
|
|
717
|
+
const requestedBaseUrl = normalizeBaseUrl(options.baseUrl ?? process.env.OPENPOND_BASE_URL);
|
|
718
|
+
const idxWithBase = findAccountIndex(accounts, requested, requestedBaseUrl);
|
|
719
|
+
const idx = idxWithBase !== -1 ? idxWithBase : findAccountIndex(accounts, requested);
|
|
720
|
+
const account = idx === -1 ? null : accounts[idx];
|
|
721
|
+
const session = account?.session;
|
|
722
|
+
return {
|
|
723
|
+
...global,
|
|
724
|
+
activeHandle: requested,
|
|
725
|
+
apiKey: account?.apiKey,
|
|
726
|
+
baseUrl: account?.baseUrl,
|
|
727
|
+
token: session?.token,
|
|
728
|
+
deviceCode: session?.deviceCode,
|
|
729
|
+
appId: session?.appId,
|
|
730
|
+
conversationId: session?.conversationId
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
async function saveGlobalConfig(next) {
|
|
734
|
+
const current = await loadGlobalConfig();
|
|
735
|
+
applyTopLevelPatch(current, next);
|
|
736
|
+
applyAccountPatch(current, next, { undefinedDeletes: false });
|
|
737
|
+
await writeGlobalConfig(current);
|
|
738
|
+
}
|
|
471
739
|
|
|
472
740
|
// src/stream.ts
|
|
473
741
|
function normalizeDataFrames(raw) {
|
|
@@ -644,7 +912,7 @@ function formatStreamItem(item) {
|
|
|
644
912
|
// src/cli-package.ts
|
|
645
913
|
function parseArgs(argv) {
|
|
646
914
|
const args = [...argv];
|
|
647
|
-
|
|
915
|
+
let command = "";
|
|
648
916
|
const options = {};
|
|
649
917
|
const rest = [];
|
|
650
918
|
while (args.length > 0) {
|
|
@@ -655,19 +923,62 @@ function parseArgs(argv) {
|
|
|
655
923
|
const value = args[0] && !args[0].startsWith("--") ? args.shift() : "true";
|
|
656
924
|
options[key] = value;
|
|
657
925
|
} else {
|
|
658
|
-
|
|
926
|
+
if (!command) {
|
|
927
|
+
command = next;
|
|
928
|
+
} else {
|
|
929
|
+
rest.push(next);
|
|
930
|
+
}
|
|
659
931
|
}
|
|
660
932
|
}
|
|
661
933
|
return { command, options, rest };
|
|
662
934
|
}
|
|
935
|
+
function resolveAccountOption(options) {
|
|
936
|
+
const raw = typeof options.account === "string" ? options.account : typeof options.profile === "string" ? options.profile : null;
|
|
937
|
+
if (!raw)
|
|
938
|
+
return null;
|
|
939
|
+
const trimmed = raw.trim();
|
|
940
|
+
if (!trimmed || trimmed === "true") {
|
|
941
|
+
throw new Error("account must be a non-empty value");
|
|
942
|
+
}
|
|
943
|
+
return trimmed;
|
|
944
|
+
}
|
|
945
|
+
function resolveBaseUrlOption(options) {
|
|
946
|
+
const raw = typeof options.baseUrl === "string" ? options.baseUrl : typeof options.baseurl === "string" ? options.baseurl : null;
|
|
947
|
+
if (!raw)
|
|
948
|
+
return null;
|
|
949
|
+
const trimmed = raw.trim();
|
|
950
|
+
if (!trimmed || trimmed === "true") {
|
|
951
|
+
throw new Error("baseurl must be a non-empty value");
|
|
952
|
+
}
|
|
953
|
+
return trimmed.replace(/\/$/, "");
|
|
954
|
+
}
|
|
663
955
|
function resolveBaseUrl(config) {
|
|
664
956
|
const envBase = process.env.OPENPOND_BASE_URL;
|
|
665
957
|
const base = envBase || config.baseUrl || "https://openpond.ai";
|
|
666
958
|
return base.replace(/\/$/, "");
|
|
667
959
|
}
|
|
668
|
-
function
|
|
960
|
+
function mapUiBaseToApiBase(baseUrl) {
|
|
961
|
+
if (!baseUrl)
|
|
962
|
+
return null;
|
|
963
|
+
const trimmed = baseUrl.replace(/\/$/, "");
|
|
964
|
+
try {
|
|
965
|
+
const url = new URL(trimmed);
|
|
966
|
+
const host = url.hostname.toLowerCase();
|
|
967
|
+
if (host === "staging.openpond.ai") {
|
|
968
|
+
return "https://api.staging-api.openpond.ai";
|
|
969
|
+
}
|
|
970
|
+
if (host === "openpond.ai" || host === "openpond.live" || host === "www.openpond.live") {
|
|
971
|
+
return "https://api.openpond.ai";
|
|
972
|
+
}
|
|
973
|
+
} catch {
|
|
974
|
+
return null;
|
|
975
|
+
}
|
|
976
|
+
return null;
|
|
977
|
+
}
|
|
978
|
+
function resolvePublicApiBaseUrl(config) {
|
|
669
979
|
const envBase = process.env.OPENPOND_API_URL;
|
|
670
|
-
const
|
|
980
|
+
const mapped = mapUiBaseToApiBase(process.env.OPENPOND_BASE_URL || config?.baseUrl);
|
|
981
|
+
const base = envBase || mapped || "https://api.openpond.ai";
|
|
671
982
|
return base.replace(/\/$/, "");
|
|
672
983
|
}
|
|
673
984
|
function normalizeTemplateRepoUrl(input2, baseUrl) {
|
|
@@ -759,7 +1070,7 @@ async function ensureApiKey(config, baseUrl) {
|
|
|
759
1070
|
if (existing)
|
|
760
1071
|
return existing;
|
|
761
1072
|
const apiKey = await promptForApiKey();
|
|
762
|
-
await saveGlobalConfig({ apiKey, baseUrl });
|
|
1073
|
+
await saveGlobalConfig({ apiKey, baseUrl, activeHandle: config.activeHandle });
|
|
763
1074
|
console.log("saved api key to ~/.openpond/config.json");
|
|
764
1075
|
return apiKey;
|
|
765
1076
|
}
|
|
@@ -945,7 +1256,7 @@ async function pollDeploymentLogs(params) {
|
|
|
945
1256
|
async function runTemplateStatus(_options, target) {
|
|
946
1257
|
const config = await loadConfig();
|
|
947
1258
|
const uiBase = resolveBaseUrl(config);
|
|
948
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1259
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
949
1260
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
950
1261
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
951
1262
|
const status = await getTemplateStatus(apiBase, apiKey, app.id);
|
|
@@ -954,7 +1265,7 @@ async function runTemplateStatus(_options, target) {
|
|
|
954
1265
|
async function runTemplateBranches(_options, target) {
|
|
955
1266
|
const config = await loadConfig();
|
|
956
1267
|
const uiBase = resolveBaseUrl(config);
|
|
957
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1268
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
958
1269
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
959
1270
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
960
1271
|
const branches = await listTemplateBranches(apiBase, apiKey, app.id);
|
|
@@ -963,7 +1274,7 @@ async function runTemplateBranches(_options, target) {
|
|
|
963
1274
|
async function runTemplateUpdate(options, target) {
|
|
964
1275
|
const config = await loadConfig();
|
|
965
1276
|
const uiBase = resolveBaseUrl(config);
|
|
966
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1277
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
967
1278
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
968
1279
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
969
1280
|
const envRaw = typeof options.env === "string" ? options.env : typeof options.environment === "string" ? options.environment : undefined;
|
|
@@ -1001,8 +1312,12 @@ function printHelp() {
|
|
|
1001
1312
|
console.log(" openpond apps positions tx [--method <GET|POST>] [--body <json>] [--params <json>]");
|
|
1002
1313
|
console.log(" openpond opentool <init|validate|build> [args]");
|
|
1003
1314
|
console.log("");
|
|
1315
|
+
console.log("Global options:");
|
|
1316
|
+
console.log(" --account <name> (alias: --profile <name>)");
|
|
1317
|
+
console.log(" --base-url <url> (alias: --baseurl)");
|
|
1318
|
+
console.log("");
|
|
1004
1319
|
console.log("Env:");
|
|
1005
|
-
console.log(" OPENPOND_API_KEY, OPENPOND_BASE_URL, OPENPOND_API_URL, OPENPOND_TOOL_URL");
|
|
1320
|
+
console.log(" OPENPOND_API_KEY, OPENPOND_ACCOUNT, OPENPOND_BASE_URL, OPENPOND_API_URL, OPENPOND_TOOL_URL");
|
|
1006
1321
|
}
|
|
1007
1322
|
async function runLogin(options) {
|
|
1008
1323
|
const config = await loadConfig();
|
|
@@ -1015,13 +1330,13 @@ async function runLogin(options) {
|
|
|
1015
1330
|
if (!apiKey.startsWith("opk_")) {
|
|
1016
1331
|
console.log("warning: API keys usually start with opk_.");
|
|
1017
1332
|
}
|
|
1018
|
-
await saveGlobalConfig({ apiKey, baseUrl });
|
|
1333
|
+
await saveGlobalConfig({ apiKey, baseUrl, activeHandle: config.activeHandle });
|
|
1019
1334
|
console.log("saved api key to ~/.openpond/config.json");
|
|
1020
1335
|
}
|
|
1021
1336
|
async function runToolList(options, target) {
|
|
1022
1337
|
const config = await loadConfig();
|
|
1023
1338
|
const uiBase = resolveBaseUrl(config);
|
|
1024
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1339
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1025
1340
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1026
1341
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
1027
1342
|
const branch = typeof options.branch === "string" ? String(options.branch) : undefined;
|
|
@@ -1048,7 +1363,7 @@ async function runToolList(options, target) {
|
|
|
1048
1363
|
async function runToolRun(options, target, toolName) {
|
|
1049
1364
|
const config = await loadConfig();
|
|
1050
1365
|
const uiBase = resolveBaseUrl(config);
|
|
1051
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1366
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1052
1367
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1053
1368
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
1054
1369
|
const branch = typeof options.branch === "string" ? String(options.branch) : undefined;
|
|
@@ -1082,7 +1397,7 @@ async function runToolRun(options, target, toolName) {
|
|
|
1082
1397
|
async function runDeployWatch(options, target) {
|
|
1083
1398
|
const config = await loadConfig();
|
|
1084
1399
|
const uiBase = resolveBaseUrl(config);
|
|
1085
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1400
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1086
1401
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1087
1402
|
const { app, handle, repo } = await resolveAppTarget(apiBase, apiKey, target);
|
|
1088
1403
|
const branch = typeof options.branch === "string" ? String(options.branch) : undefined;
|
|
@@ -1112,7 +1427,7 @@ async function runRepoCreate(options, nameParts) {
|
|
|
1112
1427
|
const config = await loadConfig();
|
|
1113
1428
|
const uiBase = resolveBaseUrl(config);
|
|
1114
1429
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1115
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1430
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1116
1431
|
const templateInput = typeof options.template === "string" ? options.template.trim() : "";
|
|
1117
1432
|
if (templateInput && (options.empty === "true" || options.opentool === "true")) {
|
|
1118
1433
|
throw new Error("choose one: --template or --empty/--opentool");
|
|
@@ -1325,14 +1640,14 @@ async function runAppsTools() {
|
|
|
1325
1640
|
const config = await loadConfig();
|
|
1326
1641
|
const uiBase = resolveBaseUrl(config);
|
|
1327
1642
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1328
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1643
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1329
1644
|
const tools = await fetchToolsWithCache({ apiBase, apiKey });
|
|
1330
1645
|
console.log(JSON.stringify(tools, null, 2));
|
|
1331
1646
|
}
|
|
1332
1647
|
async function runAppsList(options) {
|
|
1333
1648
|
const config = await loadConfig();
|
|
1334
1649
|
const uiBase = resolveBaseUrl(config);
|
|
1335
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1650
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1336
1651
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1337
1652
|
const handle = typeof options.handle === "string" ? String(options.handle) : undefined;
|
|
1338
1653
|
const normalizedHandle = handle ? normalizeRepoName(handle) : null;
|
|
@@ -1362,7 +1677,7 @@ async function runAppsPerformance(options) {
|
|
|
1362
1677
|
const config = await loadConfig();
|
|
1363
1678
|
const uiBase = resolveBaseUrl(config);
|
|
1364
1679
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1365
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1680
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1366
1681
|
const appId = typeof options.appId === "string" ? String(options.appId) : undefined;
|
|
1367
1682
|
const performance = await getUserPerformance(apiBase, apiKey, { appId });
|
|
1368
1683
|
console.log(JSON.stringify(performance, null, 2));
|
|
@@ -1370,7 +1685,7 @@ async function runAppsPerformance(options) {
|
|
|
1370
1685
|
async function runAppsSummary(_options, target) {
|
|
1371
1686
|
const config = await loadConfig();
|
|
1372
1687
|
const uiBase = resolveBaseUrl(config);
|
|
1373
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1688
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1374
1689
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1375
1690
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
1376
1691
|
const summary = await getAppRuntimeSummary(apiBase, apiKey, app.id);
|
|
@@ -1383,7 +1698,7 @@ async function runAppsAssistant(options, mode, target, contentParts) {
|
|
|
1383
1698
|
}
|
|
1384
1699
|
const config = await loadConfig();
|
|
1385
1700
|
const uiBase = resolveBaseUrl(config);
|
|
1386
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1701
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1387
1702
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1388
1703
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
1389
1704
|
const result = await runAssistantMode(apiBase, apiKey, {
|
|
@@ -1397,7 +1712,7 @@ async function runAppsAgentCreate(options, contentParts) {
|
|
|
1397
1712
|
const config = await loadConfig();
|
|
1398
1713
|
const uiBase = resolveBaseUrl(config);
|
|
1399
1714
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1400
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1715
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1401
1716
|
const prompt = (typeof options.prompt === "string" ? options.prompt : null) || contentParts.join(" ");
|
|
1402
1717
|
if (!prompt.trim()) {
|
|
1403
1718
|
throw new Error("usage: apps agent create --prompt <text>");
|
|
@@ -1481,7 +1796,7 @@ async function runAppsToolsExecute(options, appId, deploymentId, toolName) {
|
|
|
1481
1796
|
const config = await loadConfig();
|
|
1482
1797
|
const uiBase = resolveBaseUrl(config);
|
|
1483
1798
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1484
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1799
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1485
1800
|
const methodRaw = typeof options.method === "string" ? String(options.method).toUpperCase() : undefined;
|
|
1486
1801
|
const method = methodRaw && ["GET", "POST", "PUT", "DELETE"].includes(methodRaw) ? methodRaw : undefined;
|
|
1487
1802
|
if (methodRaw && !method) {
|
|
@@ -1529,7 +1844,7 @@ async function runAppsEnvSet(options, target) {
|
|
|
1529
1844
|
}
|
|
1530
1845
|
const config = await loadConfig();
|
|
1531
1846
|
const uiBase = resolveBaseUrl(config);
|
|
1532
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1847
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1533
1848
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1534
1849
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
1535
1850
|
const result = await updateAppEnvironment(apiBase, apiKey, app.id, { envVars });
|
|
@@ -1538,7 +1853,7 @@ async function runAppsEnvSet(options, target) {
|
|
|
1538
1853
|
async function runAppsEnvGet(_options, target) {
|
|
1539
1854
|
const config = await loadConfig();
|
|
1540
1855
|
const uiBase = resolveBaseUrl(config);
|
|
1541
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1856
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1542
1857
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1543
1858
|
const { app } = await resolveAppTarget(apiBase, apiKey, target);
|
|
1544
1859
|
const result = await getAppEnvironment(apiBase, apiKey, app.id);
|
|
@@ -1547,7 +1862,7 @@ async function runAppsEnvGet(_options, target) {
|
|
|
1547
1862
|
async function runAppsDeploy(options, target) {
|
|
1548
1863
|
const config = await loadConfig();
|
|
1549
1864
|
const uiBase = resolveBaseUrl(config);
|
|
1550
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1865
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1551
1866
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1552
1867
|
const { app, handle, repo } = await resolveAppTarget(apiBase, apiKey, target);
|
|
1553
1868
|
const envRaw = typeof options.env === "string" ? options.env : typeof options.environment === "string" ? options.environment : undefined;
|
|
@@ -1570,7 +1885,7 @@ async function runAppsPositionsTx(options) {
|
|
|
1570
1885
|
const config = await loadConfig();
|
|
1571
1886
|
const uiBase = resolveBaseUrl(config);
|
|
1572
1887
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1573
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1888
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1574
1889
|
const methodRaw = typeof options.method === "string" ? String(options.method).toUpperCase() : "POST";
|
|
1575
1890
|
const method = methodRaw === "GET" ? "GET" : "POST";
|
|
1576
1891
|
if (methodRaw !== "GET" && methodRaw !== "POST") {
|
|
@@ -1638,7 +1953,7 @@ async function runAppsStoreEvents(options) {
|
|
|
1638
1953
|
const config = await loadConfig();
|
|
1639
1954
|
const uiBase = resolveBaseUrl(config);
|
|
1640
1955
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1641
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1956
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1642
1957
|
const query = resolveStoreEventsParams(options);
|
|
1643
1958
|
const result = await submitPositionsTx(apiBase, apiKey, {
|
|
1644
1959
|
method: "GET",
|
|
@@ -1650,7 +1965,7 @@ async function runAppsTradeFacts(options) {
|
|
|
1650
1965
|
const config = await loadConfig();
|
|
1651
1966
|
const uiBase = resolveBaseUrl(config);
|
|
1652
1967
|
const apiKey = await ensureApiKey(config, uiBase);
|
|
1653
|
-
const apiBase = resolvePublicApiBaseUrl();
|
|
1968
|
+
const apiBase = resolvePublicApiBaseUrl(config);
|
|
1654
1969
|
const appId = typeof options.appId === "string" ? options.appId : undefined;
|
|
1655
1970
|
const performance = await getUserPerformance(apiBase, apiKey, { appId });
|
|
1656
1971
|
if (performance && typeof performance === "object" && "trades" in performance && Array.isArray(performance.trades)) {
|
|
@@ -1661,6 +1976,17 @@ async function runAppsTradeFacts(options) {
|
|
|
1661
1976
|
}
|
|
1662
1977
|
async function main() {
|
|
1663
1978
|
const { command, options, rest } = parseArgs(process.argv.slice(2));
|
|
1979
|
+
const selectedAccount = resolveAccountOption(options);
|
|
1980
|
+
const selectedBaseUrl = resolveBaseUrlOption(options);
|
|
1981
|
+
if (selectedAccount) {
|
|
1982
|
+
process.env.OPENPOND_ACCOUNT = selectedAccount;
|
|
1983
|
+
}
|
|
1984
|
+
if (!selectedAccount && typeof options.handle === "string" && options.handle.trim().length > 0) {
|
|
1985
|
+
process.env.OPENPOND_ACCOUNT = options.handle.trim();
|
|
1986
|
+
}
|
|
1987
|
+
if (selectedBaseUrl) {
|
|
1988
|
+
process.env.OPENPOND_BASE_URL = selectedBaseUrl;
|
|
1989
|
+
}
|
|
1664
1990
|
if (!command || command === "help") {
|
|
1665
1991
|
printHelp();
|
|
1666
1992
|
return;
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
|
+
export type LocalSessionConfig = {
|
|
2
|
+
token?: string;
|
|
3
|
+
deviceCode?: string | null;
|
|
4
|
+
appId?: string | null;
|
|
5
|
+
conversationId?: string | null;
|
|
6
|
+
};
|
|
7
|
+
export type LocalAccountConfig = {
|
|
8
|
+
handle: string;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
environment?: string;
|
|
12
|
+
session?: LocalSessionConfig;
|
|
13
|
+
};
|
|
1
14
|
export type LocalConfig = {
|
|
15
|
+
accounts?: LocalAccountConfig[];
|
|
16
|
+
activeHandle?: string;
|
|
2
17
|
baseUrl?: string;
|
|
3
18
|
apiKey?: string;
|
|
4
19
|
token?: string;
|
|
@@ -9,8 +24,12 @@ export type LocalConfig = {
|
|
|
9
24
|
executionMode?: "local" | "hosted";
|
|
10
25
|
mode?: "general" | "builder";
|
|
11
26
|
};
|
|
27
|
+
export type LoadConfigOptions = {
|
|
28
|
+
account?: string;
|
|
29
|
+
baseUrl?: string;
|
|
30
|
+
};
|
|
12
31
|
export declare function getConfigPath(): string;
|
|
13
32
|
export declare function loadGlobalConfig(): Promise<LocalConfig>;
|
|
14
|
-
export declare function loadConfig(): Promise<LocalConfig>;
|
|
33
|
+
export declare function loadConfig(options?: LoadConfigOptions): Promise<LocalConfig>;
|
|
15
34
|
export declare function saveConfig(next: LocalConfig): Promise<void>;
|
|
16
35
|
export declare function saveGlobalConfig(next: LocalConfig): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -356,9 +356,15 @@ function resolveWorkerBaseUrl(baseUrl) {
|
|
|
356
356
|
if (host === "apps.openpond.live") {
|
|
357
357
|
return null;
|
|
358
358
|
}
|
|
359
|
-
if (host === "
|
|
359
|
+
if (host === "apps.staging.openpond.live") {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
if (host === "api.openpond.ai" || host === "openpond.ai" || host === "openpond.live" || host === "www.openpond.live") {
|
|
360
363
|
return "https://apps.openpond.live";
|
|
361
364
|
}
|
|
365
|
+
if (host === "api.staging-api.openpond.ai" || host === "staging.openpond.ai") {
|
|
366
|
+
return "https://apps.staging.openpond.live";
|
|
367
|
+
}
|
|
362
368
|
return null;
|
|
363
369
|
})();
|
|
364
370
|
if (mappedHost) {
|
|
@@ -827,6 +833,15 @@ import os2 from "node:os";
|
|
|
827
833
|
import path2 from "node:path";
|
|
828
834
|
var GLOBAL_DIRNAME = ".openpond";
|
|
829
835
|
var GLOBAL_CONFIG_FILENAME = "config.json";
|
|
836
|
+
var DEFAULT_ACCOUNT_HANDLE = "default";
|
|
837
|
+
var ACCOUNT_SCOPED_KEYS = [
|
|
838
|
+
"apiKey",
|
|
839
|
+
"baseUrl",
|
|
840
|
+
"token",
|
|
841
|
+
"deviceCode",
|
|
842
|
+
"appId",
|
|
843
|
+
"conversationId"
|
|
844
|
+
];
|
|
830
845
|
function getConfigPath() {
|
|
831
846
|
return getGlobalConfigPath();
|
|
832
847
|
}
|
|
@@ -841,34 +856,287 @@ async function loadConfigFile(filePath) {
|
|
|
841
856
|
return {};
|
|
842
857
|
}
|
|
843
858
|
}
|
|
844
|
-
|
|
845
|
-
return
|
|
859
|
+
function hasOwn(value, key) {
|
|
860
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
846
861
|
}
|
|
847
|
-
|
|
848
|
-
|
|
862
|
+
function normalizeHandle(value) {
|
|
863
|
+
if (typeof value !== "string")
|
|
864
|
+
return null;
|
|
865
|
+
const trimmed = value.trim();
|
|
866
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
849
867
|
}
|
|
850
|
-
|
|
868
|
+
function normalizeBaseUrl(value) {
|
|
869
|
+
if (typeof value !== "string")
|
|
870
|
+
return null;
|
|
871
|
+
const trimmed = value.trim();
|
|
872
|
+
if (!trimmed)
|
|
873
|
+
return null;
|
|
874
|
+
return trimmed.replace(/\/$/, "");
|
|
875
|
+
}
|
|
876
|
+
function handleEquals(left, right) {
|
|
877
|
+
return left.trim().toLowerCase() === right.trim().toLowerCase();
|
|
878
|
+
}
|
|
879
|
+
function findAccountIndex(accounts, handle, baseUrl) {
|
|
880
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
881
|
+
return accounts.findIndex((candidate) => {
|
|
882
|
+
if (!handleEquals(candidate.handle, handle))
|
|
883
|
+
return false;
|
|
884
|
+
if (!normalizedBaseUrl)
|
|
885
|
+
return true;
|
|
886
|
+
return normalizeBaseUrl(candidate.baseUrl) === normalizedBaseUrl;
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
function sanitizeSession(value) {
|
|
890
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
const input = value;
|
|
894
|
+
const out = {};
|
|
895
|
+
if (typeof input.token === "string")
|
|
896
|
+
out.token = input.token;
|
|
897
|
+
if (typeof input.deviceCode === "string" || input.deviceCode === null) {
|
|
898
|
+
out.deviceCode = input.deviceCode;
|
|
899
|
+
}
|
|
900
|
+
if (typeof input.appId === "string" || input.appId === null) {
|
|
901
|
+
out.appId = input.appId;
|
|
902
|
+
}
|
|
903
|
+
if (typeof input.conversationId === "string" || input.conversationId === null) {
|
|
904
|
+
out.conversationId = input.conversationId;
|
|
905
|
+
}
|
|
906
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
907
|
+
}
|
|
908
|
+
function sanitizeAccount(value) {
|
|
909
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
910
|
+
return null;
|
|
911
|
+
const input = value;
|
|
912
|
+
const handle = normalizeHandle(typeof input.handle === "string" ? input.handle : undefined);
|
|
913
|
+
if (!handle)
|
|
914
|
+
return null;
|
|
915
|
+
const out = { handle };
|
|
916
|
+
if (typeof input.apiKey === "string")
|
|
917
|
+
out.apiKey = input.apiKey;
|
|
918
|
+
if (typeof input.baseUrl === "string")
|
|
919
|
+
out.baseUrl = input.baseUrl;
|
|
920
|
+
if (typeof input.environment === "string")
|
|
921
|
+
out.environment = input.environment;
|
|
922
|
+
const session = sanitizeSession(input.session);
|
|
923
|
+
if (session)
|
|
924
|
+
out.session = session;
|
|
925
|
+
return out;
|
|
926
|
+
}
|
|
927
|
+
function extractLegacySession(raw) {
|
|
928
|
+
const session = {};
|
|
929
|
+
if (typeof raw.token === "string")
|
|
930
|
+
session.token = raw.token;
|
|
931
|
+
if (typeof raw.deviceCode === "string" || raw.deviceCode === null) {
|
|
932
|
+
session.deviceCode = raw.deviceCode;
|
|
933
|
+
}
|
|
934
|
+
if (typeof raw.appId === "string" || raw.appId === null) {
|
|
935
|
+
session.appId = raw.appId;
|
|
936
|
+
}
|
|
937
|
+
if (typeof raw.conversationId === "string" || raw.conversationId === null) {
|
|
938
|
+
session.conversationId = raw.conversationId;
|
|
939
|
+
}
|
|
940
|
+
return Object.keys(session).length > 0 ? session : undefined;
|
|
941
|
+
}
|
|
942
|
+
function extractLegacyAccount(raw, handle) {
|
|
943
|
+
const out = { handle };
|
|
944
|
+
if (typeof raw.apiKey === "string")
|
|
945
|
+
out.apiKey = raw.apiKey;
|
|
946
|
+
if (typeof raw.baseUrl === "string")
|
|
947
|
+
out.baseUrl = raw.baseUrl;
|
|
948
|
+
const session = extractLegacySession(raw);
|
|
949
|
+
if (session)
|
|
950
|
+
out.session = session;
|
|
951
|
+
return out;
|
|
952
|
+
}
|
|
953
|
+
function normalizeGlobalConfig(raw) {
|
|
954
|
+
const normalized = {};
|
|
955
|
+
if (typeof raw.lspEnabled === "boolean")
|
|
956
|
+
normalized.lspEnabled = raw.lspEnabled;
|
|
957
|
+
if (raw.executionMode === "local" || raw.executionMode === "hosted") {
|
|
958
|
+
normalized.executionMode = raw.executionMode;
|
|
959
|
+
}
|
|
960
|
+
if (raw.mode === "general" || raw.mode === "builder") {
|
|
961
|
+
normalized.mode = raw.mode;
|
|
962
|
+
}
|
|
963
|
+
const accounts = [];
|
|
964
|
+
const sourceAccounts = Array.isArray(raw.accounts) ? raw.accounts : [];
|
|
965
|
+
for (const candidate of sourceAccounts) {
|
|
966
|
+
const account = sanitizeAccount(candidate);
|
|
967
|
+
if (!account)
|
|
968
|
+
continue;
|
|
969
|
+
if (findAccountIndex(accounts, account.handle, account.baseUrl) !== -1)
|
|
970
|
+
continue;
|
|
971
|
+
accounts.push(account);
|
|
972
|
+
}
|
|
973
|
+
if (accounts.length === 0) {
|
|
974
|
+
const legacyHandle = normalizeHandle(raw.activeHandle) || DEFAULT_ACCOUNT_HANDLE;
|
|
975
|
+
accounts.push(extractLegacyAccount(raw, legacyHandle));
|
|
976
|
+
}
|
|
977
|
+
const requested = normalizeHandle(raw.activeHandle);
|
|
978
|
+
const resolvedHandle = requested && findAccountIndex(accounts, requested) !== -1 ? accounts[findAccountIndex(accounts, requested)].handle : accounts[0].handle;
|
|
979
|
+
normalized.accounts = accounts;
|
|
980
|
+
normalized.activeHandle = resolvedHandle;
|
|
981
|
+
return normalized;
|
|
982
|
+
}
|
|
983
|
+
function resolveRequestedHandle(global, explicitAccount) {
|
|
984
|
+
const accounts = global.accounts ?? [];
|
|
985
|
+
const requested = normalizeHandle(explicitAccount) || normalizeHandle(process.env.OPENPOND_ACCOUNT) || normalizeHandle(global.activeHandle) || accounts[0]?.handle || DEFAULT_ACCOUNT_HANDLE;
|
|
986
|
+
const idx = findAccountIndex(accounts, requested);
|
|
987
|
+
return idx === -1 ? requested : accounts[idx].handle;
|
|
988
|
+
}
|
|
989
|
+
function ensureAccount(accounts, handle, baseUrl) {
|
|
990
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
991
|
+
const idx = findAccountIndex(accounts, handle, normalizedBaseUrl);
|
|
992
|
+
if (idx !== -1) {
|
|
993
|
+
return accounts[idx];
|
|
994
|
+
}
|
|
995
|
+
if (!normalizedBaseUrl) {
|
|
996
|
+
const firstByHandle = findAccountIndex(accounts, handle);
|
|
997
|
+
if (firstByHandle !== -1) {
|
|
998
|
+
return accounts[firstByHandle];
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
const next = { handle };
|
|
1002
|
+
if (normalizedBaseUrl) {
|
|
1003
|
+
next.baseUrl = normalizedBaseUrl;
|
|
1004
|
+
}
|
|
1005
|
+
accounts.push(next);
|
|
1006
|
+
return next;
|
|
1007
|
+
}
|
|
1008
|
+
function cleanupAccount(account) {
|
|
1009
|
+
if (account.session && Object.keys(account.session).length === 0) {
|
|
1010
|
+
delete account.session;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
function applyScopedKey(account, key, value, options) {
|
|
1014
|
+
const shouldDelete = value === null || value === undefined && options.undefinedDeletes;
|
|
1015
|
+
switch (key) {
|
|
1016
|
+
case "apiKey": {
|
|
1017
|
+
if (shouldDelete) {
|
|
1018
|
+
delete account.apiKey;
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
if (typeof value === "string") {
|
|
1022
|
+
account.apiKey = value;
|
|
1023
|
+
}
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
case "baseUrl": {
|
|
1027
|
+
if (shouldDelete) {
|
|
1028
|
+
delete account.baseUrl;
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
if (typeof value === "string") {
|
|
1032
|
+
account.baseUrl = value;
|
|
1033
|
+
}
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
case "token":
|
|
1037
|
+
case "deviceCode":
|
|
1038
|
+
case "appId":
|
|
1039
|
+
case "conversationId": {
|
|
1040
|
+
if (!account.session)
|
|
1041
|
+
account.session = {};
|
|
1042
|
+
if (shouldDelete) {
|
|
1043
|
+
delete account.session[key];
|
|
1044
|
+
cleanupAccount(account);
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
if (typeof value === "string" || value === null) {
|
|
1048
|
+
account.session[key] = value;
|
|
1049
|
+
}
|
|
1050
|
+
cleanupAccount(account);
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
function applyAccountPatch(global, source, options) {
|
|
1056
|
+
const hasScopedPatch = ACCOUNT_SCOPED_KEYS.some((key) => hasOwn(source, key));
|
|
1057
|
+
if (!hasScopedPatch)
|
|
1058
|
+
return false;
|
|
1059
|
+
const accounts = global.accounts ?? [];
|
|
1060
|
+
const handle = resolveRequestedHandle(global, source.activeHandle);
|
|
1061
|
+
const requestedBaseUrl = normalizeBaseUrl(hasOwn(source, "baseUrl") ? source.baseUrl ?? null : process.env.OPENPOND_BASE_URL);
|
|
1062
|
+
const account = ensureAccount(accounts, handle, requestedBaseUrl);
|
|
1063
|
+
for (const key of ACCOUNT_SCOPED_KEYS) {
|
|
1064
|
+
if (!hasOwn(source, key))
|
|
1065
|
+
continue;
|
|
1066
|
+
applyScopedKey(account, key, source[key], options);
|
|
1067
|
+
}
|
|
1068
|
+
global.accounts = accounts;
|
|
1069
|
+
global.activeHandle = handle;
|
|
1070
|
+
return true;
|
|
1071
|
+
}
|
|
1072
|
+
function applyTopLevelPatch(global, source) {
|
|
1073
|
+
if (hasOwn(source, "lspEnabled")) {
|
|
1074
|
+
if (typeof source.lspEnabled === "boolean") {
|
|
1075
|
+
global.lspEnabled = source.lspEnabled;
|
|
1076
|
+
} else if (source.lspEnabled === null) {
|
|
1077
|
+
delete global.lspEnabled;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
if (hasOwn(source, "executionMode")) {
|
|
1081
|
+
if (source.executionMode === "local" || source.executionMode === "hosted") {
|
|
1082
|
+
global.executionMode = source.executionMode;
|
|
1083
|
+
} else if (source.executionMode === null) {
|
|
1084
|
+
delete global.executionMode;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
if (hasOwn(source, "mode")) {
|
|
1088
|
+
if (source.mode === "general" || source.mode === "builder") {
|
|
1089
|
+
global.mode = source.mode;
|
|
1090
|
+
} else if (source.mode === null) {
|
|
1091
|
+
delete global.mode;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
if (typeof source.activeHandle === "string" && source.activeHandle.trim().length > 0) {
|
|
1095
|
+
const requested = resolveRequestedHandle(global, source.activeHandle);
|
|
1096
|
+
global.activeHandle = requested;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
async function writeGlobalConfig(next) {
|
|
851
1100
|
const filePath = getGlobalConfigPath();
|
|
852
1101
|
await fs2.mkdir(path2.dirname(filePath), { recursive: true });
|
|
853
|
-
const payload = JSON.stringify(
|
|
1102
|
+
const payload = JSON.stringify(next, null, 2);
|
|
854
1103
|
await fs2.writeFile(filePath, payload, "utf-8");
|
|
855
1104
|
}
|
|
1105
|
+
async function loadGlobalConfig() {
|
|
1106
|
+
const raw = await loadConfigFile(getGlobalConfigPath());
|
|
1107
|
+
return normalizeGlobalConfig(raw);
|
|
1108
|
+
}
|
|
1109
|
+
async function loadConfig(options = {}) {
|
|
1110
|
+
const global = await loadGlobalConfig();
|
|
1111
|
+
const accounts = global.accounts ?? [];
|
|
1112
|
+
const requested = resolveRequestedHandle(global, options.account);
|
|
1113
|
+
const requestedBaseUrl = normalizeBaseUrl(options.baseUrl ?? process.env.OPENPOND_BASE_URL);
|
|
1114
|
+
const idxWithBase = findAccountIndex(accounts, requested, requestedBaseUrl);
|
|
1115
|
+
const idx = idxWithBase !== -1 ? idxWithBase : findAccountIndex(accounts, requested);
|
|
1116
|
+
const account = idx === -1 ? null : accounts[idx];
|
|
1117
|
+
const session = account?.session;
|
|
1118
|
+
return {
|
|
1119
|
+
...global,
|
|
1120
|
+
activeHandle: requested,
|
|
1121
|
+
apiKey: account?.apiKey,
|
|
1122
|
+
baseUrl: account?.baseUrl,
|
|
1123
|
+
token: session?.token,
|
|
1124
|
+
deviceCode: session?.deviceCode,
|
|
1125
|
+
appId: session?.appId,
|
|
1126
|
+
conversationId: session?.conversationId
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
async function saveConfig(next) {
|
|
1130
|
+
const global = normalizeGlobalConfig(next);
|
|
1131
|
+
applyTopLevelPatch(global, next);
|
|
1132
|
+
applyAccountPatch(global, next, { undefinedDeletes: true });
|
|
1133
|
+
await writeGlobalConfig(global);
|
|
1134
|
+
}
|
|
856
1135
|
async function saveGlobalConfig(next) {
|
|
857
|
-
const filePath = getGlobalConfigPath();
|
|
858
|
-
await fs2.mkdir(path2.dirname(filePath), { recursive: true });
|
|
859
1136
|
const current = await loadGlobalConfig();
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
continue;
|
|
864
|
-
if (value === null) {
|
|
865
|
-
delete merged[key];
|
|
866
|
-
} else {
|
|
867
|
-
merged[key] = value;
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
const payload = JSON.stringify(merged, null, 2);
|
|
871
|
-
await fs2.writeFile(filePath, payload, "utf-8");
|
|
1137
|
+
applyTopLevelPatch(current, next);
|
|
1138
|
+
applyAccountPatch(current, next, { undefinedDeletes: false });
|
|
1139
|
+
await writeGlobalConfig(current);
|
|
872
1140
|
}
|
|
873
1141
|
|
|
874
1142
|
// src/index.ts
|