@arcadialdev/arcality 2.4.24 → 2.4.26
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/.agents/skills/e2e-testing-expert/SKILL.md +28 -28
- package/.agents/skills/security-qa/SKILL.md +254 -0
- package/README.md +95 -95
- package/bin/arcality.mjs +55 -55
- package/package.json +68 -68
- package/playwright.config.js +33 -33
- package/scripts/gen-and-run.mjs +932 -929
- package/scripts/init.mjs +297 -297
- package/scripts/postinstall.mjs +77 -77
- package/src/arcalityClient.mjs +266 -266
- package/src/configLoader.mjs +179 -179
- package/src/configManager.mjs +172 -172
- package/src/envSetup.ts +205 -205
- package/src/index.ts +25 -25
- package/src/services/collectiveMemoryService.ts +1 -1
- package/src/services/securityScanner.ts +128 -0
- package/tests/_helpers/ArcalityReporter.js +706 -303
- package/tests/_helpers/ArcalityReporter.ts +262 -27
- package/tests/_helpers/agentic-runner.bundle.spec.js +357 -5
- package/tests/_helpers/agentic-runner.spec.ts +37 -1
- package/tests/_helpers/ai-agent-helper.ts +128 -6
- package/tests/_helpers/qa-security-tools.ts +265 -0
package/src/configLoader.mjs
CHANGED
|
@@ -1,179 +1,179 @@
|
|
|
1
|
-
// src/configLoader.mjs
|
|
2
|
-
// Configuration loader — supports arcality.config (primary) and .env / global config (fallback)
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import os from 'node:os';
|
|
6
|
-
import dotenv from 'dotenv';
|
|
7
|
-
|
|
8
|
-
dotenv.config();
|
|
9
|
-
|
|
10
|
-
export const CONFIG_DIR = path.join(os.homedir(), '.arcality');
|
|
11
|
-
export const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Returns the internal API URL for the Arcality backend.
|
|
15
|
-
* This is loaded exclusively from the tool's .env file (via dotenv).
|
|
16
|
-
* It is NOT configurable by the user, CLI flags, or arcality.config.
|
|
17
|
-
* To change it, modify the ARCALITY_API_URL variable in the tool's .env.
|
|
18
|
-
* @returns {string}
|
|
19
|
-
*/
|
|
20
|
-
export function getApiUrl() {
|
|
21
|
-
return process.env.ARCALITY_API_URL || 'https://arcalityqadev.arcadial.lat';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Loads the local arcality.config file from cwd (if it exists).
|
|
26
|
-
* @returns {object|null}
|
|
27
|
-
*/
|
|
28
|
-
function loadLocalArcalityConfig() {
|
|
29
|
-
try {
|
|
30
|
-
const configPath = path.join(process.cwd(), 'arcality.config');
|
|
31
|
-
if (fs.existsSync(configPath)) {
|
|
32
|
-
let raw = fs.readFileSync(configPath, 'utf8');
|
|
33
|
-
if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1);
|
|
34
|
-
return JSON.parse(raw);
|
|
35
|
-
}
|
|
36
|
-
} catch { }
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Loads configuration from multiple sources:
|
|
42
|
-
* 1. arcality.config (local project config — highest priority)
|
|
43
|
-
* 2. .env (environment variables)
|
|
44
|
-
* 3. ~/.arcality/config.json (global config)
|
|
45
|
-
*
|
|
46
|
-
* NOTE: ARCALITY_API_URL is NOT included here — use getApiUrl() instead.
|
|
47
|
-
*
|
|
48
|
-
* @returns {{
|
|
49
|
-
* ARCALITY_API_KEY: string,
|
|
50
|
-
* ARCALITY_PROJECT_ID?: string
|
|
51
|
-
* }}
|
|
52
|
-
*/
|
|
53
|
-
export function loadConfig() {
|
|
54
|
-
const localConfig = loadLocalArcalityConfig();
|
|
55
|
-
|
|
56
|
-
const config = {
|
|
57
|
-
ARCALITY_API_KEY: localConfig?.apiKey || process.env.ARCALITY_API_KEY,
|
|
58
|
-
ARCALITY_PROJECT_ID: localConfig?.projectId || process.env.ARCALITY_PROJECT_ID,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
if (!config.ARCALITY_API_KEY) {
|
|
62
|
-
throw new Error('ARCALITY_API_KEY is not defined. Run `arcality init` or set it in your .env file.');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return config;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Reads the user's global config (~/.arcality/config.json)
|
|
71
|
-
* @returns {{ api_key?: string, install_dir?: string, version?: string } | null}
|
|
72
|
-
*/
|
|
73
|
-
export function loadGlobalConfig() {
|
|
74
|
-
try {
|
|
75
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
76
|
-
let raw = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
77
|
-
// Strip BOM that PowerShell adds with -Encoding UTF8
|
|
78
|
-
if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1);
|
|
79
|
-
return JSON.parse(raw);
|
|
80
|
-
}
|
|
81
|
-
} catch { }
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Saves/updates the user's global config
|
|
87
|
-
* @param {object} updates - Fields to update
|
|
88
|
-
*/
|
|
89
|
-
export function saveGlobalConfig(updates) {
|
|
90
|
-
try {
|
|
91
|
-
if (!fs.existsSync(CONFIG_DIR)) {
|
|
92
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
93
|
-
}
|
|
94
|
-
const existing = loadGlobalConfig() || {};
|
|
95
|
-
const merged = { ...existing, ...updates };
|
|
96
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2), 'utf8');
|
|
97
|
-
return true;
|
|
98
|
-
} catch {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Gets the API Key (priority: arcality.config > env var > global config)
|
|
105
|
-
* @returns {{ key: string | null, source: 'config' | 'env' | 'global' | 'none' }}
|
|
106
|
-
*/
|
|
107
|
-
export function getApiKey() {
|
|
108
|
-
// 1. Local arcality.config
|
|
109
|
-
const localConfig = loadLocalArcalityConfig();
|
|
110
|
-
if (localConfig?.apiKey) {
|
|
111
|
-
process.env.ARCALITY_API_KEY = localConfig.apiKey;
|
|
112
|
-
return { key: localConfig.apiKey, source: 'config' };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 2. Environment variable (.env or shell)
|
|
116
|
-
if (process.env.ARCALITY_API_KEY) {
|
|
117
|
-
return { key: process.env.ARCALITY_API_KEY, source: 'env' };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Global config fallback removed strictly per project requirements
|
|
121
|
-
|
|
122
|
-
return { key: null, source: 'none' };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Loads additional secrets (like Anthropic) from global config
|
|
127
|
-
*/
|
|
128
|
-
export function setupProcessEnv() {
|
|
129
|
-
const config = loadGlobalConfig();
|
|
130
|
-
if (!config) return;
|
|
131
|
-
|
|
132
|
-
// Load Arcality API Key
|
|
133
|
-
getApiKey();
|
|
134
|
-
|
|
135
|
-
// Load Anthropic API Key if not already in env
|
|
136
|
-
if (config.anthropic_api_key && !process.env.ANTHROPIC_API_KEY) {
|
|
137
|
-
process.env.ANTHROPIC_API_KEY = config.anthropic_api_key;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Load default model if exists
|
|
141
|
-
if (config.model && !process.env.CLAUDE_MODEL) {
|
|
142
|
-
process.env.CLAUDE_MODEL = config.model;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Also inject arcality.config values into process.env for backward compat
|
|
146
|
-
const localConfig = loadLocalArcalityConfig();
|
|
147
|
-
if (localConfig) {
|
|
148
|
-
if (localConfig.apiKey && !process.env.ARCALITY_API_KEY) {
|
|
149
|
-
process.env.ARCALITY_API_KEY = localConfig.apiKey;
|
|
150
|
-
}
|
|
151
|
-
if (localConfig.projectId && !process.env.ARCALITY_PROJECT_ID) {
|
|
152
|
-
process.env.ARCALITY_PROJECT_ID = localConfig.projectId;
|
|
153
|
-
}
|
|
154
|
-
if (localConfig.project?.baseUrl && !process.env.BASE_URL) {
|
|
155
|
-
process.env.BASE_URL = localConfig.project.baseUrl;
|
|
156
|
-
}
|
|
157
|
-
if (localConfig.auth?.username && !process.env.LOGIN_USER) {
|
|
158
|
-
process.env.LOGIN_USER = localConfig.auth.username;
|
|
159
|
-
}
|
|
160
|
-
if (localConfig.auth?.password && !process.env.LOGIN_PASSWORD) {
|
|
161
|
-
process.env.LOGIN_PASSWORD = localConfig.auth.password;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
// SIEMPRE garantizar que la URL interna de la API esté en process.env.
|
|
165
|
-
// Esta URL es interna de la herramienta, no configurable por el usuario.
|
|
166
|
-
// Proviene del .env de la librería o usa el valor por defecto.
|
|
167
|
-
if (!process.env.ARCALITY_API_URL) {
|
|
168
|
-
process.env.ARCALITY_API_URL = 'https://arcalityqadev.arcadial.lat';
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Visual mask of API Key for banner display
|
|
174
|
-
* "arc_k_live_abc123xyz" → "arc_k_****xyz"
|
|
175
|
-
*/
|
|
176
|
-
export function maskApiKey(key) {
|
|
177
|
-
if (!key || key.length < 8) return '***';
|
|
178
|
-
return key.slice(0, 6) + '****' + key.slice(-4);
|
|
179
|
-
}
|
|
1
|
+
// src/configLoader.mjs
|
|
2
|
+
// Configuration loader — supports arcality.config (primary) and .env / global config (fallback)
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import dotenv from 'dotenv';
|
|
7
|
+
|
|
8
|
+
dotenv.config();
|
|
9
|
+
|
|
10
|
+
export const CONFIG_DIR = path.join(os.homedir(), '.arcality');
|
|
11
|
+
export const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Returns the internal API URL for the Arcality backend.
|
|
15
|
+
* This is loaded exclusively from the tool's .env file (via dotenv).
|
|
16
|
+
* It is NOT configurable by the user, CLI flags, or arcality.config.
|
|
17
|
+
* To change it, modify the ARCALITY_API_URL variable in the tool's .env.
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
export function getApiUrl() {
|
|
21
|
+
return process.env.ARCALITY_API_URL || 'https://arcalityqadev.arcadial.lat';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Loads the local arcality.config file from cwd (if it exists).
|
|
26
|
+
* @returns {object|null}
|
|
27
|
+
*/
|
|
28
|
+
function loadLocalArcalityConfig() {
|
|
29
|
+
try {
|
|
30
|
+
const configPath = path.join(process.cwd(), 'arcality.config');
|
|
31
|
+
if (fs.existsSync(configPath)) {
|
|
32
|
+
let raw = fs.readFileSync(configPath, 'utf8');
|
|
33
|
+
if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1);
|
|
34
|
+
return JSON.parse(raw);
|
|
35
|
+
}
|
|
36
|
+
} catch { }
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Loads configuration from multiple sources:
|
|
42
|
+
* 1. arcality.config (local project config — highest priority)
|
|
43
|
+
* 2. .env (environment variables)
|
|
44
|
+
* 3. ~/.arcality/config.json (global config)
|
|
45
|
+
*
|
|
46
|
+
* NOTE: ARCALITY_API_URL is NOT included here — use getApiUrl() instead.
|
|
47
|
+
*
|
|
48
|
+
* @returns {{
|
|
49
|
+
* ARCALITY_API_KEY: string,
|
|
50
|
+
* ARCALITY_PROJECT_ID?: string
|
|
51
|
+
* }}
|
|
52
|
+
*/
|
|
53
|
+
export function loadConfig() {
|
|
54
|
+
const localConfig = loadLocalArcalityConfig();
|
|
55
|
+
|
|
56
|
+
const config = {
|
|
57
|
+
ARCALITY_API_KEY: localConfig?.apiKey || process.env.ARCALITY_API_KEY,
|
|
58
|
+
ARCALITY_PROJECT_ID: localConfig?.projectId || process.env.ARCALITY_PROJECT_ID,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (!config.ARCALITY_API_KEY) {
|
|
62
|
+
throw new Error('ARCALITY_API_KEY is not defined. Run `arcality init` or set it in your .env file.');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return config;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Reads the user's global config (~/.arcality/config.json)
|
|
71
|
+
* @returns {{ api_key?: string, install_dir?: string, version?: string } | null}
|
|
72
|
+
*/
|
|
73
|
+
export function loadGlobalConfig() {
|
|
74
|
+
try {
|
|
75
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
76
|
+
let raw = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
77
|
+
// Strip BOM that PowerShell adds with -Encoding UTF8
|
|
78
|
+
if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1);
|
|
79
|
+
return JSON.parse(raw);
|
|
80
|
+
}
|
|
81
|
+
} catch { }
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Saves/updates the user's global config
|
|
87
|
+
* @param {object} updates - Fields to update
|
|
88
|
+
*/
|
|
89
|
+
export function saveGlobalConfig(updates) {
|
|
90
|
+
try {
|
|
91
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
92
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
93
|
+
}
|
|
94
|
+
const existing = loadGlobalConfig() || {};
|
|
95
|
+
const merged = { ...existing, ...updates };
|
|
96
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2), 'utf8');
|
|
97
|
+
return true;
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Gets the API Key (priority: arcality.config > env var > global config)
|
|
105
|
+
* @returns {{ key: string | null, source: 'config' | 'env' | 'global' | 'none' }}
|
|
106
|
+
*/
|
|
107
|
+
export function getApiKey() {
|
|
108
|
+
// 1. Local arcality.config
|
|
109
|
+
const localConfig = loadLocalArcalityConfig();
|
|
110
|
+
if (localConfig?.apiKey) {
|
|
111
|
+
process.env.ARCALITY_API_KEY = localConfig.apiKey;
|
|
112
|
+
return { key: localConfig.apiKey, source: 'config' };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 2. Environment variable (.env or shell)
|
|
116
|
+
if (process.env.ARCALITY_API_KEY) {
|
|
117
|
+
return { key: process.env.ARCALITY_API_KEY, source: 'env' };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Global config fallback removed strictly per project requirements
|
|
121
|
+
|
|
122
|
+
return { key: null, source: 'none' };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Loads additional secrets (like Anthropic) from global config
|
|
127
|
+
*/
|
|
128
|
+
export function setupProcessEnv() {
|
|
129
|
+
const config = loadGlobalConfig();
|
|
130
|
+
if (!config) return;
|
|
131
|
+
|
|
132
|
+
// Load Arcality API Key
|
|
133
|
+
getApiKey();
|
|
134
|
+
|
|
135
|
+
// Load Anthropic API Key if not already in env
|
|
136
|
+
if (config.anthropic_api_key && !process.env.ANTHROPIC_API_KEY) {
|
|
137
|
+
process.env.ANTHROPIC_API_KEY = config.anthropic_api_key;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Load default model if exists
|
|
141
|
+
if (config.model && !process.env.CLAUDE_MODEL) {
|
|
142
|
+
process.env.CLAUDE_MODEL = config.model;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Also inject arcality.config values into process.env for backward compat
|
|
146
|
+
const localConfig = loadLocalArcalityConfig();
|
|
147
|
+
if (localConfig) {
|
|
148
|
+
if (localConfig.apiKey && !process.env.ARCALITY_API_KEY) {
|
|
149
|
+
process.env.ARCALITY_API_KEY = localConfig.apiKey;
|
|
150
|
+
}
|
|
151
|
+
if (localConfig.projectId && !process.env.ARCALITY_PROJECT_ID) {
|
|
152
|
+
process.env.ARCALITY_PROJECT_ID = localConfig.projectId;
|
|
153
|
+
}
|
|
154
|
+
if (localConfig.project?.baseUrl && !process.env.BASE_URL) {
|
|
155
|
+
process.env.BASE_URL = localConfig.project.baseUrl;
|
|
156
|
+
}
|
|
157
|
+
if (localConfig.auth?.username && !process.env.LOGIN_USER) {
|
|
158
|
+
process.env.LOGIN_USER = localConfig.auth.username;
|
|
159
|
+
}
|
|
160
|
+
if (localConfig.auth?.password && !process.env.LOGIN_PASSWORD) {
|
|
161
|
+
process.env.LOGIN_PASSWORD = localConfig.auth.password;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// SIEMPRE garantizar que la URL interna de la API esté en process.env.
|
|
165
|
+
// Esta URL es interna de la herramienta, no configurable por el usuario.
|
|
166
|
+
// Proviene del .env de la librería o usa el valor por defecto.
|
|
167
|
+
if (!process.env.ARCALITY_API_URL) {
|
|
168
|
+
process.env.ARCALITY_API_URL = 'https://arcalityqadev.arcadial.lat';
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Visual mask of API Key for banner display
|
|
174
|
+
* "arc_k_live_abc123xyz" → "arc_k_****xyz"
|
|
175
|
+
*/
|
|
176
|
+
export function maskApiKey(key) {
|
|
177
|
+
if (!key || key.length < 8) return '***';
|
|
178
|
+
return key.slice(0, 6) + '****' + key.slice(-4);
|
|
179
|
+
}
|