command-cmd 1.0.2 → 1.0.5
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.
- package/cmd.js +2165 -16
- package/doc.md +292 -152
- package/docPTBR.md +299 -152
- package/map.md +244 -0
- package/mapPTBR.md +244 -0
- package/package.json +5 -2
package/docPTBR.md
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
# command-cmd (Documentacao PT-BR)
|
|
2
2
|
|
|
3
|
-
`command-cmd`
|
|
3
|
+
`command-cmd` extrai comandos de texto de IA e executa automacoes com cursor via `robotjs`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Funcoes exportadas:
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
- Capturar varios comandos na mesma mensagem.
|
|
13
|
-
- Normalizar saida em um objeto padrao com `type`, `command`, `extra` e `seq`.
|
|
14
|
-
- Interpretar entradas com chaves em ingles e portugues (`type/tipo`, `command/comando`).
|
|
15
|
-
|
|
16
|
-
Ela **nao executa comandos**. Ela apenas faz parsing.
|
|
7
|
+
- `cmd`
|
|
8
|
+
- `extractFirstCommand`
|
|
9
|
+
- `cursor`
|
|
10
|
+
- `initMap`
|
|
11
|
+
- `initDoc`
|
|
17
12
|
|
|
18
13
|
## Instalacao
|
|
19
14
|
|
|
@@ -21,223 +16,375 @@ Ela **nao executa comandos**. Ela apenas faz parsing.
|
|
|
21
16
|
npm install command-cmd
|
|
22
17
|
```
|
|
23
18
|
|
|
24
|
-
##
|
|
19
|
+
## Importacao (com nomes em PT-BR)
|
|
25
20
|
|
|
26
21
|
```js
|
|
27
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
cmd as extrairComandos,
|
|
24
|
+
extractFirstCommand as extrairPrimeiroComando,
|
|
25
|
+
cursor as executarCursor,
|
|
26
|
+
initMap as iniciarMap,
|
|
27
|
+
initDoc as iniciarDoc
|
|
28
|
+
} from 'command-cmd';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 1) `cmd(message)`
|
|
32
|
+
|
|
33
|
+
Extrai blocos de comando de um texto.
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
Vamos executar em duas etapas:
|
|
31
|
-
[tipo: shell, comando: npm test, extra: executar na raiz do projeto, seq: 2]
|
|
32
|
-
`;
|
|
35
|
+
Formato aceito:
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
```txt
|
|
38
|
+
[tipo: abrir_app, comando: tiktok, botao: barra_pesquisa, seq: 1]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Para movimento sequencial:
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
```txt
|
|
44
|
+
[mover_sequencia, points: 120x220|420x260|800x300, interval: 300, click: between, doubleClick: true]
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
Tambem aceita o formato curto que voce pediu:
|
|
42
48
|
|
|
43
|
-
```
|
|
44
|
-
[
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
extra: 'executar na raiz do projeto',
|
|
49
|
-
seq: 2
|
|
50
|
-
}
|
|
51
|
-
]
|
|
49
|
+
```txt
|
|
50
|
+
[abrir_app, comando: tiktok, botao: pularADS]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Objeto retornado:
|
|
52
54
|
|
|
55
|
+
```js
|
|
53
56
|
{
|
|
54
|
-
type: '
|
|
55
|
-
command: '
|
|
56
|
-
extra:
|
|
57
|
-
|
|
57
|
+
type: 'abrir_app',
|
|
58
|
+
command: 'tiktok',
|
|
59
|
+
extra: undefined,
|
|
60
|
+
button: 'pularADS',
|
|
61
|
+
seq: 1
|
|
58
62
|
}
|
|
59
63
|
```
|
|
60
64
|
|
|
61
|
-
##
|
|
65
|
+
## 2) `extractFirstCommand(message)`
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
Retorna apenas o primeiro comando valido.
|
|
64
68
|
|
|
65
|
-
|
|
69
|
+
Saida:
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
```js
|
|
72
|
+
{
|
|
73
|
+
type,
|
|
74
|
+
command,
|
|
75
|
+
extra,
|
|
76
|
+
button,
|
|
77
|
+
key,
|
|
78
|
+
modifiers,
|
|
79
|
+
text,
|
|
80
|
+
typeDelay,
|
|
81
|
+
points,
|
|
82
|
+
path,
|
|
83
|
+
interval,
|
|
84
|
+
clickDelay,
|
|
85
|
+
click,
|
|
86
|
+
doubleClick,
|
|
87
|
+
seq
|
|
88
|
+
} | null
|
|
89
|
+
```
|
|
71
90
|
|
|
72
|
-
|
|
91
|
+
## 3) `cursor(input, options?)`
|
|
73
92
|
|
|
74
|
-
|
|
75
|
-
- `command` (ou `comando`)
|
|
93
|
+
Executa os comandos com mouse/teclado.
|
|
76
94
|
|
|
77
|
-
|
|
95
|
+
`input` pode ser:
|
|
78
96
|
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
97
|
+
- `string` (a funcao chama `cmd` internamente)
|
|
98
|
+
- objeto unico
|
|
99
|
+
- lista de objetos
|
|
82
100
|
|
|
83
|
-
|
|
101
|
+
Campos aceitos no objeto:
|
|
84
102
|
|
|
85
|
-
|
|
103
|
+
- `type` ou `tipo`
|
|
104
|
+
- `command` ou `comando`
|
|
105
|
+
- `button` ou `botao`
|
|
106
|
+
- `key` ou `tecla` (para `key_tap`)
|
|
107
|
+
- `modifiers` ou `modificadores` (ex.: `command+shift`)
|
|
108
|
+
- `text` ou `texto` (para `type_string_delayed`)
|
|
109
|
+
- `typeDelay` ou `typingDelay` (ms por caractere na digitacao)
|
|
110
|
+
- `points` ou `pontos` (sequencia de coordenadas)
|
|
111
|
+
- `path` ou `caminho` ou `trajeto` (alias de `points`)
|
|
112
|
+
- `interval` ou `intervalo` (ms entre pontos)
|
|
113
|
+
- `clickDelay` ou `delayClique` (ms entre chegada no ponto e clique)
|
|
114
|
+
- `click` ou `clique` (`none`, `between`, `each`, `first`, `last`)
|
|
115
|
+
- `doubleClick` ou `duplo` (true/false)
|
|
116
|
+
- `seq` ou `sequencia`
|
|
117
|
+
- `extra`
|
|
86
118
|
|
|
87
|
-
|
|
88
|
-
- Saida: `{ type, command, extra, seq } | null`
|
|
89
|
-
- Se nao houver comando valido: retorna `null`.
|
|
119
|
+
## 4) `initMap(options?)`
|
|
90
120
|
|
|
91
|
-
|
|
121
|
+
Cria (ou carrega/mescla) o `map.json` de forma explicita.
|
|
92
122
|
|
|
93
|
-
|
|
123
|
+
Exemplo:
|
|
94
124
|
|
|
95
|
-
```
|
|
96
|
-
|
|
125
|
+
```js
|
|
126
|
+
await iniciarMap();
|
|
127
|
+
await iniciarMap({ mapPath: './config/map.json' });
|
|
97
128
|
```
|
|
98
129
|
|
|
99
|
-
|
|
130
|
+
Campos opcionais:
|
|
100
131
|
|
|
101
|
-
- `
|
|
102
|
-
- `
|
|
103
|
-
- `
|
|
104
|
-
- `
|
|
132
|
+
- `mapPath`
|
|
133
|
+
- `createMapIfMissing`
|
|
134
|
+
- `persistMap`
|
|
135
|
+
- `apps`
|
|
136
|
+
- `defaultClosePoint`
|
|
137
|
+
- `skipAdsPoint`
|
|
138
|
+
- `persistMerged` (salva defaults mesclados mesmo se o map ja existir)
|
|
105
139
|
|
|
106
|
-
|
|
140
|
+
## 5) `initDoc(options?)`
|
|
107
141
|
|
|
108
|
-
|
|
142
|
+
Cria os arquivos de documentacao usando os templates do pacote.
|
|
109
143
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
144
|
+
Por padrao, escreve no diretório atual:
|
|
145
|
+
|
|
146
|
+
- `doc.md`
|
|
147
|
+
- `docPTBR.md`
|
|
148
|
+
- `map.md`
|
|
149
|
+
- `mapPTBR.md`
|
|
150
|
+
|
|
151
|
+
Exemplo:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
await iniciarDoc();
|
|
155
|
+
await iniciarDoc({ outputDir: './docs', overwrite: true, includeMapDocs: false });
|
|
113
156
|
```
|
|
114
157
|
|
|
115
|
-
|
|
158
|
+
Campos opcionais:
|
|
116
159
|
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
- `seq` so e aplicado quando for numero inteiro nao negativo.
|
|
122
|
-
- Chaves desconhecidas usam fallback:
|
|
123
|
-
- A primeira chave desconhecida pode virar `type`, e o valor vira `command`.
|
|
124
|
-
- Chaves desconhecidas seguintes podem preencher `extra`, se ainda estiver vazio.
|
|
160
|
+
- `outputDir` (alias: `dir`, `path`)
|
|
161
|
+
- `overwrite`
|
|
162
|
+
- `includeMapDocs`
|
|
163
|
+
- `files` (ex.: `['doc', 'docPTBR', 'map', 'mapPTBR']`)
|
|
125
164
|
|
|
126
|
-
|
|
165
|
+
### Nome dos apps e botoes (importante)
|
|
127
166
|
|
|
128
|
-
|
|
167
|
+
Voce pode chamar apps e botoes como quiser.
|
|
129
168
|
|
|
130
|
-
|
|
169
|
+
A lib usa o nome apenas para buscar no `map.json`, aplicando normalizacao:
|
|
131
170
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
171
|
+
- ignora maiusculas/minusculas;
|
|
172
|
+
- converte espaco/hifen para `_`;
|
|
173
|
+
- remove acentos.
|
|
174
|
+
|
|
175
|
+
Exemplos que viram a mesma chave logica:
|
|
136
176
|
|
|
137
|
-
|
|
177
|
+
- `Pular ADS`
|
|
178
|
+
- `pular-ads`
|
|
179
|
+
- `pular_ads`
|
|
180
|
+
|
|
181
|
+
O mesmo vale para nome de app:
|
|
182
|
+
|
|
183
|
+
- `Tik Tok`
|
|
184
|
+
- `tik-tok`
|
|
185
|
+
- `tik_tok`
|
|
186
|
+
|
|
187
|
+
Exemplo com objeto em PT-BR:
|
|
138
188
|
|
|
139
189
|
```js
|
|
140
|
-
[
|
|
141
|
-
{
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
]
|
|
190
|
+
const listaDeComandos = [
|
|
191
|
+
{ tipo: 'abrir_app', comando: 'youtube', botao: 'barra_pesquisa', seq: 1 },
|
|
192
|
+
{ tipo: 'abrir_app', comando: 'youtube', botao: 'pularADS', seq: 1 }
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
const resumoDeExecucao = await executarCursor(listaDeComandos);
|
|
196
|
+
console.log(resumoDeExecucao);
|
|
148
197
|
```
|
|
149
198
|
|
|
150
|
-
|
|
199
|
+
## Estado de app (aberto/fechado)
|
|
151
200
|
|
|
152
|
-
|
|
201
|
+
Para comandos de app (`abrir_app`, `close_app`), a lib usa `map.json`:
|
|
153
202
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
```
|
|
203
|
+
1. Le o estado atual do app (`aberto` ou `fechado`).
|
|
204
|
+
2. Se ja estiver `aberto`, nao tenta abrir de novo.
|
|
205
|
+
3. Executa o clique no botao mapeado.
|
|
206
|
+
4. Se o botao tiver `setState`, atualiza o estado no `map.json`.
|
|
159
207
|
|
|
160
|
-
|
|
208
|
+
Obs.: `abrir_app/open_app` sempre dispara `robot.keyTap("command")` antes do fluxo do app.
|
|
209
|
+
|
|
210
|
+
### Criacao automatica do `map.json`
|
|
211
|
+
|
|
212
|
+
Se o arquivo `map.json` nao existir, a lib cria automaticamente na raiz do projeto (cwd), por padrao.
|
|
213
|
+
|
|
214
|
+
Tambem da para criar explicitamente antes das automacoes:
|
|
161
215
|
|
|
162
216
|
```js
|
|
163
|
-
|
|
164
|
-
{ type: 'shell', command: 'npm install', extra: undefined, seq: 1 },
|
|
165
|
-
{ type: 'shell', command: 'npm run dev', extra: 'porta padrao 3000', seq: 1 },
|
|
166
|
-
{ type: 'shell', command: 'npm test', extra: undefined, seq: 3 }
|
|
167
|
-
]
|
|
217
|
+
await iniciarMap();
|
|
168
218
|
```
|
|
169
219
|
|
|
170
|
-
|
|
220
|
+
Esse arquivo inicial ja vem com:
|
|
221
|
+
|
|
222
|
+
- `state` em cada app;
|
|
223
|
+
- `buttons` em cada app;
|
|
224
|
+
- botao `fechar` padrao em cada app (`setState: "fechado"`).
|
|
225
|
+
|
|
226
|
+
Isso permite cenarios como:
|
|
171
227
|
|
|
172
|
-
|
|
228
|
+
- "clique na barra de pesquisa do TikTok"
|
|
229
|
+
- "clique no botao de pular anuncio do YouTube"
|
|
230
|
+
|
|
231
|
+
A IA pode converter para:
|
|
173
232
|
|
|
174
233
|
```txt
|
|
175
|
-
[
|
|
234
|
+
[abrir_app, comando: tiktok, botao: barra_pesquisa]
|
|
235
|
+
[abrir_app, comando: youtube, botao: pularADS]
|
|
176
236
|
```
|
|
177
237
|
|
|
178
|
-
|
|
238
|
+
## Comandos de `type` suportados
|
|
179
239
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
240
|
+
- `abrir_app` / `open_app`
|
|
241
|
+
- `fechar_app` / `close_app`
|
|
242
|
+
- `click` / `clicar`
|
|
243
|
+
- `double_click` / `clique_duplo`
|
|
244
|
+
- `scroll` / `rolar`
|
|
245
|
+
- `mover_sequencia` / `move_sequence`
|
|
246
|
+
- `skip_ads` / `pular_ads`
|
|
247
|
+
- `key_tap` / `tecla`
|
|
248
|
+
- `type_string_delayed` / `digitar`
|
|
249
|
+
|
|
250
|
+
## Teclado e digitacao
|
|
251
|
+
|
|
252
|
+
Atalho simples:
|
|
253
|
+
|
|
254
|
+
```txt
|
|
255
|
+
[key_tap, key: enter]
|
|
189
256
|
```
|
|
190
257
|
|
|
191
|
-
|
|
258
|
+
Atalho com modificador:
|
|
192
259
|
|
|
193
|
-
|
|
260
|
+
```txt
|
|
261
|
+
[key_tap, key: v, modifiers: command]
|
|
262
|
+
```
|
|
194
263
|
|
|
195
|
-
|
|
264
|
+
Digitando devagar:
|
|
196
265
|
|
|
197
266
|
```txt
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
[tipo: <categoria>, comando: <comando>, extra: <contexto opcional>, seq: <inteiro opcional>]
|
|
267
|
+
[type_string_delayed, text: Digitando devagar..., typeDelay: 100]
|
|
268
|
+
```
|
|
201
269
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
270
|
+
## Movimento sequencial (novo)
|
|
271
|
+
|
|
272
|
+
Use `mover_sequencia` para mover o mouse por 2 ou mais coordenadas em ordem.
|
|
273
|
+
|
|
274
|
+
### Formato de coordenadas
|
|
275
|
+
|
|
276
|
+
Use `points` no formato:
|
|
277
|
+
|
|
278
|
+
```txt
|
|
279
|
+
100x200|300x260|640x420
|
|
208
280
|
```
|
|
209
281
|
|
|
210
|
-
|
|
282
|
+
Tambem funciona com `:`:
|
|
211
283
|
|
|
212
284
|
```txt
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
285
|
+
100:200|300:260|640:420
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Controle de clique entre pontos
|
|
289
|
+
|
|
290
|
+
Campo `click`:
|
|
291
|
+
|
|
292
|
+
- `none`: sem clique
|
|
293
|
+
- `between`: clica em cada ponto antes do ultimo
|
|
294
|
+
- `each`: clica em todos os pontos
|
|
295
|
+
- `first`: clica so no primeiro ponto
|
|
296
|
+
- `last`: clica so no ultimo ponto
|
|
297
|
+
|
|
298
|
+
Campo `doubleClick`:
|
|
299
|
+
|
|
300
|
+
- `true`: usa clique duplo quando houver clique
|
|
301
|
+
- `false`: clique simples
|
|
216
302
|
|
|
217
|
-
|
|
218
|
-
|
|
303
|
+
Campo `clickDelay`:
|
|
304
|
+
|
|
305
|
+
- delay (ms) entre chegada no ponto e clique naquele ponto
|
|
306
|
+
|
|
307
|
+
### Exemplo em texto da IA
|
|
308
|
+
|
|
309
|
+
```txt
|
|
310
|
+
[mover_sequencia, points: 140x260|520x280|980x300, interval: 250, click: between, doubleClick: true]
|
|
219
311
|
```
|
|
220
312
|
|
|
221
|
-
|
|
313
|
+
Com `clickDelay`:
|
|
222
314
|
|
|
223
315
|
```txt
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
316
|
+
[mover_sequencia, caminho: 140x260|520x280|980x300, interval: 250, clickDelay: 120, click: between, doubleClick: true]
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Exemplo em objeto JS (mais facil para o dev)
|
|
320
|
+
|
|
321
|
+
```js
|
|
322
|
+
await executarCursor({
|
|
323
|
+
tipo: 'mover_sequencia',
|
|
324
|
+
pontos: [
|
|
325
|
+
{ x: 140, y: 260 },
|
|
326
|
+
{ x: 520, y: 280 },
|
|
327
|
+
{ x: 980, y: 300 }
|
|
328
|
+
],
|
|
329
|
+
intervalo: 250,
|
|
330
|
+
delayClique: 120,
|
|
331
|
+
clique: 'between',
|
|
332
|
+
duplo: true
|
|
333
|
+
});
|
|
227
334
|
```
|
|
228
335
|
|
|
229
|
-
##
|
|
336
|
+
## Opcoes de `cursor`
|
|
230
337
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
338
|
+
```js
|
|
339
|
+
{
|
|
340
|
+
mapPath: 'map.json', // caminho do mapeador
|
|
341
|
+
createMapIfMissing: true, // padrao: cria map automaticamente se faltar
|
|
342
|
+
persistMap: true, // salva estado no arquivo
|
|
343
|
+
launchKey: 'command', // usado no fallback de close_app (atalho command+w)
|
|
344
|
+
moveSteps: 50,
|
|
345
|
+
moveDelay: 8,
|
|
346
|
+
scrollSteps: 10,
|
|
347
|
+
scrollDelay: 20,
|
|
348
|
+
typeDelay: 50,
|
|
349
|
+
sequenceInterval: 250, // intervalo padrao do mover_sequencia
|
|
350
|
+
sequenceClick: 'none', // none|between|each|first|last
|
|
351
|
+
sequenceDoubleClick: false, // clique duplo por padrao
|
|
352
|
+
defaultClosePoint: { x: 1888, y: 16 } // botao "fechar" padrao
|
|
353
|
+
}
|
|
354
|
+
```
|
|
234
355
|
|
|
235
|
-
##
|
|
356
|
+
## map.json (doc dedicada)
|
|
236
357
|
|
|
237
|
-
|
|
358
|
+
Voce pediu uma doc dedicada para o mapeador. Ela esta aqui:
|
|
359
|
+
|
|
360
|
+
- `mapPTBR.md` (PT-BR)
|
|
361
|
+
- `map.md` (English)
|
|
362
|
+
|
|
363
|
+
Esses arquivos explicam:
|
|
364
|
+
|
|
365
|
+
- como montar `apps`, `buttons` e `state`;
|
|
366
|
+
- como mapear coordenadas;
|
|
367
|
+
- como mapear botoes por app;
|
|
368
|
+
- como usar `setState` para atualizar para `fechado`.
|
|
369
|
+
|
|
370
|
+
## System prompt recomendado (IA -> comando)
|
|
371
|
+
|
|
372
|
+
```txt
|
|
373
|
+
Voce e um assistente tecnico.
|
|
374
|
+
Quando sugerir acao executavel, responda apenas com blocos:
|
|
375
|
+
[tipo: <tipo>, comando: <app_ou_valor>, key: <tecla_opcional>, modifiers: <mods_opcional>, text: <texto_opcional>, typeDelay: <ms_digitacao>, points: <pontos_opcionais>, botao: <botao_opcional>, interval: <ms_opcional>, clickDelay: <ms_ate_click>, click: <modo_opcional>, doubleClick: <boolean_opcional>, extra: <texto_opcional>, seq: <inteiro_opcional>]
|
|
376
|
+
|
|
377
|
+
Regras:
|
|
378
|
+
1. Use sempre colchetes.
|
|
379
|
+
2. Um comando por bloco.
|
|
380
|
+
3. seq deve ser inteiro >= 0.
|
|
381
|
+
4. Para app, use tipo abrir_app e comando com nome do app.
|
|
382
|
+
5. Quando for clique de elemento de UI, preencha botao com a chave do map.json.
|
|
383
|
+
6. Para movimento sequencial, use tipo mover_sequencia e `points` no formato `xXy|xXy|xXy`.
|
|
384
|
+
```
|
|
238
385
|
|
|
239
|
-
|
|
386
|
+
## Observacoes importantes
|
|
240
387
|
|
|
241
|
-
-
|
|
242
|
-
-
|
|
243
|
-
-
|
|
388
|
+
- `cursor` precisa de ambiente desktop com `robotjs`.
|
|
389
|
+
- Se `map.json` nao existir e `createMapIfMissing` for `false`, comandos de app retornam erro.
|
|
390
|
+
- Evite virgulas dentro dos valores do bloco `[ ... ]`, porque o parser divide por virgula.
|