@arcadialdev/arcality 3.0.2 → 3.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/scripts/init.mjs CHANGED
@@ -2,10 +2,10 @@
2
2
  // scripts/init.mjs — Command: arcality init
3
3
  // Single-configuration setup flow:
4
4
  // 1. Prompt API key → validate with backend
5
- // 2. Prompt project name, baseUrl, username, password
5
+ // 2. Prompt project name, baseUrl, username, password
6
6
  // 3. Detect framework (package.json only, NO .git)
7
7
  // 4. Create project via POST /api/v1/projects
8
- // 5. Write arcality.config
8
+ // 5. Write arcality.config
9
9
 
10
10
  import 'dotenv/config';
11
11
  import fs from 'node:fs';
@@ -18,8 +18,10 @@ import {
18
18
  loadProjectConfig,
19
19
  saveProjectConfig,
20
20
  createConfig,
21
- } from '../src/configManager.mjs';
22
- import { getApiUrl } from '../src/configLoader.mjs';
21
+ isRealProjectId,
22
+ } from '../src/configManager.mjs';
23
+ import { getApiUrl } from '../src/configLoader.mjs';
24
+ import { installPlaywrightAssets, getPlaywrightInstallCommand } from '../src/playwrightAssets.mjs';
23
25
 
24
26
  const __filename = fileURLToPath(import.meta.url);
25
27
  const __dirname = path.dirname(__filename);
@@ -271,21 +273,37 @@ async function main() {
271
273
  // If response is HTML (e.g. Cloudflare 521), show a clean message
272
274
  const isHtml = errText.trim().startsWith('<');
273
275
  const displayError = isHtml
274
- ? `El servidor backend de Arcality no está disponible temporalmente (HTTP ${res.status}). El proyecto se guardará solo de forma local.`
276
+ ? `El servidor backend de Arcality no esta disponible temporalmente (HTTP ${res.status}).`
275
277
  : `HTTP ${res.status}: ${errText.slice(0, 200)}`;
276
278
 
277
- sCreate.stop(chalk.yellow(`⚠️ ${displayError}`));
279
+ sCreate.stop(chalk.red(`No se pudo crear el proyecto en Arcality: ${displayError.replace(/El proyecto.*$/i, '').trim()}`));
278
280
  // Don't exit — write the config with a local-only project ID so user can still run
279
- projectId = projectId || `local_${Date.now()}`;
281
+ note(
282
+ chalk.white('No se guardo arcality.config porque Arcality requiere un proyecto real conectado al backend.'),
283
+ 'Configuracion detenida'
284
+ );
285
+ process.exit(1);
280
286
  } else {
281
287
  const created = await res.json();
282
- projectId = created.id || created.Id;
288
+ projectId = created.id || created.Id;
289
+ if (!isRealProjectId(projectId)) {
290
+ sCreate.stop(chalk.red('El backend no devolvio un Project ID valido.'));
291
+ note(
292
+ chalk.white('No se guardo arcality.config. Toda instancia de Arcality debe estar ligada a un proyecto real.'),
293
+ 'Configuracion detenida'
294
+ );
295
+ process.exit(1);
296
+ }
283
297
  organizationId = organizationId || created.organizationId || created.organization_id || null;
284
298
  sCreate.stop(chalk.green(`✅ Proyecto creado: "${projectName.trim()}" (${projectId})`));
285
299
  }
286
300
  } catch (err) {
287
- sCreate.stop(chalk.yellow(`⚠️ No se pudo conectar con el servidor de Arcality: ${err.message}. Se continuará en modo local.`));
288
- projectId = projectId || `local_${Date.now()}`;
301
+ sCreate.stop(chalk.red(`No se pudo conectar con el servidor de Arcality: ${err.message}`));
302
+ note(
303
+ chalk.white('No se guardo arcality.config porque la herramienta no funciona en modo offline/local.'),
304
+ 'Configuracion detenida'
305
+ );
306
+ process.exit(1);
289
307
  }
290
308
 
291
309
  // ── Step 6: Write arcality.config ──
@@ -293,15 +311,32 @@ async function main() {
293
311
  apiKey: apiKey.trim(),
294
312
  organizationId,
295
313
  projectId,
296
- projectName: projectName.trim(),
297
- baseUrl: baseUrl.trim(),
298
- frameworkDetected,
299
- username: username.trim(),
300
- password,
301
- arcalityVersion: version,
302
- });
314
+ projectName: projectName.trim(),
315
+ baseUrl: baseUrl.trim(),
316
+ frameworkDetected,
317
+ username: username.trim(),
318
+ password,
319
+ arcalityVersion: version,
320
+ });
303
321
 
