slk 0.15.0 → 0.16.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +5 -3
- data/lib/slk/api/huddles.rb +25 -0
- data/lib/slk/commands/debug.rb +25 -3
- data/lib/slk/commands/huddles.rb +2 -1
- data/lib/slk/commands/who.rb +4 -3
- data/lib/slk/services/api_client.rb +1 -1
- data/lib/slk/services/huddle_fetch.rb +10 -1
- data/lib/slk/services/huddle_room.rb +47 -0
- data/lib/slk/services/huddle_room_enricher.rb +88 -0
- data/lib/slk/services/huddle_scanner.rb +12 -6
- data/lib/slk/services/pooled_fanout.rb +59 -0
- data/lib/slk/version.rb +1 -1
- data/lib/slk.rb +4 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5edea2fd65213e0875f06f53729966f8658ae880bd38321bd9a9d8980200c07a
|
|
4
|
+
data.tar.gz: 7a532e0e1991807962aae21099ad2e9c2c98b03a364dc3e6db90ebf7f2fdabf6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 256c73b33433f9488bfcd1333c14f57e953e80fea54a07500239933cdf2129e682beb5d18cc3ab6f730d77570fd103ea77ab2b2ad7f2f8386d80924e6240f5e1
|
|
7
|
+
data.tar.gz: 388ffeef9e34949a549fb4cc7bcd8560e7132ad9ebde68b189c7dccfac5b749e3e21445c41fea2f614e5a3f1f179101b45b15727a219a3ab289d916aa0cb4f8a
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.16.0] - 2026-10-29
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `slk debug huddle <call id|user>` (hidden command) prints the raw `huddles.get` response. A user is resolved to the call in their profile's `huddle_state_call_id`.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- `slk huddles` and `slk who` show the huddle's channel again. Slack stopped sending `huddle_state_channel_id` on profiles, so every huddle read "channel unknown". The call id is now looked up with `huddles.get`, which also adds Slack Connect guests missing from `users.list`. Huddles in conversations you can't see still show "channel unknown". Room and guest-name lookups run on four connections per workspace, about 3× faster than one at a time.
|
|
19
|
+
|
|
10
20
|
## [0.15.0] - 2026-10-13
|
|
11
21
|
|
|
12
22
|
### Added
|
data/README.md
CHANGED
|
@@ -232,9 +232,11 @@ slk huddles --json # Call id, channel, and participants
|
|
|
232
232
|
```
|
|
233
233
|
|
|
234
234
|
Slack has no huddle list. `slk huddles` reads `huddle_state` from `users.list`
|
|
235
|
-
and groups people who share a call id.
|
|
236
|
-
|
|
237
|
-
Slack Connect guests
|
|
235
|
+
and groups people who share a call id. Profiles no longer say which channel a
|
|
236
|
+
huddle is in, so each call id is looked up with `huddles.get` (undocumented),
|
|
237
|
+
which also lists Slack Connect guests missing from the roster. That only works
|
|
238
|
+
for conversations you can see; any other huddle shows "channel unknown" and
|
|
239
|
+
only its roster members. The roster is
|
|
238
240
|
fetched live and is not cached. `--all` scans every workspace at the same time.
|
|
239
241
|
One connection can only read one roster, so each workspace gets its own.
|
|
240
242
|
People who are not in a huddle are dropped as each page arrives. `slk who`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Slk
|
|
4
|
+
module Api
|
|
5
|
+
# Wrapper for Slack's undocumented huddles.* endpoints (the web client's).
|
|
6
|
+
class Huddles
|
|
7
|
+
def initialize(api_client, workspace)
|
|
8
|
+
@api = api_client
|
|
9
|
+
@workspace = workspace
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# The room for one call id: channels, live participants, has_ended.
|
|
13
|
+
# Raises not_authorized for a huddle in a conversation the token
|
|
14
|
+
# cannot see.
|
|
15
|
+
def get(huddle_id)
|
|
16
|
+
info(huddle_id)['huddle'] || {}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The whole response, for `slk debug huddle`.
|
|
20
|
+
def info(huddle_id)
|
|
21
|
+
@api.post(@workspace, 'huddles.get', { huddle_id: huddle_id })
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/slk/commands/debug.rb
CHANGED
|
@@ -25,12 +25,13 @@ module Slk
|
|
|
25
25
|
in ['profile'] then dump_profile(nil)
|
|
26
26
|
in ['team'] then dump_team
|
|
27
27
|
in ['schema'] then dump_schema
|
|
28
|
-
in [
|
|
29
|
-
in ['channel', target] then dump_channel(target)
|
|
28
|
+
in [action, target] if TARGET_ACTIONS.key?(action) then send(TARGET_ACTIONS[action], target)
|
|
30
29
|
else unknown_action
|
|
31
30
|
end
|
|
32
31
|
end
|
|
33
32
|
|
|
33
|
+
TARGET_ACTIONS = { 'thread' => :dump_thread, 'channel' => :dump_channel, 'huddle' => :dump_huddle }.freeze
|
|
34
|
+
|
|
34
35
|
private
|
|
35
36
|
|
|
36
37
|
def dump_profile(user_input)
|
|
@@ -79,6 +80,26 @@ module Slk
|
|
|
79
80
|
0
|
|
80
81
|
end
|
|
81
82
|
|
|
83
|
+
# Raw huddles.get for a call id (R...), or for the call a user is in
|
|
84
|
+
# now. Profiles carry only the call id; this is where the channel and
|
|
85
|
+
# the full participant list (Slack Connect guests too) come from.
|
|
86
|
+
def dump_huddle(target)
|
|
87
|
+
workspace = runner.workspace(@options[:workspace])
|
|
88
|
+
call_id = huddle_call_id(workspace, target)
|
|
89
|
+
output.puts(JSON.pretty_generate(Api::Huddles.new(api_client, workspace).info(call_id)))
|
|
90
|
+
0
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def huddle_call_id(workspace, target)
|
|
94
|
+
return target if target.match?(/\AR[A-Z0-9]+\z/)
|
|
95
|
+
|
|
96
|
+
user_id = resolve_user_id(workspace, target)
|
|
97
|
+
call_id = runner.users_api(workspace.name).info(user_id).dig('user', 'profile', 'huddle_state_call_id')
|
|
98
|
+
raise ApiError, "#{target} is not in a huddle" if call_id.to_s.empty?
|
|
99
|
+
|
|
100
|
+
call_id
|
|
101
|
+
end
|
|
102
|
+
|
|
82
103
|
def resolve_target(target)
|
|
83
104
|
Services::TargetResolver.new(runner: runner, cache_store: cache_store)
|
|
84
105
|
.resolve(target, default_workspace: runner.workspace(@options[:workspace]))
|
|
@@ -128,7 +149,7 @@ module Slk
|
|
|
128
149
|
|
|
129
150
|
def unknown_action
|
|
130
151
|
error("Unknown debug action: #{positional_args.first.inspect}")
|
|
131
|
-
error('Valid actions: profile [user], team, schema, thread <url>, channel <id|url>')
|
|
152
|
+
error('Valid actions: profile [user], team, schema, thread <url>, channel <id|url>, huddle <call|user>')
|
|
132
153
|
1
|
|
133
154
|
end
|
|
134
155
|
|
|
@@ -146,6 +167,7 @@ module Slk
|
|
|
146
167
|
schema Dump team.profile.get
|
|
147
168
|
thread <url> Dump thread parent + subscriptions.thread.get
|
|
148
169
|
channel <id|url> Dump conversations.info (also #name)
|
|
170
|
+
huddle <call|user> Dump huddles.get for a call id (R...) or a user's current call
|
|
149
171
|
|
|
150
172
|
USER
|
|
151
173
|
(none) | me Self
|
data/lib/slk/commands/huddles.rb
CHANGED
|
@@ -25,7 +25,8 @@ module Slk
|
|
|
25
25
|
help.note('Slack has no huddle list. This reads huddle_state from users.list')
|
|
26
26
|
help.note('and groups people who share a call id. The roster is fetched live.')
|
|
27
27
|
help.note('Primary workspace only. --all scans every workspace at the same time.')
|
|
28
|
-
help.note('
|
|
28
|
+
help.note('Channels and Slack Connect guests come from huddles.get, so only')
|
|
29
|
+
help.note('huddles in conversations you can see get them.')
|
|
29
30
|
add_options_section(help)
|
|
30
31
|
add_examples_section(help)
|
|
31
32
|
help.render
|
data/lib/slk/commands/who.rb
CHANGED
|
@@ -89,12 +89,13 @@ module Slk
|
|
|
89
89
|
# Channel ids are useless on a card. A failed lookup still leaves the
|
|
90
90
|
# state, which is the part Slack always sends.
|
|
91
91
|
def attach_huddle_channel(workspace, profile)
|
|
92
|
-
|
|
92
|
+
channel_id = Services::HuddleRoom.new(api_client: api_client, workspace: workspace).channel_for(profile)
|
|
93
|
+
return profile if channel_id.to_s.empty?
|
|
93
94
|
|
|
94
|
-
label = huddle_channels.label(workspace,
|
|
95
|
+
label = huddle_channels.label(workspace, channel_id)
|
|
95
96
|
return profile unless label
|
|
96
97
|
|
|
97
|
-
Models::Profile.new(**profile.to_h, huddle_channel: label)
|
|
98
|
+
Models::Profile.new(**profile.to_h, huddle_channel_id: channel_id, huddle_channel: label)
|
|
98
99
|
end
|
|
99
100
|
|
|
100
101
|
def huddle_channels
|
|
@@ -13,6 +13,7 @@ module Slk
|
|
|
13
13
|
@output = output
|
|
14
14
|
@counts = {}
|
|
15
15
|
@mutex = Mutex.new
|
|
16
|
+
@cache_mutex = Mutex.new
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def call(workspaces)
|
|
@@ -30,7 +31,8 @@ module Slk
|
|
|
30
31
|
def fetch(workspace)
|
|
31
32
|
client = scan_client
|
|
32
33
|
users = Api::Users.new(client, workspace, on_debug: debug_logger)
|
|
33
|
-
HuddleScanner.group(collect(workspace, users))
|
|
34
|
+
huddles = HuddleScanner.group(collect(workspace, users))
|
|
35
|
+
enricher(workspace, client).call(huddles)
|
|
34
36
|
ensure
|
|
35
37
|
close_client(client)
|
|
36
38
|
end
|
|
@@ -49,6 +51,13 @@ module Slk
|
|
|
49
51
|
Models::WorkspaceHuddles.new(workspace: workspace.name, huddles: labeled)
|
|
50
52
|
end
|
|
51
53
|
|
|
54
|
+
def enricher(workspace, client)
|
|
55
|
+
HuddleRoomEnricher.new(
|
|
56
|
+
workspace: workspace, client: client, cache_store: @runner.cache_store,
|
|
57
|
+
cache_mutex: @cache_mutex, on_debug: debug_logger
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
52
61
|
def scan_client
|
|
53
62
|
return @runner.api_client.isolated if @parallel
|
|
54
63
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Slk
|
|
4
|
+
module Services
|
|
5
|
+
# Fills in what a profile no longer says about a huddle.
|
|
6
|
+
#
|
|
7
|
+
# Slack stopped sending huddle_state_channel_id; profiles carry only the
|
|
8
|
+
# state and the call id. huddles.get maps the call id to its channel and
|
|
9
|
+
# the full participant list, which includes Slack Connect guests who are
|
|
10
|
+
# missing from users.list. A huddle the token cannot see is left as is.
|
|
11
|
+
class HuddleRoom
|
|
12
|
+
Room = Data.define(:channel_id, :participant_ids)
|
|
13
|
+
|
|
14
|
+
def initialize(api_client:, workspace:, on_debug: nil)
|
|
15
|
+
@api = Api::Huddles.new(api_client, workspace)
|
|
16
|
+
@on_debug = on_debug
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Room, nil]
|
|
20
|
+
def lookup(call_id)
|
|
21
|
+
return nil if call_id.to_s.empty?
|
|
22
|
+
|
|
23
|
+
room = @api.get(call_id)
|
|
24
|
+
return nil if room.empty? || room['has_ended']
|
|
25
|
+
|
|
26
|
+
Room.new(channel_id: single_channel(room), participant_ids: Array(room['participants']))
|
|
27
|
+
rescue ApiError => e
|
|
28
|
+
@on_debug&.call("huddles.get #{call_id} failed: #{e.message}")
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# A profile's channel id if Slack sent one, else the room's.
|
|
33
|
+
def channel_for(profile)
|
|
34
|
+
return profile.huddle_channel_id unless profile.huddle_channel_id.to_s.empty?
|
|
35
|
+
|
|
36
|
+
lookup(profile.huddle_call_id)&.channel_id
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def single_channel(room)
|
|
42
|
+
channels = Array(room['channels']).reject { |id| id.to_s.empty? }.uniq
|
|
43
|
+
channels.first if channels.one?
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Slk
|
|
4
|
+
module Services
|
|
5
|
+
# Adds what profiles no longer say to one workspace's huddles: the
|
|
6
|
+
# channel, and Slack Connect guests missing from users.list.
|
|
7
|
+
#
|
|
8
|
+
# huddles.get runs once per call id, and users.info once per guest whose
|
|
9
|
+
# name is not cached, both on a small worker pool so a busy workspace
|
|
10
|
+
# does not wait on dozens of requests in a row. Workspaces are scanned
|
|
11
|
+
# concurrently too, so cache reads and writes go through cache_mutex.
|
|
12
|
+
class HuddleRoomEnricher
|
|
13
|
+
WORKERS = 4
|
|
14
|
+
|
|
15
|
+
def initialize(workspace:, client:, cache_store:, cache_mutex:, on_debug: nil)
|
|
16
|
+
@workspace = workspace
|
|
17
|
+
@client = client
|
|
18
|
+
@cache = cache_store
|
|
19
|
+
@cache_mutex = cache_mutex
|
|
20
|
+
@on_debug = on_debug
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def call(huddles)
|
|
24
|
+
rooms = fan_out(huddles) { |huddle, client| room_for(huddle, client) }
|
|
25
|
+
names = guest_names(guest_ids(huddles, rooms))
|
|
26
|
+
HuddleScanner.sort(huddles.zip(rooms).map { |huddle, room| apply(huddle, room, names) })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def fan_out(items, &)
|
|
32
|
+
PooledFanout.call(items, workers: WORKERS, client: @client, &)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def room_for(huddle, client)
|
|
36
|
+
return nil if huddle.channel_id || huddle.call_id.nil?
|
|
37
|
+
|
|
38
|
+
HuddleRoom.new(api_client: client, workspace: @workspace, on_debug: @on_debug).lookup(huddle.call_id)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def guest_ids(huddles, rooms)
|
|
42
|
+
huddles.zip(rooms).flat_map do |huddle, room|
|
|
43
|
+
room ? room.participant_ids - huddle.participants.map(&:id) : []
|
|
44
|
+
end.uniq
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def guest_names(ids)
|
|
48
|
+
cached = cached_names(ids)
|
|
49
|
+
missing = ids - cached.keys
|
|
50
|
+
fetched = missing.zip(fan_out(missing) { |id, client| fetch_name(id, client) }).to_h.compact
|
|
51
|
+
remember(fetched)
|
|
52
|
+
cached.merge(fetched)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def cached_names(ids)
|
|
56
|
+
@cache_mutex.synchronize { ids.to_h { |id| [id, @cache.get_user(@workspace.name, id)] }.compact }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def fetch_name(user_id, client)
|
|
60
|
+
user = Api::Users.new(client, @workspace, on_debug: @on_debug).info(user_id)['user']
|
|
61
|
+
user && Models::User.from_api(user).best_name
|
|
62
|
+
rescue ApiError => e
|
|
63
|
+
@on_debug&.call("User lookup failed for #{user_id}: #{e.message}")
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def remember(names)
|
|
68
|
+
return if names.empty?
|
|
69
|
+
|
|
70
|
+
@cache_mutex.synchronize do
|
|
71
|
+
names.each { |id, name| @cache.set_user(@workspace.name, id, name) }
|
|
72
|
+
@cache.save_user_cache(@workspace.name)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def apply(huddle, room, names)
|
|
77
|
+
return huddle unless room
|
|
78
|
+
|
|
79
|
+
known = huddle.participants.map(&:id)
|
|
80
|
+
added = (room.participant_ids - known).map do |id|
|
|
81
|
+
Models::HuddleParticipant.new(id: id, name: names[id] || id)
|
|
82
|
+
end
|
|
83
|
+
huddle.with(channel_id: room.channel_id,
|
|
84
|
+
participants: HuddleScanner.sort_participants(huddle.participants + added))
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -26,12 +26,22 @@ module Slk
|
|
|
26
26
|
member.dig('profile', 'huddle_state') == IN_HUDDLE
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def self.sort(huddles)
|
|
30
|
+
huddles.sort_by do |huddle|
|
|
31
|
+
[-huddle.participants.size, huddle.participants.first.name.downcase, huddle.call_id.to_s]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.sort_participants(people)
|
|
36
|
+
people.sort_by { |person| [person.name.downcase, person.id] }
|
|
37
|
+
end
|
|
38
|
+
|
|
29
39
|
def initialize(members)
|
|
30
40
|
@members = members
|
|
31
41
|
end
|
|
32
42
|
|
|
33
43
|
def group
|
|
34
|
-
|
|
44
|
+
self.class.sort(huddles)
|
|
35
45
|
end
|
|
36
46
|
|
|
37
47
|
private
|
|
@@ -67,7 +77,7 @@ module Slk
|
|
|
67
77
|
end
|
|
68
78
|
|
|
69
79
|
def sorted_participants(people)
|
|
70
|
-
people.map { |member| participant(member) }
|
|
80
|
+
self.class.sort_participants(people.map { |member| participant(member) })
|
|
71
81
|
end
|
|
72
82
|
|
|
73
83
|
def participant(member)
|
|
@@ -92,10 +102,6 @@ module Slk
|
|
|
92
102
|
text = value.to_s
|
|
93
103
|
text.empty? ? nil : text
|
|
94
104
|
end
|
|
95
|
-
|
|
96
|
-
def sort_key(huddle)
|
|
97
|
-
[-huddle.participants.size, huddle.participants.first.name.downcase, huddle.call_id.to_s]
|
|
98
|
-
end
|
|
99
105
|
end
|
|
100
106
|
end
|
|
101
107
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Slk
|
|
4
|
+
module Services
|
|
5
|
+
# Runs a block per item on a few worker threads, each with its own
|
|
6
|
+
# connection, and returns the results in the original order.
|
|
7
|
+
#
|
|
8
|
+
# Net::HTTP is not safe to share across threads, so every worker gets an
|
|
9
|
+
# isolated client and closes it when the queue is empty. A client that
|
|
10
|
+
# cannot isolate (a test double) runs the items one at a time on itself.
|
|
11
|
+
# A failure waits for the other workers, then raises.
|
|
12
|
+
module PooledFanout
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
def call(items, workers:, client:, &block)
|
|
16
|
+
return items.map { |item| block.call(item, client) } unless pooled?(items, workers, client)
|
|
17
|
+
|
|
18
|
+
queue = Queue.new
|
|
19
|
+
items.each_with_index { |item, index| queue << [item, index] }
|
|
20
|
+
queue.close
|
|
21
|
+
results = Array.new(items.size)
|
|
22
|
+
threads = Array.new([workers, items.size].min) { start(queue, results, client, &block) }
|
|
23
|
+
wait_for_all(threads)
|
|
24
|
+
threads.each(&:value)
|
|
25
|
+
results
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Thread#join re-raises a worker's exception at once, which would
|
|
29
|
+
# return before the other workers close their connections.
|
|
30
|
+
def wait_for_all(threads)
|
|
31
|
+
threads.each do |thread|
|
|
32
|
+
thread.join
|
|
33
|
+
rescue StandardError
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def pooled?(items, workers, client)
|
|
39
|
+
workers > 1 && items.size > 1 && client.respond_to?(:isolated)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def start(queue, results, client, &block)
|
|
43
|
+
worker_client = client.isolated
|
|
44
|
+
Thread.new { drain(queue, results, worker_client, &block) }.tap do |thread|
|
|
45
|
+
thread.report_on_exception = false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def drain(queue, results, client, &block)
|
|
50
|
+
while (job = queue.pop)
|
|
51
|
+
item, index = job
|
|
52
|
+
results[index] = block.call(item, client)
|
|
53
|
+
end
|
|
54
|
+
ensure
|
|
55
|
+
client.close if client.respond_to?(:close)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/slk/version.rb
CHANGED
data/lib/slk.rb
CHANGED
|
@@ -123,6 +123,9 @@ module Slk
|
|
|
123
123
|
autoload :HuddleScanner, 'slk/services/huddle_scanner'
|
|
124
124
|
autoload :HuddleFetch, 'slk/services/huddle_fetch'
|
|
125
125
|
autoload :HuddleState, 'slk/services/huddle_state'
|
|
126
|
+
autoload :HuddleRoom, 'slk/services/huddle_room'
|
|
127
|
+
autoload :HuddleRoomEnricher, 'slk/services/huddle_room_enricher'
|
|
128
|
+
autoload :PooledFanout, 'slk/services/pooled_fanout'
|
|
126
129
|
autoload :WorkspaceFanout, 'slk/services/workspace_fanout'
|
|
127
130
|
autoload :HuddleChannelLabel, 'slk/services/huddle_channel_label'
|
|
128
131
|
autoload :GroupDmLabel, 'slk/services/group_dm_label'
|
|
@@ -199,6 +202,7 @@ module Slk
|
|
|
199
202
|
autoload :Saved, 'slk/api/saved'
|
|
200
203
|
autoload :CustomStatus, 'slk/api/custom_status'
|
|
201
204
|
autoload :Team, 'slk/api/team'
|
|
205
|
+
autoload :Huddles, 'slk/api/huddles'
|
|
202
206
|
end
|
|
203
207
|
|
|
204
208
|
# Utility classes for paths, parsing, and helpers
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: slk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eric Boehs
|
|
@@ -33,6 +33,7 @@ files:
|
|
|
33
33
|
- lib/slk/api/custom_status.rb
|
|
34
34
|
- lib/slk/api/dnd.rb
|
|
35
35
|
- lib/slk/api/emoji.rb
|
|
36
|
+
- lib/slk/api/huddles.rb
|
|
36
37
|
- lib/slk/api/saved.rb
|
|
37
38
|
- lib/slk/api/search.rb
|
|
38
39
|
- lib/slk/api/team.rb
|
|
@@ -120,10 +121,13 @@ files:
|
|
|
120
121
|
- lib/slk/services/group_dm_label.rb
|
|
121
122
|
- lib/slk/services/huddle_channel_label.rb
|
|
122
123
|
- lib/slk/services/huddle_fetch.rb
|
|
124
|
+
- lib/slk/services/huddle_room.rb
|
|
125
|
+
- lib/slk/services/huddle_room_enricher.rb
|
|
123
126
|
- lib/slk/services/huddle_scanner.rb
|
|
124
127
|
- lib/slk/services/huddle_state.rb
|
|
125
128
|
- lib/slk/services/message_resolver.rb
|
|
126
129
|
- lib/slk/services/meta_cache.rb
|
|
130
|
+
- lib/slk/services/pooled_fanout.rb
|
|
127
131
|
- lib/slk/services/preset_store.rb
|
|
128
132
|
- lib/slk/services/profile_builder.rb
|
|
129
133
|
- lib/slk/services/profile_resolver.rb
|