tycono 0.3.28 → 0.3.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tycono",
3
- "version": "0.3.28",
3
+ "version": "0.3.30",
4
4
  "description": "Build an AI company. Watch them work.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -425,14 +425,14 @@ Examples:
425
425
  // New turn starts — flush accumulated text from previous turn
426
426
  if (e.type === 'msg:start') {
427
427
  if (currentText.trim()) {
428
- exchanges.push({ role: 'supervisor', text: currentText.trim().slice(0, 100) });
428
+ exchanges.push({ role: 'supervisor', text: currentText.trim().slice(0, 500) });
429
429
  currentText = '';
430
430
  }
431
431
  // Extract CEO directive
432
432
  const task = String(e.data.task ?? '');
433
433
  const match = task.match(/\[CEO (?:Supervisor|Question)\]\s*(.*?)(?:\n|$)/);
434
434
  if (match) {
435
- exchanges.push({ role: 'ceo', text: match[1].slice(0, 80) });
435
+ exchanges.push({ role: 'ceo', text: match[1].slice(0, 200) });
436
436
  }
437
437
  }
438
438
  // Accumulate supervisor response text
@@ -445,27 +445,27 @@ Examples:
445
445
  // Turn boundary — flush
446
446
  if (e.type === 'msg:done' || e.type === 'msg:awaiting_input' || e.type === 'msg:error') {
447
447
  if (currentText.trim()) {
448
- exchanges.push({ role: 'supervisor', text: currentText.trim().slice(0, 100) });
448
+ exchanges.push({ role: 'supervisor', text: currentText.trim().slice(0, 500) });
449
449
  currentText = '';
450
450
  }
451
451
  }
452
452
  }
453
453
  // Flush any remaining text
454
454
  if (currentText.trim()) {
455
- exchanges.push({ role: 'supervisor', text: currentText.trim().slice(0, 100) });
455
+ exchanges.push({ role: 'supervisor', text: currentText.trim().slice(0, 500) });
456
456
  }
457
457
  }
458
458
 
459
459
  if (exchanges.length === 0) return '';
460
460
 
461
- // Keep last 4 exchanges (2 Q&A pairs), cap total at 500 chars
462
- const recent = exchanges.slice(-4);
461
+ // Keep last 10 exchanges (5 Q&A pairs), cap total at 3000 chars
462
+ const recent = exchanges.slice(-10);
463
463
  const formatted = recent.map(e =>
464
464
  e.role === 'ceo' ? `CEO: "${e.text}"` : `→ ${e.text}`
465
465
  ).join('\n');
466
466
 
467
- const result = formatted.length > 500
468
- ? `\n[Previous conversation]\n${formatted.slice(-500)}\n`
467
+ const result = formatted.length > 3000
468
+ ? `\n[Previous conversation]\n${formatted.slice(-3000)}\n`
469
469
  : `\n[Previous conversation]\n${formatted}\n`;
470
470
  console.log(`[WaveHistory] Result (${result.length} chars): ${result.slice(0, 200)}`);
471
471
  return result;
@@ -484,41 +484,53 @@ Examples:
484
484
  // If no in-memory history, load from disk (restart case)
485
485
  const diskHistory = !directiveHistory ? this.loadWaveHistory(state.waveId) : '';
486
486
 
487
- // Extract last execution's output from activity stream (what "just happened")
488
- let lastExecutionSummary = '';
489
- // Try current supervisorSessionId first, then search by waveId
487
+ // Save last execution's full output to a temp file so conversation CEO can read it.
488
+ // No truncation — CEO reads the file for full context instead of getting a sliced summary.
489
+ let contextFilePath = '';
490
490
  const sessionIdToCheck = state.supervisorSessionId
491
491
  || listSessions().find(s => s.waveId === state.waveId && s.roleId === 'ceo')?.id;
