Class: Clacky::ChannelConfig

Inherits:
Object
  • Object
show all
Defined in:
lib/clacky/server/channel/channel_config.rb

Overview

ChannelConfig manages IM platform credentials (Feishu, WeCom, etc.).

Config is stored in ~/.clacky/channels.yml:

channels:
feishu:
  enabled: true
  app_id: cli_xxx
  app_secret: xxx
  domain: https://open.feishu.cn
  allowed_users:
    - ou_xxx
wecom:
  enabled: false
  bot_id: xxx
  secret: xxx

This class is only responsible for platform credentials. working_dir and permission_mode live in AgentConfig.

Constant Summary collapse

CONFIG_DIR =
File.join(Dir.home, ".clacky")
CONFIG_FILE =
File.join(CONFIG_DIR, "channels.yml")

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(channels: {}, status_messages: false, process_messages: false) ⇒ ChannelConfig

Returns a new instance of ChannelConfig.

Parameters:

  • channels (Hash<String, Hash>) (defaults to: {})

    string-keyed platform configs (raw from YAML)

  • status_messages (Boolean) (defaults to: false)

    global toggle for process-status messages ("Thinking...", "Done" summary) sent to IM chats

  • process_messages (Boolean) (defaults to: false)

    global toggle for tool-process messages (interim narration, file/shell previews) sent to IM chats



36
37
38
39
40
# File 'lib/clacky/server/channel/channel_config.rb', line 36

def initialize(channels: {}, status_messages: false, process_messages: false)
  @channels         = channels || {}
  @status_messages  = status_messages == true ? true : false
  @process_messages = process_messages == true ? true : false
end

Class Method Details

.load(config_file = CONFIG_FILE) ⇒ ChannelConfig

Load from disk. Returns an empty instance if the file does not exist.

Parameters:

  • config_file (String) (defaults to: CONFIG_FILE)

Returns:



45
46
47
48
49
50
51
52
53
# File 'lib/clacky/server/channel/channel_config.rb', line 45

def self.load(config_file = CONFIG_FILE)
  if File.exist?(config_file)
    data = YAMLCompat.safe_load(File.read(config_file), permitted_classes: [Symbol]) || {}
  else
    data = {}
  end

  new(channels: data["channels"] || {}, status_messages: data["status_messages"], process_messages: data["process_messages"])
end

Instance Method Details

#any_enabled?Boolean

Returns true if at least one channel is enabled.

Returns:

  • (Boolean)


70
71
72
# File 'lib/clacky/server/channel/channel_config.rb', line 70

def any_enabled?
  @channels.any? { |_, cfg| cfg["enabled"] }
end

#deep_copyChannelConfig

Deep copy - prevents callers from mutating shared config state.

Returns:



204
205
206
# File 'lib/clacky/server/channel/channel_config.rb', line 204

def deep_copy
  self.class.new(channels: JSON.parse(JSON.generate(@channels)), status_messages: @status_messages, process_messages: @process_messages)
end

#disable_platform(platform) ⇒ Object

Disable a platform (keeps credentials, just sets enabled: false).

Parameters:

  • platform (Symbol, String)


190
191
192
193
194
# File 'lib/clacky/server/channel/channel_config.rb', line 190

def disable_platform(platform)
  key = platform.to_s
  return unless @channels.key?(key)
  @channels[key]["enabled"] = false
end

#enable_platform(platform) ⇒ Object

Enable a platform (requires it to already be configured).

Parameters:

  • platform (Symbol, String)

Raises:

  • (ArgumentError)

    if the platform has no stored credentials yet.



182
183
184
185
186
# File 'lib/clacky/server/channel/channel_config.rb', line 182

def enable_platform(platform)
  key = platform.to_s
  raise ArgumentError, "Platform #{platform} is not configured" unless @channels.key?(key)
  @channels[key]["enabled"] = true
end

#enabled?(platform) ⇒ Boolean

Returns true if the given platform is configured and enabled.

Parameters:

  • platform (Symbol, String)

Returns:

  • (Boolean)


85
86
87
88
# File 'lib/clacky/server/channel/channel_config.rb', line 85

def enabled?(platform)
  cfg = @channels[platform.to_s]
  cfg && cfg["enabled"]
end

#enabled_platformsArray<Symbol>

Returns the list of enabled platform symbols.

Returns:

  • (Array<Symbol>)


76
77
78
79
80
81
# File 'lib/clacky/server/channel/channel_config.rb', line 76

def enabled_platforms
  @channels
    .select { |_, cfg| cfg["enabled"] }
    .keys
    .map(&:to_sym)
