chati-dev 1.2.0 → 1.3.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.
@@ -1,6 +1,6 @@
1
1
  # /chati — Orchestrator
2
2
 
3
- You are the **chati.dev Orchestrator**, the single entry point for the chati.dev framework. You route requests, manage sessions, handle deviations, track backlog, and guide users through the development pipeline.
3
+ You are the **chati.dev Orchestrator**, the single entry point for the chati.dev system. You route requests, manage sessions, handle deviations, track backlog, and guide users through the development pipeline.
4
4
 
5
5
  ---
6
6
 
@@ -9,7 +9,7 @@ You are the **chati.dev Orchestrator**, the single entry point for the chati.dev
9
9
  - **Name**: Chati
10
10
  - **Role**: Orchestrator & Router
11
11
  - **Position**: Entry point (always first contact)
12
- - **Scope**: Framework-wide routing, session management, deviation handling, backlog
12
+ - **Scope**: System-wide routing, session management, deviation handling, backlog
13
13
 
14
14
  ---
15
15
 
@@ -26,19 +26,50 @@ When the user invokes `/chati`, execute this sequence:
26
26
  5. Detect language from session.yaml -> respond in that language
27
27
  ```
28
28
 
29
- ### Step 2: Determine State
29
+ ### Step 2: Check Subcommands
30
+
31
+ Before determining state, check if the user passed a subcommand:
32
+
33
+ ```
34
+ /chati exit | /chati stop | /chati quit:
35
+ -> Execute Exit Protocol (see Session Lock Protocol section)
36
+ -> Do NOT proceed further
37
+
38
+ /chati status:
39
+ -> Display status dashboard (see /chati status section)
40
+ -> Stay locked, do NOT exit
41
+
42
+ /chati resume:
43
+ -> Load continuation from .chati/continuation/latest.md (if exists)
44
+ -> Resume session with full context recovery
45
+ -> Re-activate session lock
46
+
47
+ /chati help:
48
+ -> Display available commands:
49
+ /chati Start or resume session
50
+ /chati status Show project dashboard
51
+ /chati resume Resume from continuation file
52
+ /chati exit Save and exit session
53
+ /chati help Show this help
54
+ -> Stay locked
55
+
56
+ (no subcommand or unrecognized):
57
+ -> Continue to Step 3 (Determine State)
58
+ ```
59
+
60
+ ### Step 3: Determine State
30
61
 
31
62
  **If session.yaml is empty or project.name is empty:**
32
63
  ```
33
- -> First run. Go to Step 3 (New Project Setup)
64
+ -> First run. Go to Step 4 (New Project Setup)
34
65
  ```
35
66
 
36
67
  **If session.yaml has active project:**
37
68
  ```
38
- -> Resume session. Go to Step 4 (Session Resume)
69
+ -> Resume session. Go to Step 5 (Session Resume)
39
70
  ```
40
71
 
41
- ### Step 3: New Project Setup
72
+ ### Step 4: New Project Setup
42
73
 
43
74
  #### 3a. Detect Project Type
44
75
  ```
@@ -78,7 +109,7 @@ If greenfield -> Read chati.dev/agents/clarity/greenfield-wu.md -> Activate
78
109
  If brownfield -> Read chati.dev/agents/clarity/brownfield-wu.md -> Activate
79
110
  ```
80
111
 
81
- ### Step 4: Session Resume
112
+ ### Step 5: Session Resume
82
113
  ```
83
114
  1. Read session.yaml -> identify current_agent, project.state, last_handoff
84
115
  2. Read latest handoff from chati.dev/artifacts/handoffs/
@@ -412,10 +443,125 @@ To activate autonomous mode:
412
443
 
413
444
  ---
414
445
 
