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) ⇒ 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, file/shell previews) sent to IM chats



34
35
36
37
# File 'lib/clacky/server/channel/channel_config.rb', line 34

def initialize(channels: {}, status_messages: false)
  @channels        = channels || {}
  @status_messages = status_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:



42
43
44
45
46
47
48
49
50
# File 'lib/clacky/server/channel/channel_config.rb', line 42

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"])
end

Instance Method Details

#any_enabled?Boolean

Returns true if at least one channel is enabled.

Returns:

  • (Boolean)


67
68
69
# File 'lib/clacky/server/channel/channel_config.rb', line 67

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

#deep_copyChannelConfig

Deep copy - prevents callers from mutating shared config state.

Returns:



189
190
191
# File 'lib/clacky/server/channel/channel_config.rb', line 189

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

#disable_platform(platform) ⇒ Object

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

Parameters:

  • platform (Symbol, String)


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

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.



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

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)


82
83
84
85
# File 'lib/clacky/server/channel/channel_config.rb', line 82

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>)


73
74
75
76
77
78
# File 'lib/clacky/server/channel/channel_config.rb', line 73

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)


92
93
94
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
# File 'lib/clacky/server/channel/channel_config.rb', line 92

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

#remove_platform(platform) ⇒ Object

Remove a platform entry entirely.

Parameters:

  • platform (Symbol, String)


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

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)


54
55
56
57
58
# File 'lib/clacky/server/channel/channel_config.rb', line 54

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



145
146
147
148
149
150
# File 'lib/clacky/server/channel/channel_config.rb', line 145

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_status_messages(enabled) ⇒ Object

Enable/disable process-status messages globally.

Parameters:

  • enabled (Boolean)


160
161
162
# File 'lib/clacky/server/channel/channel_config.rb', line 160

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

#status_messages_enabled?Boolean

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

Returns:

  • (Boolean)


154
155
156
# File 'lib/clacky/server/channel/channel_config.rb', line 154

def status_messages_enabled?
  @status_messages == true
end

#to_yamlString

Serialize to YAML string.

Returns:

  • (String)


62
63
64
# File 'lib/clacky/server/channel/channel_config.rb', line 62

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