@elizaos/plugin-commands 2.0.0-beta.1 → 2.0.3-beta.3

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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/auto-enable.ts +1 -1
  4. package/dist/cjs/index.cjs +959 -24
  5. package/dist/cjs/index.cjs.map +17 -6
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +959 -24
  9. package/dist/index.js.map +17 -6
  10. package/dist/src/actions/command-actions.d.ts +17 -0
  11. package/dist/src/actions/command-actions.d.ts.map +1 -0
  12. package/dist/src/actions/command-settings.d.ts +35 -0
  13. package/dist/src/actions/command-settings.d.ts.map +1 -0
  14. package/dist/src/actions/dispatch.d.ts +54 -0
  15. package/dist/src/actions/dispatch.d.ts.map +1 -0
  16. package/dist/src/actions/handlers.d.ts +26 -0
  17. package/dist/src/actions/handlers.d.ts.map +1 -0
  18. package/dist/src/actions/index.d.ts +19 -0
  19. package/dist/src/actions/index.d.ts.map +1 -0
  20. package/dist/src/actions/shortcuts.d.ts +41 -0
  21. package/dist/src/actions/shortcuts.d.ts.map +1 -0
  22. package/dist/src/connector-bridge.d.ts +128 -0
  23. package/dist/src/connector-bridge.d.ts.map +1 -0
  24. package/dist/src/connector-catalog.d.ts +71 -0
  25. package/dist/src/connector-catalog.d.ts.map +1 -0
  26. package/dist/src/index.d.ts +68 -0
  27. package/dist/src/index.d.ts.map +1 -0
  28. package/dist/src/navigation-commands.d.ts +28 -0
  29. package/dist/src/navigation-commands.d.ts.map +1 -0
  30. package/dist/src/parser.d.ts +32 -0
  31. package/dist/src/parser.d.ts.map +1 -0
  32. package/dist/src/registry.d.ts +66 -0
  33. package/dist/src/registry.d.ts.map +1 -0
  34. package/dist/src/serialize.d.ts +30 -0
  35. package/dist/src/serialize.d.ts.map +1 -0
  36. package/dist/src/settings-sections.d.ts +32 -0
  37. package/dist/src/settings-sections.d.ts.map +1 -0
  38. package/dist/src/types.d.ts +175 -0
  39. package/dist/src/types.d.ts.map +1 -0
  40. package/package.json +27 -16
  41. package/registry-entry.json +63 -0
package/dist/index.js CHANGED
@@ -97,6 +97,7 @@ var DEFAULT_COMMANDS = [
97
97
  scope: "both",
98
98
  category: "session",
99
99
  acceptsArgs: true,
100
+ requiresAuth: true,
100
101
  args: [
101
102
  { name: "instructions", description: "Optional compaction instructions" }
102
103
  ]
@@ -152,7 +153,13 @@ var DEFAULT_COMMANDS = [
152
153
  scope: "both",
153
154
  category: "options",
154
155
  acceptsArgs: true,
155
- args: [{ name: "model", description: "provider/model or alias" }]
156
+ args: [
157
+ {
158
+ name: "model",
159
+ description: "provider/model or alias",
160
+ dynamicChoices: "models"
161
+ }
162
+ ]
156
163
  },
157
164
  {
158
165
  key: "models",
@@ -267,6 +274,15 @@ var DEFAULT_COMMANDS = [
267
274
  }
268
275
  ]
269
276
  },
