struere 0.11.3 → 0.12.1

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