gulp-cli 1.1.5__tar.gz → 1.1.7__tar.gz
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.
- {gulp_cli-1.1.5/src/gulp_cli.egg-info → gulp_cli-1.1.7}/PKG-INFO +2 -1
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/README.md +1 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/docs/command-reference.md +35 -10
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/docs/examples.md +3 -4
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/_version.py +3 -3
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/cli.py +11 -16
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/ingest.py +700 -137
- gulp_cli-1.1.7/src/gulp_cli/commands/utility.py +21 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/config.py +4 -0
- gulp_cli-1.1.7/src/gulp_cli/version.py +20 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7/src/gulp_cli.egg-info}/PKG-INFO +2 -1
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli.egg-info/SOURCES.txt +9 -1
- gulp_cli-1.1.7/src/gulp_cli.egg-info/scm_file_list.json +61 -0
- gulp_cli-1.1.7/src/gulp_cli.egg-info/scm_version.json +8 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/tests/test_enrich_live.py +1 -1
- gulp_cli-1.1.7/tests/test_ingest_paths_file.py +78 -0
- gulp_cli-1.1.7/tests/test_ingest_wait_log.py +258 -0
- gulp_cli-1.1.7/tests/test_version.py +48 -0
- gulp_cli-1.1.7/tests/test_zip_create.py +327 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/.github/workflows/portable-bundles.yml +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/.github/workflows/python-package.yml +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/.gitignore +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/GULP_DUAL_LICENSE.txt +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/LICENSE.AGPL-3.0.txt +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/LICENSE.md +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/docs/extensions.md +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/docs/getting-started.md +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/docs/portable.md +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/docs/resource-management.md +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/docs/troubleshooting-cli.md +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/gulp-cli.spec +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/portable/launch-linux.sh +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/portable/launch-macos.sh +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/portable/launch-windows.bat +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/pyproject.toml +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/setup.cfg +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/__init__.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/__main__.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/client.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/__init__.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/acl.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/auth.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/collab.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/context.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/db.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/enhance_map.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/enrich.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/glyph.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/mapping.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/operations.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/plugin.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/query.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/source.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/stats.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/storage.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/user_group.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/commands/users.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/extension/__init__.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/extension/query_sigma_zip.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/extension/story.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/extension_helpers.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/extensions.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/output.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli/utils.py +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli.egg-info/dependency_links.txt +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli.egg-info/entry_points.txt +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli.egg-info/requires.txt +0 -0
- {gulp_cli-1.1.5 → gulp_cli-1.1.7}/src/gulp_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gulp-cli
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.7
|
|
4
4
|
Summary: Command-line client for gULP
|
|
5
5
|
Author-email: Mentat <info@mentat.is>
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -57,6 +57,7 @@ cd gulp-cli && pip install -e .
|
|
|
57
57
|
|
|
58
58
|
# Verify installation
|
|
59
59
|
gulp-cli --help
|
|
60
|
+
gulp-version
|
|
60
61
|
```
|
|
61
62
|
|
|
62
63
|
### Portable Bundles
|
|
@@ -25,6 +25,18 @@ gulp-cli --verbose --as-user USER_NAME <group> <command> ...
|
|
|
25
25
|
|
|
26
26
|
## Core Commands
|
|
27
27
|
|
|
28
|
+
### `utility`
|
|
29
|
+
|
|
30
|
+
Utility commands for gULP server metadata and similar endpoints.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
gulp-cli utility gulp-version
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`utility gulp-version` prints only the gULP version and uses the saved CLI session, so run `gulp-cli auth login` first.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
28
40
|
### Authentication (`auth`)
|
|
29
41
|
|
|
30
42
|
#### `login`
|
|
@@ -437,20 +449,21 @@ gulp-cli operation revoke-user my_investigation alice
|
|
|
437
449
|
Ingest one or more files into an operation.
|
|
438
450
|
|
|
439
451
|
```bash
|
|
440
|
-
gulp-cli ingest file OPERATION_ID PLUGIN
|
|
452
|
+
gulp-cli ingest file OPERATION_ID PLUGIN [FILE...] [OPTIONS]
|
|
441
453
|
```
|
|
442
454
|
|
|
443
455
|
**Arguments:**
|
|
444
456
|
|
|
445
457
|
- `OPERATION_ID` — Target operation
|
|
446
458
|
- `PLUGIN` — Plugin name (e.g., `win_evtx`, `syslog`, `csv`)
|
|
447
|
-
- `FILE` — File path or glob pattern (multiple allowed)
|
|
459
|
+
- `FILE` — File path or glob pattern (multiple allowed; optional when `--paths-file` is set)
|
|
448
460
|
|
|
449
461
|
**Options:**
|
|
450
462
|
|
|
451
|
-
- `--context
|
|
463
|
+
- `--context TEXT` — Context for ingestion, specify a name to create a new context if it doesn't exist, or an existing `context_id` (default: `sdk_context`)
|
|
452
464
|
- `--plugin-params TEXT` — JSON string with plugin parameters
|
|
453
465
|
- `--flt TEXT` — JSON object for `GulpIngestionFilter`
|
|
466
|
+
- `--paths-file PATH` — Text file with one file or glob pattern per line. When set, positional `FILE` arguments are optional and ignored if also provided.
|
|
454
467
|
- `--reset-operation` — Delete and recreate the operation before ingest starts
|
|
455
468
|
- `--create-operation` — Create operation automatically when it does not exist
|
|
456
469
|
- `--preview` — Run preview-only ingestion (no persistence)
|
|
@@ -474,6 +487,9 @@ gulp-cli ingest file my_op win_evtx 'samples/win_evtx/*.evtx'
|
|
|
474
487
|
# Multiple patterns
|
|
475
488
|
gulp-cli ingest file my_op win_evtx '**/*.evtx' '/logs/*.json'
|
|
476
489
|
|
|
490
|
+
# Paths file
|
|
491
|
+
gulp-cli ingest file my_op win_evtx --paths-file /tmp/file_paths.txt
|
|
492
|
+
|
|
477
493
|
# With plugin parameters
|
|
478
494
|
gulp-cli ingest file my_op csv file.csv --plugin-params '{"delimiter":";","encoding":"utf-8"}'
|
|
479
495
|
|
|
@@ -494,18 +510,20 @@ gulp-cli ingest file my_op win_evtx 'samples/win_evtx/*.evtx' --wait
|
|
|
494
510
|
Add files to an existing source.
|
|
495
511
|
|
|
496
512
|
```bash
|
|
497
|
-
gulp-cli ingest file-to-source SOURCE_ID
|
|
513
|
+
gulp-cli ingest file-to-source SOURCE_ID [FILE...] [OPTIONS]
|
|
498
514
|
```
|
|
499
515
|
|
|
500
516
|
**Arguments:**
|
|
501
517
|
|
|
502
518
|
- `SOURCE_ID` — Source ID
|
|
503
|
-
- `FILE` — File path or glob pattern (multiple allowed)
|
|
519
|
+
- `FILE` — File path or glob pattern (multiple allowed; optional when `--paths-file` is set)
|
|
504
520
|
|
|
505
521
|
**Options:**
|
|
506
522
|
|
|
507
|
-
- `--plugin
|
|
523
|
+
- `--plugin TEXT` — Override the plugin associated with the source (requires `--plugin-params`)
|
|
524
|
+
- `--plugin-params TEXT` — JSON object for plugin_params (overrides source defaults; required when `--plugin` is set, `{}` is allowed)
|
|
508
525
|
- `--flt TEXT` — JSON object for GulpIngestionFilter
|
|
526
|
+
- `--paths-file PATH` — Text file with one file or glob pattern per line. When set, positional `FILE` arguments are optional and ignored if also provided.
|
|
509
527
|
- `--wait` — Wait for completion with progress
|
|
510
528
|
- `--show-per-file-progress / --no-show-per-file-progress` — Show one line per completed file request in `--wait` mode (default: on)
|
|
511
529
|
- `--timeout INTEGER` — Timeout in seconds for `--wait` mode
|
|
@@ -516,6 +534,8 @@ gulp-cli ingest file-to-source SOURCE_ID FILE [FILE...] [OPTIONS]
|
|
|
516
534
|
```bash
|
|
517
535
|
gulp-cli ingest file-to-source source123 /new/System.evtx --wait
|
|
518
536
|
gulp-cli ingest file-to-source source123 '/new/*.evtx'
|
|
537
|
+
gulp-cli ingest file-to-source source123 --paths-file /tmp/file_paths.txt
|
|
538
|
+
gulp-cli ingest file-to-source source123 /new/events.json --plugin json --plugin-params '{"mapping_parameters": {}}'
|
|
519
539
|
```
|
|
520
540
|
|
|
521
541
|
---
|
|
@@ -537,7 +557,7 @@ gulp-cli ingest zip OPERATION_ID ZIP_FILE [OPTIONS]
|
|
|
537
557
|
|
|
538
558
|
**Options:**
|
|
539
559
|
|
|
540
|
-
- `--context
|
|
560
|
+
- `--context TEXT` — Context for ingestion, specify a name to create a new context if it doesn't exist, or an existing `context_id` (default: `sdk_context`)
|
|
541
561
|
- `--flt TEXT` — JSON object for `GulpIngestionFilter`
|
|
542
562
|
- `--create-operation` — Create operation automatically when it does not exist
|
|
543
563
|
- `--wait` — Wait for completion
|
|
@@ -576,7 +596,12 @@ gulp-cli ingest zip-create OUTPUT_ZIP [PATH_PATTERN...] [OPTIONS]
|
|
|
576
596
|
**Options:**
|
|
577
597
|
|
|
578
598
|
- `--paths-file TEXT` — Text file with one source path expression per line (supports environment variables and `~` per line)
|
|
579
|
-
- `--overwrite` —
|
|
599
|
+
- `--no-overwrite` — Do not overwrite output ZIP if it already exists (default: overwrite enabled)
|
|
600
|
+
- `--no-preserve-path` — Do not preserve the source path hierarchy inside archive entries (default: preserve path enabled)
|
|
601
|
+
- `--split-size TEXT` — Create multipart ZIP volumes at this size (bytes, `kb`, `mb`, `gb`; default: disabled)
|
|
602
|
+
|
|
603
|
+
When `--split-size` is set, `zip-create` writes multipart ZIP volumes such as `evidence.zip.001`, `evidence.zip.002`, etc. Extract those volumes with `7z` or another tool that supports split ZIP files.
|
|
604
|
+
When `--paths-file` is set, positional `PATH_PATTERN` values are ignored. Without `--paths-file`, positional `PATH_PATTERN` values are used.
|
|
580
605
|
|
|
581
606
|
**Examples:**
|
|
582
607
|
|
|
@@ -585,10 +610,10 @@ gulp-cli ingest zip-create OUTPUT_ZIP [PATH_PATTERN...] [OPTIONS]
|
|
|
585
610
|
gulp-cli ingest zip-create /tmp/evidence.zip /data/host1/*.evtx /data/host2 /data/readme.txt
|
|
586
611
|
|
|
587
612
|
# Use environment variables and home shortcuts
|
|
588
|
-
gulp-cli ingest zip-create '$CASE_DIR/evidence.zip' '$CASE_DIR/raw/*.json' '~/pcaps/*.pcap'
|
|
613
|
+
gulp-cli ingest zip-create '$CASE_DIR/evidence.zip' '$CASE_DIR/raw/*.json' '~/pcaps/*.pcap'
|
|
589
614
|
|
|
590
615
|
# Read source path expressions from a file
|
|
591
|
-
gulp-cli ingest zip-create /tmp/evidence.zip --paths-file /tmp/evidence_paths.txt
|
|
616
|
+
gulp-cli ingest zip-create /tmp/evidence.zip --paths-file /tmp/evidence_paths.txt
|
|
592
617
|
```
|
|
593
618
|
|
|
594
619
|
---
|
|
@@ -175,8 +175,7 @@ gulp-cli ingest file incident-001 csv /data/access_log.csv \
|
|
|
175
175
|
--plugin-params '{"delimiter":";","encoding":"iso-8859-1","has_header":true}'
|
|
176
176
|
|
|
177
177
|
# pass mapping directly without using a mapping file
|
|
178
|
-
gulp-cli ingest file test_operation csv ./samples/mftecmd/sample_record.csv --plugin-params '{ "mapping_parameters": { "mappings": { "
|
|
179
|
-
_mapping": { "fields": { "Created0x10": { "ecs": [ "@timestamp" ] } } } } } }' --reset-operation --wait
|
|
178
|
+
gulp-cli ingest file test_operation csv ./samples/mftecmd/sample_record.csv --plugin-params '{ "mapping_parameters": { "mappings": { "test_mapping": { "fields": { "Created0x10": { "ecs": ["@timestamp" ] } } } } } }' --reset-operation --wait
|
|
180
179
|
|
|
181
180
|
# pass mapping using a gulp mapping file with mapping_id to specify which mapping to use in the file
|
|
182
181
|
gulp-cli ingest file test_operation csv ./samples/mftecmd/sample_record.csv --plugin-params '{ "mapping_parameters"
|
|
@@ -220,11 +219,11 @@ gulp-cli ingest zip incident-001 /evidence/evidence.zip --create-operation
|
|
|
220
219
|
|
|
221
220
|
```bash
|
|
222
221
|
# Build ZIP from mixed sources: file, directory, and wildcard mask
|
|
223
|
-
gulp-cli ingest zip-create /evidence/evidence.zip /forensic/host1/*.evtx /forensic/host2 /forensic/notes.txt --overwrite
|
|
222
|
+
gulp-cli ingest zip-create /evidence/evidence.zip /forensic/host1/*.evtx /forensic/host2 /forensic/notes.txt --no-overwrite
|
|
224
223
|
|
|
225
224
|
# Use environment variables and ~ in source expressions and output path
|
|
226
225
|
export CASE_ROOT=~/cases/incident-001
|
|
227
|
-
gulp-cli ingest zip-create '$CASE_ROOT/evidence.zip' '$CASE_ROOT/windows/*.evtx' '$CASE_ROOT/network/*' --overwrite
|
|
226
|
+
gulp-cli ingest zip-create '$CASE_ROOT/evidence.zip' '$CASE_ROOT/windows/*.evtx' '$CASE_ROOT/network/*' --no-overwrite
|
|
228
227
|
|
|
229
228
|
# Build ZIP from a text file (one path expression per line)
|
|
230
229
|
cat > /tmp/evidence_paths.txt <<'EOF'
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 1,
|
|
21
|
+
__version__ = version = '1.1.7'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 1, 7)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g5f188bb2b'
|
|
@@ -15,12 +15,12 @@ from gulp_cli.commands.mapping import app as mapping_app
|
|
|
15
15
|
from gulp_cli.commands.operations import app as operation_app
|
|
16
16
|
from gulp_cli.commands.plugin import app as plugin_app
|
|
17
17
|
from gulp_cli.commands.query import app as query_app
|
|
18
|
+
from gulp_cli.commands.utility import app as utility_app
|
|
18
19
|
from gulp_cli.commands.source import app as source_app
|
|
19
20
|
from gulp_cli.commands.stats import app as stats_app
|
|
20
21
|
from gulp_cli.commands.storage import app as storage_app
|
|
21
22
|
from gulp_cli.commands.user_group import app as user_group_app
|
|
22
23
|
from gulp_cli.commands.users import app as user_app
|
|
23
|
-
from gulp_sdk.client import GulpClient
|
|
24
24
|
|
|
25
25
|
from gulp_cli.config import (
|
|
26
26
|
set_runtime_as_user,
|
|
@@ -28,28 +28,21 @@ from gulp_cli.config import (
|
|
|
28
28
|
set_runtime_verbose,
|
|
29
29
|
)
|
|
30
30
|
from gulp_cli.extensions import load_extensions
|
|
31
|
-
|
|
32
|
-
app = typer.Typer(
|
|
33
|
-
no_args_is_help=True,
|
|
34
|
-
help="Modern CLI for gULP, powered by gulp-sdk",
|
|
35
|
-
)
|
|
31
|
+
from gulp_cli.version import print_version
|
|
36
32
|
|
|
37
33
|
|
|
38
34
|
def _show_versions(value: bool) -> None:
|
|
39
35
|
if not value:
|
|
40
36
|
return
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
sdk_version = GulpClient("http://localhost:8080").version()
|
|
45
|
-
print(
|
|
46
|
-
f"gulp-cli version: {__version__} ({__commit_id__})"
|
|
47
|
-
if __commit_id__
|
|
48
|
-
else __version__
|
|
49
|
-
)
|
|
50
|
-
print(f"gulp-sdk version: {sdk_version}")
|
|
38
|
+
print_version()
|
|
51
39
|
raise typer.Exit()
|
|
52
40
|
|
|
41
|
+
app = typer.Typer(
|
|
42
|
+
no_args_is_help=True,
|
|
43
|
+
help="Modern CLI for gULP, powered by gulp-sdk",
|
|
44
|
+
)
|
|
45
|
+
|
|
53
46
|
|
|
54
47
|
@app.callback(invoke_without_command=True)
|
|
55
48
|
def main(
|
|
@@ -74,7 +67,7 @@ def main(
|
|
|
74
67
|
"--version",
|
|
75
68
|
callback=_show_versions,
|
|
76
69
|
is_eager=True,
|
|
77
|
-
help="Show CLI
|
|
70
|
+
help="Show the CLI version and exit.",
|
|
78
71
|
),
|
|
79
72
|
) -> None:
|
|
80
73
|
set_runtime_config_dir(config_dir)
|
|
@@ -100,6 +93,7 @@ app.add_typer(plugin_app, name="plugin")
|
|
|
100
93
|
app.add_typer(mapping_app, name="mapping")
|
|
101
94
|
app.add_typer(enhance_map_app, name="enhance-map")
|
|
102
95
|
app.add_typer(glyph_app, name="glyph")
|
|
96
|
+
app.add_typer(utility_app, name="utility")
|
|
103
97
|
|
|
104
98
|
load_extensions(
|
|
105
99
|
app,
|
|
@@ -122,5 +116,6 @@ load_extensions(
|
|
|
122
116
|
"mapping": mapping_app,
|
|
123
117
|
"enhance-map": enhance_map_app,
|
|
124
118
|
"glyph": glyph_app,
|
|
119
|
+
"utility": utility_app,
|
|
125
120
|
},
|
|
126
121
|
)
|