release: v2.0.2 - Structural Integrity & Automated Context Management

This commit is contained in:
g1nation
2026-05-13 22:34:44 +09:00
parent e85e11aac6
commit c40571b7ef
22 changed files with 2802 additions and 232 deletions
+17 -16
View File
@@ -357,24 +357,25 @@
border-color: var(--border-bright);
}
/* Compact model picker placed directly below the input box. */
.input-model-row {
display: flex; align-items: center; gap: 8px;
margin-top: 6px; padding: 4px 8px;
background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
/* Inline model picker that lives in the input footer, next to the attach
button. Replaces the (now-removed) bottom model row + the separate
"Model: ..." status text — one surface, click to change. */
.model-pill {
display: inline-flex; align-items: center; gap: 4px;
font-size: 10px; color: var(--text-dim); max-width: 220px;
}
.input-model-label {
font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
color: var(--text-dim); flex-shrink: 0;
.model-prefix { color: var(--text-dim); flex-shrink: 0; }
.model-inline-sel {
background: transparent; border: none; outline: none;
color: var(--text-primary); font-size: 10px;
padding: 0; margin: 0; cursor: pointer;
max-width: 180px; min-width: 0;
text-overflow: ellipsis; overflow: hidden; white-space: nowrap;
font-weight: 500;
}
.input-model-select-wrap { flex: 1; min-width: 0; }
.input-model-select-wrap select {
width: 100%; min-width: 0;
background: transparent; color: var(--text-primary);
border: none; outline: none; padding: 4px 6px;
font-size: 11px; cursor: pointer;
}
.input-model-select-wrap select:focus { box-shadow: 0 0 0 2px var(--accent-glow); border-radius: 4px; }
.model-inline-sel:hover { color: var(--accent); }
.model-inline-sel:focus-visible { outline: 1px dashed var(--accent); outline-offset: 2px; }
.status-label { font-size: 10px; color: var(--text-dim); }
.send-btn {
background: var(--accent); color: #fff; border: none; padding: 6px 14px; border-radius: 6px;
+6 -8
View File
@@ -257,11 +257,15 @@
</div>
<div class="input-box">
<div id="attachPreview" class="attachment-preview"></div>
<textarea id="input" rows="1" placeholder="Type your request..."></textarea>
<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 id="statusLabel" style="font-size:10px; color:var(--text-dim);">Ready</span>
<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">
@@ -272,12 +276,6 @@
</div>
<div id="toastNotif" class="toast-notif"></div>
</div>
<div class="input-model-row" id="inlineModelRow">
<label for="inlineModelSel" class="input-model-label">Model</label>
<div class="select-wrap input-model-select-wrap">
<select id="inlineModelSel" title="Switch model for this conversation"></select>
</div>
</div>
</div>
<input type="file" id="fileInput" multiple hidden accept="image/*,.txt,.md,.pdf,.csv,.json,.js,.ts,.py,.java,.rs,.go">
</div>
+15 -15
View File
@@ -660,7 +660,7 @@
break;
case 'modelsList': {
modelSel.innerHTML = '';
const inlineModelSel = document.getElementById('inlineModelSel');
const inlineModelSel = document.getElementById('modelInlineSel');
if (inlineModelSel) inlineModelSel.innerHTML = '';
// [State Persistence - Tier 2] LocalStorage에서 마지막 선택 모델 복원 시도
const _savedModel = localStorage.getItem('g1nation_last_model');
@@ -690,8 +690,10 @@
if (_savedModel && _savedModel !== msg.value.selected && msg.value.models.includes(_savedModel)) {
vscode.postMessage({ type: 'model', value: _savedModel });
}
if (typeof updateInputPlaceholder === 'function') updateInputPlaceholder();
statusLabel.innerText = `Model: ${_preferredModel}`;
// The model name is now visible inside the footer pill itself,
// so statusLabel is reserved for actual status (autoContinue
// progress, etc.). Keep it empty in steady state.
statusLabel.innerText = '';
// Refresh per-agent model dropdown options (if currently visible) so it stays in sync.
if (typeof refreshAgentMapModelOptions === 'function') refreshAgentMapModelOptions();
break;
@@ -820,7 +822,7 @@
// clearing the override should restore the previous selection.
const pinned = msg.value && msg.value.model;
if (pinned) {
const inlineSel = document.getElementById('inlineModelSel');
const inlineSel = document.getElementById('modelInlineSel');
// Add an option if it isn't already known so the value can stick.
const ensureOption = (sel) => {
if (!sel) return;
@@ -835,8 +837,9 @@
};
ensureOption(modelSel);
ensureOption(inlineSel);
statusLabel.innerText = `Model: ${pinned} (agent override)`;
if (typeof updateInputPlaceholder === 'function') updateInputPlaceholder();
// The pill shows the model directly; surface the override as a tooltip
// instead of a duplicate status string.
if (inlineSel) inlineSel.title = `Model pinned by current agent: ${pinned}`;
}
break;
}
@@ -1149,13 +1152,13 @@
document.getElementById('historyBtn').onclick = () => vscode.postMessage({ type: 'getSessions' });
document.getElementById('historyBtn').addEventListener('click', () => historyOverlay.classList.add('visible'));
document.getElementById('closeHistoryBtn').onclick = () => historyOverlay.classList.remove('visible');
// The input placeholder is now a constant brand label — the model name
// lives in the footer pill itself, so we don't repeat it here.
const updateInputPlaceholder = () => {
if (typeof input !== 'undefined' && input) {
input.placeholder = `Ask ${modelSel ? modelSel.value : 'AI'}...`;
}
if (typeof input !== 'undefined' && input) input.placeholder = 'Ask Astra...';
};
// Shared handler so the top-bar dropdown and the inline-below-input dropdown
// Shared handler so the header dropdown and the footer pill dropdown
// always commit the same way and stay visually synced.
const applyModelSelection = (selectedModel, originEl) => {
if (!selectedModel) return;
@@ -1168,15 +1171,12 @@
// [State Persistence - Tier 1] VS Code 전역 설정에 동기화 (영구 저장)
vscode.postMessage({ type: 'model', value: selectedModel });
// Mirror the value to the *other* dropdown so both pickers reflect reality.
const inlineSel = document.getElementById('inlineModelSel');
const inlineSel = document.getElementById('modelInlineSel');
if (originEl !== modelSel && modelSel.value !== selectedModel) modelSel.value = selectedModel;
if (inlineSel && originEl !== inlineSel && inlineSel.value !== selectedModel) inlineSel.value = selectedModel;
updateInputPlaceholder();
// 상태 레이블 즉시 업데이트
statusLabel.innerText = `Model: ${selectedModel}`;
};
modelSel.onchange = () => applyModelSelection(modelSel.value, modelSel);
const _inlineModelSelEl = document.getElementById('inlineModelSel');
const _inlineModelSelEl = document.getElementById('modelInlineSel');
if (_inlineModelSelEl) {
_inlineModelSelEl.onchange = () => applyModelSelection(_inlineModelSelEl.value, _inlineModelSelEl);
}