304
- saveProjectConfig(config, projectRoot);
322
+ saveProjectConfig(config, projectRoot);
323
+
324
+ const sPlaywright = spinner();
325
+ sPlaywright.start('Preparando navegador de pruebas (Chromium + ffmpeg)...');
326
+ let playwrightReady = true;
327
+
328
+ try {
329
+ await installPlaywrightAssets({ cwd: PACKAGE_ROOT });
330
+ sPlaywright.stop(chalk.green('Playwright listo para ejecutar misiones'));
331
+ } catch (err) {
332
+ playwrightReady = false;
333
+ sPlaywright.stop(chalk.yellow(`No se pudieron instalar los assets de Playwright: ${err.message}`));
334
+ note(
335
+ chalk.white('La configuracion del proyecto ya fue guardada, pero antes de la primera mision ejecuta:') + '\n\n' +
336
+ chalk.cyan(getPlaywrightInstallCommand()),
337
+ 'Accion Manual Requerida'
338
+ );
339
+ }
305
340
 
306
341
  // ── Step 7: Custom QA Context ──
307
342
  note(
@@ -369,7 +404,8 @@ Los bullets que empiecen con "Ejemplo:" se ignoran hasta que los reemplaces.
369
404
  chalk.bold.white(' URL Base: ') + chalk.cyan(config.project.baseUrl) + '\n' +
370
405
  chalk.bold.white(' Framework: ') + chalk.magenta(config.project.frameworkDetected || 'N/A') + '\n' +
371
406
  chalk.bold.white(' ID del Proyecto: ') + chalk.gray(config.projectId) + '\n' +
372
- chalk.bold.white(' Carpeta de Misiones: ') + chalk.yellow(config.runtime.yamlOutputDir),
407
+ chalk.bold.white(' Carpeta de Misiones: ') + chalk.yellow(config.runtime.yamlOutputDir) + '\n' +
408
+ chalk.bold.white(' Playwright: ') + (playwrightReady ? chalk.green('listo') : chalk.yellow('pendiente de instalacion manual')),
373
409
  'Configuración Guardada'
374
410
  );
375
411
 
