terminal-smart-cli 0.98.0 → 0.99.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.
- package/README.md +7 -5
- package/bin/ts.js +344 -196
- package/hub/cli.js +255 -0
- package/hub/controle.js +262 -0
- package/hub/dpapi.js +55 -0
- package/hub/estado.js +274 -0
- package/hub/exportar-telas.js +149 -0
- package/hub/hub.js +717 -0
- package/hub/mascara.js +67 -0
- package/hub/parar.js +151 -0
- package/hub/principal.js +5 -0
- package/hub/proto/PROTOCOLO.md +789 -0
- package/hub/proto/ts-proto.js +1643 -0
- package/hub/relay-conexao.js +200 -0
- package/hub/telas-arquivo.js +130 -0
- package/hub/tmux.js +189 -0
- package/hub/vps/README.md +109 -0
- package/hub/vps/tmux-agentes.conf +5 -0
- package/hub/vps/ts-hub-exportar-telas.service +30 -0
- package/hub/vps/ts-hub-parar-consumir +67 -0
- package/hub/vps/ts-hub-parar.path +16 -0
- package/hub/vps/ts-hub-parar.service +23 -0
- package/hub/vps/ts-hub-parar.tmpfiles.conf +10 -0
- package/hub/vps/ts-hub.service +39 -0
- package/hub/vps/ts-tmux.service +19 -0
- package/lib/acp.js +8 -2
- package/lib/agent.js +186 -87
- package/lib/chat-local.js +139 -0
- package/lib/core.js +336 -23
- package/lib/doctor.js +13 -5
- package/lib/i18n.js +69 -31
- package/lib/ia-local.js +388 -0
- package/lib/intelligence-core.js +108 -1
- package/lib/keyring.js +0 -1
- package/lib/meta.js +8 -8
- package/lib/personal-agent-llm.js +99 -26
- package/lib/sentinela.js +2 -2
- package/lib/tools.js +638 -8
- package/package.json +4 -2
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# EXEMPLO — não aplicado. Instalar em /usr/local/sbin/ts-hub-parar-consumir (root:root, 0755).
|
|
3
|
+
# Chamado pelo ts-hub-parar.service (root) quando o hub grava um pedido. Ver README.md.
|
|
4
|
+
#
|
|
5
|
+
# Regras:
|
|
6
|
+
# - nunca lê o CONTEÚDO do pedido (o arquivo vem do usuário do hub): só o nome, validado
|
|
7
|
+
# contra ^parar-<13 dígitos>-<16 hex>\.pedido$;
|
|
8
|
+
# - tudo o que estiver em pedidos/ sai de lá por rename (mv no mesmo sistema de arquivos não
|
|
9
|
+
# segue link): válidos para consumidos/<nome>, o resto para consumidos/invalido-...;
|
|
10
|
+
# o diretório sempre fica vazio, então o .path não dispara em laço;
|
|
11
|
+
# - roda o ts-parar-tudo UMA vez por lote, mesmo que haja vários pedidos;
|
|
12
|
+
# - grava confirmacoes/<base>.ok (ou .falhou) de forma atômica, legível pelo hub (0644).
|
|
13
|
+
#
|
|
14
|
+
# Variáveis (só para teste; em produção valem os padrões):
|
|
15
|
+
# TS_HUB_PARAR_BASE (padrão /var/lib/ts-hub-parar)
|
|
16
|
+
# TS_HUB_PARAR_CMD (padrão /usr/local/sbin/ts-parar-tudo)
|
|
17
|
+
|
|
18
|
+
BASE="${TS_HUB_PARAR_BASE:-/var/lib/ts-hub-parar}"
|
|
19
|
+
CMD="${TS_HUB_PARAR_CMD:-/usr/local/sbin/ts-parar-tudo}"
|
|
20
|
+
PED="$BASE/pedidos"
|
|
21
|
+
CONF="$BASE/confirmacoes"
|
|
22
|
+
CONS="$BASE/consumidos"
|
|
23
|
+
umask 022
|
|
24
|
+
|
|
25
|
+
[ -d "$PED" ] && [ ! -L "$PED" ] || { echo "ts-hub-parar: $PED ausente" >&2; exit 1; }
|
|
26
|
+
[ -d "$CONF" ] && [ ! -L "$CONF" ] || { echo "ts-hub-parar: $CONF ausente" >&2; exit 1; }
|
|
27
|
+
[ -d "$CONS" ] && [ ! -L "$CONS" ] || { echo "ts-hub-parar: $CONS ausente" >&2; exit 1; }
|
|
28
|
+
|
|
29
|
+
# Nome válido: casado caractere a caractere (sem grep: nome com quebra de linha, espaço ou
|
|
30
|
+
# curinga nunca passa).
|
|
31
|
+
D='[0-9]'
|
|
32
|
+
X='[0-9a-f]'
|
|
33
|
+
D13="$D$D$D$D$D$D$D$D$D$D$D$D$D"
|
|
34
|
+
X16="$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X"
|
|
35
|
+
|
|
36
|
+
validos=""
|
|
37
|
+
n=0
|
|
38
|
+
for f in "$PED"/* "$PED"/.[!.]* "$PED"/..?*; do
|
|
39
|
+
[ -e "$f" ] || [ -L "$f" ] || continue # padrão que não casou com nada
|
|
40
|
+
nome=${f##*/}
|
|
41
|
+
n=$((n + 1))
|
|
42
|
+
valido=0
|
|
43
|
+
case "$nome" in
|
|
44
|
+
parar-$D13-$X16.pedido) [ -f "$f" ] && [ ! -L "$f" ] && valido=1 ;;
|
|
45
|
+
esac
|
|
46
|
+
if [ "$valido" = 1 ]; then
|
|
47
|
+
if mv -fT -- "$f" "$CONS/$nome"; then
|
|
48
|
+
validos="$validos ${nome%.pedido}"
|
|
49
|
+
fi
|
|
50
|
+
else
|
|
51
|
+
mv -fT -- "$f" "$CONS/invalido-$(date -u +%Y%m%d%H%M%S)-$$-$n" || echo "ts-hub-parar: não consegui tirar uma entrada de $PED" >&2
|
|
52
|
+
fi
|
|
53
|
+
done
|
|
54
|
+
|
|
55
|
+
[ -n "$validos" ] || exit 0
|
|
56
|
+
set -f # daqui em diante, nada de curinga na lista (os nomes já são só [a-z0-9-])
|
|
57
|
+
|
|
58
|
+
if "$CMD" "celular"; then resultado=ok; else resultado=falhou; fi
|
|
59
|
+
echo "ts-hub-parar: ts-parar-tudo terminou ($resultado)"
|
|
60
|
+
|
|
61
|
+
for base in $validos; do
|
|
62
|
+
tmp=$(mktemp "$CONF/.tmp.XXXXXX") || continue
|
|
63
|
+
printf '{"resultado":"%s","em":"%s"}\n' "$resultado" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$tmp"
|
|
64
|
+
chmod 0644 "$tmp"
|
|
65
|
+
mv -fT -- "$tmp" "$CONF/$base.$resultado"
|
|
66
|
+
done
|
|
67
|
+
exit 0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# EXEMPLO — não aplicado. Instalação e motivos: README.md nesta pasta.
|
|
2
|
+
# Copiar para /etc/systemd/system/ts-hub-parar.path (dono root, 0644).
|
|
3
|
+
#
|
|
4
|
+
# Observa o diretório de pedidos do hub. O serviço sempre esvazia o diretório (renomeia tudo
|
|
5
|
+
# para consumidos/), então o .path não dispara em laço; o limite abaixo é só uma segunda trava.
|
|
6
|
+
[Unit]
|
|
7
|
+
Description=Terminal Smart: pedido de "Parar tudo" vindo do hub (celular)
|
|
8
|
+
|
|
9
|
+
[Path]
|
|
10
|
+
DirectoryNotEmpty=/var/lib/ts-hub-parar/pedidos
|
|
11
|
+
Unit=ts-hub-parar.service
|
|
12
|
+
TriggerLimitIntervalSec=60
|
|
13
|
+
TriggerLimitBurst=20
|
|
14
|
+
|
|
15
|
+
[Install]
|
|
16
|
+
WantedBy=paths.target
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# EXEMPLO — não aplicado. Instalação e motivos: README.md nesta pasta.
|
|
2
|
+
# Copiar para /etc/systemd/system/ts-hub-parar.service (dono root, 0644).
|
|
3
|
+
#
|
|
4
|
+
# Roda como root (o ts-parar-tudo precisa parar os agentes). Não lê o conteúdo de nenhum
|
|
5
|
+
# pedido: só valida o NOME, renomeia o pedido para consumidos/, roda
|
|
6
|
+
# /usr/local/sbin/ts-parar-tudo "celular" uma vez e grava a confirmação que o hub lê.
|
|
7
|
+
[Unit]
|
|
8
|
+
Description=Terminal Smart: executa "Parar tudo" e confirma ao hub
|
|
9
|
+
StartLimitIntervalSec=60
|
|
10
|
+
StartLimitBurst=10
|
|
11
|
+
|
|
12
|
+
[Service]
|
|
13
|
+
Type=oneshot
|
|
14
|
+
User=root
|
|
15
|
+
Group=root
|
|
16
|
+
UMask=0022
|
|
17
|
+
ExecStart=/usr/local/sbin/ts-hub-parar-consumir
|
|
18
|
+
TimeoutStartSec=90
|
|
19
|
+
PrivateTmp=yes
|
|
20
|
+
# Endurecimento extra, se o ts-parar-tudo continuar funcionando com ele (testar antes):
|
|
21
|
+
#ProtectHome=read-only
|
|
22
|
+
#ProtectKernelTunables=yes
|
|
23
|
+
#ProtectControlGroups=no
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# EXEMPLO — não aplicado. Copiar para /etc/tmpfiles.d/ts-hub-parar.conf e rodar
|
|
2
|
+
# systemd-tmpfiles --create /etc/tmpfiles.d/ts-hub-parar.conf
|
|
3
|
+
#
|
|
4
|
+
# pedidos/ só o hub (tshub) escreve; root lê o nome e renomeia
|
|
5
|
+
# confirmacoes/ só root escreve; o hub lê (0755, arquivos 0644)
|
|
6
|
+
# consumidos/ só root; histórico dos pedidos, apagado depois de 30 dias
|
|
7
|
+
d /var/lib/ts-hub-parar 0755 root root -
|
|
8
|
+
d /var/lib/ts-hub-parar/pedidos 0700 tshub tshub -
|
|
9
|
+
d /var/lib/ts-hub-parar/confirmacoes 0755 root root -
|
|
10
|
+
d /var/lib/ts-hub-parar/consumidos 0700 root root 30d
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# EXEMPLO — não aplicado. Copiar para /etc/systemd/system/ts-hub.service.
|
|
2
|
+
# O hub roda como tshub (sem sudo, sem docker, sem tmux): só abre conexão de SAÍDA até o
|
|
3
|
+
# relay, lê as telas exportadas (grupo ts-telas) e pede o Parar tudo por arquivo-sinal.
|
|
4
|
+
[Unit]
|
|
5
|
+
Description=Terminal Smart: hub (acesso pelo celular, só leitura + Parar tudo)
|
|
6
|
+
Wants=network-online.target
|
|
7
|
+
After=network-online.target ts-hub-parar.path
|
|
8
|
+
|
|
9
|
+
[Service]
|
|
10
|
+
User=tshub
|
|
11
|
+
Group=tshub
|
|
12
|
+
SupplementaryGroups=ts-telas
|
|
13
|
+
UMask=0077
|
|
14
|
+
Environment=TS_HUB_DIR=/var/lib/tshub/hub
|
|
15
|
+
Environment="TS_HUB_NOME=VPS dos agentes"
|
|
16
|
+
Environment=TS_HUB_PARAR_DIR=/var/lib/ts-hub-parar
|
|
17
|
+
Environment=TS_HUB_TELAS_DIR=/var/lib/ts-hub-telas
|
|
18
|
+
ExecStart=/usr/bin/node /opt/ts-hub/hub/principal.js iniciar
|
|
19
|
+
Restart=on-failure
|
|
20
|
+
RestartSec=10
|
|
21
|
+
NoNewPrivileges=yes
|
|
22
|
+
PrivateTmp=yes
|
|
23
|
+
PrivateDevices=yes
|
|
24
|
+
ProtectSystem=strict
|
|
25
|
+
ProtectHome=yes
|
|
26
|
+
ProtectKernelTunables=yes
|
|
27
|
+
ProtectKernelModules=yes
|
|
28
|
+
ProtectControlGroups=yes
|
|
29
|
+
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
|
30
|
+
RestrictSUIDSGID=yes
|
|
31
|
+
LockPersonality=yes
|
|
32
|
+
CapabilityBoundingSet=
|
|
33
|
+
ReadWritePaths=/var/lib/tshub /var/lib/ts-hub-parar/pedidos
|
|
34
|
+
ReadOnlyPaths=/var/lib/ts-hub-telas /var/lib/ts-hub-parar/confirmacoes
|
|
35
|
+
# Sem caminho para a produção, nem para a própria VPS/rede privada (o relay fica na Cloudflare).
|
|
36
|
+
IPAddressDeny=82.25.68.244 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 169.254.0.0/16
|
|
37
|
+
|
|
38
|
+
[Install]
|
|
39
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Instalado na VPS em /etc/systemd/user/ts-tmux.service (root, 0644); habilitado para o
|
|
2
|
+
# tsagentes com `systemctl --user enable --now ts-tmux` (como tsagentes).
|
|
3
|
+
# tmux dos agentes (servidor -L ts). Roda dentro do user@997: o Parar tudo derruba junto.
|
|
4
|
+
[Unit]
|
|
5
|
+
Description=TS: tmux dos agentes (-L ts)
|
|
6
|
+
ConditionUser=tsagentes
|
|
7
|
+
|
|
8
|
+
[Service]
|
|
9
|
+
Type=simple
|
|
10
|
+
WorkingDirectory=%h
|
|
11
|
+
ExecStart=/usr/bin/tmux -L ts -f /usr/local/lib/ts/tmux-agentes.conf -D
|
|
12
|
+
# janela de teste do hub (entrega 1); sai quando os agentes reais tiverem as janelas deles
|
|
13
|
+
ExecStartPost=/bin/sh -c 'sleep 1; /usr/bin/tmux -L ts has-session -t piloto 2>/dev/null || /usr/bin/tmux -L ts new-session -d -s piloto -n docker -c %h /usr/local/lib/ts/tela-piloto.sh'
|
|
14
|
+
ExecStop=/usr/bin/tmux -L ts kill-server
|
|
15
|
+
Restart=on-failure
|
|
16
|
+
RestartSec=5
|
|
17
|
+
|
|
18
|
+
[Install]
|
|
19
|
+
WantedBy=default.target
|
package/lib/acp.js
CHANGED
|
@@ -146,11 +146,17 @@ function acpServer({ token, lang = 'pt', plan = 'free' }) {
|
|
|
146
146
|
const o = res && res.outcome;
|
|
147
147
|
return !!(o && o.outcome === 'selected' && o.optionId === 'allow');
|
|
148
148
|
},
|
|
149
|
-
onRemote: () => {},
|
|
150
149
|
});
|
|
151
150
|
} catch (e) {
|
|
152
151
|
if (e && (e.code === 'no_credits' || e.status === 402)) {
|
|
153
|
-
|
|
152
|
+
// Com chave própria ativa (a execução rodou nela), 402/teto é saldo do PROVEDOR; sem ela,
|
|
153
|
+
// é a IA do Terminal Smart sem créditos legados — orienta a usar a IA própria (sua
|
|
154
|
+
// chave, Ollama local ou sua assinatura). Mesmos textos do terminal.
|
|
155
|
+
const T = require('./i18n').t(lang);
|
|
156
|
+
let own = null;
|
|
157
|
+
try { const a = require('./keyring').ativo(); if (a && (a.key || (require('./providers').info(a.id) || {}).semChave)) own = a; } catch (_) {}
|
|
158
|
+
const text = own ? T.byok_no_balance(own.provedor || own.id) : T.no_credits;
|
|
159
|
+
notify('session/update', { sessionId: sid, update: { sessionUpdate: 'agent_message_chunk', content: { type: 'text', text } } });
|
|
154
160
|
return { stopReason: 'refusal' };
|
|
155
161
|
}
|
|
156
162
|
log('erro no prompt:', String((e && e.message) || e));
|