release: v2.0.3 - AI 1-Person Company Engine & Business Intelligence

This commit is contained in:
g1nation
2026-05-13 23:22:00 +09:00
parent c40571b7ef
commit b6899851c3
31 changed files with 2504 additions and 41 deletions
+97
View File
@@ -34,6 +34,15 @@ import {
scanProject,
} from './features/projectArchitecture';
import { detectProjectIntent, KnownProject } from './features/projectArchitecture/intentDetector';
import {
readCompanyState,
runCompanyTurn,
summarizeForChip,
CompanyTurnEvent,
COMPANY_AGENTS,
COMPANY_AGENT_ORDER,
} from './features/company';
import { AIService } from './core/services';
export interface SidebarLmStudioDeps {
lifecycle: ModelLifecycleManager;
@@ -1177,6 +1186,94 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
});
}
// ─── 1인 기업 (Company) Mode ────────────────────────────────────────────
//
// When `companyState.enabled` is true, prompts coming through the chat
// handler are routed to `_runCompanyTurn` instead of the normal
// AgentExecutor path. The dispatcher emits `companyTurnUpdate` events as
// each phase progresses; the webview shows a step-by-step header for
// CEO planning, each specialist's dispatch, and the final synthesis.
/** True iff company mode is active. Cheap — read from globalState. */
isCompanyModeEnabled(): boolean {
return readCompanyState(this._context).enabled;
}
/** Send the chip state (active flag + agent count + name) to the webview. */
async _sendCompanyStatus(): Promise<void> {
if (!this._view) return;
const state = readCompanyState(this._context);
this._view.webview.postMessage({
type: 'companyStatus',
value: {
enabled: state.enabled,
companyName: state.companyName,
summary: summarizeForChip(state),
activeAgentIds: state.activeAgentIds,
modelOverrides: state.modelOverrides,
},
});
}
/** Push the full agent catalogue when the manage panel opens. */
async _sendCompanyAgents(): Promise<void> {
if (!this._view) return;
const state = readCompanyState(this._context);
const agents = COMPANY_AGENT_ORDER.map((id) => {
const def = COMPANY_AGENTS[id];
return {
id,
name: def.name,
role: def.role,
emoji: def.emoji,
color: def.color,
tagline: def.tagline,
specialty: def.specialty,
hasPersona: !!def.persona,
alwaysOn: !!def.alwaysOn,
active: id === 'ceo' || state.activeAgentIds.includes(id),
modelOverride: state.modelOverrides[id] || '',
};
});
this._view.webview.postMessage({
type: 'companyAgents',
value: {
companyName: state.companyName,
agents,
},
});
}
/**
* Drive one full company turn. Caller is the chat handler; it's already
* persisted the user message and started a streaming bubble. We feed
* progress events back as `companyTurnUpdate` messages so the same bubble
* fills in as each agent finishes.
*/
async _runCompanyTurn(userPrompt: string): Promise<void> {
const cfg = getConfig();
const ai = new AIService();
const emit = (event: CompanyTurnEvent) => {
this._view?.webview.postMessage({ type: 'companyTurnUpdate', value: event });
};
try {
await runCompanyTurn(userPrompt, {
context: this._context,
ai,
defaultModel: cfg.defaultModel || 'gemma4:e2b',
onEvent: emit,
});
} catch (e: any) {
logError('company.runTurn: unexpected failure.', { error: e?.message ?? String(e) });
this._view?.webview.postMessage({
type: 'error',
value: `1인 기업 모드 실행 실패: ${e?.message ?? e}`,
});
} finally {
void this._sendReadyStatus();
}
}
/** Open the architecture doc in editor group 2. */
async _openArchitectureDoc(): Promise<void> {
const p = this._getActiveChronicleProject();