package/scripts/setup.mjs CHANGED
@@ -1,166 +1,120 @@
1
- #!/usr/bin/env node
2
- // scripts/setup.mjs Comando: arcality setup
3
- // Configura API Key + instala navegador Playwright (Chromium)
4
-
5
- import fs from 'node:fs';
6
- import path from 'node:path';
7
- import os from 'node:os';
8
- import { spawn } from 'node:child_process';
9
- import { createInterface } from 'node:readline';
10
-
11
- const CONFIG_DIR = path.join(os.homedir(), '.arcality');
12
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
13
- const PACKAGE_ROOT = process.env.ARCALITY_ROOT || path.resolve(path.dirname(new URL(import.meta.url).pathname), '..');
14
-
15
- function question(prompt) {
16
- const rl = createInterface({ input: process.stdin, output: process.stdout });
17
- return new Promise(resolve => {
18
- rl.question(prompt, answer => { rl.close(); resolve(answer.trim()); });
19
- });
20
- }
21
-
22
- function loadConfig() {
23
- try {
24
- if (fs.existsSync(CONFIG_FILE)) {
25
- let raw = fs.readFileSync(CONFIG_FILE, 'utf8');
26
- if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1);
27
- return JSON.parse(raw);
28
- }
29
- } catch { }
30
- return {};
31
- }
32
-
33
- function saveConfig(config) {
34
- if (!fs.existsSync(CONFIG_DIR)) {
35
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
36
- }
37
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
38
- }
39
-
40
- async function main() {
41
- // Leer versión
42
- let version = 'unknown';
43
- try {
44
- const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8'));
45
- version = pkg.version || 'unknown';
46
- } catch { }
47
-
48
- console.log('');
49
- console.log(' ╔══════════════════════════════════════════╗');
50
- console.log(` ║ ARCALITY Setup v${version.padEnd(24)}║`);
51
- console.log(' ╚══════════════════════════════════════════╝');
52
- console.log('');
53
-
54
- const config = loadConfig();
55
-
56
- // ──────────────── Paso 1: API Key de Arcality ────────────────
57
- const currentKey = config.api_key || '';
58
- const currentAnthropic = config.anthropic_api_key || '';
59
-
60
- const maskedArc = currentKey
61
- ? `✅ ${currentKey.slice(0, 6)}****${currentKey.slice(-4)}`
62
- : '❌ (No configurada)';
63
-
64
- const maskedAnt = currentAnthropic
65
- ? `✅ ${currentAnthropic.slice(0, 6)}****${currentAnthropic.slice(-4)}`
66
- : '❌ (No configurada)';
67
-
68
- console.log(` 🔑 Arcality API Key (dummy/real): ${maskedArc}`);
69
- console.log(` 🧠 Anthropic API Key (corporativa): ${maskedAnt}`);
70
- console.log('');
71
-
72
- const newKey = await question(' 👉 Ingresa Arcality API Key (Enter p. mantener): ');
73
- if (newKey) {
74
- if (!newKey.startsWith('arc_')) {
75
- console.log(' ❌ La API Key debe iniciar con "arc_"');
76
- process.exit(1);
77
- }
78
- config.api_key = newKey;
79
- }
80
-
81
- // API URL is internal-only (loaded via dotenv), always available
82
- const hasSaaSBackend = !!process.env.ARCALITY_API_URL;
83
-
84
- if (hasSaaSBackend) {
85
- console.log(' 🧠 Anthropic API Key (omitida se usará el Cerebro SaaS)');
86
- // Podemos limpiar la llave local por seguridad si queremos
87
- if (config.anthropic_api_key) delete config.anthropic_api_key;
88
- } else {
89
- const newAnt = await question(' 👉 Ingresa Anthropic API Key (Enter p. mantener): ');
90
- if (newAnt) {
91
- if (!newAnt.startsWith('sk-ant-')) {
92
- console.log(' ⚠️ Formato de llave Anthropic inusual. Verifica que inicie con "sk-ant-"');
93
- }
94
- config.anthropic_api_key = newAnt;
95
- }
96
- }
97
-
98
- // Configurar modelo por defecto
99
- config.model = config.model || 'claude-sonnet-4-5';
100
-
101
- // Guardar config
102
- config.version = version;
103
- config.setup_at = new Date().toISOString();
104
- saveConfig(config);
105
- console.log('');
106
- console.log(' ✅ Configuración guardada correctamente.');
107
-
108
- // ─── Paso 2: Instalar Chromium ───
109
- console.log('');
110
- console.log(' 🌐 Instalando navegador (Chromium para Playwright)...');
111
- console.log('');
112
-
113
- try {
114
- await new Promise((resolve, reject) => {
115
- const child = spawn('npx', ['playwright', 'install', 'chromium'], {
116
- stdio: 'inherit',
117
- shell: true,
118
- cwd: PACKAGE_ROOT
119
- });
120
- child.on('exit', code => code === 0 ? resolve() : reject(new Error(`Playwright install falló (exit code ${code})`)));
121
- child.on('error', reject);
122
- });
123
- console.log('');
124
- console.log(' ✅ Chromium instalado correctamente');
125
- } catch (err) {
126
- console.log('');
127
- console.log(` ⚠️ No se pudo instalar Chromium automáticamente: ${err.message}`);
128
- console.log(' Puedes instalarlo manualmente ejecutando:');
129
- console.log(' npx playwright install chromium');
130
- }
131
-
132
- // ─── Paso 3: Crear .env si no existe ───
133
- const envFile = path.join(PACKAGE_ROOT, '.env');
134
- const envExample = path.join(PACKAGE_ROOT, '.env.example');
135
-
136
- if (!fs.existsSync(envFile) && fs.existsSync(envExample)) {
137
- let content = fs.readFileSync(envExample, 'utf8');
138
-
139
- // Inyectar la API Key
140
- if (config.api_key) {
141
- content = content.replace('ARCALITY_API_KEY=', `ARCALITY_API_KEY=${config.api_key}`);
142
- }
143
-
144
- fs.writeFileSync(envFile, content, 'utf8');
145
- console.log(' ✅ .env creado desde .env.example');
146
- } else if (fs.existsSync(envFile)) {
147
- console.log(' ✅ .env existente (sin modificar)');
148
- }
149
-
150
- // ─── Resumen final ───
151
- console.log('');
152
- console.log(' ╔══════════════════════════════════════════╗');
153
- console.log(' ║ ✅ SETUP COMPLETADO ║');
154
- console.log(' ╚══════════════════════════════════════════╝');
155
- console.log('');
156
- console.log(' Para empezar, ejecuta:');
157
- console.log('');
158
- console.log(' arcality → Menú interactivo');
159
- console.log(' arcality --agent "tu misión" → Ejecución directa');
160
- console.log('');
161
- }
162
-
163
- main().catch(err => {
164
- console.error(' ❌ Error durante setup:', err.message);
165
- process.exit(1);
166
- });
1
+ #!/usr/bin/env node
2
+ // scripts/setup.mjs - Command: arcality setup
3
+ // Prepares the local machine for Arcality. Project configuration lives in `arcality init`.
4
+
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import os from 'node:os';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { installPlaywrightAssets, getPlaywrightInstallCommand } from '../src/playwrightAssets.mjs';
10
+
11
+ const CONFIG_DIR = path.join(os.homedir(), '.arcality');
12
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
13
+
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+ const PACKAGE_ROOT = process.env.ARCALITY_ROOT || path.resolve(__dirname, '..');
17
+
18
+ function loadConfig() {
19
+ try {
20
+ if (!fs.existsSync(CONFIG_FILE)) return {};
21
+ let raw = fs.readFileSync(CONFIG_FILE, 'utf8');
22
+ if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1);
23
+ return JSON.parse(raw);
24
+ } catch {
25
+ return {};
26
+ }
27
+ }
28
+
29
+ function saveConfig(config) {
30
+ if (!fs.existsSync(CONFIG_DIR)) {
31
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
32
+ }
33
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
34
+ }
35
+
36
+ function getVersion() {
37
+ try {
38
+ const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8'));
39
+ return pkg.version || 'unknown';
40
+ } catch {
41
+ return 'unknown';
42
+ }
43
+ }
44
+
45
+ function printHeader(version) {
46
+ console.log('');
47
+ console.log(' ARCALITY SETUP');
48
+ console.log(` Version: ${version}`);
49
+ console.log('');
50
+ console.log(' Este comando prepara la maquina local para ejecutar misiones.');
51
+ console.log(' La configuracion del proyecto se hace con: arcality init');
52
+ console.log('');
53
+ }
54
+
55
+ async function main() {
56
+ const version = getVersion();
57
+ printHeader(version);
58
+
59
+ const config = loadConfig();
60
+ const removedLegacyKeys = [];
61
+
62
+ if (config.anthropic_api_key) {
63
+ delete config.anthropic_api_key;
64
+ removedLegacyKeys.push('anthropic_api_key');
65
+ }
66
+
67
+ if (config.model) {
68
+ delete config.model;
69
+ removedLegacyKeys.push('model');
70
+ }
71
+
72
+ config.version = version;
73
+ config.setup_at = new Date().toISOString();
74
+ saveConfig(config);
75
+
76
+ console.log(' [1/3] Configuracion global revisada.');
77
+ if (removedLegacyKeys.length > 0) {
78
+ console.log(` Se removio configuracion legacy no usada: ${removedLegacyKeys.join(', ')}`);
79
+ } else {
80
+ console.log(' No se requiere ninguna llave de proveedor externo.');
81
+ }
82
+
83
+ console.log('');
84
+ console.log(' [2/3] Instalando assets de Playwright: Chromium + ffmpeg');
85
+ console.log(' Esto evita fallos de primera ejecucion al abrir el navegador o grabar video.');
86
+ console.log('');
87
+
88
+ let playwrightReady = false;
89
+ try {
90
+ await installPlaywrightAssets({ cwd: PACKAGE_ROOT });
91
+ playwrightReady = true;
92
+ console.log('');
93
+ console.log(' Playwright listo.');
94
+ } catch (err) {
95
+ console.log('');
96
+ console.log(` No se pudieron instalar los assets automaticamente: ${err.message}`);
97
+ console.log(' Ejecuta manualmente:');
98
+ console.log(` ${getPlaywrightInstallCommand()}`);
99
+ }
100
+
101
+ console.log('');
102
+ console.log(' [3/3] Siguientes pasos');
103
+ console.log(' En cada proyecto donde uses Arcality:');
104
+ console.log(' 1. arcality init');
105
+ console.log(' 2. arcality run');
106
+ console.log('');
107
+
108
+ if (!playwrightReady) {
109
+ console.log(' Setup finalizado con accion manual pendiente.');
110
+ process.exitCode = 1;
111
+ return;
112
+ }
113
+
114
+ console.log(' Setup completado correctamente.');
115
+ }
116
+
117
+ main().catch(err => {
118
+ console.error(' Error durante setup:', err.message);
119
+ process.exit(1);
120
+ });
@@ -36,6 +36,15 @@ export interface ProjectDto {
36
36
  base_url?: string;
37
37
  }
