auroq-os 2.3.7 → 2.4.1
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 +22 -0
- package/bin/auroq-os.js +106 -11
- package/installer/README.md +102 -0
- package/installer/install.ps1 +515 -0
- package/installer/install.sh +553 -0
- package/lib/auth.js +14 -2
- package/lib/diagnostico.js +125 -0
- package/package.json +3 -2
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Auroq OS — instalador do Mac.
|
|
3
|
+
#
|
|
4
|
+
# curl -fsSL https://arka.education/install.sh | bash
|
|
5
|
+
#
|
|
6
|
+
# Este script roda na maquina de alguem que ainda nao tem NADA: sem Git, sem o
|
|
7
|
+
# motor do sistema, as vezes sem as ferramentas da Apple. Por isso ele e escrito
|
|
8
|
+
# pro bash 3.2 (o que vem no macOS), nao pede senha nenhuma e nao usa sudo.
|
|
9
|
+
#
|
|
10
|
+
# Ordem obrigatoria (PRD "Embarque em 2 passos" §4.2):
|
|
11
|
+
# diagnostico -> Git -> motor -> login da mentoria -> pasta do negocio -> init
|
|
12
|
+
#
|
|
13
|
+
# O `init` e quem escreve o registro do conteudo ao vivo. O instalador nao mexe
|
|
14
|
+
# nisso (ADR-7) — a maquina do aluno tem um dono so pra esse arquivo.
|
|
15
|
+
#
|
|
16
|
+
# Modo biblioteca (usado pelos testes): AUROQ_INSTALL_LIB=1 . install.sh
|
|
17
|
+
# Modo ensaio (nao toca em nada): AUROQ_INSTALL_DRY_RUN=1 bash install.sh
|
|
18
|
+
|
|
19
|
+
set -u
|
|
20
|
+
|
|
21
|
+
SUPORTE="11 93621-4486"
|
|
22
|
+
NODE_MIN=20
|
|
23
|
+
MACOS_MIN=13
|
|
24
|
+
DISCO_MIN_MB=2048
|
|
25
|
+
AUROQ_DIR="${HOME}/.auroq"
|
|
26
|
+
NODE_DIR="${AUROQ_DIR}/node"
|
|
27
|
+
|
|
28
|
+
# Cores — desligadas quando a saida nao e um terminal (log de suporte fica limpo).
|
|
29
|
+
if [ -t 1 ]; then
|
|
30
|
+
ROXO=$'\033[38;2;120;80;200m'; CIANO=$'\033[38;2;34;211;238m'; VERDE=$'\033[38;2;52;211;153m'
|
|
31
|
+
AMBAR=$'\033[38;2;251;191;36m'; VERMELHO=$'\033[38;2;248;113;113m'; FRACO=$'\033[2m'; FIM=$'\033[0m'
|
|
32
|
+
else
|
|
33
|
+
ROXO=''; CIANO=''; VERDE=''; AMBAR=''; VERMELHO=''; FRACO=''; FIM=''
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# ─── Fala com o aluno ─────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
diz() { printf ' %s\n' "$*"; }
|
|
39
|
+
titulo() { printf '\n%s %s%s\n\n' "$ROXO" "$*" "$FIM"; }
|
|
40
|
+
passo() { printf '\n %s>%s %s\n' "$CIANO" "$FIM" "$*"; }
|
|
41
|
+
ok_feito() { printf ' %s+%s %s\n' "$VERDE" "$FIM" "$*"; }
|
|
42
|
+
aviso() { printf ' %s!%s %s\n' "$AMBAR" "$FIM" "$*"; }
|
|
43
|
+
|
|
44
|
+
# Toda falha diz tres coisas: o que aconteceu, o que fazer agora e o suporte.
|
|
45
|
+
# Um instalador que trava calado e pior que o passo a passo manual.
|
|
46
|
+
auroq_erro() {
|
|
47
|
+
printf '\n %sParou aqui:%s %s\n' "$VERMELHO" "$FIM" "${1:-Algo deu errado.}"
|
|
48
|
+
printf '\n %sO que fazer agora:%s %s\n' "$CIANO" "$FIM" "${2:-Rode o mesmo comando de novo.}"
|
|
49
|
+
printf '\n %sSe continuar travado, chame o suporte: %s%s\n\n' "$FRACO" "$SUPORTE" "$FIM"
|
|
50
|
+
auroq_registrar_log "erro" "${1:-}"
|
|
51
|
+
exit 1
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# ─── Registro pro suporte (§5.7) ──────────────────────────────────────────────
|
|
55
|
+
# Uma linha por evento. Nunca entra senha, token ou e-mail — o suporte precisa
|
|
56
|
+
# saber o que aconteceu na maquina, nao quem e a pessoa.
|
|
57
|
+
|
|
58
|
+
auroq_registrar_log() {
|
|
59
|
+
[ -n "${AUROQ_INSTALL_DRY_RUN:-}" ] && return 0
|
|
60
|
+
mkdir -p "${HOME}/.auroq" 2>/dev/null || return 0
|
|
61
|
+
printf '%s\t%s\t%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "${1:-}" "${2:-}" \
|
|
62
|
+
>> "${HOME}/.auroq/install.log" 2>/dev/null || true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# ─── Decisoes puras (testadas uma a uma) ──────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
# So letras minusculas, numeros e hifen. Recusar e melhor que "consertar" sozinho:
|
|
68
|
+
# o nome da pasta e o nome do negocio dele, e ele precisa reconhecer.
|
|
69
|
+
auroq_validar_pasta() {
|
|
70
|
+
local nome="${1:-}"
|
|
71
|
+
local ok=1
|
|
72
|
+
# Enter vazio nao e erro do aluno: ele ainda nao escreveu nada. So repete a
|
|
73
|
+
# pergunta — acusar "nome errado" aqui assusta a toa.
|
|
74
|
+
if [ -z "$nome" ]; then
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
case "$nome" in
|
|
78
|
+
'' ) ok=0 ;;
|
|
79
|
+
* ) LC_ALL=C; case "$nome" in
|
|
80
|
+
*[!a-z0-9-]* ) ok=0 ;;
|
|
81
|
+
-* | *-- ) ok=0 ;;
|
|
82
|
+
* ) ok=1 ;;
|
|
83
|
+
esac ;;
|
|
84
|
+
esac
|
|
85
|
+
if [ "$ok" -eq 1 ]; then
|
|
86
|
+
return 0
|
|
87
|
+
fi
|
|
88
|
+
diz "Esse nome nao serve: use so letras minusculas, numeros e hifen."
|
|
89
|
+
diz "${FRACO}Exemplo bom: minha-empresa${FIM}"
|
|
90
|
+
return 1
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
auroq_macos_serve() {
|
|
94
|
+
local versao="${1:-0}"
|
|
95
|
+
local maior="${versao%%.*}"
|
|
96
|
+
case "$maior" in
|
|
97
|
+
''|*[!0-9]* ) return 1 ;;
|
|
98
|
+
esac
|
|
99
|
+
[ "$maior" -ge "$MACOS_MIN" ]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
auroq_node_serve() {
|
|
103
|
+
local versao="${1:-}"
|
|
104
|
+
versao="${versao#v}"
|
|
105
|
+
local maior="${versao%%.*}"
|
|
106
|
+
case "$maior" in
|
|
107
|
+
''|*[!0-9]* ) return 1 ;;
|
|
108
|
+
esac
|
|
109
|
+
[ "$maior" -ge "$NODE_MIN" ]
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
auroq_node_tarball() {
|
|
113
|
+
local versao="${1:-}"
|
|
114
|
+
local arq="${2:-}"
|
|
115
|
+
local alvo="x64"
|
|
116
|
+
[ "$arq" = "arm64" ] && alvo="arm64"
|
|
117
|
+
printf 'node-v%s-darwin-%s.tar.gz\n' "$versao" "$alvo"
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# ─── Falar com o aluno de dentro de um `curl | bash` ──────────────────────────
|
|
121
|
+
# Quando o script chega por `curl ... | bash`, a entrada padrao dele — e de TUDO
|
|
122
|
+
# que ele chamar — e o proprio texto do script. Um programa filho que pergunta
|
|
123
|
+
# "qual o seu e-mail?" leria a proxima linha do install.sh como resposta.
|
|
124
|
+
# Por isso todo comando que conversa com o aluno e ligado no terminal de verdade.
|
|
125
|
+
|
|
126
|
+
auroq_tem_terminal() {
|
|
127
|
+
[ -t 0 ] && return 0
|
|
128
|
+
[ -e /dev/tty ] && (exec 3< /dev/tty) 2>/dev/null && return 0
|
|
129
|
+
return 1
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# npx que o aluno consegue responder. Sem isso, login e as perguntas do `init`
|
|
133
|
+
# recebem pedaco do script no lugar da resposta dele.
|
|
134
|
+
auroq_npx_aluno() {
|
|
135
|
+
if [ -t 0 ]; then
|
|
136
|
+
npx -y auroq-os@latest "$@"
|
|
137
|
+
else
|
|
138
|
+
npx -y auroq-os@latest "$@" < /dev/tty
|
|
139
|
+
fi
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# nova | vazia | auroq | ocupada — decidido ANTES de escrever qualquer coisa.
|
|
143
|
+
auroq_estado_pasta() {
|
|
144
|
+
local dir="${1:-}"
|
|
145
|
+
if [ ! -d "$dir" ]; then printf 'nova\n'; return 0; fi
|
|
146
|
+
if [ -d "${dir}/.auroq-core" ]; then printf 'auroq\n'; return 0; fi
|
|
147
|
+
local resto
|
|
148
|
+
resto="$(ls -A "$dir" 2>/dev/null | grep -v -x -e '.DS_Store' -e '.localized' | head -1)"
|
|
149
|
+
if [ -z "$resto" ]; then printf 'vazia\n'; else printf 'ocupada\n'; fi
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# ─── O motor visivel pra quem abre pelo icone (§5.4) ──────────────────────────
|
|
153
|
+
# A falha mais perigosa do projeto: o app aberto pelo Dock monta o ambiente lendo
|
|
154
|
+
# os arquivos de perfil. Se o motor nao estiver la, o app sobe SEM ERRO NENHUM e
|
|
155
|
+
# o Companion parece burro. Por isso escrevemos nos dois arquivos, sempre.
|
|
156
|
+
|
|
157
|
+
auroq_aplicar_path() {
|
|
158
|
+
local arquivo="${1:-}"
|
|
159
|
+
local bin="${2:-}"
|
|
160
|
+
local tmp="${arquivo}.auroq-tmp.$$"
|
|
161
|
+
[ -f "$arquivo" ] || : > "$arquivo"
|
|
162
|
+
# tira o bloco antigo (se houver) e escreve o novo — nunca empilha
|
|
163
|
+
awk '
|
|
164
|
+
/^# >>> auroq >>>$/ { pulando=1; next }
|
|
165
|
+
/^# <<< auroq <<<$/ { pulando=0; next }
|
|
166
|
+
pulando != 1 { print }
|
|
167
|
+
' "$arquivo" > "$tmp" 2>/dev/null || cp "$arquivo" "$tmp"
|
|
168
|
+
{
|
|
169
|
+
printf '# >>> auroq >>>\n'
|
|
170
|
+
printf '# Motor do Auroq OS. Bloco gerado pelo instalador — pode apagar se desinstalar.\n'
|
|
171
|
+
printf 'export PATH="%s:$PATH"\n' "$bin"
|
|
172
|
+
printf '# <<< auroq <<<\n'
|
|
173
|
+
} >> "$tmp"
|
|
174
|
+
mv "$tmp" "$arquivo"
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# O motor precisa aparecer em DOIS lugares diferentes, por motivos diferentes.
|
|
178
|
+
#
|
|
179
|
+
# Os arquivos do zsh sao obrigatorios sempre: e por eles que o Claude Code e o
|
|
180
|
+
# Codex abertos pelo ICONE montam o ambiente. Sem isso o app sobe sem erro
|
|
181
|
+
# nenhum e o Companion "nao sabe de nada" (§5.4 do PRD).
|
|
182
|
+
#
|
|
183
|
+
# Os do shell do aluno sao pra janela que ele digita. O macOS 13+ usa zsh e os
|
|
184
|
+
# dois coincidem — mas quem trocou pra bash instalava com sucesso, nao via erro,
|
|
185
|
+
# e depois nenhum comando era reconhecido. Falha silenciosa e a pior de todas:
|
|
186
|
+
# nao tem o que pesquisar, entao a conclusao vira "esse sistema e ruim".
|
|
187
|
+
auroq_publicar_node_no_path() {
|
|
188
|
+
local bin="${1:-}"
|
|
189
|
+
local arquivo
|
|
190
|
+
|
|
191
|
+
# Sempre: o app aberto pelo icone le daqui.
|
|
192
|
+
for arquivo in "${HOME}/.zshrc" "${HOME}/.zprofile"; do
|
|
193
|
+
auroq_aplicar_path "$arquivo" "$bin"
|
|
194
|
+
done
|
|
195
|
+
|
|
196
|
+
case "${SHELL:-}" in
|
|
197
|
+
*zsh )
|
|
198
|
+
: # ja coberto acima
|
|
199
|
+
;;
|
|
200
|
+
*bash )
|
|
201
|
+
for arquivo in "${HOME}/.bash_profile" "${HOME}/.bashrc"; do
|
|
202
|
+
auroq_aplicar_path "$arquivo" "$bin"
|
|
203
|
+
done
|
|
204
|
+
;;
|
|
205
|
+
'' )
|
|
206
|
+
: # sem SHELL definido (roda dentro de outro programa): o zsh cobre
|
|
207
|
+
;;
|
|
208
|
+
* )
|
|
209
|
+
# Nao invento a sintaxe de um shell que nao sei testar. Melhor o aluno
|
|
210
|
+
# saber agora, com nome e saida, do que descobrir que "nada funciona".
|
|
211
|
+
aviso "O seu terminal (${SHELL##*/}) nao e o padrao do Mac, entao eu nao consigo"
|
|
212
|
+
diz " deixar o sistema pronto nele. Use o app Terminal (que vem no Mac) pra"
|
|
213
|
+
diz " trabalhar com o Auroq, ou chame o suporte ${SUPORTE} pra ajustar o seu."
|
|
214
|
+
auroq_registrar_log "path" "shell-nao-suportado=${SHELL##*/}"
|
|
215
|
+
;;
|
|
216
|
+
esac
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
# ─── Passo 1: diagnostico (§5.1) ──────────────────────────────────────────────
|
|
220
|
+
|
|
221
|
+
auroq_diagnostico() {
|
|
222
|
+
passo "Vendo o seu computador..."
|
|
223
|
+
|
|
224
|
+
local sistema
|
|
225
|
+
sistema="$(uname -s 2>/dev/null || echo desconhecido)"
|
|
226
|
+
if [ "$sistema" != "Darwin" ]; then
|
|
227
|
+
auroq_erro "Este instalador e do Mac, e aqui nao parece ser um Mac." "No Windows, use o outro endereco: arka.education/install.ps1"
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
local versao
|
|
231
|
+
versao="${AUROQ_INSTALL_FAKE_MACOS:-$(sw_vers -productVersion 2>/dev/null || echo 0)}"
|
|
232
|
+
if ! auroq_macos_serve "$versao"; then
|
|
233
|
+
auroq_erro "Seu Mac esta no macOS ${versao} e o sistema precisa do 13 ou mais novo." "Atualize o Mac em Ajustes > Geral > Atualizacao de Software, ou fale com o suporte antes de continuar."
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
local chip
|
|
237
|
+
chip="$(uname -m 2>/dev/null || echo desconhecido)"
|
|
238
|
+
local nome_chip="Intel"
|
|
239
|
+
[ "$chip" = "arm64" ] && nome_chip="chip Apple"
|
|
240
|
+
ok_feito "Mac com ${nome_chip}, macOS ${versao} — serve"
|
|
241
|
+
|
|
242
|
+
local livre_mb
|
|
243
|
+
livre_mb="${AUROQ_INSTALL_FAKE_DISCO_MB:-$(df -m "$HOME" 2>/dev/null | awk 'NR==2 {print $4}')}"
|
|
244
|
+
case "${livre_mb:-0}" in
|
|
245
|
+
''|*[!0-9]* ) livre_mb=999999 ;;
|
|
246
|
+
esac
|
|
247
|
+
if [ "$livre_mb" -lt "$DISCO_MIN_MB" ]; then
|
|
248
|
+
auroq_erro "Falta espaco no disco: sobram ${livre_mb} MB e sao necessarios pelo menos 2 GB." "Libere espaco (Ajustes > Geral > Armazenamento) e rode o mesmo comando de novo."
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
if [ -n "${AUROQ_INSTALL_FAKE_SEM_INTERNET:-}" ]; then
|
|
252
|
+
auroq_erro "Nao consegui falar com a internet." "Conecte na internet e rode o mesmo comando de novo. Nada foi instalado pela metade."
|
|
253
|
+
fi
|
|
254
|
+
if [ -z "${AUROQ_INSTALL_DRY_RUN:-}" ]; then
|
|
255
|
+
if ! curl -sfI --max-time 15 https://registry.npmjs.org/ >/dev/null 2>&1; then
|
|
256
|
+
auroq_erro "Nao consegui falar com a internet." "Conecte na internet e rode o mesmo comando de novo. Nada foi instalado pela metade."
|
|
257
|
+
fi
|
|
258
|
+
fi
|
|
259
|
+
auroq_registrar_log "diagnostico" "macos=${versao} chip=${chip} disco_mb=${livre_mb}"
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# ─── Passo 2: Git (§5.2) ──────────────────────────────────────────────────────
|
|
263
|
+
# No Mac o Git vem junto das ferramentas da Apple. O script abre a janela; quem
|
|
264
|
+
# clica em "Instalar" e o aluno. Isso nao da pra automatizar — e janela do sistema.
|
|
265
|
+
|
|
266
|
+
auroq_git_responde() {
|
|
267
|
+
git --version >/dev/null 2>&1 && return 0
|
|
268
|
+
[ -x /usr/bin/git ] && /usr/bin/git --version >/dev/null 2>&1 && return 0
|
|
269
|
+
return 1
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
auroq_garantir_git() {
|
|
273
|
+
passo "Verificando o Git (o programa que guarda as versoes do seu trabalho)..."
|
|
274
|
+
|
|
275
|
+
if [ -n "${AUROQ_INSTALL_DRY_RUN:-}" ]; then
|
|
276
|
+
ok_feito "Git — seria verificado aqui"
|
|
277
|
+
return 0
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
if auroq_git_responde; then
|
|
281
|
+
ok_feito "Git ja estava instalado"
|
|
282
|
+
auroq_registrar_log "git" "ja-existia"
|
|
283
|
+
return 0
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
aviso "Falta instalar. Vai abrir uma janela da Apple agora."
|
|
287
|
+
diz " Clique em \"Instalar\" e volte pra ca — pode levar de 5 a 10 minutos."
|
|
288
|
+
diz " Pode deixar baixando e ir tomar um cafe; eu espero."
|
|
289
|
+
xcode-select --install >/dev/null 2>&1 || true
|
|
290
|
+
|
|
291
|
+
local esperou=0
|
|
292
|
+
while [ "$esperou" -lt 1200 ]; do
|
|
293
|
+
if auroq_git_responde; then
|
|
294
|
+
ok_feito "Git instalado"
|
|
295
|
+
auroq_registrar_log "git" "instalado-pelas-ferramentas-da-apple"
|
|
296
|
+
return 0
|
|
297
|
+
fi
|
|
298
|
+
sleep 10
|
|
299
|
+
esperou=$((esperou + 10))
|
|
300
|
+
if [ $((esperou % 120)) -eq 0 ]; then
|
|
301
|
+
diz "${FRACO} ainda baixando... (${esperou}s)${FIM}"
|
|
302
|
+
fi
|
|
303
|
+
done
|
|
304
|
+
|
|
305
|
+
auroq_erro "A instalacao das ferramentas da Apple nao terminou." "Termine a janela da Apple e rode o mesmo comando de novo — nada do que ja foi feito se perde."
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
# ─── Passo 3: o motor (§5.3) ──────────────────────────────────────────────────
|
|
309
|
+
# Fica numa pasta do proprio aluno. Sem senha, sem sudo, sem tocar no que ele ja
|
|
310
|
+
# tinha instalado: se ja existe um motor bom, usamos o dele.
|
|
311
|
+
|
|
312
|
+
# Abre o pacote do motor direto na pasta final.
|
|
313
|
+
#
|
|
314
|
+
# A versao anterior descompactava ao lado e movia com `mv .../node-v*-darwin-* destino`.
|
|
315
|
+
# O curinga pegava DOIS caminhos — a pasta aberta e o proprio .tar.gz, que mora no
|
|
316
|
+
# mesmo lugar — e `mv` com duas origens exige que o destino ja seja uma pasta. Como
|
|
317
|
+
# o destino tinha acabado de ser renomeado pra `.antigo`, ele nao existia: todo aluno
|
|
318
|
+
# sem motor na maquina batia em "Nao consegui guardar o motor na sua pasta".
|
|
319
|
+
#
|
|
320
|
+
# Aqui nao existe curinga: `--strip-components=1` joga o conteudo direto no destino.
|
|
321
|
+
auroq_desempacotar_node() {
|
|
322
|
+
local pacote="$1" destino="$2"
|
|
323
|
+
|
|
324
|
+
rm -rf "${destino}.antigo" 2>/dev/null || true
|
|
325
|
+
if [ -d "$destino" ]; then
|
|
326
|
+
mv "$destino" "${destino}.antigo" 2>/dev/null || return 1
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
mkdir -p "$destino" 2>/dev/null || return 1
|
|
330
|
+
tar -xzf "$pacote" -C "$destino" --strip-components=1 2>/dev/null || return 1
|
|
331
|
+
|
|
332
|
+
# So e sucesso se o motor de fato ficou de pe.
|
|
333
|
+
[ -x "${destino}/bin/node" ] || return 1
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
auroq_garantir_node() {
|
|
337
|
+
passo "Verificando o motor do sistema..."
|
|
338
|
+
|
|
339
|
+
if [ -n "${AUROQ_INSTALL_DRY_RUN:-}" ]; then
|
|
340
|
+
ok_feito "Motor — seria instalado em uma pasta sua, sem senha"
|
|
341
|
+
return 0
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
local atual
|
|
345
|
+
atual="$(node --version 2>/dev/null || true)"
|
|
346
|
+
if auroq_node_serve "$atual"; then
|
|
347
|
+
ok_feito "O motor ja estava instalado (${atual})"
|
|
348
|
+
auroq_registrar_log "motor" "ja-existia versao=${atual} origem=$(command -v node 2>/dev/null || echo desconhecida)"
|
|
349
|
+
return 0
|
|
350
|
+
fi
|
|
351
|
+
|
|
352
|
+
if [ -n "$atual" ]; then
|
|
353
|
+
aviso "Voce ja tinha um motor antigo (${atual}); vou instalar um novo do lado, sem mexer no seu."
|
|
354
|
+
fi
|
|
355
|
+
diz " (e um programa que fica numa pasta sua, nao pede senha e nao mexe em nada do seu Mac)"
|
|
356
|
+
|
|
357
|
+
local chip alvo indice versao tarball url tmpdir
|
|
358
|
+
chip="$(uname -m)"
|
|
359
|
+
alvo="$(auroq_node_tarball "0" "$chip")"
|
|
360
|
+
|
|
361
|
+
indice="$(curl -fsSL --max-time 30 https://nodejs.org/dist/index.json 2>/dev/null || true)"
|
|
362
|
+
[ -z "$indice" ] && auroq_erro "Nao consegui baixar o motor do sistema." "Confira a internet (ou o antivirus, se houver) e rode o mesmo comando de novo."
|
|
363
|
+
|
|
364
|
+
versao="$(printf '%s' "$indice" | tr ',' '\n' | grep -o '"version":"v24\.[0-9.]*"' | head -1 | sed 's/.*"v//; s/"//')"
|
|
365
|
+
[ -z "$versao" ] && versao="$(printf '%s' "$indice" | tr ',' '\n' | grep -o '"version":"v2[0-9]\.[0-9.]*"' | head -1 | sed 's/.*"v//; s/"//')"
|
|
366
|
+
[ -z "$versao" ] && auroq_erro "Nao consegui descobrir qual motor baixar." "Rode o mesmo comando de novo em alguns minutos. Se insistir, chame o suporte."
|
|
367
|
+
|
|
368
|
+
tarball="$(auroq_node_tarball "$versao" "$chip")"
|
|
369
|
+
url="https://nodejs.org/dist/v${versao}/${tarball}"
|
|
370
|
+
tmpdir="$(mktemp -d)"
|
|
371
|
+
|
|
372
|
+
curl -fsSL --max-time 600 -o "${tmpdir}/${tarball}" "$url" 2>/dev/null \
|
|
373
|
+
|| auroq_erro "O download do motor nao completou." "Pode ser antivirus ou rede instavel. Rode o mesmo comando de novo; se repetir, chame o suporte."
|
|
374
|
+
|
|
375
|
+
# Sem conferir a soma oficial, nao instala. Binario nao verificado nao entra.
|
|
376
|
+
local somas esperado obtido
|
|
377
|
+
somas="$(curl -fsSL --max-time 60 "https://nodejs.org/dist/v${versao}/SHASUMS256.txt" 2>/dev/null || true)"
|
|
378
|
+
esperado="$(printf '%s' "$somas" | grep " ${tarball}\$" | awk '{print $1}')"
|
|
379
|
+
obtido="$(shasum -a 256 "${tmpdir}/${tarball}" 2>/dev/null | awk '{print $1}')"
|
|
380
|
+
if [ -z "$esperado" ] || [ "$esperado" != "$obtido" ]; then
|
|
381
|
+
rm -rf "$tmpdir"
|
|
382
|
+
auroq_erro "O arquivo do motor baixou com defeito." "Rode o mesmo comando de novo — o arquivo estragado ja foi apagado."
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
auroq_desempacotar_node "${tmpdir}/${tarball}" "$NODE_DIR" \
|
|
386
|
+
|| { rm -rf "$tmpdir"; auroq_erro "Nao consegui guardar o motor na sua pasta." "Rode o mesmo comando de novo."; }
|
|
387
|
+
rm -rf "$tmpdir" "${NODE_DIR}.antigo"
|
|
388
|
+
|
|
389
|
+
auroq_publicar_node_no_path "${NODE_DIR}/bin"
|
|
390
|
+
export PATH="${NODE_DIR}/bin:${PATH}"
|
|
391
|
+
# npm global dentro da pasta do aluno: instalar ferramenta depois nao pede senha
|
|
392
|
+
export npm_config_prefix="${NODE_DIR}"
|
|
393
|
+
|
|
394
|
+
ok_feito "Motor instalado (${versao})"
|
|
395
|
+
auroq_registrar_log "motor" "instalado versao=${versao} chip=${chip}"
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
# ─── Passo 4: login da mentoria (§5.5) ────────────────────────────────────────
|
|
399
|
+
# Mesma checagem que o resto do sistema usa. So contrato ativo instala.
|
|
400
|
+
|
|
401
|
+
auroq_login_mentoria() {
|
|
402
|
+
passo "Agora entre com o seu acesso da Mentoria Arcane."
|
|
403
|
+
|
|
404
|
+
if [ -n "${AUROQ_INSTALL_DRY_RUN:-}" ]; then
|
|
405
|
+
ok_feito "Login — seria pedido aqui (e-mail e senha da plataforma)"
|
|
406
|
+
return 0
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
if ! auroq_tem_terminal; then
|
|
410
|
+
auroq_erro "Preciso do seu e-mail e senha da Mentoria Arcane, e esta janela nao aceita resposta." "Abra o Terminal (ou o terminal de dentro do Claude Code) e cole o mesmo comando la."
|
|
411
|
+
fi
|
|
412
|
+
|
|
413
|
+
# `check-access` e a mesma regua do resto do sistema: exit 0 so com contrato
|
|
414
|
+
# ativo conferido agora. Sem sessao salva, ele mesmo pede e-mail e senha; com
|
|
415
|
+
# sessao boa, passa direto e nao pergunta de novo.
|
|
416
|
+
#
|
|
417
|
+
# NAO usar `whoami` aqui: ele imprime "Nao autenticado" e mesmo assim sai com
|
|
418
|
+
# sucesso. Usado como pergunta de sim/nao, ele dizia "voce ja estava logado"
|
|
419
|
+
# pra quem nunca logou, pulava o portao e deixava a conta sem acesso chegar ate
|
|
420
|
+
# a criacao da pasta.
|
|
421
|
+
if ! auroq_npx_aluno check-access; then
|
|
422
|
+
auroq_registrar_log "login" "recusado"
|
|
423
|
+
printf '\n %sSem acesso ativo, a instalacao para aqui — e nada foi criado no seu computador.%s\n' "$FRACO" "$FIM"
|
|
424
|
+
printf ' %sO que fazer agora: fale com o suporte %s%s\n\n' "$FRACO" "$SUPORTE" "$FIM"
|
|
425
|
+
exit 1
|
|
426
|
+
fi
|
|
427
|
+
auroq_registrar_log "login" "ok"
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
# ─── Passo 5: pasta do negocio (§5.6) ─────────────────────────────────────────
|
|
431
|
+
|
|
432
|
+
auroq_escolher_pasta() {
|
|
433
|
+
passo "Qual o nome da pasta do seu negocio?"
|
|
434
|
+
diz "${FRACO}(so letras minusculas e hifen — ex: minha-empresa)${FIM}"
|
|
435
|
+
|
|
436
|
+
local nome="${AUROQ_INSTALL_PASTA:-}"
|
|
437
|
+
local tentativas=0
|
|
438
|
+
|
|
439
|
+
while : ; do
|
|
440
|
+
if [ -z "$nome" ]; then
|
|
441
|
+
# Rodando por `curl ... | bash`, a entrada padrao e o proprio script:
|
|
442
|
+
# a pergunta tem que ir pro terminal de verdade.
|
|
443
|
+
if [ ! -t 0 ]; then
|
|
444
|
+
if [ -e /dev/tty ] && (exec 3< /dev/tty) 2>/dev/null; then
|
|
445
|
+
printf ' Nome: '
|
|
446
|
+
read -r nome < /dev/tty 2>/dev/null || nome=''
|
|
447
|
+
else
|
|
448
|
+
auroq_erro "Nao consegui te perguntar o nome da pasta: esta janela nao aceita resposta." "Abra o Terminal (ou o terminal de dentro do Claude Code) e cole o mesmo comando la."
|
|
449
|
+
fi
|
|
450
|
+
else
|
|
451
|
+
printf ' Nome: '
|
|
452
|
+
read -r nome || nome=''
|
|
453
|
+
fi
|
|
454
|
+
fi
|
|
455
|
+
|
|
456
|
+
if auroq_validar_pasta "$nome"; then
|
|
457
|
+
PASTA_ALVO="${HOME}/${nome}"
|
|
458
|
+
case "$(auroq_estado_pasta "$PASTA_ALVO")" in
|
|
459
|
+
auroq )
|
|
460
|
+
printf '\n'
|
|
461
|
+
aviso "Ja existe um Auroq em ${PASTA_ALVO} — nao vou mexer nele."
|
|
462
|
+
diz "Pra conferir se esta tudo certo la, abra essa pasta e rode:"
|
|
463
|
+
diz "${CIANO} auroq-os doctor${FIM}"
|
|
464
|
+
auroq_registrar_log "pasta" "ja-tinha-auroq"
|
|
465
|
+
exit 0
|
|
466
|
+
;;
|
|
467
|
+
ocupada )
|
|
468
|
+
aviso "A pasta ${nome} ja existe e tem coisa sua dentro. Escolha outro nome."
|
|
469
|
+
nome=''
|
|
470
|
+
;;
|
|
471
|
+
* )
|
|
472
|
+
break
|
|
473
|
+
;;
|
|
474
|
+
esac
|
|
475
|
+
else
|
|
476
|
+
nome=''
|
|
477
|
+
fi
|
|
478
|
+
|
|
479
|
+
tentativas=$((tentativas + 1))
|
|
480
|
+
if [ "$tentativas" -ge 5 ]; then
|
|
481
|
+
auroq_erro "Nao consegui um nome valido pra pasta." "Rode o mesmo comando de novo e escreva algo como: minha-empresa"
|
|
482
|
+
fi
|
|
483
|
+
done
|
|
484
|
+
|
|
485
|
+
if [ -n "${AUROQ_INSTALL_DRY_RUN:-}" ]; then
|
|
486
|
+
ok_feito "Pasta ${PASTA_ALVO} — seria criada aqui"
|
|
487
|
+
return 0
|
|
488
|
+
fi
|
|
489
|
+
|
|
490
|
+
mkdir -p "$PASTA_ALVO" 2>/dev/null \
|
|
491
|
+
|| auroq_erro "Nao consegui criar a pasta ${PASTA_ALVO}." "Confira se voce tem permissao de escrita na sua pasta pessoal e rode de novo."
|
|
492
|
+
auroq_registrar_log "pasta" "criada"
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
# ─── Passo 6: montar o Auroq ──────────────────────────────────────────────────
|
|
496
|
+
|
|
497
|
+
auroq_rodar_init() {
|
|
498
|
+
passo "Montando o Auroq dentro de ${PASTA_ALVO}..."
|
|
499
|
+
|
|
500
|
+
if [ -n "${AUROQ_INSTALL_DRY_RUN:-}" ]; then
|
|
501
|
+
ok_feito "Sistema — seria montado aqui"
|
|
502
|
+
return 0
|
|
503
|
+
fi
|
|
504
|
+
|
|
505
|
+
cd "$PASTA_ALVO" || auroq_erro "Nao consegui entrar na pasta ${PASTA_ALVO}." "Rode o mesmo comando de novo."
|
|
506
|
+
# ligado no terminal de verdade: o `init` ainda pergunta se ele ja usa o Auroq
|
|
507
|
+
# em outra maquina (3a pergunta do §4.4), e essa resposta e do aluno.
|
|
508
|
+
if ! auroq_npx_aluno init; then
|
|
509
|
+
auroq_registrar_log "init" "falhou"
|
|
510
|
+
auroq_erro "A montagem do sistema parou no meio." "Rode o mesmo comando de novo. Se repetir, mande pro suporte o arquivo ~/.auroq/install.log"
|
|
511
|
+
fi
|
|
512
|
+
auroq_registrar_log "init" "ok"
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
# ─── Passo 7: fecho ───────────────────────────────────────────────────────────
|
|
516
|
+
|
|
517
|
+
auroq_fecho() {
|
|
518
|
+
printf '\n %s%s%s\n\n' "$ROXO" "─────────────────────────────────────────────" "$FIM"
|
|
519
|
+
diz "Pronto. O Auroq esta em ${PASTA_ALVO}"
|
|
520
|
+
printf '\n'
|
|
521
|
+
diz "Falta um detalhe importante:"
|
|
522
|
+
printf '\n'
|
|
523
|
+
diz " 1. FECHE o Claude Code (ou o Codex) por completo e abra de novo"
|
|
524
|
+
diz " ${FRACO}— sem isso ele nao enxerga o que acabou de ser instalado${FIM}"
|
|
525
|
+
diz " 2. Abra a pasta ${PASTA_ALVO##*/}"
|
|
526
|
+
diz " 3. Chame o Ops: ${CIANO}/AuroqOS:agents:ops${FIM} ${FRACO}(no Codex: \$ops)${FIM}"
|
|
527
|
+
diz " 4. Digite: ${CIANO}*bootstrap${FIM}"
|
|
528
|
+
printf '\n'
|
|
529
|
+
diz "O Ops instala o resto e te guia daqui pra frente."
|
|
530
|
+
printf '\n'
|
|
531
|
+
auroq_registrar_log "fim" "ok pasta=${PASTA_ALVO##*/}"
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
# ─── Fluxo ────────────────────────────────────────────────────────────────────
|
|
535
|
+
|
|
536
|
+
auroq_main() {
|
|
537
|
+
titulo "Auroq OS — instalacao"
|
|
538
|
+
auroq_diagnostico
|
|
539
|
+
auroq_garantir_git
|
|
540
|
+
auroq_garantir_node
|
|
541
|
+
auroq_login_mentoria
|
|
542
|
+
auroq_escolher_pasta
|
|
543
|
+
auroq_rodar_init
|
|
544
|
+
auroq_fecho
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
# Carregado pelos testes: so define as funcoes e sai.
|
|
548
|
+
if [ -n "${AUROQ_INSTALL_LIB:-}" ]; then
|
|
549
|
+
return 0 2>/dev/null || true
|
|
550
|
+
else
|
|
551
|
+
PASTA_ALVO=""
|
|
552
|
+
auroq_main
|
|
553
|
+
fi
|
package/lib/auth.js
CHANGED
|
@@ -5,7 +5,7 @@ const { createAuthClient } = require('./supabase');
|
|
|
5
5
|
const credentials = require('./credentials');
|
|
6
6
|
|
|
7
7
|
const PLATFORM_URL = 'https://arcane.arka.education';
|
|
8
|
-
const SUPPORT_CONTACT = '11
|
|
8
|
+
const SUPPORT_CONTACT = '11 93621-4486';
|
|
9
9
|
const MAX_LOGIN_ATTEMPTS = 3;
|
|
10
10
|
|
|
11
11
|
const PURPLE = '\x1b[38;2;120;80;200m';
|
|
@@ -296,13 +296,24 @@ async function logout() {
|
|
|
296
296
|
ok('Sessao encerrada. Credenciais locais removidas.');
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Mostra quem esta autenticado NESTA maquina, pelo que esta salvo no disco.
|
|
301
|
+
*
|
|
302
|
+
* Retorna `true` so quando ha sessao salva com o ultimo status conhecido
|
|
303
|
+
* 'ativo' — e o CLI transforma isso em codigo de saida. Antes ele saia com
|
|
304
|
+
* sucesso ate sem credencial nenhuma, e quem usasse `whoami` como pergunta de
|
|
305
|
+
* sim/nao (era o caso do instalador) concluia que o aluno ja estava logado.
|
|
306
|
+
*
|
|
307
|
+
* Continua sendo uma leitura LOCAL: pra decidir acesso de verdade, o portao e
|
|
308
|
+
* `check-access` / `requireActiveAccess()`, que confere online.
|
|
309
|
+
*/
|
|
299
310
|
function whoami() {
|
|
300
311
|
const cred = credentials.load();
|
|
301
312
|
if (!cred) {
|
|
302
313
|
log(`${DIM}Nao autenticado.${RESET}`);
|
|
303
314
|
log('');
|
|
304
315
|
log(`${DIM}Para entrar: ${CYAN}auroq-os login${RESET}`);
|
|
305
|
-
return;
|
|
316
|
+
return false;
|
|
306
317
|
}
|
|
307
318
|
const now = Math.floor(Date.now() / 1000);
|
|
308
319
|
const validatedAgo = cred.last_validated_at ? Math.floor((now - cred.last_validated_at) / 60) : null;
|
|
@@ -320,6 +331,7 @@ function whoami() {
|
|
|
320
331
|
}
|
|
321
332
|
log(`${DIM}Access token:${RESET} ${expired ? `${GOLD}expirado${RESET}` : `${GREEN}valido${RESET}`}`);
|
|
322
333
|
log('');
|
|
334
|
+
return cred.last_status === 'ativo';
|
|
323
335
|
}
|
|
324
336
|
|
|
325
337
|
/**
|