struere 0.12.1 → 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.
@@ -35,6 +35,7 @@ __export(exports_convex, {
35
35
  getPullState: () => getPullState,
36
36
  createOrganization: () => createOrganization,
37
37
  compilePrompt: () => compilePrompt,
38
+ chatWithRouter: () => chatWithRouter,
38
39
  chatWithAgent: () => chatWithAgent
39
40
  });
40
41
  async function refreshToken() {
@@ -184,6 +185,7 @@ async function syncViaHttp(apiKey, payload) {
184
185
  roles: payload.roles,
185
186
  evalSuites: payload.evalSuites,
186
187
  triggers: payload.triggers,
188
+ routers: payload.routers,
187
189
  fixtures: payload.fixtures
188
190
  }),
189
191
  signal: AbortSignal.timeout(30000)
@@ -635,6 +637,65 @@ async function chatWithAgent(options) {
635
637
  return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
636
638
  }
637
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
+ }
638
699
  async function getPullState(organizationId, environment = "development") {
639
700
  const credentials = loadCredentials();
640
701
  const apiKey = getApiKey();
@@ -1343,6 +1404,26 @@ export default defineTrigger({
1343
1404
  })
1344
1405
  `;
1345
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
+ }
1346
1427
 
1347
1428
  // src/cli/utils/scaffold.ts
1348
1429
  function ensureDir(filePath) {
@@ -1368,6 +1449,7 @@ function scaffoldProject(cwd, options) {
1368
1449
  "tools",
1369
1450
  "evals",
1370
1451
  "triggers",
1452
+ "routers",
1371
1453
  "fixtures",
1372
1454
  ".struere"
1373
1455
  ];
@@ -1487,6 +1569,24 @@ function scaffoldTrigger(cwd, name, slug) {
1487
1569
  result.createdFiles.push(`triggers/${fileName}`);
1488
1570
  return result;
1489
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
+ }
1490
1590
  function scaffoldFixture(cwd, name, slug) {
1491
1591
  const result = {
1492
1592
  createdFiles: [],
@@ -1916,9 +2016,10 @@ async function loadAllResources(cwd) {
1916
2016
  const { suites: evalSuites, errors: evalErrors } = loadEvalSuites(join5(cwd, "evals"));
1917
2017
  errors.push(...evalErrors);
1918
2018
  const triggers = await loadTsDirectory(join5(cwd, "triggers"));
2019
+ const routers = await loadTsDirectory(join5(cwd, "routers"));
1919
2020
  const { fixtures, errors: fixtureErrors } = loadFixtures(join5(cwd, "fixtures"));
1920
2021
  errors.push(...fixtureErrors);
1921
- return { agents, entityTypes, roles, customTools, evalSuites, triggers, fixtures, errors };
2022
+ return { agents, entityTypes, roles, customTools, evalSuites, triggers, routers, fixtures, errors };
1922
2023
  }
1923
2024
  async function loadTsDirectory(dir) {
1924
2025
  if (!existsSync5(dir)) {
@@ -2005,6 +2106,7 @@ function getResourceDirectories(cwd) {
2005
2106
  tools: join5(cwd, "tools"),
2006
2107
  evals: join5(cwd, "evals"),
2007
2108
  triggers: join5(cwd, "triggers"),
2109
+ routers: join5(cwd, "routers"),
2008
2110
  fixtures: join5(cwd, "fixtures")
2009
2111
  };
2010
2112
  }
@@ -2143,6 +2245,7 @@ async function generateDocs(cwd, targets) {
2143
2245
  customTools: [],
2144
2246
  evalSuites: [],
2145
2247
  triggers: [],
2248
+ routers: [],
2146
2249
  fixtures: [],
2147
2250
  errors: []
2148
2251
  });
@@ -2687,6 +2790,29 @@ function extractSyncPayload(resources) {
2687
2790
  schedule: t.schedule,
2688
2791
  retry: t.retry
2689
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;
2690
2816
  const fixtures = resources.fixtures.length > 0 ? resources.fixtures.map((f) => ({
2691
2817
  name: f.name,
2692
2818
  slug: f.slug,
@@ -2703,7 +2829,7 @@ function extractSyncPayload(resources) {
2703
2829
  metadata: r.metadata
2704
2830
  }))
2705
2831
  })) : undefined;
2706
- return { agents, entityTypes, roles, evalSuites, triggers, fixtures };
2832
+ return { agents, entityTypes, roles, evalSuites, triggers, routers, fixtures };
2707
2833
  }
2708
2834
  function extractAgentPayload(agent, customToolsMap) {
2709
2835
  let systemPrompt;
@@ -3132,6 +3258,7 @@ ${resources.errors.join(`
3132
3258
  entityTypes: payload.entityTypes,
3133
3259
  roles: payload.roles,
3134
3260
  triggers: payload.triggers,
3261
+ routers: payload.routers,
3135
3262
  organizationId,
3136
3263
  environment: "development"
3137
3264
  });