38
38
 
39
+ function isRealProjectId(projectId?: string | null): boolean {
40
+ const id = String(projectId || '').trim();
41
+ if (!id) return false;
42
+ if (id === 'undefined' || id === 'null') return false;
43
+ if (/^(local|mock)_/i.test(id)) return false;
44
+ if (/^0{8}-0{4}-0{4}-0{4}-0{12}$/i.test(id)) return false;
45
+ return true;
46
+ }
47
+
39
48
  export class KnowledgeService {
40
49
  private static instance: KnowledgeService;
41
50
  private apiBase: string;
@@ -80,10 +89,10 @@ export class KnowledgeService {
80
89
  }
81
90
 
82
91
  public getProjectId(): string | null {
83
- if (!this.projectId || this.projectId === 'undefined' || this.projectId === 'null') {
92
+ if (!isRealProjectId(this.projectId)) {
84
93
  this.projectId = process.env.ARCALITY_PROJECT_ID || null;
85
94
  }
86
- return this.projectId;
95
+ return isRealProjectId(this.projectId) ? this.projectId : null;
87
96
  }
88
97
 
89
98
  /**
@@ -98,7 +107,7 @@ export class KnowledgeService {
98
107
  const data = await res.json();
99
108
  return data.projects || [];
100
109
  } catch (e: any) {
101
- console.warn(chalk.yellow(`[KnowledgeService] Error al obtener proyectos: ${e.message}`));
110
+ if (process.env.DEBUG) console.warn(chalk.yellow(`[KnowledgeService] Error al obtener proyectos: ${e.message}`));
102
111
  return [];
103
112
  }
104
113
  }
@@ -116,7 +125,7 @@ export class KnowledgeService {
116
125
  if (!res.ok) return null;
117
126
  return await res.json();
118
127
  } catch (e: any) {
119
- console.error(chalk.red(`[KnowledgeService] Falló creación de proyecto: ${e.message}`));
128
+ if (process.env.DEBUG) console.error(chalk.red(`[KnowledgeService] Falló creación de proyecto: ${e.message}`));
120
129
  return null;
121
130
  }
122
131
  }
@@ -125,8 +134,8 @@ export class KnowledgeService {
125
134
  * 2. Ingesta (Post-Percept)
126
135
  */
127
136
  public async ingest(payload: PortalIngestRequest): Promise<void> {
128
- if (!payload.project_id || payload.project_id === 'undefined') {
129
- console.warn(chalk.yellow(`[Knowledge] Ingesta cancelada: project_id es inválido.`));
137
+ if (!isRealProjectId(payload.project_id)) {
138
+ if (process.env.DEBUG) console.warn(chalk.yellow(`[Knowledge] Ingesta cancelada: project_id es inválido.`));
130
139
  return;
131
140
  }
132
141
 
@@ -148,7 +157,7 @@ export class KnowledgeService {
148
157
  }
149
158
  }
150
159
  } catch (e: any) {
151
- console.warn(chalk.yellow(`[Knowledge] Error en ingesta: ${e.message}`));
160
+ if (process.env.DEBUG) console.warn(chalk.yellow(`[Knowledge] Error en ingesta: ${e.message}`));
152
161
  }
153
162
  }
154
163
 
@@ -170,7 +179,7 @@ export class KnowledgeService {
170
179
  if (!res.ok) return null;
171
180
  return await res.json();
172
181
  } catch (e: any) {
173
- console.warn(chalk.yellow(`[Knowledge] Error al obtener contexto: ${e.message}`));
182
+ if (process.env.DEBUG) console.warn(chalk.yellow(`[Knowledge] Error al obtener contexto: ${e.message}`));
174
183
  return null;
175
184
  }
176
185
  }
