Skip to content

Commit e0ec879

Browse files
committed
release: merge develop into main for v0.30.1
2 parents 6b62b16 + c465e55 commit e0ec879

7 files changed

Lines changed: 64 additions & 49 deletions

File tree

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ 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.30.1] - 2026-04-23
9+
10+
Patch release focused on thread UX polish: session now swaps cleanly when switching threads via the sidebar, the agent is briefed explicitly about running inside a persistent thread (not a fresh one-shot session), the assignee dropdown stops hiding agents, and fresh installs no longer inherit Evolution-specific goal seed data.
11+
12+
### Fixed
13+
14+
- **Thread switch leaked previous conversation** — switching threads via the sidebar kept `threadSessionId` pinned to the old ticket and `<AgentChat>` kept rendering the old messages until a full page reload (or going back to `/topics` and entering again). Two fixes in `TicketDetail.tsx`: (1) a new effect resets `threadSessionId` whenever `ticket?.id` changes so the auto-init re-runs for the new ticket; (2) `<AgentChat key={ticket.id}>` forces a full remount so the WebSocket, message buffer and internal effects restart cleanly.
15+
- **Topics assignee dropdown hid 18 of 38 agents** — the Assign-to-agent combobox in `/topics` sliced the filtered list at 20 items (`filteredAgents.slice(0, 20)`), silently dropping agents whose slugs come later alphabetically (from `m` onward). Removed the slice and bumped `max-h-48` to `max-h-72` so ~12 agents are visible at once without scrolling and all 38 are reachable.
16+
- **Goals: Evolution-specific seed leaking into open-source installs**`dashboard/backend/app.py` was seeding a hardcoded "Evolution Revenue $1M Q4 2026" mission with 3 projects (evo-ai, evo-summit, evo-academy) and 5 goals on first boot. Removed the seed block so new instances start empty. The `/goals` empty state now points users at the `/create-goal` skill instead of the misleading "Run the backend migration to seed initial data" message. Existing installations with the seed applied can clean it with `DELETE FROM goal_tasks; DELETE FROM goals; DELETE FROM projects; DELETE FROM missions;`.
17+
18+
### Changed
19+
20+
- **Thread context now always injected into the agent's system prompt** — when a thread session initialises, `TicketDetail.initThreadSession` always builds a "Thread Context" block explaining that the agent is running inside a persistent thread (not a fresh session): the thread title, description, assigned agent slug, default workspace folder, memory file path, summarization cadence, and resume behaviour. It also tells the agent **not** to re-invoke itself via the `Agent` tool (which was causing confusing `@zara-cs` calling `@zara-cs` patterns). Memory.md content is appended when present, so empty threads still get the full context and populated threads still surface prior-session knowledge. Respects the existing `!sdkSessionId` guard in `chat-bridge.js` — only injected on fresh sessions, not on `--resume`.
21+
822
## [0.30.0] - 2026-04-23
923

