@nexus-cortex/core 4.93.0 → 4.95.0
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/{.env.example → .env.defaults} +134 -25
- package/dist/config/MentorshipConfigService.d.ts +0 -1
- package/dist/config/MentorshipConfigService.d.ts.map +1 -1
- package/dist/config/MentorshipConfigService.js +10 -5
- package/dist/config/MentorshipConfigService.js.map +1 -1
- package/dist/config/SettingsLoader.d.ts +92 -11
- package/dist/config/SettingsLoader.d.ts.map +1 -1
- package/dist/config/SettingsLoader.js +331 -131
- package/dist/config/SettingsLoader.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts +1 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +10 -1
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/middleware/HelperModelMiddleware.d.ts +32 -0
- package/dist/middleware/HelperModelMiddleware.d.ts.map +1 -1
- package/dist/middleware/HelperModelMiddleware.js +57 -5
- package/dist/middleware/HelperModelMiddleware.js.map +1 -1
- package/dist/models/cards/deepseek/deepseek-v4-flash.d.ts.map +1 -1
- package/dist/models/cards/deepseek/deepseek-v4-flash.js +4 -2
- package/dist/models/cards/deepseek/deepseek-v4-flash.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +34 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +292 -6
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/OrchestratorFactory.js +1 -1
- package/dist/orchestrator/OrchestratorFactory.js.map +1 -1
- package/dist/orchestrator/displayHistorySanitizer.d.ts +29 -0
- package/dist/orchestrator/displayHistorySanitizer.d.ts.map +1 -0
- package/dist/orchestrator/displayHistorySanitizer.js +62 -0
- package/dist/orchestrator/displayHistorySanitizer.js.map +1 -0
- package/dist/orchestrator/loopToolBlock.d.ts +46 -0
- package/dist/orchestrator/loopToolBlock.d.ts.map +1 -0
- package/dist/orchestrator/loopToolBlock.js +66 -0
- package/dist/orchestrator/loopToolBlock.js.map +1 -0
- package/dist/tools/context-management/InitCortexContext.js +1 -1
- package/dist/tools/context-management/InitCortexContext.js.map +1 -1
- package/dist/training/DecisionStore.d.ts +1 -1
- package/dist/training/DecisionStore.d.ts.map +1 -1
- package/dist/training/DecisionStore.js.map +1 -1
- package/dist/training/deadlineExitMentor.d.ts +67 -0
- package/dist/training/deadlineExitMentor.d.ts.map +1 -0
- package/dist/training/deadlineExitMentor.js +99 -0
- package/dist/training/deadlineExitMentor.js.map +1 -0
- package/dist/training/endTurnResolver.d.ts +14 -3
- package/dist/training/endTurnResolver.d.ts.map +1 -1
- package/dist/training/endTurnResolver.js +27 -10
- package/dist/training/endTurnResolver.js.map +1 -1
- package/dist/training/loopExitPlanner.d.ts +30 -0
- package/dist/training/loopExitPlanner.d.ts.map +1 -0
- package/dist/training/loopExitPlanner.js +61 -0
- package/dist/training/loopExitPlanner.js.map +1 -0
- package/dist/training/toolOutcome.d.ts.map +1 -1
- package/dist/training/toolOutcome.js +33 -2
- package/dist/training/toolOutcome.js.map +1 -1
- package/package.json +5 -5
|
@@ -8,7 +8,7 @@ import * as fs from 'fs';
|
|
|
8
8
|
import * as path from 'path';
|
|
9
9
|
import * as os from 'os';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
|
-
import { DEFAULT_SETTINGS, validateSetting, getSettingMetadata } from './SettingsSchema.js';
|
|
11
|
+
import { DEFAULT_SETTINGS, SETTINGS_METADATA, validateSetting, getSettingMetadata } from './SettingsSchema.js';
|
|
12
12
|
/**
|
|
13
13
|
* Parse .env file content into key-value pairs
|
|
14
14
|
*/
|
|
@@ -49,20 +49,89 @@ export function getGlobalConfigDir() {
|
|
|
49
49
|
export function getGlobalEnvPath() {
|
|
50
50
|
return path.join(getGlobalConfigDir(), '.env');
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Resolve the shipped `.env.defaults` — the read-live default config layer.
|
|
54
|
+
*
|
|
55
|
+
* This file is committed + ships in the package and is READ directly (never copied
|
|
56
|
+
* into the user's .env), so a package upgrade ships new defaults automatically. It is
|
|
57
|
+
* loaded as the LOWEST-precedence layer (below the user's ~/.cortex/.env, below the
|
|
58
|
+
* real shell env) and also overlays DEFAULT_SETTINGS as the effective floor.
|
|
59
|
+
*
|
|
60
|
+
* Search order mirrors the (legacy) seed: the caller's packageRoot, then cwd, then
|
|
61
|
+
* CORE's own root — core is a dependency of every entry point and is build-synced
|
|
62
|
+
* with the root canonical, so the file exists for any current/future bin even when
|
|
63
|
+
* the calling package doesn't ship its own copy.
|
|
64
|
+
*/
|
|
65
|
+
export function resolveDefaultsEnvPath(packageRoot) {
|
|
66
|
+
const cwd = process.cwd();
|
|
67
|
+
const coreOwnRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
68
|
+
return [
|
|
69
|
+
packageRoot ? path.join(packageRoot, '.env.defaults') : undefined,
|
|
70
|
+
path.join(cwd, '.env.defaults'),
|
|
71
|
+
path.join(coreOwnRoot, '.env.defaults'),
|
|
72
|
+
].find((p) => !!p && fs.existsSync(p));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The keys-only seed for a fresh `~/.cortex/.env`: the secret keys + a short header,
|
|
76
|
+
* NO levers. Harness defaults ship in `.env.defaults` and are read live, so freezing
|
|
77
|
+
* them into the user's file is exactly what blocks upgrades from propagating new
|
|
78
|
+
* defaults. Seeding only the keys keeps the file sparse — an upgrade brings new
|
|
79
|
+
* defaults with nothing to regenerate and no keys to re-enter.
|
|
80
|
+
*/
|
|
81
|
+
export function keysOnlyStub() {
|
|
82
|
+
const secretKeys = SETTINGS_METADATA.filter(m => m.secret).map(m => m.key);
|
|
83
|
+
const header = '# Nexus Cortex — your keys & overrides\n' +
|
|
84
|
+
'#\n' +
|
|
85
|
+
'# Put your provider API keys here (or run: cortex config set <KEY> <value>).\n' +
|
|
86
|
+
'# Harness DEFAULTS are NOT in this file — they ship in the package (.env.defaults)\n' +
|
|
87
|
+
'# and are read live, so upgrades bring new defaults with nothing to regenerate and\n' +
|
|
88
|
+
'# no keys to re-enter. Only set a lever here to DIVERGE from the shipped default;\n' +
|
|
89
|
+
'# an uncommented KEY=value here overrides it.\n' +
|
|
90
|
+
'\n';
|
|
91
|
+
return header + secretKeys.map(k => `${k}=`).join('\n') + '\n';
|
|
92
|
+
}
|
|
93
|
+
let _effectiveDefaults;
|
|
94
|
+
/**
|
|
95
|
+
* `DEFAULT_SETTINGS` overlaid with the shipped `.env.defaults` — the EFFECTIVE floor.
|
|
96
|
+
*
|
|
97
|
+
* The read-live default layer reaches most levers through `process.env` (bootstrapEnv
|
|
98
|
+
* loads `.env.defaults` as the lowest base file), but a handful of merge keys don't
|
|
99
|
+
* consult `process.env`. Overlaying `.env.defaults` onto `DEFAULT_SETTINGS` makes the
|
|
100
|
+
* shipped file authoritative for EVERY lever. Secrets are untouched (they are Omitted
|
|
101
|
+
* from `DEFAULT_SETTINGS`, so the loop never visits them). Cached — the shipped file
|
|
102
|
+
* does not change at runtime.
|
|
103
|
+
*/
|
|
104
|
+
export function getEffectiveDefaults() {
|
|
105
|
+
if (_effectiveDefaults)
|
|
106
|
+
return _effectiveDefaults;
|
|
107
|
+
const d = { ...DEFAULT_SETTINGS };
|
|
108
|
+
const shipped = resolveDefaultsEnvPath();
|
|
109
|
+
if (shipped) {
|
|
110
|
+
try {
|
|
111
|
+
const parsed = parseEnvFile(fs.readFileSync(shipped, 'utf-8'));
|
|
112
|
+
for (const k of Object.keys(DEFAULT_SETTINGS)) {
|
|
113
|
+
const v = parsed[k];
|
|
114
|
+
if (v !== undefined && v !== '')
|
|
115
|
+
d[k] = v;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch { /* keep the hardcoded floor */ }
|
|
119
|
+
}
|
|
120
|
+
_effectiveDefaults = d;
|
|
121
|
+
return d;
|
|
122
|
+
}
|
|
52
123
|
/**
|
|
53
124
|
* THE canonical .env → process.env bootstrap for every CLI/TUI entry point.
|
|
54
125
|
*
|
|
55
126
|
* One implementation, so a consumer never hand-rolls dotenv loading (and can't
|
|
56
|
-
* forget the global `~/.cortex/.env`).
|
|
57
|
-
* .env files into process.env
|
|
58
|
-
*
|
|
59
|
-
* copies the shipped `.env.example` → `~/.cortex/.env` when that file is missing
|
|
60
|
-
* (the Docker image does the same copy at build time). All bins call this ONCE at
|
|
61
|
-
* startup; a change here takes effect for every launcher.
|
|
127
|
+
* forget the global `~/.cortex/.env`). It seeds a KEYS-ONLY `~/.cortex/.env` on first
|
|
128
|
+
* run (below), then READS + layers the .env files into process.env. All bins call this
|
|
129
|
+
* ONCE at startup; a change here takes effect for every launcher.
|
|
62
130
|
*
|
|
63
|
-
* Precedence (highest → lowest): a `.env.local` beside any of the base files wins
|
|
64
|
-
*
|
|
65
|
-
* `~/.cortex/.env
|
|
131
|
+
* Precedence (highest → lowest): a `.env.local` beside any of the base files wins over
|
|
132
|
+
* everything; then project `./.env` (or `packageRoot/.env`) beats the global
|
|
133
|
+
* `~/.cortex/.env`, which beats the shipped `.env.defaults` (the read-live default
|
|
134
|
+
* layer, appended last). Matches `loadEnvFile()`'s layering.
|
|
66
135
|
*
|
|
67
136
|
* FIRST-WINS over the real environment: a value already present in `process.env`
|
|
68
137
|
* (e.g. a key the hosting container injected) is NEVER overwritten by a base .env
|
|
@@ -75,48 +144,39 @@ export function getGlobalEnvPath() {
|
|
|
75
144
|
*/
|
|
76
145
|
export function bootstrapEnv(packageRoot) {
|
|
77
146
|
const cwd = process.cwd();
|
|
78
|
-
// FIRST-ACTIVATION SEED
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// (build-synced from the repo root) and is a dependency of every entry point,
|
|
93
|
-
// so this fallback makes the seed unconditional for any current or future bin.
|
|
94
|
-
const coreOwnRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
95
|
-
const examplePath = [
|
|
96
|
-
packageRoot ? path.join(packageRoot, '.env.example') : undefined,
|
|
97
|
-
path.join(cwd, '.env.example'),
|
|
98
|
-
path.join(coreOwnRoot, '.env.example'),
|
|
99
|
-
].find((p) => !!p && fs.existsSync(p));
|
|
100
|
-
if (examplePath) {
|
|
101
|
-
const seedTargets = [
|
|
102
|
-
getGlobalEnvPath(), // global ~/.cortex/.env
|
|
103
|
-
...(packageRoot ? [path.join(packageRoot, '.env')] : []), // user-findable install-dir .env
|
|
104
|
-
];
|
|
105
|
-
for (const target of seedTargets) {
|
|
106
|
-
try {
|
|
107
|
-
if (!fs.existsSync(target)) {
|
|
108
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
109
|
-
fs.copyFileSync(examplePath, target);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
catch { /* read-only dir — skip; the file just won't exist for this launch */ }
|
|
147
|
+
// FIRST-ACTIVATION SEED — a KEYS-ONLY `~/.cortex/.env` (somewhere to put secrets),
|
|
148
|
+
// NOT a copy of every lever. The first time ANY entry point activates the library
|
|
149
|
+
// (server, `cortex`, `cortex-cli`, `fuzzycortex`, `neoncortex`, …) and no global
|
|
150
|
+
// config exists yet, write the sparse keys stub. Harness DEFAULTS are read live from
|
|
151
|
+
// the shipped `.env.defaults` (loaded below as the lowest layer) — freezing them into
|
|
152
|
+
// the user's file is exactly what USED to block upgrades from propagating new
|
|
153
|
+
// defaults, so we no longer seed levers or a `packageRoot/.env` copy. Best-effort —
|
|
154
|
+
// a read-only home is skipped, and a real injected key still works (blank = unset).
|
|
155
|
+
const defaultsPath = resolveDefaultsEnvPath(packageRoot);
|
|
156
|
+
try {
|
|
157
|
+
const target = getGlobalEnvPath();
|
|
158
|
+
if (!fs.existsSync(target)) {
|
|
159
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
160
|
+
fs.writeFileSync(target, keysOnlyStub(), 'utf-8');
|
|
113
161
|
}
|
|
114
162
|
}
|
|
115
|
-
|
|
163
|
+
catch { /* read-only home — skip; the file just won't exist for this launch */ }
|
|
164
|
+
// 🔴 NO auto-migration here. `migrateGlobalConfigToSparse()` used to run at bootstrap and
|
|
165
|
+
// COLLAPSE a full-snapshot ~/.cortex/.env in place — which silently mutated a live/working
|
|
166
|
+
// config (it clobbered the dev config 2026-09-06). Migration is now OPT-IN only (a deliberate
|
|
167
|
+
// `cortex config migrate` command with a diff + confirm); bootstrap must NEVER modify the
|
|
168
|
+
// user's config. Propagation for the common case already works without it: any lever a user
|
|
169
|
+
// did not override flows from the shipped `.env.defaults` (read-live) on upgrade.
|
|
170
|
+
// Base files, HIGHEST precedence first (first-wins → earlier entries win). The
|
|
171
|
+
// shipped `.env.defaults` is appended LAST = lowest precedence: it is the read-live
|
|
172
|
+
// default layer, below the user's files and below the real injected env — so a user
|
|
173
|
+
// override (or a bench env-override) always wins, and unset levers flow from the
|
|
174
|
+
// shipped defaults.
|
|
116
175
|
const baseFiles = [
|
|
117
176
|
path.join(cwd, '.env'),
|
|
118
177
|
...(packageRoot ? [path.join(packageRoot, '.env')] : []),
|
|
119
178
|
getGlobalEnvPath(),
|
|
179
|
+
...(defaultsPath ? [defaultsPath] : []),
|
|
120
180
|
];
|
|
121
181
|
// `.local` overrides beside each base location (these DO override existing env).
|
|
122
182
|
const localFiles = [
|
|
@@ -297,6 +357,124 @@ export function writeEnvSettings(projectPath, settings) {
|
|
|
297
357
|
}
|
|
298
358
|
return results;
|
|
299
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Surgically REMOVE a setting's line from the .env file (delete the `KEY=...` line and
|
|
362
|
+
* its value), preserving every other line and all comments. This is the correct "reset
|
|
363
|
+
* to default" in the read-live model: deleting a user's override line makes the lever
|
|
364
|
+
* fall back to the shipped `.env.defaults` — so the user rejoins the default flow and
|
|
365
|
+
* picks up future improvements. (Writing the current default VALUE would re-freeze it.)
|
|
366
|
+
* A key that isn't present is a no-op success.
|
|
367
|
+
*/
|
|
368
|
+
export function removeEnvSetting(projectPath, key) {
|
|
369
|
+
const envPath = path.join(projectPath, '.env');
|
|
370
|
+
if (!fs.existsSync(envPath)) {
|
|
371
|
+
return { success: true, newValue: '' }; // nothing to remove
|
|
372
|
+
}
|
|
373
|
+
let content;
|
|
374
|
+
try {
|
|
375
|
+
content = fs.readFileSync(envPath, 'utf-8');
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
return { success: false, error: `Failed to read .env file: ${error.message}`, newValue: '' };
|
|
379
|
+
}
|
|
380
|
+
const previousValue = parseEnvFile(content)[key];
|
|
381
|
+
if (previousValue === undefined) {
|
|
382
|
+
return { success: true, newValue: '' }; // key not set — nothing to remove
|
|
383
|
+
}
|
|
384
|
+
// Drop the KEY=... line (allow leading whitespace); leave comments/other lines intact.
|
|
385
|
+
const keyLine = new RegExp(`^[ \\t]*${key}=.*(?:\\r?\\n)?`, 'm');
|
|
386
|
+
const newContent = content.replace(keyLine, '');
|
|
387
|
+
try {
|
|
388
|
+
fs.writeFileSync(envPath, newContent, 'utf-8');
|
|
389
|
+
return { success: true, previousValue, newValue: '' };
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
return { success: false, error: `Failed to write .env file: ${error.message}`, previousValue, newValue: '' };
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/** Set a single setting in the GLOBAL ~/.cortex/.env (surgical, sparse). The canonical
|
|
396
|
+
* write target for every /config surface — harness config is global (identical from any
|
|
397
|
+
* directory), so a user's choice lives in one place and survives package updates. */
|
|
398
|
+
export function setGlobalSetting(key, value) {
|
|
399
|
+
return writeEnvSetting(getGlobalConfigDir(), key, value);
|
|
400
|
+
}
|
|
401
|
+
/** Remove a single setting's override line from the GLOBAL ~/.cortex/.env (reset-to-default). */
|
|
402
|
+
export function removeGlobalSetting(key) {
|
|
403
|
+
return removeEnvSetting(getGlobalConfigDir(), key);
|
|
404
|
+
}
|
|
405
|
+
/** The SHIPPED default value for a lever, read from the live `.env.defaults` (covers every
|
|
406
|
+
* lever, including the ones not in DEFAULT_SETTINGS). '' if the file/key is absent. Used
|
|
407
|
+
* to restore a lever to its shipped default after removing a user override. */
|
|
408
|
+
export function getShippedDefault(key) {
|
|
409
|
+
const p = resolveDefaultsEnvPath();
|
|
410
|
+
if (!p)
|
|
411
|
+
return '';
|
|
412
|
+
try {
|
|
413
|
+
return parseEnvFile(fs.readFileSync(p, 'utf-8'))[key] ?? '';
|
|
414
|
+
}
|
|
415
|
+
catch {
|
|
416
|
+
return '';
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* ONE-TIME migration for EXISTING users upgrading to the read-live model. The old install
|
|
421
|
+
* seeded a FULL copy of every lever into `~/.cortex/.env`, which now FREEZES those levers
|
|
422
|
+
* (a user value beats the shipped `.env.defaults`), so an upgrade would never reach them.
|
|
423
|
+
*
|
|
424
|
+
* This collapses that full snapshot back to SPARSE: a lever line is removed when its value
|
|
425
|
+
* equals a DEFAULT — either the new shipped default (`.env.defaults`) OR the hardcoded
|
|
426
|
+
* `DEFAULT_SETTINGS` floor (which still holds the OLD pre-reson defaults). Matching either
|
|
427
|
+
* means the user never deliberately chose it, so removing it lets the lever inherit the
|
|
428
|
+
* current shipped default (and every future one). Genuine divergences and ALL API keys are
|
|
429
|
+
* preserved untouched. Marker-gated (`~/.cortex/.env-migrated`) so it runs exactly once;
|
|
430
|
+
* best-effort (never blocks boot); only acts on a FULL snapshot, never a sparse file.
|
|
431
|
+
*/
|
|
432
|
+
export function migrateGlobalConfigToSparse() {
|
|
433
|
+
const dir = getGlobalConfigDir();
|
|
434
|
+
const marker = path.join(dir, '.env-migrated');
|
|
435
|
+
const envPath = getGlobalEnvPath();
|
|
436
|
+
try {
|
|
437
|
+
if (fs.existsSync(marker) || !fs.existsSync(envPath))
|
|
438
|
+
return { migrated: false, removed: 0 };
|
|
439
|
+
const shippedPath = resolveDefaultsEnvPath();
|
|
440
|
+
const shipped = shippedPath ? parseEnvFile(fs.readFileSync(shippedPath, 'utf-8')) : {};
|
|
441
|
+
const userEnv = parseEnvFile(fs.readFileSync(envPath, 'utf-8'));
|
|
442
|
+
const secretKeys = new Set(SETTINGS_METADATA.filter(m => m.secret).map(m => m.key));
|
|
443
|
+
const leverEntries = Object.entries(userEnv).filter(([k]) => !secretKeys.has(k));
|
|
444
|
+
// Only act on a FULL snapshot (the old copy-seed signature) — never disturb a file the
|
|
445
|
+
// user has already curated down to a few sparse overrides.
|
|
446
|
+
if (leverEntries.length <= 15) {
|
|
447
|
+
try {
|
|
448
|
+
fs.writeFileSync(marker, `skipped (sparse) ${new Date().toISOString()}\n`);
|
|
449
|
+
}
|
|
450
|
+
catch { /* ignore */ }
|
|
451
|
+
return { migrated: false, removed: 0 };
|
|
452
|
+
}
|
|
453
|
+
const toRemove = leverEntries
|
|
454
|
+
.filter(([k, v]) => {
|
|
455
|
+
const shippedVal = shipped[k];
|
|
456
|
+
const floorVal = DEFAULT_SETTINGS[k];
|
|
457
|
+
return (shippedVal !== undefined && shippedVal === v) || (floorVal !== undefined && floorVal === v);
|
|
458
|
+
})
|
|
459
|
+
.map(([k]) => k);
|
|
460
|
+
if (toRemove.length > 0) {
|
|
461
|
+
try {
|
|
462
|
+
fs.copyFileSync(envPath, envPath + '.pre-migrate-backup');
|
|
463
|
+
}
|
|
464
|
+
catch { /* best-effort */ }
|
|
465
|
+
for (const k of toRemove)
|
|
466
|
+
removeEnvSetting(dir, k);
|
|
467
|
+
}
|
|
468
|
+
try {
|
|
469
|
+
fs.writeFileSync(marker, `migrated ${new Date().toISOString()} removed=${toRemove.length}\n`);
|
|
470
|
+
}
|
|
471
|
+
catch { /* ignore */ }
|
|
472
|
+
return { migrated: true, removed: toRemove.length };
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
return { migrated: false, removed: 0 };
|
|
476
|
+
}
|
|
477
|
+
}
|
|
300
478
|
/**
|
|
301
479
|
* Get Google/Gemini API key with proper fallback
|
|
302
480
|
* Priority: GEMINI_API_KEY (recommended by Google) -> GOOGLE_API_KEY (legacy)
|
|
@@ -315,6 +493,9 @@ export function mergeWithDefaults(env) {
|
|
|
315
493
|
if (!process.env.GEMINI_API_KEY && process.env.GOOGLE_API_KEY) {
|
|
316
494
|
process.env.GEMINI_API_KEY = process.env.GOOGLE_API_KEY;
|
|
317
495
|
}
|
|
496
|
+
// Effective floor = hardcoded DEFAULT_SETTINGS overlaid with the shipped .env.defaults
|
|
497
|
+
// (read-live). Used below wherever a value falls through to the code default.
|
|
498
|
+
const D = getEffectiveDefaults();
|
|
318
499
|
return {
|
|
319
500
|
// API Keys (no defaults, use empty string if not set)
|
|
320
501
|
ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_API_KEY || '',
|
|
@@ -332,98 +513,98 @@ export function mergeWithDefaults(env) {
|
|
|
332
513
|
CLOUDFLARE_ACCOUNT_ID: env.CLOUDFLARE_ACCOUNT_ID || process.env.CLOUDFLARE_ACCOUNT_ID || '',
|
|
333
514
|
NVIDIA_API_KEY: env.NVIDIA_API_KEY || process.env.NVIDIA_API_KEY || '',
|
|
334
515
|
// Anthropic Authentication
|
|
335
|
-
ANTHROPIC_AUTH_METHOD: env.ANTHROPIC_AUTH_METHOD || process.env.ANTHROPIC_AUTH_METHOD ||
|
|
516
|
+
ANTHROPIC_AUTH_METHOD: env.ANTHROPIC_AUTH_METHOD || process.env.ANTHROPIC_AUTH_METHOD || D.ANTHROPIC_AUTH_METHOD,
|
|
336
517
|
CLAUDE_CODE_OAUTH_TOKEN: env.CLAUDE_CODE_OAUTH_TOKEN || process.env.CLAUDE_CODE_OAUTH_TOKEN || '',
|
|
337
518
|
// Prompt Caching
|
|
338
|
-
ANTHROPIC_PROMPT_CACHING: env.ANTHROPIC_PROMPT_CACHING || process.env.ANTHROPIC_PROMPT_CACHING ||
|
|
519
|
+
ANTHROPIC_PROMPT_CACHING: env.ANTHROPIC_PROMPT_CACHING || process.env.ANTHROPIC_PROMPT_CACHING || D.ANTHROPIC_PROMPT_CACHING,
|
|
339
520
|
// Model Configuration
|
|
340
|
-
DEFAULT_MODEL_ID: env.DEFAULT_MODEL_ID ||
|
|
341
|
-
HELPER_MODEL_ID: env.HELPER_MODEL_ID ||
|
|
521
|
+
DEFAULT_MODEL_ID: env.DEFAULT_MODEL_ID || D.DEFAULT_MODEL_ID,
|
|
522
|
+
HELPER_MODEL_ID: env.HELPER_MODEL_ID || D.HELPER_MODEL_ID,
|
|
342
523
|
// System Settings
|
|
343
|
-
DEBUG: env.DEBUG ||
|
|
344
|
-
USE_EMOJI: env.USE_EMOJI ||
|
|
345
|
-
PROJECT_PATH: env.PROJECT_PATH ||
|
|
524
|
+
DEBUG: env.DEBUG || D.DEBUG,
|
|
525
|
+
USE_EMOJI: env.USE_EMOJI || D.USE_EMOJI,
|
|
526
|
+
PROJECT_PATH: env.PROJECT_PATH || D.PROJECT_PATH,
|
|
346
527
|
// Reactive Mentorship
|
|
347
|
-
MENTORSHIP_ENABLED: env.MENTORSHIP_ENABLED ||
|
|
348
|
-
MENTORSHIP_TRIGGER_ON_ERROR: env.MENTORSHIP_TRIGGER_ON_ERROR ||
|
|
349
|
-
MENTORSHIP_ERROR_THRESHOLD: env.MENTORSHIP_ERROR_THRESHOLD ||
|
|
350
|
-
MENTORSHIP_KEYWORDS_ENABLED: env.MENTORSHIP_KEYWORDS_ENABLED ||
|
|
351
|
-
MENTORSHIP_CUSTOM_KEYWORDS: env.MENTORSHIP_CUSTOM_KEYWORDS ||
|
|
352
|
-
MENTORSHIP_HELPER_MODEL: env.MENTORSHIP_HELPER_MODEL ||
|
|
353
|
-
MENTORSHIP_TURN_BASED_ENABLED: env.MENTORSHIP_TURN_BASED_ENABLED ||
|
|
354
|
-
MENTORSHIP_TURN_INTERVAL: env.MENTORSHIP_TURN_INTERVAL ||
|
|
355
|
-
MENTORSHIP_INTERLEAVED_THINKING: env.MENTORSHIP_INTERLEAVED_THINKING ||
|
|
356
|
-
MENTORSHIP_PATTERN_DETECTION: env.MENTORSHIP_PATTERN_DETECTION ||
|
|
357
|
-
MENTORSHIP_PATTERN_THRESHOLD: env.MENTORSHIP_PATTERN_THRESHOLD ||
|
|
358
|
-
MENTORSHIP_ACTIVE_DISCOVERY: env.MENTORSHIP_ACTIVE_DISCOVERY ||
|
|
528
|
+
MENTORSHIP_ENABLED: env.MENTORSHIP_ENABLED || D.MENTORSHIP_ENABLED,
|
|
529
|
+
MENTORSHIP_TRIGGER_ON_ERROR: env.MENTORSHIP_TRIGGER_ON_ERROR || D.MENTORSHIP_TRIGGER_ON_ERROR,
|
|
530
|
+
MENTORSHIP_ERROR_THRESHOLD: env.MENTORSHIP_ERROR_THRESHOLD || D.MENTORSHIP_ERROR_THRESHOLD,
|
|
531
|
+
MENTORSHIP_KEYWORDS_ENABLED: env.MENTORSHIP_KEYWORDS_ENABLED || D.MENTORSHIP_KEYWORDS_ENABLED,
|
|
532
|
+
MENTORSHIP_CUSTOM_KEYWORDS: env.MENTORSHIP_CUSTOM_KEYWORDS || D.MENTORSHIP_CUSTOM_KEYWORDS,
|
|
533
|
+
MENTORSHIP_HELPER_MODEL: env.MENTORSHIP_HELPER_MODEL || D.MENTORSHIP_HELPER_MODEL,
|
|
534
|
+
MENTORSHIP_TURN_BASED_ENABLED: env.MENTORSHIP_TURN_BASED_ENABLED || D.MENTORSHIP_TURN_BASED_ENABLED,
|
|
535
|
+
MENTORSHIP_TURN_INTERVAL: env.MENTORSHIP_TURN_INTERVAL || D.MENTORSHIP_TURN_INTERVAL,
|
|
536
|
+
MENTORSHIP_INTERLEAVED_THINKING: env.MENTORSHIP_INTERLEAVED_THINKING || D.MENTORSHIP_INTERLEAVED_THINKING,
|
|
537
|
+
MENTORSHIP_PATTERN_DETECTION: env.MENTORSHIP_PATTERN_DETECTION || D.MENTORSHIP_PATTERN_DETECTION,
|
|
538
|
+
MENTORSHIP_PATTERN_THRESHOLD: env.MENTORSHIP_PATTERN_THRESHOLD || D.MENTORSHIP_PATTERN_THRESHOLD,
|
|
539
|
+
MENTORSHIP_ACTIVE_DISCOVERY: env.MENTORSHIP_ACTIVE_DISCOVERY || D.MENTORSHIP_ACTIVE_DISCOVERY,
|
|
359
540
|
// Turn Summary & Prediction
|
|
360
|
-
TURN_SUMMARY_PREDICTION: env.TURN_SUMMARY_PREDICTION ||
|
|
541
|
+
TURN_SUMMARY_PREDICTION: env.TURN_SUMMARY_PREDICTION || D.TURN_SUMMARY_PREDICTION,
|
|
361
542
|
// Canon (reactive session capture)
|
|
362
|
-
CANON_AUTO_SYNC: env.CANON_AUTO_SYNC || process.env.CANON_AUTO_SYNC ||
|
|
363
|
-
CANON_AUTO_SYNC_DEBOUNCE_MS: env.CANON_AUTO_SYNC_DEBOUNCE_MS || process.env.CANON_AUTO_SYNC_DEBOUNCE_MS ||
|
|
364
|
-
CANON_STORE: env.CANON_STORE || process.env.CANON_STORE ||
|
|
365
|
-
CANON_REPO: env.CANON_REPO || process.env.CANON_REPO ||
|
|
543
|
+
CANON_AUTO_SYNC: env.CANON_AUTO_SYNC || process.env.CANON_AUTO_SYNC || D.CANON_AUTO_SYNC,
|
|
544
|
+
CANON_AUTO_SYNC_DEBOUNCE_MS: env.CANON_AUTO_SYNC_DEBOUNCE_MS || process.env.CANON_AUTO_SYNC_DEBOUNCE_MS || D.CANON_AUTO_SYNC_DEBOUNCE_MS,
|
|
545
|
+
CANON_STORE: env.CANON_STORE || process.env.CANON_STORE || D.CANON_STORE,
|
|
546
|
+
CANON_REPO: env.CANON_REPO || process.env.CANON_REPO || D.CANON_REPO,
|
|
366
547
|
// Context Management
|
|
367
|
-
THINKING_AS_TEXT_FALLBACK: env.THINKING_AS_TEXT_FALLBACK || process.env.THINKING_AS_TEXT_FALLBACK ||
|
|
548
|
+
THINKING_AS_TEXT_FALLBACK: env.THINKING_AS_TEXT_FALLBACK || process.env.THINKING_AS_TEXT_FALLBACK || D.THINKING_AS_TEXT_FALLBACK,
|
|
368
549
|
// Session Configuration
|
|
369
|
-
SESSION_STORAGE_DIR: env.SESSION_STORAGE_DIR ||
|
|
370
|
-
MCP_AUTO_INJECT: env.MCP_AUTO_INJECT ||
|
|
371
|
-
AUTORESEARCH_AGENTS: env.AUTORESEARCH_AGENTS ||
|
|
372
|
-
SYSTEM_MESSAGE_DOC_MAX_BYTES: env.SYSTEM_MESSAGE_DOC_MAX_BYTES ||
|
|
373
|
-
MEMORY_ARCHIVE_MAX_BYTES: env.MEMORY_ARCHIVE_MAX_BYTES ||
|
|
550
|
+
SESSION_STORAGE_DIR: env.SESSION_STORAGE_DIR || D.SESSION_STORAGE_DIR,
|
|
551
|
+
MCP_AUTO_INJECT: env.MCP_AUTO_INJECT || D.MCP_AUTO_INJECT,
|
|
552
|
+
AUTORESEARCH_AGENTS: env.AUTORESEARCH_AGENTS || D.AUTORESEARCH_AGENTS,
|
|
553
|
+
SYSTEM_MESSAGE_DOC_MAX_BYTES: env.SYSTEM_MESSAGE_DOC_MAX_BYTES || D.SYSTEM_MESSAGE_DOC_MAX_BYTES,
|
|
554
|
+
MEMORY_ARCHIVE_MAX_BYTES: env.MEMORY_ARCHIVE_MAX_BYTES || D.MEMORY_ARCHIVE_MAX_BYTES,
|
|
374
555
|
// Loop Control
|
|
375
|
-
MAX_TOOL_ITERATIONS: env.MAX_TOOL_ITERATIONS ||
|
|
376
|
-
MAX_CONSECUTIVE_ERRORS: env.MAX_CONSECUTIVE_ERRORS ||
|
|
377
|
-
TOOL_BUDGET_SOFT: env.TOOL_BUDGET_SOFT ||
|
|
378
|
-
TOOL_TIMEOUT_MS: env.TOOL_TIMEOUT_MS ||
|
|
379
|
-
MAX_LOOP_REPETITIONS: env.MAX_LOOP_REPETITIONS ||
|
|
556
|
+
MAX_TOOL_ITERATIONS: env.MAX_TOOL_ITERATIONS || D.MAX_TOOL_ITERATIONS,
|
|
557
|
+
MAX_CONSECUTIVE_ERRORS: env.MAX_CONSECUTIVE_ERRORS || D.MAX_CONSECUTIVE_ERRORS,
|
|
558
|
+
TOOL_BUDGET_SOFT: env.TOOL_BUDGET_SOFT || D.TOOL_BUDGET_SOFT,
|
|
559
|
+
TOOL_TIMEOUT_MS: env.TOOL_TIMEOUT_MS || D.TOOL_TIMEOUT_MS,
|
|
560
|
+
MAX_LOOP_REPETITIONS: env.MAX_LOOP_REPETITIONS || D.MAX_LOOP_REPETITIONS,
|
|
380
561
|
// Web Tools
|
|
381
|
-
WEB_TOOLS_MODEL: env.WEB_TOOLS_MODEL || process.env.WEB_TOOLS_MODEL ||
|
|
562
|
+
WEB_TOOLS_MODEL: env.WEB_TOOLS_MODEL || process.env.WEB_TOOLS_MODEL || D.WEB_TOOLS_MODEL,
|
|
382
563
|
// Server-Side Tools
|
|
383
|
-
ENABLE_SERVER_SIDE_TOOLS: env.ENABLE_SERVER_SIDE_TOOLS || process.env.ENABLE_SERVER_SIDE_TOOLS ||
|
|
384
|
-
XAI_API_MODE: env.XAI_API_MODE || process.env.XAI_API_MODE ||
|
|
385
|
-
OPENAI_API_MODE: env.OPENAI_API_MODE || process.env.OPENAI_API_MODE ||
|
|
564
|
+
ENABLE_SERVER_SIDE_TOOLS: env.ENABLE_SERVER_SIDE_TOOLS || process.env.ENABLE_SERVER_SIDE_TOOLS || D.ENABLE_SERVER_SIDE_TOOLS,
|
|
565
|
+
XAI_API_MODE: env.XAI_API_MODE || process.env.XAI_API_MODE || D.XAI_API_MODE,
|
|
566
|
+
OPENAI_API_MODE: env.OPENAI_API_MODE || process.env.OPENAI_API_MODE || D.OPENAI_API_MODE,
|
|
386
567
|
// Agent Team Monitoring
|
|
387
|
-
AGENT_TMUX_MONITOR: env.AGENT_TMUX_MONITOR || process.env.AGENT_TMUX_MONITOR ||
|
|
568
|
+
AGENT_TMUX_MONITOR: env.AGENT_TMUX_MONITOR || process.env.AGENT_TMUX_MONITOR || D.AGENT_TMUX_MONITOR,
|
|
388
569
|
// PTC / Code Execution / Deferred Loading
|
|
389
|
-
ENABLE_PTC: env.ENABLE_PTC || process.env.ENABLE_PTC ||
|
|
390
|
-
ENABLE_WEBTOOLS: env.ENABLE_WEBTOOLS || process.env.ENABLE_WEBTOOLS ||
|
|
391
|
-
VISION_HELPER_MODEL: env.VISION_HELPER_MODEL || process.env.VISION_HELPER_MODEL ||
|
|
392
|
-
TOOL_TIMEOUT_MODE: env.TOOL_TIMEOUT_MODE || process.env.TOOL_TIMEOUT_MODE ||
|
|
393
|
-
VISION_HANDOFF_MAX: env.VISION_HANDOFF_MAX || process.env.VISION_HANDOFF_MAX ||
|
|
394
|
-
CORTEX_SLICE_NUDGE: env.CORTEX_SLICE_NUDGE || process.env.CORTEX_SLICE_NUDGE ||
|
|
395
|
-
ENABLE_LOCAL_CODE_EXECUTION: env.ENABLE_LOCAL_CODE_EXECUTION || process.env.ENABLE_LOCAL_CODE_EXECUTION ||
|
|
396
|
-
ENABLE_DEFERRED_TOOL_LOADING: env.ENABLE_DEFERRED_TOOL_LOADING || process.env.ENABLE_DEFERRED_TOOL_LOADING ||
|
|
570
|
+
ENABLE_PTC: env.ENABLE_PTC || process.env.ENABLE_PTC || D.ENABLE_PTC,
|
|
571
|
+
ENABLE_WEBTOOLS: env.ENABLE_WEBTOOLS || process.env.ENABLE_WEBTOOLS || D.ENABLE_WEBTOOLS,
|
|
572
|
+
VISION_HELPER_MODEL: env.VISION_HELPER_MODEL || process.env.VISION_HELPER_MODEL || D.VISION_HELPER_MODEL,
|
|
573
|
+
TOOL_TIMEOUT_MODE: env.TOOL_TIMEOUT_MODE || process.env.TOOL_TIMEOUT_MODE || D.TOOL_TIMEOUT_MODE,
|
|
574
|
+
VISION_HANDOFF_MAX: env.VISION_HANDOFF_MAX || process.env.VISION_HANDOFF_MAX || D.VISION_HANDOFF_MAX,
|
|
575
|
+
CORTEX_SLICE_NUDGE: env.CORTEX_SLICE_NUDGE || process.env.CORTEX_SLICE_NUDGE || D.CORTEX_SLICE_NUDGE,
|
|
576
|
+
ENABLE_LOCAL_CODE_EXECUTION: env.ENABLE_LOCAL_CODE_EXECUTION || process.env.ENABLE_LOCAL_CODE_EXECUTION || D.ENABLE_LOCAL_CODE_EXECUTION,
|
|
577
|
+
ENABLE_DEFERRED_TOOL_LOADING: env.ENABLE_DEFERRED_TOOL_LOADING || process.env.ENABLE_DEFERRED_TOOL_LOADING || D.ENABLE_DEFERRED_TOOL_LOADING,
|
|
397
578
|
// Model Router
|
|
398
|
-
MODEL_ROUTER_ENABLED: env.MODEL_ROUTER_ENABLED || process.env.MODEL_ROUTER_ENABLED ||
|
|
399
|
-
MODEL_ROUTER_STRATEGY: env.MODEL_ROUTER_STRATEGY || process.env.MODEL_ROUTER_STRATEGY ||
|
|
400
|
-
MODEL_ROUTER_RECORD: env.MODEL_ROUTER_RECORD || process.env.MODEL_ROUTER_RECORD ||
|
|
401
|
-
ROUTER_MIN_CONFIDENCE: env.ROUTER_MIN_CONFIDENCE || process.env.ROUTER_MIN_CONFIDENCE ||
|
|
402
|
-
ROUTER_MIN_SAMPLES: env.ROUTER_MIN_SAMPLES || process.env.ROUTER_MIN_SAMPLES ||
|
|
403
|
-
MODEL_ROUTER_EXPLORATION: env.MODEL_ROUTER_EXPLORATION || process.env.MODEL_ROUTER_EXPLORATION ||
|
|
404
|
-
MODEL_ROUTER_EXCLUDE: env.MODEL_ROUTER_EXCLUDE ?? process.env.MODEL_ROUTER_EXCLUDE ??
|
|
579
|
+
MODEL_ROUTER_ENABLED: env.MODEL_ROUTER_ENABLED || process.env.MODEL_ROUTER_ENABLED || D.MODEL_ROUTER_ENABLED,
|
|
580
|
+
MODEL_ROUTER_STRATEGY: env.MODEL_ROUTER_STRATEGY || process.env.MODEL_ROUTER_STRATEGY || D.MODEL_ROUTER_STRATEGY,
|
|
581
|
+
MODEL_ROUTER_RECORD: env.MODEL_ROUTER_RECORD || process.env.MODEL_ROUTER_RECORD || D.MODEL_ROUTER_RECORD,
|
|
582
|
+
ROUTER_MIN_CONFIDENCE: env.ROUTER_MIN_CONFIDENCE || process.env.ROUTER_MIN_CONFIDENCE || D.ROUTER_MIN_CONFIDENCE,
|
|
583
|
+
ROUTER_MIN_SAMPLES: env.ROUTER_MIN_SAMPLES || process.env.ROUTER_MIN_SAMPLES || D.ROUTER_MIN_SAMPLES,
|
|
584
|
+
MODEL_ROUTER_EXPLORATION: env.MODEL_ROUTER_EXPLORATION || process.env.MODEL_ROUTER_EXPLORATION || D.MODEL_ROUTER_EXPLORATION,
|
|
585
|
+
MODEL_ROUTER_EXCLUDE: env.MODEL_ROUTER_EXCLUDE ?? process.env.MODEL_ROUTER_EXCLUDE ?? D.MODEL_ROUTER_EXCLUDE,
|
|
405
586
|
// Endturn Gate / Training
|
|
406
|
-
CORTEX_ENDTURN_GATE: env.CORTEX_ENDTURN_GATE || process.env.CORTEX_ENDTURN_GATE ||
|
|
407
|
-
CORTEX_TOOL_PROFILE: env.CORTEX_TOOL_PROFILE || process.env.CORTEX_TOOL_PROFILE ||
|
|
587
|
+
CORTEX_ENDTURN_GATE: env.CORTEX_ENDTURN_GATE || process.env.CORTEX_ENDTURN_GATE || D.CORTEX_ENDTURN_GATE,
|
|
588
|
+
CORTEX_TOOL_PROFILE: env.CORTEX_TOOL_PROFILE || process.env.CORTEX_TOOL_PROFILE || D.CORTEX_TOOL_PROFILE,
|
|
408
589
|
// Decision Store
|
|
409
|
-
CORTEX_RECORD_DECISIONS: env.CORTEX_RECORD_DECISIONS || process.env.CORTEX_RECORD_DECISIONS ||
|
|
410
|
-
CORTEX_LOOKUP_PRIOR_DECISIONS: env.CORTEX_LOOKUP_PRIOR_DECISIONS || process.env.CORTEX_LOOKUP_PRIOR_DECISIONS ||
|
|
411
|
-
CORTEX_DECISIONS_MAX_BYTES: env.CORTEX_DECISIONS_MAX_BYTES || process.env.CORTEX_DECISIONS_MAX_BYTES ||
|
|
590
|
+
CORTEX_RECORD_DECISIONS: env.CORTEX_RECORD_DECISIONS || process.env.CORTEX_RECORD_DECISIONS || D.CORTEX_RECORD_DECISIONS,
|
|
591
|
+
CORTEX_LOOKUP_PRIOR_DECISIONS: env.CORTEX_LOOKUP_PRIOR_DECISIONS || process.env.CORTEX_LOOKUP_PRIOR_DECISIONS || D.CORTEX_LOOKUP_PRIOR_DECISIONS,
|
|
592
|
+
CORTEX_DECISIONS_MAX_BYTES: env.CORTEX_DECISIONS_MAX_BYTES || process.env.CORTEX_DECISIONS_MAX_BYTES || D.CORTEX_DECISIONS_MAX_BYTES,
|
|
412
593
|
// Runtime
|
|
413
|
-
CORTEX_MODE: env.CORTEX_MODE ||
|
|
414
|
-
CORTEX_UPDATE_POLICY: env.CORTEX_UPDATE_POLICY || process.env.CORTEX_UPDATE_POLICY ||
|
|
415
|
-
YOLO: env.YOLO || process.env.YOLO ||
|
|
416
|
-
AUTO_RESUME: env.AUTO_RESUME || process.env.AUTO_RESUME ||
|
|
417
|
-
PORT: env.PORT || process.env.PORT ||
|
|
418
|
-
CORTEX_SERVER_URL: env.CORTEX_SERVER_URL ||
|
|
419
|
-
DEBUG_PAYLOAD: env.DEBUG_PAYLOAD || process.env.DEBUG_PAYLOAD ||
|
|
420
|
-
DEBUG_THINKING: env.DEBUG_THINKING || process.env.DEBUG_THINKING ||
|
|
421
|
-
ENABLE_SMOKE_TESTS: env.ENABLE_SMOKE_TESTS || process.env.ENABLE_SMOKE_TESTS ||
|
|
594
|
+
CORTEX_MODE: env.CORTEX_MODE || D.CORTEX_MODE,
|
|
595
|
+
CORTEX_UPDATE_POLICY: env.CORTEX_UPDATE_POLICY || process.env.CORTEX_UPDATE_POLICY || D.CORTEX_UPDATE_POLICY,
|
|
596
|
+
YOLO: env.YOLO || process.env.YOLO || D.YOLO,
|
|
597
|
+
AUTO_RESUME: env.AUTO_RESUME || process.env.AUTO_RESUME || D.AUTO_RESUME,
|
|
598
|
+
PORT: env.PORT || process.env.PORT || D.PORT,
|
|
599
|
+
CORTEX_SERVER_URL: env.CORTEX_SERVER_URL || D.CORTEX_SERVER_URL,
|
|
600
|
+
DEBUG_PAYLOAD: env.DEBUG_PAYLOAD || process.env.DEBUG_PAYLOAD || D.DEBUG_PAYLOAD,
|
|
601
|
+
DEBUG_THINKING: env.DEBUG_THINKING || process.env.DEBUG_THINKING || D.DEBUG_THINKING,
|
|
602
|
+
ENABLE_SMOKE_TESTS: env.ENABLE_SMOKE_TESTS || process.env.ENABLE_SMOKE_TESTS || D.ENABLE_SMOKE_TESTS,
|
|
422
603
|
// Git / PR access control
|
|
423
|
-
GIT_ALLOWED_REPOS: env.GIT_ALLOWED_REPOS || process.env.GIT_ALLOWED_REPOS ||
|
|
424
|
-
GIT_ALLOWED_ACTIONS: env.GIT_ALLOWED_ACTIONS || process.env.GIT_ALLOWED_ACTIONS ||
|
|
604
|
+
GIT_ALLOWED_REPOS: env.GIT_ALLOWED_REPOS || process.env.GIT_ALLOWED_REPOS || D.GIT_ALLOWED_REPOS,
|
|
605
|
+
GIT_ALLOWED_ACTIONS: env.GIT_ALLOWED_ACTIONS || process.env.GIT_ALLOWED_ACTIONS || D.GIT_ALLOWED_ACTIONS,
|
|
425
606
|
GIT_AUTH_TOKEN: env.GIT_AUTH_TOKEN || process.env.GIT_AUTH_TOKEN || '',
|
|
426
|
-
GIT_HOST: env.GIT_HOST || process.env.GIT_HOST ||
|
|
607
|
+
GIT_HOST: env.GIT_HOST || process.env.GIT_HOST || D.GIT_HOST,
|
|
427
608
|
GITHUB_WEBHOOK_SECRET: env.GITHUB_WEBHOOK_SECRET || process.env.GITHUB_WEBHOOK_SECRET || '',
|
|
428
609
|
};
|
|
429
610
|
}
|
|
@@ -581,27 +762,46 @@ export class SettingsLoader {
|
|
|
581
762
|
return results;
|
|
582
763
|
}
|
|
583
764
|
/**
|
|
584
|
-
*
|
|
765
|
+
* Remove a setting's override line (reset-to-default). Deletes the user's override so
|
|
766
|
+
* the lever falls back to the shipped `.env.defaults` — the correct reset in the
|
|
767
|
+
* read-live model (writing the current default value would re-freeze it).
|
|
585
768
|
*/
|
|
769
|
+
remove(key) {
|
|
770
|
+
const result = removeEnvSetting(this.projectPath, key);
|
|
771
|
+
if (result.success)
|
|
772
|
+
this.reload();
|
|
773
|
+
return result;
|
|
774
|
+
}
|
|
775
|
+
/** Alias — reset a single setting to the shipped default by removing the override. */
|
|
586
776
|
resetToDefault(key) {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
777
|
+
return this.remove(key);
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* True if this key is set as an override in the user's OWN .env file (vs flowing from
|
|
781
|
+
* the shipped .env.defaults). Powers the "your override / shipped default" display.
|
|
782
|
+
*/
|
|
783
|
+
isUserOverride(key) {
|
|
784
|
+
return readEnvFileAt(path.join(this.projectPath, '.env'))[key] !== undefined;
|
|
785
|
+
}
|
|
786
|
+
/** All keys the user has overridden in their own .env file (one read — for a display
|
|
787
|
+
* that needs to mark many rows without re-reading the file per row). */
|
|
788
|
+
getOverriddenKeys() {
|
|
789
|
+
return Object.keys(readEnvFileAt(path.join(this.projectPath, '.env')));
|
|
596
790
|
}
|
|
597
791
|
/**
|
|
598
|
-
* Reset all
|
|
792
|
+
* Reset all LEVERS to defaults by removing their override lines (API keys preserved),
|
|
793
|
+
* so every lever falls back to the shipped `.env.defaults`.
|
|
599
794
|
*/
|
|
600
795
|
resetAllToDefaults() {
|
|
601
796
|
const results = {};
|
|
602
|
-
|
|
603
|
-
|
|
797
|
+
const secretKeys = new Set(SETTINGS_METADATA.filter(m => m.secret).map(m => m.key));
|
|
798
|
+
const fileEnv = readEnvFileAt(path.join(this.projectPath, '.env'));
|
|
799
|
+
for (const key of Object.keys(fileEnv)) {
|
|
800
|
+
if (secretKeys.has(key))
|
|
801
|
+
continue; // preserve API keys
|
|
802
|
+
results[key] = removeEnvSetting(this.projectPath, key);
|
|
604
803
|
}
|
|
804
|
+
this.reload();
|
|
605
805
|
return results;
|
|
606
806
|
}
|
|
607
807
|
/**
|