end

#platform_config(platform) ⇒ Hash?

Return the symbol-keyed config hash expected by each adapter's initializer. Returns nil if the platform is not configured.

Parameters:

  • platform (Symbol, String)

Returns:

  • (Hash, nil)


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/clacky/server/channel/channel_config.rb', line 95

def platform_config(platform)
  raw = @channels[platform.to_s]
  return nil unless raw

  case platform.to_sym
  when :feishu
    {
      app_id:        raw["app_id"],
      app_secret:    raw["app_secret"],
      domain:        raw["domain"],
      allowed_users: raw["allowed_users"]
    }.compact
  when :wecom
    {
      bot_id: raw["bot_id"],
      secret: raw["secret"]
    }.compact
  when :weixin
    {
      token:         raw["token"],
      base_url:      raw["base_url"],
      allowed_users: raw["allowed_users"]
    }.compact
  when :discord
    {
      bot_token:     raw["bot_token"]
    }.compact
  when :dingtalk
    {
      client_id:     raw["client_id"],
      client_secret: raw["client_secret"],
      allowed_users: raw["allowed_users"]
    }.compact
  when :telegram
    {
      bot_token:     raw["bot_token"],
      base_url:      raw["base_url"],
      parse_mode:    raw.key?("parse_mode") ? raw["parse_mode"] : "Markdown",
      allowed_users: raw["allowed_users"]
    }.compact
  else
    # Unknown platform — pass all non-meta keys as symbol-keyed hash
    raw.reject { |k, _| k == "enabled" }
       .transform_keys(&:to_sym)
  end
end

#process_messages_enabled?Boolean

Global toggle: whether tool-process messages (interim narration, file/shell previews) are sent to IM chats. Defaults to false.

Returns:

  • (Boolean)


169
170
171
# File 'lib/clacky/server/channel/channel_config.rb', line 169

def process_messages_enabled?
  @process_messages == true
end

#remove_platform(platform) ⇒ Object

Remove a platform entry entirely.

Parameters:

  • platform (Symbol, String)


198
199
200
# File 'lib/clacky/server/channel/channel_config.rb', line 198

def remove_platform(platform)
  @channels.delete(platform.to_s)
end

#save(config_file = CONFIG_FILE) ⇒ Object

Persist to disk.

Parameters:

  • config_file (String) (defaults to: CONFIG_FILE)


57
58
59
60
61
# File 'lib/clacky/server/channel/channel_config.rb', line 57

def save(config_file = CONFIG_FILE)
  FileUtils.mkdir_p(File.dirname(config_file))
  File.write(config_file, to_yaml)
  FileUtils.chmod(0o600, config_file)
end

#set_platform(platform, **fields) ⇒ Object

Set or update a platform's credentials. Merges provided fields into the existing entry. Automatically sets enabled: true unless explicitly provided.

Parameters:

  • platform (Symbol, String)
  • fields (Hash)

    symbol-keyed credential fields



148
149
150
151
152
153
# File 'lib/clacky/server/channel/channel_config.rb', line 148

def set_platform(platform, **fields)
  key = platform.to_s
  @channels[key] ||= {}
  fields.each { |k, v| @channels[key][k.to_s] = v }
  @channels[key]["enabled"] = true unless @channels[key].key?("enabled")
end

#set_process_messages(enabled) ⇒ Object

Enable/disable tool-process messages globally.

Parameters:

  • enabled (Boolean)


175
176
177
# File 'lib/clacky/server/channel/channel_config.rb', line 175

def set_process_messages(enabled)
  @process_messages = enabled ? true : false
end

#set_status_messages(enabled) ⇒ Object

Enable/disable process-status messages globally.

Parameters:

  • enabled (Boolean)


163
164
165
# File 'lib/clacky/server/channel/channel_config.rb', line 163

def set_status_messages(enabled)
  @status_messages = enabled ? true : false
end

#status_messages_enabled?Boolean

Global toggle: whether process-status messages ("Thinking...", "Done" summary) are sent to IM chats. Defaults to false.

Returns:

  • (Boolean)


157
158
159
# File 'lib/clacky/server/channel/channel_config.rb', line 157

def status_messages_enabled?
  @status_messages == true
end

#to_yamlString

Serialize to YAML string.

Returns:

  • (String)


65
66
67
# File 'lib/clacky/server/channel/channel_config.rb', line 65

def to_yaml
  YAML.dump({ "status_messages" => @status_messages, "process_messages" => @process_messages, "channels" => @channels })
end