auroq-os 1.2.6 → 1.3.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 +21 -8
- package/bin/auroq-os.js +31 -1
- package/lib/auth.js +334 -0
- package/lib/credentials.js +68 -0
- package/lib/supabase.js +19 -0
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -15,19 +15,32 @@ Transforma o Claude Code num centro de comando inteligente para operar seu negoc
|
|
|
15
15
|
### Setup
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
# 1.
|
|
19
|
-
|
|
20
|
-
cd meu-negocio
|
|
18
|
+
# 1. Crie uma pasta pro seu negocio
|
|
19
|
+
mkdir meu-negocio && cd meu-negocio
|
|
21
20
|
|
|
22
|
-
# 2.
|
|
21
|
+
# 2. Instale o Auroq OS (gate: email + senha da Mentoria Arcane)
|
|
22
|
+
npx auroq-os init
|
|
23
|
+
|
|
24
|
+
# 3. Abra o Claude Code
|
|
23
25
|
claude
|
|
24
26
|
|
|
25
|
-
#
|
|
27
|
+
# 4. Ative o Companion
|
|
26
28
|
/companion
|
|
27
|
-
|
|
28
|
-
# 4. Comece a operar
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
> **Acesso exclusivo para alunos da Mentoria Arcane.** O `init` pede o mesmo email + senha
|
|
32
|
+
> que voce usa em [mentoria-arcane.vercel.app](https://mentoria-arcane.vercel.app).
|
|
33
|
+
> A sessao fica salva em `~/.arcane/credentials.json` e renova automaticamente.
|
|
34
|
+
|
|
35
|
+
### Comandos de sessao
|
|
36
|
+
|
|
37
|
+
| Comando | O que faz |
|
|
38
|
+
|---------|-----------|
|
|
39
|
+
| `auroq-os init` | Instala o Auroq OS (exige login na primeira vez) |
|
|
40
|
+
| `auroq-os login` | Forca novo login (substitui credencial atual) |
|
|
41
|
+
| `auroq-os logout` | Encerra sessao local (remove `~/.arcane/credentials.json`) |
|
|
42
|
+
| `auroq-os whoami` | Mostra usuario autenticado e status de acesso |
|
|
43
|
+
|
|
31
44
|
## Estrutura
|
|
32
45
|
|
|
33
46
|
```
|
|
@@ -73,4 +86,4 @@ agents/ → Seu exercito (companion, workers, minds, squads)
|
|
|
73
86
|
|
|
74
87
|
---
|
|
75
88
|
|
|
76
|
-
*Auroq OS v1.
|
|
89
|
+
*Auroq OS v1.3.0 — by Euriler Jube / Arka*
|
package/bin/auroq-os.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const fs = require('fs-extra');
|
|
17
17
|
const { execSync } = require('child_process');
|
|
18
|
+
const auth = require('../lib/auth');
|
|
18
19
|
|
|
19
20
|
// ─── CORES ───────────────────────────────────────────────
|
|
20
21
|
const PURPLE = '\x1b[38;2;120;80;200m';
|
|
@@ -98,6 +99,15 @@ async function init() {
|
|
|
98
99
|
process.exit(1);
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
// ─── Fase 1b: Gate de acesso (Mentoria Arcane)
|
|
103
|
+
step('Verificando acesso...');
|
|
104
|
+
try {
|
|
105
|
+
await auth.getValidSession();
|
|
106
|
+
} catch (e) {
|
|
107
|
+
error(`Falha na autenticacao: ${e.message}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
101
111
|
// ─── Fase 2: Copiar estrutura do framework
|
|
102
112
|
step('Criando estrutura do Auroq OS...');
|
|
103
113
|
|
|
@@ -468,6 +478,23 @@ if (command === 'init' || command === 'install') {
|
|
|
468
478
|
error(`Falha na instalacao: ${err.message}`);
|
|
469
479
|
process.exit(1);
|
|
470
480
|
});
|
|
481
|
+
} else if (command === 'login') {
|
|
482
|
+
auth.interactiveLogin().catch(err => {
|
|
483
|
+
error(`Falha no login: ${err.message}`);
|
|
484
|
+
process.exit(1);
|
|
485
|
+
});
|
|
486
|
+
} else if (command === 'logout') {
|
|
487
|
+
auth.logout().catch(err => {
|
|
488
|
+
error(`Falha no logout: ${err.message}`);
|
|
489
|
+
process.exit(1);
|
|
490
|
+
});
|
|
491
|
+
} else if (command === 'whoami') {
|
|
492
|
+
try {
|
|
493
|
+
auth.whoami();
|
|
494
|
+
} catch (err) {
|
|
495
|
+
error(`Falha: ${err.message}`);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
471
498
|
} else if (command === 'update') {
|
|
472
499
|
// Update e feito pelo Ops dentro do Claude Code, nao pelo CLI diretamente
|
|
473
500
|
log(`${BOLD}Para atualizar o Auroq OS:${RESET}`);
|
|
@@ -481,8 +508,11 @@ if (command === 'init' || command === 'install') {
|
|
|
481
508
|
showBanner();
|
|
482
509
|
log(`${BOLD}Comandos disponiveis:${RESET}`);
|
|
483
510
|
log(` ${CYAN}init${RESET} Instalar Auroq OS no diretorio atual`);
|
|
511
|
+
log(` ${CYAN}login${RESET} Autenticar com email + senha da Mentoria Arcane`);
|
|
512
|
+
log(` ${CYAN}logout${RESET} Encerrar sessao local`);
|
|
513
|
+
log(` ${CYAN}whoami${RESET} Mostrar usuario autenticado`);
|
|
484
514
|
log(` ${CYAN}update${RESET} Atualizar (via Ops dentro do Claude Code)`);
|
|
485
515
|
log('');
|
|
486
|
-
log(`${DIM}Uso: npx
|
|
516
|
+
log(`${DIM}Uso: npx auroq-os init${RESET}`);
|
|
487
517
|
log('');
|
|
488
518
|
}
|
package/lib/auth.js
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const prompts = require('prompts');
|
|
4
|
+
const { createAuthClient } = require('./supabase');
|
|
5
|
+
const credentials = require('./credentials');
|
|
6
|
+
|
|
7
|
+
const PLATFORM_URL = 'https://arcane.arka.education';
|
|
8
|
+
const SUPPORT_CONTACT = '11 97312-2273';
|
|
9
|
+
const MAX_LOGIN_ATTEMPTS = 3;
|
|
10
|
+
|
|
11
|
+
const PURPLE = '\x1b[38;2;120;80;200m';
|
|
12
|
+
const GOLD = '\x1b[38;2;245;158;11m';
|
|
13
|
+
const CYAN = '\x1b[38;2;34;211;238m';
|
|
14
|
+
const GREEN = '\x1b[38;2;52;211;153m';
|
|
15
|
+
const DIM = '\x1b[2m';
|
|
16
|
+
const BOLD = '\x1b[1m';
|
|
17
|
+
const RESET = '\x1b[0m';
|
|
18
|
+
|
|
19
|
+
function log(msg) { console.log(` ${msg}`); }
|
|
20
|
+
function step(msg) { console.log(`\n ${CYAN}▸${RESET} ${msg}`); }
|
|
21
|
+
function ok(msg) { console.log(` ${GREEN}✓${RESET} ${msg}`); }
|
|
22
|
+
function warn(msg) { console.log(` ${GOLD}!${RESET} ${msg}`); }
|
|
23
|
+
function err(msg) { console.log(` ${PURPLE}✗${RESET} ${msg}`); }
|
|
24
|
+
|
|
25
|
+
function translateAuthError(error) {
|
|
26
|
+
if (!error) return 'Erro desconhecido.';
|
|
27
|
+
const msg = error.message || String(error);
|
|
28
|
+
if (msg === 'Invalid login credentials' || /invalid.*credentials/i.test(msg)) {
|
|
29
|
+
return 'E-mail ou senha incorretos.';
|
|
30
|
+
}
|
|
31
|
+
if (/email not confirmed/i.test(msg)) {
|
|
32
|
+
return 'Conta ainda nao confirmada. Entre na plataforma primeiro.';
|
|
33
|
+
}
|
|
34
|
+
if (/rate limit|too many/i.test(msg)) {
|
|
35
|
+
return 'Muitas tentativas. Aguarde alguns minutos e tente novamente.';
|
|
36
|
+
}
|
|
37
|
+
return msg;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function statusMessage(status) {
|
|
41
|
+
if (status === 'cancelado') {
|
|
42
|
+
return `Seu contrato foi cancelado. Contato do suporte: ${SUPPORT_CONTACT}`;
|
|
43
|
+
}
|
|
44
|
+
if (status === 'suspenso') {
|
|
45
|
+
return `Seu acesso esta suspenso. Regularize com o financeiro: ${SUPPORT_CONTACT}`;
|
|
46
|
+
}
|
|
47
|
+
if (status === 'finalizado') {
|
|
48
|
+
return `Seu contrato foi finalizado. Contato do suporte: ${SUPPORT_CONTACT}`;
|
|
49
|
+
}
|
|
50
|
+
return `Seu acesso nao esta ativo (${status || 'desconhecido'}). Contato: ${SUPPORT_CONTACT}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isOffline(error) {
|
|
54
|
+
if (!error) return false;
|
|
55
|
+
const msg = error.message || String(error);
|
|
56
|
+
return /fetch failed|network|enotfound|eai_again|econnrefused|timeout/i.test(msg);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function checkAccess(client) {
|
|
60
|
+
const { data, error } = await client.rpc('check_access_status');
|
|
61
|
+
if (error) {
|
|
62
|
+
const e = new Error(`Falha ao verificar acesso: ${error.message}`);
|
|
63
|
+
e.cause = error;
|
|
64
|
+
throw e;
|
|
65
|
+
}
|
|
66
|
+
return data;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function promptCredentials() {
|
|
70
|
+
if (!process.stdin.isTTY) {
|
|
71
|
+
throw new Error('Login interativo precisa de um terminal. Rode em um shell interativo.');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const response = await prompts([
|
|
75
|
+
{
|
|
76
|
+
type: 'text',
|
|
77
|
+
name: 'email',
|
|
78
|
+
message: 'Email (Mentoria Arcane)',
|
|
79
|
+
validate: (val) => (/^\S+@\S+\.\S+$/.test(val) ? true : 'Email invalido'),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: 'password',
|
|
83
|
+
name: 'password',
|
|
84
|
+
message: 'Senha',
|
|
85
|
+
validate: (val) => (val && val.length >= 1 ? true : 'Senha obrigatoria'),
|
|
86
|
+
},
|
|
87
|
+
], {
|
|
88
|
+
onCancel: () => {
|
|
89
|
+
throw new Error('Login cancelado.');
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return response;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function interactiveLogin({ forceFresh = false } = {}) {
|
|
97
|
+
log('');
|
|
98
|
+
log(`${BOLD}Login — Mentoria Arcane${RESET}`);
|
|
99
|
+
log(`${DIM}Use o mesmo email e senha da plataforma web.${RESET}`);
|
|
100
|
+
log(`${DIM}${PLATFORM_URL}${RESET}`);
|
|
101
|
+
log('');
|
|
102
|
+
|
|
103
|
+
let lastError = null;
|
|
104
|
+
|
|
105
|
+
for (let attempt = 1; attempt <= MAX_LOGIN_ATTEMPTS; attempt++) {
|
|
106
|
+
const { email, password } = await promptCredentials();
|
|
107
|
+
|
|
108
|
+
const client = createAuthClient();
|
|
109
|
+
let authResult;
|
|
110
|
+
try {
|
|
111
|
+
authResult = await client.auth.signInWithPassword({ email, password });
|
|
112
|
+
} catch (e) {
|
|
113
|
+
if (isOffline(e)) {
|
|
114
|
+
err('Sem conexao com a internet. Conecte e tente de novo.');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
err(translateAuthError(e));
|
|
118
|
+
lastError = e;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (authResult.error) {
|
|
123
|
+
err(translateAuthError(authResult.error));
|
|
124
|
+
lastError = authResult.error;
|
|
125
|
+
if (attempt < MAX_LOGIN_ATTEMPTS) {
|
|
126
|
+
log(`${DIM}Tentativa ${attempt} de ${MAX_LOGIN_ATTEMPTS}.${RESET}`);
|
|
127
|
+
}
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const { session, user } = authResult.data;
|
|
132
|
+
if (!session || !user) {
|
|
133
|
+
err('Sessao invalida retornada pelo servidor.');
|
|
134
|
+
lastError = new Error('No session');
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
log('');
|
|
139
|
+
step('Verificando acesso ativo...');
|
|
140
|
+
let status;
|
|
141
|
+
try {
|
|
142
|
+
status = await checkAccess(client);
|
|
143
|
+
} catch (e) {
|
|
144
|
+
if (isOffline(e)) {
|
|
145
|
+
err('Sem conexao. Nao foi possivel verificar acesso.');
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
err(`Nao foi possivel verificar o status de acesso: ${e.message}`);
|
|
149
|
+
await client.auth.signOut().catch(() => {});
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (status !== 'ativo') {
|
|
154
|
+
await client.auth.signOut().catch(() => {});
|
|
155
|
+
err(statusMessage(status));
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const saved = credentials.save({
|
|
160
|
+
access_token: session.access_token,
|
|
161
|
+
refresh_token: session.refresh_token,
|
|
162
|
+
expires_at: session.expires_at,
|
|
163
|
+
user: { id: user.id, email: user.email },
|
|
164
|
+
last_validated_at: Math.floor(Date.now() / 1000),
|
|
165
|
+
last_status: status,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
ok(`Autenticado como ${BOLD}${user.email}${RESET}`);
|
|
169
|
+
ok(`Status: ${GREEN}ativo${RESET}`);
|
|
170
|
+
return saved;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
err(`Falha no login apos ${MAX_LOGIN_ATTEMPTS} tentativas.`);
|
|
174
|
+
if (lastError) {
|
|
175
|
+
log(`${DIM}${translateAuthError(lastError)}${RESET}`);
|
|
176
|
+
}
|
|
177
|
+
log('');
|
|
178
|
+
log(`${DIM}Esqueceu a senha? Recupere em ${PLATFORM_URL}${RESET}`);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function refreshSession(cred) {
|
|
183
|
+
const client = createAuthClient();
|
|
184
|
+
const { data, error } = await client.auth.refreshSession({
|
|
185
|
+
refresh_token: cred.refresh_token,
|
|
186
|
+
});
|
|
187
|
+
if (error || !data.session) {
|
|
188
|
+
const e = new Error(error ? error.message : 'Refresh sem sessao');
|
|
189
|
+
e.cause = error;
|
|
190
|
+
throw e;
|
|
191
|
+
}
|
|
192
|
+
return { client, session: data.session, user: data.user };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function getValidSession({ allowOffline = true } = {}) {
|
|
196
|
+
const cred = credentials.load();
|
|
197
|
+
|
|
198
|
+
if (!cred) {
|
|
199
|
+
return await interactiveLogin();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!credentials.isExpired(cred)) {
|
|
203
|
+
step('Verificando acesso...');
|
|
204
|
+
try {
|
|
205
|
+
const client = createAuthClient();
|
|
206
|
+
await client.auth.setSession({
|
|
207
|
+
access_token: cred.access_token,
|
|
208
|
+
refresh_token: cred.refresh_token,
|
|
209
|
+
});
|
|
210
|
+
const status = await checkAccess(client);
|
|
211
|
+
if (status !== 'ativo') {
|
|
212
|
+
err(statusMessage(status));
|
|
213
|
+
credentials.clear();
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
const saved = credentials.save({
|
|
217
|
+
...cred,
|
|
218
|
+
last_validated_at: Math.floor(Date.now() / 1000),
|
|
219
|
+
last_status: status,
|
|
220
|
+
});
|
|
221
|
+
ok(`Autenticado como ${BOLD}${cred.user.email}${RESET}`);
|
|
222
|
+
ok(`Status: ${GREEN}ativo${RESET}`);
|
|
223
|
+
return saved;
|
|
224
|
+
} catch (e) {
|
|
225
|
+
if (isOffline(e) && allowOffline) {
|
|
226
|
+
const age = Math.floor((Date.now() / 1000 - (cred.last_validated_at || 0)) / 3600);
|
|
227
|
+
warn(`Modo offline — ultima validacao ha ${age}h`);
|
|
228
|
+
ok(`Autenticado como ${BOLD}${cred.user.email}${RESET} ${DIM}(offline)${RESET}`);
|
|
229
|
+
return cred;
|
|
230
|
+
}
|
|
231
|
+
warn(`Falha ao verificar sessao atual: ${e.message}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
step('Renovando sessao...');
|
|
236
|
+
try {
|
|
237
|
+
const { client, session, user } = await refreshSession(cred);
|
|
238
|
+
let status;
|
|
239
|
+
try {
|
|
240
|
+
status = await checkAccess(client);
|
|
241
|
+
} catch (e) {
|
|
242
|
+
if (isOffline(e) && allowOffline) {
|
|
243
|
+
const age = Math.floor((Date.now() / 1000 - (cred.last_validated_at || 0)) / 3600);
|
|
244
|
+
warn(`Modo offline — ultima validacao ha ${age}h`);
|
|
245
|
+
return cred;
|
|
246
|
+
}
|
|
247
|
+
err(`Falha ao verificar acesso: ${e.message}`);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (status !== 'ativo') {
|
|
252
|
+
err(statusMessage(status));
|
|
253
|
+
credentials.clear();
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const saved = credentials.save({
|
|
258
|
+
access_token: session.access_token,
|
|
259
|
+
refresh_token: session.refresh_token,
|
|
260
|
+
expires_at: session.expires_at,
|
|
261
|
+
user: { id: user.id, email: user.email },
|
|
262
|
+
last_validated_at: Math.floor(Date.now() / 1000),
|
|
263
|
+
last_status: status,
|
|
264
|
+
});
|
|
265
|
+
ok(`Sessao renovada — ${BOLD}${user.email}${RESET}`);
|
|
266
|
+
ok(`Status: ${GREEN}ativo${RESET}`);
|
|
267
|
+
return saved;
|
|
268
|
+
} catch (e) {
|
|
269
|
+
if (isOffline(e) && allowOffline) {
|
|
270
|
+
const age = Math.floor((Date.now() / 1000 - (cred.last_validated_at || 0)) / 3600);
|
|
271
|
+
warn(`Modo offline — ultima validacao ha ${age}h. Seguindo com credencial local.`);
|
|
272
|
+
ok(`Autenticado como ${BOLD}${cred.user.email}${RESET} ${DIM}(offline)${RESET}`);
|
|
273
|
+
return cred;
|
|
274
|
+
}
|
|
275
|
+
warn('Sessao expirada. Refaca o login.');
|
|
276
|
+
credentials.clear();
|
|
277
|
+
return await interactiveLogin();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async function logout() {
|
|
282
|
+
const cred = credentials.load();
|
|
283
|
+
if (!cred) {
|
|
284
|
+
log(`${DIM}Ja estava desconectado.${RESET}`);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
const client = createAuthClient();
|
|
289
|
+
await client.auth.setSession({
|
|
290
|
+
access_token: cred.access_token,
|
|
291
|
+
refresh_token: cred.refresh_token,
|
|
292
|
+
});
|
|
293
|
+
await client.auth.signOut().catch(() => {});
|
|
294
|
+
} catch {}
|
|
295
|
+
credentials.clear();
|
|
296
|
+
ok('Sessao encerrada. Credenciais locais removidas.');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function whoami() {
|
|
300
|
+
const cred = credentials.load();
|
|
301
|
+
if (!cred) {
|
|
302
|
+
log(`${DIM}Nao autenticado.${RESET}`);
|
|
303
|
+
log('');
|
|
304
|
+
log(`${DIM}Para entrar: ${CYAN}auroq-os login${RESET}`);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const now = Math.floor(Date.now() / 1000);
|
|
308
|
+
const validatedAgo = cred.last_validated_at ? Math.floor((now - cred.last_validated_at) / 60) : null;
|
|
309
|
+
const expired = credentials.isExpired(cred);
|
|
310
|
+
|
|
311
|
+
log('');
|
|
312
|
+
log(`${BOLD}Autenticado como:${RESET} ${cred.user.email}`);
|
|
313
|
+
log(`${DIM}Id:${RESET} ${cred.user.id}`);
|
|
314
|
+
log(`${DIM}Ultimo status:${RESET} ${cred.last_status || 'desconhecido'}`);
|
|
315
|
+
if (validatedAgo !== null) {
|
|
316
|
+
const humanAge = validatedAgo < 60
|
|
317
|
+
? `${validatedAgo} min atras`
|
|
318
|
+
: `${Math.floor(validatedAgo / 60)}h atras`;
|
|
319
|
+
log(`${DIM}Validado:${RESET} ${humanAge}`);
|
|
320
|
+
}
|
|
321
|
+
log(`${DIM}Access token:${RESET} ${expired ? `${GOLD}expirado${RESET}` : `${GREEN}valido${RESET}`}`);
|
|
322
|
+
log('');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
module.exports = {
|
|
326
|
+
interactiveLogin,
|
|
327
|
+
getValidSession,
|
|
328
|
+
logout,
|
|
329
|
+
whoami,
|
|
330
|
+
checkAccess,
|
|
331
|
+
translateAuthError,
|
|
332
|
+
statusMessage,
|
|
333
|
+
isOffline,
|
|
334
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const CRED_DIR = path.join(os.homedir(), '.arcane');
|
|
8
|
+
const CRED_FILE = path.join(CRED_DIR, 'credentials.json');
|
|
9
|
+
|
|
10
|
+
function ensureDir() {
|
|
11
|
+
if (!fs.existsSync(CRED_DIR)) {
|
|
12
|
+
fs.mkdirSync(CRED_DIR, { recursive: true, mode: 0o700 });
|
|
13
|
+
} else {
|
|
14
|
+
try {
|
|
15
|
+
fs.chmodSync(CRED_DIR, 0o700);
|
|
16
|
+
} catch {}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function load() {
|
|
21
|
+
if (!fs.existsSync(CRED_FILE)) return null;
|
|
22
|
+
try {
|
|
23
|
+
const raw = fs.readFileSync(CRED_FILE, 'utf8');
|
|
24
|
+
const data = JSON.parse(raw);
|
|
25
|
+
if (!data.access_token || !data.refresh_token || !data.user) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return data;
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function save(cred) {
|
|
35
|
+
ensureDir();
|
|
36
|
+
const payload = {
|
|
37
|
+
access_token: cred.access_token,
|
|
38
|
+
refresh_token: cred.refresh_token,
|
|
39
|
+
expires_at: cred.expires_at,
|
|
40
|
+
user: {
|
|
41
|
+
id: cred.user.id,
|
|
42
|
+
email: cred.user.email,
|
|
43
|
+
},
|
|
44
|
+
last_validated_at: cred.last_validated_at || Math.floor(Date.now() / 1000),
|
|
45
|
+
last_status: cred.last_status || 'unknown',
|
|
46
|
+
};
|
|
47
|
+
fs.writeFileSync(CRED_FILE, JSON.stringify(payload, null, 2), { mode: 0o600 });
|
|
48
|
+
try {
|
|
49
|
+
fs.chmodSync(CRED_FILE, 0o600);
|
|
50
|
+
} catch {}
|
|
51
|
+
return payload;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function clear() {
|
|
55
|
+
if (fs.existsSync(CRED_FILE)) {
|
|
56
|
+
fs.unlinkSync(CRED_FILE);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isExpired(cred) {
|
|
63
|
+
if (!cred || !cred.expires_at) return true;
|
|
64
|
+
const now = Math.floor(Date.now() / 1000);
|
|
65
|
+
return now >= cred.expires_at - 60;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = { load, save, clear, isExpired, CRED_DIR, CRED_FILE };
|
package/lib/supabase.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createClient } = require('@supabase/supabase-js');
|
|
4
|
+
|
|
5
|
+
const SUPABASE_URL = 'https://tzvfkdqzdkftcqfourom.supabase.co';
|
|
6
|
+
const SUPABASE_ANON_KEY =
|
|
7
|
+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InR6dmZrZHF6ZGtmdGNxZm91cm9tIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njg5NTA2MTQsImV4cCI6MjA4NDUyNjYxNH0.Ajmg36iq6Aj3x9L5DjpYZKOYpnjImqxVtU9rw5vkEAM';
|
|
8
|
+
|
|
9
|
+
function createAuthClient() {
|
|
10
|
+
return createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
|
11
|
+
auth: {
|
|
12
|
+
persistSession: false,
|
|
13
|
+
autoRefreshToken: false,
|
|
14
|
+
detectSessionInUrl: false,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = { createAuthClient, SUPABASE_URL, SUPABASE_ANON_KEY };
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auroq-os",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Auroq OS — Sistema Operacional de IA para Experts",
|
|
5
|
-
|
|
5
|
+
"bin": {
|
|
6
6
|
"auroq-os": "bin/auroq-os.js"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"bin/",
|
|
10
|
+
"lib/",
|
|
10
11
|
".auroq-core/",
|
|
11
12
|
".claude/",
|
|
12
13
|
".synapse/",
|
|
@@ -18,8 +19,10 @@
|
|
|
18
19
|
".env.example"
|
|
19
20
|
],
|
|
20
21
|
"dependencies": {
|
|
22
|
+
"@supabase/supabase-js": "^2.103.0",
|
|
23
|
+
"fs-extra": "^11.3.0",
|
|
21
24
|
"js-yaml": "^4.1.0",
|
|
22
|
-
"
|
|
25
|
+
"prompts": "^2.4.2"
|
|
23
26
|
},
|
|
24
27
|
"author": "Euriler Jube / Arka",
|
|
25
28
|
"license": "UNLICENSED"
|