Files
connectai/media/sidebar.html
T

357 lines
20 KiB
HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Astra</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="__STYLES_URI__">
</head>
<body>
<div class="header">
<div class="header-top">
<div class="brand"><div class="logo"></div> Astra</div>
<div class="header-actions">
<button class="icon-btn" id="newChatBtn" data-tooltip="New Chat">New</button>
<button class="icon-btn toggle-chip active" id="brainTraceBtn" data-tooltip="Second Brain Trace Mode">Trace</button>
<button class="icon-btn toggle-chip" id="internetBtn" data-tooltip="Internet Access">Web</button>
<!--
Corp toggle — replaces the old pill-shaped chip that lived
in the records-line. Same rounded-rectangle style as the
other header buttons. Clicking toggles 1인 기업 모드 on/off;
the adjacent ▾ opens the manage overlay (agents · models ·
prompt edits · Knowledge Mix sliders).
-->
<button class="icon-btn toggle-chip" id="companyChip" data-tooltip="1인 기업 모드 토글">Corp</button>
<button class="icon-btn" id="companyManageBtn" data-tooltip="회사 관리 (에이전트·모델·prompt·Knowledge Mix)"></button>
<div class="hdr-dropdown" data-dd>
<button class="icon-btn" id="toolsMenuBtn" data-dd-trigger data-tooltip="Tools">Tools ▾</button>
<div class="hdr-menu" id="toolsMenu" data-dd-menu>
<div class="hdr-menu-label">Tools</div>
<button class="hdr-menu-item toggle-item" id="brainTraceDebugBtn" data-tooltip="Second Brain Debug JSON">Debug Trace JSON</button>
<button class="hdr-menu-item" id="saveWikiRawBtn" data-tooltip="Save Wiki Raw">Save Wiki Raw</button>
<button class="hdr-menu-item" id="brainBtn" data-tooltip="Sync Knowledge (commit + push)">Sync Knowledge</button>
</div>
</div>
<button class="icon-btn" id="historyBtn" data-tooltip="View History">History</button>
<button class="icon-btn" id="settingsBtn" data-tooltip="Settings">Set</button>
</div>
</div>
</div>
<div id="readyBar" class="ready-bar" title="현재 준비 상태 — 엔진 / 모델 / 컨텍스트 창 / 메모리">
<span class="rb-dot" id="rbDot"></span>
<span class="rb-content" id="rbContent">준비 상태 확인 중…</span>
<span id="statusDot" class="status-dot" hidden></span><span id="engineStatusText" hidden></span>
</div>
<div class="context-bar">
<div class="context-summary" id="contextSummary">
<span class="cb-seg"><span class="cb-key">Brain</span> <span id="ctxBrainName" class="cb-val"></span></span>
<span class="cb-sep">·</span>
<span class="cb-seg"><span class="cb-key">Agent</span> <span id="ctxAgentName" class="cb-val"></span></span>
<span class="cb-sep">·</span>
<span class="cb-seg"><span class="cb-key">Project</span> <span id="ctxProjectName" class="cb-val"></span></span>
</div>
<div class="hdr-dropdown context-edit-dd" data-dd>
<button class="icon-btn" id="contextEditBtn" data-dd-trigger data-tooltip="Model / Brain / Agent / Knowledge Map / Project">Edit ▾</button>
<div class="hdr-menu hdr-menu-wide" id="contextEditMenu" data-dd-menu>
<div class="hdr-menu-label">Model</div>
<div class="select-wrap"><select id="modelSel" title="Select Model"></select></div>
<div class="hdr-menu-label">
Knowledge Mix
<span class="hdr-menu-hint" id="knowledgeMixHint">Model 50% · Brain 50%</span>
</div>
<div class="knowledge-mix-control" title="Slide left for more model knowledge, right for more Second Brain reliance">
<span class="km-end-label">Model</span>
<input type="range" id="knowledgeMixSlider" min="0" max="100" step="5" value="50" class="km-slider">
<span class="km-end-label">Brain</span>
</div>
<div class="hdr-menu-label">Brain</div>
<div class="control-row">
<div class="select-wrap"><select id="brainSel" title="Select Brain"></select></div>
<div class="tool-group" aria-label="Brain actions">
<button class="icon-btn" id="addBrainBtn" data-tooltip="Add Brain">Add</button>
<button class="icon-btn" id="editBrainBtn" data-tooltip="Edit Brain">Edit</button>
<button class="icon-btn" id="deleteBrainBtn" data-tooltip="Delete Brain">Del</button>
</div>
</div>
<div class="hdr-menu-label">Agent</div>
<div class="control-row">
<div class="select-wrap"><select id="agentSel" title="Select Agentic Skill"></select></div>
<div class="tool-group" aria-label="Agent actions">
<button class="icon-btn" id="addAgentBtn" data-tooltip="Create Agent">Add</button>
<button class="icon-btn" id="editAgentBtn" data-tooltip="Edit Agent Skill">Edit</button>
<button class="icon-btn" id="deleteAgentBtn" data-tooltip="Delete Agent Skill">Del</button>
</div>
</div>
<div class="hdr-menu-label">Agent ↔ Knowledge</div>
<div class="control-row">
<div class="select-wrap"><select id="knowledgeScopeSel" title="Knowledge folders mapped to this agent"></select></div>
<div class="tool-group" aria-label="Knowledge map actions">
<button class="icon-btn" id="editKnowledgeMapBtn" data-tooltip="Edit Agent ↔ Knowledge Map">Map</button>
<button class="icon-btn" id="reloadKnowledgeMapBtn" data-tooltip="Reload Knowledge Map">Rld</button>
</div>
</div>
<div class="hdr-menu-label">Project (Chronicle)</div>
<div class="control-row">
<div class="select-wrap"><select id="designerSel" title="Select Designer Project"></select></div>
<div class="tool-group" aria-label="Designer actions">
<button class="icon-btn" id="addDesignerBtn" data-tooltip="Create Designer Project">Add</button>
</div>
</div>
</div>
</div>
</div>
<div class="records-line">
<div class="rl-summary">
<span class="status-dot ready"></span>
<span id="chronicleAutoStatus" title="Project records are saved automatically after meaningful project turns.">Auto Records</span>
<span class="rl-latest" id="recordsLatest"></span>
</div>
<!-- (Removed) Corp chip moved to the header toolbar above —
see #companyChip / #companyManageBtn alongside New/Trace/Web. -->
<div class="hdr-dropdown" data-dd>
<button class="icon-btn" id="recordsMenuBtn" data-dd-trigger data-tooltip="Chronicle records">Records ▾</button>
<div class="hdr-menu hdr-menu-wide" id="recordsMenu" data-dd-menu>
<div class="hdr-menu-label">Chronicle Records</div>
<div class="select-wrap"><select id="chronicleRecordSel" title="Select Chronicle Record"></select></div>
<button class="hdr-menu-item" id="openChronicleRecordBtn" data-tooltip="Open Selected Record">Open Selected Record</button>
<button class="hdr-menu-item" id="refreshChronicleRecordsBtn" data-tooltip="Refresh Records">Refresh Records</button>
<button class="hdr-menu-item" id="openDesignerBtn" data-tooltip="Open Record Folder">Open Record Folder</button>
</div>
</div>
</div>
<!--
Company manage overlay. Uses the same overlay framework as the agent
knowledge map modal (`.history-overlay` / `.visible`) so styling and
keyboard dismissal stay consistent.
-->
<div id="companyOverlay" class="history-overlay">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:14px;">
<div>
<h2 style="color:var(--text-bright); margin:0;">🏢 1인 기업 모드</h2>
<p style="margin:4px 0 0; font-size:11px; color:var(--text-dim);">
CEO가 사용자의 요청을 분석하고 활성화된 specialist에게 순차 dispatch합니다.
동시에 메모리에 올라가는 모델은 항상 1개입니다.
</p>
</div>
<button class="icon-btn" id="closeCompanyOverlayBtn"></button>
</div>
<div class="map-section">
<div class="map-section-head">
<div>
<div class="map-section-title">회사 정보</div>
<div class="map-section-hint">CEO와 보고서에 사용되는 회사명. 한국어/영어 모두 가능.</div>
</div>
</div>
<div class="control-row" style="margin-top:8px;">
<input id="companyNameInput" type="text" class="company-name-input" placeholder="회사명 (예: My Company)" />
<button class="secondary-btn" id="saveCompanyNameBtn">저장</button>
</div>
</div>
<div class="map-section">
<div class="map-section-head">
<div>
<div class="map-section-title">활성 에이전트 + 모델</div>
<div class="map-section-hint">CEO는 항상 활성. 각 에이전트별로 모델을 따로 지정할 수 있습니다 — 다른 모델을 쓸 때만 LM Studio가 swap합니다.</div>
</div>
</div>
<ul id="companyAgentList" class="map-list company-agent-list"></ul>
</div>
<div class="map-footer">
<button class="secondary-btn" id="openCompanySessionsBtn" title="이번 회사가 만든 세션 폴더 열기">세션 폴더 열기</button>
<div style="flex:1"></div>
<button class="send-btn" id="closeCompanyOverlayBtn2">닫기</button>
</div>
<div id="companyStatus" class="map-status"></div>
</div>
<div id="historyOverlay" class="history-overlay">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
<h2 style="color:var(--text-bright);">Chat History</h2>
<button class="icon-btn" id="closeHistoryBtn"></button>
</div>
<div id="historyList" style="flex:1; overflow-y:auto;"></div>
</div>
<div id="agentMapOverlay" class="history-overlay">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:14px;">
<div>
<h2 style="color:var(--text-bright); margin:0;">Agent Mapping</h2>
<p style="margin:4px 0 0; font-size:11px; color:var(--text-dim);">
선택한 에이전트에 <strong>지식 폴더</strong><strong>외부 스킬 폴더/파일</strong>을 연결합니다.
</p>
</div>
<button class="icon-btn" id="closeAgentMapBtn"></button>
</div>
<div class="map-agent-row">
<div class="field-label">Agent</div>
<div id="agentMapAgentName" class="map-agent-name">(선택된 에이전트가 없습니다)</div>
</div>
<div class="map-section">
<div class="map-section-head">
<div>
<div class="map-section-title">🤖 Model for this agent</div>
<div class="map-section-hint">이 에이전트를 선택했을 때 사용할 모델을 지정합니다. <strong>Use current model</strong>을 선택하면 상단에서 고른 기본 모델을 그대로 사용합니다.</div>
</div>
</div>
<div class="select-wrap" style="margin-top:8px;">
<select id="agentMapModelSel" title="Model override for this agent"></select>
</div>
</div>
<div class="map-section">
<div class="map-section-head">
<div>
<div class="map-section-title">🎚 Knowledge Mix for this agent</div>
<div class="map-section-hint">에이전트별 의존도. <strong>Use global setting</strong>을 켜두면 상단 슬라이더 값을 그대로 따릅니다.</div>
</div>
</div>
<label class="map-checkbox-row" style="margin-top:8px;">
<input type="checkbox" id="agentMapMixUseGlobal" checked>
<span>Use global setting</span>
</label>
<div class="knowledge-mix-control map-mix-control" style="margin-top:6px;">
<span class="km-end-label">Model</span>
<input type="range" id="agentMapMixSlider" min="0" max="100" step="5" value="50" class="km-slider" disabled>
<span class="km-end-label">Brain</span>
</div>
<div class="map-section-hint" id="agentMapMixHint" style="margin-top:4px;">Model 50% · Brain 50%</div>
</div>
<div class="map-section">
<div class="map-section-head">
<div>
<div class="map-section-title">📚 Knowledge Folders</div>
<div class="map-section-hint">Brain 안에서 검색(RAG)에 사용할 폴더입니다. 폴더가 Brain 외부면 자동으로 제외됩니다.</div>
</div>
<button class="secondary-btn" id="addKnowledgeFolderBtn">+ 폴더 추가</button>
</div>
<ul id="knowledgeFolderList" class="map-list"></ul>
</div>
<div class="map-section">
<div class="map-section-head">
<div>
<div class="map-section-title">🛠 External Skills</div>
<div class="map-section-hint">.md 스킬 파일이 들어 있는 폴더 또는 개별 .md 파일을 연결하세요. 채팅 시 항상 함께 로드됩니다.</div>
</div>
<div class="map-btn-group">
<button class="secondary-btn" id="addSkillFolderBtn">+ 폴더 추가</button>
<button class="secondary-btn" id="addSkillFileBtn">+ 파일 추가</button>
</div>
</div>
<ul id="skillFolderList" class="map-list"></ul>
</div>
<div class="map-footer">
<button class="secondary-btn" id="editAgentMapJsonBtn" title="고급 사용자용: JSON으로 직접 편집">JSON 편집</button>
<div style="flex:1"></div>
<button class="secondary-btn" id="cancelAgentMapBtn">취소</button>
<button class="send-btn" id="saveAgentMapBtn">저장</button>
</div>
<div id="agentMapStatus" class="map-status"></div>
</div>
<div class="thinking-bar" id="thinkingBar"></div>
<div id="stepper" class="stepper-container">
<div class="steps">
<div class="step" id="step-analyze"><div class="step-dot"></div><div class="step-label">Analyze</div></div>
<div class="step" id="step-plan"><div class="step-dot"></div><div class="step-label">Plan</div></div>
<div class="step" id="step-execute"><div class="step-dot"></div><div class="step-label">Execute</div></div>
<div class="step" id="step-verify"><div class="step-dot"></div><div class="step-label">Verify</div></div>
</div>
</div>
<div class="chat" id="chat">
<div class="welcome">
<div class="welcome-logo"></div>
<div class="welcome-title">Welcome to Astra</div>
<p>Your premium local AI assistant.<br>Ready to analyze projects and build reports.</p>
</div>
</div>
<div class="input-wrap">
<!--
Project Architecture chip. Hidden by default; the JS handler flips
`data-active` when the extension host sends an `architectureStatus`
message with active=true. Click "Open" / "Refresh" / "Detach" to
route back to the chatHandlers cases.
-->
<!--
Three-state chip:
data-state="hidden" → completely collapsed
data-state="active" → full info + Open / Refresh / Detach
data-state="inactive" → project name + Attach (or Re-attach) only
JS switches the state attribute on every `architectureStatus`
event so the user always has a one-click path back into project
mode after a Detach.
-->
<div id="archChip" class="arch-chip" data-state="hidden">
<span class="arch-chip-icon">📋</span>
<div class="arch-chip-info">
<div class="arch-chip-title" id="archChipTitle"></div>
<div class="arch-chip-meta" id="archChipMeta"></div>
</div>
<div class="arch-chip-actions" id="archChipActions">
<!-- active state buttons -->
<button class="arch-chip-btn arch-chip-active-only" id="archOpenBtn" title="Architecture 문서 열기">Open</button>
<button class="arch-chip-btn arch-chip-active-only" id="archRefreshBtn" title="지금 다시 스캔">Refresh</button>
<button class="arch-chip-btn arch-chip-active-only" id="archDetachBtn" title="자동 첨부 끄기">Detach</button>
<!-- inactive state button -->
<button class="arch-chip-btn arch-chip-inactive-only" id="archAttachBtn" title="이 프로젝트에 architecture 자동 첨부 켜기">Attach</button>
</div>
</div>
<div id="agentConfigPanel" class="panel">
<div class="field-label">Agent Persona/Instructions</div>
<textarea id="agentPrompt" rows="5" placeholder="Agent Persona & Instructions..."></textarea>
<div class="field-label">Negative Prompt (Strict Rules)</div>
<textarea id="negativePrompt" rows="2" placeholder="What NOT to do..."></textarea>
<button id="updateAgentBtn" class="secondary-btn">Update Agent Skill</button>
</div>
<div class="input-box">
<div id="attachPreview" class="attachment-preview"></div>
<textarea id="input" rows="1" placeholder="Ask Astra..."></textarea>
<div class="input-footer">
<div class="footer-left">
<button class="icon-btn" id="attachBtn" title="Attach Files">📎</button>
<span class="model-pill" title="Switch model for this conversation">
<span class="model-prefix">Model:</span>
<select id="modelInlineSel" class="model-inline-sel" title="Switch model"></select>
</span>
<span id="statusLabel" class="status-label"></span>
<span id="ctxBadge" class="ctx-badge" title="직전 요청에 실제로 들어간 컨텍스트 추정치"></span>
</div>
<div class="footer-right">
<button id="cancelBtn" class="cancel-btn" title="Clear draft" style="display:none;">✕ Clear</button>
<button id="stopBtn" class="stop-btn" title="Stop generation" style="display:none;">■ Stop</button>
<button id="sendBtn" class="send-btn">Send</button>
</div>
</div>
<div id="toastNotif" class="toast-notif"></div>
</div>
</div>
<input type="file" id="fileInput" multiple hidden accept="image/*,.txt,.md,.pdf,.csv,.json,.js,.ts,.py,.java,.rs,.go">
</div>
<script src="__SCRIPT_URI__"></script>
</body>
</html>