446
+ ## Session Lock Protocol
447
+
448
+ Once `/chati` is invoked and a session is active, the orchestrator LOCKS the session. ALL subsequent user messages are routed through the orchestrator and the active agent. The user never "falls out" of the chati.dev system.
449
+
450
+ ### Lock Activation
451
+
452
+ ```
453
+ When /chati is invoked:
454
+ 1. Load session state (Step 1-2 above)
455
+ 2. SET session lock = ACTIVE
456
+ 3. Update CLAUDE.md with Session Lock block (see template below)
457
+ 4. ALL subsequent messages are intercepted by the orchestrator
458
+ 5. Messages are routed to current_agent
459
+ ```
460
+
461
+ ### Session Lock Block (CLAUDE.md)
462
+
463
+ When the session is active, CLAUDE.md MUST contain this block:
464
+
465
+ ```markdown
466
+ ## ⚠️ Session Lock — ACTIVE
467
+
468
+ **chati.dev session is ACTIVE.** You MUST follow these rules for EVERY message:
469
+
470
+ 1. Read `chati.dev/orchestrator/chati.md` and follow its routing logic
471
+ 2. Route ALL user messages through the current agent: `{current_agent}`
472
+ 3. NEVER respond outside of the chati.dev system
473
+ 4. NEVER act as generic Claude — you ARE the chati.dev orchestrator
474
+ 5. If the user asks something unrelated to the current agent's scope,
475
+ handle it via the Deviation Protocol (Section 5.7), do NOT exit the system
476
+ 6. The ONLY way to exit is via explicit exit commands (see below)
477
+ ```
478
+
479
+ This block is injected into CLAUDE.md when the session starts and removed when the user exits.
480
+
481
+ ### Message Routing (while locked)
482
+
483
+ ```
484
+ User sends message:
485
+
486
+ ├─ Is it an exit command? (see Exit Commands below)
487
+ │ YES -> Execute Exit Protocol
488
+ │ NO -> Continue
489
+
490
+ ├─ Is it a /chati subcommand? (/chati status, /chati help, etc.)
491
+ │ YES -> Execute subcommand, stay locked
492
+ │ NO -> Continue
493
+
494
+ ├─ Is it relevant to current agent's scope?
495
+ │ YES -> Route to current agent
496
+ │ NO -> Handle via Deviation Protocol (5.7)
497
+ │ -> Orchestrator re-routes to appropriate agent
498
+ │ -> Stay locked
499
+
500
+ └─ NEVER drop to raw/generic mode
501
+ ```
502
+
503
+ ### Exit Commands
504
+
505
+ The session lock is ONLY released by explicit user intent:
506
+
507
+ ```
508
+ Explicit commands (any language):
509
+ /chati exit
510
+ /chati stop
511
+ /chati quit
512
+
513
+ Natural language (detected by orchestrator):
514
+ EN: "exit chati", "stop chati", "I want to leave", "quit the system"
515
+ PT: "sair do chati", "quero sair", "parar o chati"
516
+ ES: "salir de chati", "quiero salir", "parar el chati"
517
+ FR: "quitter chati", "je veux sortir", "arrêter chati"
518
+
519
+ NOT exit triggers (stay locked):
520
+ - "stop" (without "chati" — could mean stop current task)
521
+ - "wait" / "pause" (temporary, not exit)
522
+ - "go back" / "voltar" (navigation within pipeline)
523
+ - "cancel" (cancel current action, not exit system)
524
+ - Closing the IDE (session persists in session.yaml for resume)
525
+ ```
526
+
527
+ ### Exit Protocol
528
+
529
+ ```
530
+ When exit is triggered:
531
+ 1. Save current agent state to session.yaml
532
+ 2. Generate session digest (for Memory Layer):
533
+ - Decisions made this session
534
+ - Current progress and partial work
535
+ - Pending items
536
+ 3. Update CLAUDE.md:
537
+ - REMOVE Session Lock block
538
+ - UPDATE project status with current state
539
+ - ADD resume instructions:
540
+ "Session paused at {agent}. Type /chati to resume."
541
+ 4. Confirm to user in their language:
542
+ EN: "Session saved. Type /chati anytime to resume."
543
+ PT: "Sessão salva. Digite /chati para retomar."
544
+ ES: "Sesión guardada. Escribe /chati para reanudar."
545
+ FR: "Session sauvée. Tapez /chati pour reprendre."
546
+ 5. Session data PERSISTS — nothing is lost
547
+ ```
548
+
549
+ ### Resume After Exit
550
+
551
+ ```
552
+ When user types /chati after a previous exit:
553
+ -> Normal Step 5 (Session Resume) flow
554
+ -> Session Lock is RE-ACTIVATED
555
+ -> CLAUDE.md lock block is RE-INJECTED
556
+ -> User is back in the system seamlessly
557
+ ```
558
+
559
+ ---
560
+
415
561
  ## Constitution Enforcement
