@openlife/cli 1.7.10 → 1.7.12
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/dist/cli/ChatBanner.js +112 -0
- package/dist/cli/ChatTui.js +316 -0
- package/dist/cli/ConfigTui.js +418 -0
- package/dist/cli/MatrixRain.js +141 -0
- package/dist/cli/MatrixTheme.js +86 -0
- package/dist/cli/ProviderSelector.js +178 -0
- package/dist/index.js +66 -7
- package/dist/memory/MemoryProviderRegistry.js +5 -1
- package/dist/memory/MempalaceProvider.js +53 -5
- package/dist/memory/OmniMemory.js +9 -5
- package/dist/orchestrator/Brain.js +126 -13
- package/dist/orchestrator/Gatekeeper.js +46 -51
- package/dist/orchestrator/Gateway.js +149 -6
- package/dist/orchestrator/RuntimePolicy.js +28 -3
- package/dist/orchestrator/SquadCreator.js +15 -11
- package/dist/test_chat_tui.js +116 -0
- package/dist/test_config_tui.js +116 -0
- package/dist/test_gateway_fast_ack.js +66 -0
- package/dist/test_matrix_rain.js +69 -0
- package/dist/test_no_automatic_messages.js +64 -0
- package/package.json +9 -3
- package/scripts/reauth-providers.sh +205 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const assert = __importStar(require("assert"));
|
|
37
|
+
const Gateway_1 = require("./orchestrator/Gateway");
|
|
38
|
+
async function main() {
|
|
39
|
+
process.env.OPENLIFE_TELEGRAM_ALLOWED_USER_ID = '';
|
|
40
|
+
process.env.OPENLIFE_ENABLE_TTS = 'false';
|
|
41
|
+
const gateway = new Gateway_1.Gateway();
|
|
42
|
+
gateway.classifier = {
|
|
43
|
+
classify: async (_text) => ({ intent: 'KNOWLEDGE_RETRIEVAL', budget: 0.1 })
|
|
44
|
+
};
|
|
45
|
+
gateway.gatekeeper = {
|
|
46
|
+
routeTask: async (_task, _text, _userId) => {
|
|
47
|
+
await new Promise(resolve => setTimeout(resolve, 1200));
|
|
48
|
+
return 'FINAL_AGENT_RESPONSE_FROM_GPT55_PATH';
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const started = Date.now();
|
|
52
|
+
const result = await gateway.processTextForTestDetailed('1344110010', 'ola');
|
|
53
|
+
const totalMs = Date.now() - started;
|
|
54
|
+
assert.ok(result.ackMs !== null, 'ACK_NOT_SENT');
|
|
55
|
+
assert.ok(result.ackMs < 500, `ACK_TOO_SLOW_${result.ackMs}`);
|
|
56
|
+
assert.ok(result.events.length >= 2, `EXPECTED_ACK_AND_FINAL_EVENTS_${JSON.stringify(result.events)}`);
|
|
57
|
+
assert.strictEqual(result.events[0].kind, 'reply', 'FIRST_EVENT_SHOULD_BE_ACK_REPLY');
|
|
58
|
+
assert.ok(result.events[0].text.includes('processando'), `ACK_TEXT_UNEXPECTED_${result.events[0].text}`);
|
|
59
|
+
assert.strictEqual(result.finalText, 'FINAL_AGENT_RESPONSE_FROM_GPT55_PATH', `FINAL_TEXT_UNEXPECTED_${result.finalText}`);
|
|
60
|
+
assert.ok(totalMs >= 1100, 'TEST_STUB_DID_NOT_SIMULATE_SLOW_PATH');
|
|
61
|
+
console.log('TEST_GATEWAY_FAST_ACK_OK');
|
|
62
|
+
}
|
|
63
|
+
main().catch((err) => {
|
|
64
|
+
console.error('TEST_GATEWAY_FAST_ACK_FAIL:', err?.message || err);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/test_matrix_rain.ts
|
|
3
|
+
// Smoke tests for the Matrix theme + rain renderer.
|
|
4
|
+
// - banner renders deterministic plain-text shape under stripAnsi
|
|
5
|
+
// - inventory panel borders align (top/bottom widths match)
|
|
6
|
+
// - rain.start() in non-TTY returns no-op handle (no interval leak)
|
|
7
|
+
// - sampleFrame() produces requested dimensions
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const ChatBanner_1 = require("./cli/ChatBanner");
|
|
10
|
+
const MatrixRain_1 = require("./cli/MatrixRain");
|
|
11
|
+
const MatrixTheme_1 = require("./cli/MatrixTheme");
|
|
12
|
+
let failed = 0;
|
|
13
|
+
function check(label, condition, detail) {
|
|
14
|
+
if (condition) {
|
|
15
|
+
console.log(`✅ ${label}`);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
console.error(`❌ ${label}${detail ? ` — ${detail}` : ''}`);
|
|
19
|
+
failed++;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// 1. Banner contains the OPENLIFE letters
|
|
23
|
+
{
|
|
24
|
+
const plain = (0, MatrixTheme_1.stripAnsi)((0, ChatBanner_1.openlifeBanner)());
|
|
25
|
+
check('banner contains OPENLIFE letters (5 rows of █)', plain.includes('██████ ██████ ███████ ███ ██ ██ ██ ███████ ███████'));
|
|
26
|
+
check('banner has horizon line', plain.includes('▁'));
|
|
27
|
+
}
|
|
28
|
+
// 2. Inventory panel borders align
|
|
29
|
+
{
|
|
30
|
+
const stats = { version: 'v1.7.12', model: 'openai-cli/gpt-5.5', sessionId: 'TEST_SESSION', cwd: '/tmp', agents: 1, squads: 2, skills: 3, mcps: 4 };
|
|
31
|
+
const plain = (0, MatrixTheme_1.stripAnsi)((0, ChatBanner_1.inventoryPanel)(stats));
|
|
32
|
+
const lines = plain.split('\n').filter(Boolean);
|
|
33
|
+
const top = lines[0];
|
|
34
|
+
const bot = lines[lines.length - 1];
|
|
35
|
+
check('panel top and bottom widths match', top.length === bot.length, `top=${top.length} bot=${bot.length}`);
|
|
36
|
+
check('panel shows model', plain.includes('openai-cli/gpt-5.5'));
|
|
37
|
+
check('panel shows catalog counts', plain.includes('agents 1') && plain.includes('skills 3'));
|
|
38
|
+
}
|
|
39
|
+
// 3. bootOutput composes banner + panel + welcome
|
|
40
|
+
{
|
|
41
|
+
const stats = { version: 'v1.7.12', model: 'm', sessionId: 's', cwd: '/c', agents: 0, squads: 0, skills: 0, mcps: 0 };
|
|
42
|
+
const plain = (0, MatrixTheme_1.stripAnsi)((0, ChatBanner_1.bootOutput)(stats));
|
|
43
|
+
check('bootOutput contains banner OPENLIFE marker', plain.includes('██████'));
|
|
44
|
+
check('bootOutput contains welcome line', plain.includes('Welcome to OpenLife'));
|
|
45
|
+
check('bootOutput contains divider line', plain.includes('━'));
|
|
46
|
+
}
|
|
47
|
+
// 4. Rain in non-TTY env returns no-op handle
|
|
48
|
+
{
|
|
49
|
+
// We're running under node test runner — stdout.isTTY is false.
|
|
50
|
+
const handle = (0, MatrixRain_1.startRain)({ row: 1, col: 1, width: 10, height: 4 });
|
|
51
|
+
check('rain.isRunning() returns false in non-TTY', handle.isRunning() === false);
|
|
52
|
+
// stop() must be safe to call without state
|
|
53
|
+
handle.stop();
|
|
54
|
+
check('rain.stop() in non-TTY is a no-op (no throw)', true);
|
|
55
|
+
}
|
|
56
|
+
// 5. sampleFrame produces requested dimensions
|
|
57
|
+
{
|
|
58
|
+
const frame = (0, MatrixRain_1.sampleFrame)(10, 5);
|
|
59
|
+
const rows = frame.split('\n');
|
|
60
|
+
check('sampleFrame produces correct number of rows', rows.length === 5);
|
|
61
|
+
// Each row is at most 10 visible chars (after stripAnsi)
|
|
62
|
+
const plainRowLengths = rows.map(r => (0, MatrixTheme_1.stripAnsi)(r).length);
|
|
63
|
+
check('sampleFrame rows are at most width chars', plainRowLengths.every(n => n <= 10), `lengths=${plainRowLengths.join(',')}`);
|
|
64
|
+
}
|
|
65
|
+
if (failed > 0) {
|
|
66
|
+
console.error(`\n${failed} check(s) failed.`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
console.log('\nTEST_MATRIX_RAIN_OK');
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Regression: OpenLife chat surface must not return canned/automatic replies.
|
|
4
|
+
* The main ask/Gatekeeper path should invoke the configured model executor even
|
|
5
|
+
* for greetings; deterministic status commands remain explicit operational paths.
|
|
6
|
+
*/
|
|
7
|
+
function assertTrue(cond, label) {
|
|
8
|
+
if (!cond)
|
|
9
|
+
throw new Error(`ASSERT_FAILED[${label}]`);
|
|
10
|
+
}
|
|
11
|
+
function installBrainMock(mock) {
|
|
12
|
+
const brainPath = require.resolve('./orchestrator/Brain');
|
|
13
|
+
const orig = require.cache[brainPath];
|
|
14
|
+
require.cache[brainPath] = {
|
|
15
|
+
...orig,
|
|
16
|
+
exports: {
|
|
17
|
+
Brain: class {
|
|
18
|
+
isAnyProviderAvailable() { return true; }
|
|
19
|
+
async thinkFast(_systemPrompt, userMessage) {
|
|
20
|
+
mock.invocations += 1;
|
|
21
|
+
mock.lastUserMessage = userMessage;
|
|
22
|
+
return mock.reply;
|
|
23
|
+
}
|
|
24
|
+
async think(_systemPrompt, userMessage) {
|
|
25
|
+
mock.invocations += 1;
|
|
26
|
+
mock.lastUserMessage = userMessage;
|
|
27
|
+
return mock.reply;
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
return () => {
|
|
33
|
+
if (orig)
|
|
34
|
+
require.cache[brainPath] = orig;
|
|
35
|
+
else
|
|
36
|
+
delete require.cache[brainPath];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function main() {
|
|
40
|
+
process.env.OPENLIFE_OUTCOME_SIMULATION = 'off';
|
|
41
|
+
const mock = { invocations: 0, reply: 'MODEL_REPLY_FROM_GPT55_PATH' };
|
|
42
|
+
const restore = installBrainMock(mock);
|
|
43
|
+
try {
|
|
44
|
+
const { IntentClassifier } = require('./orchestrator/IntentClassifier');
|
|
45
|
+
const { Gatekeeper } = require('./orchestrator/Gatekeeper');
|
|
46
|
+
const classifier = new IntentClassifier();
|
|
47
|
+
const gatekeeper = new Gatekeeper();
|
|
48
|
+
const greeting = 'ola';
|
|
49
|
+
const task = await classifier.classify(greeting);
|
|
50
|
+
const response = await gatekeeper.routeTask(task, greeting, 'no-auto-test');
|
|
51
|
+
assertTrue(response === 'MODEL_REPLY_FROM_GPT55_PATH', 'greeting response comes from Brain/model path');
|
|
52
|
+
assertTrue(mock.invocations === 1, `Brain invoked exactly once for greeting (got ${mock.invocations})`);
|
|
53
|
+
assertTrue(mock.lastUserMessage === greeting, 'original greeting passed to model');
|
|
54
|
+
assertTrue(!/OpenLife online|Como posso ajudar|OPENLIFE ONLINE|Intenção desconhecida/.test(response), 'no canned chat text returned');
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
restore();
|
|
58
|
+
}
|
|
59
|
+
console.log('TEST_NO_AUTOMATIC_MESSAGES_OK');
|
|
60
|
+
}
|
|
61
|
+
main().catch((err) => {
|
|
62
|
+
console.error(err);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openlife/cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.12",
|
|
4
4
|
"description": "OPEN-LIFE Córtex Orquestrador Dual-Core",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -159,13 +159,19 @@
|
|
|
159
159
|
"test:status-command": "npm run build && node dist/test_status_command.js",
|
|
160
160
|
"test:logs-command": "npm run build && node dist/test_logs_command.js",
|
|
161
161
|
"test:agent-creator": "npm run build && node dist/test_agent_creator.js",
|
|
162
|
+
"test:matrix-rain": "npm run build && node dist/test_matrix_rain.js",
|
|
163
|
+
"test:chat-tui": "npm run build && node dist/test_chat_tui.js",
|
|
164
|
+
"test:config-tui": "npm run build && node dist/test_config_tui.js",
|
|
162
165
|
"pretest:all": "node scripts/clean-test-pollution.js",
|
|
163
|
-
"test:all": "npm run build && node dist/test_distribution_installability.js && node dist/test_orchestration_assets_lifecycle.js && node dist/test_openlife_runtime_source_truth.js && node dist/test_openlife_evolution_surface.js && node dist/test_openlife_routing_surface.js && node dist/test_openlife_auto_creator_routing.js && node dist/test_openlife_gatekeeper_routing.js && node dist/test_enterprise_agentic_core.js && node dist/test_admin_teams_networks.js && node dist/test_agent_team_skill_network.js && node dist/test_benchmark_engine.js && node dist/test_cli_service_commands.js && node dist/test_consequence_forecaster.js && node dist/test_conversation_memory.js && node dist/test_create_entities.js && node dist/test_designmd_import_registry.js && node dist/test_designmd_mode.js && node dist/test_designmd_mode_workspace.js && node dist/test_dream_organizer.js && node dist/test_dual_mode.js && node dist/test_governance.js && node dist/test_governance_advanced.js && node dist/test_install_flow.js && node dist/test_job_lifecycle.js && node dist/test_memory_orchestrator.js && node dist/test_memory_promotion.js && node dist/test_memory_retention.js && node dist/test_operating_system.js && node dist/test_optimization_loop.js && node dist/test_outcome_simulator.js && node dist/test_performance_scorecard.js && node dist/test_phase6_board.js && node dist/test_phase6_cadence.js && node dist/test_phase6_ops.js && node dist/test_release_gate.js && node dist/test_reversa_contracts_e2e.js && node dist/test_reversa_export_and_strict.js && node dist/test_reversa_full_execution.js && node dist/test_reversa_lite.js && node dist/test_runtime_policy.js && node dist/test_runtime_probe.js && node dist/test_runtime_registry.js && node dist/test_security_download_guard.js && node dist/test_service_command_surface.js && node dist/test_service_completion_policy.js && node dist/test_service_guardrails_delete.js && node dist/test_sources_import_ref.js && node dist/test_sources_scaffold.js && node dist/test_teammate_learning.js && node dist/test_telegram_delete_guardrail.js && node dist/test_daemon_sigterm.js && node dist/test_ask_exit.js && node dist/test_brain_error_diagnostics.js && node dist/test_cli_doc_parity.js && node dist/test_trigger_basic_auth.js && node dist/test_brain_fallback_chain.js && node dist/test_cli_help_surface.js && node dist/test_cli_diagnostics.js && node dist/test_cli_crud_roundtrip.js && node dist/test_subsystems_routing_governance.js && node dist/test_subsystems_org_state.js && node dist/test_subsystems_promotion_memory_assets.js && node dist/test_phase1_check_exit.js && node dist/test_install_flow_host_validation.js && node dist/test_dist_templates_layout.js && node dist/test_host_installer.js && node dist/test_host_uninstaller.js && node dist/test_install_wizard.js && node dist/test_multi_host_docs_parity.js && node dist/test_host_install_e2e.js && node dist/test_runtime_profile_oauth_only.js && node dist/test_atomic_writer.js && node dist/test_mission_checkpoint.js && node dist/test_workflow_parser.js && node dist/test_workflow_engine.js && node dist/test_workflow_e2e.js && node dist/test_distributed_lock.js && node dist/test_watchdog_heartbeat.js && node dist/test_runtime_health_backoff.js && node dist/test_queue_scheduler.js && node dist/test_squad_skill_creator.js && node dist/test_aiobuilder_cli_parity.js && node dist/test_catalog_quality.js && node dist/test_royal_stack_golden.js && node dist/test_capability_pack_schema.js && node dist/test_capability_genesis_engine.js && node dist/test_workflow_schema_backward_compat.js && node dist/test_service_mode_explicit_only.js && node dist/test_deep_research_capability.js && node dist/test_guided_creator_cli.js && node dist/test_governance_v13_policies.js && node dist/test_gateway_telegram_guardrails.js && node dist/test_cron_manager.js && node dist/test_profile_toolset_mcp.js && node dist/test_squad_skill_design_llm.js && node dist/test_workflow_condition_parser.js && node dist/test_security_download_and_scan.js && node dist/test_host_installers_gemini_codex.js && node dist/test_toolset_enforcement.js && node dist/test_creator_placeholders_completed.js && node dist/test_performance_latency.js && node dist/test_post_mission_evaluation.js && node dist/test_governance_scope_ledger.js && node dist/test_consequence_forecast_brain.js && node dist/test_remote_publish.js && node dist/test_process_sandbox.js && node dist/test_v15_e2e_integration.js && node dist/test_doctor_sandbox_check.js && node dist/test_task_executor_sandbox_optin.js && node dist/test_forecast_brain_wiring.js && node dist/test_status_command.js && node dist/test_logs_command.js && node dist/test_agent_creator.js",
|
|
164
|
-
"prepublishOnly": "npm run test:all"
|
|
166
|
+
"test:all": "npm run build && node dist/test_distribution_installability.js && node dist/test_orchestration_assets_lifecycle.js && node dist/test_openlife_runtime_source_truth.js && node dist/test_openlife_evolution_surface.js && node dist/test_openlife_routing_surface.js && node dist/test_openlife_auto_creator_routing.js && node dist/test_openlife_gatekeeper_routing.js && node dist/test_enterprise_agentic_core.js && node dist/test_admin_teams_networks.js && node dist/test_agent_team_skill_network.js && node dist/test_benchmark_engine.js && node dist/test_cli_service_commands.js && node dist/test_consequence_forecaster.js && node dist/test_conversation_memory.js && node dist/test_create_entities.js && node dist/test_designmd_import_registry.js && node dist/test_designmd_mode.js && node dist/test_designmd_mode_workspace.js && node dist/test_dream_organizer.js && node dist/test_dual_mode.js && node dist/test_governance.js && node dist/test_governance_advanced.js && node dist/test_install_flow.js && node dist/test_job_lifecycle.js && node dist/test_memory_orchestrator.js && node dist/test_memory_promotion.js && node dist/test_memory_retention.js && node dist/test_operating_system.js && node dist/test_optimization_loop.js && node dist/test_outcome_simulator.js && node dist/test_performance_scorecard.js && node dist/test_phase6_board.js && node dist/test_phase6_cadence.js && node dist/test_phase6_ops.js && node dist/test_release_gate.js && node dist/test_reversa_contracts_e2e.js && node dist/test_reversa_export_and_strict.js && node dist/test_reversa_full_execution.js && node dist/test_reversa_lite.js && node dist/test_runtime_policy.js && node dist/test_runtime_probe.js && node dist/test_runtime_registry.js && node dist/test_security_download_guard.js && node dist/test_service_command_surface.js && node dist/test_service_completion_policy.js && node dist/test_service_guardrails_delete.js && node dist/test_sources_import_ref.js && node dist/test_sources_scaffold.js && node dist/test_teammate_learning.js && node dist/test_telegram_delete_guardrail.js && node dist/test_daemon_sigterm.js && node dist/test_ask_exit.js && node dist/test_brain_error_diagnostics.js && node dist/test_cli_doc_parity.js && node dist/test_trigger_basic_auth.js && node dist/test_brain_fallback_chain.js && node dist/test_cli_help_surface.js && node dist/test_cli_diagnostics.js && node dist/test_cli_crud_roundtrip.js && node dist/test_subsystems_routing_governance.js && node dist/test_subsystems_org_state.js && node dist/test_subsystems_promotion_memory_assets.js && node dist/test_phase1_check_exit.js && node dist/test_install_flow_host_validation.js && node dist/test_dist_templates_layout.js && node dist/test_host_installer.js && node dist/test_host_uninstaller.js && node dist/test_install_wizard.js && node dist/test_multi_host_docs_parity.js && node dist/test_host_install_e2e.js && node dist/test_runtime_profile_oauth_only.js && node dist/test_atomic_writer.js && node dist/test_mission_checkpoint.js && node dist/test_workflow_parser.js && node dist/test_workflow_engine.js && node dist/test_workflow_e2e.js && node dist/test_distributed_lock.js && node dist/test_watchdog_heartbeat.js && node dist/test_runtime_health_backoff.js && node dist/test_queue_scheduler.js && node dist/test_squad_skill_creator.js && node dist/test_aiobuilder_cli_parity.js && node dist/test_catalog_quality.js && node dist/test_royal_stack_golden.js && node dist/test_capability_pack_schema.js && node dist/test_capability_genesis_engine.js && node dist/test_workflow_schema_backward_compat.js && node dist/test_service_mode_explicit_only.js && node dist/test_deep_research_capability.js && node dist/test_guided_creator_cli.js && node dist/test_governance_v13_policies.js && node dist/test_gateway_telegram_guardrails.js && node dist/test_cron_manager.js && node dist/test_profile_toolset_mcp.js && node dist/test_squad_skill_design_llm.js && node dist/test_workflow_condition_parser.js && node dist/test_security_download_and_scan.js && node dist/test_host_installers_gemini_codex.js && node dist/test_toolset_enforcement.js && node dist/test_creator_placeholders_completed.js && node dist/test_performance_latency.js && node dist/test_post_mission_evaluation.js && node dist/test_governance_scope_ledger.js && node dist/test_consequence_forecast_brain.js && node dist/test_remote_publish.js && node dist/test_process_sandbox.js && node dist/test_v15_e2e_integration.js && node dist/test_doctor_sandbox_check.js && node dist/test_task_executor_sandbox_optin.js && node dist/test_forecast_brain_wiring.js && node dist/test_status_command.js && node dist/test_logs_command.js && node dist/test_agent_creator.js && node dist/test_matrix_rain.js && node dist/test_chat_tui.js && node dist/test_config_tui.js",
|
|
167
|
+
"prepublishOnly": "npm run test:all",
|
|
168
|
+
"test:no-automatic-messages": "npm run build && node dist/test_no_automatic_messages.js",
|
|
169
|
+
"test:gateway-fast-ack": "npm run build && node dist/test_gateway_fast_ack.js"
|
|
165
170
|
},
|
|
166
171
|
"dependencies": {
|
|
167
172
|
"@anthropic-ai/sdk": "^0.86.1",
|
|
168
173
|
"@google/generative-ai": "^0.24.1",
|
|
174
|
+
"@openai/codex": "^0.130.0",
|
|
169
175
|
"axios": "^1.15.0",
|
|
170
176
|
"commander": "^11.1.0",
|
|
171
177
|
"dotenv": "^16.3.1",
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/reauth-providers.sh
|
|
3
|
+
# Guided re-authentication for OpenLife LLM providers: Codex (gpt-5.5), Gemini, Anthropic.
|
|
4
|
+
# Idempotent. Per-provider menu (reauth/skip/edit-key). Validates each via real API call.
|
|
5
|
+
# Restarts daemon if running. Final status table.
|
|
6
|
+
|
|
7
|
+
set -u
|
|
8
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
9
|
+
cd "$ROOT"
|
|
10
|
+
|
|
11
|
+
# Matrix-green ANSI palette (matches the new TUI theme)
|
|
12
|
+
GREEN=$'\033[38;5;46m'
|
|
13
|
+
GREEN_HI=$'\033[38;5;82m\033[1m'
|
|
14
|
+
GREEN_DIM=$'\033[38;5;22m'
|
|
15
|
+
RED=$'\033[38;5;196m'
|
|
16
|
+
YELLOW=$'\033[38;5;226m'
|
|
17
|
+
RESET=$'\033[0m'
|
|
18
|
+
|
|
19
|
+
say() { printf '%s%s%s\n' "$GREEN" "$*" "$RESET"; }
|
|
20
|
+
hi() { printf '%s%s%s\n' "$GREEN_HI" "$*" "$RESET"; }
|
|
21
|
+
warn() { printf '%s%s%s\n' "$YELLOW" "$*" "$RESET"; }
|
|
22
|
+
err() { printf '%s%s%s\n' "$RED" "$*" "$RESET" 1>&2; }
|
|
23
|
+
hr() { printf '%s' "$GREEN_DIM"; printf '─%.0s' $(seq 1 60); printf '%s\n' "$RESET"; }
|
|
24
|
+
|
|
25
|
+
# ─────────────────────────────────────────────────────────────
|
|
26
|
+
# Probe — current credential state
|
|
27
|
+
# ─────────────────────────────────────────────────────────────
|
|
28
|
+
probe_codex() {
|
|
29
|
+
command -v codex >/dev/null 2>&1 || { echo "missing"; return; }
|
|
30
|
+
if codex login status 2>/dev/null | grep -qi 'logged in'; then
|
|
31
|
+
# Cached status doesn't guarantee the refresh token is valid. Do a 8s probe.
|
|
32
|
+
if timeout 8 codex exec --model gpt-5.5 --skip-git-repo-check 'OK' >/dev/null 2>&1; then
|
|
33
|
+
echo "ok"
|
|
34
|
+
else
|
|
35
|
+
echo "stale"
|
|
36
|
+
fi
|
|
37
|
+
else
|
|
38
|
+
echo "logged-out"
|
|
39
|
+
fi
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
probe_gemini() {
|
|
43
|
+
command -v gemini >/dev/null 2>&1 || { echo "missing"; return; }
|
|
44
|
+
if gemini login status 2>/dev/null | grep -qi 'logged in'; then
|
|
45
|
+
echo "ok"
|
|
46
|
+
else
|
|
47
|
+
echo "logged-out"
|
|
48
|
+
fi
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
probe_anthropic() {
|
|
52
|
+
local key
|
|
53
|
+
key="$(grep -E '^ANTHROPIC_API_KEY=' "$ROOT/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
|
54
|
+
if [[ -z "$key" ]]; then echo "missing"; return; fi
|
|
55
|
+
local code
|
|
56
|
+
code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 8 \
|
|
57
|
+
-H "x-api-key: $key" -H "anthropic-version: 2023-06-01" \
|
|
58
|
+
-H "content-type: application/json" \
|
|
59
|
+
-d '{"model":"claude-haiku-4-5","max_tokens":4,"messages":[{"role":"user","content":"ok"}]}' \
|
|
60
|
+
https://api.anthropic.com/v1/messages 2>/dev/null || echo 000)"
|
|
61
|
+
case "$code" in
|
|
62
|
+
200) echo "ok" ;;
|
|
63
|
+
401|403) echo "auth-bad" ;;
|
|
64
|
+
429) echo "rate-limited" ;;
|
|
65
|
+
*) echo "http-$code" ;;
|
|
66
|
+
esac
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
print_status_table() {
|
|
70
|
+
hr
|
|
71
|
+
printf '%s%-12s %-12s %s%s\n' "$GREEN_HI" "PROVIDER" "STATUS" "DETAIL" "$RESET"
|
|
72
|
+
hr
|
|
73
|
+
printf '%-12s %-12s %s\n' "codex" "$1" "(gpt-5.5 via Codex OAuth)"
|
|
74
|
+
printf '%-12s %-12s %s\n' "gemini" "$2" "(google-genai OAuth)"
|
|
75
|
+
printf '%-12s %-12s %s\n' "anthropic" "$3" "(ANTHROPIC_API_KEY in .env)"
|
|
76
|
+
hr
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ─────────────────────────────────────────────────────────────
|
|
80
|
+
# Per-provider menus
|
|
81
|
+
# ─────────────────────────────────────────────────────────────
|
|
82
|
+
menu_for() {
|
|
83
|
+
local name="$1" status="$2"
|
|
84
|
+
echo
|
|
85
|
+
hi "── $name ──"
|
|
86
|
+
echo " current status: $status"
|
|
87
|
+
echo " 1) reauth 2) skip 3) edit key (anthropic only)"
|
|
88
|
+
read -r -p " choose [1/2/3]: " choice
|
|
89
|
+
echo "$choice"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
reauth_codex() {
|
|
93
|
+
say "Logging out of Codex…"
|
|
94
|
+
codex logout 2>/dev/null || true
|
|
95
|
+
hi "Opening Codex login (browser). Complete the flow, then press ENTER here."
|
|
96
|
+
codex login || { err "codex login failed"; return 1; }
|
|
97
|
+
if timeout 12 codex exec --model gpt-5.5 --skip-git-repo-check 'OK' >/dev/null 2>&1; then
|
|
98
|
+
hi "✓ codex gpt-5.5 responding"
|
|
99
|
+
return 0
|
|
100
|
+
fi
|
|
101
|
+
err "codex still failing after login. Inspect: codex login status"
|
|
102
|
+
return 1
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
reauth_gemini() {
|
|
106
|
+
say "Logging out of Gemini…"
|
|
107
|
+
gemini logout 2>/dev/null || true
|
|
108
|
+
hi "Opening Gemini login (device-auth). Follow on-screen URL, then return."
|
|
109
|
+
gemini login --device-auth || { err "gemini login failed"; return 1; }
|
|
110
|
+
hi "✓ gemini login completed (quota state checked on next call)"
|
|
111
|
+
return 0
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
reauth_anthropic_edit_key() {
|
|
115
|
+
echo
|
|
116
|
+
warn "Paste your ANTHROPIC_API_KEY (sk-ant-…). Input is hidden."
|
|
117
|
+
read -r -s -p " key: " newkey
|
|
118
|
+
echo
|
|
119
|
+
[[ -z "$newkey" ]] && { warn "(empty — keeping current key)"; return 0; }
|
|
120
|
+
# Idempotent .env edit: remove existing line then append.
|
|
121
|
+
local envfile="$ROOT/.env"
|
|
122
|
+
touch "$envfile"
|
|
123
|
+
grep -v -E '^ANTHROPIC_API_KEY=' "$envfile" > "$envfile.tmp" 2>/dev/null || true
|
|
124
|
+
mv "$envfile.tmp" "$envfile"
|
|
125
|
+
printf 'ANTHROPIC_API_KEY=%s\n' "$newkey" >> "$envfile"
|
|
126
|
+
say "✓ .env updated"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# ─────────────────────────────────────────────────────────────
|
|
130
|
+
# Daemon restart helper
|
|
131
|
+
# ─────────────────────────────────────────────────────────────
|
|
132
|
+
maybe_restart_daemon() {
|
|
133
|
+
local snapshot
|
|
134
|
+
snapshot="$(node bin/openlife.js status 2>/dev/null || echo '{}')"
|
|
135
|
+
if echo "$snapshot" | grep -q '"fresh":true'; then
|
|
136
|
+
say "Daemon is running — restarting to pick up new credentials…"
|
|
137
|
+
node bin/openlife.js restart >/dev/null 2>&1 || true
|
|
138
|
+
nohup node bin/openlife.js start --daemon >/dev/null 2>&1 &
|
|
139
|
+
disown 2>/dev/null || true
|
|
140
|
+
# Give it 3 seconds to boot + revalidate executors
|
|
141
|
+
sleep 3
|
|
142
|
+
say "✓ daemon restarted"
|
|
143
|
+
else
|
|
144
|
+
say "Daemon not running — skipping restart"
|
|
145
|
+
fi
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# ─────────────────────────────────────────────────────────────
|
|
149
|
+
# Main
|
|
150
|
+
# ─────────────────────────────────────────────────────────────
|
|
151
|
+
hi "╔══════════════════════════════════════════════════════════╗"
|
|
152
|
+
hi "║ OPENLIFE · provider reauth ║"
|
|
153
|
+
hi "╚══════════════════════════════════════════════════════════╝"
|
|
154
|
+
say "Probing current credentials…"
|
|
155
|
+
|
|
156
|
+
CODEX="$(probe_codex)"
|
|
157
|
+
GEMINI="$(probe_gemini)"
|
|
158
|
+
ANTHROPIC="$(probe_anthropic)"
|
|
159
|
+
print_status_table "$CODEX" "$GEMINI" "$ANTHROPIC"
|
|
160
|
+
|
|
161
|
+
# Codex
|
|
162
|
+
case "$CODEX" in ok) say "codex already healthy — skipping menu" ;; *)
|
|
163
|
+
case "$(menu_for codex "$CODEX")" in
|
|
164
|
+
1) reauth_codex && CODEX=ok || CODEX=failed ;;
|
|
165
|
+
2) say "(skipped)" ;;
|
|
166
|
+
*) say "(skipped)" ;;
|
|
167
|
+
esac
|
|
168
|
+
;; esac
|
|
169
|
+
|
|
170
|
+
# Gemini
|
|
171
|
+
case "$GEMINI" in ok) say "gemini already healthy — skipping menu" ;; *)
|
|
172
|
+
case "$(menu_for gemini "$GEMINI")" in
|
|
173
|
+
1) reauth_gemini && GEMINI=ok || GEMINI=failed ;;
|
|
174
|
+
2) say "(skipped)" ;;
|
|
175
|
+
*) say "(skipped)" ;;
|
|
176
|
+
esac
|
|
177
|
+
;; esac
|
|
178
|
+
|
|
179
|
+
# Anthropic
|
|
180
|
+
case "$ANTHROPIC" in ok) say "anthropic already healthy — skipping menu" ;; *)
|
|
181
|
+
case "$(menu_for anthropic "$ANTHROPIC")" in
|
|
182
|
+
1|3) reauth_anthropic_edit_key
|
|
183
|
+
ANTHROPIC="$(probe_anthropic)" ;;
|
|
184
|
+
2) say "(skipped)" ;;
|
|
185
|
+
*) say "(skipped)" ;;
|
|
186
|
+
esac
|
|
187
|
+
;; esac
|
|
188
|
+
|
|
189
|
+
# Final state
|
|
190
|
+
echo
|
|
191
|
+
hi "── final state ──"
|
|
192
|
+
print_status_table "$CODEX" "$GEMINI" "$ANTHROPIC"
|
|
193
|
+
|
|
194
|
+
# Restart daemon if running so executors revalidate
|
|
195
|
+
maybe_restart_daemon
|
|
196
|
+
|
|
197
|
+
# Show status snapshot
|
|
198
|
+
echo
|
|
199
|
+
hi "── openlife status ──"
|
|
200
|
+
node bin/openlife.js status 2>/dev/null \
|
|
201
|
+
| node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>{try{const j=JSON.parse(d);console.log("heartbeat fresh:",j.heartbeat&&j.heartbeat.fresh);(j.executors||[]).forEach(e=>console.log(` ${e.executor.padEnd(8)} avail=${e.available} reason=${e.reason}`));}catch(e){console.error("status parse failed");}});' \
|
|
202
|
+
2>/dev/null || warn "status command unavailable"
|
|
203
|
+
|
|
204
|
+
# Exit code: 0 if at least one provider is ok
|
|
205
|
+
[[ "$CODEX" == "ok" || "$GEMINI" == "ok" || "$ANTHROPIC" == "ok" ]] && exit 0 || exit 1
|