struere 0.12.0 → 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.
@@ -1,68 +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
- 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
+ chatWithAgent: () => chatWithAgent
39
+ });
66
40
  async function refreshToken() {
67
41
  const credentials = loadCredentials();
68
42
  if (!credentials?.sessionId)
@@ -81,6 +55,7 @@ async function refreshToken() {
81
55
  if (!data.token)
82
56
  return null;
83
57
  credentials.token = data.token;
58
+ credentials.expiresAt = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString();
84
59
  saveCredentials(credentials);
85
60
  return data.token;
86
61
  } catch {
@@ -716,8 +691,100 @@ async function getPullState(organizationId, environment = "development") {
716
691
  }
717
692
  return { error: `Unexpected response: ${JSON.stringify(result)}` };
718
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";
719
781
 
720
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";
721
788
  var AUTH_CALLBACK_PORT = 9876;
722
789
  var loginCommand = new Command("login").description("Log in to Struere").action(async () => {
723
790
  const spinner = ora();
@@ -726,10 +793,26 @@ var loginCommand = new Command("login").description("Log in to Struere").action(
726
793
  console.log();
727
794
  const existing = loadCredentials();
728
795
  if (existing) {
729
- console.log(chalk.yellow("Already logged in as"), chalk.cyan(existing.user.email));
730
- console.log(chalk.gray("Run"), chalk.cyan("struere logout"), chalk.gray("to log out first"));
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..."));
731
815
  console.log();
732
- return;
733
816
  }
734
817
  await browserLogin(spinner);
735
818
  });
@@ -812,7 +895,7 @@ async function browserLoginInternal(spinner) {
812
895
  email: user.email,
813
896
  name: user.name || user.email
814
897
  },
815
- expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString()
898
+ expiresAt: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString()
816
899
  };
817
900
  saveCredentials(credentials);
818
901
  spinner.succeed("Logged in successfully");
@@ -1423,6 +1506,9 @@ function scaffoldFixture(cwd, name, slug) {
1423
1506
  return result;
1424
1507
  }
1425
1508
 
1509
+ // src/cli/commands/init.ts
1510
+ init_convex();
1511
+
1426
1512
  // src/cli/utils/plugin.ts
1427
1513
  import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1428
1514
  import { join as join4 } from "path";
@@ -2104,6 +2190,7 @@ var docsCommand = new Command2("docs").description("Generate AI context files (C
2104
2190
  });
2105
2191
 
2106
2192
  // src/cli/utils/runtime.ts
2193
+ init_credentials();
2107
2194
  import ora3 from "ora";
2108
2195
  import chalk3 from "chalk";
2109
2196
  function isInteractive() {
@@ -2174,6 +2261,9 @@ function isOrgAccessError(error) {
2174
2261
  }
2175
2262
 
2176
2263
  // src/cli/commands/org.ts
2264
+ init_credentials();
2265
+ init_convex();
2266
+ init_convex();
2177
2267
  import { Command as Command3 } from "commander";
2178
2268
  import chalk4 from "chalk";
2179
2269
  import ora4 from "ora";
@@ -2475,6 +2565,7 @@ function slugify(name) {
2475
2565
  }
2476
2566
 
2477
2567
  // src/cli/commands/dev.ts
2568
+ init_credentials();
2478
2569
  import { Command as Command6 } from "commander";
2479
2570
  import chalk7 from "chalk";
2480
2571
  import ora6 from "ora";
@@ -2483,9 +2574,11 @@ import { join as join8 } from "path";
2483
2574
  import { existsSync as existsSync8 } from "fs";
2484
2575
 
2485
2576
  // src/cli/commands/sync.ts
2577
+ init_credentials();
2486
2578
  import { Command as Command5 } from "commander";
2487
2579
  import chalk6 from "chalk";
2488
2580
  import { confirm as confirm2 } from "@inquirer/prompts";
2581
+ init_convex();
2489
2582
 
2490
2583
  // src/cli/utils/extractor.ts
2491
2584
  var BUILTIN_TOOLS = [
@@ -3544,10 +3637,12 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
3544
3637
  });
3545
3638
 
3546
3639
  // src/cli/commands/deploy.ts
3640
+ init_credentials();
3547
3641
  import { Command as Command7 } from "commander";
3548
3642
  import chalk8 from "chalk";
3549
3643
  import ora7 from "ora";
3550
3644
  import { confirm as confirm4 } from "@inquirer/prompts";
3645
+ init_convex();
3551
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) => {
3552
3647
  const spinner = ora7();
3553
3648
  const cwd = process.cwd();
@@ -3859,6 +3954,7 @@ var deployCommand = new Command7("deploy").description("Deploy all resources to
3859
3954
  });