@@ -198,7 +207,7 @@ export class KnowledgeService {
198
207
  severity
199
208
  })
200
209
  });
201
- console.log(chalk.green(`[Knowledge] Nueva regla registrada: ${title}`));
210
+ if (process.env.DEBUG) console.log(chalk.green(`[Knowledge] Nueva regla registrada: ${title}`));
202
211
  } catch (e) { }
203
212
  }
204
213
 
@@ -224,7 +233,7 @@ export class KnowledgeService {
224
233
  source: "agent_auto"
225
234
  })
226
235
  });
227
- console.log(chalk.green(`[Knowledge] Nuevo campo catalogado: ${identifier}`));
236
+ if (process.env.DEBUG) console.log(chalk.green(`[Knowledge] Nuevo campo catalogado: ${identifier}`));
228
237
  } catch (e) { }
229
238
  }
230
239
 
@@ -250,7 +259,7 @@ export class KnowledgeService {
250
259
  source: "agent_auto"
251
260
  })
252
261
  });
253
- console.log(chalk.green(`[Knowledge] Nuevo conocimiento guardado: ${title}`));
262
+ if (process.env.DEBUG) console.log(chalk.green(`[Knowledge] Nuevo conocimiento guardado: ${title}`));
254
263
  } catch (e) { }
255
264
  }
256
265