lex-microsoft_teams 0.5.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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +16 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +56 -0
  6. data/CHANGELOG.md +59 -0
  7. data/CLAUDE.md +206 -0
  8. data/Dockerfile +6 -0
  9. data/Gemfile +12 -0
  10. data/Gemfile.lock +103 -0
  11. data/LICENSE +21 -0
  12. data/README.md +183 -0
  13. data/docs/plans/2026-03-15-meetings-transcripts-design.md +506 -0
  14. data/docs/plans/2026-03-16-delegated-oauth-browser-flow-design.md +198 -0
  15. data/docs/plans/2026-03-16-delegated-oauth-browser-flow-plan.md +1176 -0
  16. data/lex-microsoft_teams.gemspec +32 -0
  17. data/lib/legion/extensions/microsoft_teams/actors/cache_bulk_ingest.rb +41 -0
  18. data/lib/legion/extensions/microsoft_teams/actors/cache_sync.rb +54 -0
  19. data/lib/legion/extensions/microsoft_teams/actors/direct_chat_poller.rb +105 -0
  20. data/lib/legion/extensions/microsoft_teams/actors/message_processor.rb +23 -0
  21. data/lib/legion/extensions/microsoft_teams/actors/observed_chat_poller.rb +111 -0
  22. data/lib/legion/extensions/microsoft_teams/client.rb +68 -0
  23. data/lib/legion/extensions/microsoft_teams/helpers/browser_auth.rb +139 -0
  24. data/lib/legion/extensions/microsoft_teams/helpers/callback_server.rb +82 -0
  25. data/lib/legion/extensions/microsoft_teams/helpers/client.rb +38 -0
  26. data/lib/legion/extensions/microsoft_teams/helpers/high_water_mark.rb +59 -0
  27. data/lib/legion/extensions/microsoft_teams/helpers/prompt_resolver.rb +64 -0
  28. data/lib/legion/extensions/microsoft_teams/helpers/session_manager.rb +150 -0
  29. data/lib/legion/extensions/microsoft_teams/helpers/subscription_registry.rb +140 -0
  30. data/lib/legion/extensions/microsoft_teams/helpers/token_cache.rb +209 -0
  31. data/lib/legion/extensions/microsoft_teams/local_cache/extractor.rb +258 -0
  32. data/lib/legion/extensions/microsoft_teams/local_cache/record_parser.rb +199 -0
  33. data/lib/legion/extensions/microsoft_teams/local_cache/sstable_reader.rb +121 -0
  34. data/lib/legion/extensions/microsoft_teams/runners/adaptive_cards.rb +59 -0
  35. data/lib/legion/extensions/microsoft_teams/runners/auth.rb +116 -0
  36. data/lib/legion/extensions/microsoft_teams/runners/bot.rb +409 -0
  37. data/lib/legion/extensions/microsoft_teams/runners/cache_ingest.rb +122 -0
  38. data/lib/legion/extensions/microsoft_teams/runners/channel_messages.rb +52 -0
  39. data/lib/legion/extensions/microsoft_teams/runners/channels.rb +53 -0
  40. data/lib/legion/extensions/microsoft_teams/runners/chats.rb +51 -0
  41. data/lib/legion/extensions/microsoft_teams/runners/local_cache.rb +62 -0
  42. data/lib/legion/extensions/microsoft_teams/runners/meetings.rb +68 -0
  43. data/lib/legion/extensions/microsoft_teams/runners/messages.rb +48 -0
  44. data/lib/legion/extensions/microsoft_teams/runners/presence.rb +31 -0
  45. data/lib/legion/extensions/microsoft_teams/runners/subscriptions.rb +76 -0
  46. data/lib/legion/extensions/microsoft_teams/runners/teams.rb +33 -0
  47. data/lib/legion/extensions/microsoft_teams/runners/transcripts.rb +45 -0
  48. data/lib/legion/extensions/microsoft_teams/transport/exchanges/messages.rb +15 -0
  49. data/lib/legion/extensions/microsoft_teams/transport/messages/teams_message.rb +16 -0
  50. data/lib/legion/extensions/microsoft_teams/transport/queues/messages_process.rb +16 -0
  51. data/lib/legion/extensions/microsoft_teams/version.rb +9 -0
  52. data/lib/legion/extensions/microsoft_teams.rb +44 -0
  53. metadata +139 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c9f65eaac56b416e05eb5d96d914d6e3a88b86c91fdd083162fa09e5a6c887f4
