luciq-cli 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b148325e3ea055acf54acad389f7d5617534b687bf06125fb2b5fd565150d23
4
- data.tar.gz: 6faf85d4ff073213742b72294db3e95a0e22e802e559d3cfdd0e8957822e1849
3
+ metadata.gz: 6882405a8d129fe6337191a3fafcf09ce88290166b640acb36c016af9c4bdd35
4
+ data.tar.gz: 866a5f76f6d8d1b922b24c73dc33687c9a9cd7dc8a139722d449c129b8e474a5
5
5
  SHA512:
6
- metadata.gz: 924ab969fefff13e013d4412414626b530dbcd81e46683dc471d70357e190122eec1eb730dfd6b12636dbd49573c1498d7b8ce5593e920bac9082635e945f9f8
7
- data.tar.gz: 8ef521174571a0db1a2eefc181b39c291ace667f3dd21251a15cf193bb35aed06d4b310b93f28bcd1cdfced0a09407a157b0f9a46456722214ae21221eb4df34
6
+ metadata.gz: 2c48c7bbb0a56349d8bd41e9ad78a7b4c459a50e0befa5dd1b69a2eb98beca174c3fb1cfdbfba1d2815b55ab9b8eb96b75738f5b49abf4c9ee45d19b9bc208e9
7
+ data.tar.gz: 5eb8bc3833309adfb682cfcf3c13b2c4690803a4086df71f8fa8b6d23be99b865bdcbbb144d390d65b0b4f46b6e6377da79e894dfb168daac14bdd795729f561
data/CHANGELOG.md CHANGED
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2026-07-05
11
+
12
+ ### Added
13
+
14
+ - `luciq crashes` - Query crashes: `list`, `show`, `patterns`, `diagnostics`, `hangs`, `occurrence-tokens`, `occurrence`
15
+ - `luciq bugs` - Query and update bugs: `list`, `show`, `update` (status, priority, tags, duplicate marking)
16
+ - `luciq apm` - Query APM data: `groups`, `group`, `occurrence`, and funnels (`funnel-events`, `funnel-create`, `funnel-update`, `funnel-delete`)
17
+ - `luciq reviews list` - Query app reviews
18
+ - `luciq surveys` - Query surveys: `list`, `show`
19
+ - `luciq apps list` - List accessible applications
20
+ - `luciq insights` - Show aggregated app-health insights
21
+ - `luciq issues list` - List issues across sources ranked by impact
22
+ - `luciq opportunities` - Query opportunities: `list`, `show`
23
+ - `luciq alerts` - Manage alert rules: `list`, `show`, `init`, `create`, `update`, `delete`
24
+ - `luciq incidents` - Manage triggered alerts: `list`, `show`, `resolve`, `reopen`
25
+ - Typed filter flags with a raw `--filters` JSON escape hatch on query commands
26
+
10
27
  ## [0.1.0] - 2025-12-16
11
28
 
12
29
  ### Added
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Luciq CLI
2
2
 
3
- Command-line interface for uploading symbol files to Luciq.
3
+ Command-line interface for Luciq: upload symbol files and query or manage your
4
+ app data — crashes, bugs, APM, reviews, surveys, issues, opportunities, alerts,
5
+ and more.
4
6
 
5
7
  ## Installation
6
8
 
@@ -46,10 +48,10 @@ luciq login --auth-token YOUR_CLI_TOKEN
46
48
 
47
49
  ### 2. Upload Symbol Files
48
50
 
49
- Upload Android mapping files (`.zip` containing a single mapping text file):
51
+ Upload Android mapping files (`mapping.txt`):
50
52
 
