@openlife/cli 1.7.13 → 1.8.2
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/INSTALL.md +29 -1
- package/dist/cli/ChatTui.js +32 -0
- package/dist/cli/InstallModules.js +17 -2
- package/dist/cli/InstallWizardV2.js +110 -0
- package/dist/cli/install/Multiselect.js +285 -0
- package/dist/cli/install/OAuthRunner.js +170 -0
- package/dist/cli/install/Phases.js +864 -0
- package/dist/cli/install/ProvidersCatalog.js +320 -0
- package/dist/cli/install/WizardIO.js +271 -0
- package/dist/cli/install/types.js +17 -0
- package/dist/index.js +170 -35
- package/dist/orchestrator/ConsequenceForecaster.js +24 -1
- package/dist/orchestrator/DreamGoalStore.js +130 -0
- package/dist/orchestrator/Gatekeeper.js +14 -0
- package/dist/orchestrator/Gateway.js +194 -15
- package/dist/orchestrator/ModelManager.js +7 -1
- package/dist/orchestrator/OrchestrationLoop.js +12 -0
- package/dist/orchestrator/ParallelOrchestrationLoop.js +12 -2
- package/dist/orchestrator/RuntimePolicy.js +4 -1
- package/dist/orchestrator/ServiceCompletionPolicy.js +15 -0
- package/dist/orchestrator/SynthesizerAgent.js +20 -1
- package/dist/orchestrator/TaskExecutor.js +53 -0
- package/dist/orchestrator/capability/CapabilityGenesisEngine.js +66 -11
- package/dist/test_capability_genesis_engine.js +1 -1
- package/dist/test_chat_smoke_command.js +59 -0
- package/dist/test_dream_goal_commands.js +76 -0
- package/dist/test_gateway_telegram_formatting.js +74 -0
- package/dist/test_install_wizard_v2.js +193 -0
- package/dist/test_on_demand_voice_reply.js +65 -0
- package/dist/test_remaining_sprints_contracts.js +103 -0
- package/dist/test_runtime_policy.js +25 -6
- package/dist/test_service_completion_policy.js +7 -0
- package/dist/test_subsystems_routing_governance.js +13 -3
- package/dist/test_task_executor_gemini_api.js +68 -0
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -76,6 +76,7 @@ const SystemDoctor_1 = require("./orchestrator/SystemDoctor");
|
|
|
76
76
|
const WorldClassCommands_1 = require("./cli/WorldClassCommands");
|
|
77
77
|
const InstallBanner_1 = require("./cli/InstallBanner");
|
|
78
78
|
const DreamOrganizer_1 = require("./cli/DreamOrganizer");
|
|
79
|
+
const DreamGoalStore_1 = require("./orchestrator/DreamGoalStore");
|
|
79
80
|
const InstallFlow_1 = require("./cli/InstallFlow");
|
|
80
81
|
const InstallWizard_1 = require("./cli/InstallWizard");
|
|
81
82
|
const InstallHeadless_1 = require("./cli/InstallHeadless");
|
|
@@ -236,6 +237,22 @@ program
|
|
|
236
237
|
.name('openlife')
|
|
237
238
|
.description('OPEN-LIFE Córtex Orquestrador (Dual-Core)')
|
|
238
239
|
.version(pkgVersion);
|
|
240
|
+
program
|
|
241
|
+
.command('dream [text...]')
|
|
242
|
+
.description('Define ou consulta a visão /dream atual do OpenLife')
|
|
243
|
+
.action((parts) => {
|
|
244
|
+
const store = new DreamGoalStore_1.DreamGoalStore();
|
|
245
|
+
const input = `/dream ${Array.isArray(parts) ? parts.join(' ') : ''}`.trim();
|
|
246
|
+
console.log(store.handleSlashCommand(input));
|
|
247
|
+
});
|
|
248
|
+
program
|
|
249
|
+
.command('goal [text...]')
|
|
250
|
+
.description('Define ou consulta a missão /goal atual do OpenLife')
|
|
251
|
+
.action((parts) => {
|
|
252
|
+
const store = new DreamGoalStore_1.DreamGoalStore();
|
|
253
|
+
const input = `/goal ${Array.isArray(parts) ? parts.join(' ') : ''}`.trim();
|
|
254
|
+
console.log(store.handleSlashCommand(input));
|
|
255
|
+
});
|
|
239
256
|
program
|
|
240
257
|
.command('install')
|
|
241
258
|
.description('Onboarding unificado: instala CLI ou Agente Autônomo')
|
|
@@ -296,46 +313,68 @@ program
|
|
|
296
313
|
// INIT — Interactive install wizard (Story 3.5)
|
|
297
314
|
// ============================================================================
|
|
298
315
|
program.command('init')
|
|
299
|
-
.description('Interactive install wizard —
|
|
300
|
-
.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
316
|
+
.description('Interactive install wizard — phase-based, sequential, multi-host (v2)')
|
|
317
|
+
.option('--legacy', 'use the v1 (batched-Q&A) wizard instead of v2 (sequential phases)')
|
|
318
|
+
.action(async (options) => {
|
|
319
|
+
if (options.legacy) {
|
|
320
|
+
// v1 wizard — kept for users who scripted around the old prompts.
|
|
321
|
+
console.log((0, InstallBanner_1.installationBanner)());
|
|
322
|
+
console.log('');
|
|
323
|
+
const { InstallWizard, ReadlineAnswerProvider } = require('./cli/InstallWizard');
|
|
324
|
+
const { InstallFlow } = require('./cli/InstallFlow');
|
|
325
|
+
const provider = new ReadlineAnswerProvider();
|
|
326
|
+
const wizard = new InstallWizard(process.cwd(), provider);
|
|
327
|
+
try {
|
|
328
|
+
const result = await wizard.run();
|
|
329
|
+
if (!result.ok) {
|
|
330
|
+
console.log(JSON.stringify(result, null, 2));
|
|
331
|
+
process.exitCode = result.reason === 'user_aborted' ? 0 : 1;
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const flow = new InstallFlow();
|
|
335
|
+
const installResult = flow.run(result.options);
|
|
336
|
+
for (const line of flow.renderSummary(installResult))
|
|
337
|
+
console.log(line);
|
|
338
|
+
if (result.warnings?.length) {
|
|
339
|
+
console.log('');
|
|
340
|
+
console.log('⚠️ Warnings:');
|
|
341
|
+
for (const w of result.warnings)
|
|
342
|
+
console.log(` - ${w}`);
|
|
343
|
+
}
|
|
320
344
|
console.log('');
|
|
321
|
-
console.log('
|
|
322
|
-
for (const w of result.warnings)
|
|
323
|
-
console.log(` - ${w}`);
|
|
345
|
+
console.log('✅ OpenLife ready (v1 wizard).');
|
|
324
346
|
}
|
|
347
|
+
finally {
|
|
348
|
+
provider.close?.();
|
|
349
|
+
}
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
// v2 wizard — phase-based, sequential, multi-host, multi-product.
|
|
353
|
+
// Banner is rendered by the first phase, not here.
|
|
354
|
+
const { InstallWizardV2 } = require('./cli/InstallWizardV2');
|
|
355
|
+
const wizard = new InstallWizardV2();
|
|
356
|
+
const result = await wizard.run();
|
|
357
|
+
if (!result.ok) {
|
|
325
358
|
console.log('');
|
|
326
|
-
console.log(
|
|
327
|
-
|
|
328
|
-
|
|
359
|
+
console.log(`Install wizard ended without finishing (${result.reason}${result.detail ? `: ${result.detail}` : ''}).`);
|
|
360
|
+
process.exitCode = result.reason === 'user_aborted' ? 0 : 1;
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
console.log('');
|
|
364
|
+
console.log('✅ OpenLife ready.');
|
|
365
|
+
console.log('');
|
|
366
|
+
console.log('Try:');
|
|
367
|
+
if (result.context.products.includes('openlife-core')) {
|
|
329
368
|
console.log(' openlife ask "hello, what can you do?"');
|
|
330
369
|
console.log(' openlife status');
|
|
331
|
-
console.log(' openlife --help');
|
|
332
|
-
console.log('');
|
|
333
|
-
console.log('Docs: https://github.com/GOOODZ/openlife-core');
|
|
334
370
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
371
|
+
if (result.context.products.includes('openlife-agent')) {
|
|
372
|
+
console.log(' openlife agent start --daemon');
|
|
373
|
+
console.log(' openlife agent status');
|
|
338
374
|
}
|
|
375
|
+
console.log(' openlife --help');
|
|
376
|
+
console.log('');
|
|
377
|
+
console.log('Docs: https://github.com/GOOODZ/openlife-core');
|
|
339
378
|
});
|
|
340
379
|
// ============================================================================
|
|
341
380
|
// OBSERVABILITY — `openlife status`, `openlife logs`
|
|
@@ -2825,6 +2864,91 @@ profileCmd.command('import <file>').description('Import a profile from a JSON fi
|
|
|
2825
2864
|
process.exitCode = 1;
|
|
2826
2865
|
}
|
|
2827
2866
|
});
|
|
2867
|
+
// `openlife telegram` — manage Telegram delivery mode (polling vs webhook)
|
|
2868
|
+
const telegramCmd = program
|
|
2869
|
+
.command('telegram')
|
|
2870
|
+
.description('Gerencia o modo de entrega do Telegram (polling vs webhook)');
|
|
2871
|
+
telegramCmd
|
|
2872
|
+
.command('status')
|
|
2873
|
+
.description('Mostra modo atual + webhook info')
|
|
2874
|
+
.action(async () => {
|
|
2875
|
+
const token = (process.env.TELEGRAM_BOT_TOKEN || '').trim();
|
|
2876
|
+
if (!token) {
|
|
2877
|
+
console.log(JSON.stringify({ ok: false, error: 'TELEGRAM_BOT_TOKEN ausente' }, null, 2));
|
|
2878
|
+
return;
|
|
2879
|
+
}
|
|
2880
|
+
const { execFileSync } = require('child_process');
|
|
2881
|
+
try {
|
|
2882
|
+
const raw = String(execFileSync('curl', ['-sS', '--max-time', '8', `https://api.telegram.org/bot${token}/getWebhookInfo`], { encoding: 'utf-8' })).trim();
|
|
2883
|
+
const j = JSON.parse(raw);
|
|
2884
|
+
const info = (j && j.result) || {};
|
|
2885
|
+
const mode = info.url ? 'webhook' : 'polling';
|
|
2886
|
+
const onRailway = !!(process.env.RAILWAY_ENVIRONMENT || process.env.RAILWAY_PUBLIC_DOMAIN || process.env.RAILWAY_STATIC_URL);
|
|
2887
|
+
const configured = String(process.env.OPENLIFE_TELEGRAM_MODE || 'auto').toLowerCase();
|
|
2888
|
+
console.log(JSON.stringify({
|
|
2889
|
+
ok: true,
|
|
2890
|
+
mode_telegram_thinks: mode,
|
|
2891
|
+
mode_configured: configured,
|
|
2892
|
+
railway_detected: onRailway,
|
|
2893
|
+
webhook_url: info.url || null,
|
|
2894
|
+
pending_updates: info.pending_update_count || 0,
|
|
2895
|
+
last_error: info.last_error_message || null,
|
|
2896
|
+
}, null, 2));
|
|
2897
|
+
}
|
|
2898
|
+
catch (e) {
|
|
2899
|
+
console.log(JSON.stringify({ ok: false, error: 'getWebhookInfo_failed', detail: e.message }, null, 2));
|
|
2900
|
+
process.exitCode = 1;
|
|
2901
|
+
}
|
|
2902
|
+
});
|
|
2903
|
+
telegramCmd
|
|
2904
|
+
.command('webhook-set <domain>')
|
|
2905
|
+
.description('Configura webhook (uso típico Railway). Ex: openlife telegram webhook-set https://app.up.railway.app')
|
|
2906
|
+
.option('--path <path>', 'Caminho do webhook (default: /api/v1/telegram/webhook)', '/api/v1/telegram/webhook')
|
|
2907
|
+
.action(async (domain, opts) => {
|
|
2908
|
+
const token = (process.env.TELEGRAM_BOT_TOKEN || '').trim();
|
|
2909
|
+
if (!token) {
|
|
2910
|
+
console.error('TELEGRAM_BOT_TOKEN ausente em .env');
|
|
2911
|
+
process.exitCode = 1;
|
|
2912
|
+
return;
|
|
2913
|
+
}
|
|
2914
|
+
const fullDomain = domain.startsWith('http') ? domain : `https://${domain}`;
|
|
2915
|
+
const url = `${fullDomain.replace(/\/$/, '')}${opts.path}`;
|
|
2916
|
+
const { execFileSync } = require('child_process');
|
|
2917
|
+
try {
|
|
2918
|
+
const raw = String(execFileSync('curl', ['-sS', '--max-time', '8', '-X', 'POST', '-d', `url=${url}`, `https://api.telegram.org/bot${token}/setWebhook`], { encoding: 'utf-8' })).trim();
|
|
2919
|
+
const j = JSON.parse(raw);
|
|
2920
|
+
console.log(JSON.stringify({ ok: !!j.ok, url, telegram_response: j }, null, 2));
|
|
2921
|
+
if (!j.ok)
|
|
2922
|
+
process.exitCode = 1;
|
|
2923
|
+
}
|
|
2924
|
+
catch (e) {
|
|
2925
|
+
console.error('webhook-set falhou:', e.message);
|
|
2926
|
+
process.exitCode = 1;
|
|
2927
|
+
}
|
|
2928
|
+
});
|
|
2929
|
+
telegramCmd
|
|
2930
|
+
.command('webhook-clear')
|
|
2931
|
+
.description('Remove webhook (volta para polling)')
|
|
2932
|
+
.action(async () => {
|
|
2933
|
+
const token = (process.env.TELEGRAM_BOT_TOKEN || '').trim();
|
|
2934
|
+
if (!token) {
|
|
2935
|
+
console.error('TELEGRAM_BOT_TOKEN ausente');
|
|
2936
|
+
process.exitCode = 1;
|
|
2937
|
+
return;
|
|
2938
|
+
}
|
|
2939
|
+
const { execFileSync } = require('child_process');
|
|
2940
|
+
try {
|
|
2941
|
+
const raw = String(execFileSync('curl', ['-sS', '--max-time', '8', '-X', 'POST', `https://api.telegram.org/bot${token}/deleteWebhook`], { encoding: 'utf-8' })).trim();
|
|
2942
|
+
const j = JSON.parse(raw);
|
|
2943
|
+
console.log(JSON.stringify({ ok: !!j.ok, telegram_response: j }, null, 2));
|
|
2944
|
+
if (!j.ok)
|
|
2945
|
+
process.exitCode = 1;
|
|
2946
|
+
}
|
|
2947
|
+
catch (e) {
|
|
2948
|
+
console.error('webhook-clear falhou:', e.message);
|
|
2949
|
+
process.exitCode = 1;
|
|
2950
|
+
}
|
|
2951
|
+
});
|
|
2828
2952
|
// `openlife config` — interactive configuration TUI (provider, keys, telegram, voice, daemon)
|
|
2829
2953
|
program
|
|
2830
2954
|
.command('config')
|
|
@@ -2838,8 +2962,19 @@ program
|
|
|
2838
2962
|
program
|
|
2839
2963
|
.command('chat')
|
|
2840
2964
|
.description('Inicia o chat interativo no terminal (Matrix-themed REPL)')
|
|
2841
|
-
.
|
|
2842
|
-
|
|
2965
|
+
.option('--test', 'executa smoke não-interativo do chat e sai')
|
|
2966
|
+
.action(async (opts) => {
|
|
2967
|
+
const { runChat, runChatSmoke } = require('./cli/ChatTui');
|
|
2968
|
+
if (opts.test) {
|
|
2969
|
+
const result = runChatSmoke({ cwd: process.cwd() });
|
|
2970
|
+
console.log(`${result.marker}: ${result.detail}`);
|
|
2971
|
+
console.log(`sessionId=${result.sessionId}`);
|
|
2972
|
+
console.log(`model=${result.model}`);
|
|
2973
|
+
console.log(`cwd=${result.cwd}`);
|
|
2974
|
+
if (!result.ok)
|
|
2975
|
+
process.exitCode = 1;
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2843
2978
|
await runChat();
|
|
2844
2979
|
});
|
|
2845
2980
|
// Bare invocation (no subcommand + interactive TTY) → launch chat TUI.
|
|
@@ -48,7 +48,9 @@ class ConsequenceForecaster {
|
|
|
48
48
|
];
|
|
49
49
|
const selectedPath = this.pickBest(paths);
|
|
50
50
|
const executiveSummary = this.buildExecutiveSummary(selectedPath, governanceRisk, normalizedGoal);
|
|
51
|
-
|
|
51
|
+
const valueScores = this.scoreValues(selectedPath, governanceRisk, normalizedGoal);
|
|
52
|
+
const horizons = this.buildHorizons(selectedPath, governanceRisk, normalizedGoal);
|
|
53
|
+
return { selectedPath, consideredPaths: paths, executiveSummary, valueScores, horizons };
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
54
56
|
* Story 14.3 (v1.5) — Brain-enriched forecast with persistent cache.
|
|
@@ -257,6 +259,27 @@ class ConsequenceForecaster {
|
|
|
257
259
|
return 'safety';
|
|
258
260
|
return 'neutral';
|
|
259
261
|
}
|
|
262
|
+
scoreValues(selectedPath, risk, normalizedGoal) {
|
|
263
|
+
const safety = risk === 'high' && selectedPath.id === 'conservative' ? 9 : risk === 'high' ? 5 : 7;
|
|
264
|
+
const usefulness = selectedPath.id === 'aggressive' ? 8 : selectedPath.id === 'balanced' ? 8 : 6;
|
|
265
|
+
const reversibility = normalizedGoal.includes('delete') || normalizedGoal.includes('remove') || normalizedGoal.includes('produção') || normalizedGoal.includes('production') ? 5 : 8;
|
|
266
|
+
const cost = selectedPath.policy.maxBranches > 2 ? 5 : 8;
|
|
267
|
+
return [
|
|
268
|
+
{ criterion: 'safety', score: safety, rationale: 'Prioriza risco governado e superfície de execução.' },
|
|
269
|
+
{ criterion: 'usefulness', score: usefulness, rationale: 'Estima probabilidade de entregar valor útil ao usuário.' },
|
|
270
|
+
{ criterion: 'reversibility', score: reversibility, rationale: 'Avalia facilidade de desfazer ou pausar a ação.' },
|
|
271
|
+
{ criterion: 'cost', score: cost, rationale: 'Penaliza fan-out e paralelismo quando aumentam custo operacional.' },
|
|
272
|
+
];
|
|
273
|
+
}
|
|
274
|
+
buildHorizons(selectedPath, risk, normalizedGoal) {
|
|
275
|
+
const safeAction = risk === 'high' ? 'exigir validação explícita antes de efeitos externos' : 'executar com validação padrão';
|
|
276
|
+
return {
|
|
277
|
+
now: { impact: `Rota ${selectedPath.id} selecionada; ${selectedPath.consequences[0]}.`, recommendedAction: safeAction, risk },
|
|
278
|
+
'24h': { impact: 'Evidências e logs devem confirmar ausência de regressão operacional.', recommendedAction: 'revisar serviceEvidence e eventos de governança', risk: risk === 'low' ? 'low' : 'medium' },
|
|
279
|
+
'7d': { impact: 'Padrões de falha ou retrabalho começam a aparecer nos KPIs do serviço.', recommendedAction: 'avaliar scorecard e ajustar capability/workflow se necessário', risk: 'medium' },
|
|
280
|
+
'30d': { impact: 'Efeito acumulado em custo, confiabilidade e confiança do operador fica mensurável.', recommendedAction: 'promover, pausar ou refatorar a capacidade com base em evidência', risk: normalizedGoal.includes('production') || normalizedGoal.includes('produção') ? 'high' : 'medium' },
|
|
281
|
+
};
|
|
282
|
+
}
|
|
260
283
|
scorePath(risk, policy, executors, normalizedGoal, conservative) {
|
|
261
284
|
let score = 0;
|
|
262
285
|
if (executors.length > 1)
|
|
@@ -0,0 +1,130 @@
|
|
|
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
|
+
exports.DreamGoalStore = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
class DreamGoalStore {
|
|
40
|
+
stateDir;
|
|
41
|
+
constructor(stateDir = process.env.OPENLIFE_STATE_DIR || path.join(process.cwd(), '.openlife')) {
|
|
42
|
+
this.stateDir = stateDir;
|
|
43
|
+
}
|
|
44
|
+
setDream(value) {
|
|
45
|
+
return this.set('dream', value);
|
|
46
|
+
}
|
|
47
|
+
setGoal(value) {
|
|
48
|
+
return this.set('goal', value);
|
|
49
|
+
}
|
|
50
|
+
getDream() {
|
|
51
|
+
return this.load().dream;
|
|
52
|
+
}
|
|
53
|
+
getGoal() {
|
|
54
|
+
return this.load().goal;
|
|
55
|
+
}
|
|
56
|
+
summary() {
|
|
57
|
+
const state = this.load();
|
|
58
|
+
const dream = state.dream?.value || 'não definido';
|
|
59
|
+
const goal = state.goal?.value || 'não definido';
|
|
60
|
+
return [`Dream atual: ${dream}`, `Goal atual: ${goal}`].join('\n');
|
|
61
|
+
}
|
|
62
|
+
handleSlashCommand(input) {
|
|
63
|
+
const trimmed = input.trim();
|
|
64
|
+
const match = trimmed.match(/^\/(dream|goal)(?:\s+([\s\S]+))?$/i);
|
|
65
|
+
if (!match)
|
|
66
|
+
return null;
|
|
67
|
+
const kind = match[1].toLowerCase();
|
|
68
|
+
const value = (match[2] || '').trim();
|
|
69
|
+
if (!value) {
|
|
70
|
+
const current = kind === 'dream' ? this.getDream() : this.getGoal();
|
|
71
|
+
if (!current) {
|
|
72
|
+
return `${this.label(kind)} ainda não definido. Use /${kind} <texto> para registrar.`;
|
|
73
|
+
}
|
|
74
|
+
return `${this.label(kind)} atual:\n${current.value}\n\nAtualizado em: ${current.updatedAt}`;
|
|
75
|
+
}
|
|
76
|
+
const entry = this.set(kind, value);
|
|
77
|
+
const counterpart = kind === 'dream' ? this.getGoal() : this.getDream();
|
|
78
|
+
const nextHint = kind === 'dream'
|
|
79
|
+
? 'Use /goal para transformar esse sonho em uma missão executável.'
|
|
80
|
+
: 'Use /dream para ajustar a visão maior por trás deste objetivo.';
|
|
81
|
+
return [
|
|
82
|
+
`${this.label(kind)} registrado ✅`,
|
|
83
|
+
'',
|
|
84
|
+
entry.value,
|
|
85
|
+
'',
|
|
86
|
+
counterpart ? this.summary() : nextHint,
|
|
87
|
+
].join('\n');
|
|
88
|
+
}
|
|
89
|
+
set(kind, rawValue) {
|
|
90
|
+
const value = rawValue.trim();
|
|
91
|
+
if (!value)
|
|
92
|
+
throw new Error(`${kind}_cannot_be_empty`);
|
|
93
|
+
const state = this.load();
|
|
94
|
+
const entry = { kind, value, updatedAt: new Date().toISOString() };
|
|
95
|
+
state[kind] = entry;
|
|
96
|
+
state.history = [...(state.history || []), entry].slice(-50);
|
|
97
|
+
this.save(state);
|
|
98
|
+
this.appendMarkdown(entry);
|
|
99
|
+
return entry;
|
|
100
|
+
}
|
|
101
|
+
label(kind) {
|
|
102
|
+
return kind === 'dream' ? 'Dream' : 'Goal';
|
|
103
|
+
}
|
|
104
|
+
filePath() {
|
|
105
|
+
return path.join(this.stateDir, 'dream-goal.json');
|
|
106
|
+
}
|
|
107
|
+
load() {
|
|
108
|
+
const file = this.filePath();
|
|
109
|
+
if (!fs.existsSync(file))
|
|
110
|
+
return { history: [] };
|
|
111
|
+
try {
|
|
112
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
113
|
+
return { ...parsed, history: parsed.history || [] };
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return { history: [] };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
save(state) {
|
|
120
|
+
fs.mkdirSync(this.stateDir, { recursive: true });
|
|
121
|
+
fs.writeFileSync(this.filePath(), JSON.stringify(state, null, 2), 'utf-8');
|
|
122
|
+
}
|
|
123
|
+
appendMarkdown(entry) {
|
|
124
|
+
const dir = path.join(this.stateDir, 'dream-goal');
|
|
125
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
126
|
+
const file = path.join(dir, `${entry.kind}.md`);
|
|
127
|
+
fs.appendFileSync(file, `## /${entry.kind} ${entry.updatedAt}\n\n${entry.value}\n\n`, 'utf-8');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.DreamGoalStore = DreamGoalStore;
|
|
@@ -53,6 +53,7 @@ const ModelManager_1 = require("./ModelManager");
|
|
|
53
53
|
const WorldClassCommands_1 = require("../cli/WorldClassCommands");
|
|
54
54
|
const GovernanceLayer_1 = require("./GovernanceLayer");
|
|
55
55
|
const child_process_1 = require("child_process");
|
|
56
|
+
const DreamGoalStore_1 = require("./DreamGoalStore");
|
|
56
57
|
class Gatekeeper {
|
|
57
58
|
memory;
|
|
58
59
|
squadManager;
|
|
@@ -117,6 +118,12 @@ class Gatekeeper {
|
|
|
117
118
|
}
|
|
118
119
|
async routeTask(task, userInput, userId = "default", options) {
|
|
119
120
|
console.log(`\n[GATEKEEPER] Intenção: ${task.intent} | Budget: $${task.budgetLimit} | User: ${userId}`);
|
|
121
|
+
const dreamGoalResponse = new DreamGoalStore_1.DreamGoalStore().handleSlashCommand(userInput);
|
|
122
|
+
if (dreamGoalResponse) {
|
|
123
|
+
this.sessionManager.addMessage(userId, 'user', userInput);
|
|
124
|
+
this.sessionManager.addMessage(userId, 'agent', dreamGoalResponse);
|
|
125
|
+
return dreamGoalResponse;
|
|
126
|
+
}
|
|
120
127
|
const parsedCommand = this.commandLanguage.parse(userInput);
|
|
121
128
|
const commandResult = this.commandRouter.route(parsedCommand);
|
|
122
129
|
if (commandResult) {
|
|
@@ -280,6 +287,9 @@ ${searchResult ? `Contexto relevante:\n${searchResult.substring(0, 900)}\n` : ''
|
|
|
280
287
|
Histórico recente:
|
|
281
288
|
${recentHistory.slice(-1200)}
|
|
282
289
|
|
|
290
|
+
Dream/Goal atual do usuário:
|
|
291
|
+
${new DreamGoalStore_1.DreamGoalStore().summary()}
|
|
292
|
+
|
|
283
293
|
Instruções:
|
|
284
294
|
- Responda diretamente à última mensagem, em português natural.
|
|
285
295
|
- Seja rápido e conciso por padrão.
|
|
@@ -319,6 +329,10 @@ Instruções:
|
|
|
319
329
|
const usedFallback = state.attempts.some(a => a.role === 'executor' && a.status === 'partial');
|
|
320
330
|
console.log("[SELF-EVALUATION LOOP] Analisando o resultado real do loop multiagente...");
|
|
321
331
|
const traceMode = String(process.env.OPENLIFE_REASONING_MODE || 'errors').toLowerCase();
|
|
332
|
+
const isResearchTask = task.intent === IntentClassifier_1.TaskIntent.RESEARCH_ANALYSIS && inferredMode === 'task';
|
|
333
|
+
if (isResearchTask) {
|
|
334
|
+
return orchestration.response;
|
|
335
|
+
}
|
|
322
336
|
const toolTrace = state.attempts.slice(-10).map((a) => {
|
|
323
337
|
const raw = String(a.summary || '').replace(/\n/g, ' ');
|
|
324
338
|
const m = raw.match(/^TOOL_TRACE\s+(search_files|read_file|write_file|terminal):\s*(.*)$/i);
|