4
+ data.tar.gz: ba6cd5f7d0d1b08cc8bc880cd8ab0db61d799ba66afaca8ae1938df057149a16
5
+ SHA512:
6
+ metadata.gz: e996a958fbffca134f301089fcc9c3be7abd03ef73f7b756f975198d3653dcbefaaa53a3ddf26c3afd33c92aea574f33336200604912088383e7ac6acdff54d5
7
+ data.tar.gz: 800d036ddcb4a99ee833b3abb3ff255a60f1102625ed8ef1ec0ea9ad90c0e0195b654b8b14a0fff41835eb4288191c62fd0aaf03fcb8b58b087c752b1c32f20e
@@ -0,0 +1,16 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+
7
+ jobs:
8
+ ci:
9
+ uses: LegionIO/.github/.github/workflows/ci.yml@main
10
+
11
+ release:
12
+ needs: ci
13
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
14
+ uses: LegionIO/.github/.github/workflows/release.yml@main
15
+ secrets:
16
+ rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ # local credentials
14
+ .env
15
+ test_device_code.rb
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,56 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.4
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+
6
+ Layout/LineLength:
7
+ Max: 160
8
+
9
+ Layout/SpaceAroundEqualsInParameterDefault:
10
+ EnforcedStyle: space
11
+
12
+ Layout/HashAlignment:
13
+ EnforcedHashRocketStyle: table
14
+ EnforcedColonStyle: table
15
+
16
+ Metrics/MethodLength:
17
+ Max: 50
18
+
19
+ Metrics/ClassLength:
20
+ Max: 1500
21
+
22
+ Metrics/ModuleLength:
23
+ Max: 1500
24
+
25
+ Metrics/BlockLength:
26
+ Max: 40
27
+ Exclude:
28
+ - 'spec/**/*'
29
+
30
+ Metrics/ParameterLists:
31
+ Max: 8
32
+
33
+ Metrics/AbcSize:
34
+ Max: 60
35
+
36
+ Metrics/CyclomaticComplexity:
37
+ Max: 15
38
+
39
+ Metrics/PerceivedComplexity:
40
+ Max: 17
41
+
42
+ Style/Documentation:
43
+ Enabled: false
44
+
45
+ Style/SymbolArray:
46
+ Enabled: true
47
+
48
+ Style/FrozenStringLiteralComment:
49
+ Enabled: true
50
+ EnforcedStyle: always
51
+
52
+ Naming/FileName:
53
+ Enabled: false
54
+
55
+ Naming/PredicateMethod:
56
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,59 @@
1
+ # Changelog
2
+
3
+ ## [0.5.0] - 2026-03-16
4
+
5
+ ### Added
6
+ - Delegated OAuth browser flow with Authorization Code + PKCE
7
+ - Automatic Device Code fallback for headless environments
8
+ - `Helpers::BrowserAuth` orchestrator (PKCE generation, headless detection, browser opening)
9
+ - `Helpers::CallbackServer` ephemeral TCP server for OAuth redirect
10
+ - `Runners::Auth#authorize_url`, `#exchange_code`, `#refresh_delegated_token` methods
11
+ - `Helpers::TokenCache` delegated token slot with Vault persistence and silent refresh
12
+ - `legion auth teams` CLI command (in LegionIO) for interactive authentication
13
+ - `GET /api/oauth/microsoft_teams/callback` Sinatra route (in LegionIO) for daemon re-auth
14
+
15
+ ### Fixed
16
+ - `poll_device_code` now persists `slow_down` interval increase per RFC 8628
17
+ - `poll_device_code` returns error hash on timeout instead of raising RuntimeError
18
+
19
+ ## [0.4.1] - 2026-03-15
20
+
21
+ ### Added
22
+ - Preference commands: `prefer <value>`, `preferences`, `reset preferences`
23
+ - PromptResolver queries PreferenceProfile for per-user system prompt customization
24
+ - SessionManager passes owner_id through to PromptResolver
25
+ - `SessionManager#refresh_prompt` rebuilds system prompt without clearing history
26
+
27
+ ## [0.4.0] - 2026-03-15
28
+
29
+ ### Added
30
+ - Meetings runner: list, get, create, update, delete online meetings, lookup by join URL, attendance reports
31
+ - Transcripts runner: list, get metadata, get content (VTT/DOCX format support)
32
+ - New Graph API permissions: `OnlineMeeting.Read.All`, `OnlineMeetingTranscript.Read.All`
33
+
34
+ ## [0.3.0] - 2026-03-15
35
+
36
+ ### Added
37
+ - Token cache helper with 60-second pre-expiry automatic refresh
38
+ - Subscription registry with in-memory store and lex-memory persistence
39
+ - Command handler for bot DMs: watch, unwatch, list, pause, resume
40
+ - Token cache wired into DirectChatPoller and ObservedChatPoller
41
+ - Subscription registry wired into ObservedChatPoller
42
+
43
+ ## [0.2.0] - 2026-03-15
44
+
45
+ ### Added
46
+ - AI bot with direct chat mode (LLM-powered 1:1 responses via polling)
47
+ - Conversation observer mode (task/context extraction from watched chats, default disabled)
48
+ - AMQP-based message routing (teams.messages exchange and queue)
49
+ - Session manager with lex-memory persistence for multi-turn conversations
50
+ - Layered prompt resolver (settings -> mode -> per-conversation overrides)
51
+ - High-water mark tracking for message deduplication
52
+ - DirectChatPoller actor (5s interval, Graph API polling)
53
+ - ObservedChatPoller actor (30s interval, compliance-gated)
54
+ - MessageProcessor subscription actor (AMQP consumer, routes by mode)
55
+
56
+ ## [0.1.0] - 2026-03-13
57
+
58
+ ### Added
59
+ - Initial release
data/CLAUDE.md ADDED
@@ -0,0 +1,206 @@
1
+ # lex-microsoft_teams: Microsoft Teams Integration for LegionIO
2
+
3
+ **Repository Level 3 Documentation**
4
+ - **Parent (Level 2)**: `/Users/miverso2/rubymine/legion/extensions/CLAUDE.md`
5
+ - **Parent (Level 1)**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
6
+
7
+ ## Purpose
8
+
9
+ Legion Extension that connects LegionIO to Microsoft Teams via Graph API and Bot Framework. Provides runners for chats, channels, messages, subscriptions (change notifications), adaptive cards, bot communication, and an AI-powered bot with conversation observation.
10
+
11
+ **GitHub**: https://github.com/LegionIO/lex-microsoft_teams
12
+ **License**: MIT
13
+ **Version**: 0.5.0
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ Legion::Extensions::MicrosoftTeams
19
+ ├── Runners/
20
+ │ ├── Auth # OAuth2 client credentials (Graph + Bot Framework)
21
+ │ ├── Teams # List/get teams, members
22
+ │ ├── Chats # 1:1 and group chat CRUD
23
+ │ ├── Messages # Chat message send/read/reply
24
+ │ ├── Channels # Team channel CRUD
25
+ │ ├── ChannelMessages # Channel message send/read/reply
26
+ │ ├── Subscriptions # Graph change notification webhooks
27
+ │ ├── AdaptiveCards # Adaptive Card payload builder
28
+ │ ├── Bot # Bot Framework + AI bot (handle_message, handle_command, observe_message)
29
+ │ ├── Presence # Graph API user presence
30
+ │ ├── Meetings # Online meeting CRUD, join URL lookup, attendance reports
31
+ │ ├── Transcripts # Meeting transcript list/get/content (VTT/DOCX)
32
+ │ ├── LocalCache # Offline message extraction from local LevelDB cache
33
+ │ └── CacheIngest # Ingest cached messages into lex-memory as episodic traces
34
+ ├── Actors/
35
+ │ ├── CacheBulkIngest # Once: full cache ingest at startup (imprint window support)
36
+ │ ├── CacheSync # Every 5min: incremental ingest of new messages
37
+ │ ├── DirectChatPoller # Every 5s: polls bot DM chats via Graph API
38
+ │ ├── ObservedChatPoller # Every 30s: polls subscribed human conversations (compliance-gated)
39
+ │ └── MessageProcessor # Subscription: consumes AMQP queue, routes by mode
40
+ ├── Transport/
41
+ │ ├── Exchanges/Messages # teams.messages topic exchange
42
+ │ ├── Queues/MessagesProcess # teams.messages.process durable queue
43
+ │ └── Messages/TeamsMessage # Message schema with routing key
44
+ ├── LocalCache/
45
+ │ ├── SSTableReader # Pure Ruby LevelDB .ldb file reader (Snappy decompression)
46
+ │ ├── RecordParser # Chromium IndexedDB value parser (field-value pairing)
47
+ │ └── Extractor # Message extraction, filtering, dedup from local cache
48
+ ├── Helpers/
49
+ │ ├── Client # Three connection builders (Graph, Bot, OAuth)
50
+ │ ├── HighWaterMark # Per-chat message dedup via legion-cache (with in-memory fallback)
51
+ │ ├── PromptResolver # Layered system prompt resolution (settings -> mode -> per-conversation)
52
+ │ ├── SessionManager # Multi-turn LLM session lifecycle with lex-memory persistence
53
+ │ ├── TokenCache # In-memory OAuth token cache with pre-expiry refresh (app + delegated slots)
54
+ │ ├── SubscriptionRegistry # Conversation observation subscriptions (in-memory + lex-memory)
55
+ │ ├── BrowserAuth # Delegated OAuth orchestrator (PKCE, headless detection, browser launch)
56
+ │ └── CallbackServer # Ephemeral TCP server for OAuth redirect callback
57
+ └── Client # Standalone client (includes all runners)
58
+ ```
59
+
60
+ ## Delegated Authentication (v0.5.0)
61
+
62
+ Opt-in browser-based OAuth for delegated Microsoft Graph permissions. Two flows:
63
+
64
+ - **Authorization Code + PKCE** (primary): Opens browser for Entra ID login, captures callback on ephemeral local port, exchanges code with PKCE verification
65
+ - **Device Code** (fallback): Auto-selected in headless/SSH environments (no `DISPLAY`/`WAYLAND_DISPLAY`)
66
+
67
+ Tokens stored in Vault (`legionio/microsoft_teams/delegated_token`) with configurable pre-expiry silent refresh. CLI command: `legion auth teams`. Sinatra route: `GET /api/oauth/microsoft_teams/callback` for daemon re-auth.
68
+
69
+ Key files: `Helpers::BrowserAuth` (orchestrator), `Helpers::CallbackServer` (ephemeral TCP), `Runners::Auth` (authorize_url, exchange_code, refresh_delegated_token), `Helpers::TokenCache` (delegated slot).
70
+
71
+ ## AI Bot (v0.2.0)
72
+
73
+ Two operating modes, both using polling (Graph API) with AMQP-based message routing:
74
+
75
+ ### Mode 1: Direct Chat
76
+ User DMs the bot 1:1. Bot responds via legion-llm with multi-turn session context.
77
+
78
+ ```
79
+ DirectChatPoller (5s) → AMQP exchange → MessageProcessor → Bot::handle_message
80
+ → SessionManager.get_or_create → llm_session.ask(text) → Graph API reply
81
+ ```
82
+
83
+ ### Mode 2: Conversation Observer
84
+ User subscribes the bot to watch a human 1:1 conversation. Bot passively extracts tasks, context, and relationship data.
85
+
86
+ ```
87
+ ObservedChatPoller (30s) → AMQP exchange → MessageProcessor → Bot::observe_message
88
+ → LLM extraction → lex-memory episodic trace → optional notification to owner
89
+ ```
90
+
91
+ **Observer is disabled by default** (`settings[:bot][:observe][:enabled] = false`). Compliance gate — must be explicitly enabled.
92
+
93
+ ### Message Flow
94
+
95
+ Both pollers publish to the same `teams.messages` AMQP exchange. The MessageProcessor subscription actor consumes from the queue and routes by `mode` field (`:direct` → `handle_message`, `:observe` → `observe_message`). This architecture supports a future webhook path: a `POST /api/hooks/microsoft_teams/bot` endpoint would publish to the same exchange with zero runner changes.
96
+
97
+ ### Configuration
98
+
99
+ Layered config cascade in `Legion::Settings[:microsoft_teams]`:
100
+
101
+ ```yaml
102
+ microsoft_teams:
103
+ auth:
104
+ tenant_id: "..."
105
+ client_id: "..."
106
+ client_secret: "vault://secret/teams/client_secret"
107
+ bot:
108
+ bot_id: "28:your-bot-id"
109
+ direct_poll_interval: 5 # seconds
110
+ observe_poll_interval: 30 # seconds
111
+ system_prompt: "You are a helpful assistant."
112
+ direct:
113
+ system_prompt: ~ # nil = inherit base
114
+ observe:
115
+ enabled: false # compliance gate
116
+ notify: false # DM notifications for action items
117
+ system_prompt: "Extract action items. Return structured JSON."
118
+ llm:
119
+ model: ~ # nil = use legion-llm router
120
+ intent:
121
+ capability: moderate
122
+ session:
123
+ flush_threshold: 20 # messages before auto-persist
124
+ idle_timeout: 900 # seconds (15 min)
125
+ max_recent_messages: 5 # kept raw on persist
126
+ ```
127
+
128
+ Per-conversation overrides stored in lex-memory (system_prompt_append, llm model/intent).
129
+
130
+ ### Key Design Decisions
131
+
132
+ - **Polling first, webhook later**: All connections outbound from user's local LegionIO instance. No public endpoint needed.
133
+ - **AMQP-first routing**: Pollers and future webhooks publish to the same exchange. Decouples ingestion from processing.
134
+ - **High-water marks**: Per-chat last-seen timestamp in legion-cache prevents reprocessing. Falls back to in-memory when cache unavailable.
135
+ - **Session persistence**: Multi-turn sessions flush to lex-memory on threshold (20 msgs), idle timeout (15 min), or shutdown. Restored on restart via summary + recent messages.
136
+ - **Token caching**: In-memory OAuth token cache refreshes 60 seconds before expiry. Both pollers share a `TokenCache` instance instead of hitting OAuth every cycle.
137
+ - **Subscription registry**: In-memory working set of observed conversations, persisted to lex-memory on change. No legion-data migration needed.
138
+ - **Design docs**: `docs/plans/2026-03-15-teams-ai-bot-design.md`, `docs/plans/2026-03-15-teams-bot-commands-design.md`
139
+
140
+ ### Bot Commands (v0.3.0)
141
+
142
+ Keyword-based command detection in bot DMs, checked before LLM response:
143
+
144
+ | Command | Action |
145
+ |---------|--------|
146
+ | `watch <name>` | Find chat via Graph API, subscribe to observe |
147
+ | `stop watching <name>` / `unwatch <name>` | Unsubscribe |
148
+ | `watching` / `list` / `subscriptions` | List active subscriptions |
149
+ | `pause <name>` | Disable subscription temporarily |
150
+ | `resume <name>` | Re-enable paused subscription |
151
+ | `prefer <value>` | Set preference (concise, detailed, formal, casual, etc.) |
152
+ | `preferences` / `my preferences` | Show current resolved preferences |
153
+ | `reset preferences` | Clear explicit preferences, fall back to observed/defaults |
154
+ | anything else | LLM response (existing flow) |
155
+
156
+ ## API Surface
157
+
158
+ Four distinct APIs accessed via Faraday + one local data source:
159
+ - **Microsoft Graph API** (`graph.microsoft.com/v1.0`) — chats, channels, messages, teams, subscriptions, presence
160
+ - **Bot Framework Service** (`service_url` per conversation) — send activities, create conversations
161
+ - **Entra ID OAuth** (`login.microsoftonline.com`) — client_credentials token acquisition
162
+ - **Local LevelDB Cache** (Chromium IndexedDB) — offline message extraction from Teams 2.x local storage
163
+
164
+ ## Graph API Permissions Required
165
+
166
+ | Permission | Type | Purpose |
167
+ |-----------|------|---------|
168
+ | `Chat.Read.All` | Application | Read chat messages |
169
+ | `Chat.ReadWrite.All` | Application | Send chat messages |
170
+ | `ChannelMessage.Read.All` | Application | Read channel messages |
171
+ | `ChannelMessage.Send` | Delegated | Send channel messages |
172
+ | `Team.ReadBasic.All` | Application | List teams and members |
173
+ | `Channel.ReadBasic.All` | Application | List channels |
174
+ | `Presence.Read.All` | Application | Read user presence |
175
+ | `OnlineMeetings.Read` | Delegated | Read online meetings (user context) |
176
+ | `OnlineMeetings.Read.All` | Application | Read online meetings |
177
+ | `OnlineMeetingTranscript.Read.All` | Application/Delegated | Read meeting transcripts |
178
+
179
+ For bot scenarios, register the Entra app as a Teams Bot via Bot Framework portal.
180
+
181
+ ## Dependencies
182
+
183
+ | Gem | Purpose |
184
+ |-----|---------|
185
+ | `faraday` (>= 2.0) | HTTP client for Graph API, Bot Framework, and OAuth |
186
+ | `snappy` (>= 0.5) | Snappy decompression for LevelDB SSTable blocks |
187
+ | `base64` (>= 0.1) | Base64 encoding for PKCE (removed from Ruby 3.4 default gems) |
188
+
189
+ Optional framework dependencies (guarded with `defined?`, not in gemspec):
190
+ - `legion-transport` — AMQP exchange/queue/message for bot message routing
191
+ - `legion-llm` — LLM routing for bot responses (`llm_chat`, `llm_session`)
192
+ - `legion-cache` — High-water mark storage for message dedup
193
+ - `lex-memory` — Session persistence and episodic trace storage
194
+ - `lex-mesh` — PreferenceProfile for per-user preference resolution
195
+
196
+ ## Testing
197
+
198
+ ```bash
199
+ bundle install
200
+ bundle exec rspec # 185 specs (as of v0.5.0)
201
+ bundle exec rubocop # Clean
202
+ ```
203
+
204
+ ---
205
+
206
+ **Maintained By**: Matthew Iverson (@Esity)
data/Dockerfile ADDED
@@ -0,0 +1,6 @@
1
+ FROM legionio/legion
2
+
3
+ COPY . /usr/src/app/lex-microsoft_teams
4
+
5
+ WORKDIR /usr/src/app/lex-microsoft_teams
6
+ RUN bundle install
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rake'
8
+ gem 'rspec'
9
+ gem 'rspec_junit_formatter'
10
+ gem 'rubocop'
11
+ gem 'simplecov'
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,103 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lex-microsoft_teams (0.5.0)
5
+ base64 (>= 0.1)
6
+ faraday (>= 2.0)
7
+ snappy (>= 0.5)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.8.9)
13
+ public_suffix (>= 2.0.2, < 8.0)
14
+ ast (2.4.3)
15
+ base64 (0.3.0)
16
+ bigdecimal (4.0.1)
17
+ diff-lcs (1.6.2)
18
+ docile (1.4.1)
19
+ faraday (2.14.1)
20
+ faraday-net_http (>= 2.0, < 3.5)
21
+ json
22
+ logger
23
+ faraday-net_http (3.4.2)
24
+ net-http (~> 0.5)
25
+ json (2.19.1)
26
+ json-schema (6.2.0)
27
+ addressable (~> 2.8)
28
+ bigdecimal (>= 3.1, < 5)
29
+ language_server-protocol (3.17.0.5)
30
+ lint_roller (1.1.0)
31
+ logger (1.7.0)
32
+ mcp (0.8.0)
33
+ json-schema (>= 4.1)
34
+ net-http (0.9.1)
35
+ uri (>= 0.11.1)
36
+ parallel (1.27.0)
37
+ parser (3.3.10.2)
38
+ ast (~> 2.4.1)
39
+ racc
40
+ prism (1.9.0)
41
+ public_suffix (7.0.5)
42
+ racc (1.8.1)
43
+ rainbow (3.1.1)
44
+ rake (13.3.1)
45
+ regexp_parser (2.11.3)
46
+ rspec (3.13.2)
47
+ rspec-core (~> 3.13.0)
48
+ rspec-expectations (~> 3.13.0)
49
+ rspec-mocks (~> 3.13.0)
50
+ rspec-core (3.13.6)
51
+ rspec-support (~> 3.13.0)
52
+ rspec-expectations (3.13.5)
53
+ diff-lcs (>= 1.2.0, < 2.0)
54
+ rspec-support (~> 3.13.0)
55
+ rspec-mocks (3.13.8)
56
+ diff-lcs (>= 1.2.0, < 2.0)
57
+ rspec-support (~> 3.13.0)
58
+ rspec-support (3.13.7)
59
+ rspec_junit_formatter (0.6.0)
60
+ rspec-core (>= 2, < 4, != 2.12.0)
61
+ rubocop (1.85.1)
62
+ json (~> 2.3)
63
+ language_server-protocol (~> 3.17.0.2)
64
+ lint_roller (~> 1.1.0)
65
+ mcp (~> 0.6)
66
+ parallel (~> 1.10)
67
+ parser (>= 3.3.0.2)
68
+ rainbow (>= 2.2.2, < 4.0)
69
+ regexp_parser (>= 2.9.3, < 3.0)
70
+ rubocop-ast (>= 1.49.0, < 2.0)
71
+ ruby-progressbar (~> 1.7)
72
+ unicode-display_width (>= 2.4.0, < 4.0)
73
+ rubocop-ast (1.49.1)
74
+ parser (>= 3.3.7.2)
75
+ prism (~> 1.7)
76
+ ruby-progressbar (1.13.0)
77
+ simplecov (0.22.0)
78
+ docile (~> 1.1)
79
+ simplecov-html (~> 0.11)
80
+ simplecov_json_formatter (~> 0.1)
81
+ simplecov-html (0.13.2)
82
+ simplecov_json_formatter (0.1.4)
83
+ snappy (0.5.0)
84
+ unicode-display_width (3.2.0)
85
+ unicode-emoji (~> 4.1)
86
+ unicode-emoji (4.2.0)
87
+ uri (1.1.1)
88
+
89
+ PLATFORMS
90
+ arm64-darwin-25
91
+ ruby
92
+ x86_64-linux
93
+
94
+ DEPENDENCIES
95
+ lex-microsoft_teams!
96
+ rake
97
+ rspec
98
+ rspec_junit_formatter
99
+ rubocop
100
+ simplecov
101
+
102
+ BUNDLED WITH
103
+ 2.6.9
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Esity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.