492
492
  if (sessionIdToCheck) {
493
493
  try {
494
494
  const events = ActivityStream.readAll(sessionIdToCheck);
495
- // Get last text outputs (the supervisor's final response)
496
495
  const textEvents = events.filter(e => e.type === 'text' && e.roleId === 'ceo');
497
- const toolEvents = events.filter(e => e.type === 'tool:start' && e.roleId === 'ceo');
498
-
499
- // Summarize: what tools were used + final text
500
- const toolSummary = toolEvents.slice(-10).map(e => {
501
- const name = (e.data.name as string) ?? '';
502
- const inp = e.data.input as Record<string, unknown> | undefined;
503
- const detail = inp?.file_path ?? inp?.command ?? '';
504
- return ` → ${name} ${String(detail).slice(0, 60)}`;
505
- }).join('\n');
506
-
507
- const lastText = textEvents.slice(-5).map(e => String(e.data.text ?? '')).join('').slice(-500);
508
-
509
- if (toolSummary || lastText) {
510
- lastExecutionSummary = `\n[Previous execution in this wave]\nTools used:\n${toolSummary}\n\nLast response:\n${lastText.slice(0, 500)}\n`;
496
+ const fullText = textEvents.map(e => String(e.data.text ?? '')).join('\n').trim();
497
+ if (fullText) {
498
+ contextFilePath = path.join(COMPANY_ROOT, '.tycono', `conversation-context-${state.waveId}.md`);
499
+ fs.writeFileSync(contextFilePath, `# Previous CEO Response (Wave ${state.waveId})\n\n${fullText}\n`);
511
500
  }
512
501
  } catch { /* ignore */ }
513
502
  }
514
503
 
515
- const context = [directiveHistory || diskHistory, lastExecutionSummary].filter(Boolean).join('\n');
504
+ // Build a compact pointer — what was done, where to look
505
+ const contextPointer = contextFilePath
506
+ ? `\n[Previous execution output saved to: ${contextFilePath}]\nRead this file for full context before answering.\n`
507
+ : '';
508
+ const context = [directiveHistory || diskHistory, contextPointer].filter(Boolean).join('\n');
509
+
510
+ // Also find files created/modified in this wave
511
+ let waveArtifacts = '';
512
+ try {
513
+ const waveFile = path.join(COMPANY_ROOT, 'operations', 'waves', `${state.waveId}.json`);
514
+ if (fs.existsSync(waveFile)) {
515
+ const waveData = JSON.parse(fs.readFileSync(waveFile, 'utf-8'));
516
+ const files = waveData.roles?.flatMap((r: { artifacts?: string[] }) => r.artifacts ?? []) ?? [];
517
+ if (files.length > 0) {
518
+ waveArtifacts = `\n[Files created/modified in this wave]:\n${files.slice(0, 20).map((f: string) => ` - ${f}`).join('\n')}\n`;
519
+ }
520
+ }
521
+ } catch { /* ignore */ }
522
+
523
+ const task = `${context}${waveArtifacts}
524
+ [CEO Question] ${directive}
516
525
 
517
- const task = `${context ? context + '\n' : ''}[CEO Question] ${directive}
526
+ You are the CEO Supervisor responding to the CEO's follow-up question.
518
527
 
519
- You are the CEO's AI assistant. The above shows what happened previously in this wave.
520
- Answer the CEO's question based on context. Be specific reference files, results, and actions from the previous execution.
521
- Do NOT dispatch anyone. Do NOT create new files. Just answer concisely.`;
528
+ ## Rules
529
+ 1. **READ the context file above** before answering. It contains the full previous response don't guess.
530
+ 2. **READ wave artifact files** if they exist they contain the team's deliverables (reports, analysis).
531
+ 3. **Be concrete.** Use actual data, numbers, quotes from the documents. The CEO wants substance, not metadata.
532
+ 4. Do NOT dispatch anyone. Do NOT create new files. This is a conversation.
533
+ 5. Answer in the same language the CEO used.`;
522
534
 
523
535
  // Reuse session
524
536
  let sessionId = state.supervisorSessionId;