v2.2.15: Astra Office Refactor & Multi-Service Integration
This commit is contained in:
@@ -945,6 +945,7 @@
|
||||
case 'companyStatus': {
|
||||
const v = msg.value || {};
|
||||
renderCompanyChip(!!v.enabled, v.summary || '');
|
||||
renderScopeSeg(v.activePipelineId || null);
|
||||
break;
|
||||
}
|
||||
case 'companyIntentDecision': {
|
||||
@@ -965,11 +966,51 @@
|
||||
break;
|
||||
}
|
||||
case 'pixelOfficeUpdate': {
|
||||
// 새 path (officeSnapshot) 가 한 번이라도 도착했다면 옛 message 는 무시.
|
||||
if (window.__officeSnapshotSeen) break;
|
||||
if (typeof window.__pixelOfficeApply === 'function') {
|
||||
window.__pixelOfficeApply(msg.value || {});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'officeSnapshot': {
|
||||
// refactor #E — mini view 도 OfficeSnapshot 수신.
|
||||
// OfficeSnapshot 을 옛 {state, bubbles, config} payload 모양으로 변환 후
|
||||
// 기존 __pixelOfficeApply 재사용. dual-mode 안전 전환.
|
||||
window.__officeSnapshotSeen = true;
|
||||
const snap = msg.value;
|
||||
if (!snap || typeof window.__pixelOfficeApply !== 'function') break;
|
||||
const roster = Array.isArray(snap.roster) ? snap.roster : [];
|
||||
const active = (snap.activeAgentId && roster.find((a) => a.agentId === snap.activeAgentId)) || roster[0];
|
||||
const phaseToStatus = (p) => {
|
||||
if (p === 'awaiting-approval') return 'waiting_approval';
|
||||
if (p === 'reporting') return 'done';
|
||||
if (p === 'intake') return 'analyzing';
|
||||
return p || 'idle';
|
||||
};
|
||||
const synthetic = {
|
||||
agentId: snap.activeAgentId || (active && active.agentId) || 'main',
|
||||
agentName: (active && active.agentName) || 'Agent',
|
||||
status: (active && active.status) || phaseToStatus(snap.phase),
|
||||
currentTask: snap.task && snap.task.goal,
|
||||
currentStep: active && active.currentStep,
|
||||
message: snap.activeAgentId || '',
|
||||
recentLogs: (active && active.lastLog) ? [active.lastLog] : [],
|
||||
progress: snap.pipeline ? (snap.pipeline.index / Math.max(1, snap.pipeline.stages.length)) : 0,
|
||||
pipelineStages: snap.pipeline && snap.pipeline.stages,
|
||||
needUserInput: (snap.awaiting && snap.awaiting.kind === 'clarification') ? snap.awaiting.questions : undefined,
|
||||
awaitingApproval: (snap.awaiting && snap.awaiting.kind === 'approval') ? snap.awaiting.questions[0] : undefined,
|
||||
requirementContract: snap.task,
|
||||
updatedAt: snap.updatedAt,
|
||||
};
|
||||
window.__pixelOfficeApply({
|
||||
state: synthetic,
|
||||
bubbles: Array.isArray(snap.newBubbles) ? snap.newBubbles : [],
|
||||
// config 는 그대로 유지 — snapshot 에는 enabled 만 함의적, 옛 cfg 가 살아있음.
|
||||
config: undefined,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'companyAlignmentCard': {
|
||||
// Intent Alignment 카드. kind에 따라 4가지 모드:
|
||||
// - 'auto-proceed' : confidence high → 자동 진행 안내(읽기 전용)
|
||||
@@ -1843,8 +1884,44 @@
|
||||
? `1인 기업 ON · ${summary || ''}`.trim()
|
||||
: '1인 기업 모드 OFF — 클릭해서 켜기',
|
||||
);
|
||||
// 스코프 프리셋 segmented control 도 기업 모드 ON 일 때만 노출.
|
||||
const scopeSeg = document.getElementById('companyScopeSeg');
|
||||
if (scopeSeg) scopeSeg.hidden = !active;
|
||||
};
|
||||
|
||||
// 활성 pipeline 의 id 가 어느 SCOPE 프리셋의 suggestedPipelineId 와 매칭되는지로 active 표시.
|
||||
// companyStatus 메시지가 activePipelineId 를 보낼 때마다 호출.
|
||||
const SCOPE_PRESET_TO_PIPELINE_ID = {
|
||||
'plan-only': 'plan-only',
|
||||
'dev-only': 'dev-only',
|
||||
'full-product-dev': 'product-dev',
|
||||
};
|
||||
const renderScopeSeg = (activePipelineId) => {
|
||||
const scopeSeg = document.getElementById('companyScopeSeg');
|
||||
if (!scopeSeg) return;
|
||||
for (const btn of scopeSeg.querySelectorAll('.scope-seg-btn')) {
|
||||
const tplId = btn.getAttribute('data-scope');
|
||||
const expected = SCOPE_PRESET_TO_PIPELINE_ID[tplId];
|
||||
btn.classList.toggle('active', !!activePipelineId && activePipelineId === expected);
|
||||
}
|
||||
};
|
||||
// Wire up clicks once.
|
||||
const _scopeSeg = document.getElementById('companyScopeSeg');
|
||||
if (_scopeSeg && !_scopeSeg.dataset.wired) {
|
||||
_scopeSeg.dataset.wired = '1';
|
||||
_scopeSeg.addEventListener('click', (e) => {
|
||||
const btn = e.target && e.target.closest && e.target.closest('.scope-seg-btn');
|
||||
if (!btn) return;
|
||||
const tplId = btn.getAttribute('data-scope');
|
||||
if (!tplId) return;
|
||||
// Optimistic visual flip — backend ack 가 companyStatus 갱신으로 결과 확정.
|
||||
for (const b of _scopeSeg.querySelectorAll('.scope-seg-btn')) {
|
||||
b.classList.toggle('active', b === btn);
|
||||
}
|
||||
vscode.postMessage({ type: 'setCompanyScopePreset', templateId: tplId });
|
||||
});
|
||||
}
|
||||
|
||||
if (_companyChip) {
|
||||
_companyChip.onclick = () => {
|
||||
const isActive = _companyChip.classList.contains('active');
|
||||
|
||||
Reference in New Issue
Block a user