416
562
 
417
563
  The orchestrator enforces the Constitution (chati.dev/constitution.md):
418
- - **BLOCK** enforcement: Halt agent on violation (Articles I, II, III, IV, VII, VIII, X, XI)
564
+ - **BLOCK** enforcement: Halt agent on violation (Articles I, II, III, IV, VII, VIII, X, XI, XV)
419
565
  - **GUIDE** enforcement: Correct behavior without halting (Articles V, IX)
420
566
  - **WARN** enforcement: Generate warning in QA (Article VI)
421
567
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "title": "chati.dev Config",
4
- "description": "Schema for chati.dev/config.yaml - framework version and installation tracking",
4
+ "description": "Schema for chati.dev/config.yaml - system version and installation tracking",
5
5
  "type": "object",
6
6
  "required": ["version"],
7
7
  "properties": {
@@ -0,0 +1,98 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "chati.dev Context Block",
4
+ "description": "Schema for <chati-context> XML block structure injected into agent prompts",
5
+ "type": "object",
6
+ "required": ["bracket", "constitution", "mode"],
7
+ "properties": {
8
+ "bracket": {
9
+ "enum": ["FRESH", "MODERATE", "DEPLETED", "CRITICAL"],
10
+ "description": "Current context bracket based on remaining context window"
11
+ },
12
+ "constitution": {
13
+ "type": "string",
14
+ "description": "Summarized constitution content (always injected, L0 layer)"
15
+ },
16
+ "mode": {
17
+ "enum": ["clarity", "build", "deploy"],
18
+ "description": "Current execution mode from session state (L1 layer)"
19
+ },
20
+ "agent": {
21
+ "type": "object",
22
+ "description": "Active agent scope information (L2 layer, active when bracket >= DEPLETED)",
23
+ "required": ["name", "mission"],
24
+ "properties": {
25
+ "name": { "type": "string", "description": "Agent identifier" },
26
+ "mission": { "type": "string", "description": "One-line agent mission statement" },
27
+ "inputs": { "type": "string", "description": "Expected inputs for this agent" },
28
+ "outputs": { "type": "string", "description": "Expected outputs from this agent" },
29
+ "criteria": { "type": "string", "description": "Success criteria summary" }
30
+ }
31
+ },
32
+ "pipeline": {
33
+ "type": "string",
34
+ "description": "Pipeline state string showing agent progression (L3 layer, active when bracket >= MODERATE)"
35
+ },
36
+ "task": {
37
+ "type": "string",
38
+ "description": "Current task description (L4 layer, active when bracket >= MODERATE)"
39
+ },
40
+ "handoff": {
41
+ "type": "object",
42
+ "description": "Previous agent handoff summary (L4 layer, active when bracket >= MODERATE)",
43
+ "properties": {
44
+ "from": { "type": "string", "description": "Source agent name" },
45
+ "score": { "type": "number", "minimum": 0, "maximum": 100, "description": "Source agent final score" },
46
+ "summary": { "type": "string", "description": "Key context from previous agent" }
47
+ }
48
+ },
49
+ "memory": {
50
+ "type": "object",
51
+ "description": "Memory injection based on bracket level",
52
+ "properties": {
53
+ "bracket": {
54
+ "enum": ["FRESH", "MODERATE", "DEPLETED", "CRITICAL"],
55
+ "description": "Memory retrieval bracket (mirrors context bracket)"
56
+ },
57
+ "level": {
58
+ "enum": ["none", "metadata", "chunks", "full"],
59
+ "description": "Memory retrieval level: none (FRESH), metadata (MODERATE), chunks (DEPLETED), full (CRITICAL)"
60
+ },
61
+ "entries": {
62
+ "type": "array",
63
+ "items": {
64
+ "type": "object",
65
+ "properties": {
66
+ "id": { "type": "string", "description": "Memory entry identifier" },
67
+ "title": { "type": "string", "description": "Memory title" },
68
+ "tier": { "enum": ["hot", "warm", "cold"], "description": "Memory attention tier" },
69
+ "summary": { "type": "string", "description": "Memory summary (L2 chunks level)" },
70
+ "content": { "type": "string", "description": "Full memory content (L3 full level)" }
71
+ }
72
+ }
73
+ }
74
+ }
75
+ },
76
+ "token_budget": {
77
+ "type": "object",
78
+ "description": "Token usage estimates",
79
+ "properties": {
80
+ "estimated_used": { "type": "integer", "minimum": 0, "description": "Estimated tokens used" },
81
+ "max_context": { "type": "integer", "minimum": 0, "description": "Maximum context window tokens" },
82
+ "remaining_percent": { "type": "number", "minimum": 0, "maximum": 100, "description": "Percentage of context remaining" },
83
+ "injection_budget": {
84
+ "type": "integer",
85
+ "minimum": 0,
86
+ "description": "Token budget for context injection (FRESH: 2500, MODERATE: 2000, DEPLETED: 1500, CRITICAL: 800)"
87
+ }
88
+ }
89
+ },
90
+ "active_layers": {
91
+ "type": "array",
92
+ "items": {
93
+ "enum": ["L0", "L1", "L2", "L3", "L4"]
94
+ },
95
+ "description": "Currently active injection layers based on bracket"
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "chati.dev Memory Entry",
4
+ "description": "Schema for memory entry YAML frontmatter in .chati/memories/",
5
+ "type": "object",
6
+ "required": ["id", "type", "agent", "tags", "confidence", "sector", "tier", "created_at"],
7
+ "properties": {
8
+ "id": {
9
+ "type": "string",
10
+ "pattern": "^mem-\\d{4}-\\d{2}-\\d{2}-\\d{3}$",
11
+ "description": "Unique memory identifier (mem-YYYY-MM-DD-NNN)"
12
+ },
13
+ "type": {
14
+ "enum": ["decision", "error_pattern", "resolution", "user_correction", "validated_pattern", "gotcha", "lesson"],
15
+ "description": "Classification of what this memory captures"
16
+ },
17
+ "agent": {
18
+ "type": "string",
19
+ "description": "Agent that created or owns this memory"
20
+ },
21
+ "tags": {
22
+ "type": "array",
23
+ "items": { "type": "string" },
24
+ "minItems": 1,
25
+ "description": "Searchable tags for similarity matching and retrieval"
26
+ },
27
+ "confidence": {
28
+ "type": "number",
29
+ "minimum": 0,
30
+ "maximum": 1,
31
+ "description": "System confidence in this memory (0.0-1.0)"
32
+ },
33
+ "sector": {
34
+ "enum": ["episodic", "semantic", "procedural", "reflective"],
35
+ "description": "Cognitive sector: episodic (what happened), semantic (what we know), procedural (how to do it), reflective (what we learned)"
36
+ },
37
+ "tier": {
38
+ "enum": ["hot", "warm", "cold"],
39
+ "description": "Attention tier: hot (>0.7, auto-loaded), warm (0.3-0.7, on-demand), cold (<0.3, explicit search)"
40
+ },
41
+ "access_count": {
42
+ "type": "integer",
43
+ "minimum": 0,
44
+ "default": 0,
45
+ "description": "Number of times this memory has been accessed"
46
+ },
47
+ "evidence_count": {
48
+ "type": "integer",
49
+ "minimum": 0,
50
+ "default": 0,
51
+ "description": "Number of corroborating observations"
52
+ },
53
+ "last_accessed": {
54
+ "type": ["string", "null"],
55
+ "format": "date-time",
56
+ "description": "Timestamp of last access"
57
+ },
58
+ "created_at": {
59
+ "type": "string",
60
+ "format": "date-time",
61
+ "description": "Timestamp of memory creation"
62
+ },
63
+ "expires_at": {
64
+ "type": ["string", "null"],
65
+ "format": "date-time",
66
+ "description": "Expiration timestamp (null for durable memories)"
67
+ },
68
+ "storage_tier": {
69
+ "enum": ["session", "daily", "durable"],
70
+ "default": "daily",
71
+ "description": "Storage persistence: session (cleaned on restart), daily (archived after 30d), durable (permanent)"
72
+ },
73
+ "scope": {
74
+ "enum": ["shared", "private"],
75
+ "default": "shared",
76
+ "description": "Visibility: shared (all agents) or private (owning agent only)"
77
+ }
78
+ }
79
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "chati-dev",
3
- "version": "1.2.0",
4
- "description": "AI-Powered Multi-Agent Development Framework — 13 agents, 6 IDEs, 4 languages",
3
+ "version": "1.3.0",
4
+ "description": "AI-Powered Multi-Agent Orchestration System — 13 agents, 6 IDEs, 4 languages",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "chati": "bin/chati.js",
@@ -19,13 +19,15 @@
19
19
  "start": "node bin/chati.js",
20
20
  "bundle": "node scripts/bundle-framework.js",
21
21
  "prepublishOnly": "node scripts/bundle-framework.js",
22
- "test": "node --test"
22
+ "test": "node --test test/**/*.test.js",
23
+ "lint": "eslint src/ bin/",
24
+ "lint:fix": "eslint src/ bin/ --fix"
23
25
  },
24
26
  "keywords": [
25
27
  "ai",
26
28
  "agents",
27
29
  "development",
28
- "framework",
30
+ "system",
29
31
  "planning",
30
32
  "multi-agent",
31
33
  "cli",
@@ -46,15 +48,20 @@
46
48
  },
47
49
  "dependencies": {
48
50
  "@clack/prompts": "^0.7.0",
51
+ "blessed": "^0.1.81",
49
52
  "chalk": "^5.3.0",
50
- "ora": "^8.0.1",
51
53
  "cli-progress": "^3.12.0",
52
54
  "fs-extra": "^11.2.0",
53
55
  "js-yaml": "^4.1.0",
54
- "semver": "^7.6.0",
55
- "blessed": "^0.1.81"
56
+ "ora": "^8.0.1",
57
+ "semver": "^7.6.0"
56
58
  },
57
59
  "engines": {
58
60
  "node": ">=18.0.0"
61
+ },
62
+ "devDependencies": {
63
+ "@eslint/js": "^10.0.1",
64
+ "eslint": "^10.0.0",
65
+ "globals": "^17.3.0"
59
66
  }
60
67
  }
@@ -35,7 +35,7 @@ const dirs = [
35
35
  'agents/clarity', 'agents/quality', 'agents/build', 'agents/deploy',
36
36
  'templates', 'workflows', 'quality-gates',
37
37
  'schemas', 'frameworks', 'intelligence', 'patterns',
38
- 'i18n', 'migrations',
38
+ 'i18n', 'migrations', 'data',
39
39
  ];
40
40
 
41
41
  for (const dir of dirs) {
@@ -1,11 +1,11 @@
1
- import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
1
+ import { readFileSync, existsSync, readdirSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import yaml from 'js-yaml';
4
4
 
5
5
  /**
6
6
  * Read all dashboard data from project directory
7
7
  */
8
- export function readDashboardData(targetDir) {
8
+ export async function readDashboardData(targetDir) {
9
9
  const data = {
10
10
  session: null,
11
11
  config: null,
@@ -15,6 +15,9 @@ export function readDashboardData(targetDir) {
15
15
  recentActivity: [],
16
16
  blockers: [],
17
17
  gotchas: [],
18
+ memoryStats: null,
19
+ contextStatus: null,
20
+ registryStats: null,
18
21
  };
19
22
 
20
23
  // Read session.yaml
@@ -95,5 +98,27 @@ export function readDashboardData(targetDir) {
95
98
  });
96
99
  }
97
100
 
101
+ // Intelligence Layer data (graceful degradation)
102
+ try {
103
+ const { getMemoryStats } = await import('../intelligence/memory-manager.js');
104
+ data.memoryStats = getMemoryStats(targetDir);
105
+ } catch {
106
+ // Intelligence module not available
107
+ }
108
+
109
+ try {
110
+ const { getContextStatus } = await import('../intelligence/context-status.js');
111
+ data.contextStatus = getContextStatus(targetDir);
112
+ } catch {
113
+ // Intelligence module not available
114
+ }
115
+
116
+ try {
117
+ const { getRegistryStats } = await import('../intelligence/registry-manager.js');
118
+ data.registryStats = getRegistryStats(targetDir);
119
+ } catch {
120
+ // Intelligence module not available
121
+ }
122
+
98
123
  return data;
99
124
  }
@@ -135,6 +135,27 @@ export function buildValidateSection(data) {
135
135
  ];
136
136
  }
137
137
 
138
+ /**
139
+ * Build INTELLIGENCE section
140
+ */
141
+ export function buildIntelligenceSection(data) {
142
+ const mem = data.memoryStats;
143
+ const ctx = data.contextStatus;
144
+ const reg = data.registryStats;
145
+
146
+ const memText = mem ? `${mem.total} total (H:${mem.byTier.hot} W:${mem.byTier.warm} C:${mem.byTier.cold})` : gray('N/A');
147
+ const ctxText = ctx ? `${ctx.bracket} [${ctx.activeLayers.join(',')}]` : gray('N/A');
148
+ const regText = reg && reg.exists ? `${reg.totalEntities} entities (${reg.countMatch ? green('match') : yellow('mismatch')})` : gray('N/A');
149
+
150
+ return [
151
+ brand('│') + ` ${brand('── INTELLIGENCE')} ${'─'.repeat(41)}` + brand('│'),
152
+ brand('│') + ` │ ${dim('Memory:')} ${memText}` + ' '.repeat(Math.max(1, 35 - String(memText).length)) + brand('│'),
153
+ brand('│') + ` │ ${dim('Context:')} ${ctxText}` + ' '.repeat(Math.max(1, 35 - String(ctxText).length)) + brand('│'),
154
+ brand('│') + ` │ ${dim('Registry:')} ${regText}` + ' '.repeat(Math.max(1, 35 - String(regText).length)) + brand('│'),
155
+ brand('│') + ` ${'─'.repeat(57)}` + brand('│'),
156
+ ];
157
+ }
158
+
138
159
  /**
139
160
  * Build footer with recent activity, blockers, gotchas
140
161
  */
@@ -5,6 +5,7 @@ import {
5
5
  buildClaritySection,
6
6
  buildBuildSection,
7
7
  buildValidateSection,
8
+ buildIntelligenceSection,
8
9
  buildFooter,
9
10
  } from './layout.js';
10
11
  import { dim } from '../utils/colors.js';
@@ -12,8 +13,8 @@ import { dim } from '../utils/colors.js';
12
13
  /**
13
14
  * Render dashboard once (static mode)
14
15
  */
15
- export function renderDashboard(targetDir) {
16
- const data = readDashboardData(targetDir);
16
+ export async function renderDashboard(targetDir) {
17
+ const data = await readDashboardData(targetDir);
17
18
 
18
19
  if (!data.session) {
19
20
  console.log('No chati.dev session found. Run `npx chati-dev init` first.');
@@ -30,6 +31,8 @@ export function renderDashboard(targetDir) {
30
31
  '',
31
32
  ...buildValidateSection(data),
32
33
  '',
34
+ ...buildIntelligenceSection(data),
35
+ '',
33
36
  ...buildFooter(data),
34
37
  ];
35
38
 
@@ -43,16 +46,16 @@ export function renderDashboard(targetDir) {
43
46
  /**
44
47
  * Render dashboard in watch mode (auto-refresh)
45
48
  */
46
- export function renderDashboardWatch(targetDir, intervalMs = 5000) {
49
+ export async function renderDashboardWatch(targetDir, intervalMs = 5000) {
47
50
  // Initial render
48
51
  console.clear();
49
- renderDashboard(targetDir);
52
+ await renderDashboard(targetDir);
50
53
  console.log(dim(` Auto-refreshing every ${intervalMs / 1000}s. Press Ctrl+C to exit.`));
51
54
 
52
55
  // Set up interval
53
- const timer = setInterval(() => {
56
+ const timer = setInterval(async () => {
54
57
  console.clear();
55
- renderDashboard(targetDir);
58
+ await renderDashboard(targetDir);
56
59
  console.log(dim(` Auto-refreshing every ${intervalMs / 1000}s. Press Ctrl+C to exit.`));
57
60
  console.log(dim(` Last update: ${new Date().toLocaleTimeString()}`));
58
61
  }, intervalMs);
@@ -70,8 +73,8 @@ export function renderDashboardWatch(targetDir, intervalMs = 5000) {
70
73
  /**
71
74
  * Render plain text fallback (for terminals without TUI support)
72
75
  */
73
- export function renderPlainDashboard(targetDir) {
74
- const data = readDashboardData(targetDir);
76
+ export async function renderPlainDashboard(targetDir) {
77
+ const data = await readDashboardData(targetDir);
75
78
 
76
79
  if (!data.session) {
77
80
  console.log('No chati.dev session found. Run `npx chati-dev init` first.');