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.
@@ -0,0 +1,515 @@
1
+ # Auroq OS - instalador do Windows.
2
+ #
3
+ # irm https://arka.education/install.ps1 | iex
4
+ #
5
+ # Roda no PowerShell 5.1 (o que vem no Windows 10) sem privilegio elevado. A politica
6
+ # de execucao nao entra aqui: ela so afeta arquivo .ps1 salvo em disco, e este
7
+ # script roda em memoria. Exigir elevacao era resto da era npm.
8
+ #
9
+ # Ordem obrigatoria (PRD "Embarque em 2 passos" sec. 4.2):
10
+ # diagnostico -> Git -> motor -> login da mentoria -> pasta do negocio -> init
11
+ #
12
+ # O `init` e quem escreve o registro do conteudo ao vivo (ADR-7).
13
+ #
14
+ # Modo biblioteca (usado pelos testes): $env:AUROQ_INSTALL_LIB='1'; . install.ps1
15
+ # Modo ensaio (nao toca em nada): $env:AUROQ_INSTALL_DRY_RUN='1'
16
+
17
+ # TLS 1.2 antes de qualquer download - sem isto o Windows 10 antigo estoura em SSL.
18
+ # ATENCAO: este arquivo e ASCII PURO de proposito. Nao coloque acento, travessao
19
+ # nem simbolo aqui.
20
+ #
21
+ # O Windows PowerShell 5.1 (o que vem no Windows, e o que o aluno usa) le script
22
+ # sem BOM na codepage do sistema - Windows-1252 no Brasil. Cada caractere UTF-8
23
+ # de dois ou tres bytes vira lixo, e o parser morre com "Missing closing '}'"
24
+ # antes de executar UMA linha. Provado numa maquina Windows real: lido como
25
+ # Windows-1252 => 4 erros de sintaxe; lido como UTF-8 => nenhum.
26
+ #
27
+ # ASCII puro resolve os dois caminhos de uma vez: rodar o arquivo do disco e
28
+ # baixar por `irm ... | iex`, onde a decodificacao depende do que o servidor
29
+ # declara.
30
+
31
+ try {
32
+ [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
33
+ } catch {
34
+ # PowerShell 7 ja negocia TLS moderno sozinho
35
+ }
36
+
37
+ $AuroqSuporte = '11 93621-4486'
38
+ $AuroqNodeMin = 20
39
+ $AuroqBuildMin = 17763 # Windows 10 1809
40
+ $AuroqDiscoMinMb = 2048
41
+
42
+ function Get-AuroqHome {
43
+ if ($env:AUROQ_INSTALL_HOME) { return $env:AUROQ_INSTALL_HOME }
44
+ if ($env:USERPROFILE) { return $env:USERPROFILE }
45
+ return $HOME
46
+ }
47
+
48
+ function Get-AuroqNodeDir {
49
+ $base = $env:LOCALAPPDATA
50
+ if (-not $base) { $base = Join-Path (Get-AuroqHome) 'AppData\Local' }
51
+ return (Join-Path $base 'Auroq\node')
52
+ }
53
+
54
+ # --- Fala com o aluno ---------------------------------------------------------
55
+
56
+ function Write-AuroqTitulo { param([string]$Texto) Write-Host ''; Write-Host " $Texto" -ForegroundColor Magenta; Write-Host '' }
57
+ function Write-AuroqPasso { param([string]$Texto) Write-Host ''; Write-Host " > $Texto" -ForegroundColor Cyan }
58
+ function Write-AuroqDiz { param([string]$Texto) Write-Host " $Texto" }
59
+ function Write-AuroqOk { param([string]$Texto) Write-Host " + $Texto" -ForegroundColor Green }
60
+ function Write-AuroqAviso { param([string]$Texto) Write-Host " ! $Texto" -ForegroundColor Yellow }
61
+
62
+ # Toda falha diz tres coisas: o que aconteceu, o que fazer agora e o suporte.
63
+ function Write-AuroqErro {
64
+ param([string]$Aconteceu = 'Algo deu errado.', [string]$OqueFazer = 'Rode o mesmo comando de novo.')
65
+ Write-Host ''
66
+ Write-Host " Parou aqui: $Aconteceu" -ForegroundColor Red
67
+ Write-Host ''
68
+ Write-Host " O que fazer agora: $OqueFazer" -ForegroundColor Cyan
69
+ Write-Host ''
70
+ Write-Host " Se continuar travado, chame o suporte: $AuroqSuporte" -ForegroundColor DarkGray
71
+ Write-Host ''
72
+ Write-AuroqLog 'erro' $Aconteceu
73
+ exit 1
74
+ }
75
+
76
+ # --- Registro pro suporte (sec. 5.7) ----------------------------------------------
77
+ # Uma linha por evento. Nunca entra senha, token ou e-mail.
78
+
79
+ function Write-AuroqLog {
80
+ param([string]$Evento = '', [string]$Detalhe = '')
81
+ if ($env:AUROQ_INSTALL_DRY_RUN) { return }
82
+ try {
83
+ $dir = Join-Path (Get-AuroqHome) '.auroq'
84
+ if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
85
+ $quando = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
86
+ Add-Content -Path (Join-Path $dir 'install.log') -Value "$quando`t$Evento`t$Detalhe" -Encoding UTF8
87
+ } catch {
88
+ # registro e conveniencia pro suporte; nunca derruba a instalacao
89
+ }
90
+ }
91
+
92
+ # --- Decisoes puras (testadas uma a uma) --------------------------------------
93
+
94
+ # So letras minusculas, numeros e hifen. -cmatch porque o -match do PowerShell
95
+ # ignora maiuscula por padrao e deixaria passar "MinhaEmpresa".
96
+ function Test-AuroqPasta {
97
+ param([string]$Nome = '')
98
+ if ([string]::IsNullOrWhiteSpace($Nome)) { return $false }
99
+ if ($Nome -cmatch '^[a-z0-9][a-z0-9-]*$') { return $true }
100
+ return $false
101
+ }
102
+
103
+ function Test-AuroqNode {
104
+ param([string]$Versao = '')
105
+ if ([string]::IsNullOrWhiteSpace($Versao)) { return $false }
106
+ $limpa = $Versao.TrimStart('v')
107
+ $maior = ($limpa -split '\.')[0]
108
+ $numero = 0
109
+ if (-not [int]::TryParse($maior, [ref]$numero)) { return $false }
110
+ return ($numero -ge $AuroqNodeMin)
111
+ }
112
+
113
+ function Get-AuroqNodeZip {
114
+ param([string]$Versao = '', [string]$Arquitetura = 'AMD64')
115
+ $alvo = 'x64'
116
+ if ($Arquitetura -eq 'ARM64') { $alvo = 'arm64' }
117
+ return "node-v$Versao-win-$alvo.zip"
118
+ }
119
+
120
+ # nova | vazia | auroq | ocupada - decidido ANTES de escrever qualquer coisa.
121
+ function Get-AuroqEstadoPasta {
122
+ param([string]$Caminho = '')
123
+ if (-not (Test-Path $Caminho)) { return 'nova' }
124
+ if (Test-Path (Join-Path $Caminho '.auroq-core')) { return 'auroq' }
125
+ $itens = @(Get-ChildItem -LiteralPath $Caminho -Force -ErrorAction SilentlyContinue |
126
+ Where-Object { $_.Name -ne 'desktop.ini' -and $_.Name -ne 'Thumbs.db' -and $_.Name -ne '.DS_Store' })
127
+ if ($itens.Count -eq 0) { return 'vazia' }
128
+ return 'ocupada'
129
+ }
130
+
131
+ # --- O motor visivel pra quem abre pelo icone (sec. 5.4) --------------------------
132
+ # No Windows o programa aberto pelo Menu Iniciar herda o ambiente do USUARIO.
133
+ # Gravar no escopo da maquina inteira exigiria elevacao - o PRD proibe pedir isso.
134
+
135
+ function Set-AuroqPath {
136
+ param([string]$Bin = '')
137
+ $atual = [Environment]::GetEnvironmentVariable('Path', 'User')
138
+ if (-not $atual) { $atual = '' }
139
+ $partes = @($atual -split ';' | Where-Object { $_ -and ($_ -ne $Bin) })
140
+ $novo = (@($Bin) + $partes) -join ';'
141
+ [Environment]::SetEnvironmentVariable('Path', $novo, 'User')
142
+ $env:Path = "$Bin;$env:Path"
143
+ }
144
+
145
+ # --- Passo 1: diagnostico (sec. 5.1) ----------------------------------------------
146
+
147
+ function Test-AuroqMaquina {
148
+ Write-AuroqPasso 'Vendo o seu computador...'
149
+
150
+ if (-not [Environment]::Is64BitProcess) {
151
+ Write-AuroqErro 'Voce abriu a versao de 32 bits do PowerShell.' 'Feche esta janela. No menu Iniciar procure por "Windows PowerShell" (sem x86), abra e cole o comando de novo.'
152
+ }
153
+
154
+ $build = 0
155
+ if ($env:AUROQ_INSTALL_FAKE_BUILD) {
156
+ $build = [int]$env:AUROQ_INSTALL_FAKE_BUILD
157
+ } else {
158
+ try { $build = [System.Environment]::OSVersion.Version.Build } catch { $build = $AuroqBuildMin }
159
+ }
160
+ if ($build -lt $AuroqBuildMin) {
161
+ Write-AuroqErro "Seu Windows esta numa versao antiga (compilacao $build) e o sistema precisa da 1809 ou mais nova." 'Rode o Windows Update ate o fim e tente de novo, ou fale com o suporte antes de continuar.'
162
+ }
163
+
164
+ $chip = $env:PROCESSOR_ARCHITECTURE
165
+ if (-not $chip) { $chip = 'AMD64' }
166
+ Write-AuroqOk "Windows 64 bits, compilacao $build - serve"
167
+
168
+ $livreMb = 999999
169
+ if ($env:AUROQ_INSTALL_FAKE_DISCO_MB) {
170
+ $livreMb = [int]$env:AUROQ_INSTALL_FAKE_DISCO_MB
171
+ } else {
172
+ try {
173
+ $unidade = (Get-AuroqHome).Substring(0, 1)
174
+ $drive = Get-PSDrive -Name $unidade -ErrorAction SilentlyContinue
175
+ if ($drive -and $drive.Free) { $livreMb = [int]($drive.Free / 1MB) }
176
+ } catch {
177
+ $livreMb = 999999
178
+ }
179
+ }
180
+ if ($livreMb -lt $AuroqDiscoMinMb) {
181
+ Write-AuroqErro "Falta espaco no disco: sobram $livreMb MB e sao necessarios pelo menos 2 GB." 'Libere espaco (Configuracoes > Sistema > Armazenamento) e rode o mesmo comando de novo.'
182
+ }
183
+
184
+ if ($env:AUROQ_INSTALL_FAKE_SEM_INTERNET) {
185
+ Write-AuroqErro 'Nao consegui falar com a internet.' 'Conecte na internet e rode o mesmo comando de novo. Nada foi instalado pela metade.'
186
+ }
187
+ if (-not $env:AUROQ_INSTALL_DRY_RUN) {
188
+ try {
189
+ Invoke-WebRequest -Uri 'https://registry.npmjs.org/' -Method Head -TimeoutSec 15 -UseBasicParsing | Out-Null
190
+ } catch {
191
+ Write-AuroqErro 'Nao consegui falar com a internet.' 'Conecte na internet e rode o mesmo comando de novo. Nada foi instalado pela metade.'
192
+ }
193
+ }
194
+ Write-AuroqLog 'diagnostico' "build=$build chip=$chip disco_mb=$livreMb"
195
+ }
196
+
197
+ # --- Passo 2: Git (sec. 5.2) ------------------------------------------------------
198
+
199
+ function Test-AuroqGitResponde {
200
+ try {
201
+ $null = & git --version 2>$null
202
+ if ($LASTEXITCODE -eq 0) { return $true }
203
+ } catch {
204
+ # segue pro caminho padrao
205
+ }
206
+ # Dois lugares, porque sao duas instalacoes possiveis: com administrador o Git
207
+ # vai pra Program Files; sem administrador ele vai pra pasta do usuario. Olhar
208
+ # so o primeiro fazia o script jurar que o Git nao existe e ficar esperando sem fim.
209
+ $candidatos = @(
210
+ (Join-Path $env:ProgramFiles 'Git\cmd\git.exe'),
211
+ (Join-Path ${env:ProgramFiles(x86)} 'Git\cmd\git.exe'),
212
+ (Join-Path $env:LOCALAPPDATA 'Programs\Git\cmd\git.exe')
213
+ )
214
+ foreach ($padrao in $candidatos) {
215
+ if ($padrao -and (Test-Path $padrao)) {
216
+ $env:Path = "$(Split-Path $padrao);$env:Path"
217
+ return $true
218
+ }
219
+ }
220
+ return $false
221
+ }
222
+
223
+ function Install-AuroqGit {
224
+ Write-AuroqPasso 'Verificando o Git (o programa que guarda as versoes do seu trabalho)...'
225
+
226
+ if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk 'Git - seria verificado aqui'; return }
227
+
228
+ if (Test-AuroqGitResponde) {
229
+ Write-AuroqOk 'Git ja estava instalado'
230
+ Write-AuroqLog 'git' 'ja-existia'
231
+ return
232
+ }
233
+
234
+ $temWinget = $false
235
+ try {
236
+ $null = & winget --version 2>$null
237
+ if ($LASTEXITCODE -eq 0) { $temWinget = $true }
238
+ } catch {
239
+ $temWinget = $false
240
+ }
241
+
242
+ if ($temWinget) {
243
+ Write-AuroqAviso 'Falta instalar o Git. Vai aparecer uma janela pedindo permissao.'
244
+ Write-AuroqDiz ' Se ela perguntar so "Sim ou Nao", clique em Sim.'
245
+ Write-AuroqDiz ' Se ela pedir SENHA DE ADMINISTRADOR e voce nao tiver, pode fechar:'
246
+ Write-AuroqDiz ' eu instalo de outro jeito, que nao precisa de administrador.'
247
+ & winget install --id Git.Git -e --source winget --accept-package-agreements --accept-source-agreements | Out-Null
248
+ Start-Sleep -Seconds 3
249
+ if (Test-AuroqGitResponde) {
250
+ Write-AuroqOk 'Git instalado'
251
+ Write-AuroqLog 'git' 'instalado-winget'
252
+ return
253
+ }
254
+ # Nao morre aqui. Quem nao e administrador NUNCA vai conseguir passar dessa
255
+ # janela, e mandar "rode de novo e clique em Sim" tranca essa pessoa num
256
+ # loop. O caminho de baixo instala sem administrador nenhum.
257
+ Write-AuroqAviso 'A janela de permissao nao passou. Vou pelo caminho que nao precisa de administrador.'
258
+ Write-AuroqLog 'git' 'winget-nao-passou'
259
+ }
260
+
261
+ # Duas situacoes caem aqui: Windows 10 antigo sem winget, e aluno sem direito
262
+ # de administrador. O instalador oficial do Git resolve as duas: ele declara
263
+ # `PrivilegesRequired=none` e sabe instalar so pro usuario, em %LOCALAPPDATA%.
264
+ Write-AuroqAviso 'Vou abrir a pagina oficial do Git no seu navegador.'
265
+ Write-AuroqDiz ' 1. Baixe o instalador que a pagina oferecer'
266
+ Write-AuroqDiz ' 2. De dois cliques no arquivo baixado'
267
+ Write-AuroqDiz ' 3. Se ele perguntar para quem instalar, escolha a opcao de instalar'
268
+ Write-AuroqDiz ' SO PRA VOCE - ela nao pede senha de administrador'
269
+ Write-AuroqDiz ' 4. Clique em "Next" em todas as telas e depois em "Install"'
270
+ Write-AuroqDiz ' 5. No fim, clique em "Finish" e volte pra ca - eu espero'
271
+ Start-Process 'https://git-scm.com/downloads/win'
272
+
273
+ # 20 minutos de espera pelo aluno. O teto e regulavel so pra maquina limpa do
274
+ # CI nao gastar 20 minutos de runner provando uma mensagem.
275
+ $teto = 1200
276
+ if ($env:AUROQ_INSTALL_ESPERA_GIT) { $teto = [int]$env:AUROQ_INSTALL_ESPERA_GIT }
277
+ $esperou = 0
278
+ while ($esperou -lt $teto) {
279
+ if (Test-AuroqGitResponde) {
280
+ Write-AuroqOk 'Git instalado'
281
+ Write-AuroqLog 'git' 'instalado-manual'
282
+ return
283
+ }
284
+ Start-Sleep -Seconds 10
285
+ $esperou = $esperou + 10
286
+ if (($esperou % 120) -eq 0) { Write-AuroqDiz " ainda esperando... ($esperou s)" }
287
+ }
288
+ Write-AuroqErro 'A instalacao do Git nao terminou.' 'Termine a instalacao e rode o mesmo comando de novo - nada do que ja foi feito se perde.'
289
+ }
290
+
291
+ # --- Passo 3: o motor (sec. 5.3) --------------------------------------------------
292
+
293
+ function Install-AuroqNode {
294
+ Write-AuroqPasso 'Verificando o motor do sistema...'
295
+
296
+ if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk 'Motor - seria instalado em uma pasta sua, sem senha'; return }
297
+
298
+ $atual = ''
299
+ try {
300
+ $atual = (& node --version 2>$null)
301
+ } catch {
302
+ $atual = ''
303
+ }
304
+ if (Test-AuroqNode $atual) {
305
+ Write-AuroqOk "O motor ja estava instalado ($atual)"
306
+ Write-AuroqLog 'motor' "ja-existia versao=$atual"
307
+ return
308
+ }
309
+ if ($atual) {
310
+ Write-AuroqAviso "Voce ja tinha um motor antigo ($atual); vou instalar um novo do lado, sem mexer no seu."
311
+ }
312
+ Write-AuroqDiz ' (e um programa que fica numa pasta sua, nao pede senha e nao mexe em nada do seu Windows)'
313
+
314
+ $chip = $env:PROCESSOR_ARCHITECTURE
315
+ if (-not $chip) { $chip = 'AMD64' }
316
+
317
+ try {
318
+ $indice = Invoke-RestMethod -Uri 'https://nodejs.org/dist/index.json' -TimeoutSec 30 -UseBasicParsing
319
+ } catch {
320
+ Write-AuroqErro 'Nao consegui baixar o motor do sistema.' 'Confira a internet (ou o antivirus, se houver) e rode o mesmo comando de novo.'
321
+ }
322
+ $escolhido = $indice | Where-Object { $_.version -like 'v24.*' } | Select-Object -First 1
323
+ if (-not $escolhido) { $escolhido = $indice | Where-Object { $_.lts } | Select-Object -First 1 }
324
+ if (-not $escolhido) {
325
+ Write-AuroqErro 'Nao consegui descobrir qual motor baixar.' 'Rode o mesmo comando de novo em alguns minutos. Se insistir, chame o suporte.'
326
+ }
327
+ $versao = $escolhido.version.TrimStart('v')
328
+ $zip = Get-AuroqNodeZip $versao $chip
329
+ $destino = Join-Path $env:TEMP $zip
330
+
331
+ try {
332
+ Invoke-WebRequest -Uri "https://nodejs.org/dist/v$versao/$zip" -OutFile $destino -TimeoutSec 600 -UseBasicParsing
333
+ } catch {
334
+ Write-AuroqErro 'O download do motor nao completou.' 'Pode ser antivirus ou rede instavel. Rode o mesmo comando de novo; se repetir, chame o suporte.'
335
+ }
336
+
337
+ # Sem conferir a soma oficial, nao instala.
338
+ try {
339
+ $somas = (Invoke-WebRequest -Uri "https://nodejs.org/dist/v$versao/SHASUMS256.txt" -TimeoutSec 60 -UseBasicParsing).Content
340
+ $linha = ($somas -split "`n" | Where-Object { $_ -match [regex]::Escape($zip) } | Select-Object -First 1)
341
+ $esperado = ($linha -split '\s+')[0]
342
+ $obtido = (Get-FileHash -Path $destino -Algorithm SHA256).Hash
343
+ } catch {
344
+ $esperado = ''
345
+ $obtido = 'x'
346
+ }
347
+ if (-not $esperado -or ($esperado.ToLower() -ne $obtido.ToLower())) {
348
+ Remove-Item $destino -Force -ErrorAction SilentlyContinue
349
+ Write-AuroqErro 'O arquivo do motor baixou com defeito.' 'Rode o mesmo comando de novo - o arquivo estragado ja foi apagado.'
350
+ }
351
+
352
+ # mark-of-the-web: sem desbloquear, o Windows recusa abrir o que veio da internet
353
+ Unblock-File -Path $destino -ErrorAction SilentlyContinue
354
+
355
+ $nodeDir = Get-AuroqNodeDir
356
+ $pai = Split-Path $nodeDir
357
+ try {
358
+ if (-not (Test-Path $pai)) { New-Item -ItemType Directory -Path $pai -Force | Out-Null }
359
+ if (Test-Path $nodeDir) { Remove-Item $nodeDir -Recurse -Force -ErrorAction SilentlyContinue }
360
+ Expand-Archive -Path $destino -DestinationPath $pai -Force
361
+ $extraido = Join-Path $pai "node-v$versao-win-$(if ($chip -eq 'ARM64') { 'arm64' } else { 'x64' })"
362
+ Rename-Item -Path $extraido -NewName 'node' -Force
363
+ } catch {
364
+ Write-AuroqErro 'Nao consegui guardar o motor na sua pasta.' 'Rode o mesmo comando de novo. Se repetir, mande pro suporte o arquivo install.log da pasta .auroq.'
365
+ }
366
+ Remove-Item $destino -Force -ErrorAction SilentlyContinue
367
+
368
+ Set-AuroqPath $nodeDir
369
+ # instalar ferramenta depois nao pode pedir elevacao
370
+ $env:npm_config_prefix = $nodeDir
371
+
372
+ Write-AuroqOk "Motor instalado ($versao)"
373
+ Write-AuroqLog 'motor' "instalado versao=$versao chip=$chip"
374
+ }
375
+
376
+ # --- Passo 4: login da mentoria (sec. 5.5) ----------------------------------------
377
+
378
+ function Invoke-AuroqLogin {
379
+ Write-AuroqPasso 'Agora entre com o seu acesso da Mentoria Arcane.'
380
+
381
+ if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk 'Login - seria pedido aqui (e-mail e senha da plataforma)'; return }
382
+
383
+ # `check-access` e a mesma regua do resto do sistema: sai com sucesso so com
384
+ # contrato ativo conferido agora. Sem sessao salva, ele mesmo pede e-mail e
385
+ # senha; com sessao boa, passa direto e nao pergunta de novo.
386
+ #
387
+ # NAO usar `whoami` aqui: ele imprime "Nao autenticado" e mesmo assim sai com
388
+ # sucesso. Usado como pergunta de sim/nao, ele dizia "voce ja estava logado"
389
+ # pra quem nunca logou, pulava o portao e deixava a conta sem acesso chegar ate
390
+ # a criacao da pasta.
391
+ & npx -y auroq-os@latest check-access
392
+ if ($LASTEXITCODE -ne 0) {
393
+ Write-AuroqLog 'login' 'recusado'
394
+ Write-Host ''
395
+ Write-Host ' Sem acesso ativo, a instalacao para aqui - e nada foi criado no seu computador.' -ForegroundColor DarkGray
396
+ Write-Host " O que fazer agora: fale com o suporte $AuroqSuporte" -ForegroundColor DarkGray
397
+ Write-Host ''
398
+ exit 1
399
+ }
400
+ Write-AuroqLog 'login' 'ok'
401
+ }
402
+
403
+ # --- Passo 5: pasta do negocio (sec. 5.6) -----------------------------------------
404
+
405
+ function Get-AuroqPasta {
406
+ Write-AuroqPasso 'Qual o nome da pasta do seu negocio?'
407
+ Write-AuroqDiz '(so letras minusculas e hifen - ex: minha-empresa)'
408
+
409
+ $nome = $env:AUROQ_INSTALL_PASTA
410
+ $tentativas = 0
411
+
412
+ while ($true) {
413
+ if (-not $nome) { $nome = Read-Host ' Nome' }
414
+
415
+ if (Test-AuroqPasta $nome) {
416
+ $alvo = Join-Path (Get-AuroqHome) $nome
417
+ $estado = Get-AuroqEstadoPasta $alvo
418
+ if ($estado -eq 'auroq') {
419
+ Write-Host ''
420
+ Write-AuroqAviso "Ja existe um Auroq em $alvo - nao vou mexer nele."
421
+ Write-AuroqDiz 'Pra conferir se esta tudo certo la, abra essa pasta e rode:'
422
+ Write-AuroqDiz ' auroq-os doctor'
423
+ Write-AuroqLog 'pasta' 'ja-tinha-auroq'
424
+ exit 0
425
+ }
426
+ if ($estado -eq 'ocupada') {
427
+ Write-AuroqAviso "A pasta $nome ja existe e tem coisa sua dentro. Escolha outro nome."
428
+ $nome = ''
429
+ } else {
430
+ $script:AuroqPastaAlvo = $alvo
431
+ break
432
+ }
433
+ } elseif ([string]::IsNullOrWhiteSpace($nome)) {
434
+ # Enter vazio so repete a pergunta - o aluno ainda nao escreveu nada.
435
+ $nome = ''
436
+ } else {
437
+ Write-AuroqDiz 'Esse nome nao serve: use so letras minusculas, numeros e hifen.'
438
+ Write-AuroqDiz 'Exemplo bom: minha-empresa'
439
+ $nome = ''
440
+ }
441
+
442
+ $tentativas = $tentativas + 1
443
+ if ($tentativas -ge 5) {
444
+ Write-AuroqErro 'Nao consegui um nome valido pra pasta.' 'Rode o mesmo comando de novo e escreva algo como: minha-empresa'
445
+ }
446
+ }
447
+
448
+ if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk "Pasta $script:AuroqPastaAlvo - seria criada aqui"; return }
449
+
450
+ try {
451
+ if (-not (Test-Path $script:AuroqPastaAlvo)) {
452
+ New-Item -ItemType Directory -Path $script:AuroqPastaAlvo -Force | Out-Null
453
+ }
454
+ } catch {
455
+ Write-AuroqErro "Nao consegui criar a pasta $script:AuroqPastaAlvo." 'Confira se voce tem permissao de escrita na sua pasta pessoal e rode de novo.'
456
+ }
457
+ Write-AuroqLog 'pasta' 'criada'
458
+ }
459
+
460
+ # --- Passo 6: montar o Auroq --------------------------------------------------
461
+
462
+ function Invoke-AuroqInit {
463
+ Write-AuroqPasso "Montando o Auroq dentro de $script:AuroqPastaAlvo..."
464
+
465
+ if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk 'Sistema - seria montado aqui'; return }
466
+
467
+ Set-Location $script:AuroqPastaAlvo
468
+ & npx -y auroq-os@latest init
469
+ if ($LASTEXITCODE -ne 0) {
470
+ Write-AuroqLog 'init' 'falhou'
471
+ Write-AuroqErro 'A montagem do sistema parou no meio.' 'Rode o mesmo comando de novo. Se repetir, mande pro suporte o arquivo install.log da pasta .auroq.'
472
+ }
473
+ Write-AuroqLog 'init' 'ok'
474
+ }
475
+
476
+ # --- Passo 7: fecho -----------------------------------------------------------
477
+
478
+ function Write-AuroqFecho {
479
+ $nome = Split-Path $script:AuroqPastaAlvo -Leaf
480
+ Write-Host ''
481
+ Write-Host ' ---------------------------------------------' -ForegroundColor Magenta
482
+ Write-Host ''
483
+ Write-AuroqDiz "Pronto. O Auroq esta em $script:AuroqPastaAlvo"
484
+ Write-Host ''
485
+ Write-AuroqDiz 'Falta um detalhe importante:'
486
+ Write-Host ''
487
+ Write-AuroqDiz ' 1. FECHE o Claude Code (ou o Codex) por completo e abra de novo'
488
+ Write-AuroqDiz ' - sem isso ele nao enxerga o que acabou de ser instalado'
489
+ Write-AuroqDiz " 2. Abra a pasta $nome"
490
+ Write-AuroqDiz ' 3. Chame o Ops: /AuroqOS:agents:ops (no Codex: $ops)'
491
+ Write-AuroqDiz ' 4. Digite: *bootstrap'
492
+ Write-Host ''
493
+ Write-AuroqDiz 'O Ops instala o resto e te guia daqui pra frente.'
494
+ Write-Host ''
495
+ Write-AuroqLog 'fim' "ok pasta=$nome"
496
+ }
497
+
498
+ # --- Fluxo --------------------------------------------------------------------
499
+
500
+ function Invoke-AuroqInstalacao {
501
+ Write-AuroqTitulo 'Auroq OS - instalacao'
502
+ Test-AuroqMaquina
503
+ Install-AuroqGit
504
+ Install-AuroqNode
505
+ Invoke-AuroqLogin
506
+ Get-AuroqPasta
507
+ Invoke-AuroqInit
508
+ Write-AuroqFecho
509
+ }
510
+
511
+ # Carregado pelos testes: so define as funcoes e sai.
512
+ if (-not $env:AUROQ_INSTALL_LIB) {
513
+ $script:AuroqPastaAlvo = ''
514
+ Invoke-AuroqInstalacao
515
+ }