Skip to content

Commit ba6328c

Browse files
committed
release: merge develop into main for v0.22.3
2 parents 314265b + 0fe1986 commit ba6328c

6 files changed

Lines changed: 70 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.22.3] - 2026-04-14
9+
10+
### Added
11+
12+
- **TodoWrite renders as checklist in chat** — instead of a JSON dump, the chat now shows ○ pending / ◐ in_progress / ● completed (with strikethrough for done items) plus a `N/M done` counter in the card header. Falls back to the generic JSON view if the input is malformed.
13+
14+
### Changed
15+
16+
- **Trust mode is re-read on every tool call** — toggling Settings → Trust now takes effect immediately for ongoing chat sessions, no restart needed. Previously the value was snapshotted at session start.
17+
818
## [0.22.2] - 2026-04-14
919

1020
### Added

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@evoapi/evo-nexus",
3-
"version": "0.22.2",
3+
"version": "0.22.3",
44
"description": "Unofficial open source toolkit for Claude Code — AI-powered business operating system",
55
"keywords": [
66
"claude-code",

dashboard/frontend/src/components/AgentChat.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,57 @@ function ToolCard({ block, accentColor }: { block: Extract<AssistantBlock, { typ
12711271
)
12721272
}
12731273

1274+
// TodoWrite — pretty checklist renderer
1275+
if (block.toolName === 'TodoWrite' && Array.isArray(parsedInput?.todos)) {
1276+
const todos: Array<{ content: string; status: string; priority?: string; id?: string }> = parsedInput.todos
1277+
const completedCount = todos.filter(t => t.status === 'completed').length
1278+
1279+
return (
1280+
<div className="border border-[#21262d] rounded-lg overflow-hidden">
1281+
<button
1282+
onClick={() => setOpen(!open)}
1283+
className="flex items-center gap-2 w-full px-3 py-2 text-[12px] bg-[#161b22] hover:bg-[#1c2333] transition-colors"
1284+
>
1285+
{open ? <ChevronDown size={12} className="text-[#667085]" /> : <ChevronRight size={12} className="text-[#667085]" />}
1286+
<CheckCircle2 size={13} style={{ color: accentColor }} />
1287+
<span className="font-medium text-[#e6edf3]">TodoWrite</span>
1288+
<span className="text-[#667085] text-[11px]">{completedCount}/{todos.length} done</span>
1289+
<span className="ml-auto flex-shrink-0">
1290+
{block.done ? (
1291+
<CheckCircle2 size={13} className="text-[#22C55E]" />
1292+
) : (
1293+
<TypingIndicatorMini accentColor={accentColor} />
1294+
)}
1295+
</span>
1296+
</button>
1297+
<div className="px-3 py-2 border-t border-[#21262d] bg-[#0d1117] space-y-1">
1298+
{todos.map((todo, i) => {
1299+
const isPending = todo.status === 'pending'
1300+
const isInProgress = todo.status === 'in_progress'
1301+
const isCompleted = todo.status === 'completed'
1302+
const icon = isPending ? '○' : isInProgress ? '◐' : '●'
1303+
return (
1304+
<div key={i} className="flex items-start gap-2 text-[12px]">
1305+
<span
1306+
className="flex-shrink-0 mt-0.5 font-mono text-[13px]"
1307+
style={{ color: isPending ? '#667085' : '#00FFA7' }}
1308+
>
1309+
{icon}
1310+
</span>
1311+
<span
1312+
className={isCompleted ? 'line-through opacity-60' : ''}
1313+
style={{ color: isPending ? '#8b949e' : isCompleted ? '#8b949e' : '#e6edf3' }}
1314+
>
1315+
{todo.content}
1316+
</span>
1317+
</div>
1318+
)
1319+
})}
1320+
</div>
1321+
</div>
1322+
)
1323+
}
1324+
12741325
// Regular tool card
12751326
const displayInfo = parsedInput
12761327
? (parsedInput.command || parsedInput.file_path || parsedInput.path || parsedInput.pattern || parsedInput.description || '')

dashboard/terminal-server/src/chat-bridge.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,10 @@ class ChatBridge {
249249
'NotebookEdit', 'ToolSearch',
250250
];
251251

252-
// Read trust mode fresh on each session start so the toggle takes effect immediately.
253-
const trustMode = readTrustMode();
254-
if (trustMode) {
255-
console.log(`[chat-bridge] Trust mode ON — all tools auto-approved for session ${sessionId}`);
252+
// trustMode is read fresh on EVERY tool decision below, so toggling it in
253+
// the UI takes effect mid-session without needing a restart.
254+
if (readTrustMode()) {
255+
console.log(`[chat-bridge] Trust mode ON at session start (${sessionId})`);
256256
}
257257

258258
// Per-tool approval flow — works for main thread AND spawned subagents.
@@ -282,7 +282,7 @@ class ChatBridge {
282282
};
283283

284284
queryOptions.canUseTool = async (toolName, input, sdkOptions) => {
285-
if (trustMode || AUTO_APPROVE.has(toolName)) {
285+
if (readTrustMode() || AUTO_APPROVE.has(toolName)) {
286286
return { behavior: 'allow' };
287287
}
288288
const requestId = sdkOptions.toolUseID || `req-${Date.now()}-${Math.random().toString(36).slice(2)}`;
@@ -296,7 +296,7 @@ class ChatBridge {
296296
const toolName = hookInput.tool_name;
297297
const toolInput = hookInput.tool_input;
298298
const agentId = hookInput.agent_id || null;
299-
if (trustMode || AUTO_APPROVE.has(toolName)) {
299+
if (readTrustMode() || AUTO_APPROVE.has(toolName)) {
300300
return {
301301
hookSpecificOutput: {
302302
hookEventName: 'PreToolUse',

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "evo-nexus"
3-
version = "0.22.2"
3+
version = "0.22.3"
44
description = "Unofficial open source toolkit for Claude Code — AI-powered business operating system"
55
requires-python = ">=3.10"
66
dependencies = [

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)