release: v2.0.8 - UX Persistence & Per-Agent Knowledge Mix (2026-05-14)
This commit is contained in:
+31
-20
@@ -321,26 +321,10 @@
|
||||
.input-footer { display: flex; align-items: center; justify-content: space-between; }
|
||||
.footer-left { display: flex; align-items: center; gap: 8px; }
|
||||
|
||||
/* Company chip — sits in the records-line beside the Records ▾ menu. */
|
||||
.company-chip {
|
||||
display: inline-flex; align-items: center; gap: 5px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 999px;
|
||||
padding: 3px 10px;
|
||||
color: var(--text-dim);
|
||||
font-size: 11px; font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
.company-chip:hover { border-color: var(--border-bright); color: var(--text-primary); }
|
||||
.company-chip[data-active="true"] {
|
||||
background: var(--accent-glow);
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
.company-chip-icon { font-size: 12px; }
|
||||
.company-manage-btn { padding: 2px 6px; font-size: 11px; margin-left: 2px; }
|
||||
/* (Removed) Pill-shaped `.company-chip` / `.company-manage-btn` —
|
||||
the Corp toggle now lives in the header toolbar reusing the
|
||||
existing `.icon-btn.toggle-chip` rounded-rectangle look. See
|
||||
#companyChip in sidebar.html. */
|
||||
.company-name-input {
|
||||
flex: 1; background: var(--input-bg); border: 1px solid var(--border);
|
||||
border-radius: 6px; padding: 6px 10px; color: var(--text-primary); font-size: 12px;
|
||||
@@ -407,6 +391,33 @@
|
||||
background: var(--accent-glow);
|
||||
}
|
||||
|
||||
/* Per-agent Knowledge Mix slider row — sits between the controls
|
||||
row and the (collapsed) prompt editor. Indent matches the
|
||||
prompt-editor indent (38px) so the emoji stays as the visual
|
||||
"ruler" for everything that follows. */
|
||||
.company-agent-mix-row {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
margin: 6px 0 0 38px;
|
||||
font-size: 10px; color: var(--text-dim);
|
||||
}
|
||||
.company-agent-mix-label { flex-shrink: 0; }
|
||||
.company-agent-mix-slider {
|
||||
flex: 1; min-width: 0;
|
||||
accent-color: var(--accent);
|
||||
cursor: pointer;
|
||||
}
|
||||
.company-agent-mix-slider:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.company-agent-mix-hint {
|
||||
flex-shrink: 0; font-size: 9.5px; color: var(--text-dim);
|
||||
min-width: 165px; text-align: right;
|
||||
}
|
||||
.company-agent-mix-cbwrap {
|
||||
display: inline-flex; align-items: center; gap: 3px;
|
||||
font-size: 9.5px; cursor: pointer; color: var(--text-dim);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.company-agent-mix-cbwrap input[type="checkbox"] { accent-color: var(--accent); }
|
||||
|
||||
/* Expandable prompt editor under each agent card. Toggled via the
|
||||
Edit button. Three textareas (tagline / specialty / persona) +
|
||||
Reset / Save / Cancel — empty save clears that field's override. */
|
||||
|
||||
+11
-10
@@ -15,6 +15,15 @@
|
||||
<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>
|
||||
@@ -106,16 +115,8 @@
|
||||
<span id="chronicleAutoStatus" title="Project records are saved automatically after meaningful project turns.">Auto Records</span>
|
||||
<span class="rl-latest" id="recordsLatest"></span>
|
||||
</div>
|
||||
<!--
|
||||
Company-mode chip. Click toggles enabled; the ▾ opens the manage
|
||||
overlay. The chip stays visible at all times so the user can flip
|
||||
into 1인 기업 mode from anywhere in the chat surface.
|
||||
-->
|
||||
<button class="company-chip" id="companyChip" data-active="false" title="1인 기업 모드 토글">
|
||||
<span class="company-chip-icon">🏢</span>
|
||||
<span class="company-chip-label" id="companyChipLabel">Company OFF</span>
|
||||
</button>
|
||||
<button class="icon-btn company-manage-btn" id="companyManageBtn" data-tooltip="회사 관리 (에이전트·모델 설정)">▾</button>
|
||||
<!-- (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>
|
||||
|
||||
+99
-6
@@ -1432,7 +1432,6 @@
|
||||
// model overrides. State round-trips through `companyStatus` /
|
||||
// `companyAgents` messages so the webview and extension stay in sync.
|
||||
const _companyChip = document.getElementById('companyChip');
|
||||
const _companyChipLabel = document.getElementById('companyChipLabel');
|
||||
const _companyManageBtn = document.getElementById('companyManageBtn');
|
||||
const _companyOverlay = document.getElementById('companyOverlay');
|
||||
const _closeCompanyBtns = [
|
||||
@@ -1444,17 +1443,29 @@
|
||||
const _companyAgentList = document.getElementById('companyAgentList');
|
||||
const _companyStatusEl = document.getElementById('companyStatus');
|
||||
|
||||
/**
|
||||
* Chip lives in the main header toolbar now, so it uses the same
|
||||
* `icon-btn.active` styling as `brainTraceBtn` / `internetBtn`.
|
||||
* Detail (company name + agent count) goes in the tooltip — the
|
||||
* label stays a constant "Corp" so the toolbar tone-and-manner
|
||||
* isn't broken by a wildly varying-width chip.
|
||||
*/
|
||||
const renderCompanyChip = (active, summary) => {
|
||||
if (!_companyChip || !_companyChipLabel) return;
|
||||
_companyChip.setAttribute('data-active', active ? 'true' : 'false');
|
||||
_companyChipLabel.textContent = active ? (summary || 'Company ON') : 'Company OFF';
|
||||
if (!_companyChip) return;
|
||||
_companyChip.classList.toggle('active', !!active);
|
||||
_companyChip.setAttribute(
|
||||
'data-tooltip',
|
||||
active
|
||||
? `1인 기업 ON · ${summary || ''}`.trim()
|
||||
: '1인 기업 모드 OFF — 클릭해서 켜기',
|
||||
);
|
||||
};
|
||||
|
||||
if (_companyChip) {
|
||||
_companyChip.onclick = () => {
|
||||
const isActive = _companyChip.getAttribute('data-active') === 'true';
|
||||
const isActive = _companyChip.classList.contains('active');
|
||||
// Optimistic flip — backend echoes the canonical state back.
|
||||
renderCompanyChip(!isActive, _companyChipLabel?.textContent || '');
|
||||
renderCompanyChip(!isActive, '');
|
||||
vscode.postMessage({ type: 'setCompanyEnabled', value: !isActive });
|
||||
};
|
||||
}
|
||||
@@ -1612,6 +1623,15 @@
|
||||
row.appendChild(controls);
|
||||
li.appendChild(row);
|
||||
|
||||
// ── Row 1.5: per-agent Knowledge Mix slider ──
|
||||
// CEO doesn't dispatch agents itself, it only synthesises,
|
||||
// so the brain mix for CEO turns is governed by the
|
||||
// *specialist* it dispatched — exposing the slider for CEO
|
||||
// would just be a confusing dead control.
|
||||
if (a.id !== 'ceo') {
|
||||
li.appendChild(_buildAgentKnowledgeMixSlider(a, payload.globalKnowledgeMixWeight));
|
||||
}
|
||||
|
||||
// ── Row 2 (collapsed by default): prompt editor ──
|
||||
li.appendChild(_buildAgentPromptEditor(a));
|
||||
_companyAgentList.appendChild(li);
|
||||
@@ -1619,6 +1639,79 @@
|
||||
if (_companyStatusEl) _companyStatusEl.textContent = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline Knowledge Mix slider for one agent. Empty (override = null)
|
||||
* means "use the global slider value" — shown as a hint label so the
|
||||
* user knows what they'll fall back to. Slider commits on `change`
|
||||
* (not `input`) so dragging doesn't spam writes.
|
||||
*/
|
||||
function _buildAgentKnowledgeMixSlider(a, globalWeight) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'company-agent-mix-row';
|
||||
const usingOverride = a.knowledgeMixOverride !== null && a.knowledgeMixOverride !== undefined;
|
||||
const effective = a.effectiveKnowledgeMixWeight;
|
||||
const label = document.createElement('span');
|
||||
label.className = 'company-agent-mix-label';
|
||||
label.textContent = '🎚 Knowledge Mix';
|
||||
const slider = document.createElement('input');
|
||||
slider.type = 'range';
|
||||
slider.min = '0'; slider.max = '100'; slider.step = '5';
|
||||
slider.value = String(effective);
|
||||
slider.disabled = !usingOverride;
|
||||
slider.className = 'company-agent-mix-slider';
|
||||
const hint = document.createElement('span');
|
||||
hint.className = 'company-agent-mix-hint';
|
||||
const renderHint = () => {
|
||||
const w = parseInt(slider.value, 10) || 50;
|
||||
const tag = usingOverride
|
||||
? `override · Model ${100 - w}% / Brain ${w}%`
|
||||
: `global · Model ${100 - effective}% / Brain ${effective}%`;
|
||||
hint.textContent = tag;
|
||||
};
|
||||
const cb = document.createElement('input');
|
||||
cb.type = 'checkbox'; cb.checked = !usingOverride;
|
||||
cb.className = 'company-agent-mix-cb';
|
||||
cb.title = '글로벌 슬라이더 값 사용';
|
||||
cb.onchange = () => {
|
||||
if (cb.checked) {
|
||||
// Reset to global.
|
||||
slider.disabled = true;
|
||||
slider.value = String(globalWeight ?? 50);
|
||||
vscode.postMessage({
|
||||
type: 'setCompanyAgentKnowledgeMix',
|
||||
agentId: a.id, value: null,
|
||||
});
|
||||
} else {
|
||||
// Take ownership at the current displayed value.
|
||||
slider.disabled = false;
|
||||
const w = parseInt(slider.value, 10) || 50;
|
||||
vscode.postMessage({
|
||||
type: 'setCompanyAgentKnowledgeMix',
|
||||
agentId: a.id, value: w,
|
||||
});
|
||||
}
|
||||
};
|
||||
slider.addEventListener('input', renderHint);
|
||||
slider.addEventListener('change', () => {
|
||||
if (cb.checked) return; // safety: shouldn't fire when disabled
|
||||
const w = parseInt(slider.value, 10) || 50;
|
||||
vscode.postMessage({
|
||||
type: 'setCompanyAgentKnowledgeMix',
|
||||
agentId: a.id, value: w,
|
||||
});
|
||||
});
|
||||
renderHint();
|
||||
const cbWrap = document.createElement('label');
|
||||
cbWrap.className = 'company-agent-mix-cbwrap';
|
||||
cbWrap.appendChild(cb);
|
||||
cbWrap.appendChild(document.createTextNode(' use global'));
|
||||
row.appendChild(label);
|
||||
row.appendChild(slider);
|
||||
row.appendChild(hint);
|
||||
row.appendChild(cbWrap);
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the per-agent prompt editor. Hidden until the user clicks
|
||||
* the Edit button. Three fields (tagline / specialty / persona);
|
||||
|
||||
Reference in New Issue
Block a user