@@ -3165,7 +3292,8 @@ async function checkForDeletions(resources, organizationId, environment) {
3165
3292
  entityTypes: new Set(payload.entityTypes.map((et) => et.slug)),
3166
3293
  roles: new Set(payload.roles.map((r) => r.name)),
3167
3294
  evalSuites: new Set((payload.evalSuites || []).map((es) => es.slug)),
3168
- 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))
3169
3297
  };
3170
3298
  const deletions = [];
3171
3299
  const deletedAgents = remoteState.agents.filter((a) => !localSlugs.agents.has(a.slug)).map((a) => a.name);
@@ -3185,6 +3313,10 @@ async function checkForDeletions(resources, organizationId, environment) {
3185
3313
  const deletedTriggers = remoteTriggers.filter((t) => !localSlugs.triggers.has(t.slug)).map((t) => t.name);
3186
3314
  if (deletedTriggers.length > 0)
3187
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 });
3188
3320
  return deletions;
3189
3321
  }
3190
3322
  async function syncToEnvironment(cwd, organizationId, environment) {
@@ -3304,6 +3436,7 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
3304
3436
  entityTypes: payload.entityTypes.map((et) => et.slug),
3305
3437
  roles: payload.roles.map((r) => r.name),
3306
3438
  triggers: (payload.triggers || []).map((t) => t.slug),
3439
+ routers: (payload.routers || []).map((r) => r.slug),
3307
3440
  deletions: deletions.map((d) => ({ type: d.type, names: d.deleted }))
3308
3441
  }));
