@openacp/cli 2026.404.1 → 2026.405.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as Attachment, O as OutgoingMessage, I as IChannelAdapter, N as NotificationMessage, a as AgentEvent, S as StopReason, P as PermissionRequest, U as UsageRecord, b as AgentCapabilities, c as AgentDefinition, M as McpServerConfig, d as SetConfigOptionValue, e as InstalledAgent, R as RegistryAgent, f as AgentListItem, g as AvailabilityResult, h as InstallProgress, i as InstallResult, j as SessionStatus, C as ConfigOption, k as AgentSwitchEntry, l as AgentCommand, T as TurnContext, m as TurnRouting, n as SessionRecord, o as UsageRecordEvent, p as IncomingMessage, D as DisplayVerbosity, q as ChannelConfig, r as AdapterCapabilities, s as ToolCallMeta, V as ViewerLinks, t as OutputMode, u as PlanEntry } from './channel-CmTWKnpK.js';
2
- export { v as AgentDistribution, w as AuthMethod, x as AuthenticateRequest, y as ChannelAdapter, z as ConfigSelectChoice, B as ConfigSelectGroup, E as ContentBlock, K as KIND_ICONS, F as ModelInfo, G as NewSessionResponse, H as PermissionOption, J as PromptResponse, L as RegistryBinaryTarget, Q as RegistryDistribution, W as STATUS_ICONS, X as SessionListItem, Y as SessionListResponse, Z as SessionMode, _ as SessionModeState, $ as SessionModelState, a0 as TelegramPlatformData, a1 as ToolUpdateMeta, a2 as createTurnContext, a3 as getEffectiveTarget, a4 as isSystemEvent } from './channel-CmTWKnpK.js';
1
+ import { A as Attachment, O as OutgoingMessage, I as IChannelAdapter, N as NotificationMessage, a as AgentEvent, S as StopReason, P as PermissionRequest, U as UsageRecord, b as AgentCapabilities, c as AgentDefinition, M as McpServerConfig, d as SetConfigOptionValue, e as InstalledAgent, R as RegistryAgent, f as AgentListItem, g as AvailabilityResult, h as InstallProgress, i as InstallResult, j as SessionStatus, T as TurnContext, C as ConfigOption, k as AgentSwitchEntry, l as AgentCommand, m as TurnRouting, n as SessionRecord, o as UsageRecordEvent, p as IncomingMessage, D as DisplayVerbosity, q as ChannelConfig, r as AdapterCapabilities, s as ToolCallMeta, V as ViewerLinks, t as OutputMode, u as PlanEntry } from './channel-DstweC6V.js';
2
+ export { v as AgentDistribution, w as AuthMethod, x as AuthenticateRequest, y as ChannelAdapter, z as ConfigSelectChoice, B as ConfigSelectGroup, E as ContentBlock, K as KIND_ICONS, F as ModelInfo, G as NewSessionResponse, H as PermissionOption, J as PromptResponse, L as RegistryBinaryTarget, Q as RegistryDistribution, W as STATUS_ICONS, X as SessionListItem, Y as SessionListResponse, Z as SessionMode, _ as SessionModeState, $ as SessionModelState, a0 as TelegramPlatformData, a1 as ToolUpdateMeta, a2 as createTurnContext, a3 as getEffectiveTarget, a4 as isSystemEvent } from './channel-DstweC6V.js';
3
3
  import pino from 'pino';
4
4
  import * as zod from 'zod';
5
5
  import { ZodSchema, z } from 'zod';
@@ -76,6 +76,20 @@ interface SettingsAPI {
76
76
  clear(): Promise<void>;
77
77
  has(key: string): Promise<boolean>;
78
78
  }
