diff --git a/public/js/app.js b/public/js/app.js
index 96e25cd..0902107 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -142,58 +142,113 @@
sessionPanel.setActive(sessionId);
const session = bridgeSessions.find(s => s.id === sessionId);
if (session) {
- chatPanel.showSession({ name: session.name, status: 'connected' });
+ chatPanel.showSession({ name: session.name, status: session.isRunning ? 'running' : 'connected' });
}
- // cascades에서 대화 내용 가져오기
+ // trajectory에서 전체 대화 내용 가져오기
try {
- const res = await fetch('/api/bridge/cascades');
+ const res = await fetch(`/api/bridge/trajectory/${sessionId}`);
if (!res.ok) return;
const data = await res.json();
- const cascadeData = data.cascades || data;
- // 선택된 세션의 데이터 찾기
- const cascade = cascadeData[sessionId];
- if (cascade) {
- const messages = parseCascadeToMessages(cascade);
+ if (data.trajectory?.steps) {
+ const messages = parseTrajectoryToMessages(data.trajectory.steps);
chatPanel.updateChat(messages);
}
} catch (e) {
- console.warn('[Bridge] cascade 로드 실패:', e);
+ console.warn('[Bridge] trajectory 로드 실패:', e);
}
}
/**
- * Cascade 데이터를 ChatPanel이 이해하는 message[] 형식으로 변환
+ * Trajectory 스텝 배열을 ChatPanel message[] 형식으로 변환
*/
- function parseCascadeToMessages(cascade) {
+ function parseTrajectoryToMessages(steps) {
const msgs = [];
- // latestNotifyUserStep — 마지막 AI 응답
- if (cascade.latestNotifyUserStep?.step?.notifyUser?.notificationContent) {
- msgs.push({
- type: 'text',
- html: cascade.latestNotifyUserStep.step.notifyUser.notificationContent
- .replace(/\n/g, '
')
- .replace(/\*\*(.*?)\*\*/g, '$1')
- .replace(/`([^`]+)`/g, '$1'),
- });
- }
- // latestTaskBoundaryStep — 현재 작업 상태
- if (cascade.latestTaskBoundaryStep?.step?.taskBoundary) {
- const tb = cascade.latestTaskBoundaryStep.step.taskBoundary;
- msgs.push({
- type: 'task',
- title: tb.taskName || '',
- summary: tb.taskSummary || '',
- status: tb.taskStatus || '',
- mode: tb.mode || '',
- });
- }
- // summary
- if (cascade.summary && msgs.length === 0) {
- msgs.push({ type: 'text', html: `
${cascade.summary}
` }); + for (const step of steps) { + switch (step.type) { + case 'CORTEX_STEP_TYPE_USER_INPUT': { + const text = step.userInput?.items?.[0]?.chunk?.value || ''; + if (text) { + msgs.push({ type: 'user', text }); + } + break; + } + case 'CORTEX_STEP_TYPE_NOTIFY_USER': { + const content = step.notifyUser?.notificationContent || ''; + if (content) { + msgs.push({ + type: 'text', + html: simpleMarkdown(content), + }); + } + break; + } + case 'CORTEX_STEP_TYPE_TASK_BOUNDARY': { + const tb = step.taskBoundary || {}; + if (tb.taskName) { + msgs.push({ + type: 'task', + title: tb.taskName || '', + summary: tb.taskSummary || '', + status: tb.taskStatus || '', + mode: tb.mode || '', + }); + } + break; + } + case 'CORTEX_STEP_TYPE_CODE_ACTION': { + const ca = step.codeAction || {}; + const file = ca.filePath || ca.targetFile || ''; + const desc = ca.description || ''; + if (file || desc) { + msgs.push({ + type: 'code', + language: '', + code: '', + description: `📝 ${file ? file.split(/[\\/]/).pop() : '파일'}: ${desc || '코드 수정'}`, + }); + } + break; + } + case 'CORTEX_STEP_TYPE_RUN_COMMAND': { + const cmd = step.runCommand?.commandLine || step.runCommand?.command || ''; + if (cmd) { + msgs.push({ + type: 'code', + language: 'bash', + code: cmd, + description: `⚡ 명령 실행 (${step.status === 'CORTEX_STEP_STATUS_DONE' ? '완료' : '실행 중'})`, + }); + } + break; + } + case 'CORTEX_STEP_TYPE_PLANNER_RESPONSE': { + // 에이전트 사고 과정 — 접기 가능 + const text = step.plannerResponse?.text || step.plannerResponse?.rawText || ''; + if (text && text.length > 10) { + msgs.push({ + type: 'thought', + text: text.substring(0, 300) + (text.length > 300 ? '...' : ''), + }); + } + break; + } + // 덜 중요한 스텝은 생략 (VIEW_FILE, LIST_DIRECTORY, EPHEMERAL 등) + } } return msgs; } + function simpleMarkdown(text) { + return text + .replace(/&/g, '&').replace(//g, '>') + .replace(/\n/g, '$1')
+ .replace(/^## (.*)/gm, '