277
+ {
278
+ key: "transcribe",
279
+ nativeName: "transcribe",
280
+ description: "Toggle long-form transcription mode (record-only; agent stays silent until an exit phrase)",
281
+ textAliases: ["/transcribe", "/transcription", "/dictate"],
282
+ scope: "both",
283
+ category: "media",
284
+ acceptsArgs: false
285
+ },
270
286
  {
271
287
  key: "bash",
272
288
  nativeName: "bash",
@@ -301,10 +317,7 @@ function initForRuntime(agentId) {
301
317
  activeStore = store;
302
318
  }
303
319
  function useRuntime(agentId) {
304
- const store = runtimeStores.get(agentId);
305
- if (store) {
306
- activeStore = store;
307
- }
320
+ activeStore = storeForRuntime(agentId);
308
321
  }
309
322
  function getCommands() {
310
323
  return [...activeStore.commands];
@@ -363,12 +376,55 @@ function startsWithCommand(text) {
363
376
  if (normalized === alias) {
364
377
  return command;
365
378
  }
366
- if (normalized.startsWith(`${alias} `) || normalized.startsWith(`${alias}:`)) {
379
+ const remainder = normalized.slice(alias.length);
380
+ if (normalized.startsWith(alias) && /^[\s:]/.test(remainder)) {
367
381
  return command;
368
382
  }
369
383
  }
370
384
  return;
371
385
  }
386
+ function storeForRuntime(agentId) {
387
+ if (!agentId)
388
+ return fallbackStore;
389
+ return runtimeStores.get(agentId) ?? fallbackStore;
390
+ }
391
+ function getEnabledCommandsFromStore(store) {
392
+ return store.commands.filter((cmd) => cmd.enabled !== false);
393
+ }
394
+ function getCommandsByCategoryFromStore(store, category) {
395
+ return store.commands.filter((cmd) => cmd.category === category && cmd.enabled !== false);
396
+ }
397
+ function getAliasMapForStore(store) {
398
+ if (store.aliasMap)
399
+ return store.aliasMap;
400
+ store.aliasMap = new Map;
401
+ for (const command of store.commands) {
402
+ if (command.enabled === false)
403
+ continue;
404
+ for (const alias of command.textAliases) {
405
+ const normalized = alias.toLowerCase().trim();
406
+ if (!store.aliasMap.has(normalized)) {
407
+ store.aliasMap.set(normalized, command);
408
+ }
409
+ }
410
+ }
411
+ return store.aliasMap;
412
+ }
413
+ function getCommandsForRuntime(agentId) {
414
+ return [...storeForRuntime(agentId).commands];
415
+ }
416
+ function getEnabledCommandsForRuntime(agentId) {
417
+ return getEnabledCommandsFromStore(storeForRuntime(agentId));
418
+ }
419
+ function getCommandsByCategoryForRuntime(category, agentId) {
420
+ return getCommandsByCategoryFromStore(storeForRuntime(agentId), category);
421
+ }
422
+ function findCommandByAliasForRuntime(alias, agentId) {
423
+ return getAliasMapForStore(storeForRuntime(agentId)).get(alias.toLowerCase().trim());
424
+ }
425
+ function findCommandByKeyForRuntime(key, agentId) {
426
+ return storeForRuntime(agentId).commands.find((c) => c.key === key);
427
+ }
372
428
 
373
429
  // src/parser.ts
374
430
  var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -407,7 +463,8 @@ function parseCommand(text, definition) {
407
463
  matchedAlias = alias;
408
464
  break;
409
465
  }
410
- if (trimmed.toLowerCase().startsWith(`${normalized} `) || trimmed.toLowerCase().startsWith(`${normalized}:`)) {
466
+ const remainder = trimmed.slice(alias.length);
467
+ if (trimmed.toLowerCase().startsWith(normalized) && /^[\s:]/.test(remainder)) {
411
468
  matchedAlias = alias;
412
469
  break;
413
470
  }
@@ -420,12 +477,15 @@ function parseCommand(text, definition) {
420
477
  rawArgs = rawArgs.slice(1).trim();
421
478
  }
422
479
  const args = parseArgs(rawArgs, definition);
423
- return {
480
+ const parsed = {
424
481
  key: definition.key,
425
482
  canonical: definition.textAliases[0] ?? `/${definition.key}`,
426
- args,
427
- rawArgs: rawArgs || undefined
483
+ args
428
484
  };
485
+ if (rawArgs) {
486
+ parsed.rawArgs = rawArgs;
487
+ }
488
+ return parsed;
429
489
  }
430
490
  function parseArgs(rawArgs, definition) {
431
491
  if (!rawArgs || !definition.acceptsArgs) {
@@ -438,13 +498,13 @@ function parseArgs(rawArgs, definition) {
438
498
  const args = [];
439
499
  const argDefs = definition.args ?? [];
440
500
  const tokens = tokenize(rawArgs);
441
- for (let i = 0;i < tokens.length; i++) {
501
+ for (const [i, token] of tokens.entries()) {
442
502
  const argDef = argDefs[i];
443
503
  if (argDef?.captureRemaining) {
444
504
  args.push(tokens.slice(i).join(" "));
445
505
  break;
446
506
  }
447
- args.push(tokens[i]);
507
+ args.push(token);
448
508
  }
449
509
  return args;
450
510
  }
@@ -453,8 +513,7 @@ function tokenize(input) {
453
513
  let current = "";
454
514
  let inQuote = false;
455
515
  let quoteChar = "";
456
- for (let i = 0;i < input.length; i++) {
457
- const char = input[i];
516
+ for (const char of input) {
458
517
  if (inQuote) {
459
518
  if (char === quoteChar) {
460
519
  inQuote = false;
@@ -488,7 +547,7 @@ function normalizeCommandBody(text, botMention) {
488
547
  const mentionPattern = new RegExp(`^@${escapeRegExp(botMention)}\\s*`, "i");
489
548
  normalized = normalized.replace(mentionPattern, "");
490
549
  }
491
- normalized = normalized.replace(/^(\/\w+):\s*/, "$1 ");
550
+ normalized = normalized.replace(/^([/!][^\s:]+):\s*/, "$1 ");
492
551
  return normalized.trim();
493
552
  }
494
553
  function isCommandOnly(text) {
@@ -513,6 +572,849 @@ function extractCommand(text) {
513
572
  return { command, remainingText: command.rawArgs };
514
573
  }
515
574
 
575
+ // src/actions/command-settings.ts
576
+ var COMMAND_SETTING_CHOICES = {
577
+ thinking: ["off", "minimal", "low", "medium", "high", "xhigh"],
578
+ verbose: ["off", "on", "full"],
579
+ reasoning: ["off", "on", "stream"],
580
+ queue: ["steer", "followup", "collect", "interrupt"],
581
+ elevated: ["off", "on", "ask", "full"],
582
+ model: null,
583
+ tts: ["on", "off"]
584
+ };
585
+ function cacheKey(roomId) {
586
+ return `command-settings:${roomId}`;
587
+ }
588
+ async function clearCommandSettings(runtime, roomId) {
589
+ return runtime.deleteCache(cacheKey(roomId));
590
+ }
591
+ async function getCommandSettings(runtime, roomId) {
592
+ const stored = await runtime.getCache(cacheKey(roomId));
593
+ return stored ?? {};
594
+ }
595
+ async function setCommandSetting(runtime, roomId, key, rawValue) {
596
+ const value = rawValue.trim().toLowerCase();
597
+ const choices = COMMAND_SETTING_CHOICES[key];
598
+ if (choices && !choices.includes(value)) {
599
+ return {
600
+ error: `Invalid ${key} value "${rawValue}". Choose one of: ${choices.join(", ")}.`
601
+ };
602
+ }
603
+ const normalized = choices ? value : rawValue.trim();
604
+ const current = await getCommandSettings(runtime, roomId);
605
+ await runtime.setCache(cacheKey(roomId), {
606
+ ...current,
607
+ [key]: normalized
608
+ });
609
+ return { value: normalized };
610
+ }
611
+
612
+ // src/actions/handlers.ts
613
+ var DETERMINISTIC_COMMAND_KEYS = [
614
+ "help",
615
+ "commands",
616
+ "status",
617
+ "whoami",
618
+ "context",
619
+ "reset",
620
+ "new",
621
+ "compact",
622
+ "models",
623
+ "usage",
624
+ "think",
625
+ "verbose",
626
+ "reasoning",
627
+ "queue",
628
+ "elevated",
629
+ "model",
630
+ "tts"
631
+ ];
632
+ var DETERMINISTIC_KEYS = new Set(DETERMINISTIC_COMMAND_KEYS);
633
+ function isDeterministicCommand(key) {
634
+ return DETERMINISTIC_KEYS.has(key);
635
+ }
636
+ var CATEGORY_ORDER = [
637
+ "status",
638
+ "session",
639
+ "options",
640
+ "media",
641
+ "management",
642
+ "tools",
643
+ "docks",
644
+ "skills"
645
+ ];
646
+ var OPTION_COMMANDS = {
647
+ think: { key: "thinking", label: "Thinking" },
648
+ verbose: { key: "verbose", label: "Verbose" },
649
+ reasoning: { key: "reasoning", label: "Reasoning" },
650
+ queue: { key: "queue", label: "Queue mode" },
651
+ elevated: { key: "elevated", label: "Elevated mode" },
652
+ model: { key: "model", label: "Model" },
653
+ tts: { key: "tts", label: "TTS" }
654
+ };
655
+ function reply(text) {
656
+ return { handled: true, reply: text, shouldContinue: false };
657
+ }
658
+ function authError() {
659
+ return reply("This command requires authorization.");
660
+ }
661
+ function formatCommandList(agentId) {
662
+ const lines = [];
663
+ for (const category of CATEGORY_ORDER) {
664
+ const commands = getCommandsByCategoryForRuntime(category, agentId);
665
+ if (commands.length === 0)
666
+ continue;
667
+ lines.push(`**${category}**`);
668
+ for (const command of commands) {
669
+ const alias = command.textAliases[0] ?? `/${command.key}`;
670
+ const auth = command.requiresAuth ? " (requires auth)" : "";
671
+ lines.push(` ${alias} — ${command.description}${auth}`);
672
+ }
673
+ }
674
+ return lines.join(`
675
+ `);
676
+ }
677
+ function resolveModelLabel(runtime) {
678
+ const fromSetting = runtime.getSetting("LARGE_MODEL") ?? runtime.getSetting("ANTHROPIC_LARGE_MODEL") ?? runtime.getSetting("OPENAI_LARGE_MODEL");
679
+ if (typeof fromSetting === "string" && fromSetting.trim()) {
680
+ return fromSetting.trim();
681
+ }
682
+ const fromCharacter = runtime.character?.settings?.model;
683
+ if (typeof fromCharacter === "string" && fromCharacter.trim()) {
684
+ return fromCharacter.trim();
685
+ }
686
+ return "default";
687
+ }
688
+ async function countRoomMessages(runtime, roomId) {
689
+ if (typeof runtime.countMemories !== "function")
690
+ return null;
691
+ try {
692
+ return await runtime.countMemories({
693
+ roomIds: [roomId],
694
+ tableName: "messages",
695
+ unique: false
696
+ });
697
+ } catch {
698
+ return null;
699
+ }
700
+ }
701
+ async function clearRoomMessages(runtime, roomId) {
702
+ const before = await countRoomMessages(runtime, roomId);
703
+ if (typeof runtime.deleteAllMemories !== "function")
704
+ return null;
705
+ await runtime.deleteAllMemories([roomId], "messages");
706
+ return before;
707
+ }
708
+ function findAction(runtime, name) {
709
+ return runtime.actions?.find((action) => action.name === name);
710
+ }
711
+ async function runCompactAction(runtime, message, callback) {
712
+ const action = findAction(runtime, "COMPACT_CONVERSATION");
713
+ if (!action || !message) {
714
+ return reply("Conversation compaction is not available in this runtime.");
715
+ }
716
+ const result = await action.handler(runtime, message, undefined, undefined, callback);
717
+ if (result?.text && result.text.trim().length > 0)
718
+ return reply(result.text);
719
+ return reply("Conversation compaction completed.");
720
+ }
721
+ async function setOptionCommand(runtime, roomId, parsed, option) {
722
+ const rawValue = parsed.rawArgs?.trim() ?? parsed.args[0]?.trim() ?? "";
723
+ if (!rawValue) {
724
+ const settings = await getCommandSettings(runtime, roomId);
725
+ const current = option.key === "model" ? settings.model ?? resolveModelLabel(runtime) : settings[option.key] ?? "default";
726
+ return reply(`${option.label} is ${current}.`);
727
+ }
728
+ const result = await setCommandSetting(runtime, roomId, option.key, rawValue);
729
+ if ("error" in result)
730
+ return reply(result.error);
731
+ return reply(`${option.label} set to ${result.value}.`);
732
+ }
733
+ async function runCommand(runtime, parsed, context) {
734
+ const agentId = runtime.agentId;
735
+ useRuntime(agentId);
736
+ const definition = findCommandByKeyForRuntime(parsed.key, agentId);
737
+ if (definition?.requiresAuth && !context.isAuthorized)
738
+ return authError();
739
+ if (definition?.requiresElevated && !context.isElevated) {
740
+ return reply("This command requires elevated permissions.");
741
+ }
742
+ const roomId = context.roomId;
743
+ switch (parsed.key) {
744
+ case "help":
745
+ case "commands":
746
+ return reply(`Available commands:
747
+ ${formatCommandList(agentId)}`);
748
+ case "status": {
749
+ const settings = await getCommandSettings(runtime, roomId);
750
+ const messageCount = await countRoomMessages(runtime, roomId);
751
+ const lines = [
752
+ `Agent: ${runtime.character?.name ?? runtime.agentId}`,
753
+ `Model: ${settings.model ?? resolveModelLabel(runtime)}`,
754
+ `Thinking: ${settings.thinking ?? "default"}`,
755
+ `Reasoning: ${settings.reasoning ?? "default"}`,
756
+ `Verbose: ${settings.verbose ?? "default"}`,
757
+ `Queue: ${settings.queue ?? "default"}`,
758
+ `TTS: ${settings.tts ?? "default"}`,
759
+ messageCount === null ? null : `Messages: ${messageCount}`,
760
+ `Commands enabled: ${getEnabledCommandsForRuntime(agentId).length}`
761
+ ].filter(Boolean);
762
+ return reply(lines.join(`
763
+ `));
764
+ }
765
+ case "whoami": {
766
+ const who = context.senderName ?? context.senderId ?? "you";
767
+ return reply(`You are ${who}.
768
+ Authorized: ${context.isAuthorized ? "yes" : "no"}
769
+ Elevated: ${context.isElevated ? "yes" : "no"}`);
770
+ }
771
+ case "context": {
772
+ const settings = await getCommandSettings(runtime, roomId);
773
+ const lines = [
774
+ `Room: ${roomId}`,
775
+ context.channelId ? `Channel: ${context.channelId}` : null,
776
+ `Active settings: ${describeSettings(settings)}`
777
+ ].filter(Boolean);
778
+ return reply(lines.join(`
779
+ `));
780
+ }
781
+ case "models":
782
+ return reply(`Current model: ${resolveModelLabel(runtime)}`);
783
+ case "usage": {
784
+ const usage = await runtime.getCache(`token-usage:${roomId}`);
785
+ if (!usage?.totalTokens) {
786
+ return reply("No token usage recorded for this conversation yet.");
787
+ }
788
+ return reply(`Token usage — prompt: ${usage.promptTokens ?? 0}, completion: ${usage.completionTokens ?? 0}, total: ${usage.totalTokens}.`);
789
+ }
790
+ case "think":
791
+ case "verbose":
792
+ case "reasoning":
793
+ case "queue":
794
+ case "elevated":
795
+ case "model":
796
+ case "tts":
797
+ return setOptionCommand(runtime, roomId, parsed, OPTION_COMMANDS[parsed.key]);
798
+ case "reset": {
799
+ await clearCommandSettings(runtime, roomId);
800
+ const deleted = await clearRoomMessages(runtime, roomId);
801
+ if (deleted === null) {
802
+ return reply("Reset command settings for this room. Message history is unchanged because memory deletion is unavailable.");
803
+ }
804
+ return reply(`Reset this room: cleared command settings and ${deleted} message(s).`);
805
+ }
806
+ case "new":
807
+ await clearCommandSettings(runtime, roomId);
808
+ return reply("Started a new conversation context for this room.");
809
+ case "compact":
810
+ return runCompactAction(runtime, context.message, context.callback);
811
+ default:
812
+ return { handled: false, shouldContinue: true };
813
+ }
814
+ }
815
+ function describeSettings(settings) {
816
+ const entries = Object.entries(settings).filter(([, v]) => v);
817
+ if (entries.length === 0)
818
+ return "none";
819
+ return entries.map(([k, v]) => `${k}=${v}`).join(", ");
820
+ }
821
+
822
+ // src/actions/dispatch.ts
823
+ function buildContext(message, options) {
824
+ const content = message.content;
825
+ const context = {
826
+ senderId: message.entityId,
827
+ isAuthorized: options.isAuthorized ?? false,
828
+ isElevated: options.isElevated ?? false,
829
+ roomId: message.roomId,
830
+ message
831
+ };
832
+ if (options.senderName)
833
+ context.senderName = options.senderName;
834
+ if (options.callback)
835
+ context.callback = options.callback;
836
+ const channelId = content.channelId ?? content.source;
837
+ if (channelId)
838
+ context.channelId = channelId;
839
+ return context;
840
+ }
841
+ async function resolveCommand(runtime, message, options = {}) {
842
+ const text = message.content.text ?? "";
843
+ if (!hasCommand(text))
844
+ return { handled: false };
845
+ const detection = detectCommand(text);
846
+ if (!detection.isCommand || !detection.command)
847
+ return { handled: false };
848
+ const parsed = detection.command;
849
+ const definition = findCommandByKeyForRuntime(parsed.key, runtime.agentId);
850
+ if (definition?.target && definition.target.kind !== "agent") {
851
+ return { handled: false, command: parsed };
852
+ }
853
+ const deterministicOnly = options.deterministicOnly ?? options.gateSafeOnly ?? true;
854
+ if (deterministicOnly && !isDeterministicCommand(parsed.key)) {
855
+ return { handled: false, command: parsed };
856
+ }
857
+ const result = await runCommand(runtime, parsed, buildContext(message, options));
858
+ if (!result.handled)
859
+ return { handled: false, command: parsed };
860
+ const dispatched = { handled: true, command: parsed };
861
+ if (result.reply !== undefined)
862
+ dispatched.reply = result.reply;
863
+ return dispatched;
864
+ }
865
+ async function dispatchCommandMessage(runtime, message, callback, options = {}) {
866
+ const result = await resolveCommand(runtime, message, options);
867
+ if (!result.handled || result.reply === undefined)
868
+ return false;
869
+ await callback({ text: result.reply, source: "command" });
870
+ return true;
871
+ }
872
+
873
+ // src/actions/command-actions.ts
874
+ var OWNER_SOURCES = new Set([
875
+ "client_chat",
876
+ "gui",
877
+ "tui",
878
+ "direct",
879
+ "dashboard"
880
+ ]);
881
+ function resolveTrust(message) {
882
+ const source = message.content.source;
883
+ const trusted = !source || OWNER_SOURCES.has(source);
884
+ return { isAuthorized: trusted, isElevated: trusted };
885
+ }
886
+ function buildAction(key, _nativeName, description, aliases) {
887
+ return {
888
+ name: `${key.toUpperCase()}_COMMAND`,
889
+ description,
890
+ similes: aliases,
891
+ suppressEarlyReply: true,
892
+ suppressPostActionContinuation: true,
893
+ validate: async (_runtime, message) => {
894
+ const text = message.content.text ?? "";
895
+ if (!hasCommand(text))
896
+ return false;
897
+ const detection = detectCommand(text);
898
+ return detection.isCommand && detection.command?.key === key;
899
+ },
900
+ handler: async (runtime, message, _state, _options, callback) => {
901
+ const result = await resolveCommand(runtime, message, {
902
+ ...resolveTrust(message),
903
+ deterministicOnly: true,
904
+ ...callback ? { callback } : {}
905
+ });
906
+ if (!result.handled || result.reply === undefined) {
907
+ return { success: false };
908
+ }
909
+ if (callback) {
910
+ await callback({ text: result.reply, source: "command" });
911
+ }
912
+ return { success: true, text: result.reply };
913
+ }
914
+ };
915
+ }
916
+ function createCommandActions(commandKeys) {
917
+ const actions = [];
918
+ for (const key of commandKeys) {
919
+ if (!isDeterministicCommand(key))
920
+ continue;
921
+ const definition = findCommandByKey(key);
922
+ if (!definition)
923
+ continue;
924
+ if (definition.target && definition.target.kind !== "agent")
925
+ continue;
926
+ actions.push(buildAction(key, definition.nativeName ?? key, definition.description, definition.textAliases));
927
+ }
928
+ return actions;
929
+ }
930
+ // src/actions/shortcuts.ts
931
+ function createCommandShortcuts(commandKeys = DETERMINISTIC_COMMAND_KEYS) {
932
+ const shortcuts = [];
933
+ for (const key of commandKeys) {
934
+ const definition = findCommandByKey(key);
935
+ if (!definition)
936
+ continue;
937
+ if (definition.target && definition.target.kind !== "agent")
938
+ continue;
939
+ shortcuts.push({
940
+ id: `cmd:${key}`,
941
+ kind: "explicit",
942
+ aliases: definition.textAliases,
943
+ target: { kind: "action", name: `${key.toUpperCase()}_COMMAND` }
944
+ });
945
+ }
946
+ return shortcuts;
947
+ }
948
+ var explicitCommandShortcuts = createCommandShortcuts();
949
+ var naturalShortcuts = [
950
+ {
951
+ id: "nl:commands",
952
+ kind: "natural",
953
+ patterns: [
954
+ {
955
+ regex: /^what commands (?:can i (?:use|run)|are (?:there|available)|do you (?:have|support))$/u
956
+ },
957
+ {
958
+ regex: /^(?:show|list|give|tell)(?: me)?(?: a list of| the list of| all(?: of)?| the| your| available)* commands$/u
959
+ },
960
+ { regex: /^what are(?: all)?(?: the| your| available)* commands$/u }
961
+ ],
962
+ target: { kind: "action", name: "COMMANDS_COMMAND" },
963
+ requiresAction: "COMMANDS_COMMAND",
964
+ confidence: 0.95
965
+ }
966
+ ];
967
+ var commandShortcuts = [
968
+ ...explicitCommandShortcuts,
969
+ ...naturalShortcuts
970
+ ];
971
+
972
+ // src/actions/index.ts
973
+ var commandActions = createCommandActions([
974
+ ...DETERMINISTIC_COMMAND_KEYS
975
+ ]);
976
+ // src/connector-bridge.ts
977
+ function resolveConnectorCommandAuth(agentId, name) {
978
+ const definition = findCommandByKeyForRuntime(name, agentId);
979
+ return {
980
+ requiresAuth: definition?.requiresAuth ?? false,
981
+ requiresElevated: definition?.requiresElevated ?? false
982
+ };
983
+ }
984
+ function gateConnectorCommand(requirements, sender) {
985
+ if (requirements.requiresAuth && !sender.isAuthorized) {
986
+ return {
987
+ allowed: false,
988
+ reply: "This command requires authorization. Pair your account or ask an owner to run it."
989
+ };
990
+ }
991
+ if (requirements.requiresElevated && !sender.isElevated) {
992
+ return {
993
+ allowed: false,
994
+ reply: "This command requires elevated permissions."
995
+ };
996
+ }
997
+ return { allowed: true };
998
+ }
999
+ function gateConnectorCommandByName(agentId, name, sender) {
1000
+ return gateConnectorCommand(resolveConnectorCommandAuth(agentId, name), sender);
1001
+ }
1002
+ // src/settings-sections.ts
1003
+ var SETTINGS_SECTIONS = [
1004
+ {
1005
+ id: "ai-model",
1006
+ label: "AI Model & Providers",
1007
+ aliases: ["model", "models", "providers", "provider", "llm"]
1008
+ },
1009
+ { id: "general", label: "General", aliases: ["basics"] },
1010
+ { id: "agent", label: "Agent", aliases: ["character", "persona"] },
1011
+ { id: "voice", label: "Voice", aliases: ["audio", "tts", "speech"] },
1012
+ { id: "connectors", label: "Connectors", aliases: ["integrations"] },
1013
+ { id: "skills", label: "Skills" },
1014
+ { id: "memory", label: "Memory", aliases: ["knowledge"] },
1015
+ { id: "permissions", label: "Permissions", aliases: ["security", "access"] },
1016
+ { id: "billing", label: "Billing", aliases: ["plan", "subscription"] },
1017
+ { id: "appearance", label: "Appearance", aliases: ["theme", "display"] },
1018
+ { id: "notifications", label: "Notifications", aliases: ["alerts"] },
1019
+ { id: "advanced", label: "Advanced", aliases: ["developer", "debug"] }
1020
+ ];
1021
+ var lookup = null;
1022
+ function getLookup() {
1023
+ if (lookup)
1024
+ return lookup;
1025
+ const map = new Map;
1026
+ for (const section of SETTINGS_SECTIONS) {
1027
+ map.set(section.id, section);
1028
+ for (const alias of section.aliases ?? []) {
1029
+ map.set(alias, section);
1030
+ }
1031
+ }
1032
+ lookup = map;
1033
+ return map;
1034
+ }
1035
+ function getSettingsSections() {
1036
+ return [...SETTINGS_SECTIONS];
1037
+ }
1038
+ function getSettingsSectionChoices() {
1039
+ return SETTINGS_SECTIONS.map((section) => section.id);
1040
+ }
1041
+ function resolveSettingsSection(raw) {
1042
+ const normalized = raw.trim().toLowerCase();
1043
+ if (!normalized)
1044
+ return;
1045
+ return getLookup().get(normalized)?.id;
1046
+ }
1047
+
1048
+ // src/navigation-commands.ts
1049
+ var IN_APP_SURFACES = ["gui", "tui"];
1050
+ var NAVIGATE_COMMANDS = [
1051
+ {
1052
+ key: "settings",
1053
+ nativeName: "settings",
1054
+ description: "Open agent settings",
1055
+ textAliases: ["/settings"],
1056
+ scope: "both",
1057
+ category: "docks",
1058
+ icon: "settings",
1059
+ target: { kind: "navigate", path: "/settings", tab: "settings" },
1060
+ acceptsArgs: true,
1061
+ args: [
1062
+ {
1063
+ name: "section",
1064
+ description: "Settings section to open",
1065
+ required: false,
1066
+ choices: getSettingsSectionChoices(),
1067
+ dynamicChoices: "settings-sections"
1068
+ }
1069
+ ]
1070
+ },
1071
+ {
1072
+ key: "chat",
1073
+ nativeName: "chat",
1074
+ description: "Return to the chat",
1075
+ textAliases: ["/chat"],
1076
+ scope: "both",
1077
+ category: "docks",
1078
+ icon: "message-circle",
1079
+ target: { kind: "navigate", path: "/chat", tab: "chat" }
1080
+ },
1081
+ {
1082
+ key: "views",
1083
+ nativeName: "views",
1084
+ description: "Open the agent's views",
1085
+ textAliases: ["/views"],
1086
+ scope: "both",
1087
+ category: "docks",
1088
+ icon: "layout-grid",
1089
+ target: { kind: "navigate", path: "/views", tab: "views" },
1090
+ acceptsArgs: true,
1091
+ args: [
1092
+ {
1093
+ name: "view",
1094
+ description: "View to open",
1095
+ required: false,
1096
+ dynamicChoices: "views"
1097
+ }
1098
+ ]
1099
+ },
1100
+ {
1101
+ key: "orchestrator",
1102
+ nativeName: "orchestrator",
1103
+ description: "Open the agent orchestrator",
1104
+ textAliases: ["/orchestrator"],
1105
+ scope: "both",
1106
+ category: "docks",
1107
+ icon: "workflow",
1108
+ target: { kind: "navigate", path: "/orchestrator", viewId: "orchestrator" }
1109
+ },
1110
+ {
1111
+ key: "character",
1112
+ nativeName: "character",
1113
+ description: "Open the character editor",
1114
+ textAliases: ["/character"],
1115
+ scope: "both",
1116
+ category: "docks",
1117
+ icon: "user",
1118
+ target: { kind: "navigate", path: "/character", tab: "character" }
1119
+ },
1120
+ {
1121
+ key: "knowledge",
1122
+ nativeName: "knowledge",
1123
+ description: "Open the knowledge base",
1124
+ textAliases: ["/knowledge"],
1125
+ scope: "both",
1126
+ category: "docks",
1127
+ icon: "book-open",
1128
+ target: {
1129
+ kind: "navigate",
1130
+ path: "/character/documents",
1131
+ tab: "documents"
1132
+ }
1133
+ },
1134
+ {
1135
+ key: "wallet",
1136
+ nativeName: "wallet",
1137
+ description: "Open the wallet & inventory",
1138
+ textAliases: ["/wallet"],
1139
+ scope: "both",
1140
+ category: "docks",
1141
+ icon: "wallet",
1142
+ target: { kind: "navigate", path: "/wallet", tab: "inventory" }
1143
+ },
1144
+ {
1145
+ key: "automations",
1146
+ nativeName: "automations",
1147
+ description: "Open automations",
1148
+ textAliases: ["/automations"],
1149
+ scope: "both",
1150
+ category: "docks",
1151
+ icon: "zap",
1152
+ target: { kind: "navigate", path: "/automations", tab: "automations" }
1153
+ },
1154
+ {
1155
+ key: "tasks",
1156
+ nativeName: "tasks",
1157
+ description: "Open tasks",
1158
+ textAliases: ["/tasks"],
1159
+ scope: "both",
1160
+ category: "docks",
1161
+ icon: "check-square",
1162
+ target: { kind: "navigate", path: "/apps/tasks", tab: "tasks" }
1163
+ },
1164
+ {
1165
+ key: "skills",
1166
+ nativeName: "skills",
1167
+ description: "Open the skills library",
1168
+ textAliases: ["/skills"],
1169
+ scope: "both",
1170
+ category: "docks",
1171
+ icon: "sparkles",
1172
+ target: { kind: "navigate", path: "/apps/skills", tab: "skills" }
1173
+ },
1174
+ {
1175
+ key: "plugins",
1176
+ nativeName: "plugins",
1177
+ description: "Open installed plugins",
1178
+ textAliases: ["/plugins"],
1179
+ scope: "both",
1180
+ category: "docks",
1181
+ icon: "plug",
1182
+ target: { kind: "navigate", path: "/apps/plugins", tab: "plugins" }
1183
+ },
1184
+ {
1185
+ key: "logs",
1186
+ nativeName: "logs",
1187
+ description: "Open the logs",
1188
+ textAliases: ["/logs"],
1189
+ scope: "both",
1190
+ category: "docks",
1191
+ icon: "scroll-text",
1192
+ target: { kind: "navigate", path: "/apps/logs", tab: "logs" }
1193
+ },
1194
+ {
1195
+ key: "database",
1196
+ nativeName: "database",
1197
+ description: "Open the database browser",
1198
+ textAliases: ["/database"],
1199
+ scope: "both",
1200
+ category: "docks",
1201
+ icon: "database",
1202
+ target: { kind: "navigate", path: "/apps/database", tab: "database" }
1203
+ }
1204
+ ];
1205
+ var CLIENT_COMMANDS = [
1206
+ {
1207
+ key: "clear",
1208
+ nativeName: "clear",
1209
+ description: "Clear the current chat",
1210
+ textAliases: ["/clear"],
1211
+ scope: "both",
1212
+ category: "docks",
1213
+ icon: "eraser",
1214
+ surfaces: IN_APP_SURFACES,
1215
+ target: { kind: "client", clientAction: "clear-chat" }
1216
+ },
1217
+ {
1218
+ key: "fullscreen",
1219
+ nativeName: "fullscreen",
1220
+ description: "Toggle full-screen chat",
1221
+ textAliases: ["/fullscreen"],
1222
+ scope: "both",
1223
+ category: "docks",
1224
+ icon: "maximize",
1225
+ surfaces: IN_APP_SURFACES,
1226
+ target: { kind: "client", clientAction: "toggle-fullscreen" }
1227
+ },
1228
+ {
1229
+ key: "transcribe",
1230
+ nativeName: "transcribe",
1231
+ description: "Toggle long-form transcription mode (record-only; agent stays silent until an exit phrase)",
1232
+ textAliases: ["/transcribe"],
1233
+ scope: "both",
1234
+ category: "docks",
1235
+ icon: "mic",
1236
+ surfaces: IN_APP_SURFACES,
1237
+ target: { kind: "client", clientAction: "toggle-transcription" }
1238
+ }
1239
+ ];
1240
+ var VIEW_SCOPED_COMMANDS = [
1241
+ {
1242
+ key: "calendar-add",
1243
+ nativeName: "calendar-add",
1244
+ description: "Add a calendar event (in the calendar view)",
1245
+ textAliases: ["/calendar-add"],
1246
+ scope: "both",
1247
+ category: "docks",
1248
+ icon: "calendar-plus",
1249
+ surfaces: IN_APP_SURFACES,
1250
+ views: ["calendar"],
1251
+ target: { kind: "agent" },
1252
+ acceptsArgs: true,
1253
+ args: [{ name: "event", description: "What to schedule", required: false }]
1254
+ },
1255
+ {
1256
+ key: "todos-add",
1257
+ nativeName: "todos-add",
1258
+ description: "Add a to-do (in the todos view)",
1259
+ textAliases: ["/todos-add"],
1260
+ scope: "both",
1261
+ category: "docks",
1262
+ icon: "list-plus",
1263
+ surfaces: IN_APP_SURFACES,
1264
+ views: ["todos"],
1265
+ target: { kind: "agent" },
1266
+ acceptsArgs: true,
1267
+ args: [{ name: "task", description: "What to do", required: false }]
1268
+ },
1269
+ {
1270
+ key: "todos-done",
1271
+ nativeName: "todos-done",
1272
+ description: "Complete a to-do (in the todos view)",
1273
+ textAliases: ["/todos-done"],
1274
+ scope: "both",
1275
+ category: "docks",
1276
+ icon: "check",
1277
+ surfaces: IN_APP_SURFACES,
1278
+ views: ["todos"],
1279
+ target: { kind: "agent" },
1280
+ acceptsArgs: true,
1281
+ args: [
1282
+ { name: "task", description: "Which to-do to complete", required: false }
1283
+ ]
1284
+ },
1285
+ {
1286
+ key: "documents-search",
1287
+ nativeName: "documents-search",
1288
+ description: "Search the knowledge base (in the documents view)",
1289
+ textAliases: ["/documents-search"],
1290
+ scope: "both",
1291
+ category: "docks",
1292
+ icon: "search",
1293
+ surfaces: IN_APP_SURFACES,
1294
+ views: ["documents"],
1295
+ target: { kind: "agent" },
1296
+ acceptsArgs: true,
1297
+ args: [
1298
+ { name: "query", description: "What to search for", required: false }
1299
+ ]
1300
+ }
1301
+ ];
1302
+ function navigationCommandDefinitions() {
1303
+ return [...NAVIGATE_COMMANDS, ...CLIENT_COMMANDS, ...VIEW_SCOPED_COMMANDS];
1304
+ }
1305
+
1306
+ // src/serialize.ts
1307
+ var DEFAULT_TARGET = { kind: "agent" };
1308
+ function commandVisibleForSurface(surfaces, surface) {
1309
+ if (!surface)
1310
+ return true;
1311
+ if (!surfaces || surfaces.length === 0)
1312
+ return true;
1313
+ return surfaces.includes(surface);
1314
+ }
1315
+ function serializeArg(arg) {
1316
+ const serialized = {
1317
+ name: arg.name,
1318
+ description: arg.description
1319
+ };
1320
+ if (arg.required)
1321
+ serialized.required = true;
1322
+ if (arg.captureRemaining)
1323
+ serialized.captureRemaining = true;
1324
+ if (arg.dynamicChoices)
1325
+ serialized.dynamicChoices = arg.dynamicChoices;
1326
+ if (Array.isArray(arg.choices) && arg.choices.length > 0) {
1327
+ serialized.choices = arg.choices;
1328
+ }
1329
+ return serialized;
1330
+ }
1331
+ function serializeCommand(command, options = {}) {
1332
+ const args = (command.args ?? []).map(serializeArg);
1333
+ const serialized = {
1334
+ key: command.key,
1335
+ nativeName: command.nativeName ?? command.key,
1336
+ description: command.description,
1337
+ textAliases: command.textAliases,
1338
+ scope: command.scope,
1339
+ acceptsArgs: command.acceptsArgs ?? args.length > 0,
1340
+ args,
1341
+ requiresAuth: command.requiresAuth ?? false,
1342
+ requiresElevated: command.requiresElevated ?? false,
1343
+ target: command.target ?? DEFAULT_TARGET,
1344
+ source: options.source ?? "builtin"
1345
+ };
1346
+ if (command.category)
1347
+ serialized.category = command.category;
1348
+ if (command.surfaces && command.surfaces.length > 0) {
1349
+ serialized.surfaces = command.surfaces;
1350
+ }
1351
+ if (command.icon)
1352
+ serialized.icon = command.icon;
1353
+ if (command.views && command.views.length > 0) {
1354
+ serialized.views = command.views;
1355
+ }
1356
+ return serialized;
1357
+ }
1358
+
1359
+ // src/connector-catalog.ts
1360
+ var KNOWN_SURFACES = new Set([
1361
+ "gui",
1362
+ "tui",
1363
+ "discord",
1364
+ "telegram"
1365
+ ]);
1366
+ function commandVisibleForView(views, activeViewId) {
1367
+ if (!views || views.length === 0)
1368
+ return true;
1369
+ if (!activeViewId)
1370
+ return false;
1371
+ return views.includes(activeViewId);
1372
+ }
1373
+ function isConnectorScoped(command) {
1374
+ return command.scope !== "text";
1375
+ }
1376
+ function commandName(command) {
1377
+ return command.nativeName ?? command.key;
1378
+ }
1379
+ function unifiedDefinitions(agentId) {
1380
+ const agentCommands = agentId ? getEnabledCommandsForRuntime(agentId) : DEFAULT_COMMANDS.filter((command) => command.enabled !== false);
1381
+ const agent = agentCommands.filter(isConnectorScoped);
1382
+ const navigation = navigationCommandDefinitions();
1383
+ const navigationNames = new Set(navigation.map(commandName));
1384
+ const agentOnly = agent.filter((command) => !navigationNames.has(commandName(command)));
1385
+ return [...agentOnly, ...navigation];
1386
+ }
1387
+ function normalizeSurface(surface) {
1388
+ return KNOWN_SURFACES.has(surface) ? surface : null;
1389
+ }
1390
+ function visibleDefinitions(surface, activeViewId, agentId) {
1391
+ const normalized = normalizeSurface(surface);
1392
+ return unifiedDefinitions(agentId).filter((command) => commandVisibleForSurface(command.surfaces, normalized)).filter((command) => commandVisibleForView(command.views, activeViewId));
1393
+ }
1394
+ function mapDefinitionArg(arg) {
1395
+ return {
1396
+ name: arg.name,
1397
+ description: arg.description,
1398
+ required: arg.required ?? false,
1399
+ choices: Array.isArray(arg.choices) ? arg.choices : []
1400
+ };
1401
+ }
1402
+ function toConnectorCommand(command) {
1403
+ return {
1404
+ name: commandName(command),
1405
+ description: command.description,
1406
+ target: command.target ?? { kind: "agent" },
1407
+ options: (command.args ?? []).map(mapDefinitionArg),
1408
+ ...command.views && command.views.length > 0 ? { views: command.views } : {}
1409
+ };
1410
+ }
1411
+ function getConnectorCommands(surface, options = {}) {
1412
+ return visibleDefinitions(surface, options.activeViewId, options.agentId).map(toConnectorCommand);
1413
+ }
1414
+ function getCatalogCommands(surface, options = {}) {
1415
+ return visibleDefinitions(surface, options.activeViewId, options.agentId).map((command) => serializeCommand(command, options.source ? { source: options.source } : {}));
1416
+ }
1417
+
516
1418
  // src/index.ts
517
1419
  var commandRegistryProvider = {
518
1420
  name: "COMMAND_REGISTRY",
@@ -524,10 +1426,9 @@ var commandRegistryProvider = {
524
1426
  cacheStable: true,
525
1427
  cacheScope: "agent",
526
1428
  async get(runtime, message, _state) {
527
- useRuntime(runtime.agentId);
528
- const text = message.content?.text ?? "";
1429
+ const text = message.content.text ?? "";
529
1430
  const isCommand = hasCommand(text);
530
- const commands = getEnabledCommands();
1431
+ const commands = getEnabledCommandsForRuntime(runtime.agentId);
531
1432
  if (isCommand) {
532
1433
  const commandList = commands.map((cmd) => {
533
1434
  const auth = cmd.requiresAuth ? " (requires auth)" : "";
@@ -579,14 +1480,15 @@ var commandsPlugin = {
579
1480
  name: "commands",
580
1481
  description: "Chat command system with /help, /status, /reset, etc.",
581
1482
  providers: [commandRegistryProvider],
1483
+ actions: commandActions,
1484
+ shortcuts: commandShortcuts,
582
1485
  autoEnable: {
583
1486
  shouldEnable: (_env, config) => {
584
- const f = config?.features?.commands;
1487
+ const f = config.features?.commands;
585
1488
  return f === true || typeof f === "object" && f !== null && f.enabled !== false;
586
1489
  }
587
1490
  },
588
1491
  config: {
589
- COMMANDS_ENABLED: "true",
590
1492
  COMMANDS_CONFIG_ENABLED: "false",
591
1493
  COMMANDS_DEBUG_ENABLED: "false",
592
1494
  COMMANDS_BASH_ENABLED: "false",
@@ -621,8 +1523,8 @@ var commandsPlugin = {
621
1523
  if (detection.command?.key !== "think") {
622
1524
  throw new Error(`Expected key 'think', got '${detection.command?.key}'`);
623
1525
  }
624
- if (detection.command?.args[0] !== "high") {
625
- throw new Error(`Expected arg 'high', got '${detection.command?.args[0]}'`);
1526
+ if (detection.command.args[0] !== "high") {
1527
+ throw new Error(`Expected arg 'high', got '${detection.command.args[0]}'`);
626
1528
  }
627
1529
  logger.success("Command argument parsing works correctly");
628
1530
  }
@@ -758,27 +1660,60 @@ export {
758
1660
  useRuntime,
759
1661
  unregisterCommand,
760
1662
  startsWithCommand,
1663
+ setCommandSetting,
1664
+ serializeCommand,
1665
+ runCommand,
1666
+ resolveSettingsSection,
1667
+ resolveConnectorCommandAuth,
1668
+ resolveCommand,
761
1669
  resetCommands,
762
1670
  registerCommands,
763
1671
  registerCommand,
764
1672
  parseCommand,
765
1673
  normalizeCommandBody,
1674
+ navigationCommandDefinitions,
1675
+ naturalShortcuts,
766
1676
  isElevated,
1677
+ isDeterministicCommand,
767
1678
  isCommandOnly,
768
1679
  isAuthorized,
769
1680
  initForRuntime,
770
1681
  hasCommand,
1682
+ getSettingsSections,
1683
+ getSettingsSectionChoices,
1684
+ getEnabledCommandsForRuntime,
771
1685
  getEnabledCommands,
1686
+ getConnectorCommands,
1687
+ getCommandsForRuntime,
1688
+ getCommandsByCategoryForRuntime,
772
1689
  getCommandsByCategory,
773
1690
  getCommands,
1691
+ getCommandSettings,
1692
+ getCatalogCommands,
1693
+ gateConnectorCommandByName,
1694
+ gateConnectorCommand,
774
1695
  formatCommandResult,
1696
+ findCommandByKeyForRuntime,
775
1697
  findCommandByKey,
1698
+ findCommandByAliasForRuntime,
776
1699
  findCommandByAlias,
777
1700
  extractCommand,
1701
+ explicitCommandShortcuts,
1702
+ dispatchCommandMessage,
778
1703
  detectCommand,
779
1704
  src_default as default,
1705
+ createCommandShortcuts,
1706
+ createCommandActions,
780
1707
  commandsPlugin,
781
- commandRegistryProvider
1708
+ commandVisibleForView,
1709
+ commandVisibleForSurface,
1710
+ commandShortcuts,
1711
+ commandRegistryProvider,
1712
+ commandActions,
1713
+ clearCommandSettings,
1714
+ DETERMINISTIC_COMMAND_KEYS,
1715
+ DEFAULT_COMMANDS,
1716
+ COMMAND_SETTING_CHOICES
782
1717
  };
783
1718
 
784
- //# debugId=BAB16333EBF522DA64756E2164756E21
1719
+ //# debugId=0416CA3D9EF6001864756E2164756E21