3309
3442
  } else {
@@ -3313,6 +3446,7 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
3313
3446
  console.log(chalk6.gray(" Data types:"), payload.entityTypes.map((et) => et.slug).join(", ") || "none");
3314
3447
  console.log(chalk6.gray(" Roles:"), payload.roles.map((r) => r.name).join(", ") || "none");
3315
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");
3316
3450
  if (deletions.length > 0) {
3317
3451
  console.log();
3318
3452
  console.log(chalk6.yellow.bold(" Would delete:"));
@@ -3477,7 +3611,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
3477
3611
  spinner.start("Loading resources");
3478
3612
  try {
3479
3613
  loadedResources = await loadAllResources(cwd);
3480
- 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`);
3481
3615
  for (const err of loadedResources.errors) {
3482
3616
  console.log(chalk7.red(" \u2716"), err);
3483
3617
  }
@@ -3572,6 +3706,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
3572
3706
  dirs.tools,
3573
3707
  dirs.evals,
3574
3708
  dirs.triggers,
3709
+ dirs.routers,
3575
3710
  dirs.fixtures
3576
3711
  ].filter((p) => existsSync8(p));
3577
3712
  const watcher = chokidar.watch(watchPaths, {
@@ -4069,7 +4204,7 @@ var whoamiCommand = new Command9("whoami").description("Show current logged in u
4069
4204
  // src/cli/commands/add.ts
4070
4205
  import { Command as Command10 } from "commander";
4071
4206
  import chalk11 from "chalk";
4072
- 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) => {
4073
4208
  const cwd = process.cwd();
4074
4209
  console.log();
4075
4210
  if (!hasProject(cwd)) {
@@ -4147,6 +4282,17 @@ var addCommand = new Command10("add").description("Scaffold a new resource").arg
4147
4282
  console.log(chalk11.yellow("Trigger already exists:"), `triggers/${slug}.ts`);
4148
4283
  }
4149
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;
4150
4296
  case "fixture":
4151
4297
  result = scaffoldFixture(cwd, displayName, slug);
4152
4298
  if (result.createdFiles.length > 0) {
@@ -4169,6 +4315,7 @@ var addCommand = new Command10("add").description("Scaffold a new resource").arg
4169
4315
  console.log(chalk11.gray(" -"), chalk11.cyan("role"), "- Create a role with permissions");
4170
4316
  console.log(chalk11.gray(" -"), chalk11.cyan("eval"), "- Create an eval suite (YAML)");
4171
4317
  console.log(chalk11.gray(" -"), chalk11.cyan("trigger"), "- Create a data trigger");
4318
+ console.log(chalk11.gray(" -"), chalk11.cyan("router"), "- Create a message router");
4172
4319
  console.log(chalk11.gray(" -"), chalk11.cyan("fixture"), "- Create a test data fixture (YAML)");
4173
4320
  console.log();
4174
4321
  process.exit(1);
@@ -4298,6 +4445,8 @@ var statusCommand = new Command11("status").description("Compare local vs remote
4298
4445
  const devEntityTypeSlugs = new Set(devState.entityTypes.map((et) => et.slug));
4299
4446
  const localRoleNames = new Set(localResources.roles.map((r) => r.name));
4300
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));
4301
4450
  if (opts.json) {
4302
4451
  const classify = (localItems, remoteItems, useSlug) => {
4303
4452
  const localKeys = new Set(localItems.map((i) => useSlug ? i.slug : i.name));
@@ -4311,7 +4460,8 @@ var statusCommand = new Command11("status").description("Compare local vs remote
4311
4460
  console.log(JSON.stringify({
4312
4461
  agents: classify(localResources.agents, devState.agents, true),
4313
4462
  entityTypes: classify(localResources.entityTypes, devState.entityTypes, true),
4314
- roles: classify(localResources.roles, devState.roles, false)
4463
+ roles: classify(localResources.roles, devState.roles, false),
4464
+ routers: classify(localResources.routers, devState.routers || [], true)
4315
4465
  }));
4316
4466
  return;
4317
4467
  }
@@ -4381,6 +4531,26 @@ var statusCommand = new Command11("status").description("Compare local vs remote
4381
4531
  }
4382
4532
  }
4383
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();
4384
4554
  console.log(chalk12.gray("Legend:"));
4385
4555
  console.log(chalk12.gray(" "), chalk12.green("\u25CF"), "Synced", chalk12.yellow("\u25CB"), "Not in production", chalk12.blue("+"), "New", chalk12.red("-"), "Will be deleted");
4386
4556
  console.log();
@@ -4655,6 +4825,53 @@ ${parts.join(`,
4655
4825
  })
4656
4826
  `;
4657
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
+ }
4658
4875
  function generateIndexFile(type, slugs) {
4659
4876
  if (slugs.length === 0) {
4660
4877
  return "";
@@ -4789,6 +5006,7 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
4789
5006
  ensureDir2(join9(cwd, "entity-types"));
4790
5007
  ensureDir2(join9(cwd, "roles"));
4791
5008
  ensureDir2(join9(cwd, "triggers"));
5009
+ ensureDir2(join9(cwd, "routers"));
4792
5010
  ensureDir2(join9(cwd, "tools"));
4793
5011
  const agentSlugs = [];
4794
5012
  for (const agent of state.agents) {
@@ -4816,6 +5034,12 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
4816
5034
  const content = generateTriggerFile(trigger);
4817
5035
  writeOrSkip(`triggers/${trigger.slug}.ts`, content);
4818
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
+ }
4819
5043
  const customTools = collectCustomTools(state.agents);
4820
5044
  if (customTools.length > 0) {
4821
5045
  const content = generateToolsFile(customTools);
@@ -4841,6 +5065,11 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
4841
5065
  if (content)
4842
5066
  writeOrSkip("triggers/index.ts", content);
4843
5067
  }
5068
+ if (routerSlugs.length > 0) {
5069
+ const content = generateIndexFile("routers", routerSlugs);
5070
+ if (content)
5071
+ writeOrSkip("routers/index.ts", content);
5072
+ }
4844
5073
  await installSkill(cwd);
4845
5074
  if (options.json) {
4846
5075
  console.log(JSON.stringify({
@@ -8281,7 +8510,7 @@ import chalk23 from "chalk";
8281
8510
  import ora17 from "ora";
8282
8511
  import readline from "readline";
8283
8512
  init_convex();
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) => {
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) => {
8285
8514
  const spinner = ora17();
8286
8515
  const cwd = process.cwd();
8287
8516
  const nonInteractive = !isInteractive();
@@ -8333,6 +8562,15 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
8333
8562
  console.log();
8334
8563
  }
8335
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
+ }
8336
8574
  if (environment === "production" && !nonInteractive && !options.confirm) {
8337
8575
  const confirmRl = readline.createInterface({ input: process.stdin, output: process.stdout });
8338
8576
  await new Promise((resolve) => {
@@ -8342,8 +8580,20 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
8342
8580
  confirmRl.close();
8343
8581
  }
8344
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
+ }
8345
8595
  return chatWithAgent({
8346
- slug: agentSlug,
8596
+ slug,
8347
8597
  message,
8348
8598
  threadId: threadId2,
8349
8599
  environment,
@@ -8395,12 +8645,22 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
8395
8645
  }
8396
8646
  if (!jsonMode)
8397
8647
  spinner.succeed("Message sent");
8648
+ const routerResult = result;
8398
8649
  if (jsonMode) {
8399
- console.log(JSON.stringify({ message: result.message, threadId: result.threadId, usage: result.usage }, null, 2));
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));
8400
8656
  } else {
8401
8657
  console.log();
8402
8658
  console.log("\u2500".repeat(60));
8403
8659
  console.log();
8660
+ if (routerResult.routedToAgent) {
8661
+ console.log(chalk23.magenta(`Routed to: ${routerResult.routedToAgent} (${routerResult.routedToAgentSlug})`));
8662
+ console.log();
8663
+ }
8404
8664
  console.log(chalk23.green("Agent:"));
8405
8665
  console.log(result.message);
8406
8666
  console.log();
@@ -8416,7 +8676,8 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
8416
8676
  }
8417
8677
  return;
8418
8678
  }
8419
- console.log(chalk23.bold(`Chat with ${chalk23.cyan(agentSlug)} (${environment})`));
8679
+ const headerLabel = isRouterMode ? `router ${chalk23.cyan(slug)}` : chalk23.cyan(slug);
8680
+ console.log(chalk23.bold(`Chat with ${headerLabel} (${environment})`));
8420
8681
  console.log(chalk23.dim("Type 'exit' to quit"));
8421
8682
  console.log();
8422
8683
  let threadId = options.thread;
@@ -8505,7 +8766,12 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
8505
8766
  }
8506
8767
  spinner.stop();
8507
8768
  threadId = result.threadId;
8769
+ const interactiveRouterResult = result;
8508
8770
  console.log();
8771
+ if (interactiveRouterResult.routedToAgent) {
8772
+ console.log(chalk23.magenta(`Routed to: ${interactiveRouterResult.routedToAgent} (${interactiveRouterResult.routedToAgentSlug})`));
8773
+ console.log();
8774
+ }
8509
8775
  console.log(chalk23.green("Agent:"));
8510
8776
  console.log(result.message);
8511
8777
  console.log();
@@ -8531,7 +8797,7 @@ var chatCommand = new Command21("chat").description("Chat with an agent").argume
8531
8797
  // package.json
8532
8798
  var package_default = {
8533
8799
  name: "struere",
8534
- version: "0.12.1",
8800
+ version: "0.12.2",
8535
8801
  description: "Build, test, and deploy AI agents",
8536
8802
  keywords: [
8537
8803
  "ai",
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,eAAO,MAAM,UAAU,SA8HnB,CAAA"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,eAAO,MAAM,UAAU,SA2InB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,WAAW,SAyRpB,CAAA"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,WAAW,SAmUpB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAiBnC,eAAO,MAAM,UAAU,SA0PnB,CAAA"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAiBnC,eAAO,MAAM,UAAU,SA2PnB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAsBnC,eAAO,MAAM,WAAW,SA6NpB,CAAA"}
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAuBnC,eAAO,MAAM,WAAW,SA0OpB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,aAAa,SAqOtB,CAAA"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,aAAa,SAgQtB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKnC,OAAO,EAAkC,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AACnG,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAMxE,KAAK,WAAW,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;AAE7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAuC7F;AAED,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,eAAe,EAC1B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,eAAe,EAAE,CAAC,CAiC5B;AAwCD,eAAO,MAAM,WAAW,SAyMpB,CAAA"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKnC,OAAO,EAAkC,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AACnG,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAMxE,KAAK,WAAW,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;AAE7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAwC7F;AAED,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,eAAe,EAC1B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,eAAe,EAAE,CAAC,CAsC5B;AAwCD,eAAO,MAAM,WAAW,SA2MpB,CAAA"}