struere 0.11.3 → 0.12.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/dist/bin/struere.js +448 -162
- package/dist/cli/commands/login.d.ts.map +1 -1
- package/dist/cli/commands/logs.d.ts.map +1 -1
- package/dist/cli/commands/templates.d.ts.map +1 -1
- package/dist/cli/index.js +448 -162
- package/dist/cli/utils/convex.d.ts.map +1 -1
- package/dist/cli/utils/credentials.d.ts +7 -0
- package/dist/cli/utils/credentials.d.ts.map +1 -1
- package/dist/cli/utils/entities.d.ts.map +1 -1
- package/dist/cli/utils/integrations.d.ts.map +1 -1
- package/dist/cli/utils/logs.d.ts +5 -0
- package/dist/cli/utils/logs.d.ts.map +1 -1
- package/dist/cli/utils/whatsapp.d.ts +9 -0
- package/dist/cli/utils/whatsapp.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/bin/struere.js
CHANGED
|
@@ -1,73 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __export = (target, all) => {
|
|
5
|
+
for (var name in all)
|
|
6
|
+
__defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
set: (newValue) => all[name] = () => newValue
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
3
14
|
var __require = import.meta.require;
|
|
4
15
|
|
|
5
|
-
// src/cli/index.ts
|
|
6
|
-
import { program } from "commander";
|
|
7
|
-
|
|
8
|
-
// src/cli/commands/init.ts
|
|
9
|
-
import { Command as Command4 } from "commander";
|
|
10
|
-
import chalk5 from "chalk";
|
|
11
|
-
import ora5 from "ora";
|
|
12
|
-
import { select } from "@inquirer/prompts";
|
|
13
|
-
import { basename as basename2 } from "path";
|
|
14
|
-
|
|
15
|
-
// src/cli/utils/credentials.ts
|
|
16
|
-
import { homedir } from "os";
|
|
17
|
-
import { join } from "path";
|
|
18
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
19
|
-
var CONFIG_DIR = join(homedir(), ".struere");
|
|
20
|
-
var CREDENTIALS_FILE = join(CONFIG_DIR, "credentials.json");
|
|
21
|
-
function ensureConfigDir() {
|
|
22
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
23
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function saveCredentials(credentials) {
|
|
27
|
-
ensureConfigDir();
|
|
28
|
-
writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { mode: 384 });
|
|
29
|
-
}
|
|
30
|
-
function loadCredentials() {
|
|
31
|
-
if (!existsSync(CREDENTIALS_FILE)) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
const data = readFileSync(CREDENTIALS_FILE, "utf-8");
|
|
36
|
-
const credentials = JSON.parse(data);
|
|
37
|
-
if (new Date(credentials.expiresAt) < new Date) {
|
|
38
|
-
clearCredentials();
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
return credentials;
|
|
42
|
-
} catch {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
function clearCredentials() {
|
|
47
|
-
if (existsSync(CREDENTIALS_FILE)) {
|
|
48
|
-
unlinkSync(CREDENTIALS_FILE);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
function getApiKey() {
|
|
52
|
-
const credentials = loadCredentials();
|
|
53
|
-
if (credentials?.apiKey) {
|
|
54
|
-
return credentials.apiKey;
|
|
55
|
-
}
|
|
56
|
-
return process.env.STRUERE_API_KEY || null;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// src/cli/commands/login.ts
|
|
60
|
-
import { Command } from "commander";
|
|
61
|
-
import chalk from "chalk";
|
|
62
|
-
import ora from "ora";
|
|
63
|
-
|
|
64
16
|
// src/cli/utils/config.ts
|
|
65
|
-
var CONVEX_URL = process.env.STRUERE_CONVEX_URL || "https://rapid-wildebeest-172.convex.cloud";
|
|
66
17
|
function getSiteUrl() {
|
|
67
18
|
return CONVEX_URL.replace(".cloud", ".site");
|
|
68
19
|
}
|
|
20
|
+
var CONVEX_URL;
|
|
21
|
+
var init_config = __esm(() => {
|
|
22
|
+
CONVEX_URL = process.env.STRUERE_CONVEX_URL || "https://rapid-wildebeest-172.convex.cloud";
|
|
23
|
+
});
|
|
69
24
|
|
|
70
25
|
// src/cli/utils/convex.ts
|
|
26
|
+
var exports_convex = {};
|
|
27
|
+
__export(exports_convex, {
|
|
28
|
+
syncOrganization: () => syncOrganization,
|
|
29
|
+
runTool: () => runTool,
|
|
30
|
+
refreshToken: () => refreshToken,
|
|
31
|
+
listMyOrganizations: () => listMyOrganizations,
|
|
32
|
+
getUserInfo: () => getUserInfo,
|
|
33
|
+
getSyncState: () => getSyncState,
|
|
34
|
+
getSiteUrl: () => getSiteUrl,
|
|
35
|
+
getPullState: () => getPullState,
|
|
36
|
+
createOrganization: () => createOrganization,
|
|
37
|
+
compilePrompt: () => compilePrompt,
|
|
38
|
+
chatWithAgent: () => chatWithAgent
|
|
39
|
+
});
|
|
71
40
|
async function refreshToken() {
|
|
72
41
|
const credentials = loadCredentials();
|
|
73
42
|
if (!credentials?.sessionId)
|
|
@@ -86,6 +55,7 @@ async function refreshToken() {
|
|
|
86
55
|
if (!data.token)
|
|
87
56
|
return null;
|
|
88
57
|
credentials.token = data.token;
|
|
58
|
+
credentials.expiresAt = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString();
|
|
89
59
|
saveCredentials(credentials);
|
|
90
60
|
return data.token;
|
|
91
61
|
} catch {
|
|
@@ -721,8 +691,100 @@ async function getPullState(organizationId, environment = "development") {
|
|
|
721
691
|
}
|
|
722
692
|
return { error: `Unexpected response: ${JSON.stringify(result)}` };
|
|
723
693
|
}
|
|
694
|
+
var init_convex = __esm(() => {
|
|
695
|
+
init_credentials();
|
|
696
|
+
init_config();
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
// src/cli/utils/credentials.ts
|
|
700
|
+
import { homedir } from "os";
|
|
701
|
+
import { join } from "path";
|
|
702
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
703
|
+
function ensureConfigDir() {
|
|
704
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
705
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
function saveCredentials(credentials) {
|
|
709
|
+
ensureConfigDir();
|
|
710
|
+
writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { mode: 384 });
|
|
711
|
+
}
|
|
712
|
+
function loadCredentials() {
|
|
713
|
+
if (!existsSync(CREDENTIALS_FILE)) {
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
try {
|
|
717
|
+
const data = readFileSync(CREDENTIALS_FILE, "utf-8");
|
|
718
|
+
return JSON.parse(data);
|
|
719
|
+
} catch {
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
function getJwtExpiry(token) {
|
|
724
|
+
try {
|
|
725
|
+
const parts = token.split(".");
|
|
726
|
+
if (parts.length !== 3)
|
|
727
|
+
return null;
|
|
728
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
729
|
+
if (typeof payload.exp === "number")
|
|
730
|
+
return new Date(payload.exp * 1000);
|
|
731
|
+
return null;
|
|
732
|
+
} catch {
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async function getValidToken() {
|
|
737
|
+
const apiKey = getApiKey();
|
|
738
|
+
if (apiKey)
|
|
739
|
+
return { token: apiKey };
|
|
740
|
+
const credentials = loadCredentials();
|
|
741
|
+
if (!credentials?.token)
|
|
742
|
+
return { error: "Not authenticated. Run `struere login`." };
|
|
743
|
+
const expiry = getJwtExpiry(credentials.token);
|
|
744
|
+
const needsRefresh = !expiry || expiry.getTime() - Date.now() < 60000;
|
|
745
|
+
if (!needsRefresh)
|
|
746
|
+
return { token: credentials.token };
|
|
747
|
+
const { refreshToken: refreshToken2 } = await Promise.resolve().then(() => (init_convex(), exports_convex));
|
|
748
|
+
const refreshed = await refreshToken2();
|
|
749
|
+
if (refreshed)
|
|
750
|
+
return { token: refreshed };
|
|
751
|
+
return { error: "Session expired. Run `struere login`." };
|
|
752
|
+
}
|
|
753
|
+
function clearCredentials() {
|
|
754
|
+
if (existsSync(CREDENTIALS_FILE)) {
|
|
755
|
+
unlinkSync(CREDENTIALS_FILE);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
function getApiKey() {
|
|
759
|
+
const credentials = loadCredentials();
|
|
760
|
+
if (credentials?.apiKey) {
|
|
761
|
+
return credentials.apiKey;
|
|
762
|
+
}
|
|
763
|
+
return process.env.STRUERE_API_KEY || null;
|
|
764
|
+
}
|
|
765
|
+
var CONFIG_DIR, CREDENTIALS_FILE;
|
|
766
|
+
var init_credentials = __esm(() => {
|
|
767
|
+
CONFIG_DIR = join(homedir(), ".struere");
|
|
768
|
+
CREDENTIALS_FILE = join(CONFIG_DIR, "credentials.json");
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// src/cli/index.ts
|
|
772
|
+
import { program } from "commander";
|
|
773
|
+
|
|
774
|
+
// src/cli/commands/init.ts
|
|
775
|
+
init_credentials();
|
|
776
|
+
import { Command as Command4 } from "commander";
|
|
777
|
+
import chalk5 from "chalk";
|
|
778
|
+
import ora5 from "ora";
|
|
779
|
+
import { select } from "@inquirer/prompts";
|
|
780
|
+
import { basename as basename2 } from "path";
|
|
724
781
|
|
|
725
782
|
// src/cli/commands/login.ts
|
|
783
|
+
init_convex();
|
|
784
|
+
init_credentials();
|
|
785
|
+
import { Command } from "commander";
|
|
786
|
+
import chalk from "chalk";
|
|
787
|
+
import ora from "ora";
|
|
726
788
|
var AUTH_CALLBACK_PORT = 9876;
|
|
727
789
|
var loginCommand = new Command("login").description("Log in to Struere").action(async () => {
|
|
728
790
|
const spinner = ora();
|
|
@@ -731,10 +793,26 @@ var loginCommand = new Command("login").description("Log in to Struere").action(
|
|
|
731
793
|
console.log();
|
|
732
794
|
const existing = loadCredentials();
|
|
733
795
|
if (existing) {
|
|
734
|
-
|
|
735
|
-
|
|
796
|
+
const expiry = getJwtExpiry(existing.token);
|
|
797
|
+
const isValid = expiry && expiry.getTime() - Date.now() > 60000;
|
|
798
|
+
if (isValid) {
|
|
799
|
+
console.log(chalk.yellow("Already logged in as"), chalk.cyan(existing.user.email));
|
|
800
|
+
console.log(chalk.gray("Run"), chalk.cyan("struere logout"), chalk.gray("to log out first"));
|
|
801
|
+
console.log();
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
spinner.start("Session expired, refreshing token");
|
|
805
|
+
const refreshed = await refreshToken();
|
|
806
|
+
if (refreshed) {
|
|
807
|
+
spinner.succeed("Token refreshed");
|
|
808
|
+
console.log(chalk.yellow("Already logged in as"), chalk.cyan(existing.user.email));
|
|
809
|
+
console.log();
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
spinner.fail("Could not refresh session");
|
|
813
|
+
clearCredentials();
|
|
814
|
+
console.log(chalk.gray("Starting fresh login..."));
|
|
736
815
|
console.log();
|
|
737
|
-
return;
|
|
738
816
|
}
|
|
739
817
|
await browserLogin(spinner);
|
|
740
818
|
});
|
|
@@ -817,7 +895,7 @@ async function browserLoginInternal(spinner) {
|
|
|
817
895
|
email: user.email,
|
|
818
896
|
name: user.name || user.email
|
|
819
897
|
},
|
|
820
|
-
expiresAt: new Date(Date.now() +
|
|
898
|
+
expiresAt: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString()
|
|
821
899
|
};
|
|
822
900
|
saveCredentials(credentials);
|
|
823
901
|
spinner.succeed("Logged in successfully");
|
|
@@ -1428,6 +1506,9 @@ function scaffoldFixture(cwd, name, slug) {
|
|
|
1428
1506
|
return result;
|
|
1429
1507
|
}
|
|
1430
1508
|
|
|
1509
|
+
// src/cli/commands/init.ts
|
|
1510
|
+
init_convex();
|
|
1511
|
+
|
|
1431
1512
|
// src/cli/utils/plugin.ts
|
|
1432
1513
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
1433
1514
|
import { join as join4 } from "path";
|
|
@@ -2109,6 +2190,7 @@ var docsCommand = new Command2("docs").description("Generate AI context files (C
|
|
|
2109
2190
|
});
|
|
2110
2191
|
|
|
2111
2192
|
// src/cli/utils/runtime.ts
|
|
2193
|
+
init_credentials();
|
|
2112
2194
|
import ora3 from "ora";
|
|
2113
2195
|
import chalk3 from "chalk";
|
|
2114
2196
|
function isInteractive() {
|
|
@@ -2179,6 +2261,9 @@ function isOrgAccessError(error) {
|
|
|
2179
2261
|
}
|
|
2180
2262
|
|
|
2181
2263
|
// src/cli/commands/org.ts
|
|
2264
|
+
init_credentials();
|
|
2265
|
+
init_convex();
|
|
2266
|
+
init_convex();
|
|
2182
2267
|
import { Command as Command3 } from "commander";
|
|
2183
2268
|
import chalk4 from "chalk";
|
|
2184
2269
|
import ora4 from "ora";
|
|
@@ -2480,6 +2565,7 @@ function slugify(name) {
|
|
|
2480
2565
|
}
|
|
2481
2566
|
|
|
2482
2567
|
// src/cli/commands/dev.ts
|
|
2568
|
+
init_credentials();
|
|
2483
2569
|
import { Command as Command6 } from "commander";
|
|
2484
2570
|
import chalk7 from "chalk";
|
|
2485
2571
|
import ora6 from "ora";
|
|
@@ -2488,9 +2574,11 @@ import { join as join8 } from "path";
|
|
|
2488
2574
|
import { existsSync as existsSync8 } from "fs";
|
|
2489
2575
|
|
|
2490
2576
|
// src/cli/commands/sync.ts
|
|
2577
|
+
init_credentials();
|
|
2491
2578
|
import { Command as Command5 } from "commander";
|
|
2492
2579
|
import chalk6 from "chalk";
|
|
2493
2580
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
2581
|
+
init_convex();
|
|
2494
2582
|
|
|
2495
2583
|
// src/cli/utils/extractor.ts
|
|
2496
2584
|
var BUILTIN_TOOLS = [
|
|
@@ -3549,10 +3637,12 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3549
3637
|
});
|
|
3550
3638
|
|
|
3551
3639
|
// src/cli/commands/deploy.ts
|
|
3640
|
+
init_credentials();
|
|
3552
3641
|
import { Command as Command7 } from "commander";
|
|
3553
3642
|
import chalk8 from "chalk";
|
|
3554
3643
|
import ora7 from "ora";
|
|
3555
3644
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
3645
|
+
init_convex();
|
|
3556
3646
|
var deployCommand = new Command7("deploy").description("Deploy all resources to production").option("--dry-run", "Show what would be deployed without deploying").option("--force", "Skip destructive sync confirmation").option("--json", "Output results as JSON").action(async (options) => {
|
|
3557
3647
|
const spinner = ora7();
|
|
3558
3648
|
const cwd = process.cwd();
|
|
@@ -3864,6 +3954,7 @@ var deployCommand = new Command7("deploy").description("Deploy all resources to
|
|
|
3864
3954
|
});
|
|
3865
3955
|
|
|
3866
3956
|
// src/cli/commands/logout.ts
|
|
3957
|
+
init_credentials();
|
|
3867
3958
|
import { Command as Command8 } from "commander";
|
|
3868
3959
|
import chalk9 from "chalk";
|
|
3869
3960
|
var logoutCommand = new Command8("logout").description("Log out of Struere").action(async () => {
|
|
@@ -3881,6 +3972,8 @@ var logoutCommand = new Command8("logout").description("Log out of Struere").act
|
|
|
3881
3972
|
});
|
|
3882
3973
|
|
|
3883
3974
|
// src/cli/commands/whoami.ts
|
|
3975
|
+
init_credentials();
|
|
3976
|
+
init_convex();
|
|
3884
3977
|
import { Command as Command9 } from "commander";
|
|
3885
3978
|
import chalk10 from "chalk";
|
|
3886
3979
|
import ora8 from "ora";
|
|
@@ -4089,9 +4182,11 @@ function slugify2(name) {
|
|
|
4089
4182
|
}
|
|
4090
4183
|
|
|
4091
4184
|
// src/cli/commands/status.ts
|
|
4185
|
+
init_credentials();
|
|
4092
4186
|
import { Command as Command11 } from "commander";
|
|
4093
4187
|
import chalk12 from "chalk";
|
|
4094
4188
|
import ora9 from "ora";
|
|
4189
|
+
init_convex();
|
|
4095
4190
|
var statusCommand = new Command11("status").description("Compare local vs remote state").option("--json", "Output raw JSON").action(async (opts) => {
|
|
4096
4191
|
const spinner = ora9();
|
|
4097
4192
|
const cwd = process.cwd();
|
|
@@ -4295,11 +4390,13 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4295
4390
|
});
|
|
4296
4391
|
|
|
4297
4392
|
// src/cli/commands/pull.ts
|
|
4393
|
+
init_credentials();
|
|
4298
4394
|
import { Command as Command12 } from "commander";
|
|
4299
4395
|
import chalk13 from "chalk";
|
|
4300
4396
|
import ora10 from "ora";
|
|
4301
4397
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
4302
4398
|
import { join as join9 } from "path";
|
|
4399
|
+
init_convex();
|
|
4303
4400
|
|
|
4304
4401
|
// src/cli/utils/generator.ts
|
|
4305
4402
|
var BUILTIN_TOOLS2 = [
|
|
@@ -4782,21 +4879,20 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4782
4879
|
});
|
|
4783
4880
|
|
|
4784
4881
|
// src/cli/commands/entities.ts
|
|
4882
|
+
init_credentials();
|
|
4785
4883
|
import { Command as Command13 } from "commander";
|
|
4786
4884
|
import chalk15 from "chalk";
|
|
4787
4885
|
import ora11 from "ora";
|
|
4788
4886
|
import { input as input2, confirm as confirm5 } from "@inquirer/prompts";
|
|
4789
4887
|
|
|
4790
4888
|
// src/cli/utils/entities.ts
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
const apiKey = getApiKey();
|
|
4794
|
-
return apiKey || credentials?.token || null;
|
|
4795
|
-
}
|
|
4889
|
+
init_credentials();
|
|
4890
|
+
init_config();
|
|
4796
4891
|
async function convexQuery(path, args) {
|
|
4797
|
-
const
|
|
4798
|
-
if (
|
|
4799
|
-
return { error:
|
|
4892
|
+
const result = await getValidToken();
|
|
4893
|
+
if ("error" in result)
|
|
4894
|
+
return { error: result.error };
|
|
4895
|
+
const { token } = result;
|
|
4800
4896
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
4801
4897
|
method: "POST",
|
|
4802
4898
|
headers: {
|
|
@@ -4823,9 +4919,10 @@ async function convexQuery(path, args) {
|
|
|
4823
4919
|
return { error: `Unexpected response: ${text}` };
|
|
4824
4920
|
}
|
|
4825
4921
|
async function convexMutation(path, args) {
|
|
4826
|
-
const
|
|
4827
|
-
if (
|
|
4828
|
-
return { error:
|
|
4922
|
+
const result = await getValidToken();
|
|
4923
|
+
if ("error" in result)
|
|
4924
|
+
return { error: result.error };
|
|
4925
|
+
const { token } = result;
|
|
4829
4926
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
4830
4927
|
method: "POST",
|
|
4831
4928
|
headers: {
|
|
@@ -5353,20 +5450,19 @@ entitiesCommand.command("search <type> <query>").description("Search records").o
|
|
|
5353
5450
|
});
|
|
5354
5451
|
|
|
5355
5452
|
// src/cli/commands/logs.ts
|
|
5453
|
+
init_credentials();
|
|
5356
5454
|
import { Command as Command14 } from "commander";
|
|
5357
5455
|
import chalk16 from "chalk";
|
|
5358
5456
|
import ora12 from "ora";
|
|
5359
5457
|
|
|
5360
5458
|
// src/cli/utils/logs.ts
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
const apiKey = getApiKey();
|
|
5364
|
-
return apiKey || credentials?.token || null;
|
|
5365
|
-
}
|
|
5459
|
+
init_credentials();
|
|
5460
|
+
init_config();
|
|
5366
5461
|
async function convexQuery2(path, args) {
|
|
5367
|
-
const
|
|
5368
|
-
if (
|
|
5369
|
-
return { error:
|
|
5462
|
+
const tokenResult = await getValidToken();
|
|
5463
|
+
if ("error" in tokenResult)
|
|
5464
|
+
return { error: tokenResult.error };
|
|
5465
|
+
const { token } = tokenResult;
|
|
5370
5466
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
5371
5467
|
method: "POST",
|
|
5372
5468
|
headers: {
|
|
@@ -5383,7 +5479,8 @@ async function convexQuery2(path, args) {
|
|
|
5383
5479
|
return { error: text || `HTTP ${response.status}` };
|
|
5384
5480
|
}
|
|
5385
5481
|
if (!response.ok) {
|
|
5386
|
-
const
|
|
5482
|
+
const errorData = json.errorData;
|
|
5483
|
+
const msg = errorData?.message || json.message || json.errorMessage || text;
|
|
5387
5484
|
return { error: String(msg) };
|
|
5388
5485
|
}
|
|
5389
5486
|
if (json.status === "success")
|
|
@@ -5393,12 +5490,25 @@ async function convexQuery2(path, args) {
|
|
|
5393
5490
|
return { error: `Unexpected response: ${text}` };
|
|
5394
5491
|
}
|
|
5395
5492
|
async function queryThreads(options) {
|
|
5396
|
-
|
|
5493
|
+
const result = await convexQuery2("threads:listWithPreviews", {
|
|
5397
5494
|
environment: options.environment,
|
|
5398
5495
|
...options.agentId && { agentId: options.agentId },
|
|
5399
5496
|
...options.channel && { channel: options.channel },
|
|
5400
5497
|
...options.limit && { limit: options.limit }
|
|
5401
5498
|
});
|
|
5499
|
+
if (result.error || !result.data)
|
|
5500
|
+
return result;
|
|
5501
|
+
if (options.phone) {
|
|
5502
|
+
const threads = result.data;
|
|
5503
|
+
const filtered = threads.filter((t) => {
|
|
5504
|
+
const externalId = t.externalId ?? "";
|
|
5505
|
+
const params = t.channelParams;
|
|
5506
|
+
const phone = params?.phoneNumber ?? "";
|
|
5507
|
+
return externalId.includes(options.phone) || phone.includes(options.phone);
|
|
5508
|
+
});
|
|
5509
|
+
return { data: filtered };
|
|
5510
|
+
}
|
|
5511
|
+
return result;
|
|
5402
5512
|
}
|
|
5403
5513
|
async function queryThreadDetail(threadId, messageLimit) {
|
|
5404
5514
|
return convexQuery2("threads:getWithMessages", {
|
|
@@ -5409,6 +5519,31 @@ async function queryThreadDetail(threadId, messageLimit) {
|
|
|
5409
5519
|
async function queryThreadExecutions(threadId) {
|
|
5410
5520
|
return convexQuery2("executions:getByThread", { threadId });
|
|
5411
5521
|
}
|
|
5522
|
+
async function resolveThreadId(shortId, environment) {
|
|
5523
|
+
if (shortId.includes("|") || shortId.length > 20) {
|
|
5524
|
+
return { data: shortId };
|
|
5525
|
+
}
|
|
5526
|
+
const result = await queryThreads({ environment: environment ?? "development", limit: 100 });
|
|
5527
|
+
if (result.error || !result.data)
|
|
5528
|
+
return { error: result.error ?? "Could not fetch threads" };
|
|
5529
|
+
const threads = result.data;
|
|
5530
|
+
const match = threads.find((t) => t._id.endsWith(shortId));
|
|
5531
|
+
if (!match) {
|
|
5532
|
+
for (const env of ["production", "development", "eval"]) {
|
|
5533
|
+
if (env === (environment ?? "development"))
|
|
5534
|
+
continue;
|
|
5535
|
+
const envResult = await queryThreads({ environment: env, limit: 100 });
|
|
5536
|
+
if (envResult.data) {
|
|
5537
|
+
const envThreads = envResult.data;
|
|
5538
|
+
const envMatch = envThreads.find((t) => t._id.endsWith(shortId));
|
|
5539
|
+
if (envMatch)
|
|
5540
|
+
return { data: envMatch._id };
|
|
5541
|
+
}
|
|
5542
|
+
}
|
|
5543
|
+
return { error: `No thread found matching "${shortId}"` };
|
|
5544
|
+
}
|
|
5545
|
+
return { data: match._id };
|
|
5546
|
+
}
|
|
5412
5547
|
async function resolveAgentSlug(slug, organizationId) {
|
|
5413
5548
|
const result = await convexQuery2("agents:getBySlug", { slug, ...organizationId && { organizationId } });
|
|
5414
5549
|
if (result.error)
|
|
@@ -5477,7 +5612,7 @@ function formatTimestamp(ts) {
|
|
|
5477
5612
|
return d.toTimeString().slice(0, 8);
|
|
5478
5613
|
}
|
|
5479
5614
|
var logsCommand = new Command14("logs").description("View and debug agent conversations");
|
|
5480
|
-
logsCommand.command("list", { isDefault: true }).description("List recent conversations").option("--env <environment>", "Environment (development|production|eval)", "development").option("--agent <slug>", "Filter by agent slug").option("--channel <channel>", "Filter by channel (api|whatsapp|widget|dashboard)").option("--limit <n>", "Maximum results", "20").option("--json", "Output raw JSON").action(async (opts) => {
|
|
5615
|
+
logsCommand.command("list", { isDefault: true }).description("List recent conversations").option("--env <environment>", "Environment (development|production|eval)", "development").option("--agent <slug>", "Filter by agent slug").option("--channel <channel>", "Filter by channel (api|whatsapp|widget|dashboard)").option("--phone <number>", "Filter by phone number").option("--limit <n>", "Maximum results", "20").option("--json", "Output raw JSON").action(async (opts) => {
|
|
5481
5616
|
await ensureAuth2();
|
|
5482
5617
|
const spinner = ora12();
|
|
5483
5618
|
const orgId = getOrgId2();
|
|
@@ -5498,6 +5633,7 @@ logsCommand.command("list", { isDefault: true }).description("List recent conver
|
|
|
5498
5633
|
environment: opts.env,
|
|
5499
5634
|
agentId,
|
|
5500
5635
|
channel: opts.channel,
|
|
5636
|
+
phone: opts.phone,
|
|
5501
5637
|
limit: parseInt(opts.limit, 10)
|
|
5502
5638
|
});
|
|
5503
5639
|
if (error || !data) {
|
|
@@ -5506,11 +5642,12 @@ logsCommand.command("list", { isDefault: true }).description("List recent conver
|
|
|
5506
5642
|
process.exit(1);
|
|
5507
5643
|
}
|
|
5508
5644
|
const threads = data;
|
|
5509
|
-
spinner.succeed(`Found ${threads.length} conversations`);
|
|
5510
5645
|
if (opts.json) {
|
|
5646
|
+
spinner.stop();
|
|
5511
5647
|
console.log(JSON.stringify(threads, null, 2));
|
|
5512
5648
|
return;
|
|
5513
5649
|
}
|
|
5650
|
+
spinner.succeed(`Found ${threads.length} conversations`);
|
|
5514
5651
|
console.log();
|
|
5515
5652
|
renderTable([
|
|
5516
5653
|
{ key: "id", label: "ID", width: 14 },
|
|
@@ -5532,37 +5669,86 @@ logsCommand.command("list", { isDefault: true }).description("List recent conver
|
|
|
5532
5669
|
}));
|
|
5533
5670
|
console.log();
|
|
5534
5671
|
});
|
|
5535
|
-
logsCommand.command("view <thread-id>").description("View conversation messages").option("--exec", "Include execution details").option("--json", "Output raw JSON").option("--limit <n>", "Message limit", "100").action(async (
|
|
5672
|
+
logsCommand.command("view <thread-id>").description("View conversation messages").option("--env <environment>", "Environment hint for resolving short IDs").option("--exec", "Include execution details").option("--verbose", "Show full tool call arguments and results").option("--tail", "Show most recent messages (use with --limit)").option("--json", "Output raw JSON").option("--limit <n>", "Message limit", "100").action(async (rawThreadId, opts) => {
|
|
5536
5673
|
await ensureAuth2();
|
|
5537
5674
|
const spinner = ora12();
|
|
5675
|
+
spinner.start("Resolving thread");
|
|
5676
|
+
const resolved = await resolveThreadId(rawThreadId, opts.env);
|
|
5677
|
+
if (resolved.error || !resolved.data) {
|
|
5678
|
+
spinner.fail("Thread not found");
|
|
5679
|
+
console.log(chalk16.red("Error:"), resolved.error || `No thread matched "${rawThreadId}"`);
|
|
5680
|
+
process.exit(1);
|
|
5681
|
+
}
|
|
5682
|
+
const threadId = resolved.data;
|
|
5683
|
+
spinner.stop();
|
|
5538
5684
|
spinner.start("Fetching conversation");
|
|
5539
|
-
const
|
|
5685
|
+
const fetchLimit = opts.tail ? 1000 : parseInt(opts.limit, 10);
|
|
5686
|
+
const { data, error } = await queryThreadDetail(threadId, fetchLimit);
|
|
5540
5687
|
if (error || !data) {
|
|
5541
5688
|
spinner.fail("Failed to fetch conversation");
|
|
5542
5689
|
console.log(chalk16.red("Error:"), error || "Thread not found");
|
|
5543
5690
|
process.exit(1);
|
|
5544
5691
|
}
|
|
5545
|
-
spinner.
|
|
5692
|
+
spinner.stop();
|
|
5546
5693
|
const result = data;
|
|
5694
|
+
let executions = [];
|
|
5695
|
+
if (opts.exec) {
|
|
5696
|
+
const execResult = await queryThreadExecutions(threadId);
|
|
5697
|
+
if (execResult.data) {
|
|
5698
|
+
executions = execResult.data;
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5547
5701
|
if (opts.json) {
|
|
5548
|
-
console.log(JSON.stringify(result, null, 2));
|
|
5702
|
+
console.log(JSON.stringify(opts.exec ? { ...result, executions } : result, null, 2));
|
|
5549
5703
|
return;
|
|
5550
5704
|
}
|
|
5705
|
+
const truncLen = opts.verbose ? 1e4 : 500;
|
|
5551
5706
|
console.log();
|
|
5552
5707
|
console.log(chalk16.bold(`Thread: ${result._id}`));
|
|
5553
5708
|
console.log(chalk16.gray(` Environment: ${result.environment ?? "unknown"} Channel: ${result.channel ?? "api"}`));
|
|
5554
|
-
console.log(chalk16.gray("\u2500".repeat(
|
|
5555
|
-
|
|
5709
|
+
console.log(chalk16.gray("\u2500".repeat(80)));
|
|
5710
|
+
let messages = result.messages ?? [];
|
|
5711
|
+
if (opts.tail) {
|
|
5712
|
+
const limit = parseInt(opts.limit, 10);
|
|
5713
|
+
if (messages.length > limit) {
|
|
5714
|
+
messages = messages.slice(-limit);
|
|
5715
|
+
console.log(chalk16.dim(` ... ${messages.length} earlier messages hidden (showing last ${limit})`));
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5718
|
+
const execByTime = new Map;
|
|
5719
|
+
for (const exec of executions) {
|
|
5720
|
+
const ts = exec.createdAt ?? exec._creationTime ?? 0;
|
|
5721
|
+
execByTime.set(ts, exec);
|
|
5722
|
+
}
|
|
5556
5723
|
for (let i = 0;i < messages.length; i++) {
|
|
5557
5724
|
const msg = messages[i];
|
|
5558
5725
|
const ts = formatTimestamp(msg.createdAt ?? msg._creationTime ?? Date.now());
|
|
5726
|
+
const msgTs = msg.createdAt ?? msg._creationTime ?? 0;
|
|
5559
5727
|
const role = msg.role;
|
|
5560
5728
|
const content = msg.content ?? "";
|
|
5561
5729
|
const toolCalls = msg.toolCalls;
|
|
5730
|
+
const attachments = msg.attachments;
|
|
5731
|
+
const channelData = msg.channelData;
|
|
5562
5732
|
if (role === "user") {
|
|
5563
5733
|
console.log();
|
|
5564
5734
|
console.log(` ${chalk16.gray(`[${ts}]`)} ${chalk16.cyan("User")}`);
|
|
5565
5735
|
console.log(` ${content}`);
|
|
5736
|
+
if (attachments?.length) {
|
|
5737
|
+
for (const att of attachments) {
|
|
5738
|
+
console.log(` ${chalk16.magenta(`\uD83D\uDCCE ${att.type}`)} ${att.fileName ?? ""} ${chalk16.dim(att.mimeType ?? "")}`);
|
|
5739
|
+
console.log(` ${chalk16.dim(` url: ${att.url?.slice(0, 120)}`)}`);
|
|
5740
|
+
if (att.attachmentId)
|
|
5741
|
+
console.log(` ${chalk16.dim(` attachmentId: ${att.attachmentId}`)}`);
|
|
5742
|
+
}
|
|
5743
|
+
}
|
|
5744
|
+
if (channelData && typeof channelData === "object") {
|
|
5745
|
+
const cdType = channelData.type;
|
|
5746
|
+
const mediaStorageId = channelData.mediaStorageId;
|
|
5747
|
+
const mediaDirectUrl = channelData.mediaDirectUrl;
|
|
5748
|
+
if (cdType && cdType !== "text") {
|
|
5749
|
+
console.log(` ${chalk16.dim(` channel: ${cdType}${mediaStorageId ? ` storageId:${mediaStorageId}` : ""}${mediaDirectUrl ? ` directUrl:${String(mediaDirectUrl).slice(0, 80)}` : ""}`)}`);
|
|
5750
|
+
}
|
|
5751
|
+
}
|
|
5566
5752
|
} else if (role === "assistant" && toolCalls?.length) {
|
|
5567
5753
|
console.log();
|
|
5568
5754
|
console.log(` ${chalk16.gray(`[${ts}]`)} ${chalk16.green("Agent")}`);
|
|
@@ -5570,68 +5756,59 @@ logsCommand.command("view <thread-id>").description("View conversation messages"
|
|
|
5570
5756
|
console.log(` ${content}`);
|
|
5571
5757
|
for (const call of toolCalls) {
|
|
5572
5758
|
console.log(` ${chalk16.yellow("Tool: " + call.name)}`);
|
|
5573
|
-
console.log(` ${chalk16.dim("\u2192 " + JSON.stringify(call.arguments).slice(0,
|
|
5759
|
+
console.log(` ${chalk16.dim("\u2192 " + JSON.stringify(call.arguments).slice(0, truncLen))}`);
|
|
5574
5760
|
}
|
|
5575
5761
|
} else if (role === "assistant") {
|
|
5576
5762
|
console.log();
|
|
5577
5763
|
console.log(` ${chalk16.gray(`[${ts}]`)} ${chalk16.green("Agent")}`);
|
|
5578
5764
|
console.log(` ${content}`);
|
|
5579
5765
|
} else if (role === "tool") {
|
|
5580
|
-
console.log(` ${chalk16.dim("\u2190 " + content.slice(0,
|
|
5766
|
+
console.log(` ${chalk16.dim("\u2190 " + content.slice(0, truncLen))}`);
|
|
5581
5767
|
} else if (role === "system") {
|
|
5582
5768
|
console.log();
|
|
5583
5769
|
console.log(` ${chalk16.dim("[System] " + content.slice(0, 100))}`);
|
|
5584
5770
|
}
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
}
|
|
5595
|
-
spinner.succeed("Executions loaded");
|
|
5596
|
-
const executions = execResult.data;
|
|
5597
|
-
console.log();
|
|
5598
|
-
console.log(chalk16.bold("Executions"));
|
|
5599
|
-
console.log(chalk16.gray("\u2500".repeat(60)));
|
|
5600
|
-
for (const exec of executions) {
|
|
5601
|
-
const status = exec.status;
|
|
5602
|
-
const statusColor = status === "success" ? chalk16.green : status === "error" ? chalk16.red : chalk16.yellow;
|
|
5603
|
-
const toolCallDetails = exec.toolCallDetails;
|
|
5604
|
-
console.log();
|
|
5605
|
-
console.log(` ${chalk16.gray("Status:")} ${statusColor(status)}`);
|
|
5606
|
-
if (exec.model)
|
|
5607
|
-
console.log(` ${chalk16.gray("Model:")} ${exec.model}`);
|
|
5608
|
-
if (exec.inputTokens || exec.outputTokens)
|
|
5609
|
-
console.log(` ${chalk16.gray("Tokens:")} ${exec.inputTokens ?? 0} in / ${exec.outputTokens ?? 0} out`);
|
|
5610
|
-
if (exec.durationMs)
|
|
5611
|
-
console.log(` ${chalk16.gray("Duration:")} ${exec.durationMs}ms`);
|
|
5612
|
-
if (toolCallDetails?.length) {
|
|
5613
|
-
console.log(` ${chalk16.gray("Tools:")} ${toolCallDetails.length} calls`);
|
|
5614
|
-
for (const tc of toolCallDetails) {
|
|
5615
|
-
console.log(` ${tc.name} (${tc.durationMs}ms) -> ${tc.status}`);
|
|
5771
|
+
if (opts.exec && role === "assistant" && toolCalls?.length) {
|
|
5772
|
+
let closestExec;
|
|
5773
|
+
let closestDiff = Infinity;
|
|
5774
|
+
for (const exec of executions) {
|
|
5775
|
+
const execTs = exec.createdAt ?? exec._creationTime ?? 0;
|
|
5776
|
+
const diff = Math.abs(execTs - msgTs);
|
|
5777
|
+
if (diff < closestDiff) {
|
|
5778
|
+
closestDiff = diff;
|
|
5779
|
+
closestExec = exec;
|
|
5616
5780
|
}
|
|
5617
5781
|
}
|
|
5618
|
-
if (
|
|
5619
|
-
|
|
5782
|
+
if (closestExec && closestDiff < 30000) {
|
|
5783
|
+
const status = closestExec.status;
|
|
5784
|
+
const statusColor = status === "success" ? chalk16.green : status === "error" ? chalk16.red : chalk16.yellow;
|
|
5785
|
+
const model = closestExec.model;
|
|
5786
|
+
const duration = closestExec.durationMs;
|
|
5787
|
+
const inputTokens = closestExec.inputTokens;
|
|
5788
|
+
const outputTokens = closestExec.outputTokens;
|
|
5789
|
+
console.log(` ${chalk16.dim(` exec: ${statusColor(status)} ${model ?? ""} ${inputTokens ?? 0}in/${outputTokens ?? 0}out ${duration ?? 0}ms`)}`);
|
|
5790
|
+
if (closestExec.errorMessage) {
|
|
5791
|
+
console.log(` ${chalk16.red(` error: ${closestExec.errorMessage}`)}`);
|
|
5792
|
+
}
|
|
5620
5793
|
}
|
|
5621
5794
|
}
|
|
5622
|
-
console.log();
|
|
5623
5795
|
}
|
|
5796
|
+
console.log();
|
|
5624
5797
|
});
|
|
5625
5798
|
|
|
5626
5799
|
// src/cli/commands/eval.ts
|
|
5800
|
+
init_credentials();
|
|
5627
5801
|
import { Command as Command15 } from "commander";
|
|
5628
5802
|
import chalk17 from "chalk";
|
|
5629
5803
|
import ora13 from "ora";
|
|
5630
5804
|
import { join as join10 } from "path";
|
|
5631
5805
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
5806
|
+
init_convex();
|
|
5632
5807
|
|
|
5633
5808
|
// src/cli/utils/evals.ts
|
|
5634
|
-
|
|
5809
|
+
init_credentials();
|
|
5810
|
+
init_config();
|
|
5811
|
+
function getToken() {
|
|
5635
5812
|
const credentials = loadCredentials();
|
|
5636
5813
|
const apiKey = getApiKey();
|
|
5637
5814
|
const token = apiKey || credentials?.token;
|
|
@@ -5640,7 +5817,7 @@ function getToken3() {
|
|
|
5640
5817
|
return token;
|
|
5641
5818
|
}
|
|
5642
5819
|
async function convexQuery3(path, args) {
|
|
5643
|
-
const token =
|
|
5820
|
+
const token = getToken();
|
|
5644
5821
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
5645
5822
|
method: "POST",
|
|
5646
5823
|
headers: {
|
|
@@ -5665,7 +5842,7 @@ async function convexQuery3(path, args) {
|
|
|
5665
5842
|
return json.value;
|
|
5666
5843
|
}
|
|
5667
5844
|
async function convexMutation2(path, args) {
|
|
5668
|
-
const token =
|
|
5845
|
+
const token = getToken();
|
|
5669
5846
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
5670
5847
|
method: "POST",
|
|
5671
5848
|
headers: {
|
|
@@ -6081,13 +6258,16 @@ var evalCommand = new Command15("eval").description("Eval suite management");
|
|
|
6081
6258
|
evalCommand.addCommand(runCommand);
|
|
6082
6259
|
|
|
6083
6260
|
// src/cli/commands/templates.ts
|
|
6261
|
+
init_credentials();
|
|
6084
6262
|
import { Command as Command16 } from "commander";
|
|
6085
6263
|
import chalk18 from "chalk";
|
|
6086
6264
|
import { readFileSync as readFileSync5 } from "fs";
|
|
6087
6265
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
6088
6266
|
|
|
6089
6267
|
// src/cli/utils/whatsapp.ts
|
|
6090
|
-
|
|
6268
|
+
init_credentials();
|
|
6269
|
+
init_config();
|
|
6270
|
+
function getToken2() {
|
|
6091
6271
|
const credentials = loadCredentials();
|
|
6092
6272
|
const apiKey = getApiKey();
|
|
6093
6273
|
return apiKey || credentials?.token || null;
|
|
@@ -6126,7 +6306,7 @@ async function httpPost(path, body) {
|
|
|
6126
6306
|
}
|
|
6127
6307
|
}
|
|
6128
6308
|
async function convexAction(path, args) {
|
|
6129
|
-
const token =
|
|
6309
|
+
const token = getToken2();
|
|
6130
6310
|
if (!token)
|
|
6131
6311
|
return { error: "Not authenticated" };
|
|
6132
6312
|
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
@@ -6155,7 +6335,7 @@ async function convexAction(path, args) {
|
|
|
6155
6335
|
return { error: `Unexpected response: ${text}` };
|
|
6156
6336
|
}
|
|
6157
6337
|
async function convexQuery4(path, args) {
|
|
6158
|
-
const token =
|
|
6338
|
+
const token = getToken2();
|
|
6159
6339
|
if (!token)
|
|
6160
6340
|
return { error: "Not authenticated" };
|
|
6161
6341
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
@@ -6238,6 +6418,16 @@ async function getTemplateStatus(connectionId, name) {
|
|
|
6238
6418
|
name
|
|
6239
6419
|
});
|
|
6240
6420
|
}
|
|
6421
|
+
async function updateTemplate(connectionId, templateId, updates) {
|
|
6422
|
+
if (getApiKey()) {
|
|
6423
|
+
return httpPost("/v1/templates/update", { connectionId, templateId, ...updates });
|
|
6424
|
+
}
|
|
6425
|
+
return convexAction("whatsappActions:updateTemplate", {
|
|
6426
|
+
connectionId,
|
|
6427
|
+
templateId,
|
|
6428
|
+
...updates
|
|
6429
|
+
});
|
|
6430
|
+
}
|
|
6241
6431
|
|
|
6242
6432
|
// src/cli/commands/templates.ts
|
|
6243
6433
|
async function ensureAuth3() {
|
|
@@ -6330,9 +6520,9 @@ function statusColor2(status) {
|
|
|
6330
6520
|
}
|
|
6331
6521
|
}
|
|
6332
6522
|
var templatesCommand = new Command16("templates").description("Manage WhatsApp message templates");
|
|
6333
|
-
templatesCommand.command("list").description("List all message templates").option("--connection <id>", "WhatsApp connection ID").option("--json", "Output raw JSON").action(async (opts) => {
|
|
6523
|
+
templatesCommand.command("list").description("List all message templates").option("--env <environment>", "Environment to find connection (development|production|eval)").option("--connection <id>", "WhatsApp connection ID").option("--json", "Output raw JSON").action(async (opts) => {
|
|
6334
6524
|
await ensureAuth3();
|
|
6335
|
-
const connectionId = await resolveConnectionId("
|
|
6525
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6336
6526
|
const out = createOutput();
|
|
6337
6527
|
out.start("Fetching templates");
|
|
6338
6528
|
const { data, error } = await listTemplates(connectionId);
|
|
@@ -6367,9 +6557,9 @@ templatesCommand.command("list").description("List all message templates").optio
|
|
|
6367
6557
|
})));
|
|
6368
6558
|
console.log();
|
|
6369
6559
|
});
|
|
6370
|
-
templatesCommand.command("create <name>").description("Create a new message template").option("--connection <id>", "WhatsApp connection ID").option("--language <code>", "Language code", "en_US").option("--category <cat>", "Category (UTILITY|MARKETING|AUTHENTICATION)", "UTILITY").option("--components <json>", "Components as JSON string").option("--file <path>", "Read components from a JSON file").option("--allow-category-change", "Allow Meta to reassign category").option("--json", "Output raw JSON").action(async (name, opts) => {
|
|
6560
|
+
templatesCommand.command("create <name>").description("Create a new message template").option("--env <environment>", "Environment to find connection").option("--connection <id>", "WhatsApp connection ID").option("--language <code>", "Language code", "en_US").option("--category <cat>", "Category (UTILITY|MARKETING|AUTHENTICATION)", "UTILITY").option("--components <json>", "Components as JSON string").option("--file <path>", "Read components from a JSON file").option("--allow-category-change", "Allow Meta to reassign category").option("--json", "Output raw JSON").action(async (name, opts) => {
|
|
6371
6561
|
await ensureAuth3();
|
|
6372
|
-
const connectionId = await resolveConnectionId("
|
|
6562
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6373
6563
|
let components;
|
|
6374
6564
|
if (opts.file) {
|
|
6375
6565
|
try {
|
|
@@ -6415,9 +6605,9 @@ templatesCommand.command("create <name>").description("Create a new message temp
|
|
|
6415
6605
|
console.log();
|
|
6416
6606
|
}
|
|
6417
6607
|
});
|
|
6418
|
-
templatesCommand.command("delete <name>").description("Delete a message template").option("--connection <id>", "WhatsApp connection ID").option("--yes", "Skip confirmation").action(async (name, opts) => {
|
|
6608
|
+
templatesCommand.command("delete <name>").description("Delete a message template").option("--env <environment>", "Environment to find connection").option("--connection <id>", "WhatsApp connection ID").option("--yes", "Skip confirmation").action(async (name, opts) => {
|
|
6419
6609
|
await ensureAuth3();
|
|
6420
|
-
const connectionId = await resolveConnectionId("
|
|
6610
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6421
6611
|
if (!opts.yes && isInteractive()) {
|
|
6422
6612
|
const confirmed = await confirm6({
|
|
6423
6613
|
message: `Delete template "${name}"? This cannot be undone.`,
|
|
@@ -6439,9 +6629,9 @@ templatesCommand.command("delete <name>").description("Delete a message template
|
|
|
6439
6629
|
out.succeed(`Template "${name}" deleted`);
|
|
6440
6630
|
console.log();
|
|
6441
6631
|
});
|
|
6442
|
-
templatesCommand.command("status <name>").description("Check template approval status").option("--connection <id>", "WhatsApp connection ID").option("--json", "Output raw JSON").action(async (name, opts) => {
|
|
6632
|
+
templatesCommand.command("status <name>").description("Check template approval status").option("--env <environment>", "Environment to find connection").option("--connection <id>", "WhatsApp connection ID").option("--json", "Output raw JSON").action(async (name, opts) => {
|
|
6443
6633
|
await ensureAuth3();
|
|
6444
|
-
const connectionId = await resolveConnectionId("
|
|
6634
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6445
6635
|
const out = createOutput();
|
|
6446
6636
|
out.start(`Checking status for "${name}"`);
|
|
6447
6637
|
const { data, error } = await getTemplateStatus(connectionId, name);
|
|
@@ -6467,6 +6657,8 @@ templatesCommand.command("status <name>").description("Check template approval s
|
|
|
6467
6657
|
console.log(` ${chalk18.gray("Status:")} ${statusColor2(String(t.status ?? ""))}`);
|
|
6468
6658
|
console.log(` ${chalk18.gray("Category:")} ${t.category}`);
|
|
6469
6659
|
console.log(` ${chalk18.gray("Language:")} ${t.language}`);
|
|
6660
|
+
if (t.id)
|
|
6661
|
+
console.log(` ${chalk18.gray("ID:")} ${t.id}`);
|
|
6470
6662
|
if (t.components) {
|
|
6471
6663
|
console.log(` ${chalk18.gray("Components:")} ${JSON.stringify(t.components, null, 2).split(`
|
|
6472
6664
|
`).join(`
|
|
@@ -6475,22 +6667,105 @@ templatesCommand.command("status <name>").description("Check template approval s
|
|
|
6475
6667
|
console.log();
|
|
6476
6668
|
}
|
|
6477
6669
|
});
|
|
6670
|
+
templatesCommand.command("edit <name>").description("Edit a message template").option("--env <environment>", "Environment to find connection").option("--connection <id>", "WhatsApp connection ID").option("--components <json>", "New components as JSON string").option("--file <path>", "Read components from a JSON file").option("--category <cat>", "New category (UTILITY|MARKETING|AUTHENTICATION)").option("--language <code>", "Language code").option("--json", "Output raw JSON").action(async (name, opts) => {
|
|
6671
|
+
await ensureAuth3();
|
|
6672
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6673
|
+
const out = createOutput();
|
|
6674
|
+
out.start(`Fetching template "${name}"`);
|
|
6675
|
+
const { data: statusData, error: statusError } = await getTemplateStatus(connectionId, name);
|
|
6676
|
+
if (statusError) {
|
|
6677
|
+
out.fail("Failed to fetch template");
|
|
6678
|
+
out.error(statusError);
|
|
6679
|
+
process.exit(1);
|
|
6680
|
+
}
|
|
6681
|
+
const statusResult = statusData;
|
|
6682
|
+
const existing = statusResult?.data ?? [];
|
|
6683
|
+
const match = opts.language ? existing.find((t) => t.language === opts.language) : existing[0];
|
|
6684
|
+
if (!match) {
|
|
6685
|
+
out.fail(`Template "${name}" not found${opts.language ? ` for language ${opts.language}` : ""}`);
|
|
6686
|
+
process.exit(1);
|
|
6687
|
+
}
|
|
6688
|
+
const templateId = match.id;
|
|
6689
|
+
if (!templateId) {
|
|
6690
|
+
out.fail("Template ID not found in response");
|
|
6691
|
+
process.exit(1);
|
|
6692
|
+
}
|
|
6693
|
+
out.succeed(`Found template "${name}" (${match.language}, ID: ${templateId})`);
|
|
6694
|
+
let components;
|
|
6695
|
+
if (opts.file) {
|
|
6696
|
+
try {
|
|
6697
|
+
const fileContent = readFileSync5(opts.file, "utf-8");
|
|
6698
|
+
const parsed = JSON.parse(fileContent);
|
|
6699
|
+
components = Array.isArray(parsed) ? parsed : parsed.components ?? [parsed];
|
|
6700
|
+
} catch (err) {
|
|
6701
|
+
console.log(chalk18.red("Failed to read components file:"), err instanceof Error ? err.message : String(err));
|
|
6702
|
+
process.exit(1);
|
|
6703
|
+
}
|
|
6704
|
+
} else if (opts.components) {
|
|
6705
|
+
try {
|
|
6706
|
+
components = JSON.parse(opts.components);
|
|
6707
|
+
} catch {
|
|
6708
|
+
console.log(chalk18.red("Invalid JSON in --components"));
|
|
6709
|
+
process.exit(1);
|
|
6710
|
+
}
|
|
6711
|
+
}
|
|
6712
|
+
if (!components && !opts.category) {
|
|
6713
|
+
console.log();
|
|
6714
|
+
console.log(chalk18.gray("Current components:"));
|
|
6715
|
+
console.log(JSON.stringify(match.components, null, 2));
|
|
6716
|
+
console.log();
|
|
6717
|
+
console.log(chalk18.yellow("Provide --components <json>, --file <path>, or --category <cat> to update"));
|
|
6718
|
+
process.exit(1);
|
|
6719
|
+
}
|
|
6720
|
+
const updates = { name, language: opts.language ?? match.language };
|
|
6721
|
+
if (components)
|
|
6722
|
+
updates.components = components;
|
|
6723
|
+
if (opts.category)
|
|
6724
|
+
updates.category = opts.category.toUpperCase();
|
|
6725
|
+
if (!opts.json && isInteractive()) {
|
|
6726
|
+
console.log();
|
|
6727
|
+
if (components) {
|
|
6728
|
+
console.log(chalk18.gray("New components:"));
|
|
6729
|
+
console.log(JSON.stringify(components, null, 2));
|
|
6730
|
+
console.log();
|
|
6731
|
+
}
|
|
6732
|
+
const confirmed = await confirm6({
|
|
6733
|
+
message: `Update template "${name}"? This will resubmit for Meta approval.`,
|
|
6734
|
+
default: true
|
|
6735
|
+
});
|
|
6736
|
+
if (!confirmed) {
|
|
6737
|
+
console.log(chalk18.gray("Cancelled"));
|
|
6738
|
+
return;
|
|
6739
|
+
}
|
|
6740
|
+
}
|
|
6741
|
+
out.start(`Updating template "${name}"`);
|
|
6742
|
+
const { data, error } = await updateTemplate(connectionId, templateId, updates);
|
|
6743
|
+
if (error) {
|
|
6744
|
+
out.fail("Failed to update template");
|
|
6745
|
+
out.error(error);
|
|
6746
|
+
process.exit(1);
|
|
6747
|
+
}
|
|
6748
|
+
out.succeed(`Template "${name}" updated \u2014 resubmitted for approval`);
|
|
6749
|
+
if (opts.json) {
|
|
6750
|
+
console.log(JSON.stringify(data, null, 2));
|
|
6751
|
+
}
|
|
6752
|
+
console.log();
|
|
6753
|
+
});
|
|
6478
6754
|
|
|
6479
6755
|
// src/cli/commands/integration.ts
|
|
6756
|
+
init_credentials();
|
|
6480
6757
|
import { Command as Command17 } from "commander";
|
|
6481
6758
|
import chalk19 from "chalk";
|
|
6482
6759
|
import { confirm as confirm7 } from "@inquirer/prompts";
|
|
6483
6760
|
|
|
6484
6761
|
// src/cli/utils/integrations.ts
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
const apiKey = getApiKey();
|
|
6488
|
-
return apiKey || credentials?.token || null;
|
|
6489
|
-
}
|
|
6762
|
+
init_credentials();
|
|
6763
|
+
init_config();
|
|
6490
6764
|
async function convexQuery5(path, args) {
|
|
6491
|
-
const
|
|
6492
|
-
if (
|
|
6493
|
-
return { error:
|
|
6765
|
+
const result = await getValidToken();
|
|
6766
|
+
if ("error" in result)
|
|
6767
|
+
return { error: result.error };
|
|
6768
|
+
const { token } = result;
|
|
6494
6769
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
6495
6770
|
method: "POST",
|
|
6496
6771
|
headers: {
|
|
@@ -6517,9 +6792,10 @@ async function convexQuery5(path, args) {
|
|
|
6517
6792
|
return { error: `Unexpected response: ${text}` };
|
|
6518
6793
|
}
|
|
6519
6794
|
async function convexMutation3(path, args) {
|
|
6520
|
-
const
|
|
6521
|
-
if (
|
|
6522
|
-
return { error:
|
|
6795
|
+
const result = await getValidToken();
|
|
6796
|
+
if ("error" in result)
|
|
6797
|
+
return { error: result.error };
|
|
6798
|
+
const { token } = result;
|
|
6523
6799
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
6524
6800
|
method: "POST",
|
|
6525
6801
|
headers: {
|
|
@@ -6546,9 +6822,10 @@ async function convexMutation3(path, args) {
|
|
|
6546
6822
|
return { error: `Unexpected response: ${text}` };
|
|
6547
6823
|
}
|
|
6548
6824
|
async function convexAction2(path, args) {
|
|
6549
|
-
const
|
|
6550
|
-
if (
|
|
6551
|
-
return { error:
|
|
6825
|
+
const result = await getValidToken();
|
|
6826
|
+
if ("error" in result)
|
|
6827
|
+
return { error: result.error };
|
|
6828
|
+
const { token } = result;
|
|
6552
6829
|
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
6553
6830
|
method: "POST",
|
|
6554
6831
|
headers: {
|
|
@@ -6869,12 +7146,15 @@ var integrationCommand = new Command17("integration").description("Manage integr
|
|
|
6869
7146
|
});
|
|
6870
7147
|
|
|
6871
7148
|
// src/cli/commands/triggers.ts
|
|
7149
|
+
init_credentials();
|
|
6872
7150
|
import { Command as Command18 } from "commander";
|
|
6873
7151
|
import chalk20 from "chalk";
|
|
6874
7152
|
import ora14 from "ora";
|
|
6875
7153
|
|
|
6876
7154
|
// src/cli/utils/triggers.ts
|
|
6877
|
-
|
|
7155
|
+
init_credentials();
|
|
7156
|
+
init_config();
|
|
7157
|
+
function getToken3() {
|
|
6878
7158
|
const credentials = loadCredentials();
|
|
6879
7159
|
const apiKey = getApiKey();
|
|
6880
7160
|
const token = apiKey || credentials?.token;
|
|
@@ -6883,7 +7163,7 @@ function getToken6() {
|
|
|
6883
7163
|
return token;
|
|
6884
7164
|
}
|
|
6885
7165
|
async function convexQuery6(path, args) {
|
|
6886
|
-
const token =
|
|
7166
|
+
const token = getToken3();
|
|
6887
7167
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
6888
7168
|
method: "POST",
|
|
6889
7169
|
headers: {
|
|
@@ -6908,7 +7188,7 @@ async function convexQuery6(path, args) {
|
|
|
6908
7188
|
return json.value;
|
|
6909
7189
|
}
|
|
6910
7190
|
async function convexMutation4(path, args) {
|
|
6911
|
-
const token =
|
|
7191
|
+
const token = getToken3();
|
|
6912
7192
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
6913
7193
|
method: "POST",
|
|
6914
7194
|
headers: {
|
|
@@ -6979,7 +7259,7 @@ async function getTriggerExecutionDetail(eventId) {
|
|
|
6979
7259
|
return convexQuery6("triggers:getExecutionDetail", { eventId });
|
|
6980
7260
|
}
|
|
6981
7261
|
async function convexAction3(path, args) {
|
|
6982
|
-
const token =
|
|
7262
|
+
const token = getToken3();
|
|
6983
7263
|
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
6984
7264
|
method: "POST",
|
|
6985
7265
|
headers: {
|
|
@@ -7688,9 +7968,11 @@ triggersCommand.command("retry-event <event-id>").description("Retry a failed im
|
|
|
7688
7968
|
});
|
|
7689
7969
|
|
|
7690
7970
|
// src/cli/commands/compile-prompt.ts
|
|
7971
|
+
init_credentials();
|
|
7691
7972
|
import { Command as Command19 } from "commander";
|
|
7692
7973
|
import chalk21 from "chalk";
|
|
7693
7974
|
import ora15 from "ora";
|
|
7975
|
+
init_convex();
|
|
7694
7976
|
var compilePromptCommand = new Command19("compile-prompt").description("Compile and preview an agent's system prompt after template processing").argument("<agent-slug>", "Agent slug to compile prompt for").option("--env <env>", "Environment: development | production", "development").option("--message <msg>", "Sample message for template context").option("--channel <channel>", "Sample channel (whatsapp, widget, api, dashboard)").option("--param <key=value...>", "Custom thread param (repeatable)", (val, acc) => {
|
|
7695
7977
|
acc.push(val);
|
|
7696
7978
|
return acc;
|
|
@@ -7836,9 +8118,11 @@ var compilePromptCommand = new Command19("compile-prompt").description("Compile
|
|
|
7836
8118
|
});
|
|
7837
8119
|
|
|
7838
8120
|
// src/cli/commands/run-tool.ts
|
|
8121
|
+
init_credentials();
|
|
7839
8122
|
import { Command as Command20 } from "commander";
|
|
7840
8123
|
import chalk22 from "chalk";
|
|
7841
8124
|
import ora16 from "ora";
|
|
8125
|
+
init_convex();
|
|
7842
8126
|
var runToolCommand = new Command20("run-tool").description("Run a tool as it would execute during a real agent conversation").argument("<agent-slug>", "Agent slug").argument("<tool-name>", "Tool name (e.g., entity.query)").option("--env <environment>", "Environment: development | production | eval", "development").option("--args <json>", "Tool arguments as JSON string", "{}").option("--args-file <path>", "Read tool arguments from a JSON file").option("--json", "Output full JSON result").option("--confirm", "Skip production confirmation prompt").action(async (agentSlug, toolName, options) => {
|
|
7843
8127
|
const spinner = ora16();
|
|
7844
8128
|
const cwd = process.cwd();
|
|
@@ -7991,10 +8275,12 @@ var runToolCommand = new Command20("run-tool").description("Run a tool as it wou
|
|
|
7991
8275
|
});
|
|
7992
8276
|
|
|
7993
8277
|
// src/cli/commands/chat.ts
|
|
8278
|
+
init_credentials();
|
|
7994
8279
|
import { Command as Command21 } from "commander";
|
|
7995
8280
|
import chalk23 from "chalk";
|
|
7996
8281
|
import ora17 from "ora";
|
|
7997
8282
|
import readline from "readline";
|
|
8283
|
+
init_convex();
|
|
7998
8284
|
var chatCommand = new Command21("chat").description("Chat with an agent").argument("<agent-slug>", "Agent slug").option("--env <environment>", "Environment: development | production | eval", "development").option("--thread <id>", "Continue an existing thread").option("--message <msg>", "Single message mode (send and exit)").option("--json", "Output JSON").option("--channel <channel>", "Channel identifier", "api").option("-v, --verbose", "Show detailed response info").option("--confirm", "Skip production warning prompt").action(async (agentSlug, options) => {
|
|
7999
8285
|
const spinner = ora17();
|
|
8000
8286
|
const cwd = process.cwd();
|
|
@@ -8245,7 +8531,7 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8245
8531
|
// package.json
|
|
8246
8532
|
var package_default = {
|
|
8247
8533
|
name: "struere",
|
|
8248
|
-
version: "0.
|
|
8534
|
+
version: "0.12.1",
|
|
8249
8535
|
description: "Build, test, and deploy AI agents",
|
|
8250
8536
|
keywords: [
|
|
8251
8537
|
"ai",
|