79
+ /** Describes a settings field that a plugin exposes as editable via API/UI */
80
+ interface FieldDef {
81
+ /** Settings key (matches the key in plugin settings.json) */
82
+ key: string;
83
+ /** Human-readable label for UI display */
84
+ displayName: string;
85
+ type: "toggle" | "select" | "number" | "string";
86
+ /** safe = readable via API; sensitive = write-only (e.g., tokens) */
87
+ scope: "safe" | "sensitive";
88
+ /** Whether the change takes effect without restart. Default: false */
89
+ hotReload?: boolean;
90
+ /** Valid values for "select" type */
91
+ options?: string[];
92
+ }
79
93
  interface TerminalIO {
80
94
  text(opts: {
81
95
  message: string;
@@ -127,7 +141,6 @@ interface InstallContext {
127
141
  pluginName: string;
128
142
  terminal: TerminalIO;
129
143
  settings: SettingsAPI;
130
- legacyConfig?: Record<string, unknown>;
131
144
  dataDir: string;
132
145
  log: Logger$1;
133
146
  /** Root of the OpenACP instance directory (e.g. ~/.openacp) */
@@ -270,6 +283,12 @@ interface PluginContext {
270
283
  registerAssistantSection(section: AssistantSection): void;
271
284
  /** Unregister an assistant section by id. Requires 'commands:register'. */
272
285
  unregisterAssistantSection(id: string): void;
286
+ /**
287
+ * Declare this plugin's settings fields as editable via API/UI.
288
+ * Call in setup() after registering services.
289
+ * Requires 'commands:register'.
290
+ */
291
+ registerEditableFields(fields: FieldDef[]): void;
273
292
  /** Plugin-scoped storage. Requires 'storage:read' and/or 'storage:write'. */
274
293
  storage: PluginStorage;
275
294
  /** Plugin-scoped logger. Always available (no permission needed). */
@@ -525,131 +544,8 @@ declare const LoggingSchema: z.ZodDefault<z.ZodObject<{
525
544
  sessionLogRetentionDays?: number | undefined;
526
545
  }>>;
527
546
  type LoggingConfig = z.infer<typeof LoggingSchema>;
528
- declare const TunnelSchema: z.ZodDefault<z.ZodObject<{
529
- enabled: z.ZodDefault<z.ZodBoolean>;
530
- port: z.ZodDefault<z.ZodNumber>;
531
- provider: z.ZodDefault<z.ZodEnum<["openacp", "cloudflare", "ngrok", "bore", "tailscale"]>>;
532
- options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
533
- maxUserTunnels: z.ZodDefault<z.ZodNumber>;
534
- storeTtlMinutes: z.ZodDefault<z.ZodNumber>;
535
- auth: z.ZodDefault<z.ZodObject<{
536
- enabled: z.ZodDefault<z.ZodBoolean>;
537
- token: z.ZodOptional<z.ZodString>;
538
- }, "strip", z.ZodTypeAny, {
539
- enabled: boolean;
540
- token?: string | undefined;
541
- }, {
542
- enabled?: boolean | undefined;
543
- token?: string | undefined;
544
- }>>;
545
- }, "strip", z.ZodTypeAny, {
546
- provider: "openacp" | "cloudflare" | "ngrok" | "bore" | "tailscale";
547
- enabled: boolean;
548
- options: Record<string, unknown>;
549
- port: number;
550
- maxUserTunnels: number;
551
- storeTtlMinutes: number;
552
- auth: {
553
- enabled: boolean;
554
- token?: string | undefined;
555
- };
556
- }, {
557
- provider?: "openacp" | "cloudflare" | "ngrok" | "bore" | "tailscale" | undefined;
558
- enabled?: boolean | undefined;
559
- options?: Record<string, unknown> | undefined;
560
- port?: number | undefined;
561
- maxUserTunnels?: number | undefined;
562
- storeTtlMinutes?: number | undefined;
563
- auth?: {
564
- enabled?: boolean | undefined;
565
- token?: string | undefined;
566
- } | undefined;
567
- }>>;
568
- type TunnelConfig = z.infer<typeof TunnelSchema>;
569
- declare const UsageSchema: z.ZodDefault<z.ZodObject<{
570
- enabled: z.ZodDefault<z.ZodBoolean>;
571
- monthlyBudget: z.ZodOptional<z.ZodNumber>;
572
- warningThreshold: z.ZodDefault<z.ZodNumber>;
573
- currency: z.ZodDefault<z.ZodString>;
574
- retentionDays: z.ZodDefault<z.ZodNumber>;
575
- }, "strip", z.ZodTypeAny, {
576
- enabled: boolean;
577
- warningThreshold: number;
578
- currency: string;
579
- retentionDays: number;
580
- monthlyBudget?: number | undefined;
581
- }, {
582
- enabled?: boolean | undefined;
583
- monthlyBudget?: number | undefined;
584
- warningThreshold?: number | undefined;
585
- currency?: string | undefined;
586
- retentionDays?: number | undefined;
587
- }>>;
588
- type UsageConfig = z.infer<typeof UsageSchema>;
589
547
  declare const ConfigSchema: z.ZodObject<{
590
548
  instanceName: z.ZodOptional<z.ZodString>;
591
- channels: z.ZodDefault<z.ZodObject<{}, "strip", z.ZodObject<{
592
- enabled: z.ZodDefault<z.ZodBoolean>;
593
- adapter: z.ZodOptional<z.ZodString>;
594
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
595
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
596
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
597
- enabled: z.ZodDefault<z.ZodBoolean>;
598
- adapter: z.ZodOptional<z.ZodString>;
599
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
600
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
601
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
602
- enabled: z.ZodDefault<z.ZodBoolean>;
603
- adapter: z.ZodOptional<z.ZodString>;
604
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
605
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
606
- }, z.ZodTypeAny, "passthrough">>, z.objectOutputType<{}, z.ZodObject<{
607
- enabled: z.ZodDefault<z.ZodBoolean>;
608
- adapter: z.ZodOptional<z.ZodString>;
609
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
610
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
611
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
612
- enabled: z.ZodDefault<z.ZodBoolean>;
613
- adapter: z.ZodOptional<z.ZodString>;
614
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
615
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
616
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
617
- enabled: z.ZodDefault<z.ZodBoolean>;
618
- adapter: z.ZodOptional<z.ZodString>;
619
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
620
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
621
- }, z.ZodTypeAny, "passthrough">>, "strip">, z.objectInputType<{}, z.ZodObject<{
622
- enabled: z.ZodDefault<z.ZodBoolean>;
623
- adapter: z.ZodOptional<z.ZodString>;
624
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
625
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
626
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
627
- enabled: z.ZodDefault<z.ZodBoolean>;
628
- adapter: z.ZodOptional<z.ZodString>;
629
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
630
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
631
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
632
- enabled: z.ZodDefault<z.ZodBoolean>;
633
- adapter: z.ZodOptional<z.ZodString>;
634
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
635
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
636
- }, z.ZodTypeAny, "passthrough">>, "strip">>>;
637
- agents: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
638
- command: z.ZodString;
639
- args: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
640
- workingDirectory: z.ZodOptional<z.ZodString>;
641
- env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
642
- }, "strip", z.ZodTypeAny, {
643
- command: string;
644
- args: string[];
645
- env: Record<string, string>;
646
- workingDirectory?: string | undefined;
647
- }, {
648
- command: string;
649
- args?: string[] | undefined;
650
- env?: Record<string, string> | undefined;
651
- workingDirectory?: string | undefined;
652
- }>>>>;
653
549
  defaultAgent: z.ZodString;
654
550
  workspace: z.ZodDefault<z.ZodObject<{
655
551
  baseDir: z.ZodDefault<z.ZodString>;
@@ -676,19 +572,6 @@ declare const ConfigSchema: z.ZodObject<{
676
572
  envWhitelist?: string[] | undefined;
677
573
  } | undefined;
678
574
  }>>;
679
- security: z.ZodDefault<z.ZodObject<{
680
- allowedUserIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
681
- maxConcurrentSessions: z.ZodDefault<z.ZodNumber>;
682
- sessionTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
683
- }, "strip", z.ZodTypeAny, {
684
- allowedUserIds: string[];
685
- maxConcurrentSessions: number;
686
- sessionTimeoutMinutes: number;
687
- }, {
688
- allowedUserIds?: string[] | undefined;
689
- maxConcurrentSessions?: number | undefined;
690
- sessionTimeoutMinutes?: number | undefined;
691
- }>>;
692
575
  logging: z.ZodDefault<z.ZodObject<{
693
576
  level: z.ZodDefault<z.ZodEnum<["silent", "debug", "info", "warn", "error", "fatal"]>>;
694
577
  logDir: z.ZodDefault<z.ZodString>;
@@ -710,16 +593,6 @@ declare const ConfigSchema: z.ZodObject<{
710
593
  }>>;
711
594
  runMode: z.ZodDefault<z.ZodEnum<["foreground", "daemon"]>>;
712
595
  autoStart: z.ZodDefault<z.ZodBoolean>;
713
- api: z.ZodDefault<z.ZodObject<{
714
- port: z.ZodDefault<z.ZodNumber>;
715
- host: z.ZodDefault<z.ZodString>;
716
- }, "strip", z.ZodTypeAny, {
717
- port: number;
718
- host: string;
719
- }, {
720
- port?: number | undefined;
721
- host?: string | undefined;
722
- }>>;
723
596
  sessionStore: z.ZodDefault<z.ZodObject<{
724
597
  ttlDays: z.ZodDefault<z.ZodNumber>;
725
598
  }, "strip", z.ZodTypeAny, {
@@ -727,65 +600,6 @@ declare const ConfigSchema: z.ZodObject<{
727
600
  }, {
728
601
  ttlDays?: number | undefined;
729
602
  }>>;
730
- tunnel: z.ZodDefault<z.ZodObject<{
731
- enabled: z.ZodDefault<z.ZodBoolean>;
732
- port: z.ZodDefault<z.ZodNumber>;
733
- provider: z.ZodDefault<z.ZodEnum<["openacp", "cloudflare", "ngrok", "bore", "tailscale"]>>;
734
- options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
735
- maxUserTunnels: z.ZodDefault<z.ZodNumber>;
736
- storeTtlMinutes: z.ZodDefault<z.ZodNumber>;
737
- auth: z.ZodDefault<z.ZodObject<{
738
- enabled: z.ZodDefault<z.ZodBoolean>;
739
- token: z.ZodOptional<z.ZodString>;
740
- }, "strip", z.ZodTypeAny, {
741
- enabled: boolean;
742
- token?: string | undefined;
743
- }, {
744
- enabled?: boolean | undefined;
745
- token?: string | undefined;
746
- }>>;
747
- }, "strip", z.ZodTypeAny, {
748
- provider: "openacp" | "cloudflare" | "ngrok" | "bore" | "tailscale";
749
- enabled: boolean;
750
- options: Record<string, unknown>;
751
- port: number;
752
- maxUserTunnels: number;
753
- storeTtlMinutes: number;
754
- auth: {
755
- enabled: boolean;
756
- token?: string | undefined;
757
- };
758
- }, {
759
- provider?: "openacp" | "cloudflare" | "ngrok" | "bore" | "tailscale" | undefined;
760
- enabled?: boolean | undefined;
761
- options?: Record<string, unknown> | undefined;
762
- port?: number | undefined;
763
- maxUserTunnels?: number | undefined;
764
- storeTtlMinutes?: number | undefined;
765
- auth?: {
766
- enabled?: boolean | undefined;
767
- token?: string | undefined;
768
- } | undefined;
769
- }>>;
770
- usage: z.ZodDefault<z.ZodObject<{
771
- enabled: z.ZodDefault<z.ZodBoolean>;
772
- monthlyBudget: z.ZodOptional<z.ZodNumber>;
773
- warningThreshold: z.ZodDefault<z.ZodNumber>;
774
- currency: z.ZodDefault<z.ZodString>;
775
- retentionDays: z.ZodDefault<z.ZodNumber>;
776
- }, "strip", z.ZodTypeAny, {
777
- enabled: boolean;
778
- warningThreshold: number;
779
- currency: string;
780
- retentionDays: number;
781
- monthlyBudget?: number | undefined;
782
- }, {
783
- enabled?: boolean | undefined;
784
- monthlyBudget?: number | undefined;
785
- warningThreshold?: number | undefined;
786
- currency?: string | undefined;
787
- retentionDays?: number | undefined;
788
- }>>;
789
603
  integrations: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
790
604
  installed: z.ZodBoolean;
791
605
  installedAt: z.ZodOptional<z.ZodString>;
@@ -796,88 +610,6 @@ declare const ConfigSchema: z.ZodObject<{
796
610
  installed: boolean;
797
611
  installedAt?: string | undefined;
798
612
  }>>>;
799
- speech: z.ZodDefault<z.ZodOptional<z.ZodObject<{
800
- stt: z.ZodDefault<z.ZodObject<{
801
- provider: z.ZodDefault<z.ZodNullable<z.ZodString>>;
802
- providers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
803
- apiKey: z.ZodOptional<z.ZodString>;
804
- model: z.ZodOptional<z.ZodString>;
805
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
806
- apiKey: z.ZodOptional<z.ZodString>;
807
- model: z.ZodOptional<z.ZodString>;
808
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
809
- apiKey: z.ZodOptional<z.ZodString>;
810
- model: z.ZodOptional<z.ZodString>;
811
- }, z.ZodTypeAny, "passthrough">>>>;
812
- }, "strip", z.ZodTypeAny, {
813
- provider: string | null;
814
- providers: Record<string, z.objectOutputType<{
815
- apiKey: z.ZodOptional<z.ZodString>;
816
- model: z.ZodOptional<z.ZodString>;
817
- }, z.ZodTypeAny, "passthrough">>;
818
- }, {
819
- provider?: string | null | undefined;
820
- providers?: Record<string, z.objectInputType<{
821
- apiKey: z.ZodOptional<z.ZodString>;
822
- model: z.ZodOptional<z.ZodString>;
823
- }, z.ZodTypeAny, "passthrough">> | undefined;
824
- }>>;
825
- tts: z.ZodDefault<z.ZodObject<{
826
- provider: z.ZodDefault<z.ZodNullable<z.ZodString>>;
827
- providers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
828
- apiKey: z.ZodOptional<z.ZodString>;
829
- model: z.ZodOptional<z.ZodString>;
830
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
831
- apiKey: z.ZodOptional<z.ZodString>;
832
- model: z.ZodOptional<z.ZodString>;
833
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
834
- apiKey: z.ZodOptional<z.ZodString>;
835
- model: z.ZodOptional<z.ZodString>;
836
- }, z.ZodTypeAny, "passthrough">>>>;
837
- }, "strip", z.ZodTypeAny, {
838
- provider: string | null;
839
- providers: Record<string, z.objectOutputType<{
840
- apiKey: z.ZodOptional<z.ZodString>;
841
- model: z.ZodOptional<z.ZodString>;
842
- }, z.ZodTypeAny, "passthrough">>;
843
- }, {
844
- provider?: string | null | undefined;
845
- providers?: Record<string, z.objectInputType<{
846
- apiKey: z.ZodOptional<z.ZodString>;
847
- model: z.ZodOptional<z.ZodString>;
848
- }, z.ZodTypeAny, "passthrough">> | undefined;
849
- }>>;
850
- }, "strip", z.ZodTypeAny, {
851
- stt: {
852
- provider: string | null;
853
- providers: Record<string, z.objectOutputType<{
854
- apiKey: z.ZodOptional<z.ZodString>;
855
- model: z.ZodOptional<z.ZodString>;
856
- }, z.ZodTypeAny, "passthrough">>;
857
- };
858
- tts: {
859
- provider: string | null;
860
- providers: Record<string, z.objectOutputType<{
861
- apiKey: z.ZodOptional<z.ZodString>;
862
- model: z.ZodOptional<z.ZodString>;
863
- }, z.ZodTypeAny, "passthrough">>;
864
- };
865
- }, {
866
- stt?: {
867
- provider?: string | null | undefined;
868
- providers?: Record<string, z.objectInputType<{
869
- apiKey: z.ZodOptional<z.ZodString>;
870
- model: z.ZodOptional<z.ZodString>;
871
- }, z.ZodTypeAny, "passthrough">> | undefined;
872
- } | undefined;
873
- tts?: {
874
- provider?: string | null | undefined;
875
- providers?: Record<string, z.objectInputType<{
876
- apiKey: z.ZodOptional<z.ZodString>;
877
- model: z.ZodOptional<z.ZodString>;
878
- }, z.ZodTypeAny, "passthrough">> | undefined;
879
- } | undefined;
880
- }>>>;
881
613
  outputMode: z.ZodOptional<z.ZodDefault<z.ZodEnum<["low", "medium", "high"]>>>;
882
614
  agentSwitch: z.ZodDefault<z.ZodObject<{
883
615
  labelHistory: z.ZodDefault<z.ZodBoolean>;
@@ -887,49 +619,7 @@ declare const ConfigSchema: z.ZodObject<{
887
619
  labelHistory?: boolean | undefined;
888
620
  }>>;
889
621
  }, "strip", z.ZodTypeAny, {
890
- api: {
891
- port: number;
892
- host: string;
893
- };
894
- agents: Record<string, {
895
- command: string;
896
- args: string[];
897
- env: Record<string, string>;
898
- workingDirectory?: string | undefined;
899
- }>;
900
- tunnel: {
901
- provider: "openacp" | "cloudflare" | "ngrok" | "bore" | "tailscale";
902
- enabled: boolean;
903
- options: Record<string, unknown>;
904
- port: number;
905
- maxUserTunnels: number;
906
- storeTtlMinutes: number;
907
- auth: {
908
- enabled: boolean;
909
- token?: string | undefined;
910
- };
911
- };
912
- channels: {} & {
913
- [k: string]: z.objectOutputType<{
914
- enabled: z.ZodDefault<z.ZodBoolean>;
915
- adapter: z.ZodOptional<z.ZodString>;
916
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
917
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
918
- }, z.ZodTypeAny, "passthrough">;
919
- };
920
- usage: {
921
- enabled: boolean;
922
- warningThreshold: number;
923
- currency: string;
924
- retentionDays: number;
925
- monthlyBudget?: number | undefined;
926
- };
927
622
  defaultAgent: string;
928
- security: {
929
- allowedUserIds: string[];
930
- maxConcurrentSessions: number;
931
- sessionTimeoutMinutes: number;
932
- };
933
623
  workspace: {
934
624
  baseDir: string;
935
625
  security: {
@@ -953,22 +643,6 @@ declare const ConfigSchema: z.ZodObject<{
953
643
  installed: boolean;
954
644
  installedAt?: string | undefined;
955
645
  }>;
956
- speech: {
957
- stt: {
958
- provider: string | null;
959
- providers: Record<string, z.objectOutputType<{
960
- apiKey: z.ZodOptional<z.ZodString>;
961
- model: z.ZodOptional<z.ZodString>;
962
- }, z.ZodTypeAny, "passthrough">>;
963
- };
964
- tts: {
965
- provider: string | null;
966
- providers: Record<string, z.objectOutputType<{
967
- apiKey: z.ZodOptional<z.ZodString>;
968
- model: z.ZodOptional<z.ZodString>;
969
- }, z.ZodTypeAny, "passthrough">>;
970
- };
971
- };
972
646
  agentSwitch: {
973
647
  labelHistory: boolean;
974
648
  };
@@ -976,58 +650,7 @@ declare const ConfigSchema: z.ZodObject<{
976
650
  outputMode?: "low" | "medium" | "high" | undefined;
977
651
  }, {
978
652
  defaultAgent: string;
979
- api?: {
980
- port?: number | undefined;
981
- host?: string | undefined;
982
- } | undefined;
983
- agents?: Record<string, {
984
- command: string;
985
- args?: string[] | undefined;
986
- env?: Record<string, string> | undefined;
987
- workingDirectory?: string | undefined;
988
- }> | undefined;
989
- tunnel?: {
990
- provider?: "openacp" | "cloudflare" | "ngrok" | "bore" | "tailscale" | undefined;
991
- enabled?: boolean | undefined;
992
- options?: Record<string, unknown> | undefined;
993
- port?: number | undefined;
994
- maxUserTunnels?: number | undefined;
995
- storeTtlMinutes?: number | undefined;
996
- auth?: {
997
- enabled?: boolean | undefined;
998
- token?: string | undefined;
999
- } | undefined;
1000
- } | undefined;
1001
653
  instanceName?: string | undefined;
1002
- channels?: z.objectInputType<{}, z.ZodObject<{
1003
- enabled: z.ZodDefault<z.ZodBoolean>;
1004
- adapter: z.ZodOptional<z.ZodString>;
1005
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
1006
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
1007
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
1008
- enabled: z.ZodDefault<z.ZodBoolean>;
1009
- adapter: z.ZodOptional<z.ZodString>;
1010
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
1011
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
1012
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
1013
- enabled: z.ZodDefault<z.ZodBoolean>;
1014
- adapter: z.ZodOptional<z.ZodString>;
1015
- displayVerbosity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
1016
- outputMode: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
1017
- }, z.ZodTypeAny, "passthrough">>, "strip"> | undefined;
1018
- outputMode?: "low" | "medium" | "high" | undefined;
1019
- usage?: {
1020
- enabled?: boolean | undefined;
1021
- monthlyBudget?: number | undefined;
1022
- warningThreshold?: number | undefined;
1023
- currency?: string | undefined;
1024
- retentionDays?: number | undefined;
1025
- } | undefined;
1026
- security?: {
1027
- allowedUserIds?: string[] | undefined;
1028
- maxConcurrentSessions?: number | undefined;
1029
- sessionTimeoutMinutes?: number | undefined;
1030
- } | undefined;
1031
654
  workspace?: {
1032
655
  baseDir?: string | undefined;
1033
656
  security?: {
@@ -1051,22 +674,7 @@ declare const ConfigSchema: z.ZodObject<{
1051
674
  installed: boolean;
1052
675
  installedAt?: string | undefined;
1053
676
  }> | undefined;
1054
- speech?: {
1055
- stt?: {
1056
- provider?: string | null | undefined;
1057
- providers?: Record<string, z.objectInputType<{
1058
- apiKey: z.ZodOptional<z.ZodString>;
1059
- model: z.ZodOptional<z.ZodString>;
1060
- }, z.ZodTypeAny, "passthrough">> | undefined;
1061
- } | undefined;
1062
- tts?: {
1063
- provider?: string | null | undefined;
1064
- providers?: Record<string, z.objectInputType<{
1065
- apiKey: z.ZodOptional<z.ZodString>;
1066
- model: z.ZodOptional<z.ZodString>;
1067
- }, z.ZodTypeAny, "passthrough">> | undefined;
1068
- } | undefined;
1069
- } | undefined;
677
+ outputMode?: "low" | "medium" | "high" | undefined;
1070
678
  agentSwitch?: {
1071
679
  labelHistory?: boolean | undefined;
1072
680
  } | undefined;
@@ -1081,7 +689,7 @@ declare class ConfigManager extends EventEmitter {
1081
689
  get(): Config;
1082
690
  save(updates: Record<string, unknown>, changePath?: string): Promise<void>;
1083
691
  /**
1084
- * Set a single config value by dot-path (e.g. "security.maxConcurrentSessions").
692
+ * Set a single config value by dot-path (e.g. "logging.level").
1085
693
  * Builds the nested update object, validates, and saves.
1086
694
  * Throws if the path contains blocked keys or the value fails Zod validation.
1087
695
  */
@@ -1139,6 +747,7 @@ declare class StderrCapture {
1139
747
  * emitter.emit('data', 'hello')
1140
748
  */
1141
749
  declare class TypedEmitter<T extends Record<string & keyof T, (...args: any[]) => void>> {
750
+ private static readonly MAX_BUFFER_SIZE;
1142
751
  private listeners;
1143
752
  private paused;
1144
753
  private buffer;
@@ -1424,6 +1033,7 @@ interface SessionEvents {
1424
1033
  named: (name: string) => void;
1425
1034
  error: (error: Error) => void;
1426
1035
  prompt_count_changed: (count: number) => void;
1036
+ turn_started: (ctx: TurnContext) => void;
1427
1037
  }
1428
1038
  declare class Session extends TypedEmitter<SessionEvents> {
1429
1039
  id: string;
@@ -1459,6 +1069,9 @@ declare class Session extends TypedEmitter<SessionEvents> {
1459
1069
  threadIds: Map<string, string>;
1460
1070
  /** Active turn context — sealed on prompt dequeue, cleared on turn end */
1461
1071
  activeTurnContext: TurnContext | null;
1072
+ /** The agentInstance for which the agent→session event relay is wired (prevents duplicate relays from multiple bridges).
1073
+ * When the agent is swapped, the relay must be re-wired to the new instance. */
1074
+ agentRelaySource: AgentInstance | null;
1462
1075
  readonly permissionGate: PermissionGate;
1463
1076
  private readonly queue;
1464
1077
  private speechService?;
@@ -1491,7 +1104,7 @@ declare class Session extends TypedEmitter<SessionEvents> {
1491
1104
  get promptRunning(): boolean;
1492
1105
  setContext(markdown: string): void;
1493
1106
  setVoiceMode(mode: "off" | "next" | "on"): void;
1494
- enqueuePrompt(text: string, attachments?: Attachment[], routing?: TurnRouting): Promise<void>;
1107
+ enqueuePrompt(text: string, attachments?: Attachment[], routing?: TurnRouting, externalTurnId?: string): Promise<string>;
1495
1108
  private processPrompt;
1496
1109
  private maybeTranscribeAudio;
1497
1110
  private processTTSResponse;
@@ -1537,8 +1150,10 @@ declare class PromptQueue {
1537
1150
  private queue;
1538
1151
  private processing;
1539
1152
  private abortController;
1540
- constructor(processor: (text: string, attachments?: Attachment[], routing?: TurnRouting) => Promise<void>, onError?: ((err: unknown) => void) | undefined);
1541
- enqueue(text: string, attachments?: Attachment[], routing?: TurnRouting): Promise<void>;
1153
+ /** Set when abort is triggered; drainNext waits for the current processor to settle before starting the next item. */
1154
+ private processorSettled;
1155
+ constructor(processor: (text: string, attachments?: Attachment[], routing?: TurnRouting, turnId?: string) => Promise<void>, onError?: ((err: unknown) => void) | undefined);
1156
+ enqueue(text: string, attachments?: Attachment[], routing?: TurnRouting, turnId?: string): Promise<void>;
1542
1157
  private process;
1543
1158
  private drainNext;
1544
1159
  clear(): void;
@@ -1557,6 +1172,10 @@ declare class MessageTransformer {
1557
1172
  id: string;
1558
1173
  workingDirectory: string;
1559
1174
  }): OutgoingMessage;
1175
+ /** Clear cached entries whose key starts with the given prefix. */
1176
+ clearSessionCaches(prefix: string): void;
1177
+ /** Clear all caches. */
1178
+ clearCaches(): void;
1560
1179
  /** Check if rawInput is a non-empty object (not null, not {}) */
1561
1180
  private isNonEmptyInput;
1562
1181
  private enrichWithViewerLinks;
@@ -1651,6 +1270,21 @@ interface EventBusEvents {
1651
1270
  "session:configChanged": (data: {
1652
1271
  sessionId: string;
1653
1272
  }) => void;
1273
+ "message:queued": (data: {
1274
+ sessionId: string;
1275
+ turnId: string;
1276
+ text: string;
1277
+ sourceAdapterId: string;
1278
+ attachments?: unknown[];
1279
+ timestamp: string;
1280
+ queueDepth: number;
1281
+ }) => void;
1282
+ "message:processing": (data: {
1283
+ sessionId: string;
1284
+ turnId: string;
1285
+ sourceAdapterId: string;
1286
+ timestamp: string;
1287
+ }) => void;
1654
1288
  "session:agentSwitch": (data: {
1655
1289
  sessionId: string;
1656
1290
  fromAgent: string;
@@ -1802,6 +1436,19 @@ declare class ViewerStore {
1802
1436
  destroy(): void;
1803
1437
  }
1804
1438
 
1439
+ interface TunnelConfig {
1440
+ enabled: boolean;
1441
+ port: number;
1442
+ provider: string;
1443
+ options: Record<string, unknown>;
1444
+ storeTtlMinutes: number;
1445
+ maxUserTunnels?: number;
1446
+ auth: {
1447
+ enabled: boolean;
1448
+ token?: string;
1449
+ };
1450
+ }
1451
+
1805
1452
  declare class TunnelService {
1806
1453
  private registry;
1807
1454
  private store;
@@ -1844,6 +1491,8 @@ interface ContextOptions {
1844
1491
  limit?: number;
1845
1492
  /** When true, insert `## [agentName]` headers at agent boundaries in merged history */
1846
1493
  labelAgent?: boolean;
1494
+ /** When true, skip the context cache (use for live switches where history just changed) */
1495
+ noCache?: boolean;
1847
1496
  }
1848
1497
  interface SessionInfo {
1849
1498
  checkpointId: string;
@@ -1993,8 +1642,17 @@ declare class ContextManager {
1993
1642
  private providers;
1994
1643
  private cache;
1995
1644
  private historyStore?;
1645
+ private sessionFlusher?;
1996
1646
  constructor(cachePath?: string);
1997
1647
  setHistoryStore(store: HistoryStore): void;
1648
+ /** Register a callback that flushes in-memory recorder state for a session to disk. */
1649
+ registerFlusher(fn: (sessionId: string) => Promise<void>): void;
1650
+ /**
1651
+ * Flush the recorder state for a session to disk before reading its context.
1652
+ * Call this before buildContext() when switching agents to avoid a race
1653
+ * where the last turn hasn't been persisted yet.
1654
+ */
1655
+ flushSession(sessionId: string): Promise<void>;
1998
1656
  getHistory(sessionId: string): Promise<SessionHistory | null>;
1999
1657
  register(provider: ContextProvider): void;
2000
1658
  getProvider(repoPath: string): Promise<ContextProvider | null>;
@@ -2451,11 +2109,6 @@ interface ConfigFieldDef {
2451
2109
  options?: string[] | ((config: Config) => string[]);
2452
2110
  scope: "safe" | "sensitive";
2453
2111
  hotReload: boolean;
2454
- /** If set, this field lives in plugin settings rather than config.json */
2455
- plugin?: {
2456
- name: string;
2457
- key: string;
2458
- };
2459
2112
  }
2460
2113
  declare const CONFIG_REGISTRY: ConfigFieldDef[];
2461
2114
  declare function getFieldDef(path: string): ConfigFieldDef | undefined;
@@ -2997,6 +2650,9 @@ interface ToolDisplaySpec {
2997
2650
  viewerLinks?: ViewerLinks;
2998
2651
  outputViewerLink?: string;
2999
2652
  outputFallbackContent?: string;
2653
+ /** Working directory of the session that produced this tool call.
2654
+ * Adapters can use this to display relative paths instead of absolute ones. */
2655
+ workingDirectory?: string;
3000
2656
  status: string;
3001
2657
  isNoise: boolean;
3002
2658
  isHidden: boolean;
@@ -3083,7 +2739,7 @@ declare class OutputModeResolver {
3083
2739
  * OpenACP Product Guide — comprehensive reference for the AI assistant.
3084
2740
  * The assistant reads this at runtime to answer user questions about features.
3085
2741
  */
3086
- declare const PRODUCT_GUIDE = "\n# OpenACP \u2014 Product Guide\n\nOpenACP lets you chat with AI coding agents (like Claude Code) through messaging platforms (Telegram, Discord).\nYou type messages in your chat platform, the agent reads/writes/runs code in your project folder, and results stream back in real time.\n\n---\n\n## Quick Start\n\n1. Start OpenACP: `openacp` (or `openacp start` for background daemon)\n2. Open your messaging platform (Telegram group or Discord server) \u2014 you'll see the Assistant topic/thread\n3. Tap/click \uD83C\uDD95 New Session or type /new\n4. Pick an agent and a project folder\n5. Chat in the session topic/thread \u2014 the agent works on your code\n\n---\n\n## Core Concepts\n\n### Sessions\nA session = one conversation with one AI agent working in one project folder.\nEach session gets its own topic (Telegram) or forum thread (Discord). Chat there to give instructions to the agent.\n\n### Agents\nAn agent is an AI coding tool (e.g., Claude Code, Gemini, Cursor, Codex, etc.).\nOpenACP supports 28+ agents from the official ACP Registry (agentclientprotocol.com).\nYou can install multiple agents and choose which one to use per session.\nThe default agent is used when you don't specify one.\n\n### Agent Management\n- Browse agents: `/agents` in your chat platform or `openacp agents` in CLI\n- Install: tap the install button in /agents, or `openacp agents install <name>`\n- Uninstall: `openacp agents uninstall <name>`\n- Setup/login: `openacp agents run <name> -- <args>` (e.g., `openacp agents run gemini -- auth login`)\n- Details: `openacp agents info <name>` shows version, dependencies, and setup steps\n\nSome agents need additional setup before they can be used:\n- Claude: requires `claude login`\n- Gemini: requires `openacp agents run gemini -- auth login`\n- Codex: requires setting `OPENAI_API_KEY` environment variable\n- GitHub Copilot: requires `openacp agents run copilot -- auth login`\n\nAgents are installed in three ways depending on the agent:\n- **npx** \u2014 Node.js agents, downloaded automatically on first use\n- **uvx** \u2014 Python agents, downloaded automatically on first use\n- **binary** \u2014 Platform-specific binaries, downloaded to `~/.openacp/agents/`\n\n### Project Folder (Workspace)\nThe directory where the agent reads, writes, and runs code.\nWhen creating a session, you choose which folder the agent works in.\nYou can type a full path like `~/code/my-project` or just a name like `my-project` (it becomes `<base-dir>/my-project`).\n\n### System Topics\n- **Assistant** \u2014 Always-on helper that can answer questions, create sessions, check status, troubleshoot\n- **Notifications** \u2014 System alerts (permission requests, session errors, completions)\n\n---\n\n## Creating Sessions\n\n### From menu\nTap \uD83C\uDD95 New Session \u2192 choose agent (if multiple) \u2192 choose project folder \u2192 confirm\n\n### From command\n- `/new` \u2014 Interactive flow (asks agent + folder)\n- `/new claude ~/code/my-project` \u2014 Create directly with specific agent and folder\n\n### From Assistant topic\nJust ask: \"Create a session for my-project with claude\" \u2014 the assistant handles it\n\n### Quick new chat\n`/newchat` in a session topic \u2014 creates new session with same agent and folder as current one\n\n---\n\n## Working with Sessions\n\n### Chat\nType messages in the session topic. The agent responds with code changes, explanations, tool outputs.\n\n### What you see while the agent works\n- **\uD83D\uDCAD Thinking indicator** \u2014 Shows when the agent is reasoning, with elapsed time\n- **Text responses** \u2014 Streamed in real time, updated every few seconds\n- **Tool calls** \u2014 When the agent runs commands or edits files, you see tool name, input, status, and output\n- **\uD83D\uDCCB Plan card** \u2014 Visual task progress with completed/in-progress/pending items and progress bar\n- **\"View File\" / \"View Diff\" buttons** \u2014 Opens in browser with Monaco editor (requires tunnel)\n\n### Session lifecycle\n1. **Creating** \u2014 Topic created, agent spawning\n2. **Warming up** \u2014 Agent primes its cache (happens automatically, invisible to you)\n3. **Active** \u2014 Ready for your messages\n4. **Auto-naming** \u2014 After your first message, the session gets a descriptive name (agent summarizes in ~5 words). The topic title updates automatically.\n5. **Finished/Error** \u2014 Session completed or hit an error\n\n### Agent skills\nSome agents provide slash commands (e.g., /compact, /review). Available skills are pinned in the session topic.\n\n### Permission requests\nWhen the agent wants to run a command, it asks for permission.\nYou see buttons: \u2705 Allow, \u274C Reject (and sometimes \"Always Allow\").\nA notification also appears in the Notifications topic with a link to the request.\n\n### Bypass permissions\nAuto-approves ALL permission requests \u2014 the agent runs any command without asking.\n- Toggle: `/bypass_permissions on` or tap the \u2620\uFE0F button in the session\n- Disable: `/bypass_permissions off` or tap the \uD83D\uDD10 button\n- \u26A0\uFE0F Use with caution \u2014 the agent can execute anything\n\n### Session timeout\nIdle sessions are automatically cancelled after a configurable timeout (default: 60 minutes).\nConfigure via `security.sessionTimeoutMinutes` in config.\n\n---\n\n## Session Transfer (Handoff)\n\n### Chat \u2192 Terminal\n1. Type `/handoff` in a session topic/thread\n2. You get a command like `claude --resume <SESSION_ID>`\n3. Copy and run it in your terminal \u2014 the session continues there with full conversation history\n\n### Terminal \u2192 Chat\n1. First time: run `openacp integrate claude` to install the handoff skill (one-time setup)\n2. In Claude Code, use the /openacp:handoff slash command\n3. The session appears as a new topic/thread and you can continue chatting there\n\n### How it works\n- The agent session ID is shared between platforms\n- Conversation history is preserved \u2014 pick up where you left off\n- The agent that supports resume (e.g., Claude with `--resume`) handles the actual transfer\n\n---\n\n## Managing Sessions\n\n### Status\n- `/status` \u2014 Shows active sessions count and details\n- Ask the Assistant: \"What sessions are running?\"\n\n### List all sessions\n- `/sessions` \u2014 Shows all sessions with status (active, finished, error)\n\n### Cancel\n- `/cancel` in a session topic \u2014 cancels that session\n- Ask the Assistant: \"Cancel the stuck session\"\n\n### Cleanup\n- From `/sessions` \u2192 tap cleanup buttons (finished, errors, all)\n- Ask the Assistant: \"Clean up old sessions\"\n\n---\n\n## Assistant Topic\n\nThe Assistant is an always-on AI helper in its own topic. It can:\n- Answer questions about OpenACP\n- Create sessions for you\n- Check status and health\n- Cancel sessions\n- Clean up old sessions\n- Troubleshoot issues\n- Manage configuration\n\nJust chat naturally: \"How do I create a session?\", \"What's the status?\", \"Something is stuck\"\n\n### Clear history\n`/clear` in the Assistant topic \u2014 resets the conversation\n\n---\n\n## System Commands\n\n| Command | Where | What it does |\n|---------|-------|-------------|\n| `/new [agent] [path]` | Anywhere | Create new session |\n| `/newchat` | Session topic | New session, same agent + folder |\n| `/cancel` | Session topic | Cancel current session |\n| `/status` | Anywhere | Show status |\n| `/sessions` | Anywhere | List all sessions |\n| `/agents` | Anywhere | Browse & install agents from ACP Registry |\n| `/install <name>` | Anywhere | Install an agent |\n| `/bypass_permissions` | Session topic | Toggle bypass permissions (on/off) |\n| `/handoff` | Session topic | Transfer session to terminal |\n| `/clear` | Assistant topic | Clear assistant history |\n| `/menu` | Anywhere | Show action menu |\n| `/help` | Anywhere | Show help |\n| `/restart` | Anywhere | Restart OpenACP |\n| `/update` | Anywhere | Update to latest version |\n| `/integrate` | Anywhere | Manage agent integrations |\n\n---\n\n## Menu Buttons\n\n| Button | Action |\n|--------|--------|\n| \uD83C\uDD95 New Session | Create new session (interactive) |\n| \uD83D\uDCCB Sessions | List all sessions with cleanup options |\n| \uD83D\uDCCA Status | Show active/total session count |\n| \uD83E\uDD16 Agents | List available agents |\n| \uD83D\uDD17 Integrate | Manage agent integrations |\n| \u2753 Help | Show help text |\n| \uD83D\uDD04 Restart | Restart OpenACP |\n| \u2B06\uFE0F Update | Check and install updates |\n\n---\n\n## CLI Commands\n\n### Server\n- `openacp` \u2014 Start (uses configured mode: foreground or daemon)\n- `openacp start` \u2014 Start as background daemon\n- `openacp stop` \u2014 Stop daemon\n- `openacp status` \u2014 Show daemon status\n- `openacp logs` \u2014 Tail daemon logs\n- `openacp --foreground` \u2014 Force foreground mode (useful for debugging or containers)\n\n### Auto-start (run on boot)\n- macOS: installs a LaunchAgent in `~/Library/LaunchAgents/`\n- Linux: installs a systemd user service in `~/.config/systemd/user/`\n- Enabled automatically when you start the daemon. Remove with `openacp stop`.\n\n### Configuration\n- `openacp config` \u2014 Interactive config editor\n- `openacp reset` \u2014 Delete all data and start fresh\n\n### Agent Management (CLI)\n- `openacp agents` \u2014 List all agents (installed + available from ACP Registry)\n- `openacp agents install <name>` \u2014 Install an agent\n- `openacp agents uninstall <name>` \u2014 Remove an agent\n- `openacp agents info <name>` \u2014 Show details, dependencies, and setup guide\n- `openacp agents run <name> [-- args]` \u2014 Run agent CLI directly (for login, config, etc.)\n- `openacp agents refresh` \u2014 Force-refresh registry cache\n\n### Plugins\n- `openacp install <package>` \u2014 Install adapter plugin\n- `openacp uninstall <package>` \u2014 Remove adapter plugin\n- `openacp plugins` \u2014 List installed plugins\n\n### Integration\n- `openacp integrate <agent>` \u2014 Install agent integration (e.g., Claude handoff skill)\n- `openacp integrate <agent> --uninstall` \u2014 Remove integration\n\n### API (requires running daemon)\n`openacp api <command>` \u2014 Interact with running daemon:\n\n| Command | Description |\n|---------|-------------|\n| `status` | List active sessions |\n| `session <id>` | Session details |\n| `new <agent> <path>` | Create session |\n| `send <id> \"text\"` | Send prompt |\n| `cancel <id>` | Cancel session |\n| `bypass <id> on/off` | Toggle bypass permissions |\n| `topics [--status x,y]` | List topics |\n| `delete-topic <id> [--force]` | Delete topic |\n| `cleanup [--status x,y]` | Cleanup old topics |\n| `agents` | List agents |\n| `health` | System health |\n| `config` | Show config |\n| `config set <key> <value>` | Update config |\n| `adapters` | List adapters |\n| `tunnel` | Tunnel status |\n| `notify \"message\"` | Send notification |\n| `version` | Daemon version |\n| `restart` | Restart daemon |\n\n---\n\n## File Viewer (Tunnel)\n\nWhen tunnel is enabled, file edits and diffs get \"View\" buttons that open in your browser:\n- **Monaco Editor** \u2014 Full VS Code editor with syntax highlighting\n- **Diff viewer** \u2014 Side-by-side or inline comparison\n- **Line highlighting** \u2014 Click lines to highlight\n- Dark/light theme toggle\n\n### Setup\nEnable in config: set `tunnel.enabled` to `true`.\nProviders: Cloudflare (default, free), ngrok, bore, Tailscale Funnel.\n\n### Port Tunneling\n\nExpose any local port (dev servers, APIs, etc.) to the internet:\n\n**CLI commands** (agent can call these directly):\n- `openacp tunnel add <port> --label <name>` \u2014 Create tunnel to a local port\n- `openacp tunnel list` \u2014 List active tunnels\n- `openacp tunnel stop <port>` \u2014 Stop a tunnel\n- `openacp tunnel stop-all` \u2014 Stop all user tunnels\n\n**Telegram commands**:\n- `/tunnel <port> [label]` \u2014 Create tunnel\n- `/tunnels` \u2014 List active tunnels\n- `/tunnel stop <port>` \u2014 Stop tunnel\n\nExample: after starting a dev server on port 3000, run `openacp tunnel add 3000 --label my-app` to get a public URL.\n\n---\n\n## Configuration\n\nConfig file: `~/.openacp/config.json`\n\n### Channels\n- **channels.telegram.botToken** \u2014 Your Telegram bot token\n- **channels.telegram.chatId** \u2014 Your Telegram supergroup ID\n- **channels.discord.botToken** \u2014 Your Discord bot token\n- **channels.discord.guildId** \u2014 Your Discord server (guild) ID\n\n### Agents\n- **defaultAgent** \u2014 Which agent to use by default\n- Agents are managed via `/agents` (Telegram) or `openacp agents` (CLI)\n- Installed agents are stored in `~/.openacp/agents.json`\n- Agent list is fetched from the ACP Registry CDN and cached locally (24h)\n\n### Workspace\n- **workspace.baseDir** \u2014 Base directory for project folders (default: `~/openacp-workspace`)\n\n### Security\n- **security.allowedUserIds** \u2014 Restrict who can use the bot (empty = everyone)\n- **security.maxConcurrentSessions** \u2014 Max parallel sessions (default: 5)\n- **security.sessionTimeoutMinutes** \u2014 Auto-cancel idle sessions (default: 60)\n\n### Tunnel / File Viewer\n- **tunnel.enabled** \u2014 Enable file viewer tunnel\n- **tunnel.provider** \u2014 Tunnel provider: cloudflare (default, free), ngrok, bore, tailscale\n- **tunnel.port** \u2014 Local port for tunnel server (default: 3100)\n- **tunnel.auth.enabled** \u2014 Enable authentication for tunnel URLs\n- **tunnel.auth.token** \u2014 Auth token for tunnel access\n- **tunnel.storeTtlMinutes** \u2014 How long viewer links stay cached (default: 60)\n\n### Logging\n- **logging.level** \u2014 Log level: silent, debug, info, warn, error, fatal (default: info)\n- **logging.logDir** \u2014 Log directory (default: `~/.openacp/logs`)\n- **logging.maxFileSize** \u2014 Max log file size before rotation\n- **logging.maxFiles** \u2014 Max number of rotated log files\n- **logging.sessionLogRetentionDays** \u2014 Auto-delete old session logs (default: 30)\n\n### Data Retention\n- **sessionStore.ttlDays** \u2014 How long session records persist (default: 30). Old records are cleaned up automatically.\n\n### Environment variables\nOverride config with env vars:\n- `OPENACP_TELEGRAM_BOT_TOKEN`\n- `OPENACP_TELEGRAM_CHAT_ID`\n- `OPENACP_DISCORD_BOT_TOKEN`\n- `OPENACP_DISCORD_GUILD_ID`\n- `OPENACP_DEFAULT_AGENT`\n- `OPENACP_RUN_MODE` \u2014 foreground or daemon\n- `OPENACP_API_PORT` \u2014 API server port (default: 21420)\n- `OPENACP_TUNNEL_ENABLED`\n- `OPENACP_TUNNEL_PORT`\n- `OPENACP_TUNNEL_PROVIDER`\n- `OPENACP_LOG_LEVEL`\n- `OPENACP_LOG_DIR`\n- `OPENACP_DEBUG` \u2014 Sets log level to debug\n\n---\n\n## Troubleshooting\n\n### Session stuck / not responding\n- Check status: ask Assistant \"Is anything stuck?\"\n- Cancel and create new: `/cancel` then `/new`\n- Check system health: Assistant can run health check\n\n### Agent not found\n- Check available agents: `/agents` or `openacp agents`\n- Install missing agent: `openacp agents install <name>`\n- Some agents need login first: `openacp agents info <name>` to see setup steps\n- Run agent CLI for setup: `openacp agents run <name> -- <args>`\n\n### Permission request not showing\n- Check Notifications topic for the alert\n- Try `/bypass_permissions on` to auto-approve (if you trust the agent)\n\n### Session disappeared after restart\n- Sessions persist across restarts\n- Send a message in the old topic \u2014 it auto-resumes\n- If topic was deleted, the session record may still exist in status\n\n### Bot not responding at all\n- Check daemon: `openacp status`\n- Check logs: `openacp logs`\n- Restart: `openacp start` or `/restart`\n\n### Messages going to wrong topic\n- Each session is bound to a specific topic/thread\n- If you see messages appearing in the Assistant topic instead of the session topic, try creating a new session\n\n### Viewing logs\n- Session-specific logs: `~/.openacp/logs/sessions/`\n- System logs: `openacp logs` to tail live\n- Set `OPENACP_DEBUG=true` for verbose output\n\n---\n\n## Data & Storage\n\nAll data is stored in `~/.openacp/`:\n- `config.json` \u2014 Configuration\n- `agents.json` \u2014 Installed agents (managed by AgentCatalog)\n- `registry-cache.json` \u2014 Cached ACP Registry data (refreshes every 24h)\n- `agents/` \u2014 Downloaded binary agents\n- `sessions/` \u2014 Session records and state\n- `topics/` \u2014 Topic-to-session mappings\n- `logs/` \u2014 System and session logs\n- `plugins/` \u2014 Installed adapter plugins\n- `openacp.pid` \u2014 Daemon PID file\n\nSession records auto-cleanup: 30 days (configurable via `sessionStore.ttlDays`).\nSession logs auto-cleanup: 30 days (configurable via `logging.sessionLogRetentionDays`).\n";
2742
+ declare const PRODUCT_GUIDE = "\n# OpenACP \u2014 Product Guide\n\nOpenACP lets you chat with AI coding agents (like Claude Code) through messaging platforms (Telegram, Discord).\nYou type messages in your chat platform, the agent reads/writes/runs code in your project folder, and results stream back in real time.\n\n---\n\n## Quick Start\n\n1. Start OpenACP: `openacp` (or `openacp start` for background daemon)\n2. Open your messaging platform (Telegram group or Discord server) \u2014 you'll see the Assistant topic/thread\n3. Tap/click \uD83C\uDD95 New Session or type /new\n4. Pick an agent and a project folder\n5. Chat in the session topic/thread \u2014 the agent works on your code\n\n---\n\n## Core Concepts\n\n### Sessions\nA session = one conversation with one AI agent working in one project folder.\nEach session gets its own topic (Telegram) or forum thread (Discord). Chat there to give instructions to the agent.\n\n### Agents\nAn agent is an AI coding tool (e.g., Claude Code, Gemini, Cursor, Codex, etc.).\nOpenACP supports 28+ agents from the official ACP Registry (agentclientprotocol.com).\nYou can install multiple agents and choose which one to use per session.\nThe default agent is used when you don't specify one.\n\n### Agent Management\n- Browse agents: `/agents` in your chat platform or `openacp agents` in CLI\n- Install: tap the install button in /agents, or `openacp agents install <name>`\n- Uninstall: `openacp agents uninstall <name>`\n- Setup/login: `openacp agents run <name> -- <args>` (e.g., `openacp agents run gemini -- auth login`)\n- Details: `openacp agents info <name>` shows version, dependencies, and setup steps\n\nSome agents need additional setup before they can be used:\n- Claude: requires `claude login`\n- Gemini: requires `openacp agents run gemini -- auth login`\n- Codex: requires setting `OPENAI_API_KEY` environment variable\n- GitHub Copilot: requires `openacp agents run copilot -- auth login`\n\nAgents are installed in three ways depending on the agent:\n- **npx** \u2014 Node.js agents, downloaded automatically on first use\n- **uvx** \u2014 Python agents, downloaded automatically on first use\n- **binary** \u2014 Platform-specific binaries, downloaded to `~/.openacp/agents/`\n\n### Project Folder (Workspace)\nThe directory where the agent reads, writes, and runs code.\nWhen creating a session, you choose which folder the agent works in.\nYou can type a full path like `~/code/my-project` or just a name like `my-project` (it becomes `<base-dir>/my-project`).\n\n### System Topics\n- **Assistant** \u2014 Always-on helper that can answer questions, create sessions, check status, troubleshoot\n- **Notifications** \u2014 System alerts (permission requests, session errors, completions)\n\n---\n\n## Creating Sessions\n\n### From menu\nTap \uD83C\uDD95 New Session \u2192 choose agent (if multiple) \u2192 choose project folder \u2192 confirm\n\n### From command\n- `/new` \u2014 Interactive flow (asks agent + folder)\n- `/new claude ~/code/my-project` \u2014 Create directly with specific agent and folder\n\n### From Assistant topic\nJust ask: \"Create a session for my-project with claude\" \u2014 the assistant handles it\n\n### Quick new chat\n`/newchat` in a session topic \u2014 creates new session with same agent and folder as current one\n\n---\n\n## Working with Sessions\n\n### Chat\nType messages in the session topic. The agent responds with code changes, explanations, tool outputs.\n\n### What you see while the agent works\n- **\uD83D\uDCAD Thinking indicator** \u2014 Shows when the agent is reasoning, with elapsed time\n- **Text responses** \u2014 Streamed in real time, updated every few seconds\n- **Tool calls** \u2014 When the agent runs commands or edits files, you see tool name, input, status, and output\n- **\uD83D\uDCCB Plan card** \u2014 Visual task progress with completed/in-progress/pending items and progress bar\n- **\"View File\" / \"View Diff\" buttons** \u2014 Opens in browser with Monaco editor (requires tunnel)\n\n### Session lifecycle\n1. **Creating** \u2014 Topic created, agent spawning\n2. **Warming up** \u2014 Agent primes its cache (happens automatically, invisible to you)\n3. **Active** \u2014 Ready for your messages\n4. **Auto-naming** \u2014 After your first message, the session gets a descriptive name (agent summarizes in ~5 words). The topic title updates automatically.\n5. **Finished/Error** \u2014 Session completed or hit an error\n\n### Agent skills\nSome agents provide slash commands (e.g., /compact, /review). Available skills are pinned in the session topic.\n\n### Permission requests\nWhen the agent wants to run a command, it asks for permission.\nYou see buttons: \u2705 Allow, \u274C Reject (and sometimes \"Always Allow\").\nA notification also appears in the Notifications topic with a link to the request.\n\n### Bypass permissions\nAuto-approves ALL permission requests \u2014 the agent runs any command without asking.\n- Toggle: `/bypass_permissions on` or tap the \u2620\uFE0F button in the session\n- Disable: `/bypass_permissions off` or tap the \uD83D\uDD10 button\n- \u26A0\uFE0F Use with caution \u2014 the agent can execute anything\n\n### Session timeout\nIdle sessions are automatically cancelled after a configurable timeout (default: 60 minutes).\nConfigure via `security.sessionTimeoutMinutes` in config.\n\n---\n\n## Session Transfer (Handoff)\n\n### Chat \u2192 Terminal\n1. Type `/handoff` in a session topic/thread\n2. You get a command like `claude --resume <SESSION_ID>`\n3. Copy and run it in your terminal \u2014 the session continues there with full conversation history\n\n### Terminal \u2192 Chat\n1. First time: run `openacp integrate <agent>` to install handoff integration (one-time setup)\n2. In supported agents (for example Claude Code or OpenCode), use /openacp:handoff\n3. The session appears as a new topic/thread and you can continue chatting there\n\n### How it works\n- The agent session ID is shared between platforms\n- Conversation history is preserved \u2014 pick up where you left off\n- The agent that supports resume (e.g., Claude with `--resume`) handles the actual transfer\n\n---\n\n## Managing Sessions\n\n### Status\n- `/status` \u2014 Shows active sessions count and details\n- Ask the Assistant: \"What sessions are running?\"\n\n### List all sessions\n- `/sessions` \u2014 Shows all sessions with status (active, finished, error)\n\n### Cancel\n- `/cancel` in a session topic \u2014 cancels that session\n- Ask the Assistant: \"Cancel the stuck session\"\n\n### Cleanup\n- From `/sessions` \u2192 tap cleanup buttons (finished, errors, all)\n- Ask the Assistant: \"Clean up old sessions\"\n\n---\n\n## Assistant Topic\n\nThe Assistant is an always-on AI helper in its own topic. It can:\n- Answer questions about OpenACP\n- Create sessions for you\n- Check status and health\n- Cancel sessions\n- Clean up old sessions\n- Troubleshoot issues\n- Manage configuration\n\nJust chat naturally: \"How do I create a session?\", \"What's the status?\", \"Something is stuck\"\n\n### Clear history\n`/clear` in the Assistant topic \u2014 resets the conversation\n\n---\n\n## System Commands\n\n| Command | Where | What it does |\n|---------|-------|-------------|\n| `/new [agent] [path]` | Anywhere | Create new session |\n| `/newchat` | Session topic | New session, same agent + folder |\n| `/cancel` | Session topic | Cancel current session |\n| `/status` | Anywhere | Show status |\n| `/sessions` | Anywhere | List all sessions |\n| `/agents` | Anywhere | Browse & install agents from ACP Registry |\n| `/install <name>` | Anywhere | Install an agent |\n| `/bypass_permissions` | Session topic | Toggle bypass permissions (on/off) |\n| `/handoff` | Session topic | Transfer session to terminal |\n| `/clear` | Assistant topic | Clear assistant history |\n| `/menu` | Anywhere | Show action menu |\n| `/help` | Anywhere | Show help |\n| `/restart` | Anywhere | Restart OpenACP |\n| `/update` | Anywhere | Update to latest version |\n| `/integrate` | Anywhere | Manage agent integrations |\n\n---\n\n## Menu Buttons\n\n| Button | Action |\n|--------|--------|\n| \uD83C\uDD95 New Session | Create new session (interactive) |\n| \uD83D\uDCCB Sessions | List all sessions with cleanup options |\n| \uD83D\uDCCA Status | Show active/total session count |\n| \uD83E\uDD16 Agents | List available agents |\n| \uD83D\uDD17 Integrate | Manage agent integrations |\n| \u2753 Help | Show help text |\n| \uD83D\uDD04 Restart | Restart OpenACP |\n| \u2B06\uFE0F Update | Check and install updates |\n\n---\n\n## CLI Commands\n\n### Server\n- `openacp` \u2014 Start (uses configured mode: foreground or daemon)\n- `openacp start` \u2014 Start as background daemon\n- `openacp stop` \u2014 Stop daemon\n- `openacp status` \u2014 Show daemon status\n- `openacp logs` \u2014 Tail daemon logs\n- `openacp --foreground` \u2014 Force foreground mode (useful for debugging or containers)\n\n### Auto-start (run on boot)\n- macOS: installs a LaunchAgent in `~/Library/LaunchAgents/`\n- Linux: installs a systemd user service in `~/.config/systemd/user/`\n- Enabled automatically when you start the daemon. Remove with `openacp stop`.\n\n### Configuration\n- `openacp config` \u2014 Interactive config editor\n- `openacp reset` \u2014 Delete all data and start fresh\n\n### Agent Management (CLI)\n- `openacp agents` \u2014 List all agents (installed + available from ACP Registry)\n- `openacp agents install <name>` \u2014 Install an agent\n- `openacp agents uninstall <name>` \u2014 Remove an agent\n- `openacp agents info <name>` \u2014 Show details, dependencies, and setup guide\n- `openacp agents run <name> [-- args]` \u2014 Run agent CLI directly (for login, config, etc.)\n- `openacp agents refresh` \u2014 Force-refresh registry cache\n\n### Plugins\n- `openacp install <package>` \u2014 Install adapter plugin\n- `openacp uninstall <package>` \u2014 Remove adapter plugin\n- `openacp plugins` \u2014 List installed plugins\n\n### Integration\n- `openacp integrate <agent>` \u2014 Install agent integration (e.g., Claude handoff skill)\n- `openacp integrate <agent> --uninstall` \u2014 Remove integration\n\n### API (requires running daemon)\n`openacp api <command>` \u2014 Interact with running daemon:\n\n| Command | Description |\n|---------|-------------|\n| `status` | List active sessions |\n| `session <id>` | Session details |\n| `new <agent> <path>` | Create session |\n| `send <id> \"text\"` | Send prompt |\n| `cancel <id>` | Cancel session |\n| `bypass <id> on/off` | Toggle bypass permissions |\n| `topics [--status x,y]` | List topics |\n| `delete-topic <id> [--force]` | Delete topic |\n| `cleanup [--status x,y]` | Cleanup old topics |\n| `agents` | List agents |\n| `health` | System health |\n| `config` | Show config |\n| `config set <key> <value>` | Update config |\n| `adapters` | List adapters |\n| `tunnel` | Tunnel status |\n| `notify \"message\"` | Send notification |\n| `version` | Daemon version |\n| `restart` | Restart daemon |\n\n---\n\n## File Viewer (Tunnel)\n\nWhen tunnel is enabled, file edits and diffs get \"View\" buttons that open in your browser:\n- **Monaco Editor** \u2014 Full VS Code editor with syntax highlighting\n- **Diff viewer** \u2014 Side-by-side or inline comparison\n- **Line highlighting** \u2014 Click lines to highlight\n- Dark/light theme toggle\n\n### Setup\nEnable in config: set `tunnel.enabled` to `true`.\nProviders: Cloudflare (default, free), ngrok, bore, Tailscale Funnel.\n\n### Port Tunneling\n\nExpose any local port (dev servers, APIs, etc.) to the internet:\n\n**CLI commands** (agent can call these directly):\n- `openacp tunnel add <port> --label <name>` \u2014 Create tunnel to a local port\n- `openacp tunnel list` \u2014 List active tunnels\n- `openacp tunnel stop <port>` \u2014 Stop a tunnel\n- `openacp tunnel stop-all` \u2014 Stop all user tunnels\n\n**Telegram commands**:\n- `/tunnel <port> [label]` \u2014 Create tunnel\n- `/tunnels` \u2014 List active tunnels\n- `/tunnel stop <port>` \u2014 Stop tunnel\n\nExample: after starting a dev server on port 3000, run `openacp tunnel add 3000 --label my-app` to get a public URL.\n\n---\n\n## Configuration\n\nConfig file: `~/.openacp/config.json`\n\n### Channels\n- **channels.telegram.botToken** \u2014 Your Telegram bot token\n- **channels.telegram.chatId** \u2014 Your Telegram supergroup ID\n- **channels.discord.botToken** \u2014 Your Discord bot token\n- **channels.discord.guildId** \u2014 Your Discord server (guild) ID\n\n### Agents\n- **defaultAgent** \u2014 Which agent to use by default\n- Agents are managed via `/agents` (Telegram) or `openacp agents` (CLI)\n- Installed agents are stored in `~/.openacp/agents.json`\n- Agent list is fetched from the ACP Registry CDN and cached locally (24h)\n\n### Workspace\n- **workspace.baseDir** \u2014 Base directory for project folders (default: `~/openacp-workspace`)\n\n### Security\n- **security.allowedUserIds** \u2014 Restrict who can use the bot (empty = everyone)\n- **security.maxConcurrentSessions** \u2014 Max parallel sessions (default: 5)\n- **security.sessionTimeoutMinutes** \u2014 Auto-cancel idle sessions (default: 60)\n\n### Tunnel / File Viewer\n- **tunnel.enabled** \u2014 Enable file viewer tunnel\n- **tunnel.provider** \u2014 Tunnel provider: cloudflare (default, free), ngrok, bore, tailscale\n- **tunnel.port** \u2014 Local port for tunnel server (default: 3100)\n- **tunnel.auth.enabled** \u2014 Enable authentication for tunnel URLs\n- **tunnel.auth.token** \u2014 Auth token for tunnel access\n- **tunnel.storeTtlMinutes** \u2014 How long viewer links stay cached (default: 60)\n\n### Logging\n- **logging.level** \u2014 Log level: silent, debug, info, warn, error, fatal (default: info)\n- **logging.logDir** \u2014 Log directory (default: `~/.openacp/logs`)\n- **logging.maxFileSize** \u2014 Max log file size before rotation\n- **logging.maxFiles** \u2014 Max number of rotated log files\n- **logging.sessionLogRetentionDays** \u2014 Auto-delete old session logs (default: 30)\n\n### Data Retention\n- **sessionStore.ttlDays** \u2014 How long session records persist (default: 30). Old records are cleaned up automatically.\n\n### Environment variables\nOverride config with env vars:\n- `OPENACP_TELEGRAM_BOT_TOKEN`\n- `OPENACP_TELEGRAM_CHAT_ID`\n- `OPENACP_DISCORD_BOT_TOKEN`\n- `OPENACP_DISCORD_GUILD_ID`\n- `OPENACP_DEFAULT_AGENT`\n- `OPENACP_RUN_MODE` \u2014 foreground or daemon\n- `OPENACP_API_PORT` \u2014 API server port (default: 21420)\n- `OPENACP_TUNNEL_ENABLED`\n- `OPENACP_TUNNEL_PORT`\n- `OPENACP_TUNNEL_PROVIDER`\n- `OPENACP_LOG_LEVEL`\n- `OPENACP_LOG_DIR`\n- `OPENACP_DEBUG` \u2014 Sets log level to debug\n\n---\n\n## Troubleshooting\n\n### Session stuck / not responding\n- Check status: ask Assistant \"Is anything stuck?\"\n- Cancel and create new: `/cancel` then `/new`\n- Check system health: Assistant can run health check\n\n### Agent not found\n- Check available agents: `/agents` or `openacp agents`\n- Install missing agent: `openacp agents install <name>`\n- Some agents need login first: `openacp agents info <name>` to see setup steps\n- Run agent CLI for setup: `openacp agents run <name> -- <args>`\n\n### Permission request not showing\n- Check Notifications topic for the alert\n- Try `/bypass_permissions on` to auto-approve (if you trust the agent)\n\n### Session disappeared after restart\n- Sessions persist across restarts\n- Send a message in the old topic \u2014 it auto-resumes\n- If topic was deleted, the session record may still exist in status\n\n### Bot not responding at all\n- Check daemon: `openacp status`\n- Check logs: `openacp logs`\n- Restart: `openacp start` or `/restart`\n\n### Messages going to wrong topic\n- Each session is bound to a specific topic/thread\n- If you see messages appearing in the Assistant topic instead of the session topic, try creating a new session\n\n### Viewing logs\n- Session-specific logs: `~/.openacp/logs/sessions/`\n- System logs: `openacp logs` to tail live\n- Set `OPENACP_DEBUG=true` for verbose output\n\n---\n\n## Data & Storage\n\nAll data is stored in `~/.openacp/`:\n- `config.json` \u2014 Configuration\n- `agents.json` \u2014 Installed agents (managed by AgentCatalog)\n- `registry-cache.json` \u2014 Cached ACP Registry data (refreshes every 24h)\n- `agents/` \u2014 Downloaded binary agents\n- `sessions/` \u2014 Session records and state\n- `topics/` \u2014 Topic-to-session mappings\n- `logs/` \u2014 System and session logs\n- `plugins/` \u2014 Installed adapter plugins\n- `openacp.pid` \u2014 Daemon PID file\n\nSession records auto-cleanup: 30 days (configurable via `sessionStore.ttlDays`).\nSession logs auto-cleanup: 30 days (configurable via `logging.sessionLogRetentionDays`).\n";
3087
2743
 
3088
2744
  interface TelegramChannelConfig extends ChannelConfig {
3089
2745
  botToken: string;
@@ -3118,6 +2774,10 @@ declare class TelegramAdapter extends MessagingAdapter {
3118
2774
  private controlMsgIds;
3119
2775
  private _threadReadyHandler?;
3120
2776
  private _configChangedHandler?;
2777
+ /** True once topics are initialized and Phase 2 is complete */
2778
+ private _topicsInitialized;
2779
+ /** Background watcher timer — cancelled on stop() or when topics succeed */
2780
+ private _prerequisiteWatcher;
3121
2781
  /** Store control message ID in memory + persist to session record */
3122
2782
  private storeControlMsgId;
3123
2783
  /** Get control message ID (from Map, with fallback to session record) */
@@ -3139,6 +2799,8 @@ declare class TelegramAdapter extends MessagingAdapter {
3139
2799
  * Non-critical — bot works fine without autocomplete commands.
3140
2800
  */
3141
2801
  private registerCommandsWithRetry;
2802
+ private initTopicDependentFeatures;
2803
+ private startPrerequisiteWatcher;
3142
2804
  stop(): Promise<void>;
3143
2805
  private renderCommandResponse;
3144
2806
  private toCallbackData;
@@ -3188,4 +2850,4 @@ declare class TelegramAdapter extends MessagingAdapter {
3188
2850
  archiveSessionTopic(sessionId: string): Promise<void>;
3189
2851
  }
3190
2852
 
3191
- export { ActivityTracker, AdapterCapabilities, AgentCapabilities, AgentCatalog, AgentCommand, AgentDefinition, AgentEvent, AgentInstance, AgentListItem, AgentManager, AgentStore, AgentSwitchEntry, type ApiConfig, type ApiServerInstance, type ApiServerOptions, type ApiServerService, type AssistantCommand, AssistantManager, AssistantRegistry, type AssistantSection, Attachment, AvailabilityResult, BaseRenderer, type BridgeDeps, CONFIG_REGISTRY, ChannelConfig, type CleanupResult, type CommandArgs, type CommandDef, CommandRegistry, type CommandResponse, type Config, type ConfigFieldDef, ConfigManager, ConfigOption, ContextManager, type ContextOptions, type ContextProvider, type ContextQuery, type ContextResult, type ContextService, type SessionInfo as ContextSessionInfo, type DeleteTopicResult, DisplaySpecBuilder, DisplayVerbosity, DoctorEngine, type DoctorReport, DraftManager, EntireProvider, EventBus, type EventBusEvents, FileService, type FileServiceInterface, GroqSTT, IChannelAdapter, type IRenderer, IncomingMessage, type InstallContext, InstallProgress, InstallResult, InstalledAgent, type ListItem, type Logger, type LoggingConfig, McpServerConfig, type MenuItem, type MenuOption, MenuRegistry, MessageTransformer, MessagingAdapter, type MessagingAdapterConfig, type MigrateContext, NotificationManager, NotificationMessage, type NotificationService, OpenACPCore, type OpenACPPlugin, OutgoingMessage, OutputMode, OutputModeResolver, PRODUCT_GUIDE, type PendingFix, PermissionGate, PermissionRequest, PlanEntry, type PluginContext, type PluginPermission, type PluginStorage, PromptQueue, RegistryAgent, type RenderedMessage, SSEManager, type STTOptions, type STTProvider, type STTResult, SecurityGuard, type SecurityService, SendQueue, Session, SessionBridge, type SessionCreateParams, type SessionEvents, SessionFactory, type SessionListResult, SessionManager, SessionRecord, SessionStatus, type SessionSummary, SetConfigOptionValue, type SettingsAPI, type SideEffectDeps, type SpeechProviderConfig, SpeechService, type SpeechServiceConfig, type SpeechServiceInterface, StaticServer, StderrCapture, StopReason, StreamAdapter, type TTSOptions, type TTSProvider, type TTSResult, TelegramAdapter, type TerminalIO, ThoughtBuffer, type ThoughtDisplaySpec, ToolCallMeta, ToolCallTracker, type ToolCardSnapshot, ToolCardState, type ToolCardStateConfig, type ToolDisplaySpec, type ToolEntry, ToolStateMap, type TopicInfo, TopicManager, type TunnelServiceInterface, TurnContext, TurnRouting, TypedEmitter, type UsageConfig, UsageRecord, UsageRecordEvent, type UsageService, ViewerLinks, cleanupOldSessionLogs, createApiServer, createApiServerService, createChildLogger, createSessionLogger, expandHome, extractContentText, formatTokens, formatToolSummary, formatToolTitle, getConfigValue, getFieldDef, getPidPath, getSafeFields, getStatus, initLogger, installAutoStart, isAutoStartInstalled, isAutoStartSupported, isHotReloadable, log, nodeToWebReadable, nodeToWebWritable, progressBar, resolveOptions, resolveToolIcon, runConfigEditor, setLogLevel, shutdownLogger, splitMessage, startDaemon, stopDaemon, stripCodeFences, truncateContent, uninstallAutoStart };
2853
+ export { ActivityTracker, AdapterCapabilities, AgentCapabilities, AgentCatalog, AgentCommand, AgentDefinition, AgentEvent, AgentInstance, AgentListItem, AgentManager, AgentStore, AgentSwitchEntry, type ApiConfig, type ApiServerInstance, type ApiServerOptions, type ApiServerService, type AssistantCommand, AssistantManager, AssistantRegistry, type AssistantSection, Attachment, AvailabilityResult, BaseRenderer, type BridgeDeps, CONFIG_REGISTRY, ChannelConfig, type CleanupResult, type CommandArgs, type CommandDef, CommandRegistry, type CommandResponse, type Config, type ConfigFieldDef, ConfigManager, ConfigOption, ContextManager, type ContextOptions, type ContextProvider, type ContextQuery, type ContextResult, type ContextService, type SessionInfo as ContextSessionInfo, type DeleteTopicResult, DisplaySpecBuilder, DisplayVerbosity, DoctorEngine, type DoctorReport, DraftManager, EntireProvider, EventBus, type EventBusEvents, type FieldDef, FileService, type FileServiceInterface, GroqSTT, IChannelAdapter, type IRenderer, IncomingMessage, type InstallContext, InstallProgress, InstallResult, InstalledAgent, type ListItem, type Logger, type LoggingConfig, McpServerConfig, type MenuItem, type MenuOption, MenuRegistry, MessageTransformer, MessagingAdapter, type MessagingAdapterConfig, type MigrateContext, NotificationManager, NotificationMessage, type NotificationService, OpenACPCore, type OpenACPPlugin, OutgoingMessage, OutputMode, OutputModeResolver, PRODUCT_GUIDE, type PendingFix, PermissionGate, PermissionRequest, PlanEntry, type PluginContext, type PluginPermission, type PluginStorage, PromptQueue, RegistryAgent, type RenderedMessage, SSEManager, type STTOptions, type STTProvider, type STTResult, SecurityGuard, type SecurityService, SendQueue, Session, SessionBridge, type SessionCreateParams, type SessionEvents, SessionFactory, type SessionListResult, SessionManager, SessionRecord, SessionStatus, type SessionSummary, SetConfigOptionValue, type SettingsAPI, type SideEffectDeps, type SpeechProviderConfig, SpeechService, type SpeechServiceConfig, type SpeechServiceInterface, StaticServer, StderrCapture, StopReason, StreamAdapter, type TTSOptions, type TTSProvider, type TTSResult, TelegramAdapter, type TerminalIO, ThoughtBuffer, type ThoughtDisplaySpec, ToolCallMeta, ToolCallTracker, type ToolCardSnapshot, ToolCardState, type ToolCardStateConfig, type ToolDisplaySpec, type ToolEntry, ToolStateMap, type TopicInfo, TopicManager, type TunnelServiceInterface, TurnContext, TurnRouting, TypedEmitter, UsageRecord, UsageRecordEvent, type UsageService, ViewerLinks, cleanupOldSessionLogs, createApiServer, createApiServerService, createChildLogger, createSessionLogger, expandHome, extractContentText, formatTokens, formatToolSummary, formatToolTitle, getConfigValue, getFieldDef, getPidPath, getSafeFields, getStatus, initLogger, installAutoStart, isAutoStartInstalled, isAutoStartSupported, isHotReloadable, log, nodeToWebReadable, nodeToWebWritable, progressBar, resolveOptions, resolveToolIcon, runConfigEditor, setLogLevel, shutdownLogger, splitMessage, startDaemon, stopDaemon, stripCodeFences, truncateContent, uninstallAutoStart };