51
53
  ```bash
52
- luciq upload android-mapping mapping.zip \
54
+ luciq upload android-mapping mapping.txt \
53
55
  --app-token YOUR_APP_TOKEN \
54
56
  --version-name 1.0.0 \
55
57
  --version-code 1
@@ -69,8 +71,214 @@ luciq upload android-mapping mapping.zip \
69
71
  | `luciq logout` | Remove saved authentication |
70
72
  | `luciq whoami` | Show current authenticated user |
71
73
  | `luciq info` | Show CLI configuration |
72
- | `luciq upload android-mapping FILE` | Upload Android mapping file |
73
74
  | `luciq version` | Show CLI version |
75
+ | `luciq upload` | Upload symbol files (see below) |
76
+ | `luciq crashes` | Query crashes, hangs, and occurrences |
77
+ | `luciq bugs` | Query and update bugs |
78
+ | `luciq apm` | Query APM metrics and manage funnels |
79
+ | `luciq reviews` | Query app store reviews |
80
+ | `luciq surveys` | Query surveys and their responses |
81
+ | `luciq apps` | List accessible applications |
82
+ | `luciq issues` | List issues across sources, ranked by impact |
83
+ | `luciq opportunities` | Query product opportunities |
84
+ | `luciq alerts` | Manage alert rules |
85
+ | `luciq incidents` | Manage triggered alerts |
86
+ | `luciq insights` | Show aggregated app-health insights |
87
+
88
+ See [Query & management commands](#query--management-commands) for the full option
89
+ set of the data commands.
90
+
91
+ ### Upload commands
92
+
93
+ Run `luciq upload help SUBCOMMAND` for the full options of any command.
94
+
95
+ **iOS**
96
+
97
+ | Command | File | Description |
98
+ |---------|------|-------------|
99
+ | `luciq upload ios-dsym FILE` | `.zip` | iOS dSYM symbols |
100
+
101
+ **Android**
102
+
103
+ | Command | File | Description |
104
+ |---------|------|-------------|
105
+ | `luciq upload android-mapping FILE` | `mapping.txt` | Proguard/R8 mapping file |
106
+ | `luciq upload android-ndk FILE` | `.zip` | NDK `.so` shared object files (`--arch`) |
107
+
108
+ **React Native**
109
+
110
+ | Command | File | Description |
111
+ |---------|------|-------------|
112
+ | `luciq upload react-native-ios-dsym FILE` | `.zip` | iOS native dSYM symbols |
113
+ | `luciq upload react-native-ios-sourcemap FILE` | `.json`/`.txt` | iOS JavaScript source map |
114
+ | `luciq upload react-native-android-mapping FILE` | `mapping.txt` | Android native Proguard/R8 mapping |
115
+ | `luciq upload react-native-android-sourcemap FILE` | `.json`/`.txt` | Android JavaScript source map |
116
+ | `luciq upload react-native-ndk FILE` | `.zip` | NDK `.so` shared object files (`--arch`) |
117
+
118
+ **Flutter**
119
+
120
+ | Command | File | Description |
121
+ |---------|------|-------------|
122
+ | `luciq upload flutter-ios-dsym FILE` | `.zip` | iOS native dSYM symbols |
123
+ | `luciq upload flutter-ios-sourcemap FILE` | `.zip` | iOS Dart symbol files |
124
+ | `luciq upload flutter-android-mapping FILE` | `mapping.txt` | Android native Proguard/R8 mapping |
125
+ | `luciq upload flutter-android-sourcemap FILE` | `.zip` | Android Dart symbol files |
126
+ | `luciq upload flutter-ndk FILE` | `.zip` | NDK `.so` shared object files (`--arch`) |
127
+
128
+ Common options: `--app-token` is required for every command. dSYM commands
129
+ (`*-ios-dsym`) need only `--app-token`. Mapping, source-map, and Flutter Dart-symbol
130
+ commands also require `--version-name` / `--version-code` (React Native source-map
131
+ commands additionally accept `--codepush`). NDK commands require `--version-name` and
132
+ `--arch` (`armeabi-v7a`, `arm64-v8a`, `x86`, `x86_64`) — not `--version-code`.
133
+
134
+ ## Query & management commands
135
+
136
+ Beyond uploading symbols, the CLI queries and manages your Luciq data. Every
137
+ response is printed as pretty-printed JSON, so it pipes cleanly into tools like
138
+ `jq`.
139
+
140
+ ### Shared options
141
+
142
+ Most data commands target one application in one environment and share a common
143
+ set of options:
144
+
145
+ | Option | Description |
146
+ |--------|-------------|
147
+ | `--slug` | Application slug (required) |
148
+ | `--mode` | Environment: `production`, `beta`, `staging`, `alpha`, `qa`, `development` (required) |
149
+ | `--offset`, `--limit` | Pagination |
150
+ | `--sort-by`, `--direction` | Sort field and direction (`asc`/`desc`) — some commands use `--sort-direction` instead |
151
+ | `--filters` | Raw filter JSON object, merged with the typed filter flags (typed flags win on key conflicts) |
152
+
153
+ Common filters have dedicated typed flags (`--status`, `--platform`,
154
+ `--app-version`, …). Anything a tool supports but that has no flag can be passed
155
+ through `--filters`, e.g. `--filters '{"devices":["iPhone15,2"],"os_versions":["17.4"]}'`.
156
+ Run `luciq <group> help <subcommand>` for the full option list and the filter
157
+ keys each command accepts.
158
+
159
+ ### Crashes
160
+
161
+ `luciq crashes SUBCOMMAND`
162
+
163
+ | Subcommand | Description |
164
+ |------------|-------------|
165
+ | `list` | List crashes. Flags: `--status` (open/closed/in_progress), `--platform` (IOS/ANDROID/DART/JAVASCRIPT), `--type` (CRASH/ANR/OOM/NON_FATAL), `--app-version` |
166
+ | `show --number N` | Details for one crash |
167
+ | `patterns --number N` | Grouped patterns. Flags: `--pattern-key`, `--sort-by`, `--direction` |
168
+ | `diagnostics --number N` | Diagnostics for one crash |
169
+ | `hangs` | List app hangs (same filters as `list`) |
170
+ | `occurrence-tokens --number N` | Occurrence cursor tokens. Flags: `--current-token`, `--direction` (first/last) |
171
+ | `occurrence --number N --ulid U` | Details for a single occurrence |
172
+
173
+ ```bash
174
+ luciq crashes list --slug my-app --mode production --status open --limit 20
175
+ luciq crashes show --slug my-app --mode production --number 42
176
+ ```
177
+
178
+ ### Bugs
179
+
180
+ `luciq bugs SUBCOMMAND`
181
+
182
+ | Subcommand | Description |
183
+ |------------|-------------|
184
+ | `list` | List bugs. Flags: `--status` (new/closed/in_progress), `--priority` (na/trivial/minor/major/blocker), `--app-version` |
185
+ | `show --number N` | Details for one bug |
186
+ | `update --number N` | Update a bug. Flags: `--status`, `--priority`, `--tags`, `--clear-tags`, `--duplicate-of`, `--action` |
187
+
188
+ ```bash
189
+ luciq bugs update --slug my-app --mode production --number 7 --status closed --priority major
190
+ luciq bugs update --slug my-app --mode production --number 7 --duplicate-of 3
191
+ ```
192
+
193
+ Provide at least one change. Duplicate marking (`--duplicate-of` / `--action`)
194
+ can't be combined with `--status`/`--priority`; use `--clear-tags` to remove all
195
+ tags.
196
+
197
+ ### APM
198
+
199
+ `luciq apm SUBCOMMAND`
200
+
201
+ | Subcommand | Description |
202
+ |------------|-------------|
203
+ | `groups --metric M` | Rank groups worst-first. `--metric`: network, launch, flows, screen_loading, frame_drop, funnels. `--sort` is a JSON object `{"by":…,"direction":…}` |
204
+ | `group --metric M` | Panels for one group; identify with `--group-uuid` or `--group-url`. `--views` is a JSON array (default `["summary"]`); `--method` applies to network |
205
+ | `occurrence --metric M --selector S` | Inspect occurrences (`--selector`: worst/by_token/list). Flags: `--token`, `--current-token`, `--direction`, `--limit` |
206
+ | `funnel-events` | List events pickable for funnels. Flags: `--event-type`, `--q`, `--limit` |
207
+ | `funnel-create --name N --events JSON` | Create a funnel from 2–20 steps |
208
+ | `funnel-update --ulid U` | Update a funnel (`--name`, `--events`) |
209
+ | `funnel-delete --ulid U` | Delete a funnel |
210
+
211
+ ```bash
212
+ luciq apm groups --slug my-app --mode production --metric network \
213
+ --sort '{"by":"p95","direction":"desc"}'
214
+ ```
215
+
216
+ ### Reviews
217
+
218
+ `luciq reviews list` — Flags: `--rating` (1–5), `--country`, `--os` (ios/android),
219
+ `--sort-by date`, `--sort-direction`.
220
+
221
+ ### Surveys
222
+
223
+ `luciq surveys SUBCOMMAND`
224
+
225
+ | Subcommand | Description |
226
+ |------------|-------------|
227
+ | `list` | List surveys. Flags: `--type` (0=custom 1=nps 2=app_store), `--status` (0=draft 1=published 2=paused) |
228
+ | `show --id N` | A survey's questions and response statistics. `--page` paginates responses |
229
+
230
+ ### Apps
231
+
232
+ `luciq apps list` — List the applications you can access (no `--slug`/`--mode`).
233
+ Optional `--platform` (ios/android/react_native/flutter).
234
+
235
+ ### Insights
236
+
237
+ `luciq insights --slug my-app --mode production` — Aggregated app-health insights.
238
+ Narrow with `--filters` (`date_ms`, `app_version`).
239
+
240
+ ### Issues
241
+
242
+ `luciq issues list` — Issues across crashes, APM, AI, and bugs, ranked by Apdex
243
+ impact. Flags: `--limit`, `--sort-by` (apdex_impact/occurrences_counter),
244
+ `--sort-direction`, `--top-issues` (curated shortlist), `--pagination`
245
+ (per-source cursor tokens JSON).
246
+
247
+ ### Opportunities
248
+
249
+ `luciq opportunities SUBCOMMAND`
250
+
251
+ | Subcommand | Description |
252
+ |------------|-------------|
253
+ | `list` | List opportunities. Flags: `--status`, `--priority` (1–4/unset), `--team-id` |
254
+ | `show --id N` | Details for one opportunity |
255
+
256
+ ### Alerts
257
+
258
+ `luciq alerts SUBCOMMAND` — Manage alert rules.
259
+
260
+ | Subcommand | Description |
261
+ |------------|-------------|
262
+ | `list` | List rules (`--sort-by`, `--sort-direction`) |
263
+ | `show --ulid U` | Show one rule |
264
+ | `init` | Show the menu (types, triggers, conditions, actions) for building a rule |
265
+ | `create --payload JSON` | Create a rule |
266
+ | `update --ulid U --payload JSON` | Update a rule |
267
+ | `delete --ulid U` | Delete a rule |
268
+
269
+ Run `luciq alerts init` first to discover the valid rule building blocks, then
270
+ pass the rule body as `--payload`.
271
+
272
+ ### Incidents
273
+
274
+ `luciq incidents SUBCOMMAND` — Manage triggered alerts.
275
+
276
+ | Subcommand | Description |
277
+ |------------|-------------|
278
+ | `list` | List incidents. Flags: `--sort-by`, `--sort-direction`, `--status`, `--type` |
279
+ | `show --ulid U` | Show one incident |
280
+ | `resolve --ulid U` | Resolve an incident |
281
+ | `reopen --ulid U` | Reopen an incident |
74
282
 
75
283
  ## Configuration
76
284
 
@@ -9,6 +9,11 @@ require 'luciq/config'
9
9
  module Luciq
10
10
  module API
11
11
  class Client
12
+ SYMBOLS_FILES_PATH = '/api/sdk/v3/symbols_files'
13
+ SO_FILES_PATH = '/api/web/public/so_files'
14
+ FLUTTER_IOS_SYMBOLS_PATH = '/api/web/public/flutter-symbol-files/ios'
15
+ FLUTTER_ANDROID_SYMBOLS_PATH = '/api/web/public/flutter-symbol-files/android'
16
+
12
17
  def initialize
13
18
  @token = Config.load_token
14
19
  @base_url = Config.load_base_url
@@ -21,24 +26,166 @@ module Luciq
21
26
  execute(uri, request)
22
27
  end
23
28
 
29
+ # Invokes a query tool by name with a hash of arguments (slug, mode,
30
+ # filters, pagination, ...) sent as a JSON body.
31
+ def invoke_tool(tool_name, arguments = {})
32
+ uri = build_uri("/api/cli/tools/#{tool_name}")
33
+ request = Net::HTTP::Post.new(uri)
34
+ request['Content-Type'] = 'application/json'
35
+ request.body = arguments.to_json
36
+ apply_headers(request)
37
+ execute(uri, request)
38
+ end
39
+
40
+ def upload_ios_dsym(file_path:, app_token:)
41
+ upload_dsym(file_path: file_path, app_token: app_token)
42
+ end
43
+
24
44
  def upload_android_mapping(file_path:, app_token:, version_code:, version_name:)
25
- uri = build_uri('/api/web/public/mappings')
45
+ upload_mapping(
46
+ file_path: file_path, app_token: app_token,
47
+ version_code: version_code, version_name: version_name
48
+ )
49
+ end
26
50
 
51
+ def upload_android_ndk(file_path:, app_token:, app_version:, arch:)
52
+ upload_so_file(file_path: file_path, app_token: app_token, app_version: app_version, arch: arch)
53
+ end
54
+
55
+ def upload_react_native_ios_dsym(file_path:, app_token:)
56
+ upload_dsym(file_path: file_path, app_token: app_token)
57
+ end
58
+
59
+ def upload_react_native_ios_sourcemap(file_path:, app_token:, app_version:)
60
+ upload_react_native_sourcemap(
61
+ file_path: file_path, app_token: app_token, os: 'ios', app_version: app_version
62
+ )
63
+ end
64
+
65
+ def upload_react_native_android_mapping(file_path:, app_token:, version_code:, version_name:)
66
+ upload_mapping(
67
+ file_path: file_path, app_token: app_token,
68
+ version_code: version_code, version_name: version_name
69
+ )
70
+ end
71
+
72
+ def upload_react_native_android_sourcemap(file_path:, app_token:, app_version:)
73
+ upload_react_native_sourcemap(
74
+ file_path: file_path, app_token: app_token, os: 'android', app_version: app_version
75
+ )
76
+ end
77
+
78
+ def upload_react_native_ndk(file_path:, app_token:, app_version:, arch:)
79
+ upload_so_file(file_path: file_path, app_token: app_token, app_version: app_version, arch: arch)
80
+ end
81
+
82
+ def upload_flutter_ios_dsym(file_path:, app_token:)
83
+ upload_dsym(file_path: file_path, app_token: app_token)
84
+ end
85
+
86
+ def upload_flutter_ios_sourcemap(file_path:, app_token:, version_name:, version_code:)
87
+ upload_flutter_symbols(
88
+ FLUTTER_IOS_SYMBOLS_PATH,
89
+ file_path: file_path, app_token: app_token,
90
+ version_name: version_name, version_code: version_code
91
+ )
92
+ end
93
+
94
+ def upload_flutter_android_mapping(file_path:, app_token:, version_code:, version_name:)
95
+ upload_mapping(
96
+ file_path: file_path, app_token: app_token,
97
+ version_code: version_code, version_name: version_name
98
+ )
99
+ end
100
+
101
+ def upload_flutter_android_sourcemap(file_path:, app_token:, version_name:, version_code:)
102
+ upload_flutter_symbols(
103
+ FLUTTER_ANDROID_SYMBOLS_PATH,
104
+ file_path: file_path, app_token: app_token,
105
+ version_name: version_name, version_code: version_code
106
+ )
107
+ end
108
+
109
+ def upload_flutter_ndk(file_path:, app_token:, app_version:, arch:)
110
+ upload_so_file(file_path: file_path, app_token: app_token, app_version: app_version, arch: arch)
111
+ end
112
+
113
+ private
114
+
115
+ def upload_dsym(file_path:, app_token:)
116
+ uri = build_uri(SYMBOLS_FILES_PATH)
27
117
  File.open(file_path, 'rb') do |file|
28
118
  params = {
29
- 'mapping_file' => UploadIO.new(file, 'application/octet-stream', File.basename(file_path)),
119
+ 'symbols_file' => UploadIO.new(file, 'application/octet-stream', File.basename(file_path)),
30
120
  'application_token' => app_token,
31
- 'app_version_code' => version_code,
32
- 'app_version_name' => version_name
121
+ 'os' => 'ios'
33
122
  }
123
+ post_multipart(uri, params)
124
+ end
125
+ end
34
126
 
35
- request = Net::HTTP::Post::Multipart.new(uri.path, params)
36
- apply_headers(request)
37
- execute(uri, request)
127
+ def upload_mapping(file_path:, app_token:, version_code:, version_name:)
128
+ uri = build_uri(SYMBOLS_FILES_PATH)
129
+ File.open(file_path, 'rb') do |file|
130
+ params = {
131
+ 'symbols_file' => UploadIO.new(file, 'application/octet-stream', File.basename(file_path)),
132
+ 'application_token' => app_token,
133
+ 'os' => 'android',
134
+ 'app_version' => { code: version_code, name: version_name }.to_json
135
+ }
136
+ post_multipart(uri, params)
38
137
  end
39
138
  end
40
139
 
41
- private
140
+ def upload_react_native_sourcemap(file_path:, app_token:, os:, app_version:)
141
+ uri = build_uri(SYMBOLS_FILES_PATH)
142
+ File.open(file_path, 'rb') do |file|
143
+ params = {
144
+ 'symbols_file' => UploadIO.new(file, source_map_content_type(file_path), File.basename(file_path)),
145
+ 'application_token' => app_token,
146
+ 'platform' => 'react_native',
147
+ 'os' => os,
148
+ 'app_version' => app_version.to_json
149
+ }
150
+ post_multipart(uri, params)
151
+ end
152
+ end
153
+
154
+ def upload_so_file(file_path:, app_token:, app_version:, arch:)
155
+ uri = build_uri(SO_FILES_PATH)
156
+ File.open(file_path, 'rb') do |file|
157
+ params = {
158
+ 'so_file' => UploadIO.new(file, 'application/octet-stream', File.basename(file_path)),
159
+ 'application_token' => app_token,
160
+ 'app_version' => app_version,
161
+ 'arch' => arch
162
+ }
163
+ post_multipart(uri, params)
164
+ end
165
+ end
166
+
167
+ def upload_flutter_symbols(path, file_path:, app_token:, version_name:, version_code:)
168
+ uri = build_uri(path)
169
+ File.open(file_path, 'rb') do |file|
170
+ params = {
171
+ 'file' => UploadIO.new(file, 'application/octet-stream', File.basename(file_path)),
172
+ 'application_token' => app_token,
173
+ 'app_version_name' => version_name,
174
+ 'app_version_code' => version_code
175
+ }
176
+ post_multipart(uri, params)
177
+ end
178
+ end
179
+
180
+ def post_multipart(uri, params)
181
+ request = Net::HTTP::Post::Multipart.new(uri.path, params)
182
+ apply_headers(request)
183
+ execute(uri, request)
184
+ end
185
+
186
+ def source_map_content_type(file_path)
187
+ file_path.downcase.end_with?('.json') ? 'application/json' : 'text/plain'
188
+ end
42
189
 
43
190
  def build_uri(path)
44
191
  URI("#{@base_url}#{path}")
@@ -56,9 +203,11 @@ module Luciq
56
203
  http.read_timeout = 300
57
204
 
58
205
  response = http.request(request)
59
- return JSON.parse(response.body) if response.is_a?(Net::HTTPSuccess)
206
+ raise "Request failed (#{response.code}): #{response.body}" unless response.is_a?(Net::HTTPSuccess)
60
207
 
61
- raise "Request failed (#{response.code}): #{response.body}"
208
+ JSON.parse(response.body)
209
+ rescue JSON::ParserError
210
+ response.body
62
211
  end
63
212
  end
64
213
  end
data/lib/luciq/cli.rb CHANGED
@@ -3,25 +3,10 @@
3
3
  require 'thor'
4
4
  require 'luciq/version'
5
5
  require 'luciq/commands/auth'
6
- require 'luciq/commands/upload'
6
+ require 'luciq/upload_cli'
7
+ require 'luciq/query_cli'
7
8
 
8
9
  module Luciq
9
- class UploadCLI < Thor
10
- desc 'android-mapping FILE', 'Upload Android mapping file'
11
- long_desc <<~DESC
12
- Upload Android mapping files to Luciq for crash symbolication.
13
- File format: .zip containing a single text file
14
- Example:
15
- luciq upload android-mapping mapping.zip --app-token APP_TOKEN --version-name 1.0.0 --version-code 1
16
- DESC
17
- option :app_token, type: :string, required: true, desc: 'Your Luciq application token'
18
- option :version_name, type: :string, required: true, desc: 'App version name (e.g., 1.0.0)'
19
- option :version_code, type: :string, required: true, desc: 'App version code (e.g., 1)'
20
- def android_mapping(file)
21
- Commands::Upload.new(options).android_mapping(file)
22
- end
23
- end
24
-
25
10
  class CLI < Thor
26
11
  def self.exit_on_failure?
27
12
  true
@@ -56,6 +41,50 @@ module Luciq
56
41
  desc 'upload SUBCOMMAND', 'Upload symbol files to Luciq'
57
42
  subcommand 'upload', UploadCLI
58
43
 
44
+ desc 'crashes SUBCOMMAND', 'Query crashes (list, show, patterns, diagnostics, hangs, occurrence-tokens, occurrence)'
45
+ subcommand 'crashes', CrashesCLI
46
+
47
+ desc 'bugs SUBCOMMAND', 'Query bugs (list, show, update)'
48
+ subcommand 'bugs', BugsCLI
49
+
50
+ desc 'apm SUBCOMMAND', 'Query APM data (groups, group, occurrence, funnels)'
51
+ subcommand 'apm', ApmCLI
52
+
53
+ desc 'reviews SUBCOMMAND', 'Query app reviews (list)'
54
+ subcommand 'reviews', ReviewsCLI
55
+
56
+ desc 'surveys SUBCOMMAND', 'Query surveys (list, show)'
57
+ subcommand 'surveys', SurveysCLI
58
+
59
+ desc 'apps SUBCOMMAND', 'List accessible applications'
60
+ subcommand 'apps', AppsCLI
61
+
62
+ desc 'issues SUBCOMMAND', 'Query issues ranked by impact (list)'
63
+ subcommand 'issues', IssuesCLI
64
+
65
+ desc 'opportunities SUBCOMMAND', 'Query opportunities (list, show)'
66
+ subcommand 'opportunities', OpportunitiesCLI
67
+
68
+ desc 'alerts SUBCOMMAND', 'Manage alert rules (list, show, init, create, update, delete)'
69
+ subcommand 'alerts', AlertsCLI
70
+
71
+ desc 'incidents SUBCOMMAND', 'Manage triggered alerts (list, show, resolve, reopen)'
72
+ subcommand 'incidents', IncidentsCLI
73
+
74
+ desc 'insights', 'Show aggregated app-health insights for an application'
75
+ long_desc(<<~DESC, wrap: false)
76
+ Show aggregated app-health insights for an application.
77
+
78
+ Filters via --filters:
79
+ date_ms {"gte": <ms>, "lte": <ms>}
80
+ app_version ["1.2.3", ...]
81
+ DESC
82
+ QueryOptions.app(self)
83
+ QueryOptions.raw_filters(self)
84
+ def insights
85
+ Commands::Query.new(options).insights
86
+ end
87
+
59
88
  desc 'version', 'Show CLI version'
60
89
  def version
61
90
  puts "luciq-cli #{Luciq::VERSION}"