@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.
Files changed (35) hide show
  1. package/INSTALL.md +29 -1
  2. package/dist/cli/ChatTui.js +32 -0
  3. package/dist/cli/InstallModules.js +17 -2
  4. package/dist/cli/InstallWizardV2.js +110 -0
  5. package/dist/cli/install/Multiselect.js +285 -0
  6. package/dist/cli/install/OAuthRunner.js +170 -0
  7. package/dist/cli/install/Phases.js +864 -0
  8. package/dist/cli/install/ProvidersCatalog.js +320 -0
  9. package/dist/cli/install/WizardIO.js +271 -0
  10. package/dist/cli/install/types.js +17 -0
  11. package/dist/index.js +170 -35
  12. package/dist/orchestrator/ConsequenceForecaster.js +24 -1
  13. package/dist/orchestrator/DreamGoalStore.js +130 -0
  14. package/dist/orchestrator/Gatekeeper.js +14 -0
  15. package/dist/orchestrator/Gateway.js +194 -15
  16. package/dist/orchestrator/ModelManager.js +7 -1
  17. package/dist/orchestrator/OrchestrationLoop.js +12 -0
  18. package/dist/orchestrator/ParallelOrchestrationLoop.js +12 -2
  19. package/dist/orchestrator/RuntimePolicy.js +4 -1
  20. package/dist/orchestrator/ServiceCompletionPolicy.js +15 -0
  21. package/dist/orchestrator/SynthesizerAgent.js +20 -1
  22. package/dist/orchestrator/TaskExecutor.js +53 -0
  23. package/dist/orchestrator/capability/CapabilityGenesisEngine.js +66 -11
  24. package/dist/test_capability_genesis_engine.js +1 -1
  25. package/dist/test_chat_smoke_command.js +59 -0
  26. package/dist/test_dream_goal_commands.js +76 -0
  27. package/dist/test_gateway_telegram_formatting.js +74 -0
  28. package/dist/test_install_wizard_v2.js +193 -0
  29. package/dist/test_on_demand_voice_reply.js +65 -0
  30. package/dist/test_remaining_sprints_contracts.js +103 -0
  31. package/dist/test_runtime_policy.js +25 -6
  32. package/dist/test_service_completion_policy.js +7 -0
  33. package/dist/test_subsystems_routing_governance.js +13 -3
  34. package/dist/test_task_executor_gemini_api.js +68 -0
  35. 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 — guided setup for OpenLife into the chosen host CLI')
300
- .action(async () => {
301
- console.log((0, InstallBanner_1.installationBanner)());
302
- console.log('');
303
- // Lazy require preserves the lazy-import contract (`src/index.ts:11-13`).
304
- const { InstallWizard, ReadlineAnswerProvider } = require('./cli/InstallWizard');
305
- const { InstallFlow } = require('./cli/InstallFlow');
306
- const provider = new ReadlineAnswerProvider();
307
- const wizard = new InstallWizard(process.cwd(), provider);
308
- try {
309
- const result = await wizard.run();
310
- if (!result.ok) {
311
- console.log(JSON.stringify(result, null, 2));
312
- process.exitCode = result.reason === 'user_aborted' ? 0 : 1;
313
- return;
314
- }
315
- const flow = new InstallFlow();
316
- const installResult = flow.run(result.options);
317
- for (const line of flow.renderSummary(installResult))
318
- console.log(line);
319
- if (result.warnings && result.warnings.length) {
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('⚠️ Warnings:');
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('✅ OpenLife ready.');
327
- console.log('');
328
- console.log('Try:');
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
- finally {
336
- // Release the readline interface so the CLI exits cleanly.
337
- provider.close?.();
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
- .action(async () => {
2842
- const { runChat } = require('./cli/ChatTui');
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
- return { selectedPath, consideredPaths: paths, executiveSummary };
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);