@automagik/omni 2.260422.4 → 2.260422.5

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 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkJpC,wBAAgB,mBAAmB,IAAI,OAAO,CAwK7C"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmJpC,wBAAgB,mBAAmB,IAAI,OAAO,CA2K7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"follow-up.d.ts","sourceRoot":"","sources":["../../src/commands/follow-up.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BpC,wBAAgB,qBAAqB,IAAI,OAAO,CAgE/C"}
1
+ {"version":3,"file":"follow-up.d.ts","sourceRoot":"","sources":["../../src/commands/follow-up.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCpC,wBAAgB,qBAAqB,IAAI,OAAO,CAmE/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"instances.d.ts","sourceRoot":"","sources":["../../src/commands/instances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0KpC,wBAAgB,sBAAsB,IAAI,OAAO,CAopChD"}
1
+ {"version":3,"file":"instances.d.ts","sourceRoot":"","sources":["../../src/commands/instances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0KpC,wBAAgB,sBAAsB,IAAI,OAAO,CA0pChD"}
@@ -6,7 +6,7 @@
6
6
  * omni providers create --name <name> --schema <schema> --base-url <url> [--api-key <key>]
7
7
  * Claude Code: --project-path <path> [--max-turns <n>] [--permission-mode <mode>]
8
8
  * OpenClaw: --default-agent-id <id>
9
- * Genie: --agent-name <name> --target-agent <name> [--team-name <template>]
9
+ * nats-genie: --agent-name <name> --target-agent <name> [--team-name <template>]
10
10
  * omni providers update <id> [--name <name>] [--base-url <url>] [--api-key <key>] [--schema-config <json>]
11
11
  * omni providers setup openclaw --gateway-url <url> --gateway-token <token> --agent-id <id>
12
12
  * omni providers agents <id>
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/commands/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4TpC,wBAAgB,sBAAsB,IAAI,OAAO,CA0JhD"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/commands/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiUpC,wBAAgB,sBAAsB,IAAI,OAAO,CA6JhD"}
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/commands/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,qBAAqB,IAAI,OAAO,CAgL/C"}
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/commands/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,qBAAqB,IAAI,OAAO,CAmL/C"}
package/dist/index.js CHANGED
@@ -113804,7 +113804,7 @@ import { fileURLToPath } from "url";
113804
113804
  // package.json
113805
113805
  var package_default = {
113806
113806
  name: "@automagik/omni",
113807
- version: "2.260422.4",
113807
+ version: "2.260422.5",
113808
113808
  description: "LLM-optimized CLI for Omni",
113809
113809
  type: "module",
113810
113810
  bin: {
@@ -114343,6 +114343,99 @@ ${ids}`);
114343
114343
  }
114344
114344
  error(`No batch job found matching "${input}"`);
114345
114345
  }
114346
+ async function resolveProviderId(input) {
114347
+ if (UUID_RE.test(input))
114348
+ return input;
114349
+ const client = getClient();
114350
+ const providers = await client.providers.list({});
114351
+ if (/^[0-9a-f]{2,}$/i.test(input)) {
114352
+ const matches = providers.filter((p) => p.id.toLowerCase().startsWith(input.toLowerCase()));
114353
+ if (matches.length === 1)
114354
+ return matches[0].id;
114355
+ if (matches.length > 1) {
114356
+ const names = matches.map((p) => ` ${p.id.slice(0, 8)} ${p.name}`).join(`
114357
+ `);
114358
+ error(`Ambiguous ID prefix "${input}" matches ${matches.length} providers:
114359
+ ${names}`);
114360
+ }
114361
+ }
114362
+ const lower = input.toLowerCase();
114363
+ const exactName = providers.find((p) => p.name.toLowerCase() === lower);
114364
+ if (exactName)
114365
+ return exactName.id;
114366
+ const nameMatches = providers.filter((p) => p.name.toLowerCase().includes(lower));
114367
+ if (nameMatches.length === 1)
114368
+ return nameMatches[0].id;
114369
+ if (nameMatches.length > 1) {
114370
+ const names = nameMatches.map((p) => ` ${p.id.slice(0, 8)} ${p.name}`).join(`
114371
+ `);
114372
+ error(`Ambiguous name "${input}" matches ${nameMatches.length} providers:
114373
+ ${names}`);
114374
+ }
114375
+ error(`No provider found matching "${input}"`);
114376
+ }
114377
+ async function resolveAgentId(input) {
114378
+ if (UUID_RE.test(input))
114379
+ return input;
114380
+ const client = getClient();
114381
+ const { items: agents } = await client.agents.list({});
114382
+ if (/^[0-9a-f]{2,}$/i.test(input)) {
114383
+ const matches = agents.filter((a) => a.id.toLowerCase().startsWith(input.toLowerCase()));
114384
+ if (matches.length === 1)
114385
+ return matches[0].id;
114386
+ if (matches.length > 1) {
114387
+ const names = matches.map((a) => ` ${a.id.slice(0, 8)} ${a.name}`).join(`
114388
+ `);
114389
+ error(`Ambiguous ID prefix "${input}" matches ${matches.length} agents:
114390
+ ${names}`);
114391
+ }
114392
+ }
114393
+ const lower = input.toLowerCase();
114394
+ const exactName = agents.find((a) => a.name.toLowerCase() === lower);
114395
+ if (exactName)
114396
+ return exactName.id;
114397
+ const nameMatches = agents.filter((a) => a.name.toLowerCase().includes(lower));
114398
+ if (nameMatches.length === 1)
114399
+ return nameMatches[0].id;
114400
+ if (nameMatches.length > 1) {
114401
+ const names = nameMatches.map((a) => ` ${a.id.slice(0, 8)} ${a.name}`).join(`
114402
+ `);
114403
+ error(`Ambiguous name "${input}" matches ${nameMatches.length} agents:
114404
+ ${names}`);
114405
+ }
114406
+ error(`No agent found matching "${input}"`);
114407
+ }
114408
+ async function resolveWebhookId(input) {
114409
+ if (UUID_RE.test(input))
114410
+ return input;
114411
+ const client = getClient();
114412
+ const sources = await client.webhooks.listSources({});
114413
+ if (/^[0-9a-f]{2,}$/i.test(input)) {
114414
+ const matches = sources.filter((w) => w.id.toLowerCase().startsWith(input.toLowerCase()));
114415
+ if (matches.length === 1)
114416
+ return matches[0].id;
114417
+ if (matches.length > 1) {
114418
+ const names = matches.map((w) => ` ${w.id.slice(0, 8)} ${w.name}`).join(`
114419
+ `);
114420
+ error(`Ambiguous ID prefix "${input}" matches ${matches.length} webhook sources:
114421
+ ${names}`);
114422
+ }
114423
+ }
114424
+ const lower = input.toLowerCase();
114425
+ const exactName = sources.find((w) => w.name.toLowerCase() === lower);
114426
+ if (exactName)
114427
+ return exactName.id;
114428
+ const nameMatches = sources.filter((w) => w.name.toLowerCase().includes(lower));
114429
+ if (nameMatches.length === 1)
114430
+ return nameMatches[0].id;
114431
+ if (nameMatches.length > 1) {
114432
+ const names = nameMatches.map((w) => ` ${w.id.slice(0, 8)} ${w.name}`).join(`
114433
+ `);
114434
+ error(`Ambiguous name "${input}" matches ${nameMatches.length} webhook sources:
114435
+ ${names}`);
114436
+ }
114437
+ error(`No webhook source found matching "${input}"`);
114438
+ }
114346
114439
  async function resolveRouteId(instanceId, input) {
114347
114440
  if (UUID_RE.test(input))
114348
114441
  return input;
@@ -114678,9 +114771,10 @@ function createAgentsCommand() {
114678
114771
  }
114679
114772
  });
114680
114773
  agents.command("get <id>").description("Get agent details").action(async (id) => {
114774
+ const resolvedId = await resolveAgentId(id);
114681
114775
  const client = getClient();
114682
114776
  try {
114683
- const agent = await client.agents.get(id);
114777
+ const agent = await client.agents.get(resolvedId);
114684
114778
  data(agent);
114685
114779
  } catch (err) {
114686
114780
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -114703,10 +114797,11 @@ function createAgentsCommand() {
114703
114797
  if (options.configPath !== undefined)
114704
114798
  body.configPath = options.configPath;
114705
114799
  const parsedMetadata = parseMetadataJson(options.metadata);
114800
+ const resolvedId = await resolveAgentId(id);
114706
114801
  const client = getClient();
114707
114802
  try {
114708
114803
  if (parsedMetadata !== undefined || options.providerAgentId !== undefined) {
114709
- const existing = await client.agents.get(id);
114804
+ const existing = await client.agents.get(resolvedId);
114710
114805
  const existingMetadata = existing.metadata ?? {};
114711
114806
  const merged = { ...existingMetadata, ...parsedMetadata ?? {} };
114712
114807
  if (options.providerAgentId !== undefined)
@@ -114716,7 +114811,7 @@ function createAgentsCommand() {
114716
114811
  if (Object.keys(body).length === 0) {
114717
114812
  error("No fields to update. Pass at least one of --name, --model, --provider, --agent-provider, --type, --active, --inactive, --config-path, --metadata, --provider-agent-id.");
114718
114813
  }
114719
- const agent = await client.agents.update(id, body);
114814
+ const agent = await client.agents.update(resolvedId, body);
114720
114815
  data(agent);
114721
114816
  } catch (err) {
114722
114817
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -114724,10 +114819,11 @@ function createAgentsCommand() {
114724
114819
  }
114725
114820
  });
114726
114821
  agents.command("delete <id>").description("Delete an agent (soft-delete, sets inactive)").action(async (id) => {
114822
+ const resolvedId = await resolveAgentId(id);
114727
114823
  const client = getClient();
114728
114824
  try {
114729
- await client.agents.delete(id);
114730
- success(`Agent ${id} deleted.`);
114825
+ await client.agents.delete(resolvedId);
114826
+ success(`Agent ${resolvedId} deleted.`);
114731
114827
  } catch (err) {
114732
114828
  const message = err instanceof Error ? err.message : "Unknown error";
114733
114829
  error(`Failed to delete agent: ${message}`, undefined, 3);
@@ -119464,6 +119560,13 @@ function assertScope(scope) {
119464
119560
  error(`Invalid scope: ${scope}. Expected one of: ${VALID_SCOPES.join(", ")}`);
119465
119561
  }
119466
119562
  }
119563
+ async function resolveScopedId(scope, id) {
119564
+ if (scope === "agents")
119565
+ return resolveAgentId(id);
119566
+ if (scope === "instances")
119567
+ return resolveInstanceId(id);
119568
+ return resolveChatId(id);
119569
+ }
119467
119570
  function readJsonArg(raw2) {
119468
119571
  let body = raw2;
119469
119572
  if (body === "-") {
@@ -119482,9 +119585,10 @@ function createFollowUpCommand() {
119482
119585
  const cmd = new Command("follow-up").description("Idle-chat follow-up config (agents/instances/chats). Closest scope wins at runtime.");
119483
119586
  cmd.command("get <scope> <id>").description("Read follow-up config at a scope (agents|instances|chats).").action(async (scope, id) => {
119484
119587
  assertScope(scope);
119588
+ const resolvedId = await resolveScopedId(scope, id);
119485
119589
  const client = getClient();
119486
119590
  try {
119487
- const data2 = scope === "agents" ? await client.followUp.getAgent(id) : scope === "instances" ? await client.followUp.getInstance(id) : await client.followUp.getChat(id);
119591
+ const data2 = scope === "agents" ? await client.followUp.getAgent(resolvedId) : scope === "instances" ? await client.followUp.getInstance(resolvedId) : await client.followUp.getChat(resolvedId);
119488
119592
  data(data2);
119489
119593
  } catch (err) {
119490
119594
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -119494,10 +119598,11 @@ function createFollowUpCommand() {
119494
119598
  cmd.command("set <scope> <id> <json>").description("Write follow-up config at a scope. <json> can be a literal, `@path`, or `-` for stdin.").action(async (scope, id, json) => {
119495
119599
  assertScope(scope);
119496
119600
  const config = readJsonArg(json);
119601
+ const resolvedId = await resolveScopedId(scope, id);
119497
119602
  const client = getClient();
119498
119603
  try {
119499
- const data2 = scope === "agents" ? await client.followUp.setAgent(id, config) : scope === "instances" ? await client.followUp.setInstance(id, config) : await client.followUp.setChat(id, config);
119500
- success(`Follow-up config set on ${scope.slice(0, -1)} ${id}.`, data2);
119604
+ const data2 = scope === "agents" ? await client.followUp.setAgent(resolvedId, config) : scope === "instances" ? await client.followUp.setInstance(resolvedId, config) : await client.followUp.setChat(resolvedId, config);
119605
+ success(`Follow-up config set on ${scope.slice(0, -1)} ${resolvedId}.`, data2);
119501
119606
  } catch (err) {
119502
119607
  const message = err instanceof Error ? err.message : "Unknown error";
119503
119608
  error(`Failed to set ${scope} follow-up: ${message}`, undefined, 3);
@@ -119505,15 +119610,16 @@ function createFollowUpCommand() {
119505
119610
  });
119506
119611
  cmd.command("unset <scope> <id>").description("Clear the override at a scope so broader scopes apply.").action(async (scope, id) => {
119507
119612
  assertScope(scope);
119613
+ const resolvedId = await resolveScopedId(scope, id);
119508
119614
  const client = getClient();
119509
119615
  try {
119510
119616
  if (scope === "agents")
119511
- await client.followUp.unsetAgent(id);
119617
+ await client.followUp.unsetAgent(resolvedId);
119512
119618
  else if (scope === "instances")
119513
- await client.followUp.unsetInstance(id);
119619
+ await client.followUp.unsetInstance(resolvedId);
119514
119620
  else
119515
- await client.followUp.unsetChat(id);
119516
- success(`Follow-up config cleared on ${scope.slice(0, -1)} ${id}.`);
119621
+ await client.followUp.unsetChat(resolvedId);
119622
+ success(`Follow-up config cleared on ${scope.slice(0, -1)} ${resolvedId}.`);
119517
119623
  } catch (err) {
119518
119624
  const message = err instanceof Error ? err.message : "Unknown error";
119519
119625
  error(`Failed to unset ${scope} follow-up: ${message}`, undefined, 3);
@@ -120207,7 +120313,7 @@ function createInstancesCommand() {
120207
120313
  error(`Failed to get instance: ${message}`, undefined, 3);
120208
120314
  }
120209
120315
  });
120210
- instances.command("create").description("Create a new instance (supports all API fields)").requiredOption("--name <name>", "Instance name").requiredOption("--channel <type>", `Channel type (${VALID_CHANNELS2.join(", ")})`).option("--agent-fk-id <uuid>", 'Agent FK UUID (references agents table, use "null" to clear)').option("--agent-provider <id>", "Agent provider ID").option("--agent <id>", "Agent ID").option("--agent-type <type>", "Agent type: agent, team, or workflow").option("--agent-timeout <seconds>", "Agent timeout in seconds", (v) => Number.parseInt(v, 10)).option("--agent-stream-mode", "Enable streaming responses").option("--agent-session-strategy <strategy>", "Session strategy: per_user, per_chat, per_user_per_chat").option("--agent-prefix-sender-name", "Prefix messages with sender name").option("--no-agent-prefix-sender-name", "Disable sender name prefix").option("--agent-wait-for-media", "Wait for media processing before dispatch").option("--no-agent-wait-for-media", "Dispatch immediately without waiting for media").option("--agent-send-media-path", "Include file path in formatted media text").option("--no-agent-send-media-path", "Exclude file path from formatted media text").option("--agent-send-media-path-types <types>", "Content types that receive file path (comma-separated: image,video,document)").option("--reply-filter-mode <mode>", "Reply filter: all or filtered").option("--reply-on-dm", "Reply to DMs").option("--no-reply-on-dm", "Ignore DMs").option("--reply-on-mention", "Reply when @mentioned").option("--no-reply-on-mention", "Ignore @mentions").option("--reply-on-reply", "Reply when message is reply to bot").option("--no-reply-on-reply", "Ignore replies").option("--reply-on-name", "Reply when bot name appears in text").option("--no-reply-on-name", "Ignore name matches").option("--reply-name-patterns <patterns>", "Custom name patterns (comma-separated)").option("--enable-auto-split", "Split responses on double newlines").option("--no-enable-auto-split", "Disable auto-split").option("--message-format-mode <mode>", "Format mode: convert or passthrough").option("--debounce-mode <mode>", "Debounce mode: disabled, fixed, or randomized").option("--debounce-min <ms>", "Minimum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-max <ms>", "Maximum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-restart-on-typing", "Restart debounce timer on typing").option("--debounce-group <ms>", "Group chat debounce in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-mode <mode>", "Split delay mode: disabled, fixed, or randomized").option("--split-delay-fixed <ms>", "Fixed delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-min <ms>", "Minimum delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-max <ms>", "Maximum delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--agent-gate", "Enable LLM response gate").option("--agent-gate-model <model>", "Model for response gate").option("--agent-gate-prompt <prompt>", "Custom gate prompt").option("--tts-voice <id>", "ElevenLabs voice ID").option("--tts-model <id>", "ElevenLabs model ID").option("--access-mode <mode>", "Access mode: disabled, blocklist, or allowlist").option("--reaction-ack <mode>", "Reaction ack mode (on|off)").option("--reaction-ack-emoji <json>", "Per-channel emoji map as JSON").option("--ack-timeout <ms>", "Ack timeout in milliseconds", (v) => Number.parseInt(v, 10)).option("--agent-stalled-timeout-ms <ms>", "Idle threshold in ms before the internal turn.stalled event fires (no channel message is ever sent)", (v) => Number.parseInt(v, 10)).option("--token <token>", "Generic bot token (auto-resolves to channel-specific field)").option("--telegram-token <token>", "Telegram bot token").option("--discord-token <token>", "Discord bot token").option("--slack-bot-token <token>", "Slack bot token").option("--slack-app-token <token>", "Slack app token").option("--gupshup-callback-url <url>", "Gupshup Custom Integration callback URL").option("--gupshup-auth-token <token>", "Gupshup Custom Integration auth token").option("--gupshup-event-id <id>", "Gupshup event ID (default: nx_omni_agent_reply)").option("--gupshup-webhook-verify-token <token>", "Gupshup webhook verify token").option("--bridge-tmux-session <name>", 'Tmux session name the genie bridge spawns into for this instance (propagated as GENIE_TMUX_SESSION via NATS). Use "null" to clear.').option("--is-default", "Set as default instance for channel").action(async (options) => {
120316
+ instances.command("create").description("Create a new instance (supports all API fields)").requiredOption("--name <name>", "Instance name").requiredOption("--channel <type>", `Channel type (${VALID_CHANNELS2.join(", ")})`).option("--agent-fk-id <uuid>", 'Agent FK UUID (references agents table, use "null" to clear). When set without --reply-filter-mode, reply filter defaults to {mode:"all", onDm:true} so messages are dispatched instead of silently dropped (omni#443).').option("--agent-provider <id>", "Agent provider ID").option("--agent <id>", "Agent ID").option("--agent-type <type>", "Agent type: agent, team, or workflow").option("--agent-timeout <seconds>", "Agent timeout in seconds", (v) => Number.parseInt(v, 10)).option("--agent-stream-mode", "Enable streaming responses").option("--agent-session-strategy <strategy>", "Session strategy: per_user, per_chat, per_user_per_chat").option("--agent-prefix-sender-name", "Prefix messages with sender name").option("--no-agent-prefix-sender-name", "Disable sender name prefix").option("--agent-wait-for-media", "Wait for media processing before dispatch").option("--no-agent-wait-for-media", "Dispatch immediately without waiting for media").option("--agent-send-media-path", "Include file path in formatted media text").option("--no-agent-send-media-path", "Exclude file path from formatted media text").option("--agent-send-media-path-types <types>", "Content types that receive file path (comma-separated: image,video,document)").option("--reply-filter-mode <mode>", "Reply filter: all or filtered").option("--reply-on-dm", "Reply to DMs").option("--no-reply-on-dm", "Ignore DMs").option("--reply-on-mention", "Reply when @mentioned").option("--no-reply-on-mention", "Ignore @mentions").option("--reply-on-reply", "Reply when message is reply to bot").option("--no-reply-on-reply", "Ignore replies").option("--reply-on-name", "Reply when bot name appears in text").option("--no-reply-on-name", "Ignore name matches").option("--reply-name-patterns <patterns>", "Custom name patterns (comma-separated)").option("--enable-auto-split", "Split responses on double newlines").option("--no-enable-auto-split", "Disable auto-split").option("--message-format-mode <mode>", "Format mode: convert or passthrough").option("--debounce-mode <mode>", "Debounce mode: disabled, fixed, or randomized").option("--debounce-min <ms>", "Minimum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-max <ms>", "Maximum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-restart-on-typing", "Restart debounce timer on typing").option("--debounce-group <ms>", "Group chat debounce in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-mode <mode>", "Split delay mode: disabled, fixed, or randomized").option("--split-delay-fixed <ms>", "Fixed delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-min <ms>", "Minimum delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-max <ms>", "Maximum delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--agent-gate", "Enable LLM response gate").option("--agent-gate-model <model>", "Model for response gate").option("--agent-gate-prompt <prompt>", "Custom gate prompt").option("--tts-voice <id>", "ElevenLabs voice ID").option("--tts-model <id>", "ElevenLabs model ID").option("--access-mode <mode>", "Access mode: disabled, blocklist, or allowlist").option("--reaction-ack <mode>", "Reaction ack mode (on|off)").option("--reaction-ack-emoji <json>", "Per-channel emoji map as JSON").option("--ack-timeout <ms>", "Ack timeout in milliseconds", (v) => Number.parseInt(v, 10)).option("--agent-stalled-timeout-ms <ms>", "Idle threshold in ms before the internal turn.stalled event fires (no channel message is ever sent)", (v) => Number.parseInt(v, 10)).option("--token <token>", "Generic bot token (auto-resolves to channel-specific field)").option("--telegram-token <token>", "Telegram bot token").option("--discord-token <token>", "Discord bot token").option("--slack-bot-token <token>", "Slack bot token").option("--slack-app-token <token>", "Slack app token").option("--gupshup-callback-url <url>", "Gupshup Custom Integration callback URL").option("--gupshup-auth-token <token>", "Gupshup Custom Integration auth token").option("--gupshup-event-id <id>", "Gupshup event ID (default: nx_omni_agent_reply)").option("--gupshup-webhook-verify-token <token>", "Gupshup webhook verify token").option("--bridge-tmux-session <name>", 'Tmux session name the genie bridge spawns into for this instance (propagated as GENIE_TMUX_SESSION via NATS). Use "null" to clear.').option("--is-default", "Set as default instance for channel").action(async (options) => {
120211
120317
  const channel = options.channel;
120212
120318
  if (!VALID_CHANNELS2.includes(channel)) {
120213
120319
  error(`Invalid channel: ${channel}`, { validChannels: VALID_CHANNELS2 });
@@ -120468,7 +120574,7 @@ function createInstancesCommand() {
120468
120574
  throw new Error(err?.error?.message ?? `HTTP ${response.status}`);
120469
120575
  }
120470
120576
  }
120471
- instances.command("update <id>").description("Update an instance (supports all API fields)").option("--name <name>", "Instance name").option("--is-default", "Set as default instance for channel").option("--no-is-default", "Unset as default instance for channel").option("--agent-fk-id <uuid>", 'Agent FK UUID (references agents table, use "null" to clear)').option("--agent-provider <id>", 'Agent provider ID (use "null" to clear)').option("--agent <id>", 'Agent ID (use "null" to clear)').option("--agent-type <type>", "Agent type: agent, team, or workflow").option("--agent-timeout <seconds>", "Agent timeout in seconds", (v) => Number.parseInt(v, 10)).option("--agent-stream-mode", "Enable streaming responses").option("--no-agent-stream-mode", "Disable streaming responses").option("--agent-session-strategy <strategy>", "Session strategy: per_user, per_chat, per_user_per_chat").option("--agent-prefix-sender-name", "Prefix messages with sender name").option("--no-agent-prefix-sender-name", "Disable sender name prefix").option("--agent-wait-for-media", "Wait for media processing before dispatch").option("--no-agent-wait-for-media", "Dispatch immediately without waiting for media").option("--agent-send-media-path", "Include file path in formatted media text").option("--no-agent-send-media-path", "Exclude file path from formatted media text").option("--agent-send-media-path-types <types>", "Content types that receive file path (comma-separated: image,video,document)").option("--reply-filter-mode <mode>", "Reply filter: all or filtered").option("--reply-on-dm", "Reply to DMs (requires --reply-filter-mode filtered)").option("--no-reply-on-dm", "Ignore DMs").option("--reply-on-mention", "Reply when @mentioned").option("--no-reply-on-mention", "Ignore @mentions").option("--reply-on-reply", "Reply when message is reply to bot").option("--no-reply-on-reply", "Ignore replies").option("--reply-on-name", "Reply when bot name appears in text").option("--no-reply-on-name", "Ignore name matches").option("--reply-name-patterns <patterns>", "Custom name patterns (comma-separated)").option("--clear-reply-filter", "Remove reply filter (set to null)").option("--enable-auto-split", "Split responses on double newlines").option("--no-enable-auto-split", "Disable auto-split").option("--message-format-mode <mode>", "Format mode: convert or passthrough").option("--debounce-mode <mode>", "Debounce mode: disabled, fixed, or randomized").option("--debounce-min <ms>", "Minimum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-max <ms>", "Maximum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-restart-on-typing", "Restart debounce timer on typing").option("--no-debounce-restart-on-typing", "Do not restart debounce on typing").option("--debounce-group <ms>", 'Group chat debounce in ms (use "null" to inherit)', (v) => v === "null" ? null : Number.parseInt(v, 10)).option("--split-delay-mode <mode>", "Split delay mode: disabled, fixed, or randomized").option("--split-delay-fixed <ms>", "Fixed delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-min <ms>", "Minimum delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-max <ms>", "Maximum delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--agent-gate", "Enable LLM response gate").option("--no-agent-gate", "Disable LLM response gate").option("--agent-gate-model <model>", 'Model for response gate (use "null" for default)').option("--agent-gate-prompt <prompt>", 'Custom gate prompt (use "null" for default)').option("--tts-voice <id>", 'ElevenLabs voice ID (use "null" to clear)').option("--tts-model <id>", 'ElevenLabs model ID (use "null" to clear)').option("--access-mode <mode>", "Access mode: disabled, blocklist, or allowlist").option("--reaction-ack <mode>", "Reaction ack mode (on|off)").option("--reaction-ack-emoji <json>", "Per-channel emoji map as JSON").option("--ack-timeout <ms>", "Ack timeout in milliseconds", (v) => Number.parseInt(v, 10)).option("--agent-stalled-timeout-ms <ms>", "Idle threshold in ms before the internal turn.stalled event fires (no channel message is ever sent)", (v) => Number.parseInt(v, 10)).option("--token <token>", "Generic bot token (auto-resolves to channel-specific field)").option("--telegram-token <token>", 'Telegram bot token (use "null" to clear)').option("--discord-token <token>", 'Discord bot token (use "null" to clear)').option("--slack-bot-token <token>", 'Slack bot token (use "null" to clear)').option("--slack-app-token <token>", 'Slack app token (use "null" to clear)').option("--trigger-events <events>", 'Trigger events (comma-separated, use "null" to clear)').option("--profile-name <name>", "Update WhatsApp display name (push name)").option("--bridge-tmux-session <name>", 'Tmux session name the genie bridge spawns into for this instance (propagated as GENIE_TMUX_SESSION via NATS). Use "null" to clear.').action(async (rawId, options) => {
120577
+ instances.command("update <id>").description("Update an instance (supports all API fields)").option("--name <name>", "Instance name").option("--is-default", "Set as default instance for channel").option("--no-is-default", "Unset as default instance for channel").option("--agent-fk-id <uuid>", 'Agent FK UUID (references agents table, use "null" to clear). When assigning an agent on an instance with no reply filter, the filter defaults to {mode:"all", onDm:true} so messages are dispatched instead of silently dropped (omni#443).').option("--agent-provider <id>", 'Agent provider ID (use "null" to clear)').option("--agent <id>", 'Agent ID (use "null" to clear)').option("--agent-type <type>", "Agent type: agent, team, or workflow").option("--agent-timeout <seconds>", "Agent timeout in seconds", (v) => Number.parseInt(v, 10)).option("--agent-stream-mode", "Enable streaming responses").option("--no-agent-stream-mode", "Disable streaming responses").option("--agent-session-strategy <strategy>", "Session strategy: per_user, per_chat, per_user_per_chat").option("--agent-prefix-sender-name", "Prefix messages with sender name").option("--no-agent-prefix-sender-name", "Disable sender name prefix").option("--agent-wait-for-media", "Wait for media processing before dispatch").option("--no-agent-wait-for-media", "Dispatch immediately without waiting for media").option("--agent-send-media-path", "Include file path in formatted media text").option("--no-agent-send-media-path", "Exclude file path from formatted media text").option("--agent-send-media-path-types <types>", "Content types that receive file path (comma-separated: image,video,document)").option("--reply-filter-mode <mode>", "Reply filter: all or filtered").option("--reply-on-dm", "Reply to DMs (requires --reply-filter-mode filtered)").option("--no-reply-on-dm", "Ignore DMs").option("--reply-on-mention", "Reply when @mentioned").option("--no-reply-on-mention", "Ignore @mentions").option("--reply-on-reply", "Reply when message is reply to bot").option("--no-reply-on-reply", "Ignore replies").option("--reply-on-name", "Reply when bot name appears in text").option("--no-reply-on-name", "Ignore name matches").option("--reply-name-patterns <patterns>", "Custom name patterns (comma-separated)").option("--clear-reply-filter", "Remove reply filter (set to null)").option("--enable-auto-split", "Split responses on double newlines").option("--no-enable-auto-split", "Disable auto-split").option("--message-format-mode <mode>", "Format mode: convert or passthrough").option("--debounce-mode <mode>", "Debounce mode: disabled, fixed, or randomized").option("--debounce-min <ms>", "Minimum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-max <ms>", "Maximum debounce delay in ms", (v) => Number.parseInt(v, 10)).option("--debounce-restart-on-typing", "Restart debounce timer on typing").option("--no-debounce-restart-on-typing", "Do not restart debounce on typing").option("--debounce-group <ms>", 'Group chat debounce in ms (use "null" to inherit)', (v) => v === "null" ? null : Number.parseInt(v, 10)).option("--split-delay-mode <mode>", "Split delay mode: disabled, fixed, or randomized").option("--split-delay-fixed <ms>", "Fixed delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-min <ms>", "Minimum delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--split-delay-max <ms>", "Maximum delay between split chunks in ms", (v) => Number.parseInt(v, 10)).option("--agent-gate", "Enable LLM response gate").option("--no-agent-gate", "Disable LLM response gate").option("--agent-gate-model <model>", 'Model for response gate (use "null" for default)').option("--agent-gate-prompt <prompt>", 'Custom gate prompt (use "null" for default)').option("--tts-voice <id>", 'ElevenLabs voice ID (use "null" to clear)').option("--tts-model <id>", 'ElevenLabs model ID (use "null" to clear)').option("--access-mode <mode>", "Access mode: disabled, blocklist, or allowlist").option("--reaction-ack <mode>", "Reaction ack mode (on|off)").option("--reaction-ack-emoji <json>", "Per-channel emoji map as JSON").option("--ack-timeout <ms>", "Ack timeout in milliseconds", (v) => Number.parseInt(v, 10)).option("--agent-stalled-timeout-ms <ms>", "Idle threshold in ms before the internal turn.stalled event fires (no channel message is ever sent)", (v) => Number.parseInt(v, 10)).option("--token <token>", "Generic bot token (auto-resolves to channel-specific field)").option("--telegram-token <token>", 'Telegram bot token (use "null" to clear)').option("--discord-token <token>", 'Discord bot token (use "null" to clear)').option("--slack-bot-token <token>", 'Slack bot token (use "null" to clear)').option("--slack-app-token <token>", 'Slack app token (use "null" to clear)').option("--trigger-events <events>", 'Trigger events (comma-separated, use "null" to clear)').option("--profile-name <name>", "Update WhatsApp display name (push name)").option("--bridge-tmux-session <name>", 'Tmux session name the genie bridge spawns into for this instance (propagated as GENIE_TMUX_SESSION via NATS). Use "null" to clear.').action(async (rawId, options) => {
120472
120578
  const client = getClient();
120473
120579
  try {
120474
120580
  const id = await resolveInstanceId(rawId);
@@ -122991,8 +123097,8 @@ Example: omni providers create --schema openclaw --default-agent-id sofia ...`;
122991
123097
  Example: omni providers create --name "My Project" --schema claude-code --base-url http://localhost:8882 --project-path /home/user/myproject`;
122992
123098
  }
122993
123099
  if (options.schema === "nats-genie" && (!options.agentName || !options.targetAgent)) {
122994
- return `Genie providers require --agent-name and --target-agent.
122995
- Example: omni providers create --name "My Genie" --schema nats-genie --base-url "file:///home/user/.claude/teams" --agent-name omni --target-agent team-lead --team-name "workspace-{chat_id}"`;
123100
+ return `nats-genie providers require --agent-name and --target-agent.
123101
+ Example: omni providers create --name "My Nats Genie" --schema nats-genie --base-url "file:///home/user/.claude/teams" --agent-name omni --target-agent team-lead --team-name "workspace-{chat_id}"`;
122996
123102
  }
122997
123103
  return null;
122998
123104
  }
@@ -123117,9 +123223,10 @@ async function handleList3(options) {
123117
123223
  }
123118
123224
  }
123119
123225
  async function handleGet2(id) {
123226
+ const resolvedId = await resolveProviderId(id);
123120
123227
  const client = getClient();
123121
123228
  try {
123122
- const provider = await client.providers.get(id);
123229
+ const provider = await client.providers.get(resolvedId);
123123
123230
  data(provider);
123124
123231
  } catch (err2) {
123125
123232
  const message2 = err2 instanceof Error ? err2.message : "Unknown error";
@@ -123156,9 +123263,10 @@ Next steps:`);
123156
123263
  }
123157
123264
  }
123158
123265
  async function handleTest(id) {
123266
+ const resolvedId = await resolveProviderId(id);
123159
123267
  const client = getClient();
123160
123268
  try {
123161
- const result = await client.providers.checkHealth(id);
123269
+ const result = await client.providers.checkHealth(resolvedId);
123162
123270
  if (result.healthy) {
123163
123271
  success(`Provider is healthy (latency: ${result.latency}ms)`);
123164
123272
  } else {
@@ -123181,14 +123289,15 @@ async function handleUpdate2(id, options) {
123181
123289
  error("No fields to update. Provide at least one option.");
123182
123290
  return;
123183
123291
  }
123292
+ const resolvedId = await resolveProviderId(id);
123184
123293
  const client = getClient();
123185
123294
  try {
123186
123295
  if (body.schemaConfig && !options.schemaConfig) {
123187
- const existing = await client.providers.get(id);
123296
+ const existing = await client.providers.get(resolvedId);
123188
123297
  const existingConfig = existing.schemaConfig ?? {};
123189
123298
  body.schemaConfig = { ...existingConfig, ...body.schemaConfig };
123190
123299
  }
123191
- const provider = await client.providers.update(id, body);
123300
+ const provider = await client.providers.update(resolvedId, body);
123192
123301
  success(`Updated provider: ${provider.id}`);
123193
123302
  data(provider);
123194
123303
  } catch (err2) {
@@ -123201,10 +123310,11 @@ async function handleDelete2(id, options) {
123201
123310
  warn(`This will delete provider ${id}. Use --force to confirm.`);
123202
123311
  return;
123203
123312
  }
123313
+ const resolvedId = await resolveProviderId(id);
123204
123314
  const client = getClient();
123205
123315
  try {
123206
- await client.providers.delete(id);
123207
- success(`Deleted provider: ${id}`);
123316
+ await client.providers.delete(resolvedId);
123317
+ success(`Deleted provider: ${resolvedId}`);
123208
123318
  } catch (err2) {
123209
123319
  const message2 = err2 instanceof Error ? err2.message : "Unknown error";
123210
123320
  error(`Failed to delete provider: ${message2}`);
@@ -123215,12 +123325,13 @@ function createProvidersCommand() {
123215
123325
  providers2.addCommand(createSetupCommand());
123216
123326
  providers2.command("list").description("List available providers").option("--active", "Show only active providers").action(handleList3);
123217
123327
  providers2.command("get <id>").description("Get provider details").action(handleGet2);
123218
- providers2.command("create").description("Create a new AI provider").requiredOption("--name <name>", "Provider name (unique)").requiredOption("--schema <schema>", `Provider schema (${VALID_SCHEMAS.join(", ")})`).requiredOption("--base-url <url>", "API base URL (ws:// or wss:// for openclaw)").option("--api-key <key>", "API key (optional for claude-code if using env ANTHROPIC_API_KEY)").option("--description <desc>", "Provider description").option("--timeout <seconds>", "Default timeout in seconds", Number.parseInt, 60).option("--stream", "Enable streaming by default").option("--default-agent-id <agentId>", "Default agent ID (required for openclaw)").option("--project-path <path>", "Project directory path (required for claude-code)").option("--max-turns <number>", "Max conversation turns (claude-code)", Number.parseInt).option("--permission-mode <mode>", "Permission mode: default, acceptEdits, bypassPermissions, plan (claude-code)").option("--model <model>", "Model override (claude-code)").option("--system-prompt <prompt>", "System prompt prepended to agent (claude-code)").option("--agent-name <name>", 'Agent identity / "from" field (required for genie)').option("--target-agent <name>", "Target agent inbox to deliver to (required for genie)").option("--team-name <template>", "Team name template, supports {chat_id}, {thread_id}, {sender_id} (genie, default: omni-{chat_id})").action(handleCreate3);
123328
+ providers2.command("create").description("Create a new AI provider").requiredOption("--name <name>", "Provider name (unique)").requiredOption("--schema <schema>", `Provider schema (${VALID_SCHEMAS.join(", ")})`).requiredOption("--base-url <url>", "API base URL (ws:// or wss:// for openclaw)").option("--api-key <key>", "API key (optional for claude-code if using env ANTHROPIC_API_KEY)").option("--description <desc>", "Provider description").option("--timeout <seconds>", "Default timeout in seconds", Number.parseInt, 60).option("--stream", "Enable streaming by default").option("--default-agent-id <agentId>", "Default agent ID (required for openclaw)").option("--project-path <path>", "Project directory path (required for claude-code)").option("--max-turns <number>", "Max conversation turns (claude-code)", Number.parseInt).option("--permission-mode <mode>", "Permission mode: default, acceptEdits, bypassPermissions, plan (claude-code)").option("--model <model>", "Model override (claude-code)").option("--system-prompt <prompt>", "System prompt prepended to agent (claude-code)").option("--agent-name <name>", 'Agent identity / "from" field (required for nats-genie)').option("--target-agent <name>", "Target agent inbox to deliver to (required for nats-genie)").option("--team-name <template>", "Team name template, supports {chat_id}, {thread_id}, {sender_id} (nats-genie, default: omni-{chat_id})").action(handleCreate3);
123219
123329
  providers2.command("test <id>").description("Test provider health").action(handleTest);
123220
123330
  providers2.command("agents <id>").description("List agents from provider (Agno)").action(async (id) => {
123331
+ const resolvedId = await resolveProviderId(id);
123221
123332
  const client = getClient();
123222
123333
  try {
123223
- const agents2 = await client.providers.listAgents(id);
123334
+ const agents2 = await client.providers.listAgents(resolvedId);
123224
123335
  const items = agents2.map((a2) => ({
123225
123336
  id: a2.agent_id,
123226
123337
  name: a2.name,
@@ -123234,9 +123345,10 @@ function createProvidersCommand() {
123234
123345
  }
123235
123346
  });
123236
123347
  providers2.command("teams <id>").description("List teams from provider (Agno)").action(async (id) => {
123348
+ const resolvedId = await resolveProviderId(id);
123237
123349
  const client = getClient();
123238
123350
  try {
123239
- const teams = await client.providers.listTeams(id);
123351
+ const teams = await client.providers.listTeams(resolvedId);
123240
123352
  const items = teams.map((t) => ({
123241
123353
  id: t.team_id,
123242
123354
  name: t.name,
@@ -123251,9 +123363,10 @@ function createProvidersCommand() {
123251
123363
  }
123252
123364
  });
123253
123365
  providers2.command("workflows <id>").description("List workflows from provider (Agno)").action(async (id) => {
123366
+ const resolvedId = await resolveProviderId(id);
123254
123367
  const client = getClient();
123255
123368
  try {
123256
- const workflows = await client.providers.listWorkflows(id);
123369
+ const workflows = await client.providers.listWorkflows(resolvedId);
123257
123370
  const items = workflows.map((w) => ({
123258
123371
  id: w.workflow_id,
123259
123372
  name: w.name,
@@ -123265,7 +123378,7 @@ function createProvidersCommand() {
123265
123378
  error(`Failed to list workflows: ${message2}`);
123266
123379
  }
123267
123380
  });
123268
- providers2.command("update <id>").description("Update a provider").option("--name <name>", "Provider name").option("--base-url <url>", "API base URL").option("--api-key <key>", "API key").option("--description <desc>", "Provider description").option("--timeout <seconds>", "Default timeout in seconds", Number.parseInt).option("--stream", "Enable streaming by default").option("--no-stream", "Disable streaming by default").option("--active", "Set provider active").option("--no-active", "Set provider inactive").option("--agent-name <name>", "Agent identity (genie)").option("--target-agent <name>", "Target agent inbox (genie)").option("--team-name <template>", "Team name template (genie)").option("--project-path <path>", "Project directory path (claude-code)").option("--max-turns <number>", "Max conversation turns (claude-code)", Number.parseInt).option("--permission-mode <mode>", "Permission mode (claude-code)").option("--model <model>", "Model override (claude-code)").option("--system-prompt <prompt>", "System prompt (claude-code)").option("--schema-config <json>", "Raw schemaConfig as JSON (overrides individual schema flags)").action(handleUpdate2);
123381
+ providers2.command("update <id>").description("Update a provider").option("--name <name>", "Provider name").option("--base-url <url>", "API base URL").option("--api-key <key>", "API key").option("--description <desc>", "Provider description").option("--timeout <seconds>", "Default timeout in seconds", Number.parseInt).option("--stream", "Enable streaming by default").option("--no-stream", "Disable streaming by default").option("--active", "Set provider active").option("--no-active", "Set provider inactive").option("--agent-name <name>", "Agent identity (nats-genie)").option("--target-agent <name>", "Target agent inbox (nats-genie)").option("--team-name <template>", "Team name template (nats-genie)").option("--project-path <path>", "Project directory path (claude-code)").option("--max-turns <number>", "Max conversation turns (claude-code)", Number.parseInt).option("--permission-mode <mode>", "Permission mode (claude-code)").option("--model <model>", "Model override (claude-code)").option("--system-prompt <prompt>", "System prompt (claude-code)").option("--schema-config <json>", "Raw schemaConfig as JSON (overrides individual schema flags)").action(handleUpdate2);
123269
123382
  providers2.command("delete <id>").description("Delete a provider").option("--force", "Skip confirmation").action(handleDelete2);
123270
123383
  return providers2;
123271
123384
  }
@@ -125308,9 +125421,10 @@ function createWebhooksCommand() {
125308
125421
  }
125309
125422
  });
125310
125423
  webhooks.command("get <id>").description("Get webhook source details").action(async (id) => {
125424
+ const resolvedId = await resolveWebhookId(id);
125311
125425
  const client = getClient();
125312
125426
  try {
125313
- const source = await client.webhooks.getSource(id);
125427
+ const source = await client.webhooks.getSource(resolvedId);
125314
125428
  data(source);
125315
125429
  } catch (err2) {
125316
125430
  const message2 = err2 instanceof Error ? err2.message : "Unknown error";
@@ -125345,6 +125459,7 @@ function createWebhooksCommand() {
125345
125459
  }
125346
125460
  });
125347
125461
  webhooks.command("update <id>").description("Update a webhook source").option("--name <name>", "New name").option("--description <desc>", "New description").option("--enable", "Enable the webhook").option("--disable", "Disable the webhook").action(async (id, options3) => {
125462
+ const resolvedId = await resolveWebhookId(id);
125348
125463
  const client = getClient();
125349
125464
  try {
125350
125465
  const updates = {};
@@ -125356,7 +125471,7 @@ function createWebhooksCommand() {
125356
125471
  updates.enabled = true;
125357
125472
  if (options3.disable)
125358
125473
  updates.enabled = false;
125359
- const source = await client.webhooks.updateSource(id, updates);
125474
+ const source = await client.webhooks.updateSource(resolvedId, updates);
125360
125475
  success(`Webhook source updated: ${source.id}`, {
125361
125476
  id: source.id,
125362
125477
  name: source.name,
@@ -125368,10 +125483,11 @@ function createWebhooksCommand() {
125368
125483
  }
125369
125484
  });
125370
125485
  webhooks.command("delete <id>").description("Delete a webhook source").action(async (id) => {
125486
+ const resolvedId = await resolveWebhookId(id);
125371
125487
  const client = getClient();
125372
125488
  try {
125373
- await client.webhooks.deleteSource(id);
125374
- success(`Webhook source deleted: ${id}`);
125489
+ await client.webhooks.deleteSource(resolvedId);
125490
+ success(`Webhook source deleted: ${resolvedId}`);
125375
125491
  } catch (err2) {
125376
125492
  const message2 = err2 instanceof Error ? err2.message : "Unknown error";
125377
125493
  error(`Failed to delete webhook source: ${message2}`);
package/dist/resolve.d.ts CHANGED
@@ -97,6 +97,42 @@ export declare function resolveAutomationId(input: string): Promise<string>;
97
97
  * Exits with error if no match or ambiguous.
98
98
  */
99
99
  export declare function resolveBatchJobId(input: string): Promise<string>;
100
+ /**
101
+ * Resolve a provider identifier to a UUID.
102
+ *
103
+ * Matches in order:
104
+ * 1. Exact UUID match (skip API call)
105
+ * 2. UUID prefix match (minimum 2 hex chars)
106
+ * 3. Exact name match (case-insensitive)
107
+ * 4. Name substring match (case-insensitive)
108
+ *
109
+ * Exits with error if no match or ambiguous.
110
+ */
111
+ export declare function resolveProviderId(input: string): Promise<string>;
112
+ /**
113
+ * Resolve an agent identifier to a UUID.
114
+ *
115
+ * Matches in order:
116
+ * 1. Exact UUID match (skip API call)
117
+ * 2. UUID prefix match (minimum 2 hex chars)
118
+ * 3. Exact name match (case-insensitive)
119
+ * 4. Name substring match (case-insensitive)
120
+ *
121
+ * Exits with error if no match or ambiguous.
122
+ */
123
+ export declare function resolveAgentId(input: string): Promise<string>;
124
+ /**
125
+ * Resolve a webhook source identifier to a UUID.
126
+ *
127
+ * Matches in order:
128
+ * 1. Exact UUID match (skip API call)
129
+ * 2. UUID prefix match (minimum 2 hex chars)
130
+ * 3. Exact name match (case-insensitive)
131
+ * 4. Name substring match (case-insensitive)
132
+ *
133
+ * Exits with error if no match or ambiguous.
134
+ */
135
+ export declare function resolveWebhookId(input: string): Promise<string>;
100
136
  /**
101
137
  * Resolve an agent route identifier to a UUID.
102
138
  *
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BtE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYrE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwCtF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBpE;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BjE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BxE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBvF"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BtE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYrE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwCtF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBpE;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BjE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BxE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBtE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BtE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BnE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BrE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBvF"}
@@ -224451,7 +224451,7 @@ var init_sentry_scrub = __esm(() => {
224451
224451
  var require_package8 = __commonJS((exports, module) => {
224452
224452
  module.exports = {
224453
224453
  name: "@omni/api",
224454
- version: "2.260422.4",
224454
+ version: "2.260422.5",
224455
224455
  type: "module",
224456
224456
  exports: {
224457
224457
  ".": {
@@ -282277,7 +282277,7 @@ function buildChatPreview(payload, rawPayload) {
282277
282277
  const badge = payload.content.type !== "text" ? MEDIA_BADGES2[payload.content.type] ?? `[${payload.content.type}]` : "";
282278
282278
  let preview = badge ? text3 ? `${badge} ${text3}` : badge : text3;
282279
282279
  if (isGroup && !isFromMe2) {
282280
- const sender = rawPayload?.pushName || rawPayload?.displayName || "";
282280
+ const sender = payload.senderName || rawPayload?.pushName || rawPayload?.displayName || "";
282281
282281
  if (sender)
282282
282282
  preview = `${sender}: ${preview}`;
282283
282283
  }
@@ -282300,7 +282300,7 @@ async function processSenderIdentity(services, payload, metadata, channel4) {
282300
282300
  if (!payload.from) {
282301
282301
  return { personId: metadata.personId, platformIdentityId: undefined };
282302
282302
  }
282303
- const displayName = truncate3(payload.rawPayload?.pushName, 255);
282303
+ const displayName = truncate3(payload.senderName ?? payload.rawPayload?.pushName, 255);
282304
282304
  const platformUserId = truncate3(payload.from, 255) ?? payload.from;
282305
282305
  const isLidAddressed = payload.rawPayload?.addressingMode === "lid" || payload.rawPayload?.senderIsLid === true;
282306
282306
  const resolvedPhone = isLidAddressed ? payload.rawPayload?.resolvedSenderPhone : undefined;
@@ -282378,14 +282378,14 @@ async function persistLidMappings(services, chat2, chatExternalId, instanceId, r
282378
282378
  }
282379
282379
  }
282380
282380
  }
282381
- async function postProcessChat(services, chat2, _chatCreated, chatExternalId, chatType, pushName, instanceId, rawPayload, isFromMe2) {
282381
+ async function postProcessChat(services, chat2, _chatCreated, chatExternalId, chatType, pushName, instanceId, rawPayload, isFromMe2, chatName) {
282382
282382
  if (chatExternalId.endsWith("@s.whatsapp.net") && !chat2.canonicalId) {
282383
282383
  await services.chats.update(chat2.id, { canonicalId: chatExternalId });
282384
282384
  chat2.canonicalId = chatExternalId;
282385
282385
  }
282386
282386
  await persistLidMappings(services, chat2, chatExternalId, instanceId, rawPayload);
282387
282387
  {
282388
- const chatNameLocal = rawPayload?.chatName;
282388
+ const chatNameLocal = chatName ?? rawPayload?.chatName;
282389
282389
  const effectiveNameLocal = resolveEffectiveChatName({
282390
282390
  chatType,
282391
282391
  isFromMe: isFromMe2,
@@ -282399,15 +282399,15 @@ async function postProcessChat(services, chat2, _chatCreated, chatExternalId, ch
282399
282399
  }
282400
282400
  }
282401
282401
  }
282402
- function resolveSenderDisplayName(rawPayload, participantResult) {
282403
- return truncate3(rawPayload?.pushName, 255) || participantResult?.participant.displayName || undefined;
282402
+ function resolveSenderDisplayName(senderName, rawPayload, participantResult) {
282403
+ return truncate3(senderName ?? rawPayload?.pushName, 255) || participantResult?.participant.displayName || undefined;
282404
282404
  }
282405
- async function maybeFindOrCreateParticipant(services, chatId, from, rawPayload, personId, platformIdentityId) {
282405
+ async function maybeFindOrCreateParticipant(services, chatId, from, rawPayload, personId, platformIdentityId, senderName) {
282406
282406
  if (!from)
282407
282407
  return;
282408
282408
  const participantUserId = truncate3(from, 255) ?? from;
282409
282409
  return services.chats.findOrCreateParticipant(chatId, participantUserId, {
282410
- displayName: truncate3(rawPayload?.pushName, 255),
282410
+ displayName: truncate3(senderName ?? rawPayload?.pushName, 255),
282411
282411
  personId,
282412
282412
  platformIdentityId
282413
282413
  });
@@ -282471,15 +282471,15 @@ async function handleMessageReceived(services, payload, metadata, eventTimestamp
282471
282471
  const rawPayload = payload.rawPayload ? deepSanitize(payload.rawPayload) : undefined;
282472
282472
  const chatType = inferChatType(payload.chatId, rawPayload?.isGroup);
282473
282473
  const isFromMe2 = rawPayload?.isFromMe === true;
282474
- const pushName = truncate3(rawPayload?.pushName, 255);
282475
- const chatName = truncate3(rawPayload?.chatName, 255);
282474
+ const pushName = truncate3(payload.senderName ?? rawPayload?.pushName, 255);
282475
+ const chatName = truncate3(payload.chatName ?? rawPayload?.chatName, 255);
282476
282476
  const effectiveName = resolveEffectiveChatName({ chatType, isFromMe: isFromMe2, chatName, pushName, rawPayload });
282477
282477
  const canonicalId = chatExternalId.endsWith("@s.whatsapp.net") ? chatExternalId : undefined;
282478
282478
  const { chat: chat2, created: chatCreated } = await resolveOrCreateChat(services, metadata.instanceId, chatExternalId, chatType, channel4, effectiveName, canonicalId, rawPayload);
282479
- await postProcessChat(services, chat2, chatCreated, chatExternalId, chatType, pushName, metadata.instanceId, rawPayload, isFromMe2);
282479
+ await postProcessChat(services, chat2, chatCreated, chatExternalId, chatType, pushName, metadata.instanceId, rawPayload, isFromMe2, chatName);
282480
282480
  const { personId, platformIdentityId } = await processSenderIdentity(services, payload, metadata, channel4);
282481
- const participantResult = await maybeFindOrCreateParticipant(services, chat2.id, payload.from, rawPayload, personId, platformIdentityId);
282482
- const senderDisplayName = resolveSenderDisplayName(rawPayload, participantResult);
282481
+ const participantResult = await maybeFindOrCreateParticipant(services, chat2.id, payload.from, rawPayload, personId, platformIdentityId, payload.senderName);
282482
+ const senderDisplayName = resolveSenderDisplayName(payload.senderName, rawPayload, participantResult);
282483
282483
  const quotedMessage = rawPayload?.quotedMessage;
282484
282484
  const platformTimestamp = extractPlatformTimestamp(rawPayload, eventTimestamp);
282485
282485
  const { message: message2, created } = await services.messages.findOrCreate(chat2.id, messageExternalId, {
@@ -286096,7 +286096,8 @@ class SyncJobService {
286096
286096
  };
286097
286097
  const updatedProgress = {
286098
286098
  ...currentProgress,
286099
- ...progress
286099
+ ...progress,
286100
+ lastProgressAt: new Date().toISOString()
286100
286101
  };
286101
286102
  const [updated] = await this.db.update(syncJobs).set({ progress: updatedProgress }).where(eq(syncJobs.id, id)).returning();
286102
286103
  if (!updated) {
@@ -287234,6 +287235,19 @@ var init_webhook_auth = __esm(() => {
287234
287235
  log95 = createLogger("api:webhook-auth");
287235
287236
  });
287236
287237
 
287238
+ // ../api/src/plugin-state.ts
287239
+ function markPluginsDegraded(reason) {
287240
+ pluginsDegraded = true;
287241
+ pluginsDegradedReason = reason;
287242
+ }
287243
+ function arePluginsDegraded() {
287244
+ return pluginsDegraded;
287245
+ }
287246
+ function getPluginsDegradedReason() {
287247
+ return pluginsDegradedReason;
287248
+ }
287249
+ var pluginsDegraded = false, pluginsDegradedReason = null;
287250
+
287237
287251
  // ../api/src/routes/health.ts
287238
287252
  var import__package2, VERSION5, startTime2, healthRoutes;
287239
287253
  var init_health2 = __esm(() => {
@@ -287247,6 +287261,7 @@ var init_health2 = __esm(() => {
287247
287261
  healthRoutes.get("/health", async (c) => {
287248
287262
  const db2 = c.get("db");
287249
287263
  const eventBus = c.get("eventBus");
287264
+ const channelRegistry2 = c.get("channelRegistry");
287250
287265
  let dbCheck;
287251
287266
  const dbStart = Date.now();
287252
287267
  try {
@@ -287274,15 +287289,23 @@ var init_health2 = __esm(() => {
287274
287289
  }).from(instances).groupBy(instances.channel);
287275
287290
  const byChannel = {};
287276
287291
  let total = 0;
287277
- let connected = 0;
287292
+ let active = 0;
287278
287293
  for (const row of instanceCounts) {
287279
287294
  byChannel[row.channel] = row.total;
287280
287295
  total += row.total;
287281
- connected += row.active;
287296
+ active += row.active;
287282
287297
  }
287283
- instanceStats = { total, connected, byChannel };
287298
+ let connected = 0;
287299
+ if (channelRegistry2) {
287300
+ for (const plugin6 of channelRegistry2.getAll()) {
287301
+ connected += plugin6.getConnectedInstances().length;
287302
+ }
287303
+ }
287304
+ instanceStats = { total, active, connected, byChannel };
287284
287305
  } catch {}
287285
- const hasErrors = dbCheck.status === "error" || natsCheck.status === "error";
287306
+ const pluginsFailed = arePluginsDegraded();
287307
+ const pluginsCheck = pluginsFailed ? { status: "error", error: getPluginsDegradedReason() ?? "Plugin initialization failed" } : { status: "ok" };
287308
+ const hasErrors = dbCheck.status === "error" || natsCheck.status === "error" || pluginsFailed;
287286
287309
  const status = hasErrors ? "degraded" : "healthy";
287287
287310
  const response = {
287288
287311
  status,
@@ -287291,7 +287314,8 @@ var init_health2 = __esm(() => {
287291
287314
  timestamp: new Date().toISOString(),
287292
287315
  checks: {
287293
287316
  database: dbCheck,
287294
- nats: natsCheck
287317
+ nats: natsCheck,
287318
+ plugins: pluginsCheck
287295
287319
  },
287296
287320
  instances: instanceStats
287297
287321
  };
@@ -287299,24 +287323,32 @@ var init_health2 = __esm(() => {
287299
287323
  });
287300
287324
  healthRoutes.get("/info", async (c) => {
287301
287325
  const db2 = c.get("db");
287326
+ const channelRegistry2 = c.get("channelRegistry");
287302
287327
  let instancesTotal = 0;
287303
- let instancesConnected = 0;
287328
+ let instancesActive = 0;
287304
287329
  const eventsToday = 0;
287305
287330
  const eventsTotal = 0;
287306
287331
  try {
287307
287332
  const [instanceStats] = await db2.select({
287308
287333
  total: sql`count(*)::int`,
287309
- connected: sql`count(*) filter (where ${instances.isActive})::int`
287334
+ active: sql`count(*) filter (where ${instances.isActive})::int`
287310
287335
  }).from(instances);
287311
287336
  instancesTotal = instanceStats?.total ?? 0;
287312
- instancesConnected = instanceStats?.connected ?? 0;
287337
+ instancesActive = instanceStats?.active ?? 0;
287313
287338
  } catch {}
287339
+ let instancesConnected = 0;
287340
+ if (channelRegistry2) {
287341
+ for (const plugin6 of channelRegistry2.getAll()) {
287342
+ instancesConnected += plugin6.getConnectedInstances().length;
287343
+ }
287344
+ }
287314
287345
  return c.json({
287315
287346
  version: VERSION5,
287316
287347
  environment: "development",
287317
287348
  uptime: Math.floor((Date.now() - startTime2) / 1000),
287318
287349
  instances: {
287319
287350
  total: instancesTotal,
287351
+ active: instancesActive,
287320
287352
  connected: instancesConnected
287321
287353
  },
287322
287354
  events: {
@@ -296519,6 +296551,18 @@ var init_agent_replay = __esm(() => {
296519
296551
  });
296520
296552
 
296521
296553
  // ../api/src/routes/v2/instances.ts
296554
+ function shouldApplyDefaultReplyFilter(args) {
296555
+ if (!args.agentIdTouched)
296556
+ return false;
296557
+ if (args.explicitReplyFilter !== undefined)
296558
+ return false;
296559
+ const effectiveAgentId = args.newAgentId !== undefined ? args.newAgentId : args.currentAgentId;
296560
+ if (!effectiveAgentId)
296561
+ return false;
296562
+ if (args.currentReplyFilter != null)
296563
+ return false;
296564
+ return true;
296565
+ }
296522
296566
  function resolveChannelToken(data) {
296523
296567
  if (data.token && !data.telegramBotToken && !data.discordBotToken && !data.slackBotToken) {
296524
296568
  if (data.channel === "telegram")
@@ -296784,7 +296828,7 @@ function getCacheKey(instanceId, guildId) {
296784
296828
  function invalidateGuildCache(instanceId, guildId) {
296785
296829
  guildConfigCache.delete(getCacheKey(instanceId, guildId));
296786
296830
  }
296787
- var log99, instancesRoutes, instanceAccess2, listQuerySchema11, agentReplyFilterSchema, createInstanceSchema, updateInstanceSchema, SENSITIVE_INSTANCE_FIELDS, pairingCodeSchema, connectInstanceSchema, syncRequestSchema, listContactsQuerySchema, listGroupsQuerySchema, checkNumberSchema, updateBioSchema, blockContactSchema, resyncSchema, replaySchema, pairingActionSchema, guildConfigOverrideSchema, guildConfigCache, GUILD_CONFIG_TTL, presenceSchema;
296831
+ var log99, instancesRoutes, instanceAccess2, listQuerySchema11, agentReplyFilterSchema, createInstanceSchema, updateInstanceSchema, DEFAULT_AGENT_REPLY_FILTER, SENSITIVE_INSTANCE_FIELDS, pairingCodeSchema, connectInstanceSchema, syncRequestSchema, listContactsQuerySchema, listGroupsQuerySchema, checkNumberSchema, updateBioSchema, blockContactSchema, resyncSchema, replaySchema, pairingActionSchema, guildConfigOverrideSchema, guildConfigCache, GUILD_CONFIG_TTL, presenceSchema;
296788
296832
  var init_instances3 = __esm(() => {
296789
296833
  init_dist6();
296790
296834
  init_src();
@@ -296888,6 +296932,10 @@ var init_instances3 = __esm(() => {
296888
296932
  messageSplitDelayMinMs: exports_external.number().int().min(0).optional(),
296889
296933
  messageSplitDelayMaxMs: exports_external.number().int().min(0).optional()
296890
296934
  });
296935
+ DEFAULT_AGENT_REPLY_FILTER = {
296936
+ mode: "all",
296937
+ conditions: { onDm: true }
296938
+ };
296891
296939
  SENSITIVE_INSTANCE_FIELDS = [
296892
296940
  "telegramBotToken",
296893
296941
  "discordBotToken",
@@ -296949,6 +296997,19 @@ var init_instances3 = __esm(() => {
296949
296997
  const data = c.req.valid("json");
296950
296998
  const services = c.get("services");
296951
296999
  const channelRegistry2 = c.get("channelRegistry");
297000
+ if (shouldApplyDefaultReplyFilter({
297001
+ newAgentId: data.agentId,
297002
+ currentAgentId: null,
297003
+ explicitReplyFilter: data.agentReplyFilter,
297004
+ currentReplyFilter: null,
297005
+ agentIdTouched: data.agentId !== undefined
297006
+ })) {
297007
+ data.agentReplyFilter = DEFAULT_AGENT_REPLY_FILTER;
297008
+ log99.info("Agent assigned without reply filter \u2014 defaulting to mode:all onDm:true (omni#443)", {
297009
+ agentId: data.agentId,
297010
+ defaultFilter: DEFAULT_AGENT_REPLY_FILTER
297011
+ });
297012
+ }
296952
297013
  const connectToken = resolveChannelToken(data);
296953
297014
  const instance4 = await services.instances.create(data);
296954
297015
  const connectionOptions = buildInstanceConnectionOptions({
@@ -296975,12 +297036,28 @@ var init_instances3 = __esm(() => {
296975
297036
  const data = c.req.valid("json");
296976
297037
  const services = c.get("services");
296977
297038
  let oldAgentId;
297039
+ let currentReplyFilter = null;
296978
297040
  if (data.agentId !== undefined) {
296979
297041
  try {
296980
297042
  const current = await services.instances.getById(id);
296981
297043
  oldAgentId = current.agentId;
297044
+ currentReplyFilter = current.agentReplyFilter;
296982
297045
  } catch {}
296983
297046
  }
297047
+ if (shouldApplyDefaultReplyFilter({
297048
+ newAgentId: data.agentId,
297049
+ currentAgentId: oldAgentId,
297050
+ explicitReplyFilter: data.agentReplyFilter,
297051
+ currentReplyFilter,
297052
+ agentIdTouched: data.agentId !== undefined
297053
+ })) {
297054
+ data.agentReplyFilter = DEFAULT_AGENT_REPLY_FILTER;
297055
+ log99.info("Agent assigned without reply filter \u2014 defaulting to mode:all onDm:true (omni#443)", {
297056
+ instanceId: id,
297057
+ agentId: data.agentId,
297058
+ defaultFilter: DEFAULT_AGENT_REPLY_FILTER
297059
+ });
297060
+ }
296984
297061
  const instance4 = await services.instances.update(id, data);
296985
297062
  if (data.accessMode !== undefined) {
296986
297063
  await accessCache.clear();
@@ -303555,6 +303632,13 @@ async function setupHistoryPushTracker(eventBus, services) {
303555
303632
  await eventBus.subscribe("instance.connected", async (event) => {
303556
303633
  const { instanceId, channelType } = event.payload;
303557
303634
  try {
303635
+ if (await services.syncJobs.hasActiveJob(instanceId, "history-push")) {
303636
+ historyPushLog.debug("Active history-push job already exists \u2014 skipping create", {
303637
+ instanceId,
303638
+ channel: channelType
303639
+ });
303640
+ return;
303641
+ }
303558
303642
  const job = await services.syncJobs.create({
303559
303643
  instanceId,
303560
303644
  channelType,
@@ -303589,13 +303673,13 @@ async function setupHistoryPushTracker(eventBus, services) {
303589
303673
  });
303590
303674
  return;
303591
303675
  }
303592
- await services.syncJobs.updateProgress(historyPushJob.id, {
303593
- fetched: payload.fetched ?? 0,
303594
- stored: 0,
303595
- duplicates: 0,
303596
- mediaDownloaded: 0,
303597
- totalEstimated: payload.progress && payload.progress > 0 ? Math.round((payload.fetched ?? 0) / (payload.progress / 100)) : 0
303598
- });
303676
+ const update2 = {
303677
+ fetched: payload.fetched ?? 0
303678
+ };
303679
+ if (typeof payload.progress === "number" && payload.progress > 0) {
303680
+ update2.totalEstimated = Math.round((payload.fetched ?? 0) / (payload.progress / 100));
303681
+ }
303682
+ await services.syncJobs.updateProgress(historyPushJob.id, update2);
303599
303683
  historyPushLog.debug("Updated history-push progress", {
303600
303684
  jobId: historyPushJob.id,
303601
303685
  instanceId: payload.instanceId,
@@ -303774,8 +303858,17 @@ var init_follow_up_hooks = __esm(() => {
303774
303858
  });
303775
303859
 
303776
303860
  // ../api/src/plugins/instance-monitor.ts
303777
- function needsReconnect(state) {
303778
- return state === "disconnected" || state === "error";
303861
+ function needsReconnect(status) {
303862
+ if (status.state === "disconnected" || status.state === "error") {
303863
+ return true;
303864
+ }
303865
+ if (status.state === "reconnecting" || status.state === "connecting") {
303866
+ const since = status.since instanceof Date ? status.since.getTime() : Number.NaN;
303867
+ if (Number.isFinite(since) && Date.now() - since > STALE_TRANSITION_MAX_AGE_MS) {
303868
+ return true;
303869
+ }
303870
+ }
303871
+ return false;
303779
303872
  }
303780
303873
  function wasAuthenticated(instance4) {
303781
303874
  return !!instance4.ownerIdentifier;
@@ -303935,7 +304028,7 @@ class InstanceMonitor {
303935
304028
  return;
303936
304029
  try {
303937
304030
  const status = await plugin6.getStatus(instance4.id);
303938
- if (needsReconnect(status.state)) {
304031
+ if (needsReconnect(status)) {
303939
304032
  this.handleUnhealthyInstance(instance4, status.state, status.message);
303940
304033
  }
303941
304034
  } catch (error2) {
@@ -304122,7 +304215,7 @@ async function processSingleBatch(batch, registry5, db3, results) {
304122
304215
  await handleBatchResult(result, instance4, db3, results);
304123
304216
  }
304124
304217
  }
304125
- var logger7, DEFAULT_CONFIG;
304218
+ var logger7, DEFAULT_CONFIG, STALE_TRANSITION_MAX_AGE_MS;
304126
304219
  var init_instance_monitor = __esm(() => {
304127
304220
  init_src5();
304128
304221
  init_drizzle_orm();
@@ -304136,6 +304229,7 @@ var init_instance_monitor = __esm(() => {
304136
304229
  maxReconnectAttempts: 10,
304137
304230
  autoReconnect: true
304138
304231
  };
304232
+ STALE_TRANSITION_MAX_AGE_MS = 10 * 60 * 1000;
304139
304233
  });
304140
304234
 
304141
304235
  // ../api/src/plugins/index.ts
@@ -305123,7 +305217,9 @@ async function main() {
305123
305217
  try {
305124
305218
  await initializeChannelPlugins(db3, eventBus);
305125
305219
  } catch (error2) {
305126
- pluginLog.error("Failed to load channel plugins", { error: String(error2) });
305220
+ const reason = String(error2);
305221
+ pluginLog.error("Failed to load channel plugins", { error: reason });
305222
+ markPluginsDegraded(reason);
305127
305223
  }
305128
305224
  } else {
305129
305225
  pluginLog.warn("Skipping channel plugin loading (no event bus)");
@@ -308495,11 +308591,15 @@ class DiscordPlugin extends BaseChannelPlugin {
308495
308591
  }
308496
308592
  async handleMessageReceived(instanceId, externalId, chatId, from, content, replyToId, rawPayload, platformTimestamp) {
308497
308593
  const timings = platformTimestamp ? this.captureInboundTimings(platformTimestamp) : undefined;
308594
+ const senderName = typeof rawPayload.displayName === "string" ? rawPayload.displayName : undefined;
308595
+ const chatName = typeof rawPayload.chatName === "string" ? rawPayload.chatName : undefined;
308498
308596
  const correlationId = await this.emitMessageReceived({
308499
308597
  instanceId,
308500
308598
  externalId,
308501
308599
  chatId,
308502
308600
  from,
308601
+ senderName,
308602
+ chatName,
308503
308603
  content,
308504
308604
  replyToId,
308505
308605
  rawPayload,
@@ -310410,11 +310510,13 @@ class SlackPlugin extends BaseChannelPlugin {
310410
310510
  async buildEnrichedPayload(instanceId, from, rawPayload) {
310411
310511
  const displayName = await this.resolveUserDisplayName(instanceId, from);
310412
310512
  const isDm = rawPayload.isDm;
310513
+ const chatName = isDm ? displayName : undefined;
310413
310514
  return {
310414
310515
  ...rawPayload,
310415
310516
  displayName,
310517
+ senderName: displayName,
310416
310518
  pushName: displayName,
310417
- chatName: isDm ? displayName : undefined,
310519
+ chatName,
310418
310520
  isGroup: !isDm
310419
310521
  };
310420
310522
  }
@@ -310571,11 +310673,15 @@ class SlackPlugin extends BaseChannelPlugin {
310571
310673
  }
310572
310674
  async handleMessageReceived(instanceId, externalId, chatId, from, content, replyToId, rawPayload, platformTimestamp) {
310573
310675
  const timings = platformTimestamp ? this.captureInboundTimings(platformTimestamp) : undefined;
310676
+ const senderName = typeof rawPayload.senderName === "string" ? rawPayload.senderName : typeof rawPayload.displayName === "string" ? rawPayload.displayName : undefined;
310677
+ const chatName = typeof rawPayload.chatName === "string" ? rawPayload.chatName : undefined;
310574
310678
  const correlationId = await this.emitMessageReceived({
310575
310679
  instanceId,
310576
310680
  externalId,
310577
310681
  chatId,
310578
310682
  from,
310683
+ senderName,
310684
+ chatName,
310579
310685
  content,
310580
310686
  replyToId,
310581
310687
  rawPayload,
@@ -313011,7 +313117,7 @@ class TelegramPlugin extends BaseChannelPlugin {
313011
313117
  if (telegramConfig.mode === "webhook") {
313012
313118
  await this.startWebhook(bot, instanceId, telegramConfig);
313013
313119
  } else {
313014
- await this.startPolling(bot, instanceId);
313120
+ await this.startPolling(bot, instanceId, config2);
313015
313121
  }
313016
313122
  await this.updateInstanceStatus(instanceId, config2, {
313017
313123
  state: "connected",
@@ -313044,6 +313150,21 @@ class TelegramPlugin extends BaseChannelPlugin {
313044
313150
  });
313045
313151
  await this.emitInstanceDisconnected(instanceId, "Manual disconnect");
313046
313152
  }
313153
+ async getStatus(instanceId) {
313154
+ const status = await super.getStatus(instanceId);
313155
+ if (status.state !== "connected")
313156
+ return status;
313157
+ const bot = getBot(instanceId);
313158
+ const pollingAlive = bot?.isRunning ? bot.isRunning() : Boolean(bot);
313159
+ if (!pollingAlive) {
313160
+ return {
313161
+ state: "error",
313162
+ since: new Date,
313163
+ message: "Polling stopped"
313164
+ };
313165
+ }
313166
+ return status;
313167
+ }
313047
313168
  async sendMessage(instanceId, message2) {
313048
313169
  const bot = getBot(instanceId);
313049
313170
  if (!bot) {
@@ -313224,11 +313345,15 @@ class TelegramPlugin extends BaseChannelPlugin {
313224
313345
  }
313225
313346
  async handleMessageReceived(instanceId, externalId, chatId, from, content, replyToId, rawPayload, platformTimestamp) {
313226
313347
  const timings = platformTimestamp ? this.captureInboundTimings(platformTimestamp) : undefined;
313348
+ const senderName = typeof rawPayload.displayName === "string" ? rawPayload.displayName : undefined;
313349
+ const chatName = typeof rawPayload.chatName === "string" ? rawPayload.chatName : undefined;
313227
313350
  const correlationId = await this.emitMessageReceived({
313228
313351
  instanceId,
313229
313352
  externalId,
313230
313353
  chatId,
313231
313354
  from,
313355
+ senderName,
313356
+ chatName,
313232
313357
  content: {
313233
313358
  type: content.type,
313234
313359
  text: content.text,
@@ -313295,7 +313420,7 @@ class TelegramPlugin extends BaseChannelPlugin {
313295
313420
  }
313296
313421
  return checks;
313297
313422
  }
313298
- async startPolling(bot, instanceId) {
313423
+ async startPolling(bot, instanceId, config2) {
313299
313424
  this.logger.info("Starting polling mode", { instanceId });
313300
313425
  bot.start({
313301
313426
  drop_pending_updates: true,
@@ -313313,6 +313438,15 @@ class TelegramPlugin extends BaseChannelPlugin {
313313
313438
  onStart: () => {
313314
313439
  this.logger.info("Polling started", { instanceId });
313315
313440
  }
313441
+ }).catch(async (err) => {
313442
+ const message2 = `Polling stopped: ${err instanceof Error ? err.message : String(err)}`;
313443
+ this.logger.error("Polling terminated", { instanceId, error: message2 });
313444
+ await this.updateInstanceStatus(instanceId, config2, {
313445
+ state: "error",
313446
+ since: new Date,
313447
+ message: message2
313448
+ });
313449
+ await this.emitInstanceDisconnected(instanceId, message2);
313316
313450
  });
313317
313451
  }
313318
313452
  async startWebhook(_bot, instanceId, _config) {
@@ -426268,6 +426402,16 @@ class WhatsAppPlugin extends BaseChannelPlugin {
426268
426402
  }
426269
426403
  handleConnectionError(instanceId, error, willRetry) {
426270
426404
  this.logger.error("Connection error", { instanceId, error, willRetry });
426405
+ if (!willRetry) {
426406
+ const config2 = this.instances.get(instanceId)?.config;
426407
+ if (config2) {
426408
+ this.updateInstanceStatus(instanceId, config2, {
426409
+ state: "disconnected",
426410
+ since: new Date,
426411
+ message: error
426412
+ });
426413
+ }
426414
+ }
426271
426415
  }
426272
426416
  getMessageContextInfo(rawMessage) {
426273
426417
  const message2 = rawMessage.message;
@@ -426357,6 +426501,8 @@ class WhatsAppPlugin extends BaseChannelPlugin {
426357
426501
  externalId,
426358
426502
  chatId,
426359
426503
  from,
426504
+ senderName: senderPushName,
426505
+ chatName: typeof extendedPayload.chatName === "string" ? extendedPayload.chatName : undefined,
426360
426506
  content: {
426361
426507
  type: content.type,
426362
426508
  text: content.text || content.caption,
@@ -426788,11 +426934,14 @@ class WhatsAppPlugin extends BaseChannelPlugin {
426788
426934
  ...msg
426789
426935
  };
426790
426936
  this.enrichPayloadWithChatName(rawPayload, instanceId, chatId);
426937
+ const historySenderName = msg.pushName ?? undefined;
426791
426938
  await this.emitMessageReceived({
426792
426939
  instanceId,
426793
426940
  externalId: msg.key.id,
426794
426941
  chatId,
426795
426942
  from: senderId,
426943
+ senderName: historySenderName,
426944
+ chatName: typeof rawPayload.chatName === "string" ? rawPayload.chatName : undefined,
426796
426945
  content: {
426797
426946
  type: content.type,
426798
426947
  text: content.text || content.caption,
@@ -426838,7 +426987,15 @@ class WhatsAppPlugin extends BaseChannelPlugin {
426838
426987
  const totalFetched = prevCount + messageCount;
426839
426988
  this.historyPushFetchCount.set(instanceId, totalFetched);
426840
426989
  const meta = { instanceId, channelType: this.id };
426841
- this.eventBus.publishGeneric("sync.progress", { instanceId, jobType: "history-push", fetched: totalFetched, progress: progress ?? 0 }, meta).catch((err) => this.logger.warn("Failed to publish sync.progress for history-push", { error: String(err) }));
426990
+ const payload = {
426991
+ instanceId,
426992
+ jobType: "history-push",
426993
+ fetched: totalFetched
426994
+ };
426995
+ if (typeof progress === "number") {
426996
+ payload.progress = progress;
426997
+ }
426998
+ this.eventBus.publishGeneric("sync.progress", payload, meta).catch((err) => this.logger.warn("Failed to publish sync.progress for history-push", { error: String(err) }));
426842
426999
  if (isLatest || progress === 100) {
426843
427000
  this.eventBus.publishGeneric("sync.completed", { instanceId, jobType: "history-push", totalFetched }, meta).catch((err) => this.logger.warn("Failed to publish sync.completed for history-push", { error: String(err) }));
426844
427001
  this.historyPushFetchCount.delete(instanceId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260422.4",
3
+ "version": "2.260422.5",
4
4
  "description": "LLM-optimized CLI for Omni",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,14 +36,14 @@
36
36
  "qrcode-terminal": "^0.12.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@omni/api": "2.260422.3",
40
- "@omni/channel-discord": "2.260422.3",
41
- "@omni/channel-sdk": "2.260422.3",
42
- "@omni/channel-slack": "2.260422.3",
43
- "@omni/channel-telegram": "2.260422.3",
44
- "@omni/channel-whatsapp": "2.260422.3",
45
- "@omni/core": "2.260422.3",
46
- "@omni/sdk": "2.260422.3",
39
+ "@omni/api": "2.260422.4",
40
+ "@omni/channel-discord": "2.260422.4",
41
+ "@omni/channel-sdk": "2.260422.4",
42
+ "@omni/channel-slack": "2.260422.4",
43
+ "@omni/channel-telegram": "2.260422.4",
44
+ "@omni/channel-whatsapp": "2.260422.4",
45
+ "@omni/core": "2.260422.4",
46
+ "@omni/sdk": "2.260422.4",
47
47
  "@types/node": "^22.10.3",
48
48
  "@types/qrcode-terminal": "^0.12.2",
49
49
  "typescript": "^5.7.3"