1024
Minor release adding a unified Activity Log — a single page aggregating execution history across routines, heartbeats and triggers so the user can answer "what did the system just do?" without visiting three separate pages.

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.30.0",
3+
"version": "0.30.1",
44
"description": "Unofficial open source toolkit for Claude Code — AI-powered business operating system",
55
"keywords": [
66
"claude-code",

dashboard/backend/app.py

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -210,45 +210,9 @@
210210
END;
211211
""")
212212
_conn.commit()
213-
# Seed data if missions table is empty (guard on row count, not table existence)
214-
_cur.execute("SELECT COUNT(*) FROM missions")
215-
if _cur.fetchone()[0] == 0:
216-
_now_seed = "2026-04-14T00:00:00.000000Z"
217-
_cur.execute("""
218-
INSERT INTO missions (slug, title, description, target_metric, target_value, current_value, due_date, status, created_at, updated_at)
219-
VALUES ('evo-revenue-1m-q4-2026', 'Evolution Revenue $1M Q4 2026',
220-
'Atingir $1M de receita anual até o Q4 2026',
221-
'revenue_usd', 1000000, 0, '2026-12-31', 'active', ?, ?)
222-
""", (_now_seed, _now_seed))
223-
_mission_id = _cur.lastrowid
224-
# Projects
225-
for _slug, _title, _desc in [
226-
('evo-ai', 'Evo AI', 'CRM + AI agents — produto principal'),
227-
('evo-summit', 'Evolution Summit', 'Evento de lançamento (14-16 Abr 2026)'),
228-
('evo-academy', 'Evo Academy', 'Plataforma de cursos'),
229-
]:
230-
_cur.execute("""
231-
INSERT INTO projects (slug, mission_id, title, description, status, created_at, updated_at)
232-
VALUES (?, ?, ?, ?, 'active', ?, ?)
233-
""", (_slug, _mission_id, _title, _desc, _now_seed, _now_seed))
234-
_conn.commit()
235-
# Goals per project
236-
_evo_ai_id = _cur.execute("SELECT id FROM projects WHERE slug='evo-ai'").fetchone()[0]
237-
_summit_id = _cur.execute("SELECT id FROM projects WHERE slug='evo-summit'").fetchone()[0]
238-
_academy_id = _cur.execute("SELECT id FROM projects WHERE slug='evo-academy'").fetchone()[0]
239-
_goals_seed = [
240-
('evo-ai-100-customers', _evo_ai_id, '100 paying customers by Jun 30', 'customers', 'count', 100, '2026-06-30'),
241-
('evo-ai-billing-v2', _evo_ai_id, 'Ship billing v2', 'shipped', 'boolean', 1, '2026-05-31'),
242-
('evo-summit-200-tickets', _summit_id, 'Sell 200 tickets', 'tickets_sold', 'count', 200, '2026-04-13'),
243-
('evo-summit-3-sponsors', _summit_id, 'Close 3 sponsors', 'sponsors', 'count', 3, '2026-04-10'),
244-
('evo-academy-50-students', _academy_id, '50 beta students', 'students', 'count', 50, '2026-06-30'),
245-
]
246-
for _gs in _goals_seed:
247-
_cur.execute("""
248-
INSERT INTO goals (slug, project_id, title, target_metric, metric_type, target_value, current_value, status, created_at, updated_at)
249-
VALUES (?, ?, ?, ?, ?, ?, 0, 'active', ?, ?)
250-
""", (_gs[0], _gs[1], _gs[2], _gs[3], _gs[4], _gs[5], _now_seed, _now_seed))
251-
_conn.commit()
213+
# No seed data — Goals start empty. Users create Mission → Project → Goal via UI
214+
# or via the create-goal skill. Previous seed was Evolution-specific and leaked
215+
# into fresh installations of open-source users.
252216
# --- End Goal Cascade migration ---
253217

254218
# --- Tickets migration (Feature 1.3) ---

dashboard/frontend/src/pages/Goals.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,8 +690,11 @@ export default function Goals() {
690690

691691
{/* Mission tree */}
692692
{filteredMissions.length === 0 ? (
693-
<div className="text-center py-16 text-[#667085] text-sm">
694-
No missions found. Run the backend migration to seed initial data.
693+
<div className="text-center py-16 px-4">
694+
<p className="text-sm text-[#e6edf3] mb-2">Nenhuma Mission criada ainda.</p>
695+
<p className="text-xs text-[#667085] max-w-md mx-auto">
696+
Missions são os objetivos de topo da sua organização. Projects e Goals descendem delas. Use a skill <code className="text-[#00FFA7]">/create-goal</code> para criar a primeira.
697+
</p>
695698
</div>
696699
) : (
697700
filteredMissions.map((mission) => (

dashboard/frontend/src/pages/TicketDetail.tsx

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,35 @@ export default function TicketDetail() {
271271
// memory fetch failure is non-fatal
272272
}
273273

274-
const systemPromptExtras = memoryContent
275-
? `## Thread Memory\n\nThis is a persistent thread. Below is the accumulated memory from previous sessions:\n\n${memoryContent}`
276-
: ''
274+
// Build a scoped context block — always injected, not just when memory exists.
275+
// Goal: tell the agent it is running inside a persistent thread with
276+
// fixed scope, a dedicated memory file, and a default working folder,
277+
// so it does not treat every turn as a fresh session nor invoke
278+
// sub-tasks of itself.
279+
const lines: string[] = []
280+
lines.push('## Thread Context')
281+
lines.push('')
282+
lines.push('You are running inside a **persistent chat thread** on EvoNexus, not a fresh one-shot session. This means:')
283+
lines.push('')
284+
lines.push(`- **Thread title:** "${t.title}"`)
285+
if (t.description) lines.push(`- **Description:** ${t.description}`)
286+
lines.push(`- **Your role:** you are the agent \`@${t.assignee_agent}\` — this thread is yours and will not switch agents. Do NOT invoke the \`Agent\` tool with \`subagent_type: ${t.assignee_agent}\` to re-launch yourself; you are already running.`)
287+
if (t.workspace_path) {
288+
lines.push(`- **Default working folder:** \`${t.workspace_path}\` — all artifacts you produce belong here unless stated otherwise.`)
289+
}
290+
lines.push('- **Memory:** a curated \`memory.md\` lives under `memory/threads/{this_ticket_id}/memory.md`. It is summarised every 20 turns. You may read and update it as part of your work to preserve knowledge across turns/days.')
291+
lines.push('- **Resume behaviour:** conversations here survive browser closes and day breaks via Claude CLI `--resume`. Assume continuity, not a cold start.')
292+
lines.push('')
293+
lines.push('Delegate to other agents via the `Agent` tool only when the task genuinely falls outside your own specialty, not as a way to "call yourself".')
294+
295+
if (memoryContent.trim()) {
296+
lines.push('')
297+
lines.push('## Thread Memory (accumulated from previous turns)')
298+
lines.push('')
299+
lines.push(memoryContent.trim())
300+
}
301+
302+
const systemPromptExtras = lines.join('\n')
277303

278304
// Get or create session scoped to this ticket
279305
const sessionRes = await fetch(`${TS_HTTP}/api/sessions/for-agent`, {
@@ -307,12 +333,19 @@ export default function TicketDetail() {
307333
}
308334
}, [])
309335

336+
// Reset thread session state when ticket id changes (switching threads via sidebar)
337+
// Without this, threadSessionId stays pinned to the previous thread and AgentChat
338+
// keeps rendering the old conversation until a full remount happens.
339+
useEffect(() => {
340+
setThreadSessionId(null)
341+
}, [ticket?.id])
342+
310343
// Auto-init thread session when ticket loads as thread
311344
useEffect(() => {
312345
if (ticket?.is_thread && !threadSessionId && !sessionLoading) {
313346
initThreadSession(ticket)
314347
}
315-
}, [ticket?.id, ticket?.is_thread])
348+
}, [ticket?.id, ticket?.is_thread, threadSessionId, sessionLoading])
316349

317350
// Option D: fire turn-completed on each chat_complete in thread mode
318351
const handleTurnCompleted = useCallback(async () => {
@@ -481,6 +514,7 @@ export default function TicketDetail() {
481514
)}
482515
<div className={`flex-1 overflow-hidden${ticket.status === 'archived' ? ' pointer-events-none opacity-60' : ''}`}>
483516
<AgentChat
517+
key={ticket.id}
484518
agent={ticket.assignee_agent || ''}
485519
sessionId={threadSessionId}
486520
workingDir={ticket.workspace_path || undefined}

dashboard/frontend/src/pages/Topics.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,8 @@ function CreateModal({ onClose, onCreated }: CreateModalProps) {
280280
onBlur={() => setTimeout(() => setAgentOpen(false), 150)}
281281
/>
282282
{agentOpen && filteredAgents.length > 0 && (
283-
<div className="absolute z-10 mt-1 w-full max-h-48 overflow-y-auto bg-[#161b22] border border-[#21262d] rounded-lg shadow-xl">
284-
{filteredAgents.slice(0, 20).map(slug => (
283+
<div className="absolute z-10 mt-1 w-full max-h-72 overflow-y-auto bg-[#161b22] border border-[#21262d] rounded-lg shadow-xl">
284+
{filteredAgents.map(slug => (
285285
<button
286286
type="button"
287287
key={slug}

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.30.0"
3+
version = "0.30.1"
44
description = "Unofficial open source toolkit for Claude Code — AI-powered business operating system"
55
requires-python = ">=3.10"
66
dependencies = [

0 commit comments

Comments
 (0)