3860
3955
 
3861
3956
  // src/cli/commands/logout.ts
3957
+ init_credentials();
3862
3958
  import { Command as Command8 } from "commander";
3863
3959
  import chalk9 from "chalk";
3864
3960
  var logoutCommand = new Command8("logout").description("Log out of Struere").action(async () => {
@@ -3876,6 +3972,8 @@ var logoutCommand = new Command8("logout").description("Log out of Struere").act
3876
3972
  });
3877
3973
 
3878
3974
  // src/cli/commands/whoami.ts
3975
+ init_credentials();
3976
+ init_convex();
3879
3977
  import { Command as Command9 } from "commander";
3880
3978
  import chalk10 from "chalk";
3881
3979
  import ora8 from "ora";
@@ -4084,9 +4182,11 @@ function slugify2(name) {
4084
4182
  }
4085
4183
 
4086
4184
  // src/cli/commands/status.ts
4185
+ init_credentials();
4087
4186
  import { Command as Command11 } from "commander";
4088
4187
  import chalk12 from "chalk";
4089
4188
  import ora9 from "ora";
4189
+ init_convex();
4090
4190
  var statusCommand = new Command11("status").description("Compare local vs remote state").option("--json", "Output raw JSON").action(async (opts) => {
4091
4191
  const spinner = ora9();
4092
4192
  const cwd = process.cwd();
@@ -4290,11 +4390,13 @@ var statusCommand = new Command11("status").description("Compare local vs remote
4290
4390
  });
4291
4391
 
4292
4392
  // src/cli/commands/pull.ts
4393
+ init_credentials();
4293
4394
  import { Command as Command12 } from "commander";
4294
4395
  import chalk13 from "chalk";
4295
4396
  import ora10 from "ora";
4296
4397
  import { existsSync as existsSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
4297
4398
  import { join as join9 } from "path";
4399
+ init_convex();
4298
4400
 
4299
4401
  // src/cli/utils/generator.ts
4300
4402
  var BUILTIN_TOOLS2 = [
@@ -4777,21 +4879,20 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
4777
4879
  });
4778
4880
 
4779
4881
  // src/cli/commands/entities.ts
4882
+ init_credentials();
4780
4883
  import { Command as Command13 } from "commander";
4781
4884
  import chalk15 from "chalk";
4782
4885
  import ora11 from "ora";
4783
4886
  import { input as input2, confirm as confirm5 } from "@inquirer/prompts";
4784
4887
 
4785
4888
  // src/cli/utils/entities.ts
4786
- function getToken() {
4787
- const credentials = loadCredentials();
4788
- const apiKey = getApiKey();
4789
- return apiKey || credentials?.token || null;
4790
- }
4889
+ init_credentials();
4890
+ init_config();
4791
4891
  async function convexQuery(path, args) {
4792
- const token = getToken();
4793
- if (!token)
4794
- return { error: "Not authenticated" };
4892
+ const result = await getValidToken();
4893
+ if ("error" in result)
4894
+ return { error: result.error };
4895
+ const { token } = result;
4795
4896
  const response = await fetch(`${CONVEX_URL}/api/query`, {
4796
4897
  method: "POST",
4797
4898
  headers: {
@@ -4818,9 +4919,10 @@ async function convexQuery(path, args) {
4818
4919
  return { error: `Unexpected response: ${text}` };
4819
4920
  }
4820
4921
  async function convexMutation(path, args) {
4821
- const token = getToken();
4822
- if (!token)
4823
- return { error: "Not authenticated" };
4922
+ const result = await getValidToken();
4923
+ if ("error" in result)
4924
+ return { error: result.error };
4925
+ const { token } = result;
4824
4926
  const response = await fetch(`${CONVEX_URL}/api/mutation`, {
4825
4927
  method: "POST",
4826
4928
  headers: {
@@ -5348,24 +5450,20 @@ entitiesCommand.command("search <type> <query>").description("Search records").o
5348
5450
  });
5349
5451
 
5350
5452
  // src/cli/commands/logs.ts
5453
+ init_credentials();
5351
5454
  import { Command as Command14 } from "commander";
5352
5455
  import chalk16 from "chalk";
5353
5456
  import ora12 from "ora";
5354
5457
 
5355
5458
  // src/cli/utils/logs.ts
5356
- function getToken2() {
5357
- const credentials = loadCredentials();
5358
- const apiKey = getApiKey();
5359
- return apiKey || credentials?.token || null;
5360
- }
5459
+ init_credentials();
5460
+ init_config();
5361
5461
  async function convexQuery2(path, args) {
5362
- let token = getToken2();
5363
- if (!token) {
5364
- token = await refreshToken();
5365
- if (!token)
5366
- return { error: "Not authenticated. Run `struere login`." };
5367
- }
5368
- let response = await fetch(`${CONVEX_URL}/api/query`, {
5462
+ const tokenResult = await getValidToken();
5463
+ if ("error" in tokenResult)
5464
+ return { error: tokenResult.error };
5465
+ const { token } = tokenResult;
5466
+ const response = await fetch(`${CONVEX_URL}/api/query`, {
5369
5467
  method: "POST",
5370
5468
  headers: {
5371
5469
  "Content-Type": "application/json",
@@ -5373,19 +5471,6 @@ async function convexQuery2(path, args) {
5373
5471
  },
5374
5472
  body: JSON.stringify({ path, args })
5375
5473
  });
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
5474
  const text = await response.text();
5390
5475
  let json;
5391
5476
  try {
@@ -5396,21 +5481,12 @@ async function convexQuery2(path, args) {
5396
5481
  if (!response.ok) {
5397
5482
  const errorData = json.errorData;
5398
5483
  const msg = errorData?.message || json.message || json.errorMessage || text;
5399
- const msgStr = String(msg);
5400
- if (msgStr.includes("OIDC") || msgStr.includes("token")) {
5401
- return { error: "Session expired. Run `struere logout && struere login`." };
5402
- }
5403
- return { error: msgStr };
5484
+ return { error: String(msg) };
5404
5485
  }
5405
5486
  if (json.status === "success")
5406
5487
  return { data: json.value };
5407
- if (json.status === "error") {
5408
- const errMsg = String(json.errorMessage || "Unknown error");
5409
- if (errMsg.includes("OIDC") || errMsg.includes("token")) {
5410
- return { error: "Session expired. Run `struere logout && struere login`." };
5411
- }
5412
- return { error: errMsg };
5413
- }
5488
+ if (json.status === "error")
5489
+ return { error: String(json.errorMessage || "Unknown error") };
5414
5490
  return { error: `Unexpected response: ${text}` };
5415
5491
  }
5416
5492
  async function queryThreads(options) {
@@ -5721,14 +5797,18 @@ logsCommand.command("view <thread-id>").description("View conversation messages"
5721
5797
  });
5722
5798
 
5723
5799
  // src/cli/commands/eval.ts
5800
+ init_credentials();
5724
5801
  import { Command as Command15 } from "commander";
5725
5802
  import chalk17 from "chalk";
5726
5803
  import ora13 from "ora";
5727
5804
  import { join as join10 } from "path";
5728
5805
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
5806
+ init_convex();
5729
5807
 
5730
5808
  // src/cli/utils/evals.ts
5731
- function getToken3() {
5809
+ init_credentials();
5810
+ init_config();
5811
+ function getToken() {
5732
5812
  const credentials = loadCredentials();
5733
5813
  const apiKey = getApiKey();
5734
5814
  const token = apiKey || credentials?.token;
@@ -5737,7 +5817,7 @@ function getToken3() {
5737
5817
  return token;
5738
5818
  }
5739
5819
  async function convexQuery3(path, args) {
5740
- const token = getToken3();
5820
+ const token = getToken();
5741
5821
  const response = await fetch(`${CONVEX_URL}/api/query`, {
5742
5822
  method: "POST",
5743
5823
  headers: {
@@ -5762,7 +5842,7 @@ async function convexQuery3(path, args) {
5762
5842
  return json.value;
5763
5843
  }
5764
5844
  async function convexMutation2(path, args) {
5765
- const token = getToken3();
5845
+ const token = getToken();
5766
5846
  const response = await fetch(`${CONVEX_URL}/api/mutation`, {
5767
5847
  method: "POST",
5768
5848
  headers: {
@@ -6178,13 +6258,16 @@ var evalCommand = new Command15("eval").description("Eval suite management");
6178
6258
  evalCommand.addCommand(runCommand);
6179
6259
 
6180
6260
  // src/cli/commands/templates.ts
6261
+ init_credentials();
6181
6262
  import { Command as Command16 } from "commander";
6182
6263
  import chalk18 from "chalk";
6183
6264
  import { readFileSync as readFileSync5 } from "fs";
6184
6265
  import { confirm as confirm6 } from "@inquirer/prompts";
6185
6266
 
6186
6267
  // src/cli/utils/whatsapp.ts
6187
- function getToken4() {
6268
+ init_credentials();
6269
+ init_config();
6270
+ function getToken2() {
6188
6271
  const credentials = loadCredentials();
6189
6272
  const apiKey = getApiKey();
6190
6273
  return apiKey || credentials?.token || null;
@@ -6223,7 +6306,7 @@ async function httpPost(path, body) {
6223
6306
  }
6224
6307
  }
6225
6308
  async function convexAction(path, args) {
6226
- const token = getToken4();
6309
+ const token = getToken2();
6227
6310
  if (!token)
6228
6311
  return { error: "Not authenticated" };
6229
6312
  const response = await fetch(`${CONVEX_URL}/api/action`, {
@@ -6252,7 +6335,7 @@ async function convexAction(path, args) {
6252
6335
  return { error: `Unexpected response: ${text}` };
6253
6336
  }
6254
6337
  async function convexQuery4(path, args) {
6255
- const token = getToken4();
6338
+ const token = getToken2();
6256
6339
  if (!token)
6257
6340
  return { error: "Not authenticated" };
6258
6341
  const response = await fetch(`${CONVEX_URL}/api/query`, {
@@ -6335,6 +6418,16 @@ async function getTemplateStatus(connectionId, name) {
6335
6418
  name
6336
6419
  });
6337
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
+ }
6338
6431
 
6339
6432
  // src/cli/commands/templates.ts
6340
6433
  async function ensureAuth3() {
@@ -6427,9 +6520,9 @@ function statusColor2(status) {
6427
6520
  }
6428
6521
  }
6429
6522
  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) => {
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) => {
6431
6524
  await ensureAuth3();
6432
- const connectionId = await resolveConnectionId("development", opts.connection);
6525
+ const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
6433
6526
  const out = createOutput();
6434
6527
  out.start("Fetching templates");
6435
6528
  const { data, error } = await listTemplates(connectionId);
@@ -6464,9 +6557,9 @@ templatesCommand.command("list").description("List all message templates").optio
6464
6557
  })));
6465
6558
  console.log();
6466
6559
  });
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) => {
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) => {
6468
6561
  await ensureAuth3();
6469
- const connectionId = await resolveConnectionId("development", opts.connection);
6562
+ const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
6470
6563
  let components;
6471
6564
  if (opts.file) {
6472
6565
  try {
@@ -6512,9 +6605,9 @@ templatesCommand.command("create <name>").description("Create a new message temp
6512
6605
  console.log();
6513
6606
  }
6514
6607
  });
6515
- 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) => {
6516
6609
  await ensureAuth3();
6517
- const connectionId = await resolveConnectionId("development", opts.connection);
6610
+ const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
6518
6611
  if (!opts.yes && isInteractive()) {
6519
6612
  const confirmed = await confirm6({
6520
6613
  message: `Delete template "${name}"? This cannot be undone.`,
@@ -6536,9 +6629,9 @@ templatesCommand.command("delete <name>").description("Delete a message template
6536
6629
  out.succeed(`Template "${name}" deleted`);
6537
6630
  console.log();
6538
6631
  });
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) => {
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) => {
6540
6633
  await ensureAuth3();
6541
- const connectionId = await resolveConnectionId("development", opts.connection);
6634
+ const connectionId = await resolveConnectionId(opts.env ?? "production", opts.connection);
6542
6635
  const out = createOutput();
6543
6636
  out.start(`Checking status for "${name}"`);
6544
6637
  const { data, error } = await getTemplateStatus(connectionId, name);
@@ -6564,6 +6657,8 @@ templatesCommand.command("status <name>").description("Check template approval s
6564
6657
  console.log(` ${chalk18.gray("Status:")} ${statusColor2(String(t.status ?? ""))}`);
6565
6658
  console.log(` ${chalk18.gray("Category:")} ${t.category}`);
6566
6659
  console.log(` ${chalk18.gray("Language:")} ${t.language}`);
6660
+ if (t.id)
6661
+ console.log(` ${chalk18.gray("ID:")} ${t.id}`);
6567
6662
  if (t.components) {
6568
6663
  console.log(` ${chalk18.gray("Components:")} ${JSON.stringify(t.components, null, 2).split(`
6569
6664
  `).join(`
@@ -6572,22 +6667,105 @@ templatesCommand.command("status <name>").description("Check template approval s
6572
6667
  console.log();
6573
6668
  }
6574
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
+ });
6575
6754
 
6576
6755
  // src/cli/commands/integration.ts
6756
+ init_credentials();
6577
6757
  import { Command as Command17 } from "commander";
6578
6758
  import chalk19 from "chalk";
6579
6759
  import { confirm as confirm7 } from "@inquirer/prompts";
6580
6760
 
6581
6761
  // src/cli/utils/integrations.ts
6582
- function getToken5() {
6583
- const credentials = loadCredentials();
6584
- const apiKey = getApiKey();
6585
- return apiKey || credentials?.token || null;
6586
- }
6762
+ init_credentials();
6763
+ init_config();
6587
6764
  async function convexQuery5(path, args) {
6588
- const token = getToken5();
6589
- if (!token)
6590
- return { error: "Not authenticated" };
6765
+ const result = await getValidToken();
6766
+ if ("error" in result)
6767
+ return { error: result.error };
6768
+ const { token } = result;
6591
6769
  const response = await fetch(`${CONVEX_URL}/api/query`, {
6592
6770
  method: "POST",
6593
6771
  headers: {
@@ -6614,9 +6792,10 @@ async function convexQuery5(path, args) {
6614
6792
  return { error: `Unexpected response: ${text}` };
6615
6793
  }
6616
6794
  async function convexMutation3(path, args) {
6617
- const token = getToken5();
6618
- if (!token)
6619
- return { error: "Not authenticated" };
6795
+ const result = await getValidToken();
6796
+ if ("error" in result)
6797
+ return { error: result.error };
6798
+ const { token } = result;
6620
6799
  const response = await fetch(`${CONVEX_URL}/api/mutation`, {
6621
6800
  method: "POST",
6622
6801
  headers: {
@@ -6643,9 +6822,10 @@ async function convexMutation3(path, args) {
6643
6822
  return { error: `Unexpected response: ${text}` };
6644
6823
  }
6645
6824
  async function convexAction2(path, args) {
6646
- const token = getToken5();
6647
- if (!token)
6648
- return { error: "Not authenticated" };
6825
+ const result = await getValidToken();
6826
+ if ("error" in result)
6827
+ return { error: result.error };
6828
+ const { token } = result;
6649
6829
  const response = await fetch(`${CONVEX_URL}/api/action`, {
6650
6830
  method: "POST",
6651
6831
  headers: {
@@ -6966,12 +7146,15 @@ var integrationCommand = new Command17("integration").description("Manage integr
6966
7146
  });
6967
7147
 
6968
7148
  // src/cli/commands/triggers.ts
7149
+ init_credentials();
6969
7150
  import { Command as Command18 } from "commander";
6970
7151
  import chalk20 from "chalk";
6971
7152
  import ora14 from "ora";
6972
7153
 
6973
7154
  // src/cli/utils/triggers.ts
6974
- function getToken6() {
7155
+ init_credentials();
7156
+ init_config();
7157
+ function getToken3() {
6975
7158
  const credentials = loadCredentials();
6976
7159
  const apiKey = getApiKey();
6977
7160
  const token = apiKey || credentials?.token;
@@ -6980,7 +7163,7 @@ function getToken6() {
6980
7163
  return token;
6981
7164
  }
6982
7165
  async function convexQuery6(path, args) {
6983
- const token = getToken6();
7166
+ const token = getToken3();
6984
7167
  const response = await fetch(`${CONVEX_URL}/api/query`, {
6985
7168
  method: "POST",
6986
7169
  headers: {
@@ -7005,7 +7188,7 @@ async function convexQuery6(path, args) {
7005
7188
  return json.value;
7006
7189
  }
7007
7190
  async function convexMutation4(path, args) {
7008
- const token = getToken6();
7191
+ const token = getToken3();
7009
7192
  const response = await fetch(`${CONVEX_URL}/api/mutation`, {
7010
7193
  method: "POST",
7011
7194
  headers: {
@@ -7076,7 +7259,7 @@ async function getTriggerExecutionDetail(eventId) {
7076
7259
  return convexQuery6("triggers:getExecutionDetail", { eventId });
7077
7260
  }
7078
7261
  async function convexAction3(path, args) {
7079
- const token = getToken6();
7262
+ const token = getToken3();
7080
7263
  const response = await fetch(`${CONVEX_URL}/api/action`, {
7081
7264
  method: "POST",
7082
7265
  headers: {
@@ -7785,9 +7968,11 @@ triggersCommand.command("retry-event <event-id>").description("Retry a failed im
7785
7968
  });
7786
7969
 
7787
7970
  // src/cli/commands/compile-prompt.ts
7971
+ init_credentials();
7788
7972
  import { Command as Command19 } from "commander";
7789
7973
  import chalk21 from "chalk";
7790
7974
  import ora15 from "ora";
7975
+ init_convex();
7791
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) => {
7792
7977
  acc.push(val);
7793
7978
  return acc;
@@ -7933,9 +8118,11 @@ var compilePromptCommand = new Command19("compile-prompt").description("Compile
7933
8118
  });
7934
8119
 
7935
8120
  // src/cli/commands/run-tool.ts
8121
+ init_credentials();
7936
8122
  import { Command as Command20 } from "commander";
7937
8123
  import chalk22 from "chalk";
7938
8124
  import ora16 from "ora";
8125
+ init_convex();
7939
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) => {
7940
8127
  const spinner = ora16();
7941
8128
  const cwd = process.cwd();
@@ -8088,10 +8275,12 @@ var runToolCommand = new Command20("run-tool").description("Run a tool as it wou
8088
8275
  });
8089
8276
 
8090
8277
  // src/cli/commands/chat.ts
8278
+ init_credentials();
8091
8279
  import { Command as Command21 } from "commander";
8092
8280
  import chalk23 from "chalk";
8093
8281
  import ora17 from "ora";
8094
8282
  import readline from "readline";
8283
+ init_convex();
8095
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) => {
8096
8285
  const spinner = ora17();
8097
8286
  const cwd = process.cwd();
@@ -8342,7 +8531,7 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
8342
8531
  // package.json
8343
8532
  var package_default = {
8344
8533
  name: "struere",
8345
- version: "0.12.0",
8534
+ version: "0.12.1",
8346
8535
  description: "Build, test, and deploy AI agents",
8347
8536
  keywords: [
8348
8537
  "ai",