command-cmd 1.0.2 → 1.0.4
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 +1640 -16
- package/doc.md +199 -157
- package/docPTBR.md +204 -157
- package/map.md +238 -0
- package/mapPTBR.md +238 -0
- package/package.json +5 -2
package/docPTBR.md
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
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
|
-
- Extrair comandos embutidos em respostas de IA.
|
|
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`
|
|
17
10
|
|
|
18
11
|
## Instalacao
|
|
19
12
|
|
|
@@ -21,223 +14,277 @@ Ela **nao executa comandos**. Ela apenas faz parsing.
|
|
|
21
14
|
npm install command-cmd
|
|
22
15
|
```
|
|
23
16
|
|
|
24
|
-
##
|
|
17
|
+
## Importacao (com nomes em PT-BR)
|
|
25
18
|
|
|
26
19
|
```js
|
|
27
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
cmd as extrairComandos,
|
|
22
|
+
extractFirstCommand as extrairPrimeiroComando,
|
|
23
|
+
cursor as executarCursor
|
|
24
|
+
} from 'command-cmd';
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 1) `cmd(message)`
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
Vamos executar em duas etapas:
|
|
31
|
-
[tipo: shell, comando: npm test, extra: executar na raiz do projeto, seq: 2]
|
|
32
|
-
`;
|
|
29
|
+
Extrai blocos de comando de um texto.
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
const primeiroComando = extractFirstCommand(textoDaIA);
|
|
31
|
+
Formato aceito:
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
```txt
|
|
34
|
+
[tipo: abrir_app, comando: tiktok, botao: barra_pesquisa, seq: 1]
|
|
39
35
|
```
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
Para movimento sequencial:
|
|
42
38
|
|
|
43
|
-
```
|
|
44
|
-
[
|
|
45
|
-
|
|
46
|
-
type: 'shell',
|
|
47
|
-
command: 'npm test',
|
|
48
|
-
extra: 'executar na raiz do projeto',
|
|
49
|
-
seq: 2
|
|
50
|
-
}
|
|
51
|
-
]
|
|
39
|
+
```txt
|
|
40
|
+
[mover_sequencia, points: 120x220|420x260|800x300, interval: 300, click: between, doubleClick: true]
|
|
41
|
+
```
|
|
52
42
|
|
|
43
|
+
Tambem aceita o formato curto que voce pediu:
|
|
44
|
+
|
|
45
|
+
```txt
|
|
46
|
+
[abrir_app, comando: tiktok, botao: pularADS]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Objeto retornado:
|
|
50
|
+
|
|
51
|
+
```js
|
|
53
52
|
{
|
|
54
|
-
type: '
|
|
55
|
-
command: '
|
|
56
|
-
extra:
|
|
57
|
-
|
|
53
|
+
type: 'abrir_app',
|
|
54
|
+
command: 'tiktok',
|
|
55
|
+
extra: undefined,
|
|
56
|
+
button: 'pularADS',
|
|
57
|
+
seq: 1
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
##
|
|
61
|
+
## 2) `extractFirstCommand(message)`
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
Retorna apenas o primeiro comando valido.
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Saida:
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
- Se nenhum comando valido for encontrado: retorna `[]`.
|
|
67
|
+
```js
|
|
68
|
+
{ type, command, extra, button, points, path, interval, clickDelay, click, doubleClick, seq } | null
|
|
69
|
+
```
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
## 3) `cursor(input, options?)`
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
- `command` (ou `comando`)
|
|
73
|
+
Executa os comandos com mouse/teclado.
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
`input` pode ser:
|
|
78
76
|
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
77
|
+
- `string` (a funcao chama `cmd` internamente)
|
|
78
|
+
- objeto unico
|
|
79
|
+
- lista de objetos
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
Campos aceitos no objeto:
|
|
84
82
|
|
|
85
|
-
|
|
83
|
+
- `type` ou `tipo`
|
|
84
|
+
- `command` ou `comando`
|
|
85
|
+
- `button` ou `botao`
|
|
86
|
+
- `points` ou `pontos` (sequencia de coordenadas)
|
|
87
|
+
- `path` ou `caminho` ou `trajeto` (alias de `points`)
|
|
88
|
+
- `interval` ou `intervalo` (ms entre pontos)
|
|
89
|
+
- `clickDelay` ou `delayClique` (ms entre chegada no ponto e clique)
|
|
90
|
+
- `click` ou `clique` (`none`, `between`, `each`, `first`, `last`)
|
|
91
|
+
- `doubleClick` ou `duplo` (true/false)
|
|
92
|
+
- `seq` ou `sequencia`
|
|
93
|
+
- `extra`
|
|
86
94
|
|
|
87
|
-
|
|
88
|
-
- Saida: `{ type, command, extra, seq } | null`
|
|
89
|
-
- Se nao houver comando valido: retorna `null`.
|
|
95
|
+
### Nome dos apps e botoes (importante)
|
|
90
96
|
|
|
91
|
-
|
|
97
|
+
Voce pode chamar apps e botoes como quiser.
|
|
92
98
|
|
|
93
|
-
|
|
99
|
+
A lib usa o nome apenas para buscar no `map.json`, aplicando normalizacao:
|
|
94
100
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
- ignora maiusculas/minusculas;
|
|
102
|
+
- converte espaco/hifen para `_`;
|
|
103
|
+
- remove acentos.
|
|
98
104
|
|
|
99
|
-
|
|
105
|
+
Exemplos que viram a mesma chave logica:
|
|
100
106
|
|
|
101
|
-
- `
|
|
102
|
-
- `
|
|
103
|
-
- `
|
|
104
|
-
- `seq`
|
|
107
|
+
- `Pular ADS`
|
|
108
|
+
- `pular-ads`
|
|
109
|
+
- `pular_ads`
|
|
105
110
|
|
|
106
|
-
|
|
111
|
+
O mesmo vale para nome de app:
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
- `Tik Tok`
|
|
114
|
+
- `tik-tok`
|
|
115
|
+
- `tik_tok`
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
Exemplo com objeto em PT-BR:
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
const listaDeComandos = [
|
|
121
|
+
{ tipo: 'abrir_app', comando: 'youtube', botao: 'barra_pesquisa', seq: 1 },
|
|
122
|
+
{ tipo: 'abrir_app', comando: 'youtube', botao: 'pularADS', seq: 1 }
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
const resumoDeExecucao = await executarCursor(listaDeComandos);
|
|
126
|
+
console.log(resumoDeExecucao);
|
|
113
127
|
```
|
|
114
128
|
|
|
115
|
-
##
|
|
129
|
+
## Estado de app (aberto/fechado)
|
|
116
130
|
|
|
117
|
-
|
|
118
|
-
- O conteudo interno e dividido por virgula.
|
|
119
|
-
- Cada parte precisa ter `:` para virar `chave: valor`.
|
|
120
|
-
- Bloco sem `type/tipo` ou `command/comando` e ignorado.
|
|
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.
|
|
131
|
+
Para comandos de app (`abrir_app`, `close_app`), a lib usa `map.json`:
|
|
125
132
|
|
|
126
|
-
|
|
133
|
+
1. Le o estado atual do app (`aberto` ou `fechado`).
|
|
134
|
+
2. Se ja estiver `aberto`, nao tenta abrir de novo.
|
|
135
|
+
3. Executa o clique no botao mapeado.
|
|
136
|
+
4. Se o botao tiver `setState`, atualiza o estado no `map.json`.
|
|
127
137
|
|
|
128
|
-
###
|
|
138
|
+
### Criacao automatica do `map.json`
|
|
129
139
|
|
|
130
|
-
|
|
140
|
+
Se o arquivo `map.json` nao existir, a lib cria automaticamente na raiz do projeto (cwd), por padrao.
|
|
131
141
|
|
|
132
|
-
|
|
133
|
-
Para listar arquivos:
|
|
134
|
-
[tipo: shell, comando: ls -la, extra: linux ou mac, seq: 1]
|
|
135
|
-
```
|
|
142
|
+
Esse arquivo inicial ja vem com:
|
|
136
143
|
|
|
137
|
-
|
|
144
|
+
- `state` em cada app;
|
|
145
|
+
- `buttons` em cada app;
|
|
146
|
+
- botao `fechar` padrao em cada app (`setState: "fechado"`).
|
|
138
147
|
|
|
139
|
-
|
|
140
|
-
[
|
|
141
|
-
{
|
|
142
|
-
type: 'shell',
|
|
143
|
-
command: 'ls -la',
|
|
144
|
-
extra: 'linux ou mac',
|
|
145
|
-
seq: 1
|
|
146
|
-
}
|
|
147
|
-
]
|
|
148
|
-
```
|
|
148
|
+
Isso permite cenarios como:
|
|
149
149
|
|
|
150
|
-
|
|
150
|
+
- "clique na barra de pesquisa do TikTok"
|
|
151
|
+
- "clique no botao de pular anuncio do YouTube"
|
|
151
152
|
|
|
152
|
-
|
|
153
|
+
A IA pode converter para:
|
|
153
154
|
|
|
154
155
|
```txt
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
Passo 3: [tipo: shell, comando: npm test, seq: 3]
|
|
156
|
+
[abrir_app, comando: tiktok, botao: barra_pesquisa]
|
|
157
|
+
[abrir_app, comando: youtube, botao: pularADS]
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
## Comandos de `type` suportados
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
- `abrir_app` / `open_app`
|
|
163
|
+
- `fechar_app` / `close_app`
|
|
164
|
+
- `click` / `clicar`
|
|
165
|
+
- `double_click` / `clique_duplo`
|
|
166
|
+
- `scroll` / `rolar`
|
|
167
|
+
- `mover_sequencia` / `move_sequence`
|
|
168
|
+
- `skip_ads` / `pular_ads`
|
|
169
|
+
|
|
170
|
+
## Movimento sequencial (novo)
|
|
169
171
|
|
|
170
|
-
|
|
172
|
+
Use `mover_sequencia` para mover o mouse por 2 ou mais coordenadas em ordem.
|
|
171
173
|
|
|
172
|
-
|
|
174
|
+
### Formato de coordenadas
|
|
175
|
+
|
|
176
|
+
Use `points` no formato:
|
|
173
177
|
|
|
174
178
|
```txt
|
|
175
|
-
|
|
179
|
+
100x200|300x260|640x420
|
|
176
180
|
```
|
|
177
181
|
|
|
178
|
-
|
|
182
|
+
Tambem funciona com `:`:
|
|
179
183
|
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
{
|
|
183
|
-
type: 'shell',
|
|
184
|
-
command: 'npm test',
|
|
185
|
-
extra: undefined,
|
|
186
|
-
seq: undefined
|
|
187
|
-
}
|
|
188
|
-
]
|
|
184
|
+
```txt
|
|
185
|
+
100:200|300:260|640:420
|
|
189
186
|
```
|
|
190
187
|
|
|
191
|
-
|
|
188
|
+
### Controle de clique entre pontos
|
|
192
189
|
|
|
193
|
-
|
|
190
|
+
Campo `click`:
|
|
194
191
|
|
|
195
|
-
|
|
192
|
+
- `none`: sem clique
|
|
193
|
+
- `between`: clica em cada ponto antes do ultimo
|
|
194
|
+
- `each`: clica em todos os pontos
|
|
195
|
+
- `first`: clica so no primeiro ponto
|
|
196
|
+
- `last`: clica so no ultimo ponto
|
|
196
197
|
|
|
197
|
-
|
|
198
|
-
Voce e um assistente tecnico.
|
|
199
|
-
Sempre que sugerir uma acao executavel, responda usando blocos no formato:
|
|
200
|
-
[tipo: <categoria>, comando: <comando>, extra: <contexto opcional>, seq: <inteiro opcional>]
|
|
198
|
+
Campo `doubleClick`:
|
|
201
199
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
200
|
+
- `true`: usa clique duplo quando houver clique
|
|
201
|
+
- `false`: clique simples
|
|
202
|
+
|
|
203
|
+
Campo `clickDelay`:
|
|
204
|
+
|
|
205
|
+
- delay (ms) entre chegada no ponto e clique naquele ponto
|
|
206
|
+
|
|
207
|
+
### Exemplo em texto da IA
|
|
208
|
+
|
|
209
|
+
```txt
|
|
210
|
+
[mover_sequencia, points: 140x260|520x280|980x300, interval: 250, click: between, doubleClick: true]
|
|
208
211
|
```
|
|
209
212
|
|
|
210
|
-
|
|
213
|
+
Com `clickDelay`:
|
|
211
214
|
|
|
212
215
|
```txt
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
+
[mover_sequencia, caminho: 140x260|520x280|980x300, interval: 250, clickDelay: 120, click: between, doubleClick: true]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Exemplo em objeto JS (mais facil para o dev)
|
|
216
220
|
|
|
217
|
-
|
|
218
|
-
|
|
221
|
+
```js
|
|
222
|
+
await executarCursor({
|
|
223
|
+
tipo: 'mover_sequencia',
|
|
224
|
+
pontos: [
|
|
225
|
+
{ x: 140, y: 260 },
|
|
226
|
+
{ x: 520, y: 280 },
|
|
227
|
+
{ x: 980, y: 300 }
|
|
228
|
+
],
|
|
229
|
+
intervalo: 250,
|
|
230
|
+
delayClique: 120,
|
|
231
|
+
clique: 'between',
|
|
232
|
+
duplo: true
|
|
233
|
+
});
|
|
219
234
|
```
|
|
220
235
|
|
|
221
|
-
|
|
236
|
+
## Opcoes de `cursor`
|
|
222
237
|
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
238
|
+
```js
|
|
239
|
+
{
|
|
240
|
+
mapPath: 'map.json', // caminho do mapeador
|
|
241
|
+
createMapIfMissing: true, // padrao: cria map automaticamente se faltar
|
|
242
|
+
persistMap: true, // salva estado no arquivo
|
|
243
|
+
launchKey: 'command', // use false para nao disparar tecla de launcher
|
|
244
|
+
moveSteps: 50,
|
|
245
|
+
moveDelay: 8,
|
|
246
|
+
scrollSteps: 10,
|
|
247
|
+
scrollDelay: 20,
|
|
248
|
+
typeDelay: 50,
|
|
249
|
+
sequenceInterval: 250, // intervalo padrao do mover_sequencia
|
|
250
|
+
sequenceClick: 'none', // none|between|each|first|last
|
|
251
|
+
sequenceDoubleClick: false, // clique duplo por padrao
|
|
252
|
+
defaultClosePoint: { x: 1888, y: 16 } // botao "fechar" padrao
|
|
253
|
+
}
|
|
227
254
|
```
|
|
228
255
|
|
|
229
|
-
##
|
|
256
|
+
## map.json (doc dedicada)
|
|
257
|
+
|
|
258
|
+
Voce pediu uma doc dedicada para o mapeador. Ela esta aqui:
|
|
230
259
|
|
|
231
|
-
-
|
|
232
|
-
-
|
|
233
|
-
- Apenas um campo `extra` e retornado por bloco.
|
|
260
|
+
- `mapPTBR.md` (PT-BR)
|
|
261
|
+
- `map.md` (English)
|
|
234
262
|
|
|
235
|
-
|
|
263
|
+
Esses arquivos explicam:
|
|
236
264
|
|
|
237
|
-
|
|
265
|
+
- como montar `apps`, `buttons` e `state`;
|
|
266
|
+
- como mapear coordenadas;
|
|
267
|
+
- como mapear botoes por app;
|
|
268
|
+
- como usar `setState` para atualizar para `fechado`.
|
|
269
|
+
|
|
270
|
+
## System prompt recomendado (IA -> comando)
|
|
271
|
+
|
|
272
|
+
```txt
|
|
273
|
+
Voce e um assistente tecnico.
|
|
274
|
+
Quando sugerir acao executavel, responda apenas com blocos:
|
|
275
|
+
[tipo: <tipo>, comando: <app_ou_valor>, 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>]
|
|
276
|
+
|
|
277
|
+
Regras:
|
|
278
|
+
1. Use sempre colchetes.
|
|
279
|
+
2. Um comando por bloco.
|
|
280
|
+
3. seq deve ser inteiro >= 0.
|
|
281
|
+
4. Para app, use tipo abrir_app e comando com nome do app.
|
|
282
|
+
5. Quando for clique de elemento de UI, preencha botao com a chave do map.json.
|
|
283
|
+
6. Para movimento sequencial, use tipo mover_sequencia e `points` no formato `xXy|xXy|xXy`.
|
|
284
|
+
```
|
|
238
285
|
|
|
239
|
-
|
|
286
|
+
## Observacoes importantes
|
|
240
287
|
|
|
241
|
-
-
|
|
242
|
-
-
|
|
243
|
-
-
|
|
288
|
+
- `cursor` precisa de ambiente desktop com `robotjs`.
|
|
289
|
+
- Se `map.json` nao existir e `createMapIfMissing` for `false`, comandos de app retornam erro.
|
|
290
|
+
- Evite virgulas dentro dos valores do bloco `[ ... ]`, porque o parser divide por virgula.
|
package/map.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# map.json (Mapper Guide - English)
|
|
2
|
+
|
|
3
|
+
This guide explains how to create `map.json` so the library knows:
|
|
4
|
+
|
|
5
|
+
- where to click to open each app;
|
|
6
|
+
- where app-specific buttons are;
|
|
7
|
+
- current app state (`open` / `closed` or `aberto` / `fechado`).
|
|
8
|
+
|
|
9
|
+
Note: `move_sequence` does not depend on `map.json`; it uses coordinates from the command payload.
|
|
10
|
+
|
|
11
|
+
## File location
|
|
12
|
+
|
|
13
|
+
Create `map.json` in your project root (where Node runs).
|
|
14
|
+
|
|
15
|
+
By default, the library auto-creates this file if it does not exist.
|
|
16
|
+
|
|
17
|
+
If you need another path:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
await cursor(commands, { mapPath: './config/map.json' });
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Minimal structure
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"version": 1,
|
|
28
|
+
"apps": {
|
|
29
|
+
"youtube": {
|
|
30
|
+
"state": "closed",
|
|
31
|
+
"launcher": { "x": 20, "y": 225 },
|
|
32
|
+
"buttons": {}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Even with minimal setup, the generated default map includes:
|
|
39
|
+
|
|
40
|
+
- `state`;
|
|
41
|
+
- `buttons`;
|
|
42
|
+
- a default `close/fechar` button per app (`setState: "fechado"`).
|
|
43
|
+
|
|
44
|
+
## Recommended structure (with buttons)
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"version": 1,
|
|
49
|
+
"apps": {
|
|
50
|
+
"tiktok": {
|
|
51
|
+
"state": "closed",
|
|
52
|
+
"launcher": {
|
|
53
|
+
"position": { "x": 28, "y": 260 },
|
|
54
|
+
"path": {
|
|
55
|
+
"points": ["60x740", "140x740", "220x740", "28x260"],
|
|
56
|
+
"click": "between",
|
|
57
|
+
"interval": 180,
|
|
58
|
+
"clickDelay": 120
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"searchIcon": { "x": 612, "y": 138 },
|
|
62
|
+
"buttons": {
|
|
63
|
+
"search_bar": { "x": 612, "y": 138 }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"youtube": {
|
|
67
|
+
"state": "open",
|
|
68
|
+
"launcher": { "x": 20, "y": 225 },
|
|
69
|
+
"searchIcon": { "x": 575, "y": 144 },
|
|
70
|
+
"buttons": {
|
|
71
|
+
"skip_ads": { "x": 808, "y": 569 },
|
|
72
|
+
"close": {
|
|
73
|
+
"position": { "x": 1888, "y": 16 },
|
|
74
|
+
"setState": "closed"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## App fields
|
|
83
|
+
|
|
84
|
+
- `state`: `open`, `closed`, `aberto`, or `fechado`
|
|
85
|
+
- `launcher`: click point used to open/focus app
|
|
86
|
+
- `searchIcon`: search icon point (optional)
|
|
87
|
+
- `buttons`: per-app button map
|
|
88
|
+
- optional `path/caminho` inside `launcher`: movement route before final click
|
|
89
|
+
|
|
90
|
+
## Button fields
|
|
91
|
+
|
|
92
|
+
Simple format:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
"skip_ads": { "x": 808, "y": 569 }
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Full format:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
"close": {
|
|
102
|
+
"position": { "x": 1888, "y": 16 },
|
|
103
|
+
"setState": "closed"
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
With path:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
"search_bar": {
|
|
111
|
+
"position": { "x": 612, "y": 138 },
|
|
112
|
+
"path": {
|
|
113
|
+
"points": ["500x140", "560x140", "612x138"],
|
|
114
|
+
"click": "between",
|
|
115
|
+
"interval": 150,
|
|
116
|
+
"clickDelay": 100,
|
|
117
|
+
"doubleClick": false
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
When `setState` is present, the library updates app state in `map.json` after click.
|
|
123
|
+
|
|
124
|
+
## App and button names
|
|
125
|
+
|
|
126
|
+
You can name buttons freely in `map.json`.
|
|
127
|
+
|
|
128
|
+
Same for app names inside `apps`.
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
"buttons": {
|
|
134
|
+
"my_custom_button": { "x": 500, "y": 300 }
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Then call it using:
|
|
139
|
+
|
|
140
|
+
```txt
|
|
141
|
+
[open_app, command: tiktok, button: my_custom_button]
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Lookup uses normalization (case-insensitive, spaces/hyphens to `_`, accent-insensitive).
|
|
145
|
+
|
|
146
|
+
## Optional `path/caminho` field
|
|
147
|
+
|
|
148
|
+
You can use `path/caminho` in:
|
|
149
|
+
|
|
150
|
+
- `apps.<name>.launcher`
|
|
151
|
+
- `apps.<name>.searchIcon`
|
|
152
|
+
- `apps.<name>.buttons.<buttonName>`
|
|
153
|
+
|
|
154
|
+
Format:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
"path": {
|
|
158
|
+
"points": ["100x200", "300x260", "640x420"],
|
|
159
|
+
"click": "between",
|
|
160
|
+
"interval": 200,
|
|
161
|
+
"clickDelay": 120,
|
|
162
|
+
"doubleClick": false
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Fields:
|
|
167
|
+
|
|
168
|
+
- `points`: coordinate sequence
|
|
169
|
+
- `click`: `none`, `between`, `each`, `first`, `last`
|
|
170
|
+
- `interval`: delay between points (ms)
|
|
171
|
+
- `clickDelay`: delay between arriving and clicking at that point (ms)
|
|
172
|
+
- `doubleClick`: whether path clicks are double clicks
|
|
173
|
+
|
|
174
|
+
Note:
|
|
175
|
+
|
|
176
|
+
- after the path, the library still performs the final click on `position`.
|
|
177
|
+
|
|
178
|
+
## How app state is used
|
|
179
|
+
|
|
180
|
+
Command:
|
|
181
|
+
|
|
182
|
+
```txt
|
|
183
|
+
[open_app, command: youtube, button: skipADS]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Flow:
|
|
187
|
+
|
|
188
|
+
1. Reads `apps.youtube.state`.
|
|
189
|
+
2. If already open, it does not open again.
|
|
190
|
+
3. Resolves `buttons.skip_ads` and clicks.
|
|
191
|
+
4. If that button has `setState`, it writes the new state to file.
|
|
192
|
+
|
|
193
|
+
## AI command examples
|
|
194
|
+
|
|
195
|
+
```txt
|
|
196
|
+
[open_app, command: tiktok, button: search_bar]
|
|
197
|
+
[open_app, command: youtube, button: skipADS]
|
|
198
|
+
[close_app, command: youtube, button: close]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Accepted aliases
|
|
202
|
+
|
|
203
|
+
App:
|
|
204
|
+
|
|
205
|
+
- `google` -> `chrome`
|
|
206
|
+
|
|
207
|
+
Button:
|
|
208
|
+
|
|
209
|
+
- `skipADS` -> `skip_ads`
|
|
210
|
+
- `search`, `search_bar`, `barra_pesquisa` -> same logical key
|
|
211
|
+
- `close`, `fechar` -> `close`/`fechar` mapping
|
|
212
|
+
|
|
213
|
+
## Quick coordinate calibration
|
|
214
|
+
|
|
215
|
+
Use this script to read current mouse coordinates:
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
import robot from 'robotjs';
|
|
219
|
+
|
|
220
|
+
setInterval(() => {
|
|
221
|
+
const p = robot.getMousePos();
|
|
222
|
+
console.log(`x=${p.x}, y=${p.y}`);
|
|
223
|
+
}, 300);
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Move mouse over launcher/buttons and copy values into `map.json`.
|
|
227
|
+
|
|
228
|
+
## Common errors
|
|
229
|
+
|
|
230
|
+
- `unknown_app:<name>`: app not found in `map.json`
|
|
231
|
+
- `unknown_button:<app>:<button>`: missing button under `apps.<app>.buttons`
|
|
232
|
+
- `missing_launcher:<app>`: app has no `launcher`
|
|
233
|
+
- `map_not_found:<path>`: map file not found
|
|
234
|
+
|
|
235
|
+
## Maintenance tip
|
|
236
|
+
|
|
237
|
+
Keep stable button keys (`search_bar`, `skip_ads`, `close`).
|
|
238
|
+
If UI changes, update only `map.json`, not your code.
|