struere 0.12.0 → 0.12.2
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 +605 -150
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/login.d.ts.map +1 -1
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/sync.d.ts.map +1 -1
- package/dist/cli/commands/templates.d.ts.map +1 -1
- package/dist/cli/index.js +605 -150
- package/dist/cli/templates/index.d.ts +1 -0
- package/dist/cli/templates/index.d.ts.map +1 -1
- package/dist/cli/utils/convex.d.ts +78 -0
- package/dist/cli/utils/convex.d.ts.map +1 -1
- package/dist/cli/utils/credentials.d.ts +6 -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/extractor.d.ts +27 -0
- package/dist/cli/utils/extractor.d.ts.map +1 -1
- package/dist/cli/utils/generator.d.ts +3 -2
- package/dist/cli/utils/generator.d.ts.map +1 -1
- package/dist/cli/utils/integrations.d.ts.map +1 -1
- package/dist/cli/utils/loader.d.ts +3 -1
- package/dist/cli/utils/loader.d.ts.map +1 -1
- package/dist/cli/utils/logs.d.ts.map +1 -1
- package/dist/cli/utils/scaffold.d.ts +1 -0
- package/dist/cli/utils/scaffold.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/dist/define/index.d.ts +1 -0
- package/dist/define/index.d.ts.map +1 -1
- package/dist/define/router.d.ts +3 -0
- package/dist/define/router.d.ts.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/bin/struere.js
CHANGED
|
@@ -1,68 +1,43 @@
|
|
|
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
|
-
return JSON.parse(data);
|
|
37
|
-
} catch {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function clearCredentials() {
|
|
42
|
-
if (existsSync(CREDENTIALS_FILE)) {
|
|
43
|
-
unlinkSync(CREDENTIALS_FILE);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
function getApiKey() {
|
|
47
|
-
const credentials = loadCredentials();
|
|
48
|
-
if (credentials?.apiKey) {
|
|
49
|
-
return credentials.apiKey;
|
|
50
|
-
}
|
|
51
|
-
return process.env.STRUERE_API_KEY || null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// src/cli/commands/login.ts
|
|
55
|
-
import { Command } from "commander";
|
|
56
|
-
import chalk from "chalk";
|
|
57
|
-
import ora from "ora";
|
|
58
|
-
|
|
59
16
|
// src/cli/utils/config.ts
|
|
60
|
-
var CONVEX_URL = process.env.STRUERE_CONVEX_URL || "https://rapid-wildebeest-172.convex.cloud";
|
|
61
17
|
function getSiteUrl() {
|
|
62
18
|
return CONVEX_URL.replace(".cloud", ".site");
|
|
63
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
|
+
});
|
|
64
24
|
|
|
65
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
|
+
chatWithRouter: () => chatWithRouter,
|
|
39
|
+
chatWithAgent: () => chatWithAgent
|
|
40
|
+
});
|
|
66
41
|
async function refreshToken() {
|
|
67
42
|
const credentials = loadCredentials();
|
|
68
43
|
if (!credentials?.sessionId)
|
|
@@ -81,6 +56,7 @@ async function refreshToken() {
|
|
|
81
56
|
if (!data.token)
|
|
82
57
|
return null;
|
|
83
58
|
credentials.token = data.token;
|
|
59
|
+
credentials.expiresAt = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString();
|
|
84
60
|
saveCredentials(credentials);
|
|
85
61
|
return data.token;
|
|
86
62
|
} catch {
|
|
@@ -209,6 +185,7 @@ async function syncViaHttp(apiKey, payload) {
|
|
|
209
185
|
roles: payload.roles,
|
|
210
186
|
evalSuites: payload.evalSuites,
|
|
211
187
|
triggers: payload.triggers,
|
|
188
|
+
routers: payload.routers,
|
|
212
189
|
fixtures: payload.fixtures
|
|
213
190
|
}),
|
|
214
191
|
signal: AbortSignal.timeout(30000)
|
|
@@ -660,6 +637,65 @@ async function chatWithAgent(options) {
|
|
|
660
637
|
return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
|
|
661
638
|
}
|
|
662
639
|
}
|
|
640
|
+
async function chatWithRouter(options) {
|
|
641
|
+
const credentials = loadCredentials();
|
|
642
|
+
const apiKey = getApiKey();
|
|
643
|
+
if (credentials?.sessionId) {
|
|
644
|
+
await refreshToken();
|
|
645
|
+
}
|
|
646
|
+
const freshCredentials = loadCredentials();
|
|
647
|
+
const token = apiKey || freshCredentials?.token;
|
|
648
|
+
if (!token) {
|
|
649
|
+
return { error: "Not authenticated" };
|
|
650
|
+
}
|
|
651
|
+
try {
|
|
652
|
+
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
653
|
+
method: "POST",
|
|
654
|
+
headers: {
|
|
655
|
+
"Content-Type": "application/json",
|
|
656
|
+
Authorization: `Bearer ${token}`
|
|
657
|
+
},
|
|
658
|
+
body: JSON.stringify({
|
|
659
|
+
path: "chat:sendByRouterSlug",
|
|
660
|
+
args: {
|
|
661
|
+
routerSlug: options.routerSlug,
|
|
662
|
+
message: options.message,
|
|
663
|
+
threadId: options.threadId,
|
|
664
|
+
phoneNumber: options.phoneNumber,
|
|
665
|
+
environment: options.environment,
|
|
666
|
+
channel: options.channel || "api"
|
|
667
|
+
}
|
|
668
|
+
}),
|
|
669
|
+
signal: options.signal || AbortSignal.timeout(120000)
|
|
670
|
+
});
|
|
671
|
+
const text = await response.text();
|
|
672
|
+
let json;
|
|
673
|
+
try {
|
|
674
|
+
json = JSON.parse(text);
|
|
675
|
+
} catch {
|
|
676
|
+
return { error: text || `HTTP ${response.status}` };
|
|
677
|
+
}
|
|
678
|
+
if (!response.ok) {
|
|
679
|
+
const msg = json.errorData?.message || json.errorMessage || text;
|
|
680
|
+
return { error: msg };
|
|
681
|
+
}
|
|
682
|
+
if (json.status === "success" && json.value) {
|
|
683
|
+
return { result: json.value };
|
|
684
|
+
}
|
|
685
|
+
if (json.status === "success" && json.value === null) {
|
|
686
|
+
return { error: `Router not found or no config for environment: ${options.environment}` };
|
|
687
|
+
}
|
|
688
|
+
if (json.status === "error") {
|
|
689
|
+
return { error: json.errorData?.message || json.errorMessage || "Unknown error from Convex" };
|
|
690
|
+
}
|
|
691
|
+
return { error: `Unexpected response: ${text}` };
|
|
692
|
+
} catch (err) {
|
|
693
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
694
|
+
return { error: "Request timed out after 120s" };
|
|
695
|
+
}
|
|
696
|
+
return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
|
|
697
|
+
}
|
|
698
|
+
}
|
|
663
699
|
async function getPullState(organizationId, environment = "development") {
|
|
664
700
|
const credentials = loadCredentials();
|
|
665
701
|
const apiKey = getApiKey();
|
|
@@ -716,8 +752,100 @@ async function getPullState(organizationId, environment = "development") {
|
|
|
716
752
|
}
|
|
717
753
|
return { error: `Unexpected response: ${JSON.stringify(result)}` };
|
|
718
754
|
}
|
|
755
|
+
var init_convex = __esm(() => {
|
|
756
|
+
init_credentials();
|
|
757
|
+
init_config();
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
// src/cli/utils/credentials.ts
|
|
761
|
+
import { homedir } from "os";
|
|
762
|
+
import { join } from "path";
|
|
763
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
764
|
+
function ensureConfigDir() {
|
|
765
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
766
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
function saveCredentials(credentials) {
|
|
770
|
+
ensureConfigDir();
|
|
771
|
+
writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { mode: 384 });
|
|
772
|
+
}
|
|
773
|
+
function loadCredentials() {
|
|
774
|
+
if (!existsSync(CREDENTIALS_FILE)) {
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
try {
|
|
778
|
+
const data = readFileSync(CREDENTIALS_FILE, "utf-8");
|
|
779
|
+
return JSON.parse(data);
|
|
780
|
+
} catch {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
function getJwtExpiry(token) {
|
|
785
|
+
try {
|
|
786
|
+
const parts = token.split(".");
|
|
787
|
+
if (parts.length !== 3)
|
|
788
|
+
return null;
|
|
789
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
790
|
+
if (typeof payload.exp === "number")
|
|
791
|
+
return new Date(payload.exp * 1000);
|
|
792
|
+
return null;
|
|
793
|
+
} catch {
|
|
794
|
+
return null;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
async function getValidToken() {
|
|
798
|
+
const apiKey = getApiKey();
|
|
799
|
+
if (apiKey)
|
|
800
|
+
return { token: apiKey };
|
|
801
|
+
const credentials = loadCredentials();
|
|
802
|
+
if (!credentials?.token)
|
|
803
|
+
return { error: "Not authenticated. Run `struere login`." };
|
|
804
|
+
const expiry = getJwtExpiry(credentials.token);
|
|
805
|
+
const needsRefresh = !expiry || expiry.getTime() - Date.now() < 60000;
|
|
806
|
+
if (!needsRefresh)
|
|
807
|
+
return { token: credentials.token };
|
|
808
|
+
const { refreshToken: refreshToken2 } = await Promise.resolve().then(() => (init_convex(), exports_convex));
|
|
809
|
+
const refreshed = await refreshToken2();
|
|
810
|
+
if (refreshed)
|
|
811
|
+
return { token: refreshed };
|
|
812
|
+
return { error: "Session expired. Run `struere login`." };
|
|
813
|
+
}
|
|
814
|
+
function clearCredentials() {
|
|
815
|
+
if (existsSync(CREDENTIALS_FILE)) {
|
|
816
|
+
unlinkSync(CREDENTIALS_FILE);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
function getApiKey() {
|
|
820
|
+
const credentials = loadCredentials();
|
|
821
|
+
if (credentials?.apiKey) {
|
|
822
|
+
return credentials.apiKey;
|
|
823
|
+
}
|
|
824
|
+
return process.env.STRUERE_API_KEY || null;
|
|
825
|
+
}
|
|
826
|
+
var CONFIG_DIR, CREDENTIALS_FILE;
|
|
827
|
+
var init_credentials = __esm(() => {
|
|
828
|
+
CONFIG_DIR = join(homedir(), ".struere");
|
|
829
|
+
CREDENTIALS_FILE = join(CONFIG_DIR, "credentials.json");
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
// src/cli/index.ts
|
|
833
|
+
import { program } from "commander";
|
|
834
|
+
|
|
835
|
+
// src/cli/commands/init.ts
|
|
836
|
+
init_credentials();
|
|
837
|
+
import { Command as Command4 } from "commander";
|
|
838
|
+
import chalk5 from "chalk";
|
|
839
|
+
import ora5 from "ora";
|
|
840
|
+
import { select } from "@inquirer/prompts";
|
|
841
|
+
import { basename as basename2 } from "path";
|
|
719
842
|
|
|
720
843
|
// src/cli/commands/login.ts
|
|
844
|
+
init_convex();
|
|
845
|
+
init_credentials();
|
|
846
|
+
import { Command } from "commander";
|
|
847
|
+
import chalk from "chalk";
|
|
848
|
+
import ora from "ora";
|
|
721
849
|
var AUTH_CALLBACK_PORT = 9876;
|
|
722
850
|
var loginCommand = new Command("login").description("Log in to Struere").action(async () => {
|
|
723
851
|
const spinner = ora();
|
|
@@ -726,10 +854,26 @@ var loginCommand = new Command("login").description("Log in to Struere").action(
|
|
|
726
854
|
console.log();
|
|
727
855
|
const existing = loadCredentials();
|
|
728
856
|
if (existing) {
|
|
729
|
-
|
|
730
|
-
|
|
857
|
+
const expiry = getJwtExpiry(existing.token);
|
|
858
|
+
const isValid = expiry && expiry.getTime() - Date.now() > 60000;
|
|
859
|
+
if (isValid) {
|
|
860
|
+
console.log(chalk.yellow("Already logged in as"), chalk.cyan(existing.user.email));
|
|
861
|
+
console.log(chalk.gray("Run"), chalk.cyan("struere logout"), chalk.gray("to log out first"));
|
|
862
|
+
console.log();
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
spinner.start("Session expired, refreshing token");
|
|
866
|
+
const refreshed = await refreshToken();
|
|
867
|
+
if (refreshed) {
|
|
868
|
+
spinner.succeed("Token refreshed");
|
|
869
|
+
console.log(chalk.yellow("Already logged in as"), chalk.cyan(existing.user.email));
|
|
870
|
+
console.log();
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
spinner.fail("Could not refresh session");
|
|
874
|
+
clearCredentials();
|
|
875
|
+
console.log(chalk.gray("Starting fresh login..."));
|
|
731
876
|
console.log();
|
|
732
|
-
return;
|
|
733
877
|
}
|
|
734
878
|
await browserLogin(spinner);
|
|
735
879
|
});
|
|
@@ -812,7 +956,7 @@ async function browserLoginInternal(spinner) {
|
|
|
812
956
|
email: user.email,
|
|
813
957
|
name: user.name || user.email
|
|
814
958
|
},
|
|
815
|
-
expiresAt: new Date(Date.now() +
|
|
959
|
+
expiresAt: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString()
|
|
816
960
|
};
|
|
817
961
|
saveCredentials(credentials);
|
|
818
962
|
spinner.succeed("Logged in successfully");
|
|
@@ -1260,6 +1404,26 @@ export default defineTrigger({
|
|
|
1260
1404
|
})
|
|
1261
1405
|
`;
|
|
1262
1406
|
}
|
|
1407
|
+
function getRouterTs(name, slug) {
|
|
1408
|
+
return `import { defineRouter } from 'struere'
|
|
1409
|
+
|
|
1410
|
+
export default defineRouter({
|
|
1411
|
+
name: "${name}",
|
|
1412
|
+
slug: "${slug}",
|
|
1413
|
+
mode: "rules",
|
|
1414
|
+
agents: [
|
|
1415
|
+
{ slug: "agent-one", description: "Handles ..." },
|
|
1416
|
+
],
|
|
1417
|
+
rules: [
|
|
1418
|
+
{
|
|
1419
|
+
conditions: [{ field: "channel", operator: "eq", value: "whatsapp" }],
|
|
1420
|
+
route: "agent-one",
|
|
1421
|
+
},
|
|
1422
|
+
],
|
|
1423
|
+
fallback: "agent-one",
|
|
1424
|
+
})
|
|
1425
|
+
`;
|
|
1426
|
+
}
|
|
1263
1427
|
|
|
1264
1428
|
// src/cli/utils/scaffold.ts
|
|
1265
1429
|
function ensureDir(filePath) {
|
|
@@ -1285,6 +1449,7 @@ function scaffoldProject(cwd, options) {
|
|
|
1285
1449
|
"tools",
|
|
1286
1450
|
"evals",
|
|
1287
1451
|
"triggers",
|
|
1452
|
+
"routers",
|
|
1288
1453
|
"fixtures",
|
|
1289
1454
|
".struere"
|
|
1290
1455
|
];
|
|
@@ -1404,6 +1569,24 @@ function scaffoldTrigger(cwd, name, slug) {
|
|
|
1404
1569
|
result.createdFiles.push(`triggers/${fileName}`);
|
|
1405
1570
|
return result;
|
|
1406
1571
|
}
|
|
1572
|
+
function scaffoldRouter(cwd, name, slug) {
|
|
1573
|
+
const result = {
|
|
1574
|
+
createdFiles: [],
|
|
1575
|
+
updatedFiles: []
|
|
1576
|
+
};
|
|
1577
|
+
const routersDir = join3(cwd, "routers");
|
|
1578
|
+
if (!existsSync3(routersDir)) {
|
|
1579
|
+
mkdirSync2(routersDir, { recursive: true });
|
|
1580
|
+
}
|
|
1581
|
+
const fileName = `${slug}.ts`;
|
|
1582
|
+
const filePath = join3(routersDir, fileName);
|
|
1583
|
+
if (existsSync3(filePath)) {
|
|
1584
|
+
return result;
|
|
1585
|
+
}
|
|
1586
|
+
writeFileSync2(filePath, getRouterTs(name, slug));
|
|
1587
|
+
result.createdFiles.push(`routers/${fileName}`);
|
|
1588
|
+
return result;
|
|
1589
|
+
}
|
|
1407
1590
|
function scaffoldFixture(cwd, name, slug) {
|
|
1408
1591
|
const result = {
|
|
1409
1592
|
createdFiles: [],
|
|
@@ -1423,6 +1606,9 @@ function scaffoldFixture(cwd, name, slug) {
|
|
|
1423
1606
|
return result;
|
|
1424
1607
|
}
|
|
1425
1608
|
|
|
1609
|
+
// src/cli/commands/init.ts
|
|
1610
|
+
init_convex();
|
|
1611
|
+
|
|
1426
1612
|
// src/cli/utils/plugin.ts
|
|
1427
1613
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
1428
1614
|
import { join as join4 } from "path";
|
|
@@ -1830,9 +2016,10 @@ async function loadAllResources(cwd) {
|
|
|
1830
2016
|
const { suites: evalSuites, errors: evalErrors } = loadEvalSuites(join5(cwd, "evals"));
|
|
1831
2017
|
errors.push(...evalErrors);
|
|
1832
2018
|
const triggers = await loadTsDirectory(join5(cwd, "triggers"));
|
|
2019
|
+
const routers = await loadTsDirectory(join5(cwd, "routers"));
|
|
1833
2020
|
const { fixtures, errors: fixtureErrors } = loadFixtures(join5(cwd, "fixtures"));
|
|
1834
2021
|
errors.push(...fixtureErrors);
|
|
1835
|
-
return { agents, entityTypes, roles, customTools, evalSuites, triggers, fixtures, errors };
|
|
2022
|
+
return { agents, entityTypes, roles, customTools, evalSuites, triggers, routers, fixtures, errors };
|
|
1836
2023
|
}
|
|
1837
2024
|
async function loadTsDirectory(dir) {
|
|
1838
2025
|
if (!existsSync5(dir)) {
|
|
@@ -1919,6 +2106,7 @@ function getResourceDirectories(cwd) {
|
|
|
1919
2106
|
tools: join5(cwd, "tools"),
|
|
1920
2107
|
evals: join5(cwd, "evals"),
|
|
1921
2108
|
triggers: join5(cwd, "triggers"),
|
|
2109
|
+
routers: join5(cwd, "routers"),
|
|
1922
2110
|
fixtures: join5(cwd, "fixtures")
|
|
1923
2111
|
};
|
|
1924
2112
|
}
|
|
@@ -2057,6 +2245,7 @@ async function generateDocs(cwd, targets) {
|
|
|
2057
2245
|
customTools: [],
|
|
2058
2246
|
evalSuites: [],
|
|
2059
2247
|
triggers: [],
|
|
2248
|
+
routers: [],
|
|
2060
2249
|
fixtures: [],
|
|
2061
2250
|
errors: []
|
|
2062
2251
|
});
|
|
@@ -2104,6 +2293,7 @@ var docsCommand = new Command2("docs").description("Generate AI context files (C
|
|
|
2104
2293
|
});
|
|
2105
2294
|
|
|
2106
2295
|
// src/cli/utils/runtime.ts
|
|
2296
|
+
init_credentials();
|
|
2107
2297
|
import ora3 from "ora";
|
|
2108
2298
|
import chalk3 from "chalk";
|
|
2109
2299
|
function isInteractive() {
|
|
@@ -2174,6 +2364,9 @@ function isOrgAccessError(error) {
|
|
|
2174
2364
|
}
|
|
2175
2365
|
|
|
2176
2366
|
// src/cli/commands/org.ts
|
|
2367
|
+
init_credentials();
|
|
2368
|
+
init_convex();
|
|
2369
|
+
init_convex();
|
|
2177
2370
|
import { Command as Command3 } from "commander";
|
|
2178
2371
|
import chalk4 from "chalk";
|
|
2179
2372
|
import ora4 from "ora";
|
|
@@ -2475,6 +2668,7 @@ function slugify(name) {
|
|
|
2475
2668
|
}
|
|
2476
2669
|
|
|
2477
2670
|
// src/cli/commands/dev.ts
|
|
2671
|
+
init_credentials();
|
|
2478
2672
|
import { Command as Command6 } from "commander";
|
|
2479
2673
|
import chalk7 from "chalk";
|
|
2480
2674
|
import ora6 from "ora";
|
|
@@ -2483,9 +2677,11 @@ import { join as join8 } from "path";
|
|
|
2483
2677
|
import { existsSync as existsSync8 } from "fs";
|
|
2484
2678
|
|
|
2485
2679
|
// src/cli/commands/sync.ts
|
|
2680
|
+
init_credentials();
|
|
2486
2681
|
import { Command as Command5 } from "commander";
|
|
2487
2682
|
import chalk6 from "chalk";
|
|
2488
2683
|
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
2684
|
+
init_convex();
|
|
2489
2685
|
|
|
2490
2686
|
// src/cli/utils/extractor.ts
|
|
2491
2687
|
var BUILTIN_TOOLS = [
|
|
@@ -2594,6 +2790,29 @@ function extractSyncPayload(resources) {
|
|
|
2594
2790
|
schedule: t.schedule,
|
|
2595
2791
|
retry: t.retry
|
|
2596
2792
|
})) : undefined;
|
|
2793
|
+
const routers = resources.routers.length > 0 ? resources.routers.map((r) => ({
|
|
2794
|
+
name: r.name,
|
|
2795
|
+
slug: r.slug,
|
|
2796
|
+
description: r.description,
|
|
2797
|
+
mode: r.mode,
|
|
2798
|
+
agents: r.agents.map((a) => ({
|
|
2799
|
+
slug: a.slug,
|
|
2800
|
+
description: a.description
|
|
2801
|
+
})),
|
|
2802
|
+
rules: r.rules?.map((rule) => ({
|
|
2803
|
+
conditions: rule.conditions.map((c) => ({
|
|
2804
|
+
field: c.field,
|
|
2805
|
+
operator: c.operator,
|
|
2806
|
+
value: c.value
|
|
2807
|
+
})),
|
|
2808
|
+
route: rule.route
|
|
2809
|
+
})),
|
|
2810
|
+
fallback: r.fallback,
|
|
2811
|
+
classifyModel: r.classifyModel,
|
|
2812
|
+
contextMessages: r.contextMessages,
|
|
2813
|
+
maxTransfers: r.maxTransfers,
|
|
2814
|
+
inactivityResetMs: r.inactivityResetMs
|
|
2815
|
+
})) : undefined;
|
|
2597
2816
|
const fixtures = resources.fixtures.length > 0 ? resources.fixtures.map((f) => ({
|
|
2598
2817
|
name: f.name,
|
|
2599
2818
|
slug: f.slug,
|
|
@@ -2610,7 +2829,7 @@ function extractSyncPayload(resources) {
|
|
|
2610
2829
|
metadata: r.metadata
|
|
2611
2830
|
}))
|
|
2612
2831
|
})) : undefined;
|
|
2613
|
-
return { agents, entityTypes, roles, evalSuites, triggers, fixtures };
|
|
2832
|
+
return { agents, entityTypes, roles, evalSuites, triggers, routers, fixtures };
|
|
2614
2833
|
}
|
|
2615
2834
|
function extractAgentPayload(agent, customToolsMap) {
|
|
2616
2835
|
let systemPrompt;
|
|
@@ -3039,6 +3258,7 @@ ${resources.errors.join(`
|
|
|
3039
3258
|
entityTypes: payload.entityTypes,
|
|
3040
3259
|
roles: payload.roles,
|
|
3041
3260
|
triggers: payload.triggers,
|
|
3261
|
+
routers: payload.routers,
|
|
3042
3262
|
organizationId,
|
|
3043
3263
|
environment: "development"
|
|
3044
3264
|
});
|
|
@@ -3072,7 +3292,8 @@ async function checkForDeletions(resources, organizationId, environment) {
|
|
|
3072
3292
|
entityTypes: new Set(payload.entityTypes.map((et) => et.slug)),
|
|
3073
3293
|
roles: new Set(payload.roles.map((r) => r.name)),
|
|
3074
3294
|
evalSuites: new Set((payload.evalSuites || []).map((es) => es.slug)),
|
|
3075
|
-
triggers: new Set((payload.triggers || []).map((t) => t.slug))
|
|
3295
|
+
triggers: new Set((payload.triggers || []).map((t) => t.slug)),
|
|
3296
|
+
routers: new Set((payload.routers || []).map((r) => r.slug))
|
|
3076
3297
|
};
|
|
3077
3298
|
const deletions = [];
|
|
3078
3299
|
const deletedAgents = remoteState.agents.filter((a) => !localSlugs.agents.has(a.slug)).map((a) => a.name);
|
|
@@ -3092,6 +3313,10 @@ async function checkForDeletions(resources, organizationId, environment) {
|
|
|
3092
3313
|
const deletedTriggers = remoteTriggers.filter((t) => !localSlugs.triggers.has(t.slug)).map((t) => t.name);
|
|
3093
3314
|
if (deletedTriggers.length > 0)
|
|
3094
3315
|
deletions.push({ type: "Triggers", remote: remoteTriggers.length, local: (payload.triggers || []).length, deleted: deletedTriggers });
|
|
3316
|
+
const remoteRouters = remoteState.routers || [];
|
|
3317
|
+
const deletedRouters = remoteRouters.filter((r) => !localSlugs.routers.has(r.slug)).map((r) => r.name);
|
|
3318
|
+
if (deletedRouters.length > 0)
|
|
3319
|
+
deletions.push({ type: "Routers", remote: remoteRouters.length, local: (payload.routers || []).length, deleted: deletedRouters });
|
|
3095
3320
|
return deletions;
|
|
3096
3321
|
}
|
|
3097
3322
|
async function syncToEnvironment(cwd, organizationId, environment) {
|
|
@@ -3211,6 +3436,7 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
|
|
|
3211
3436
|
entityTypes: payload.entityTypes.map((et) => et.slug),
|
|
3212
3437
|
roles: payload.roles.map((r) => r.name),
|
|
3213
3438
|
triggers: (payload.triggers || []).map((t) => t.slug),
|
|
3439
|
+
routers: (payload.routers || []).map((r) => r.slug),
|
|
3214
3440
|
deletions: deletions.map((d) => ({ type: d.type, names: d.deleted }))
|
|
3215
3441
|
}));
|
|
3216
3442
|
} else {
|
|
@@ -3220,6 +3446,7 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
|
|
|
3220
3446
|
console.log(chalk6.gray(" Data types:"), payload.entityTypes.map((et) => et.slug).join(", ") || "none");
|
|
3221
3447
|
console.log(chalk6.gray(" Roles:"), payload.roles.map((r) => r.name).join(", ") || "none");
|
|
3222
3448
|
console.log(chalk6.gray(" Triggers:"), (payload.triggers || []).map((t) => t.slug).join(", ") || "none");
|
|
3449
|
+
console.log(chalk6.gray(" Routers:"), (payload.routers || []).map((r) => r.slug).join(", ") || "none");
|
|
3223
3450
|
if (deletions.length > 0) {
|
|
3224
3451
|
console.log();
|
|
3225
3452
|
console.log(chalk6.yellow.bold(" Would delete:"));
|
|
@@ -3384,7 +3611,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3384
3611
|
spinner.start("Loading resources");
|
|
3385
3612
|
try {
|
|
3386
3613
|
loadedResources = await loadAllResources(cwd);
|
|
3387
|
-
spinner.succeed(`Loaded ${loadedResources.agents.length} agents, ${loadedResources.entityTypes.length} data types, ${loadedResources.roles.length} roles, ${loadedResources.customTools.length} custom tools, ${loadedResources.evalSuites.length} eval suites, ${loadedResources.triggers.length} triggers, ${loadedResources.fixtures.length} fixtures`);
|
|
3614
|
+
spinner.succeed(`Loaded ${loadedResources.agents.length} agents, ${loadedResources.entityTypes.length} data types, ${loadedResources.roles.length} roles, ${loadedResources.customTools.length} custom tools, ${loadedResources.evalSuites.length} eval suites, ${loadedResources.triggers.length} triggers, ${loadedResources.routers.length} routers, ${loadedResources.fixtures.length} fixtures`);
|
|
3388
3615
|
for (const err of loadedResources.errors) {
|
|
3389
3616
|
console.log(chalk7.red(" \u2716"), err);
|
|
3390
3617
|
}
|
|
@@ -3479,6 +3706,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3479
3706
|
dirs.tools,
|
|
3480
3707
|
dirs.evals,
|
|
3481
3708
|
dirs.triggers,
|
|
3709
|
+
dirs.routers,
|
|
3482
3710
|
dirs.fixtures
|
|
3483
3711
|
].filter((p) => existsSync8(p));
|
|
3484
3712
|
const watcher = chokidar.watch(watchPaths, {
|
|
@@ -3544,10 +3772,12 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3544
3772
|
});
|
|
3545
3773
|
|
|
3546
3774
|
// src/cli/commands/deploy.ts
|
|
3775
|
+
init_credentials();
|
|
3547
3776
|
import { Command as Command7 } from "commander";
|
|
3548
3777
|
import chalk8 from "chalk";
|
|
3549
3778
|
import ora7 from "ora";
|
|
3550
3779
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
3780
|
+
init_convex();
|
|
3551
3781
|
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) => {
|
|
3552
3782
|
const spinner = ora7();
|
|
3553
3783
|
const cwd = process.cwd();
|
|
@@ -3859,6 +4089,7 @@ var deployCommand = new Command7("deploy").description("Deploy all resources to
|
|
|
3859
4089
|
});
|
|
3860
4090
|
|
|
3861
4091
|
// src/cli/commands/logout.ts
|
|
4092
|
+
init_credentials();
|
|
3862
4093
|
import { Command as Command8 } from "commander";
|
|
3863
4094
|
import chalk9 from "chalk";
|
|
3864
4095
|
var logoutCommand = new Command8("logout").description("Log out of Struere").action(async () => {
|
|
@@ -3876,6 +4107,8 @@ var logoutCommand = new Command8("logout").description("Log out of Struere").act
|
|
|
3876
4107
|
});
|
|
3877
4108
|
|
|
3878
4109
|
// src/cli/commands/whoami.ts
|
|
4110
|
+
init_credentials();
|
|
4111
|
+
init_convex();
|
|
3879
4112
|
import { Command as Command9 } from "commander";
|
|
3880
4113
|
import chalk10 from "chalk";
|
|
3881
4114
|
import ora8 from "ora";
|
|
@@ -3971,7 +4204,7 @@ var whoamiCommand = new Command9("whoami").description("Show current logged in u
|
|
|
3971
4204
|
// src/cli/commands/add.ts
|
|
3972
4205
|
import { Command as Command10 } from "commander";
|
|
3973
4206
|
import chalk11 from "chalk";
|
|
3974
|
-
var addCommand = new Command10("add").description("Scaffold a new resource").argument("<type>", "Resource type: agent, data-type, role, eval, trigger, or fixture").argument("<name>", "Resource name").action(async (type, name) => {
|
|
4207
|
+
var addCommand = new Command10("add").description("Scaffold a new resource").argument("<type>", "Resource type: agent, data-type, role, eval, trigger, router, or fixture").argument("<name>", "Resource name").action(async (type, name) => {
|
|
3975
4208
|
const cwd = process.cwd();
|
|
3976
4209
|
console.log();
|
|
3977
4210
|
if (!hasProject(cwd)) {
|
|
@@ -4049,6 +4282,17 @@ var addCommand = new Command10("add").description("Scaffold a new resource").arg
|
|
|
4049
4282
|
console.log(chalk11.yellow("Trigger already exists:"), `triggers/${slug}.ts`);
|
|
4050
4283
|
}
|
|
4051
4284
|
break;
|
|
4285
|
+
case "router":
|
|
4286
|
+
result = scaffoldRouter(cwd, displayName, slug);
|
|
4287
|
+
if (result.createdFiles.length > 0) {
|
|
4288
|
+
console.log(chalk11.green("\u2713"), `Created router "${displayName}"`);
|
|
4289
|
+
for (const file of result.createdFiles) {
|
|
4290
|
+
console.log(chalk11.gray(" \u2192"), file);
|
|
4291
|
+
}
|
|
4292
|
+
} else {
|
|
4293
|
+
console.log(chalk11.yellow("Router already exists:"), `routers/${slug}.ts`);
|
|
4294
|
+
}
|
|
4295
|
+
break;
|
|
4052
4296
|
case "fixture":
|
|
4053
4297
|
result = scaffoldFixture(cwd, displayName, slug);
|
|
4054
4298
|
if (result.createdFiles.length > 0) {
|
|
@@ -4071,6 +4315,7 @@ var addCommand = new Command10("add").description("Scaffold a new resource").arg
|
|
|
4071
4315
|
console.log(chalk11.gray(" -"), chalk11.cyan("role"), "- Create a role with permissions");
|
|
4072
4316
|
console.log(chalk11.gray(" -"), chalk11.cyan("eval"), "- Create an eval suite (YAML)");
|
|
4073
4317
|
console.log(chalk11.gray(" -"), chalk11.cyan("trigger"), "- Create a data trigger");
|
|
4318
|
+
console.log(chalk11.gray(" -"), chalk11.cyan("router"), "- Create a message router");
|
|
4074
4319
|
console.log(chalk11.gray(" -"), chalk11.cyan("fixture"), "- Create a test data fixture (YAML)");
|
|
4075
4320
|
console.log();
|
|
4076
4321
|
process.exit(1);
|
|
@@ -4084,9 +4329,11 @@ function slugify2(name) {
|
|
|
4084
4329
|
}
|
|
4085
4330
|
|
|
4086
4331
|
// src/cli/commands/status.ts
|
|
4332
|
+
init_credentials();
|
|
4087
4333
|
import { Command as Command11 } from "commander";
|
|
4088
4334
|
import chalk12 from "chalk";
|
|
4089
4335
|
import ora9 from "ora";
|
|
4336
|
+
init_convex();
|
|
4090
4337
|
var statusCommand = new Command11("status").description("Compare local vs remote state").option("--json", "Output raw JSON").action(async (opts) => {
|
|
4091
4338
|
const spinner = ora9();
|
|
4092
4339
|
const cwd = process.cwd();
|
|
@@ -4198,6 +4445,8 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4198
4445
|
const devEntityTypeSlugs = new Set(devState.entityTypes.map((et) => et.slug));
|
|
4199
4446
|
const localRoleNames = new Set(localResources.roles.map((r) => r.name));
|
|
4200
4447
|
const devRoleNames = new Set(devState.roles.map((r) => r.name));
|
|
4448
|
+
const localRouterSlugs = new Set(localResources.routers.map((r) => r.slug));
|
|
4449
|
+
const devRouterSlugs = new Set((devState.routers || []).map((r) => r.slug));
|
|
4201
4450
|
if (opts.json) {
|
|
4202
4451
|
const classify = (localItems, remoteItems, useSlug) => {
|
|
4203
4452
|
const localKeys = new Set(localItems.map((i) => useSlug ? i.slug : i.name));
|
|
@@ -4211,7 +4460,8 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4211
4460
|
console.log(JSON.stringify({
|
|
4212
4461
|
agents: classify(localResources.agents, devState.agents, true),
|
|
4213
4462
|
entityTypes: classify(localResources.entityTypes, devState.entityTypes, true),
|
|
4214
|
-
roles: classify(localResources.roles, devState.roles, false)
|
|
4463
|
+
roles: classify(localResources.roles, devState.roles, false),
|
|
4464
|
+
routers: classify(localResources.routers, devState.routers || [], true)
|
|
4215
4465
|
}));
|
|
4216
4466
|
return;
|
|
4217
4467
|
}
|
|
@@ -4281,6 +4531,26 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4281
4531
|
}
|
|
4282
4532
|
}
|
|
4283
4533
|
console.log();
|
|
4534
|
+
console.log(chalk12.bold("Routers"));
|
|
4535
|
+
console.log(chalk12.gray("\u2500".repeat(60)));
|
|
4536
|
+
if (localResources.routers.length === 0 && (devState.routers || []).length === 0) {
|
|
4537
|
+
console.log(chalk12.gray(" No routers"));
|
|
4538
|
+
} else {
|
|
4539
|
+
for (const router of localResources.routers) {
|
|
4540
|
+
const remote = (devState.routers || []).find((r) => r.slug === router.slug);
|
|
4541
|
+
if (remote) {
|
|
4542
|
+
console.log(` ${chalk12.green("\u25CF")} ${chalk12.cyan(router.name)} (${router.slug}) - ${router.mode}`);
|
|
4543
|
+
} else {
|
|
4544
|
+
console.log(` ${chalk12.blue("+")} ${chalk12.cyan(router.name)} (${router.slug}) - ${chalk12.blue("new")}`);
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4547
|
+
for (const remote of devState.routers || []) {
|
|
4548
|
+
if (!localRouterSlugs.has(remote.slug)) {
|
|
4549
|
+
console.log(` ${chalk12.red("-")} ${remote.name} (${remote.slug}) - ${chalk12.red("will be deleted")}`);
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
}
|
|
4553
|
+
console.log();
|
|
4284
4554
|
console.log(chalk12.gray("Legend:"));
|
|
4285
4555
|
console.log(chalk12.gray(" "), chalk12.green("\u25CF"), "Synced", chalk12.yellow("\u25CB"), "Not in production", chalk12.blue("+"), "New", chalk12.red("-"), "Will be deleted");
|
|
4286
4556
|
console.log();
|
|
@@ -4290,11 +4560,13 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4290
4560
|
});
|
|
4291
4561
|
|
|
4292
4562
|
// src/cli/commands/pull.ts
|
|
4563
|
+
init_credentials();
|
|
4293
4564
|
import { Command as Command12 } from "commander";
|
|
4294
4565
|
import chalk13 from "chalk";
|
|
4295
4566
|
import ora10 from "ora";
|
|
4296
4567
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
4297
4568
|
import { join as join9 } from "path";
|
|
4569
|
+
init_convex();
|
|
4298
4570
|
|
|
4299
4571
|
// src/cli/utils/generator.ts
|
|
4300
4572
|
var BUILTIN_TOOLS2 = [
|
|
@@ -4553,6 +4825,53 @@ ${parts.join(`,
|
|
|
4553
4825
|
})
|
|
4554
4826
|
`;
|
|
4555
4827
|
}
|
|
4828
|
+
function generateRouterFile(router) {
|
|
4829
|
+
const agentLines = router.agents.map((a) => {
|
|
4830
|
+
const aParts = [
|
|
4831
|
+
` slug: "${a.slug}"`,
|
|
4832
|
+
` description: "${a.description}"`
|
|
4833
|
+
];
|
|
4834
|
+
return ` {
|
|
4835
|
+
${aParts.join(`,
|
|
4836
|
+
`)},
|
|
4837
|
+
}`;
|
|
4838
|
+
});
|
|
4839
|
+
const parts = [
|
|
4840
|
+
` name: "${router.name}"`,
|
|
4841
|
+
` slug: "${router.slug}"`
|
|
4842
|
+
];
|
|
4843
|
+
if (router.description) {
|
|
4844
|
+
parts.push(` description: "${router.description}"`);
|
|
4845
|
+
}
|
|
4846
|
+
parts.push(` mode: "${router.mode}"`);
|
|
4847
|
+
parts.push(` agents: [
|
|
4848
|
+
${agentLines.join(`,
|
|
4849
|
+
`)},
|
|
4850
|
+
]`);
|
|
4851
|
+
if (router.rules && router.rules.length > 0) {
|
|
4852
|
+
parts.push(` rules: ${stringifyValue(router.rules, 2)}`);
|
|
4853
|
+
}
|
|
4854
|
+
parts.push(` fallback: "${router.fallback}"`);
|
|
4855
|
+
if (router.classifyModel) {
|
|
4856
|
+
parts.push(` classifyModel: ${stringifyValue(router.classifyModel, 2)}`);
|
|
4857
|
+
}
|
|
4858
|
+
if (router.contextMessages !== undefined) {
|
|
4859
|
+
parts.push(` contextMessages: ${router.contextMessages}`);
|
|
4860
|
+
}
|
|
4861
|
+
if (router.maxTransfers !== undefined) {
|
|
4862
|
+
parts.push(` maxTransfers: ${router.maxTransfers}`);
|
|
4863
|
+
}
|
|
4864
|
+
if (router.inactivityResetMs !== undefined) {
|
|
4865
|
+
parts.push(` inactivityResetMs: ${router.inactivityResetMs}`);
|
|
4866
|
+
}
|
|
4867
|
+
return `import { defineRouter } from 'struere'
|
|
4868
|
+
|
|
4869
|
+
export default defineRouter({
|
|
4870
|
+
${parts.join(`,
|
|
4871
|
+
`)},
|
|
4872
|
+
})
|
|
4873
|
+
`;
|
|
4874
|
+
}
|
|
4556
4875
|
function generateIndexFile(type, slugs) {
|
|
4557
4876
|
if (slugs.length === 0) {
|
|
4558
4877
|
return "";
|
|
@@ -4687,6 +5006,7 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4687
5006
|
ensureDir2(join9(cwd, "entity-types"));
|
|
4688
5007
|
ensureDir2(join9(cwd, "roles"));
|
|
4689
5008
|
ensureDir2(join9(cwd, "triggers"));
|
|
5009
|
+
ensureDir2(join9(cwd, "routers"));
|
|
4690
5010
|
ensureDir2(join9(cwd, "tools"));
|
|
4691
5011
|
const agentSlugs = [];
|
|
4692
5012
|
for (const agent of state.agents) {
|
|
@@ -4714,6 +5034,12 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4714
5034
|
const content = generateTriggerFile(trigger);
|
|
4715
5035
|
writeOrSkip(`triggers/${trigger.slug}.ts`, content);
|
|
4716
5036
|
}
|
|
5037
|
+
const routerSlugs = [];
|
|
5038
|
+
for (const router of state.routers || []) {
|
|
5039
|
+
routerSlugs.push(router.slug);
|
|
5040
|
+
const content = generateRouterFile(router);
|
|
5041
|
+
writeOrSkip(`routers/${router.slug}.ts`, content);
|
|
5042
|
+
}
|
|
4717
5043
|
const customTools = collectCustomTools(state.agents);
|
|
4718
5044
|
if (customTools.length > 0) {
|
|
4719
5045
|
const content = generateToolsFile(customTools);
|
|
@@ -4739,6 +5065,11 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4739
5065
|
if (content)
|
|
4740
5066
|
writeOrSkip("triggers/index.ts", content);
|
|
4741
5067
|
}
|
|
5068
|
+
if (routerSlugs.length > 0) {
|
|
5069
|
+
const content = generateIndexFile("routers", routerSlugs);
|
|
5070
|
+
if (content)
|
|
5071
|
+
writeOrSkip("routers/index.ts", content);
|
|
5072
|
+
}
|
|
4742
5073
|
await installSkill(cwd);
|
|
4743
5074
|
if (options.json) {
|
|
4744
5075
|
console.log(JSON.stringify({
|
|
@@ -4777,21 +5108,20 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4777
5108
|
});
|
|
4778
5109
|
|
|
4779
5110
|
// src/cli/commands/entities.ts
|
|
5111
|
+
init_credentials();
|
|
4780
5112
|
import { Command as Command13 } from "commander";
|
|
4781
5113
|
import chalk15 from "chalk";
|
|
4782
5114
|
import ora11 from "ora";
|
|
4783
5115
|
import { input as input2, confirm as confirm5 } from "@inquirer/prompts";
|
|
4784
5116
|
|
|
4785
5117
|
// src/cli/utils/entities.ts
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
const apiKey = getApiKey();
|
|
4789
|
-
return apiKey || credentials?.token || null;
|
|
4790
|
-
}
|
|
5118
|
+
init_credentials();
|
|
5119
|
+
init_config();
|
|
4791
5120
|
async function convexQuery(path, args) {
|
|
4792
|
-
const
|
|
4793
|
-
if (
|
|
4794
|
-
return { error:
|
|
5121
|
+
const result = await getValidToken();
|
|
5122
|
+
if ("error" in result)
|
|
5123
|
+
return { error: result.error };
|
|
5124
|
+
const { token } = result;
|
|
4795
5125
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
4796
5126
|
method: "POST",
|
|
4797
5127
|
headers: {
|
|
@@ -4818,9 +5148,10 @@ async function convexQuery(path, args) {
|
|
|
4818
5148
|
return { error: `Unexpected response: ${text}` };
|
|
4819
5149
|
}
|
|
4820
5150
|
async function convexMutation(path, args) {
|
|
4821
|
-
const
|
|
4822
|
-
if (
|
|
4823
|
-
return { error:
|
|
5151
|
+
const result = await getValidToken();
|
|
5152
|
+
if ("error" in result)
|
|
5153
|
+
return { error: result.error };
|
|
5154
|
+
const { token } = result;
|
|
4824
5155
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
4825
5156
|
method: "POST",
|
|
4826
5157
|
headers: {
|
|
@@ -5348,24 +5679,20 @@ entitiesCommand.command("search <type> <query>").description("Search records").o
|
|
|
5348
5679
|
});
|
|
5349
5680
|
|
|
5350
5681
|
// src/cli/commands/logs.ts
|
|
5682
|
+
init_credentials();
|
|
5351
5683
|
import { Command as Command14 } from "commander";
|
|
5352
5684
|
import chalk16 from "chalk";
|
|
5353
5685
|
import ora12 from "ora";
|
|
5354
5686
|
|
|
5355
5687
|
// src/cli/utils/logs.ts
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
const apiKey = getApiKey();
|
|
5359
|
-
return apiKey || credentials?.token || null;
|
|
5360
|
-
}
|
|
5688
|
+
init_credentials();
|
|
5689
|
+
init_config();
|
|
5361
5690
|
async function convexQuery2(path, args) {
|
|
5362
|
-
|
|
5363
|
-
if (
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
}
|
|
5368
|
-
let response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
5691
|
+
const tokenResult = await getValidToken();
|
|
5692
|
+
if ("error" in tokenResult)
|
|
5693
|
+
return { error: tokenResult.error };
|
|
5694
|
+
const { token } = tokenResult;
|
|
5695
|
+
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
5369
5696
|
method: "POST",
|
|
5370
5697
|
headers: {
|
|
5371
5698
|
"Content-Type": "application/json",
|
|
@@ -5373,19 +5700,6 @@ async function convexQuery2(path, args) {
|
|
|
5373
5700
|
},
|
|
5374
5701
|
body: JSON.stringify({ path, args })
|
|
5375
5702
|
});
|
|
5376
|
-
if (response.status === 401 || response.status === 403) {
|
|
5377
|
-
const refreshed = await refreshToken();
|
|
5378
|
-
if (refreshed) {
|
|
5379
|
-
response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
5380
|
-
method: "POST",
|
|
5381
|
-
headers: {
|
|
5382
|
-
"Content-Type": "application/json",
|
|
5383
|
-
Authorization: `Bearer ${refreshed}`
|
|
5384
|
-
},
|
|
5385
|
-
body: JSON.stringify({ path, args })
|
|
5386
|
-
});
|
|
5387
|
-
}
|
|
5388
|
-
}
|
|
5389
5703
|
const text = await response.text();
|
|
5390
5704
|
let json;
|
|
5391
5705
|
try {
|
|
@@ -5396,21 +5710,12 @@ async function convexQuery2(path, args) {
|
|
|
5396
5710
|
if (!response.ok) {
|
|
5397
5711
|
const errorData = json.errorData;
|
|
5398
5712
|
const msg = errorData?.message || json.message || json.errorMessage || text;
|
|
5399
|
-
|
|
5400
|
-
if (msgStr.includes("OIDC") || msgStr.includes("token")) {
|
|
5401
|
-
return { error: "Session expired. Run `struere logout && struere login`." };
|
|
5402
|
-
}
|
|
5403
|
-
return { error: msgStr };
|
|
5713
|
+
return { error: String(msg) };
|
|
5404
5714
|
}
|
|
5405
5715
|
if (json.status === "success")
|
|
5406
5716
|
return { data: json.value };
|
|
5407
|
-
if (json.status === "error")
|
|
5408
|
-
|
|
5409
|
-
if (errMsg.includes("OIDC") || errMsg.includes("token")) {
|
|
5410
|
-
return { error: "Session expired. Run `struere logout && struere login`." };
|
|
5411
|
-
}
|
|
5412
|
-
return { error: errMsg };
|
|
5413
|
-
}
|
|
5717
|
+
if (json.status === "error")
|
|
5718
|
+
return { error: String(json.errorMessage || "Unknown error") };
|
|
5414
5719
|
return { error: `Unexpected response: ${text}` };
|
|
5415
5720
|
}
|
|
5416
5721
|
async function queryThreads(options) {
|
|
@@ -5721,14 +6026,18 @@ logsCommand.command("view <thread-id>").description("View conversation messages"
|
|
|
5721
6026
|
});
|
|
5722
6027
|
|
|
5723
6028
|
// src/cli/commands/eval.ts
|
|
6029
|
+
init_credentials();
|
|
5724
6030
|
import { Command as Command15 } from "commander";
|
|
5725
6031
|
import chalk17 from "chalk";
|
|
5726
6032
|
import ora13 from "ora";
|
|
5727
6033
|
import { join as join10 } from "path";
|
|
5728
6034
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
6035
|
+
init_convex();
|
|
5729
6036
|
|
|
5730
6037
|
// src/cli/utils/evals.ts
|
|
5731
|
-
|
|
6038
|
+
init_credentials();
|
|
6039
|
+
init_config();
|
|
6040
|
+
function getToken() {
|
|
5732
6041
|
const credentials = loadCredentials();
|
|
5733
6042
|
const apiKey = getApiKey();
|
|
5734
6043
|
const token = apiKey || credentials?.token;
|
|
@@ -5737,7 +6046,7 @@ function getToken3() {
|
|
|
5737
6046
|
return token;
|
|
5738
6047
|
}
|
|
5739
6048
|
async function convexQuery3(path, args) {
|
|
5740
|
-
const token =
|
|
6049
|
+
const token = getToken();
|
|
5741
6050
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
5742
6051
|
method: "POST",
|
|
5743
6052
|
headers: {
|
|
@@ -5762,7 +6071,7 @@ async function convexQuery3(path, args) {
|
|
|
5762
6071
|
return json.value;
|
|
5763
6072
|
}
|
|
5764
6073
|
async function convexMutation2(path, args) {
|
|
5765
|
-
const token =
|
|
6074
|
+
const token = getToken();
|
|
5766
6075
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
5767
6076
|
method: "POST",
|
|
5768
6077
|
headers: {
|
|
@@ -6178,13 +6487,16 @@ var evalCommand = new Command15("eval").description("Eval suite management");
|
|
|
6178
6487
|
evalCommand.addCommand(runCommand);
|
|
6179
6488
|
|
|
6180
6489
|
// src/cli/commands/templates.ts
|
|
6490
|
+
init_credentials();
|
|
6181
6491
|
import { Command as Command16 } from "commander";
|
|
6182
6492
|
import chalk18 from "chalk";
|
|
6183
6493
|
import { readFileSync as readFileSync5 } from "fs";
|
|
6184
6494
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
6185
6495
|
|
|
6186
6496
|
// src/cli/utils/whatsapp.ts
|
|
6187
|
-
|
|
6497
|
+
init_credentials();
|
|
6498
|
+
init_config();
|
|
6499
|
+
function getToken2() {
|
|
6188
6500
|
const credentials = loadCredentials();
|
|
6189
6501
|
const apiKey = getApiKey();
|
|
6190
6502
|
return apiKey || credentials?.token || null;
|
|
@@ -6223,7 +6535,7 @@ async function httpPost(path, body) {
|
|
|
6223
6535
|
}
|
|
6224
6536
|
}
|
|
6225
6537
|
async function convexAction(path, args) {
|
|
6226
|
-
const token =
|
|
6538
|
+
const token = getToken2();
|
|
6227
6539
|
if (!token)
|
|
6228
6540
|
return { error: "Not authenticated" };
|
|
6229
6541
|
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
@@ -6252,7 +6564,7 @@ async function convexAction(path, args) {
|
|
|
6252
6564
|
return { error: `Unexpected response: ${text}` };
|
|
6253
6565
|
}
|
|
6254
6566
|
async function convexQuery4(path, args) {
|
|
6255
|
-
const token =
|
|
6567
|
+
const token = getToken2();
|
|
6256
6568
|
if (!token)
|
|
6257
6569
|
return { error: "Not authenticated" };
|
|
6258
6570
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
@@ -6335,6 +6647,16 @@ async function getTemplateStatus(connectionId, name) {
|
|
|
6335
6647
|
name
|
|
6336
6648
|
});
|
|
6337
6649
|
}
|
|
6650
|
+
async function updateTemplate(connectionId, templateId, updates) {
|
|
6651
|
+
if (getApiKey()) {
|
|
6652
|
+
return httpPost("/v1/templates/update", { connectionId, templateId, ...updates });
|
|
6653
|
+
}
|
|
6654
|
+
return convexAction("whatsappActions:updateTemplate", {
|
|
6655
|
+
connectionId,
|
|
6656
|
+
templateId,
|
|
6657
|
+
...updates
|
|
6658
|
+
});
|
|
6659
|
+
}
|
|
6338
6660
|
|
|
6339
6661
|
// src/cli/commands/templates.ts
|
|
6340
6662
|
async function ensureAuth3() {
|
|
@@ -6427,9 +6749,9 @@ function statusColor2(status) {
|
|
|
6427
6749
|
}
|
|
6428
6750
|
}
|
|
6429
6751
|
var templatesCommand = new Command16("templates").description("Manage WhatsApp message templates");
|
|
6430
|
-
templatesCommand.command("list").description("List all message templates").option("--connection <id>", "WhatsApp connection ID").option("--json", "Output raw JSON").action(async (opts) => {
|
|
6752
|
+
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) => {
|
|
6431
6753
|
await ensureAuth3();
|
|
6432
|
-
const connectionId = await resolveConnectionId("
|
|
6754
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6433
6755
|
const out = createOutput();
|
|
6434
6756
|
out.start("Fetching templates");
|
|
6435
6757
|
const { data, error } = await listTemplates(connectionId);
|
|
@@ -6464,9 +6786,9 @@ templatesCommand.command("list").description("List all message templates").optio
|
|
|
6464
6786
|
})));
|
|
6465
6787
|
console.log();
|
|
6466
6788
|
});
|
|
6467
|
-
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) => {
|
|
6789
|
+
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) => {
|
|
6468
6790
|
await ensureAuth3();
|
|
6469
|
-
const connectionId = await resolveConnectionId("
|
|
6791
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6470
6792
|
let components;
|
|
6471
6793
|
if (opts.file) {
|
|
6472
6794
|
try {
|
|
@@ -6512,9 +6834,9 @@ templatesCommand.command("create <name>").description("Create a new message temp
|
|
|
6512
6834
|
console.log();
|
|
6513
6835
|
}
|
|
6514
6836
|
});
|
|
6515
|
-
templatesCommand.command("delete <name>").description("Delete a message template").option("--connection <id>", "WhatsApp connection ID").option("--yes", "Skip confirmation").action(async (name, opts) => {
|
|
6837
|
+
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) => {
|
|
6516
6838
|
await ensureAuth3();
|
|
6517
|
-
const connectionId = await resolveConnectionId("
|
|
6839
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6518
6840
|
if (!opts.yes && isInteractive()) {
|
|
6519
6841
|
const confirmed = await confirm6({
|
|
6520
6842
|
message: `Delete template "${name}"? This cannot be undone.`,
|
|
@@ -6536,9 +6858,9 @@ templatesCommand.command("delete <name>").description("Delete a message template
|
|
|
6536
6858
|
out.succeed(`Template "${name}" deleted`);
|
|
6537
6859
|
console.log();
|
|
6538
6860
|
});
|
|
6539
|
-
templatesCommand.command("status <name>").description("Check template approval status").option("--connection <id>", "WhatsApp connection ID").option("--json", "Output raw JSON").action(async (name, opts) => {
|
|
6861
|
+
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) => {
|
|
6540
6862
|
await ensureAuth3();
|
|
6541
|
-
const connectionId = await resolveConnectionId("
|
|
6863
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6542
6864
|
const out = createOutput();
|
|
6543
6865
|
out.start(`Checking status for "${name}"`);
|
|
6544
6866
|
const { data, error } = await getTemplateStatus(connectionId, name);
|
|
@@ -6564,6 +6886,8 @@ templatesCommand.command("status <name>").description("Check template approval s
|
|
|
6564
6886
|
console.log(` ${chalk18.gray("Status:")} ${statusColor2(String(t.status ?? ""))}`);
|
|
6565
6887
|
console.log(` ${chalk18.gray("Category:")} ${t.category}`);
|
|
6566
6888
|
console.log(` ${chalk18.gray("Language:")} ${t.language}`);
|
|
6889
|
+
if (t.id)
|
|
6890
|
+
console.log(` ${chalk18.gray("ID:")} ${t.id}`);
|
|
6567
6891
|
if (t.components) {
|
|
6568
6892
|
console.log(` ${chalk18.gray("Components:")} ${JSON.stringify(t.components, null, 2).split(`
|
|
6569
6893
|
`).join(`
|
|
@@ -6572,22 +6896,105 @@ templatesCommand.command("status <name>").description("Check template approval s
|
|
|
6572
6896
|
console.log();
|
|
6573
6897
|
}
|
|
6574
6898
|
});
|
|
6899
|
+
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) => {
|
|
6900
|
+
await ensureAuth3();
|
|
6901
|
+
const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
|
|
6902
|
+
const out = createOutput();
|
|
6903
|
+
out.start(`Fetching template "${name}"`);
|
|
6904
|
+
const { data: statusData, error: statusError } = await getTemplateStatus(connectionId, name);
|
|
6905
|
+
if (statusError) {
|
|
6906
|
+
out.fail("Failed to fetch template");
|
|
6907
|
+
out.error(statusError);
|
|
6908
|
+
process.exit(1);
|
|
6909
|
+
}
|
|
6910
|
+
const statusResult = statusData;
|
|
6911
|
+
const existing = statusResult?.data ?? [];
|
|
6912
|
+
const match = opts.language ? existing.find((t) => t.language === opts.language) : existing[0];
|
|
6913
|
+
if (!match) {
|
|
6914
|
+
out.fail(`Template "${name}" not found${opts.language ? ` for language ${opts.language}` : ""}`);
|
|
6915
|
+
process.exit(1);
|
|
6916
|
+
}
|
|
6917
|
+
const templateId = match.id;
|
|
6918
|
+
if (!templateId) {
|
|
6919
|
+
out.fail("Template ID not found in response");
|
|
6920
|
+
process.exit(1);
|
|
6921
|
+
}
|
|
6922
|
+
out.succeed(`Found template "${name}" (${match.language}, ID: ${templateId})`);
|
|
6923
|
+
let components;
|
|
6924
|
+
if (opts.file) {
|
|
6925
|
+
try {
|
|
6926
|
+
const fileContent = readFileSync5(opts.file, "utf-8");
|
|
6927
|
+
const parsed = JSON.parse(fileContent);
|
|
6928
|
+
components = Array.isArray(parsed) ? parsed : parsed.components ?? [parsed];
|
|
6929
|
+
} catch (err) {
|
|
6930
|
+
console.log(chalk18.red("Failed to read components file:"), err instanceof Error ? err.message : String(err));
|
|
6931
|
+
process.exit(1);
|
|
6932
|
+
}
|
|
6933
|
+
} else if (opts.components) {
|
|
6934
|
+
try {
|
|
6935
|
+
components = JSON.parse(opts.components);
|
|
6936
|
+
} catch {
|
|
6937
|
+
console.log(chalk18.red("Invalid JSON in --components"));
|
|
6938
|
+
process.exit(1);
|
|
6939
|
+
}
|
|
6940
|
+
}
|
|
6941
|
+
if (!components && !opts.category) {
|
|
6942
|
+
console.log();
|
|
6943
|
+
console.log(chalk18.gray("Current components:"));
|
|
6944
|
+
console.log(JSON.stringify(match.components, null, 2));
|
|
6945
|
+
console.log();
|
|
6946
|
+
console.log(chalk18.yellow("Provide --components <json>, --file <path>, or --category <cat> to update"));
|
|
6947
|
+
process.exit(1);
|
|
6948
|
+
}
|
|
6949
|
+
const updates = { name, language: opts.language ?? match.language };
|
|
6950
|
+
if (components)
|
|
6951
|
+
updates.components = components;
|
|
6952
|
+
if (opts.category)
|
|
6953
|
+
updates.category = opts.category.toUpperCase();
|
|
6954
|
+
if (!opts.json && isInteractive()) {
|
|
6955
|
+
console.log();
|
|
6956
|
+
if (components) {
|
|
6957
|
+
console.log(chalk18.gray("New components:"));
|
|
6958
|
+
console.log(JSON.stringify(components, null, 2));
|
|
6959
|
+
console.log();
|
|
6960
|
+
}
|
|
6961
|
+
const confirmed = await confirm6({
|
|
6962
|
+
message: `Update template "${name}"? This will resubmit for Meta approval.`,
|
|
6963
|
+
default: true
|
|
6964
|
+
});
|
|
6965
|
+
if (!confirmed) {
|
|
6966
|
+
console.log(chalk18.gray("Cancelled"));
|
|
6967
|
+
return;
|
|
6968
|
+
}
|
|
6969
|
+
}
|
|
6970
|
+
out.start(`Updating template "${name}"`);
|
|
6971
|
+
const { data, error } = await updateTemplate(connectionId, templateId, updates);
|
|
6972
|
+
if (error) {
|
|
6973
|
+
out.fail("Failed to update template");
|
|
6974
|
+
out.error(error);
|
|
6975
|
+
process.exit(1);
|
|
6976
|
+
}
|
|
6977
|
+
out.succeed(`Template "${name}" updated \u2014 resubmitted for approval`);
|
|
6978
|
+
if (opts.json) {
|
|
6979
|
+
console.log(JSON.stringify(data, null, 2));
|
|
6980
|
+
}
|
|
6981
|
+
console.log();
|
|
6982
|
+
});
|
|
6575
6983
|
|
|
6576
6984
|
// src/cli/commands/integration.ts
|
|
6985
|
+
init_credentials();
|
|
6577
6986
|
import { Command as Command17 } from "commander";
|
|
6578
6987
|
import chalk19 from "chalk";
|
|
6579
6988
|
import { confirm as confirm7 } from "@inquirer/prompts";
|
|
6580
6989
|
|
|
6581
6990
|
// src/cli/utils/integrations.ts
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
const apiKey = getApiKey();
|
|
6585
|
-
return apiKey || credentials?.token || null;
|
|
6586
|
-
}
|
|
6991
|
+
init_credentials();
|
|
6992
|
+
init_config();
|
|
6587
6993
|
async function convexQuery5(path, args) {
|
|
6588
|
-
const
|
|
6589
|
-
if (
|
|
6590
|
-
return { error:
|
|
6994
|
+
const result = await getValidToken();
|
|
6995
|
+
if ("error" in result)
|
|
6996
|
+
return { error: result.error };
|
|
6997
|
+
const { token } = result;
|
|
6591
6998
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
6592
6999
|
method: "POST",
|
|
6593
7000
|
headers: {
|
|
@@ -6614,9 +7021,10 @@ async function convexQuery5(path, args) {
|
|
|
6614
7021
|
return { error: `Unexpected response: ${text}` };
|
|
6615
7022
|
}
|
|
6616
7023
|
async function convexMutation3(path, args) {
|
|
6617
|
-
const
|
|
6618
|
-
if (
|
|
6619
|
-
return { error:
|
|
7024
|
+
const result = await getValidToken();
|
|
7025
|
+
if ("error" in result)
|
|
7026
|
+
return { error: result.error };
|
|
7027
|
+
const { token } = result;
|
|
6620
7028
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
6621
7029
|
method: "POST",
|
|
6622
7030
|
headers: {
|
|
@@ -6643,9 +7051,10 @@ async function convexMutation3(path, args) {
|
|
|
6643
7051
|
return { error: `Unexpected response: ${text}` };
|
|
6644
7052
|
}
|
|
6645
7053
|
async function convexAction2(path, args) {
|
|
6646
|
-
const
|
|
6647
|
-
if (
|
|
6648
|
-
return { error:
|
|
7054
|
+
const result = await getValidToken();
|
|
7055
|
+
if ("error" in result)
|
|
7056
|
+
return { error: result.error };
|
|
7057
|
+
const { token } = result;
|
|
6649
7058
|
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
6650
7059
|
method: "POST",
|
|
6651
7060
|
headers: {
|
|
@@ -6966,12 +7375,15 @@ var integrationCommand = new Command17("integration").description("Manage integr
|
|
|
6966
7375
|
});
|
|
6967
7376
|
|
|
6968
7377
|
// src/cli/commands/triggers.ts
|
|
7378
|
+
init_credentials();
|
|
6969
7379
|
import { Command as Command18 } from "commander";
|
|
6970
7380
|
import chalk20 from "chalk";
|
|
6971
7381
|
import ora14 from "ora";
|
|
6972
7382
|
|
|
6973
7383
|
// src/cli/utils/triggers.ts
|
|
6974
|
-
|
|
7384
|
+
init_credentials();
|
|
7385
|
+
init_config();
|
|
7386
|
+
function getToken3() {
|
|
6975
7387
|
const credentials = loadCredentials();
|
|
6976
7388
|
const apiKey = getApiKey();
|
|
6977
7389
|
const token = apiKey || credentials?.token;
|
|
@@ -6980,7 +7392,7 @@ function getToken6() {
|
|
|
6980
7392
|
return token;
|
|
6981
7393
|
}
|
|
6982
7394
|
async function convexQuery6(path, args) {
|
|
6983
|
-
const token =
|
|
7395
|
+
const token = getToken3();
|
|
6984
7396
|
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
6985
7397
|
method: "POST",
|
|
6986
7398
|
headers: {
|
|
@@ -7005,7 +7417,7 @@ async function convexQuery6(path, args) {
|
|
|
7005
7417
|
return json.value;
|
|
7006
7418
|
}
|
|
7007
7419
|
async function convexMutation4(path, args) {
|
|
7008
|
-
const token =
|
|
7420
|
+
const token = getToken3();
|
|
7009
7421
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
7010
7422
|
method: "POST",
|
|
7011
7423
|
headers: {
|
|
@@ -7076,7 +7488,7 @@ async function getTriggerExecutionDetail(eventId) {
|
|
|
7076
7488
|
return convexQuery6("triggers:getExecutionDetail", { eventId });
|
|
7077
7489
|
}
|
|
7078
7490
|
async function convexAction3(path, args) {
|
|
7079
|
-
const token =
|
|
7491
|
+
const token = getToken3();
|
|
7080
7492
|
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
7081
7493
|
method: "POST",
|
|
7082
7494
|
headers: {
|
|
@@ -7785,9 +8197,11 @@ triggersCommand.command("retry-event <event-id>").description("Retry a failed im
|
|
|
7785
8197
|
});
|
|
7786
8198
|
|
|
7787
8199
|
// src/cli/commands/compile-prompt.ts
|
|
8200
|
+
init_credentials();
|
|
7788
8201
|
import { Command as Command19 } from "commander";
|
|
7789
8202
|
import chalk21 from "chalk";
|
|
7790
8203
|
import ora15 from "ora";
|
|
8204
|
+
init_convex();
|
|
7791
8205
|
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) => {
|
|
7792
8206
|
acc.push(val);
|
|
7793
8207
|
return acc;
|
|
@@ -7933,9 +8347,11 @@ var compilePromptCommand = new Command19("compile-prompt").description("Compile
|
|
|
7933
8347
|
});
|
|
7934
8348
|
|
|
7935
8349
|
// src/cli/commands/run-tool.ts
|
|
8350
|
+
init_credentials();
|
|
7936
8351
|
import { Command as Command20 } from "commander";
|
|
7937
8352
|
import chalk22 from "chalk";
|
|
7938
8353
|
import ora16 from "ora";
|
|
8354
|
+
init_convex();
|
|
7939
8355
|
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) => {
|
|
7940
8356
|
const spinner = ora16();
|
|
7941
8357
|
const cwd = process.cwd();
|
|
@@ -8088,11 +8504,13 @@ var runToolCommand = new Command20("run-tool").description("Run a tool as it wou
|
|
|
8088
8504
|
});
|
|
8089
8505
|
|
|
8090
8506
|
// src/cli/commands/chat.ts
|
|
8507
|
+
init_credentials();
|
|
8091
8508
|
import { Command as Command21 } from "commander";
|
|
8092
8509
|
import chalk23 from "chalk";
|
|
8093
8510
|
import ora17 from "ora";
|
|
8094
8511
|
import readline from "readline";
|
|
8095
|
-
|
|
8512
|
+
init_convex();
|
|
8513
|
+
var chatCommand = new Command21("chat").description("Chat with an agent or via a router").argument("<slug>", "Agent slug (or router slug when --router is used)").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").option("--router", "Chat via a router instead of directly with an agent").option("--phone <number>", "Sender phone number for routing rules").action(async (slug, options) => {
|
|
8096
8514
|
const spinner = ora17();
|
|
8097
8515
|
const cwd = process.cwd();
|
|
8098
8516
|
const nonInteractive = !isInteractive();
|
|
@@ -8144,6 +8562,15 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8144
8562
|
console.log();
|
|
8145
8563
|
}
|
|
8146
8564
|
const environment = options.env;
|
|
8565
|
+
const isRouterMode = !!options.router;
|
|
8566
|
+
if (isRouterMode && !options.phone) {
|
|
8567
|
+
if (jsonMode) {
|
|
8568
|
+
console.log(JSON.stringify({ success: false, error: "--phone is required when using --router" }));
|
|
8569
|
+
} else {
|
|
8570
|
+
console.log(chalk23.red("--phone is required when using --router"));
|
|
8571
|
+
}
|
|
8572
|
+
process.exit(1);
|
|
8573
|
+
}
|
|
8147
8574
|
if (environment === "production" && !nonInteractive && !options.confirm) {
|
|
8148
8575
|
const confirmRl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8149
8576
|
await new Promise((resolve) => {
|
|
@@ -8153,8 +8580,20 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8153
8580
|
confirmRl.close();
|
|
8154
8581
|
}
|
|
8155
8582
|
const doChat = async (message, threadId2, signal) => {
|
|
8583
|
+
if (isRouterMode) {
|
|
8584
|
+
return chatWithRouter({
|
|
8585
|
+
routerSlug: slug,
|
|
8586
|
+
message,
|
|
8587
|
+
threadId: threadId2,
|
|
8588
|
+
phoneNumber: options.phone,
|
|
8589
|
+
environment,
|
|
8590
|
+
organizationId: project?.organization.id,
|
|
8591
|
+
channel: options.channel,
|
|
8592
|
+
signal
|
|
8593
|
+
});
|
|
8594
|
+
}
|
|
8156
8595
|
return chatWithAgent({
|
|
8157
|
-
slug
|
|
8596
|
+
slug,
|
|
8158
8597
|
message,
|
|
8159
8598
|
threadId: threadId2,
|
|
8160
8599
|
environment,
|
|
@@ -8206,12 +8645,22 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8206
8645
|
}
|
|
8207
8646
|
if (!jsonMode)
|
|
8208
8647
|
spinner.succeed("Message sent");
|
|
8648
|
+
const routerResult = result;
|
|
8209
8649
|
if (jsonMode) {
|
|
8210
|
-
|
|
8650
|
+
const output = { message: result.message, threadId: result.threadId, usage: result.usage };
|
|
8651
|
+
if (routerResult.routedToAgent) {
|
|
8652
|
+
output.routedToAgent = routerResult.routedToAgent;
|
|
8653
|
+
output.routedToAgentSlug = routerResult.routedToAgentSlug;
|
|
8654
|
+
}
|
|
8655
|
+
console.log(JSON.stringify(output, null, 2));
|
|
8211
8656
|
} else {
|
|
8212
8657
|
console.log();
|
|
8213
8658
|
console.log("\u2500".repeat(60));
|
|
8214
8659
|
console.log();
|
|
8660
|
+
if (routerResult.routedToAgent) {
|
|
8661
|
+
console.log(chalk23.magenta(`Routed to: ${routerResult.routedToAgent} (${routerResult.routedToAgentSlug})`));
|
|
8662
|
+
console.log();
|
|
8663
|
+
}
|
|
8215
8664
|
console.log(chalk23.green("Agent:"));
|
|
8216
8665
|
console.log(result.message);
|
|
8217
8666
|
console.log();
|
|
@@ -8227,7 +8676,8 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8227
8676
|
}
|
|
8228
8677
|
return;
|
|
8229
8678
|
}
|
|
8230
|
-
|
|
8679
|
+
const headerLabel = isRouterMode ? `router ${chalk23.cyan(slug)}` : chalk23.cyan(slug);
|
|
8680
|
+
console.log(chalk23.bold(`Chat with ${headerLabel} (${environment})`));
|
|
8231
8681
|
console.log(chalk23.dim("Type 'exit' to quit"));
|
|
8232
8682
|
console.log();
|
|
8233
8683
|
let threadId = options.thread;
|
|
@@ -8316,7 +8766,12 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8316
8766
|
}
|
|
8317
8767
|
spinner.stop();
|
|
8318
8768
|
threadId = result.threadId;
|
|
8769
|
+
const interactiveRouterResult = result;
|
|
8319
8770
|
console.log();
|
|
8771
|
+
if (interactiveRouterResult.routedToAgent) {
|
|
8772
|
+
console.log(chalk23.magenta(`Routed to: ${interactiveRouterResult.routedToAgent} (${interactiveRouterResult.routedToAgentSlug})`));
|
|
8773
|
+
console.log();
|
|
8774
|
+
}
|
|
8320
8775
|
console.log(chalk23.green("Agent:"));
|
|
8321
8776
|
console.log(result.message);
|
|
8322
8777
|
console.log();
|
|
@@ -8342,7 +8797,7 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
|
|
|
8342
8797
|
// package.json
|
|
8343
8798
|
var package_default = {
|
|
8344
8799
|
name: "struere",
|
|
8345
|
-
version: "0.12.
|
|
8800
|
+
version: "0.12.2",
|
|
8346
8801
|
description: "Build, test, and deploy AI agents",
|
|
8347
8802
|
keywords: [
|
|
8348
8803
|
"ai",
|