Release v2.1.8: Company Agent roster overhaul and UI polish
This commit is contained in:
@@ -3,15 +3,15 @@
|
|||||||
<!-- ASTRA:AUTO-START -->
|
<!-- ASTRA:AUTO-START -->
|
||||||
|
|
||||||
## Snapshot
|
## Snapshot
|
||||||
- **Workspace**: `ConnectAI` `v2.1.2` _(absolute path varies by environment; resolved from the active VS Code workspace)_
|
- **Workspace**: `ConnectAI` `v2.1.8` _(absolute path varies by environment; resolved from the active VS Code workspace)_
|
||||||
- **Description**: The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.
|
- **Description**: The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.
|
||||||
- **Stack**: TypeScript, Node.js, VS Code Extension, LM Studio SDK, Test runner
|
- **Stack**: TypeScript, Node.js, VS Code Extension, LM Studio SDK, Test runner
|
||||||
- **Stats**: 205 source files, ~36,036 lines across 5 top-level modules.
|
- **Stats**: 214 source files, ~39,400 lines across 5 top-level modules.
|
||||||
|
|
||||||
## Last Refresh
|
## Last Refresh
|
||||||
- **Time**: 2026-05-13T17:43:53.933Z
|
- **Time**: 2026-05-14T13:24:53.642Z
|
||||||
- **Files newly analysed**: 0
|
- **Files newly analysed**: 11
|
||||||
- **Files reused from cache**: 205
|
- **Files reused from cache**: 203
|
||||||
|
|
||||||
## Directory Map
|
## Directory Map
|
||||||
```mermaid
|
```mermaid
|
||||||
@@ -37,11 +37,11 @@ mindmap
|
|||||||
> Arrows: which top-level module imports from which.
|
> Arrows: which top-level module imports from which.
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
src["src/<br/>100 files"]
|
src["src/<br/>102 files"]
|
||||||
media["media/<br/>6 files"]
|
media["media/<br/>6 files"]
|
||||||
tests["tests/<br/>27 files"]
|
tests["tests/<br/>27 files"]
|
||||||
core_py["core_py/<br/>6 files"]
|
core_py["core_py/<br/>6 files"]
|
||||||
docs["docs/<br/>66 files"]
|
docs["docs/<br/>73 files"]
|
||||||
tests --> src
|
tests --> src
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -53,21 +53,21 @@ flowchart LR
|
|||||||
|
|
||||||
## Hub Files
|
## Hub Files
|
||||||
> Imported by many other files — touching these has wide blast radius.
|
> Imported by many other files — touching these has wide blast radius.
|
||||||
- `src/utils.ts` — referenced by **43** files
|
- `src/utils.ts` — referenced by **44** files
|
||||||
- `src/config.ts` — referenced by **12** files
|
- `src/config.ts` — referenced by **13** files
|
||||||
- `src/lib/paths.ts` — referenced by **10** files
|
- `src/lib/paths.ts` — referenced by **10** files
|
||||||
- `src/features/company/types.ts` — referenced by **9** files · Type definitions for the 1인 기업 (One-Person Company) mode. The mode turns the user into a virtual CEO that dispatches work to a roster of specialist agents. Each turn produces a session directory conta
|
- `src/features/company/types.ts` — referenced by **10** files · Type definitions for the 1인 기업 (One-Person Company) mode. The mode turns the user into a virtual CEO that dispatches work to a roster of specialist agents. Each turn produces a session directory conta
|
||||||
- `src/features/company/agents.ts` — referenced by **7** files · The 9-agent roster for 1인 기업 모드. Each entry is a static description — persona, role, specialty — used to build the specialist's system prompt at dispatch time. The set was adopted from Connectorigin's
|
- `src/retrieval/lessonHelpers.ts` — referenced by **6** files · Lesson / Experience Memory — pure helpers (no vscode dependency) "Lesson" = a markdown file in the active brain that captures a past mistake/risk and how to avoid repeating it. Identified by a lessons
|
||||||
- `src/skills/agentKnowledgeMap.ts` — referenced by **6** files
|
- `src/skills/agentKnowledgeMap.ts` — referenced by **6** files
|
||||||
- `src/lib/engine.ts` — referenced by **6** files
|
- `src/lib/engine.ts` — referenced by **6** files
|
||||||
- `src/core/services.ts` — referenced by **6** files
|
- `src/core/services.ts` — referenced by **6** files
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
### `src/` — 100 files, ~23,874 lines
|
### `src/` — 102 files, ~25,874 lines
|
||||||
|
|
||||||
**Sub-directories**
|
**Sub-directories**
|
||||||
- `src/features/` (28) — The 9-agent roster for 1인 기업 모드. Each entry is a static description — persona, role, specialty — used to build the speci
|
- `src/features/` (29) — 기본 에이전트 로스터 — 1인 기업 모드의 출고 디폴트. 설계 의도: 제품 개발 파이프라인(기획 → 디자인 → 개발 → QA → 출시 → 마케팅 → 회고)을 한 사람이 1인 기업으로 운영할 때 필요한 직군을 모두 커
|
||||||
- `src/core/` (15) — Astra Path Resolver (경로 해결기) Astra의 모든 데이터 파일(.astra 디렉토리)의 경로를 중앙에서 관리합니다. 확장 프로그램의 설치 경로(extensionUri) 기반으로 .astra 디렉토
|
- `src/core/` (15) — Astra Path Resolver (경로 해결기) Astra의 모든 데이터 파일(.astra 디렉토리)의 경로를 중앙에서 관리합니다. 확장 프로그램의 설치 경로(extensionUri) 기반으로 .astra 디렉토
|
||||||
- `src/memory/` (8) — Episodic Memory (일화 기억) 과거 대화/회의/결정의 맥락 흐름을 저장합니다. 세션 종료 시 자동으로 에피소드를 요약하여 저장합니다. "왜 이렇게 결정했는지", "어떤 흐름으로 진행했는지" 기록. 저장
|
- `src/memory/` (8) — Episodic Memory (일화 기억) 과거 대화/회의/결정의 맥락 흐름을 저장합니다. 세션 종료 시 자동으로 에피소드를 요약하여 저장합니다. "왜 이렇게 결정했는지", "어떤 흐름으로 진행했는지" 기록. 저장
|
||||||
- `src/retrieval/` (8) — Brain Index — persistent, mtime-keyed tokenized cache of the Second Brain RAG 검색은 매 질의마다 브레인의 모든 .md 파일을 읽고 토크나이즈해서 TF-I
|
- `src/retrieval/` (8) — Brain Index — persistent, mtime-keyed tokenized cache of the Second Brain RAG 검색은 매 질의마다 브레인의 모든 .md 파일을 읽고 토크나이즈해서 TF-I
|
||||||
@@ -77,42 +77,42 @@ flowchart LR
|
|||||||
- `src/lmstudio/` (4) — 4 files (.ts)
|
- `src/lmstudio/` (4) — 4 files (.ts)
|
||||||
- `src/sidebar/` (4) — 4 files (.ts)
|
- `src/sidebar/` (4) — 4 files (.ts)
|
||||||
- `src/skills/` (4) — 4 files (.ts)
|
- `src/skills/` (4) — 4 files (.ts)
|
||||||
- `src/agents/` (2) — 2 files (.ts)
|
- `src/agents/` (3) — Reflection → Lesson persistence Take the Reflector agent's structured critique and persist any substantive findings as a
|
||||||
- `src/scaffolder/` (2) — Scaffolder template catalog. Templates are pure data — (projectName) => { [relativePath]: contents }. New templates are
|
- `src/scaffolder/` (2) — Scaffolder template catalog. Templates are pure data — (projectName) => { [relativePath]: contents }. New templates are
|
||||||
|
|
||||||
**Key files**
|
**Key files**
|
||||||
- `src/utils.ts` (268 lines)
|
- `src/utils.ts` (268 lines)
|
||||||
- `src/config.ts` (216 lines)
|
- `src/config.ts` (224 lines)
|
||||||
- `src/features/company/types.ts` (150 lines) — Type definitions for the 1인 기업 (One-Person Company) mode. The mode turns the user into a virtual CEO that dispatches work to a roster of specialist agents. Each turn produces a session directory conta
|
- `src/features/company/types.ts` (331 lines) — Type definitions for the 1인 기업 (One-Person Company) mode. The mode turns the user into a virtual CEO that dispatches work to a roster of specialist agents. Each turn produces a session directory conta
|
||||||
- `src/lib/paths.ts` (151 lines)
|
- `src/lib/paths.ts` (151 lines)
|
||||||
- `src/sidebarProvider.ts` (3026 lines)
|
- `src/features/company/companyConfig.ts` (877 lines) — State + config plumbing for 1인 기업 모드. Two surfaces: - CompanyState (runtime data: enabled flag, company name, which agents are active, per-agent model overrides). Persisted in VS Code's globalState so
|
||||||
- `src/features/company/agents.ts` (136 lines) — The 9-agent roster for 1인 기업 모드. Each entry is a static description — persona, role, specialty — used to build the specialist's system prompt at dispatch time. The set was adopted from Connectorigin's
|
- `src/sidebarProvider.ts` (3232 lines)
|
||||||
- `src/memory/types.ts` (126 lines) — Memory Type Definitions (메모리 타입 정의) Astra의 5-Layer Cognitive Memory System의 모든 타입을 정의합니다. ① Short-Term ② Long-Term ③ Project ④ Procedural ⑤ Episodic
|
- `src/memory/types.ts` (126 lines) — Memory Type Definitions (메모리 타입 정의) Astra의 5-Layer Cognitive Memory System의 모든 타입을 정의합니다. ① Short-Term ② Long-Term ③ Project ④ Procedural ⑤ Episodic
|
||||||
- `src/retrieval/scoring.ts` (518 lines) — Scoring Engine — TF-IDF + Bilingual Tokenizer 단순 includes() 키워드 매칭을 넘어서, TF-IDF 가중치 기반의 문서 스코어링을 제공합니다. 한국어/영어 양국어 토크나이저를 포함합니다.
|
- `src/retrieval/scoring.ts` (518 lines) — Scoring Engine — TF-IDF + Bilingual Tokenizer 단순 includes() 키워드 매칭을 넘어서, TF-IDF 가중치 기반의 문서 스코어링을 제공합니다. 한국어/영어 양국어 토크나이저를 포함합니다.
|
||||||
- `src/skills/agentKnowledgeMap.ts` (374 lines)
|
- `src/skills/agentKnowledgeMap.ts` (374 lines)
|
||||||
- `src/core/services.ts` (164 lines)
|
- `src/core/services.ts` (164 lines)
|
||||||
- `src/agent.ts` (3232 lines)
|
|
||||||
- `src/features/company/companyConfig.ts` (330 lines) — State + config plumbing for 1인 기업 모드. Two surfaces: - CompanyState (runtime data: enabled flag, company name, which agents are active, per-agent model overrides). Persisted in VS Code's globalState so
|
|
||||||
- `src/retrieval/lessonHelpers.ts` (325 lines) — Lesson / Experience Memory — pure helpers (no vscode dependency) "Lesson" = a markdown file in the active brain that captures a past mistake/risk and how to avoid repeating it. Identified by a lessons
|
- `src/retrieval/lessonHelpers.ts` (325 lines) — Lesson / Experience Memory — pure helpers (no vscode dependency) "Lesson" = a markdown file in the active brain that captures a past mistake/risk and how to avoid repeating it. Identified by a lessons
|
||||||
- `src/lib/engine.ts` (880 lines)
|
- `src/agent.ts` (3232 lines)
|
||||||
|
- `src/lib/engine.ts` (906 lines)
|
||||||
- `src/features/approval/approvalQueue.ts` (129 lines)
|
- `src/features/approval/approvalQueue.ts` (129 lines)
|
||||||
- `src/integrations/telegram/telegramClient.ts` (154 lines)
|
- `src/integrations/telegram/telegramClient.ts` (154 lines)
|
||||||
|
- `src/features/company/dispatcher.ts` (631 lines) — Sequential dispatcher for 1인 기업 모드. Drives one company "turn": user prompt → CEO planner (JSON {brief, tasks}) → for each task in plan: dispatch one specialist (sequentially) - build specialist prompt
|
||||||
- `src/features/projectArchitecture/scanner.ts` (644 lines) — Deep static analyser for the Project Architecture Context generator. Walks the project tree (skipping the usual nodemodules / out / dist noise), pulls the role of each interesting file from its leadin
|
- `src/features/projectArchitecture/scanner.ts` (644 lines) — Deep static analyser for the Project Architecture Context generator. Walks the project tree (skipping the usual nodemodules / out / dist noise), pulls the role of each interesting file from its leadin
|
||||||
- `src/lib/contextManager.ts` (275 lines) — Context Manager (컨텍스트 한계 관리) "context length = 132k" 는 "답변을 132k 토큰까지 생성해도 된다" 가 아닙니다. 시스템 프롬프트 + 대화 기록 + 입력 문서 + 생성될 답변 + 여유분 ≤ context length 이 모듈은 요청을 보내기 전에 입력 토큰을 추정하고, - 동적으로 출력 상한(maxTokens)을 계
|
- `src/lib/contextManager.ts` (275 lines) — Context Manager (컨텍스트 한계 관리) "context length = 132k" 는 "답변을 132k 토큰까지 생성해도 된다" 가 아닙니다. 시스템 프롬프트 + 대화 기록 + 입력 문서 + 생성될 답변 + 여유분 ≤ context length 이 모듈은 요청을 보내기 전에 입력 토큰을 추정하고, - 동적으로 출력 상한(maxTokens)을 계
|
||||||
|
- `src/features/company/agents.ts` (184 lines) — 기본 에이전트 로스터 — 1인 기업 모드의 출고 디폴트. 설계 의도: 제품 개발 파이프라인(기획 → 디자인 → 개발 → QA → 출시 → 마케팅 → 회고)을 한 사람이 1인 기업으로 운영할 때 필요한 직군을 모두 커버한다. 각 에이전트는 - name — 직군에 어울리는 한국식 닉네임 - role — 한국어 정식 직함 (어떤 일을 하는 사람인지) - tagl
|
||||||
- `src/core/astraPath.ts` (50 lines) — Astra Path Resolver (경로 해결기) Astra의 모든 데이터 파일(.astra 디렉토리)의 경로를 중앙에서 관리합니다. 확장 프로그램의 설치 경로(extensionUri) 기반으로 .astra 디렉토리를 해결하여, 사용자 프로젝트 루트가 아닌 ConnectAI 패키지 내부에 데이터를 저장합니다. 이 모듈은 AAL(Astra Autonomou
|
- `src/core/astraPath.ts` (50 lines) — Astra Path Resolver (경로 해결기) Astra의 모든 데이터 파일(.astra 디렉토리)의 경로를 중앙에서 관리합니다. 확장 프로그램의 설치 경로(extensionUri) 기반으로 .astra 디렉토리를 해결하여, 사용자 프로젝트 루트가 아닌 ConnectAI 패키지 내부에 데이터를 저장합니다. 이 모듈은 AAL(Astra Autonomou
|
||||||
- `src/extension.ts` (966 lines)
|
- `src/extension.ts` (966 lines)
|
||||||
- `src/features/projectChronicle/types.ts` (118 lines)
|
- `src/features/projectChronicle/types.ts` (118 lines)
|
||||||
- `src/lmstudio/client.ts` (147 lines)
|
- `src/lmstudio/client.ts` (147 lines)
|
||||||
- `src/retrieval/brainIndex.ts` (325 lines) — Brain Index — persistent, mtime-keyed tokenized cache of the Second Brain RAG 검색은 매 질의마다 브레인의 모든 .md 파일을 읽고 토크나이즈해서 TF-IDF 점수를 계산했습니다 — 파일 수가 많아지면 그게 병목입니다. 이 모듈은 <brainPath>/.astra/brain-index.json 에
|
- `src/retrieval/brainIndex.ts` (325 lines) — Brain Index — persistent, mtime-keyed tokenized cache of the Second Brain RAG 검색은 매 질의마다 브레인의 모든 .md 파일을 읽고 토크나이즈해서 TF-IDF 점수를 계산했습니다 — 파일 수가 많아지면 그게 병목입니다. 이 모듈은 <brainPath>/.astra/brain-index.json 에
|
||||||
- `src/features/company/promptBuilder.ts` (202 lines) — System-prompt construction for company-mode agents. Each specialist needs a prompt that includes: - Their identity (name, role, specialty) + optional persona. - The action-tag contract (<createfile>,
|
- `src/features/company/promptBuilder.ts` (231 lines) — System-prompt construction for company-mode agents. Each specialist needs a prompt that includes: - Their identity (name, role, specialty) + optional persona. - The action-tag contract (<createfile>,
|
||||||
- `src/features/company/sessionStore.ts` (231 lines) — Disk persistence for company-mode session artefacts. Each company turn produces a timestamped directory: <workspaceRoot>/.astra/company/sessions/2026-05-13T21-29/ ├─ brief.md ← CEO's task decompositio
|
|
||||||
|
|
||||||
### `media/` — 6 files, ~4,099 lines
|
### `media/` — 6 files, ~5,337 lines
|
||||||
|
|
||||||
**Key files**
|
**Key files**
|
||||||
- `media/sidebar.css` (1225 lines) — Stylesheet
|
- `media/sidebar.css` (1450 lines) — Stylesheet
|
||||||
- `media/sidebar.js` (1874 lines)
|
- `media/sidebar.js` (2791 lines)
|
||||||
- `media/sidebar.html` (356 lines) — Astra
|
- `media/sidebar.html` (452 lines) — Astra
|
||||||
- `media/settings-panel.css` (210 lines) — Stylesheet
|
- `media/settings-panel.css` (210 lines) — Stylesheet
|
||||||
- `media/settings-panel.html` (164 lines) — Astra Settings
|
- `media/settings-panel.html` (164 lines) — Astra Settings
|
||||||
- `media/settings-panel.js` (270 lines)
|
- `media/settings-panel.js` (270 lines)
|
||||||
@@ -160,10 +160,10 @@ flowchart LR
|
|||||||
- `core_py/optimizer.py` (55 lines)
|
- `core_py/optimizer.py` (55 lines)
|
||||||
- `core_py/queue_worker.py` (82 lines)
|
- `core_py/queue_worker.py` (82 lines)
|
||||||
|
|
||||||
### `docs/` — 66 files, ~2,716 lines
|
### `docs/` — 73 files, ~2,842 lines
|
||||||
|
|
||||||
**Sub-directories**
|
**Sub-directories**
|
||||||
- `docs/records/` (54) — Astra Project Chronicle Records
|
- `docs/records/` (61) — Astra Project Chronicle Records
|
||||||
- `docs/docs/` (5) — docs Chronicle Records
|
- `docs/docs/` (5) — docs Chronicle Records
|
||||||
|
|
||||||
**Key files**
|
**Key files**
|
||||||
@@ -220,7 +220,7 @@ flowchart LR
|
|||||||
- `g1nation.company.toggle` — Astra: Toggle 1인 기업 Mode
|
- `g1nation.company.toggle` — Astra: Toggle 1인 기업 Mode
|
||||||
- `g1nation.company.manage` — Astra: Manage 1인 기업 Agents
|
- `g1nation.company.manage` — Astra: Manage 1인 기업 Agents
|
||||||
- `g1nation.company.openSessions` — Astra: Open 1인 기업 Sessions Folder
|
- `g1nation.company.openSessions` — Astra: Open 1인 기업 Sessions Folder
|
||||||
- **Configuration** (39 settings):
|
- **Configuration** (40 settings):
|
||||||
- `g1nation.multiAgentEnabled` *(boolean)* _(default: `false`)_ — Enable Multi-Agent Workflow (Planner -> Researcher -> Writer) for complex tasks.
|
- `g1nation.multiAgentEnabled` *(boolean)* _(default: `false`)_ — Enable Multi-Agent Workflow (Planner -> Researcher -> Writer) for complex tasks.
|
||||||
- `g1nation.memoryEnabled` *(boolean)* _(default: `true`)_ — Enable layered memory injection before each model response.
|
- `g1nation.memoryEnabled` *(boolean)* _(default: `true`)_ — Enable layered memory injection before each model response.
|
||||||
- `g1nation.memoryShortTermMessages` *(number)* _(default: `8`)_ — Number of recent conversation messages included as short-term memory.
|
- `g1nation.memoryShortTermMessages` *(number)* _(default: `8`)_ — Number of recent conversation messages included as short-term memory.
|
||||||
@@ -260,6 +260,7 @@ flowchart LR
|
|||||||
- `g1nation.embeddingBlendAlpha` *(number)* _(default: `0.5`)_ — Hybrid score blend: 0 = pure TF-IDF (sparse / keyword), 1 = pure embedding cosine (dense / semantic), 0.5 = balanced. Only used when g1nation.embeddingModel is set. Default 0.5.
|
- `g1nation.embeddingBlendAlpha` *(number)* _(default: `0.5`)_ — Hybrid score blend: 0 = pure TF-IDF (sparse / keyword), 1 = pure embedding cosine (dense / semantic), 0.5 = balanced. Only used when g1nation.embeddingModel is set. Default 0.5.
|
||||||
- `g1nation.knowledgeMix.secondBrainWeight` *(number)* _(default: `50`)_ — Knowledge Mix (0–100): how heavily the assistant should lean on Second Brain evidence vs. its own general knowledge. 0 = Second Brain disabled (model knowledge only). 50 = balanced (legacy default). 1
|
- `g1nation.knowledgeMix.secondBrainWeight` *(number)* _(default: `50`)_ — Knowledge Mix (0–100): how heavily the assistant should lean on Second Brain evidence vs. its own general knowledge. 0 = Second Brain disabled (model knowledge only). 50 = balanced (legacy default). 1
|
||||||
- `g1nation.enableReflection` *(boolean)* _(default: `true`)_ — Insert a Self-Reflection (Reflector) stage between Researcher and Writer in the multi-agent workflow. The Reflector critically reviews the plan and research output (gaps, contradictions, unsupported c
|
- `g1nation.enableReflection` *(boolean)* _(default: `true`)_ — Insert a Self-Reflection (Reflector) stage between Researcher and Writer in the multi-agent workflow. The Reflector critically reviews the plan and research output (gaps, contradictions, unsupported c
|
||||||
|
- `g1nation.autoLessonFromReflection` *(boolean)* _(default: `true`)_ — Persist substantive Reflector critiques to the active brain as lesson cards under `lessons/auto-reflector/`. Future missions automatically retrieve these cards (via the existing Experience-Memory pipe
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
- **Runtime** (2): `@lmstudio/sdk`, `pdf-parse`
|
- **Runtime** (2): `@lmstudio/sdk`, `pdf-parse`
|
||||||
@@ -307,7 +308,7 @@ Astra는 대표님의 명시적인 승인 하에 로컬 시스템의 강력한
|
|||||||
**Designed for High-Performance Decision Making.**
|
**Designed for High-Performance Decision Making.**
|
||||||
Copyright (C) **g1nation**. All rights reserved.
|
Copyright (C) **g1nation**. All rights reserved.
|
||||||
|
|
||||||
_Last auto-scan: 2026-05-13T17:43:53.933Z · signature `5020e02c`_
|
_Last auto-scan: 2026-05-14T13:24:53.642Z · signature `f554c52a`_
|
||||||
<!-- ASTRA:AUTO-END -->
|
<!-- ASTRA:AUTO-END -->
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"generatedAt": "2026-05-13T17:43:53.948Z",
|
"generatedAt": "2026-05-14T13:24:53.652Z",
|
||||||
"files": {
|
"files": {
|
||||||
"src/agent.ts": {
|
"src/agent.ts": {
|
||||||
"mtimeMs": 1778683690000,
|
"mtimeMs": 1778683690000,
|
||||||
@@ -58,6 +58,16 @@
|
|||||||
"src/lib/engine"
|
"src/lib/engine"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"src/agents/reflectionPersister.ts": {
|
||||||
|
"mtimeMs": 1778763469000,
|
||||||
|
"size": 11986,
|
||||||
|
"lines": 308,
|
||||||
|
"role": "Reflection → Lesson persistence Take the Reflector agent's structured critique and persist any substantive findings as a lesson card in <brainDir>/lessons/auto-reflector/. The existing brain retrieval",
|
||||||
|
"imports": [
|
||||||
|
"src/utils",
|
||||||
|
"src/retrieval/lessonHelpers"
|
||||||
|
]
|
||||||
|
},
|
||||||
"src/bridge.ts": {
|
"src/bridge.ts": {
|
||||||
"mtimeMs": 1778681774000,
|
"mtimeMs": 1778681774000,
|
||||||
"size": 9705,
|
"size": 9705,
|
||||||
@@ -72,9 +82,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/config.ts": {
|
"src/config.ts": {
|
||||||
"mtimeMs": 1778690442000,
|
"mtimeMs": 1778763415000,
|
||||||
"size": 9619,
|
"size": 10185,
|
||||||
"lines": 216,
|
"lines": 224,
|
||||||
"role": "",
|
"role": "",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
@@ -312,23 +322,22 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/features/company/agents.ts": {
|
"src/features/company/agents.ts": {
|
||||||
"mtimeMs": 1778680824000,
|
"mtimeMs": 1778764697000,
|
||||||
"size": 6684,
|
"size": 11623,
|
||||||
"lines": 136,
|
"lines": 184,
|
||||||
"role": "The 9-agent roster for 1인 기업 모드. Each entry is a static description — persona, role, specialty — used to build the specialist's system prompt at dispatch time. The set was adopted from Connectorigin's",
|
"role": "기본 에이전트 로스터 — 1인 기업 모드의 출고 디폴트. 설계 의도: 제품 개발 파이프라인(기획 → 디자인 → 개발 → QA → 출시 → 마케팅 → 회고)을 한 사람이 1인 기업으로 운영할 때 필요한 직군을 모두 커버한다. 각 에이전트는 - name — 직군에 어울리는 한국식 닉네임 - role — 한국어 정식 직함 (어떤 일을 하는 사람인지) - tagl",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/features/company/types"
|
"src/features/company/types"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/features/company/ceoPlanner.ts": {
|
"src/features/company/ceoPlanner.ts": {
|
||||||
"mtimeMs": 1778681095000,
|
"mtimeMs": 1778762677000,
|
||||||
"size": 8406,
|
"size": 11307,
|
||||||
"lines": 219,
|
"lines": 266,
|
||||||
"role": "CEO planner — turns a user prompt into a CompanyTaskPlan. Lifecycle of one planner call: 1. Build the planner system prompt (template + active-agent list). 2. Hit the AI service with the user prompt a",
|
"role": "CEO planner — turns a user prompt into a CompanyTaskPlan. Lifecycle of one planner call: 1. Build the planner system prompt (template + active-agent list). 2. Hit the AI service with the user prompt a",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/core/services",
|
"src/core/services",
|
||||||
"src/utils",
|
"src/utils",
|
||||||
"src/features/company/agents",
|
|
||||||
"src/features/company/companyConfig",
|
"src/features/company/companyConfig",
|
||||||
"src/features/company/promptAssets",
|
"src/features/company/promptAssets",
|
||||||
"src/features/company/promptBuilder",
|
"src/features/company/promptBuilder",
|
||||||
@@ -336,22 +345,22 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/features/company/ceoReporter.ts": {
|
"src/features/company/ceoReporter.ts": {
|
||||||
"mtimeMs": 1778681122000,
|
"mtimeMs": 1778762677000,
|
||||||
"size": 4812,
|
"size": 4895,
|
||||||
"lines": 120,
|
"lines": 122,
|
||||||
"role": "CEO synthesis pass — runs after all specialists have finished. Given the per-agent outputs, this asks the CEO model to produce the final markdown report (✅ 완료 / 🚀 다음 / 💡 인사이트) that the user actually",
|
"role": "CEO synthesis pass — runs after all specialists have finished. Given the per-agent outputs, this asks the CEO model to produce the final markdown report (✅ 완료 / 🚀 다음 / 💡 인사이트) that the user actually",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/core/services",
|
"src/core/services",
|
||||||
"src/utils",
|
"src/utils",
|
||||||
"src/features/company/agents",
|
"src/features/company/companyConfig",
|
||||||
"src/features/company/promptAssets",
|
"src/features/company/promptAssets",
|
||||||
"src/features/company/types"
|
"src/features/company/types"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/features/company/companyConfig.ts": {
|
"src/features/company/companyConfig.ts": {
|
||||||
"mtimeMs": 1778686762000,
|
"mtimeMs": 1778764783000,
|
||||||
"size": 13473,
|
"size": 39070,
|
||||||
"lines": 330,
|
"lines": 877,
|
||||||
"role": "State + config plumbing for 1인 기업 모드. Two surfaces: - CompanyState (runtime data: enabled flag, company name, which agents are active, per-agent model overrides). Persisted in VS Code's globalState so",
|
"role": "State + config plumbing for 1인 기업 모드. Two surfaces: - CompanyState (runtime data: enabled flag, company name, which agents are active, per-agent model overrides). Persisted in VS Code's globalState so",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/features/company/agents",
|
"src/features/company/agents",
|
||||||
@@ -359,9 +368,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/features/company/dispatcher.ts": {
|
"src/features/company/dispatcher.ts": {
|
||||||
"mtimeMs": 1778686839000,
|
"mtimeMs": 1778762677000,
|
||||||
"size": 20029,
|
"size": 29279,
|
||||||
"lines": 434,
|
"lines": 631,
|
||||||
"role": "Sequential dispatcher for 1인 기업 모드. Drives one company \"turn\": user prompt → CEO planner (JSON {brief, tasks}) → for each task in plan: dispatch one specialist (sequentially) - build specialist prompt",
|
"role": "Sequential dispatcher for 1인 기업 모드. Drives one company \"turn\": user prompt → CEO planner (JSON {brief, tasks}) → for each task in plan: dispatch one specialist (sequentially) - build specialist prompt",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/core/services",
|
"src/core/services",
|
||||||
@@ -369,7 +378,6 @@
|
|||||||
"src/skills/scopedBrainRetriever",
|
"src/skills/scopedBrainRetriever",
|
||||||
"src/skills/agentKnowledgeMap",
|
"src/skills/agentKnowledgeMap",
|
||||||
"src/retrieval/knowledgeMix",
|
"src/retrieval/knowledgeMix",
|
||||||
"src/features/company/agents",
|
|
||||||
"src/features/company/companyConfig",
|
"src/features/company/companyConfig",
|
||||||
"src/features/company/ceoPlanner",
|
"src/features/company/ceoPlanner",
|
||||||
"src/features/company/ceoReporter",
|
"src/features/company/ceoReporter",
|
||||||
@@ -380,18 +388,28 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/features/company/index.ts": {
|
"src/features/company/index.ts": {
|
||||||
"mtimeMs": 1778686769000,
|
"mtimeMs": 1778764795000,
|
||||||
"size": 1114,
|
"size": 1827,
|
||||||
"lines": 55,
|
"lines": 83,
|
||||||
"role": "Public API for 1인 기업 모드. Consumers (sidebarProvider, chatHandlers, command handlers) import from this barrel so internal layout can move around without touching every call site.",
|
"role": "Public API for 1인 기업 모드. Consumers (sidebarProvider, chatHandlers, command handlers) import from this barrel so internal layout can move around without touching every call site.",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/features/company/agents",
|
"src/features/company/agents",
|
||||||
"src/features/company/companyConfig",
|
"src/features/company/companyConfig",
|
||||||
"src/features/company/types",
|
"src/features/company/types",
|
||||||
|
"src/features/company/pipelineTemplates",
|
||||||
"src/features/company/dispatcher",
|
"src/features/company/dispatcher",
|
||||||
"src/features/company/sessionStore"
|
"src/features/company/sessionStore"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"src/features/company/pipelineTemplates.ts": {
|
||||||
|
"mtimeMs": 1778762677000,
|
||||||
|
"size": 11351,
|
||||||
|
"lines": 211,
|
||||||
|
"role": "Built-in pipeline templates for 1인 기업 모드. These are blueprints, not data — they're surfaced in the manage panel's \"템플릿에서 추가\" dropdown so a non-developer user can stamp out a working pipeline in one cl",
|
||||||
|
"imports": [
|
||||||
|
"src/features/company/types"
|
||||||
|
]
|
||||||
|
},
|
||||||
"src/features/company/promptAssets.ts": {
|
"src/features/company/promptAssets.ts": {
|
||||||
"mtimeMs": 1778680887000,
|
"mtimeMs": 1778680887000,
|
||||||
"size": 6782,
|
"size": 6782,
|
||||||
@@ -400,9 +418,9 @@
|
|||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/features/company/promptBuilder.ts": {
|
"src/features/company/promptBuilder.ts": {
|
||||||
"mtimeMs": 1778686868000,
|
"mtimeMs": 1778762677000,
|
||||||
"size": 10317,
|
"size": 12835,
|
||||||
"lines": 202,
|
"lines": 231,
|
||||||
"role": "System-prompt construction for company-mode agents. Each specialist needs a prompt that includes: - Their identity (name, role, specialty) + optional persona. - The action-tag contract (<createfile>, ",
|
"role": "System-prompt construction for company-mode agents. Each specialist needs a prompt that includes: - Their identity (name, role, specialty) + optional persona. - The action-tag contract (<createfile>, ",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/features/company/agents",
|
"src/features/company/agents",
|
||||||
@@ -442,22 +460,22 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/features/company/telegramReport.ts": {
|
"src/features/company/telegramReport.ts": {
|
||||||
"mtimeMs": 1778686162000,
|
"mtimeMs": 1778762677000,
|
||||||
"size": 8111,
|
"size": 8126,
|
||||||
"lines": 168,
|
"lines": 168,
|
||||||
"role": "Telegram mirror for the secretary agent (영숙). After every company turn finishes, this helper takes the CEO synthesis + task list and pushes it to the user's Telegram chat — same behaviour as Connector",
|
"role": "Telegram mirror for the secretary agent (영숙). After every company turn finishes, this helper takes the CEO synthesis + task list and pushes it to the user's Telegram chat — same behaviour as Connector",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/utils",
|
"src/utils",
|
||||||
"src/integrations/telegram/telegramClient",
|
"src/integrations/telegram/telegramClient",
|
||||||
"src/integrations/telegram/conversationHistory",
|
"src/integrations/telegram/conversationHistory",
|
||||||
"src/features/company/agents",
|
"src/features/company/companyConfig",
|
||||||
"src/features/company/types"
|
"src/features/company/types"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/features/company/types.ts": {
|
"src/features/company/types.ts": {
|
||||||
"mtimeMs": 1778686714000,
|
"mtimeMs": 1778764725000,
|
||||||
"size": 6454,
|
"size": 14306,
|
||||||
"lines": 150,
|
"lines": 331,
|
||||||
"role": "Type definitions for the 1인 기업 (One-Person Company) mode. The mode turns the user into a virtual CEO that dispatches work to a roster of specialist agents. Each turn produces a session directory conta",
|
"role": "Type definitions for the 1인 기업 (One-Person Company) mode. The mode turns the user into a virtual CEO that dispatches work to a roster of specialist agents. Each turn produces a session directory conta",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
@@ -629,9 +647,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/lib/engine.ts": {
|
"src/lib/engine.ts": {
|
||||||
"mtimeMs": 1778690608000,
|
"mtimeMs": 1778763448000,
|
||||||
"size": 40830,
|
"size": 42698,
|
||||||
"lines": 880,
|
"lines": 906,
|
||||||
"role": "",
|
"role": "",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/core/lock",
|
"src/core/lock",
|
||||||
@@ -639,7 +657,9 @@
|
|||||||
"src/utils",
|
"src/utils",
|
||||||
"src/lib/diagnostics",
|
"src/lib/diagnostics",
|
||||||
"src/lib/formatter",
|
"src/lib/formatter",
|
||||||
"src/types/interfaces"
|
"src/types/interfaces",
|
||||||
|
"src/config",
|
||||||
|
"src/agents/reflectionPersister"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/lib/formatter.ts": {
|
"src/lib/formatter.ts": {
|
||||||
@@ -902,9 +922,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/sidebar/chatHandlers.ts": {
|
"src/sidebar/chatHandlers.ts": {
|
||||||
"mtimeMs": 1778686906000,
|
"mtimeMs": 1778764814000,
|
||||||
"size": 13454,
|
"size": 22151,
|
||||||
"lines": 266,
|
"lines": 428,
|
||||||
"role": "",
|
"role": "",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/sidebarProvider",
|
"src/sidebarProvider",
|
||||||
@@ -923,9 +943,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/sidebarProvider.ts": {
|
"src/sidebarProvider.ts": {
|
||||||
"mtimeMs": 1778693581000,
|
"mtimeMs": 1778764853000,
|
||||||
"size": 132228,
|
"size": 141684,
|
||||||
"lines": 3026,
|
"lines": 3232,
|
||||||
"role": "",
|
"role": "",
|
||||||
"imports": [
|
"imports": [
|
||||||
"src/utils",
|
"src/utils",
|
||||||
@@ -945,7 +965,8 @@
|
|||||||
"src/features/projectArchitecture",
|
"src/features/projectArchitecture",
|
||||||
"src/features/projectArchitecture/intentDetector",
|
"src/features/projectArchitecture/intentDetector",
|
||||||
"src/features/company",
|
"src/features/company",
|
||||||
"src/core/services"
|
"src/core/services",
|
||||||
|
"src/features/company/dispatcher"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/skills/agentKnowledgeMap.ts": {
|
"src/skills/agentKnowledgeMap.ts": {
|
||||||
@@ -1021,8 +1042,8 @@
|
|||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"media/settings-panel.html": {
|
"media/settings-panel.html": {
|
||||||
"mtimeMs": 1778255979000,
|
"mtimeMs": 1778763966000,
|
||||||
"size": 7659,
|
"size": 7678,
|
||||||
"lines": 164,
|
"lines": 164,
|
||||||
"role": "Astra Settings",
|
"role": "Astra Settings",
|
||||||
"imports": []
|
"imports": []
|
||||||
@@ -1035,23 +1056,23 @@
|
|||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"media/sidebar.css": {
|
"media/sidebar.css": {
|
||||||
"mtimeMs": 1778688155000,
|
"mtimeMs": 1778764979000,
|
||||||
"size": 49347,
|
"size": 59761,
|
||||||
"lines": 1225,
|
"lines": 1450,
|
||||||
"role": "Stylesheet",
|
"role": "Stylesheet",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"media/sidebar.html": {
|
"media/sidebar.html": {
|
||||||
"mtimeMs": 1778687548000,
|
"mtimeMs": 1778764039000,
|
||||||
"size": 20499,
|
"size": 28185,
|
||||||
"lines": 356,
|
"lines": 452,
|
||||||
"role": "Astra",
|
"role": "Astra",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"media/sidebar.js": {
|
"media/sidebar.js": {
|
||||||
"mtimeMs": 1778688191000,
|
"mtimeMs": 1778764936000,
|
||||||
"size": 103898,
|
"size": 158341,
|
||||||
"lines": 1874,
|
"lines": 2791,
|
||||||
"role": "",
|
"role": "",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
@@ -1507,8 +1528,29 @@
|
|||||||
"role": "Bug: 문제점을 읽고 어떻게 개선하는게 최선인지 분석해주면 좋겠어. 알겠습니다. 지금부터 ConnectAI 프로젝트에만 완전히 집중하겠습니다. ...",
|
"role": "Bug: 문제점을 읽고 어떻게 개선하는게 최선인지 분석해주면 좋겠어. 알겠습니다. 지금부터 ConnectAI 프로젝트에만 완전히 집중하겠습니다. ...",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
|
"docs/records/ConnectAI/bugs/BUG-0012-질문이-있어-논문을-쓰려고해-논문-주제는-서비스적이-아닌-사용자가-ai에게-구조로-질문을-해야-사용자의-의도.md": {
|
||||||
|
"mtimeMs": 1778762677000,
|
||||||
|
"size": 2354,
|
||||||
|
"lines": 16,
|
||||||
|
"role": "Bug: 질문이 있어. 논문을 쓰려고해. 논문 주제는 서비스적이 아닌 사용자가 ai에게 구조로 질문을 해야 사용자의 의도에 맞는 답변을 받을 수 있을까야...",
|
||||||
|
"imports": []
|
||||||
|
},
|
||||||
|
"docs/records/ConnectAI/bugs/BUG-0013-thesis-paper를-쓰려고-하는데-아래와-같이-쓰면-좋을까-이런-식으로-쓰면-되지-않을까-싶음-1-in.md": {
|
||||||
|
"mtimeMs": 1778762677000,
|
||||||
|
"size": 2527,
|
||||||
|
"lines": 16,
|
||||||
|
"role": "Bug: Thesis paper를 쓰려고 하는데 아래와 같이 쓰면 좋을까? 이런 식으로 쓰면 되지 않을까 싶음 1. Introduction Thesis ...",
|
||||||
|
"imports": []
|
||||||
|
},
|
||||||
|
"docs/records/ConnectAI/bugs/BUG-0014-논문-outline-title-인간-ai-상호작용에서-의도-정렬을-높이기-위한-최소-질의-구조-연구-또는-사.md": {
|
||||||
|
"mtimeMs": 1778762677000,
|
||||||
|
"size": 2531,
|
||||||
|
"lines": 16,
|
||||||
|
"role": "Bug: 논문 Outline Title 인간-AI 상호작용에서 의도 정렬을 높이기 위한 최소 질의 구조 연구 또는 사용자의 인지적 편향을 보완하는 구조화...",
|
||||||
|
"imports": []
|
||||||
|
},
|
||||||
"docs/records/ConnectAI/chronicle.config.json": {
|
"docs/records/ConnectAI/chronicle.config.json": {
|
||||||
"mtimeMs": 1778694061000,
|
"mtimeMs": 1778763875000,
|
||||||
"size": 416,
|
"size": 416,
|
||||||
"lines": 11,
|
"lines": 11,
|
||||||
"role": "JSON configuration",
|
"role": "JSON configuration",
|
||||||
@@ -1584,6 +1626,20 @@
|
|||||||
"role": "ADR: /Volumes/Data/project/Antigravity/ConnectAI self reflection 기능이 적용되었는지 확인해줘. 1인 ...",
|
"role": "ADR: /Volumes/Data/project/Antigravity/ConnectAI self reflection 기능이 적용되었는지 확인해줘. 1인 ...",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
|
"docs/records/ConnectAI/decisions/ADR-0011-e-wiki-connectai-self-reflection-기능이-있는데-어떻게-self-reflection.md": {
|
||||||
|
"mtimeMs": 1778762677000,
|
||||||
|
"size": 1604,
|
||||||
|
"lines": 19,
|
||||||
|
"role": "ADR: E:\\Wiki\\connectai self reflection 기능이 있는데 어떻게 SELF REFLECTION이 반영되는지 분석해줘.",
|
||||||
|
"imports": []
|
||||||
|
},
|
||||||
|
"docs/records/ConnectAI/decisions/ADR-0012-e-wiki-connectai-self-reflection-기능이-있는데-어떻게-self-reflection.md": {
|
||||||
|
"mtimeMs": 1778762677000,
|
||||||
|
"size": 1448,
|
||||||
|
"lines": 19,
|
||||||
|
"role": "ADR: E:\\Wiki\\connectai self reflection 기능이 있는데 어떻게 SELF REFLECTION이 반영되는지 분석해줘.",
|
||||||
|
"imports": []
|
||||||
|
},
|
||||||
"docs/records/ConnectAI/development/2026-05-02_answer-format-readability-tuning.md": {
|
"docs/records/ConnectAI/development/2026-05-02_answer-format-readability-tuning.md": {
|
||||||
"mtimeMs": 1777808065000,
|
"mtimeMs": 1777808065000,
|
||||||
"size": 1534,
|
"size": 1534,
|
||||||
@@ -1724,6 +1780,13 @@
|
|||||||
"role": "Development Log: 너는 분석 요청하거나 내가 작업 요청을 할때 connectai architecture.md 문서를 참고하고 작업을 하나?",
|
"role": "Development Log: 너는 분석 요청하거나 내가 작업 요청을 할때 connectai architecture.md 문서를 참고하고 작업을 하나?",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
|
"docs/records/ConnectAI/development/2026-05-14_reflector-에이전트가-1인-기업-에이전트-목록에는-안보이는데_implementation.md": {
|
||||||
|
"mtimeMs": 1778762677000,
|
||||||
|
"size": 1519,
|
||||||
|
"lines": 24,
|
||||||
|
"role": "Development Log: REFLECTOR 에이전트가 1인 기업 에이전트 목록에는 안보이는데",
|
||||||
|
"imports": []
|
||||||
|
},
|
||||||
"docs/records/ConnectAI/discussions/2026-05-13_volumes-data-project-antigravity-connectai-이-프로젝트-작업-할-거야.md": {
|
"docs/records/ConnectAI/discussions/2026-05-13_volumes-data-project-antigravity-connectai-이-프로젝트-작업-할-거야.md": {
|
||||||
"mtimeMs": 1778690673000,
|
"mtimeMs": 1778690673000,
|
||||||
"size": 652,
|
"size": 652,
|
||||||
@@ -1752,6 +1815,13 @@
|
|||||||
"role": "Discussion: /Volumes/Data/project/Antigravity/ConnectAI 이 프로젝트를 작업할거야.",
|
"role": "Discussion: /Volumes/Data/project/Antigravity/ConnectAI 이 프로젝트를 작업할거야.",
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
|
"docs/records/ConnectAI/discussions/2026-05-14_최성연-알아-칼리버스에서-근무한데.md": {
|
||||||
|
"mtimeMs": 1778762677000,
|
||||||
|
"size": 1297,
|
||||||
|
"lines": 16,
|
||||||
|
"role": "Discussion: 최성연 알아? 칼리버스에서 근무한데",
|
||||||
|
"imports": []
|
||||||
|
},
|
||||||
"docs/records/ConnectAI/planning/2026-05-02_project-chronicle-guard.md": {
|
"docs/records/ConnectAI/planning/2026-05-02_project-chronicle-guard.md": {
|
||||||
"mtimeMs": 1777808065000,
|
"mtimeMs": 1777808065000,
|
||||||
"size": 2946,
|
"size": 2946,
|
||||||
@@ -1795,7 +1865,7 @@
|
|||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"docs/records/ConnectAI/timeline.md": {
|
"docs/records/ConnectAI/timeline.md": {
|
||||||
"mtimeMs": 1778694061000,
|
"mtimeMs": 1778763539000,
|
||||||
"size": 8783,
|
"size": 8783,
|
||||||
"lines": 134,
|
"lines": 134,
|
||||||
"role": "Project Timeline",
|
"role": "Project Timeline",
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"result": "Final report with inconsistencies. This should be long enough to pass validation.",
|
"result": "Final report with inconsistencies. This should be long enough to pass validation.",
|
||||||
"createdAt": 1778749506862,
|
"createdAt": 1778765114489,
|
||||||
"modelVersion": "unknown"
|
"modelVersion": "unknown"
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"result": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.",
|
"result": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.",
|
||||||
"createdAt": 1778749506860,
|
"createdAt": 1778765114485,
|
||||||
"modelVersion": "unknown"
|
"modelVersion": "unknown"
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"result": "Detailed Execution Plan: 1. Research 2. Analyze 3. Write report with high quality.",
|
"result": "Detailed Execution Plan: 1. Research 2. Analyze 3. Write report with high quality.",
|
||||||
"createdAt": 1778749506858,
|
"createdAt": 1778765114484,
|
||||||
"modelVersion": "unknown"
|
"modelVersion": "unknown"
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"result": "---\nid: stress_conflict_1778749506840\ndate: 2026-05-14T09:05:06.864Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\nFinal report with inconsistencies. This should be long enough to pass validation.\n\nFinal report with inconsistencies. This should be long enough to pass validation.\n\n---\n## 💡 Astra의 선제적 제안 (Proactive Next Actions)\nFinal report with inconsistencies. This should be long enough to pass validation.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `60/100` | ⚠️ Medium |\n| **Fallbacks Used** | `0` | ✅ None |\n| **Auto Retries** | `0` | ✅ Stable |\n| **Deduplication** | `0` | Standard |\n| **Processing Time** | `0.0s` | ✅ Fast |\n\n### 🔍 Decision Audit Trail\n- **[PLANNER]** 전략 수립 중... (17ms)\n- **[RESEARCHER]** 핵심 정보 수집 및 분석 중... (2ms)\n- **[WRITER]** 최종 리포트 작성 및 편집 중... (2ms)\n",
|
"result": "---\nid: stress_conflict_1778765114471\ndate: 2026-05-14T13:25:14.493Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\nFinal report with inconsistencies. This should be long enough to pass validation.\n\nFinal report with inconsistencies. This should be long enough to pass validation.\n\n---\n## 💡 Astra의 선제적 제안 (Proactive Next Actions)\nFinal report with inconsistencies. This should be long enough to pass validation.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `60/100` | ⚠️ Medium |\n| **Fallbacks Used** | `0` | ✅ None |\n| **Auto Retries** | `0` | ✅ Stable |\n| **Deduplication** | `0` | Standard |\n| **Processing Time** | `0.0s` | ✅ Fast |\n\n### 🔍 Decision Audit Trail\n- **[PLANNER]** 전략 수립 중... (10ms)\n- **[RESEARCHER]** 핵심 정보 수집 및 분석 중... (4ms)\n- **[WRITER]** 최종 리포트 작성 및 편집 중... (4ms)\n",
|
||||||
"createdAt": 1778749506864,
|
"createdAt": 1778765114493,
|
||||||
"modelVersion": "unknown"
|
"modelVersion": "unknown"
|
||||||
}
|
}
|
||||||
+10
-10
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"missionId": "stress_conflict_1778749506840",
|
"missionId": "stress_conflict_1778765114471",
|
||||||
"status": "completed",
|
"status": "completed",
|
||||||
"startTime": "2026-05-14T09:05:06.840Z",
|
"startTime": "2026-05-14T13:25:14.471Z",
|
||||||
"totalElapsedMs": 25,
|
"totalElapsedMs": 22,
|
||||||
"results": {
|
"results": {
|
||||||
"planner": "Detailed Execution Plan: 1. Research 2. Analyze 3. Write report with high quality.",
|
"planner": "Detailed Execution Plan: 1. Research 2. Analyze 3. Write report with high quality.",
|
||||||
"researcher": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.",
|
"researcher": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.",
|
||||||
@@ -16,30 +16,30 @@
|
|||||||
{
|
{
|
||||||
"from": "idle",
|
"from": "idle",
|
||||||
"to": "planner",
|
"to": "planner",
|
||||||
"durationMs": 17,
|
"durationMs": 10,
|
||||||
"message": "전략 수립 중...",
|
"message": "전략 수립 중...",
|
||||||
"ts": "2026-05-14T09:05:06.857Z"
|
"ts": "2026-05-14T13:25:14.481Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from": "planner",
|
"from": "planner",
|
||||||
"to": "researcher",
|
"to": "researcher",
|
||||||
"durationMs": 2,
|
"durationMs": 4,
|
||||||
"message": "핵심 정보 수집 및 분석 중...",
|
"message": "핵심 정보 수집 및 분석 중...",
|
||||||
"ts": "2026-05-14T09:05:06.859Z"
|
"ts": "2026-05-14T13:25:14.485Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from": "researcher",
|
"from": "researcher",
|
||||||
"to": "writer",
|
"to": "writer",
|
||||||
"durationMs": 2,
|
"durationMs": 4,
|
||||||
"message": "최종 리포트 작성 및 편집 중...",
|
"message": "최종 리포트 작성 및 편집 중...",
|
||||||
"ts": "2026-05-14T09:05:06.861Z"
|
"ts": "2026-05-14T13:25:14.489Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from": "writer",
|
"from": "writer",
|
||||||
"to": "completed",
|
"to": "completed",
|
||||||
"durationMs": 4,
|
"durationMs": 4,
|
||||||
"message": "미션 완료",
|
"message": "미션 완료",
|
||||||
"ts": "2026-05-14T09:05:06.865Z"
|
"ts": "2026-05-14T13:25:14.493Z"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"resilienceMetrics": {
|
"resilienceMetrics": {
|
||||||
@@ -1,5 +1,15 @@
|
|||||||
# Astra Patch Notes
|
# Astra Patch Notes
|
||||||
|
|
||||||
|
## v2.1.8 (2026-05-14)
|
||||||
|
### 🏢 Company Agent Roster Overhaul & UI Polish
|
||||||
|
- **에이전트 로스터 전면 개편:** 1인 기업 모드에 루나(사운드), 레오(유튜브), 아라(인스타) 등 특화된 에이전트를 추가하고 역할을 더욱 세분화했습니다.
|
||||||
|
- **제품 개발 파이프라인 최적화:** 기획 → 디자인 → 개발 → QA → 감리로 이어지는 핵심 워크플로우를 강화하고 기본 활성 에이전트 구성을 조정했습니다.
|
||||||
|
- **사이드바 UI 및 인터랙션 정교화:** `sidebar.js`와 스타일시트를 개선하여 대화 흐름의 시각적 안정성과 반응성을 높였습니다.
|
||||||
|
- **비즈니스 엔진 고도화:** `companyConfig.ts` 및 핸들러 로직 수정을 통해 다중 에이전트 협업 시의 컨텍스트 유지 능력을 강화했습니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
## v2.1.7 (2026-05-14)
|
## v2.1.7 (2026-05-14)
|
||||||
### 🚀 Version Up & Packaging Stabilization
|
### 🚀 Version Up & Packaging Stabilization
|
||||||
- **버전 상향 및 패키징:** 프로젝트 버전을 `v2.1.7`로 업데이트하고 신규 VSIX 패키지를 생성했습니다.
|
- **버전 상향 및 패키징:** 프로젝트 버전을 `v2.1.7`로 업데이트하고 신규 VSIX 패키지를 생성했습니다.
|
||||||
|
|||||||
Binary file not shown.
@@ -7,5 +7,5 @@
|
|||||||
"corePurpose": "",
|
"corePurpose": "",
|
||||||
"detailLevel": "standard",
|
"detailLevel": "standard",
|
||||||
"createdAt": "2026-05-13T13:09:33.788Z",
|
"createdAt": "2026-05-13T13:09:33.788Z",
|
||||||
"updatedAt": "2026-05-14T12:42:12.047Z"
|
"updatedAt": "2026-05-14T13:04:35.099Z"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,8 +77,8 @@
|
|||||||
|
|
||||||
<!-- Brain -->
|
<!-- Brain -->
|
||||||
<section class="section" data-section="brain">
|
<section class="section" data-section="brain">
|
||||||
<h2>Brain</h2>
|
<h2>두뇌 (지식 폴더)</h2>
|
||||||
<p class="hint">현재 활성 brain 프로필 정보입니다. 프로필 추가·수정은 사이드바의 Brain 메뉴 또는 VS Code Settings에서 처리합니다.</p>
|
<p class="hint">현재 활성 두뇌 프로필 정보입니다. 추가·수정은 사이드바의 [변경 ▾ → 두뇌] 또는 VS Code Settings에서 처리합니다.</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label>활성 프로필</label>
|
<label>활성 프로필</label>
|
||||||
<div class="readout" id="brainName">—</div>
|
<div class="readout" id="brainName">—</div>
|
||||||
|
|||||||
+48
-1
@@ -358,9 +358,56 @@
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.company-agent-card[data-active="false"] { opacity: 0.55; }
|
/* 비활성 카드는 더 흐릿하게 + 좌측 액센트 바를 떨궈서 한 눈에 그룹 구분되도록. */
|
||||||
|
.company-agent-card[data-active="false"] {
|
||||||
|
opacity: 0.5;
|
||||||
|
background: transparent;
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
.company-agent-card[data-active="true"] {
|
||||||
|
border-left: 3px solid var(--accent);
|
||||||
|
}
|
||||||
|
.company-agent-card[data-locked="true"] {
|
||||||
|
border-left-color: #FACC15; /* CEO는 골드 액센트 */
|
||||||
|
background: linear-gradient(180deg, rgba(250,204,21,0.06) 0%, transparent 100%);
|
||||||
|
}
|
||||||
.company-agent-card[data-locked="true"] .company-agent-toggle { cursor: not-allowed; opacity: 0.4; }
|
.company-agent-card[data-locked="true"] .company-agent-toggle { cursor: not-allowed; opacity: 0.4; }
|
||||||
|
|
||||||
|
/* 삭제 버튼 — 평소엔 다른 controls 톤과 동일, 파이프라인에서 사용 중이면 disabled. */
|
||||||
|
.company-agent-delete { color: var(--text-dim); }
|
||||||
|
.company-agent-delete:hover:not(.disabled) {
|
||||||
|
color: var(--error); border-color: var(--error);
|
||||||
|
}
|
||||||
|
.company-agent-delete.disabled {
|
||||||
|
opacity: 0.35; cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 숨겨진 빌트인 복원 영역 — 평소엔 시야에 안 들어오게 차분한 톤. */
|
||||||
|
.company-agent-hidden-section {
|
||||||
|
margin-top: 12px; padding: 10px 12px;
|
||||||
|
border: 1px dashed var(--border); border-radius: 8px;
|
||||||
|
background: transparent; list-style: none;
|
||||||
|
}
|
||||||
|
.company-agent-hidden-head {
|
||||||
|
font-size: 11px; color: var(--text-dim); font-weight: 600;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.company-agent-hidden-hint {
|
||||||
|
font-size: 10px; color: var(--text-dim); opacity: 0.8;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.company-agent-hidden-list {
|
||||||
|
display: flex; flex-wrap: wrap; gap: 6px;
|
||||||
|
}
|
||||||
|
.company-agent-hidden-chip {
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
color: var(--text-primary); font-size: 10.5px;
|
||||||
|
padding: 4px 9px; border-radius: 999px; cursor: pointer;
|
||||||
|
}
|
||||||
|
.company-agent-hidden-chip:hover {
|
||||||
|
border-color: var(--accent); color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
.company-agent-head {
|
.company-agent-head {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
+74
-74
@@ -12,9 +12,9 @@
|
|||||||
<div class="header-top">
|
<div class="header-top">
|
||||||
<div class="brand"><div class="logo">✦</div> Astra</div>
|
<div class="brand"><div class="logo">✦</div> Astra</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button class="icon-btn" id="newChatBtn" data-tooltip="New Chat">New</button>
|
<button class="icon-btn" id="newChatBtn" data-tooltip="새 대화 시작 (현재 대화는 기록에 저장)">새 대화</button>
|
||||||
<button class="icon-btn toggle-chip active" id="brainTraceBtn" data-tooltip="Second Brain Trace Mode">Trace</button>
|
<button class="icon-btn toggle-chip active" id="brainTraceBtn" data-tooltip="답변에 사용된 두뇌(지식) 근거를 함께 표시">근거 추적</button>
|
||||||
<button class="icon-btn toggle-chip" id="internetBtn" data-tooltip="Internet Access">Web</button>
|
<button class="icon-btn toggle-chip" id="internetBtn" data-tooltip="필요할 때 웹에서 정보를 가져옵니다">웹 검색</button>
|
||||||
<!--
|
<!--
|
||||||
Corp toggle — replaces the old pill-shaped chip that lived
|
Corp toggle — replaces the old pill-shaped chip that lived
|
||||||
in the records-line. Same rounded-rectangle style as the
|
in the records-line. Same rounded-rectangle style as the
|
||||||
@@ -22,19 +22,19 @@
|
|||||||
the adjacent ▾ opens the manage overlay (agents · models ·
|
the adjacent ▾ opens the manage overlay (agents · models ·
|
||||||
prompt edits · Knowledge Mix sliders).
|
prompt edits · Knowledge Mix sliders).
|
||||||
-->
|
-->
|
||||||
<button class="icon-btn toggle-chip" id="companyChip" data-tooltip="1인 기업 모드 토글">Corp</button>
|
<button class="icon-btn toggle-chip" id="companyChip" data-tooltip="1인 기업 모드 — CEO가 요청을 분석해 전문 에이전트에게 분배">기업 모드</button>
|
||||||
<button class="icon-btn" id="companyManageBtn" data-tooltip="회사 관리 (에이전트·모델·prompt·Knowledge Mix)">▾</button>
|
<button class="icon-btn" id="companyManageBtn" data-tooltip="기업 모드 관리 (에이전트 · 모델 · 프롬프트 · 지식 비중)">▾</button>
|
||||||
<div class="hdr-dropdown" data-dd>
|
<div class="hdr-dropdown" data-dd>
|
||||||
<button class="icon-btn" id="toolsMenuBtn" data-dd-trigger data-tooltip="Tools">Tools ▾</button>
|
<button class="icon-btn" id="toolsMenuBtn" data-dd-trigger data-tooltip="개발자 도구 모음">도구 ▾</button>
|
||||||
<div class="hdr-menu" id="toolsMenu" data-dd-menu>
|
<div class="hdr-menu" id="toolsMenu" data-dd-menu>
|
||||||
<div class="hdr-menu-label">Tools</div>
|
<div class="hdr-menu-label">도구</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 toggle-item" id="brainTraceDebugBtn" data-tooltip="근거 추적의 원본 JSON 표시 (개발자용)">근거 추적 JSON 보기</button>
|
||||||
<button class="hdr-menu-item" id="saveWikiRawBtn" data-tooltip="Save Wiki Raw">Save Wiki Raw</button>
|
<button class="hdr-menu-item" id="saveWikiRawBtn" data-tooltip="현재 답변의 원본 마크다운을 두뇌(지식)에 저장">원본 답변을 두뇌에 저장</button>
|
||||||
<button class="hdr-menu-item" id="brainBtn" data-tooltip="Sync Knowledge (commit + push)">Sync Knowledge</button>
|
<button class="hdr-menu-item" id="brainBtn" data-tooltip="두뇌(지식) 폴더 변경사항을 git commit + push">두뇌 동기화</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="icon-btn" id="historyBtn" data-tooltip="View History">History</button>
|
<button class="icon-btn" id="historyBtn" data-tooltip="이전 대화 기록 보기">기록</button>
|
||||||
<button class="icon-btn" id="settingsBtn" data-tooltip="Settings">Set</button>
|
<button class="icon-btn" id="settingsBtn" data-tooltip="설정 패널 열기">설정</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,62 +47,62 @@
|
|||||||
|
|
||||||
<div class="context-bar">
|
<div class="context-bar">
|
||||||
<div class="context-summary" id="contextSummary">
|
<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-seg"><span class="cb-key">두뇌</span> <span id="ctxBrainName" class="cb-val">—</span></span>
|
||||||
<span class="cb-sep">·</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-seg"><span class="cb-key">에이전트</span> <span id="ctxAgentName" class="cb-val">—</span></span>
|
||||||
<span class="cb-sep">·</span>
|
<span class="cb-sep">·</span>
|
||||||
<span class="cb-seg"><span class="cb-key">Project</span> <span id="ctxProjectName" class="cb-val">—</span></span>
|
<span class="cb-seg"><span class="cb-key">프로젝트</span> <span id="ctxProjectName" class="cb-val">—</span></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="hdr-dropdown context-edit-dd" data-dd>
|
<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>
|
<button class="icon-btn" id="contextEditBtn" data-dd-trigger data-tooltip="모델 · 두뇌 · 에이전트 · 프로젝트 변경">변경 ▾</button>
|
||||||
<div class="hdr-menu hdr-menu-wide" id="contextEditMenu" data-dd-menu>
|
<div class="hdr-menu hdr-menu-wide" id="contextEditMenu" data-dd-menu>
|
||||||
<div class="hdr-menu-label">Model</div>
|
<div class="hdr-menu-label">모델</div>
|
||||||
<div class="select-wrap"><select id="modelSel" title="Select Model"></select></div>
|
<div class="select-wrap"><select id="modelSel" title="이 대화에 사용할 모델"></select></div>
|
||||||
|
|
||||||
<div class="hdr-menu-label">
|
<div class="hdr-menu-label">
|
||||||
Knowledge Mix
|
지식 비중
|
||||||
<span class="hdr-menu-hint" id="knowledgeMixHint">Model 50% · Brain 50%</span>
|
<span class="hdr-menu-hint" id="knowledgeMixHint">모델 50% · 두뇌 50%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="knowledge-mix-control" title="Slide left for more model knowledge, right for more Second Brain reliance">
|
<div class="knowledge-mix-control" title="왼쪽으로 갈수록 모델 자체 지식, 오른쪽으로 갈수록 내 두뇌(저장된 지식)에 의존합니다">
|
||||||
<span class="km-end-label">Model</span>
|
<span class="km-end-label">모델</span>
|
||||||
<input type="range" id="knowledgeMixSlider" min="0" max="100" step="5" value="50" class="km-slider">
|
<input type="range" id="knowledgeMixSlider" min="0" max="100" step="5" value="50" class="km-slider">
|
||||||
<span class="km-end-label">Brain</span>
|
<span class="km-end-label">두뇌</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hdr-menu-label">Brain</div>
|
<div class="hdr-menu-label">두뇌 (지식 폴더)</div>
|
||||||
<div class="control-row">
|
<div class="control-row">
|
||||||
<div class="select-wrap"><select id="brainSel" title="Select Brain"></select></div>
|
<div class="select-wrap"><select id="brainSel" title="사용할 두뇌(지식 폴더) 선택"></select></div>
|
||||||
<div class="tool-group" aria-label="Brain actions">
|
<div class="tool-group" aria-label="두뇌 관리">
|
||||||
<button class="icon-btn" id="addBrainBtn" data-tooltip="Add Brain">Add</button>
|
<button class="icon-btn" id="addBrainBtn" data-tooltip="새 두뇌 추가">추가</button>
|
||||||
<button class="icon-btn" id="editBrainBtn" data-tooltip="Edit Brain">Edit</button>
|
<button class="icon-btn" id="editBrainBtn" data-tooltip="선택한 두뇌 수정">수정</button>
|
||||||
<button class="icon-btn" id="deleteBrainBtn" data-tooltip="Delete Brain">Del</button>
|
<button class="icon-btn" id="deleteBrainBtn" data-tooltip="선택한 두뇌 삭제">삭제</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hdr-menu-label">Agent</div>
|
<div class="hdr-menu-label">에이전트</div>
|
||||||
<div class="control-row">
|
<div class="control-row">
|
||||||
<div class="select-wrap"><select id="agentSel" title="Select Agentic Skill"></select></div>
|
<div class="select-wrap"><select id="agentSel" title="대화에 적용할 에이전트(역할) 선택"></select></div>
|
||||||
<div class="tool-group" aria-label="Agent actions">
|
<div class="tool-group" aria-label="에이전트 관리">
|
||||||
<button class="icon-btn" id="addAgentBtn" data-tooltip="Create Agent">Add</button>
|
<button class="icon-btn" id="addAgentBtn" data-tooltip="새 에이전트 만들기">추가</button>
|
||||||
<button class="icon-btn" id="editAgentBtn" data-tooltip="Edit Agent Skill">Edit</button>
|
<button class="icon-btn" id="editAgentBtn" data-tooltip="선택한 에이전트 수정">수정</button>
|
||||||
<button class="icon-btn" id="deleteAgentBtn" data-tooltip="Delete Agent Skill">Del</button>
|
<button class="icon-btn" id="deleteAgentBtn" data-tooltip="선택한 에이전트 삭제">삭제</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hdr-menu-label">Agent ↔ Knowledge</div>
|
<div class="hdr-menu-label">에이전트 ↔ 지식 연결</div>
|
||||||
<div class="control-row">
|
<div class="control-row">
|
||||||
<div class="select-wrap"><select id="knowledgeScopeSel" title="Knowledge folders mapped to this agent"></select></div>
|
<div class="select-wrap"><select id="knowledgeScopeSel" title="이 에이전트가 참고할 지식 폴더 범위"></select></div>
|
||||||
<div class="tool-group" aria-label="Knowledge map actions">
|
<div class="tool-group" aria-label="지식 연결 관리">
|
||||||
<button class="icon-btn" id="editKnowledgeMapBtn" data-tooltip="Edit Agent ↔ Knowledge Map">Map</button>
|
<button class="icon-btn" id="editKnowledgeMapBtn" data-tooltip="에이전트별 지식 폴더 연결 편집">연결 편집</button>
|
||||||
<button class="icon-btn" id="reloadKnowledgeMapBtn" data-tooltip="Reload Knowledge Map">Rld</button>
|
<button class="icon-btn" id="reloadKnowledgeMapBtn" data-tooltip="연결 정보를 디스크에서 다시 읽기">새로고침</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hdr-menu-label">Project (Chronicle)</div>
|
<div class="hdr-menu-label">프로젝트 (작업 기록)</div>
|
||||||
<div class="control-row">
|
<div class="control-row">
|
||||||
<div class="select-wrap"><select id="designerSel" title="Select Designer Project"></select></div>
|
<div class="select-wrap"><select id="designerSel" title="작업 기록을 남길 프로젝트 선택"></select></div>
|
||||||
<div class="tool-group" aria-label="Designer actions">
|
<div class="tool-group" aria-label="프로젝트 관리">
|
||||||
<button class="icon-btn" id="addDesignerBtn" data-tooltip="Create Designer Project">Add</button>
|
<button class="icon-btn" id="addDesignerBtn" data-tooltip="새 프로젝트 만들기">추가</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -112,19 +112,19 @@
|
|||||||
<div class="records-line">
|
<div class="records-line">
|
||||||
<div class="rl-summary">
|
<div class="rl-summary">
|
||||||
<span class="status-dot ready"></span>
|
<span class="status-dot ready"></span>
|
||||||
<span id="chronicleAutoStatus" title="Project records are saved automatically after meaningful project turns.">Auto Records</span>
|
<span id="chronicleAutoStatus" title="의미 있는 대화 후 프로젝트 기록이 자동으로 저장됩니다.">자동 기록</span>
|
||||||
<span class="rl-latest" id="recordsLatest"></span>
|
<span class="rl-latest" id="recordsLatest"></span>
|
||||||
</div>
|
</div>
|
||||||
<!-- (Removed) Corp chip moved to the header toolbar above —
|
<!-- (Removed) Corp chip moved to the header toolbar above —
|
||||||
see #companyChip / #companyManageBtn alongside New/Trace/Web. -->
|
see #companyChip / #companyManageBtn alongside New/Trace/Web. -->
|
||||||
<div class="hdr-dropdown" data-dd>
|
<div class="hdr-dropdown" data-dd>
|
||||||
<button class="icon-btn" id="recordsMenuBtn" data-dd-trigger data-tooltip="Chronicle records">Records ▾</button>
|
<button class="icon-btn" id="recordsMenuBtn" data-dd-trigger data-tooltip="저장된 작업 기록 열기">기록 ▾</button>
|
||||||
<div class="hdr-menu hdr-menu-wide" id="recordsMenu" data-dd-menu>
|
<div class="hdr-menu hdr-menu-wide" id="recordsMenu" data-dd-menu>
|
||||||
<div class="hdr-menu-label">Chronicle Records</div>
|
<div class="hdr-menu-label">작업 기록</div>
|
||||||
<div class="select-wrap"><select id="chronicleRecordSel" title="Select Chronicle Record"></select></div>
|
<div class="select-wrap"><select id="chronicleRecordSel" title="열어볼 작업 기록 선택"></select></div>
|
||||||
<button class="hdr-menu-item" id="openChronicleRecordBtn" data-tooltip="Open Selected Record">Open Selected Record</button>
|
<button class="hdr-menu-item" id="openChronicleRecordBtn" data-tooltip="선택한 기록 열기">선택한 기록 열기</button>
|
||||||
<button class="hdr-menu-item" id="refreshChronicleRecordsBtn" data-tooltip="Refresh Records">Refresh Records</button>
|
<button class="hdr-menu-item" id="refreshChronicleRecordsBtn" data-tooltip="기록 목록 다시 불러오기">기록 새로고침</button>
|
||||||
<button class="hdr-menu-item" id="openDesignerBtn" data-tooltip="Open Record Folder">Open Record Folder</button>
|
<button class="hdr-menu-item" id="openDesignerBtn" data-tooltip="기록이 저장된 폴더 열기">기록 폴더 열기</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -166,7 +166,7 @@
|
|||||||
<div class="map-section-hint">CEO는 항상 활성. 각 에이전트별로 모델을 따로 지정할 수 있습니다 — 다른 모델을 쓸 때만 LM Studio가 swap합니다.</div>
|
<div class="map-section-hint">CEO는 항상 활성. 각 에이전트별로 모델을 따로 지정할 수 있습니다 — 다른 모델을 쓸 때만 LM Studio가 swap합니다.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-btn-group">
|
<div class="map-btn-group">
|
||||||
<button class="secondary-btn" id="addCompanyAgentBtn" title="새 사용자 에이전트 추가">+ Agent</button>
|
<button class="secondary-btn" id="addCompanyAgentBtn" title="새 사용자 에이전트 추가">+ 에이전트 추가</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul id="companyAgentList" class="map-list company-agent-list"></ul>
|
<ul id="companyAgentList" class="map-list company-agent-list"></ul>
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
style="padding:3px 6px; font-size:10px; background:var(--surface); color:var(--text-primary); border:1px solid var(--border); border-radius:5px;">
|
style="padding:3px 6px; font-size:10px; background:var(--surface); color:var(--text-primary); border:1px solid var(--border); border-radius:5px;">
|
||||||
<option value="">📋 템플릿에서…</option>
|
<option value="">📋 템플릿에서…</option>
|
||||||
</select>
|
</select>
|
||||||
<button class="secondary-btn" id="addCompanyPipelineBtn" title="빈 파이프라인부터 시작">+ 빈 Pipeline</button>
|
<button class="secondary-btn" id="addCompanyPipelineBtn" title="빈 파이프라인부터 시작">+ 빈 파이프라인</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-row" style="margin-top:8px; gap:8px; align-items:center;">
|
<div class="control-row" style="margin-top:8px; gap:8px; align-items:center;">
|
||||||
@@ -255,7 +255,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; margin-top:12px; margin-bottom:6px;">
|
<div style="display:flex; justify-content:space-between; align-items:center; margin-top:12px; margin-bottom:6px;">
|
||||||
<div style="font-size:11px; font-weight:700; color:var(--text-bright);">단계 (Stages)</div>
|
<div style="font-size:11px; font-weight:700; color:var(--text-bright);">단계 (Stages)</div>
|
||||||
<button class="secondary-btn" id="addStageBtn" style="font-size:10px; padding:3px 8px;">+ Stage 추가</button>
|
<button class="secondary-btn" id="addStageBtn" style="font-size:10px; padding:3px 8px;">+ 단계 추가</button>
|
||||||
</div>
|
</div>
|
||||||
<ul id="pipelineStageList" class="pipeline-stage-list"></ul>
|
<ul id="pipelineStageList" class="pipeline-stage-list"></ul>
|
||||||
<div class="editor-actions" style="margin-top:10px;">
|
<div class="editor-actions" style="margin-top:10px;">
|
||||||
@@ -354,7 +354,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="map-footer">
|
<div class="map-footer">
|
||||||
<button class="secondary-btn" id="editAgentMapJsonBtn" title="고급 사용자용: JSON으로 직접 편집">JSON 편집</button>
|
<button class="secondary-btn" id="editAgentMapJsonBtn" title="고급 사용자용: JSON으로 직접 편집">고급 (JSON)</button>
|
||||||
<div style="flex:1"></div>
|
<div style="flex:1"></div>
|
||||||
<button class="secondary-btn" id="cancelAgentMapBtn">취소</button>
|
<button class="secondary-btn" id="cancelAgentMapBtn">취소</button>
|
||||||
<button class="send-btn" id="saveAgentMapBtn">저장</button>
|
<button class="send-btn" id="saveAgentMapBtn">저장</button>
|
||||||
@@ -377,8 +377,8 @@
|
|||||||
<div class="chat" id="chat">
|
<div class="chat" id="chat">
|
||||||
<div class="welcome">
|
<div class="welcome">
|
||||||
<div class="welcome-logo">✦</div>
|
<div class="welcome-logo">✦</div>
|
||||||
<div class="welcome-title">Welcome to Astra</div>
|
<div class="welcome-title">Astra에 오신 것을 환영합니다</div>
|
||||||
<p>Your premium local AI assistant.<br>Ready to analyze projects and build reports.</p>
|
<p>로컬에서 동작하는 개인 AI 비서입니다.<br>아래 입력창에 무엇을 도와줄지 적어보세요.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -406,39 +406,39 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="arch-chip-actions" id="archChipActions">
|
<div class="arch-chip-actions" id="archChipActions">
|
||||||
<!-- active state buttons -->
|
<!-- 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="archOpenBtn" title="프로젝트 구조 문서 열기">열기</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="archRefreshBtn" title="프로젝트를 지금 다시 스캔">새로고침</button>
|
||||||
<button class="arch-chip-btn arch-chip-active-only" id="archDetachBtn" title="자동 첨부 끄기">Detach</button>
|
<button class="arch-chip-btn arch-chip-active-only" id="archDetachBtn" title="이 프로젝트 컨텍스트 자동 첨부 끄기">분리</button>
|
||||||
<!-- inactive state button -->
|
<!-- inactive state button -->
|
||||||
<button class="arch-chip-btn arch-chip-inactive-only" id="archAttachBtn" title="이 프로젝트에 architecture 자동 첨부 켜기">Attach</button>
|
<button class="arch-chip-btn arch-chip-inactive-only" id="archAttachBtn" title="이 프로젝트 컨텍스트를 대화에 자동 첨부">첨부</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="agentConfigPanel" class="panel">
|
<div id="agentConfigPanel" class="panel">
|
||||||
<div class="field-label">Agent Persona/Instructions</div>
|
<div class="field-label">에이전트 페르소나 / 지시사항</div>
|
||||||
<textarea id="agentPrompt" rows="5" placeholder="Agent Persona & Instructions..."></textarea>
|
<textarea id="agentPrompt" rows="5" placeholder="이 에이전트가 어떤 역할로, 어떤 톤으로 답해야 하는지 적으세요..."></textarea>
|
||||||
|
|
||||||
<div class="field-label">Negative Prompt (Strict Rules)</div>
|
<div class="field-label">금지 사항 (반드시 지킬 규칙)</div>
|
||||||
<textarea id="negativePrompt" rows="2" placeholder="What NOT to do..."></textarea>
|
<textarea id="negativePrompt" rows="2" placeholder="이 에이전트가 절대 하지 말아야 할 것..."></textarea>
|
||||||
|
|
||||||
<button id="updateAgentBtn" class="secondary-btn">Update Agent Skill</button>
|
<button id="updateAgentBtn" class="secondary-btn">에이전트 저장</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<div id="attachPreview" class="attachment-preview"></div>
|
<div id="attachPreview" class="attachment-preview"></div>
|
||||||
<textarea id="input" rows="1" placeholder="Ask Astra..."></textarea>
|
<textarea id="input" rows="1" placeholder="Astra에게 무엇이든 물어보세요..."></textarea>
|
||||||
<div class="input-footer">
|
<div class="input-footer">
|
||||||
<div class="footer-left">
|
<div class="footer-left">
|
||||||
<button class="icon-btn" id="attachBtn" title="Attach Files">📎</button>
|
<button class="icon-btn" id="attachBtn" title="파일 첨부 (이미지 · 문서 · 코드)">📎</button>
|
||||||
<span class="model-pill" title="Switch model for this conversation">
|
<span class="model-pill" title="이 대화에 사용할 모델 변경">
|
||||||
<span class="model-prefix">Model:</span>
|
<span class="model-prefix">모델:</span>
|
||||||
<select id="modelInlineSel" class="model-inline-sel" title="Switch model"></select>
|
<select id="modelInlineSel" class="model-inline-sel" title="모델 변경"></select>
|
||||||
</span>
|
</span>
|
||||||
<span id="statusLabel" class="status-label"></span>
|
<span id="statusLabel" class="status-label"></span>
|
||||||
<span id="ctxBadge" class="ctx-badge" title="직전 요청에 실제로 들어간 컨텍스트 추정치"></span>
|
<span id="ctxBadge" class="ctx-badge" title="직전 요청에 실제로 들어간 컨텍스트 추정치"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-right">
|
<div class="footer-right">
|
||||||
<button id="cancelBtn" class="cancel-btn" title="Clear draft" style="display:none;">✕ Clear</button>
|
<button id="cancelBtn" class="cancel-btn" title="입력 비우기" style="display:none;">✕ 비우기</button>
|
||||||
<button id="stopBtn" class="stop-btn" title="Stop generation" style="display:none;">■ Stop</button>
|
<button id="stopBtn" class="stop-btn" title="생성 중단" style="display:none;">■ 중단</button>
|
||||||
<button id="sendBtn" class="send-btn">Send</button>
|
<button id="sendBtn" class="send-btn">보내기</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="toastNotif" class="toast-notif"></div>
|
<div id="toastNotif" class="toast-notif"></div>
|
||||||
|
|||||||
+91
-19
@@ -179,7 +179,7 @@
|
|||||||
const recordsLatest = document.getElementById('recordsLatest');
|
const recordsLatest = document.getElementById('recordsLatest');
|
||||||
|
|
||||||
function escAttr(t) { return String(t == null ? '' : t).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); }
|
function escAttr(t) { return String(t == null ? '' : t).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); }
|
||||||
function fmtMixHint(w) { return `Model ${100 - w}% · Brain ${w}%`; }
|
function fmtMixHint(w) { return `모델 ${100 - w}% · 두뇌 ${w}%`; }
|
||||||
/** Compact relative-time formatter for chips (e.g. "2m ago", "just now"). */
|
/** Compact relative-time formatter for chips (e.g. "2m ago", "just now"). */
|
||||||
function formatRelativeTime(iso) {
|
function formatRelativeTime(iso) {
|
||||||
try {
|
try {
|
||||||
@@ -405,7 +405,7 @@
|
|||||||
: Math.max(0, Math.min(100, agentMapDraft.secondBrainWeight | 0));
|
: Math.max(0, Math.min(100, agentMapDraft.secondBrainWeight | 0));
|
||||||
slider.value = String(value);
|
slider.value = String(value);
|
||||||
hint.textContent = useGlobal
|
hint.textContent = useGlobal
|
||||||
? `Use global · ${fmtMixHint(value)}`
|
? `전역 설정 사용 · ${fmtMixHint(value)}`
|
||||||
: fmtMixHint(value);
|
: fmtMixHint(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -815,12 +815,24 @@
|
|||||||
case 'deleteCompanyAgentResult': {
|
case 'deleteCompanyAgentResult': {
|
||||||
const v = msg.value || {};
|
const v = msg.value || {};
|
||||||
if (v.ok) {
|
if (v.ok) {
|
||||||
showToast(`🗑 '${v.agentId}' 에이전트 삭제됨`, 'warn');
|
const msg2 = v.kind === 'builtin-hidden'
|
||||||
|
? `🗑 기본 에이전트 '${v.agentId}' 숨김 처리 (목록 하단에서 복원 가능)`
|
||||||
|
: `🗑 '${v.agentId}' 에이전트 삭제됨`;
|
||||||
|
showToast(msg2, 'warn');
|
||||||
} else {
|
} else {
|
||||||
showToast(`삭제 실패: ${v.reason || '알 수 없음'}`, 'warn');
|
showToast(`삭제 실패: ${v.reason || '알 수 없음'}`, 'warn');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'restoreHiddenAgentResult': {
|
||||||
|
const v = msg.value || {};
|
||||||
|
if (v.ok) {
|
||||||
|
showToast(`↩ '${v.agentId}' 에이전트 복원 완료`, 'info');
|
||||||
|
} else {
|
||||||
|
showToast(`복원 실패: ${v.reason || '알 수 없음'}`, 'warn');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'companyPipelines': {
|
case 'companyPipelines': {
|
||||||
if (typeof window.__renderCompanyPipelines === 'function') {
|
if (typeof window.__renderCompanyPipelines === 'function') {
|
||||||
window.__renderCompanyPipelines(msg.value || {});
|
window.__renderCompanyPipelines(msg.value || {});
|
||||||
@@ -2279,7 +2291,24 @@
|
|||||||
}
|
}
|
||||||
if (payload && payload.roleCategoryLabels) _roleCategoryLabels = payload.roleCategoryLabels;
|
if (payload && payload.roleCategoryLabels) _roleCategoryLabels = payload.roleCategoryLabels;
|
||||||
if (payload && Array.isArray(payload.roleCategoryOrder)) _roleCategoryOrder = payload.roleCategoryOrder;
|
if (payload && Array.isArray(payload.roleCategoryOrder)) _roleCategoryOrder = payload.roleCategoryOrder;
|
||||||
const agents = (payload && Array.isArray(payload.agents)) ? payload.agents : [];
|
const rawAgents = (payload && Array.isArray(payload.agents)) ? payload.agents : [];
|
||||||
|
// 활성/비활성 정렬: CEO는 항상 최상단(alwaysOn), 그 다음 활성(켜짐) 에이전트,
|
||||||
|
// 마지막으로 비활성. 같은 그룹 내에서는 백엔드가 보낸 원래 순서를 유지(stable).
|
||||||
|
const agents = rawAgents
|
||||||
|
.map((a, i) => ({ a, i }))
|
||||||
|
.sort((x, y) => {
|
||||||
|
// CEO/alwaysOn 최우선
|
||||||
|
const xLocked = x.a.alwaysOn ? 0 : 1;
|
||||||
|
const yLocked = y.a.alwaysOn ? 0 : 1;
|
||||||
|
if (xLocked !== yLocked) return xLocked - yLocked;
|
||||||
|
// 그 다음 active 여부
|
||||||
|
const xAct = x.a.active ? 0 : 1;
|
||||||
|
const yAct = y.a.active ? 0 : 1;
|
||||||
|
if (xAct !== yAct) return xAct - yAct;
|
||||||
|
// tiebreak: 원래 순서
|
||||||
|
return x.i - y.i;
|
||||||
|
})
|
||||||
|
.map((p) => p.a);
|
||||||
for (const a of agents) {
|
for (const a of agents) {
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
li.className = 'company-agent-card';
|
li.className = 'company-agent-card';
|
||||||
@@ -2358,10 +2387,10 @@
|
|||||||
|
|
||||||
const editBtn = document.createElement('button');
|
const editBtn = document.createElement('button');
|
||||||
editBtn.className = 'company-agent-edit';
|
editBtn.className = 'company-agent-edit';
|
||||||
editBtn.textContent = '✎ Edit';
|
editBtn.textContent = '✎ 편집';
|
||||||
if (a.personaOverridden || a.specialtyOverridden || a.taglineOverridden) {
|
if (a.personaOverridden || a.specialtyOverridden || a.taglineOverridden) {
|
||||||
editBtn.classList.add('dirty');
|
editBtn.classList.add('dirty');
|
||||||
editBtn.title = 'prompt 편집됨 (원본과 다름)';
|
editBtn.title = '프롬프트가 사용자에 의해 편집되었습니다 (원본과 다름)';
|
||||||
}
|
}
|
||||||
editBtn.onclick = () => {
|
editBtn.onclick = () => {
|
||||||
const expanded = li.getAttribute('data-expanded') === 'true';
|
const expanded = li.getAttribute('data-expanded') === 'true';
|
||||||
@@ -2370,15 +2399,15 @@
|
|||||||
|
|
||||||
const toggle = document.createElement('button');
|
const toggle = document.createElement('button');
|
||||||
toggle.className = 'company-agent-toggle';
|
toggle.className = 'company-agent-toggle';
|
||||||
toggle.textContent = a.active ? 'ON' : 'OFF';
|
toggle.textContent = a.active ? '켜짐' : '꺼짐';
|
||||||
if (a.alwaysOn) {
|
if (a.alwaysOn) {
|
||||||
toggle.disabled = true;
|
toggle.disabled = true;
|
||||||
toggle.textContent = 'LOCKED';
|
toggle.textContent = '고정';
|
||||||
} else {
|
} else {
|
||||||
toggle.onclick = () => {
|
toggle.onclick = () => {
|
||||||
const wantActive = !(li.getAttribute('data-active') === 'true');
|
const wantActive = !(li.getAttribute('data-active') === 'true');
|
||||||
li.setAttribute('data-active', wantActive ? 'true' : 'false');
|
li.setAttribute('data-active', wantActive ? 'true' : 'false');
|
||||||
toggle.textContent = wantActive ? 'ON' : 'OFF';
|
toggle.textContent = wantActive ? '켜짐' : '꺼짐';
|
||||||
const nextIds = Array.from(_companyAgentList.querySelectorAll('.company-agent-card'))
|
const nextIds = Array.from(_companyAgentList.querySelectorAll('.company-agent-card'))
|
||||||
.filter(el => el.getAttribute('data-active') === 'true')
|
.filter(el => el.getAttribute('data-active') === 'true')
|
||||||
.map(el => el.dataset.agentId)
|
.map(el => el.dataset.agentId)
|
||||||
@@ -2389,17 +2418,30 @@
|
|||||||
controls.appendChild(roleSelEl);
|
controls.appendChild(roleSelEl);
|
||||||
controls.appendChild(modelSelEl);
|
controls.appendChild(modelSelEl);
|
||||||
controls.appendChild(editBtn);
|
controls.appendChild(editBtn);
|
||||||
// 사용자 추가 에이전트만 삭제 가능. 기본 9명은 코드에 박혀 있어
|
// 삭제 버튼 — CEO만 빼고 빌트인/커스텀 모두 노출. 단, 어떤 워크 파이프라인의
|
||||||
// 백엔드도 거부하므로 UI에서도 버튼을 노출하지 않음.
|
// stage라도 이 에이전트를 참조하고 있으면 disabled로 처리하고 tooltip에
|
||||||
if (a.custom) {
|
// 사용 중인 파이프라인을 적어, 사용자가 어디로 가서 빼야 하는지 보이게 한다.
|
||||||
|
if (!a.alwaysOn) {
|
||||||
const delBtn = document.createElement('button');
|
const delBtn = document.createElement('button');
|
||||||
delBtn.className = 'company-agent-edit';
|
delBtn.className = 'company-agent-edit company-agent-delete';
|
||||||
delBtn.textContent = '🗑';
|
delBtn.textContent = '🗑';
|
||||||
delBtn.title = `'${a.name}' 에이전트 삭제`;
|
const usedIn = Array.isArray(a.usedInPipelines) ? a.usedInPipelines : [];
|
||||||
|
if (usedIn.length > 0) {
|
||||||
|
delBtn.disabled = true;
|
||||||
|
delBtn.classList.add('disabled');
|
||||||
|
delBtn.title = `삭제 불가 — 다음 파이프라인에서 사용 중: ${usedIn.map((n) => `'${n}'`).join(', ')}. 파이프라인에서 먼저 빼거나 다른 에이전트로 교체하세요.`;
|
||||||
|
} else {
|
||||||
|
delBtn.title = a.custom
|
||||||
|
? `'${a.name}' 에이전트 삭제 (모든 설정 함께 제거)`
|
||||||
|
: `'${a.name}' 에이전트 숨기기 (기본 에이전트라 복원 가능)`;
|
||||||
delBtn.onclick = () => {
|
delBtn.onclick = () => {
|
||||||
if (!confirm(`'${a.name}' 에이전트를 삭제할까요? 이 에이전트의 모든 설정(모델·프롬프트·지식 믹스)도 함께 삭제됩니다.`)) return;
|
const confirmMsg = a.custom
|
||||||
|
? `'${a.name}' 에이전트를 삭제할까요? 이 에이전트의 모든 설정(모델·프롬프트·지식 비중)도 함께 삭제됩니다.`
|
||||||
|
: `기본 에이전트 '${a.name}'을(를) 목록에서 숨길까요? 나중에 [목록 맨 아래 → 삭제된 기본 에이전트] 영역에서 복원할 수 있습니다.`;
|
||||||
|
if (!confirm(confirmMsg)) return;
|
||||||
vscode.postMessage({ type: 'deleteCompanyAgent', agentId: a.id });
|
vscode.postMessage({ type: 'deleteCompanyAgent', agentId: a.id });
|
||||||
};
|
};
|
||||||
|
}
|
||||||
controls.appendChild(delBtn);
|
controls.appendChild(delBtn);
|
||||||
}
|
}
|
||||||
controls.appendChild(toggle);
|
controls.appendChild(toggle);
|
||||||
@@ -2422,6 +2464,36 @@
|
|||||||
li.appendChild(_buildAgentPromptEditor(a));
|
li.appendChild(_buildAgentPromptEditor(a));
|
||||||
_companyAgentList.appendChild(li);
|
_companyAgentList.appendChild(li);
|
||||||
}
|
}
|
||||||
|
// ── 숨겨진 기본 에이전트 복원 영역 ──
|
||||||
|
// 사용자가 "삭제"한 빌트인 에이전트를 다시 꺼낼 수 있는 출구. 빈 배열이면
|
||||||
|
// 섹션 자체를 그리지 않아 평소엔 시야에서 사라진다.
|
||||||
|
const hidden = Array.isArray(payload && payload.hiddenBuiltins) ? payload.hiddenBuiltins : [];
|
||||||
|
if (hidden.length > 0) {
|
||||||
|
const restoreLi = document.createElement('li');
|
||||||
|
restoreLi.className = 'company-agent-hidden-section';
|
||||||
|
const head = document.createElement('div');
|
||||||
|
head.className = 'company-agent-hidden-head';
|
||||||
|
head.textContent = `삭제된 기본 에이전트 (${hidden.length}명)`;
|
||||||
|
restoreLi.appendChild(head);
|
||||||
|
const hint = document.createElement('div');
|
||||||
|
hint.className = 'company-agent-hidden-hint';
|
||||||
|
hint.textContent = '복원하면 목록에 다시 추가됩니다. 설정은 모두 디폴트로 시작합니다.';
|
||||||
|
restoreLi.appendChild(hint);
|
||||||
|
const list = document.createElement('div');
|
||||||
|
list.className = 'company-agent-hidden-list';
|
||||||
|
for (const h of hidden) {
|
||||||
|
const chip = document.createElement('button');
|
||||||
|
chip.className = 'company-agent-hidden-chip';
|
||||||
|
chip.textContent = `${h.emoji || '🙂'} ${h.name} · ${h.role} ↩ 복원`;
|
||||||
|
chip.title = `'${h.name}' 복원`;
|
||||||
|
chip.onclick = () => {
|
||||||
|
vscode.postMessage({ type: 'restoreHiddenAgent', agentId: h.id });
|
||||||
|
};
|
||||||
|
list.appendChild(chip);
|
||||||
|
}
|
||||||
|
restoreLi.appendChild(list);
|
||||||
|
_companyAgentList.appendChild(restoreLi);
|
||||||
|
}
|
||||||
if (_companyStatusEl) _companyStatusEl.textContent = '';
|
if (_companyStatusEl) _companyStatusEl.textContent = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2573,15 +2645,15 @@
|
|||||||
|
|
||||||
const resetBtn = document.createElement('button');
|
const resetBtn = document.createElement('button');
|
||||||
resetBtn.className = 'danger';
|
resetBtn.className = 'danger';
|
||||||
resetBtn.textContent = 'Reset';
|
resetBtn.textContent = '기본값으로';
|
||||||
resetBtn.title = '이 에이전트의 모든 override 제거 → 디폴트로 복귀 (이름·역할·프롬프트 전부)';
|
resetBtn.title = '이 에이전트의 모든 사용자 변경 사항 제거 → 디폴트로 복귀 (이름·역할·프롬프트 전부)';
|
||||||
resetBtn.onclick = () => {
|
resetBtn.onclick = () => {
|
||||||
vscode.postMessage({ type: 'setCompanyAgentPrompt', agentId: a.id, override: null });
|
vscode.postMessage({ type: 'setCompanyAgentPrompt', agentId: a.id, override: null });
|
||||||
vscode.postMessage({ type: 'setCompanyAgentDisplay', agentId: a.id, override: null });
|
vscode.postMessage({ type: 'setCompanyAgentDisplay', agentId: a.id, override: null });
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelBtn = document.createElement('button');
|
const cancelBtn = document.createElement('button');
|
||||||
cancelBtn.textContent = 'Cancel';
|
cancelBtn.textContent = '취소';
|
||||||
cancelBtn.onclick = () => {
|
cancelBtn.onclick = () => {
|
||||||
const card = editor.closest('.company-agent-card');
|
const card = editor.closest('.company-agent-card');
|
||||||
if (card) card.setAttribute('data-expanded', 'false');
|
if (card) card.setAttribute('data-expanded', 'false');
|
||||||
@@ -2589,7 +2661,7 @@
|
|||||||
|
|
||||||
const saveBtn = document.createElement('button');
|
const saveBtn = document.createElement('button');
|
||||||
saveBtn.className = 'primary';
|
saveBtn.className = 'primary';
|
||||||
saveBtn.textContent = 'Save';
|
saveBtn.textContent = '저장';
|
||||||
saveBtn.onclick = () => {
|
saveBtn.onclick = () => {
|
||||||
// 두 개의 message로 분리 전송 — display(name/role/emoji/color)와
|
// 두 개의 message로 분리 전송 — display(name/role/emoji/color)와
|
||||||
// prompt(tagline/specialty/persona)는 백엔드에서 서로 다른
|
// prompt(tagline/specialty/persona)는 백엔드에서 서로 다른
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
"name": "astra",
|
"name": "astra",
|
||||||
"displayName": "Astra",
|
"displayName": "Astra",
|
||||||
"description": "The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.",
|
"description": "The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.",
|
||||||
"version": "2.1.7",
|
"version": "2.1.8",
|
||||||
"publisher": "g1nation",
|
"publisher": "g1nation",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"icon": "assets/icon.png",
|
"icon": "assets/icon.png",
|
||||||
|
|||||||
+124
-115
@@ -1,65 +1,61 @@
|
|||||||
/**
|
/**
|
||||||
* The 9-agent roster for 1인 기업 모드.
|
* 기본 에이전트 로스터 — 1인 기업 모드의 출고 디폴트.
|
||||||
*
|
*
|
||||||
* Each entry is a *static* description — persona, role, specialty — used to
|
* 설계 의도: 제품 개발 파이프라인(기획 → 디자인 → 개발 → QA → 출시 → 마케팅 → 회고)을
|
||||||
* build the specialist's system prompt at dispatch time. The set was adopted
|
* 한 사람이 1인 기업으로 운영할 때 필요한 직군을 모두 커버한다. 각 에이전트는
|
||||||
* from Connect_origin's `src/agents.ts` and pruned to focus on the personas
|
* - `name` — 직군에 어울리는 한국식 닉네임
|
||||||
* + specialties; per-machine state (active flag, model override) is kept
|
* - `role` — 한국어 정식 직함 (어떤 일을 하는 사람인지)
|
||||||
* separately in `CompanyState` so the roster itself stays code-shaped and
|
* - `tagline` — 한 줄 자기소개 (UI 카드에 노출)
|
||||||
* easy to review.
|
* - `specialty` — CEO가 사용자의 요청을 어떤 에이전트에게 보낼지 매칭하는 키워드 묶음
|
||||||
*
|
* - `persona` — 답변의 톤·문체 가이드 (선택)
|
||||||
* Editing rules:
|
* 을 가진다. id는 안정 키이므로 절대 변경 금지 (state 마이그레이션 없이는).
|
||||||
* - `id` is a stable key — change only with a migration plan.
|
|
||||||
* - `persona` is *optional*. When set it nudges the agent's voice but
|
|
||||||
* never overrides the system prompt's core rules (file/command tags,
|
|
||||||
* output format).
|
|
||||||
* - Keep `specialty` task-oriented (verbs + nouns), not adjective-heavy —
|
|
||||||
* the CEO planner matches user keywords against it.
|
|
||||||
*/
|
*/
|
||||||
import { CompanyAgentDef } from './types';
|
import { CompanyAgentDef } from './types';
|
||||||
|
|
||||||
export const COMPANY_AGENTS: Record<string, CompanyAgentDef> = {
|
export const COMPANY_AGENTS: Record<string, CompanyAgentDef> = {
|
||||||
ceo: {
|
ceo: {
|
||||||
id: 'ceo',
|
id: 'ceo',
|
||||||
name: 'CEO',
|
name: '대표',
|
||||||
role: 'Chief Executive Agent',
|
role: '최고 의사결정자 · CEO',
|
||||||
emoji: '🧭',
|
emoji: '🧭',
|
||||||
color: '#F8FAFC',
|
color: '#F8FAFC',
|
||||||
specialty: '오케스트레이션, 작업 분해, 종합 판단, 다음 액션 결정',
|
specialty: '오케스트레이션, 작업 분해, 우선순위 판단, 다음 액션 결정, 에이전트 분배',
|
||||||
tagline: '회사 전체 의사결정과 작업 분배를 맡습니다',
|
tagline: '회사 전체의 방향과 우선순위를 정하고 일을 나눕니다',
|
||||||
roleCategory: 'ceo',
|
roleCategory: 'ceo',
|
||||||
alwaysOn: true,
|
alwaysOn: true,
|
||||||
},
|
},
|
||||||
youtube: {
|
business: {
|
||||||
id: 'youtube',
|
id: 'business',
|
||||||
name: '레오',
|
name: '도윤',
|
||||||
role: 'Head of YouTube',
|
role: '프로덕트 매니저 · PM',
|
||||||
emoji: '📺',
|
emoji: '🎯',
|
||||||
color: '#FF4444',
|
color: '#F5C518',
|
||||||
specialty: '유튜브 채널 운영, 영상 기획서(제목·후크·구조), 트렌드 분석, 썸네일 브리프, 업로드 메타데이터, 시청자 유지율 전략',
|
specialty: '제품 요구사항 정의(PRD), 기능 우선순위, 사용자 스토리, KPI/OKR 설계, 로드맵, 비즈니스 가치 평가, 이해관계자 정렬',
|
||||||
tagline: '유튜브 채널 기획·운영 전반을 책임집니다',
|
tagline: '기능 우선순위와 출시 로드맵을 잡습니다',
|
||||||
roleCategory: 'planner',
|
roleCategory: 'planner',
|
||||||
persona: '데이터 중심·솔직·자신감 있는 톤. 결론을 먼저 말한 뒤 데이터 근거로 뒷받침. 추측보다 숫자. 가끔 직설적이지만 따뜻함은 잃지 않음. 이모지는 자제하되 "🔥"·"📊"·"🎯" 같은 핵심 강조용은 OK.',
|
persona: '제품 사고가 강한 PM. "이 기능을 왜 만들죠?"·"누구의 어떤 문제를 푸나요?"부터 묻고, 가설·성공 지표·범위를 명확히 정의. 결정은 데이터·사용자 인사이트로 뒷받침. 톤은 차분하고 명료하며 불확실성은 솔직히 명시. 이모지는 🎯·📊·🧭 정도만.',
|
||||||
},
|
},
|
||||||
instagram: {
|
researcher: {
|
||||||
id: 'instagram',
|
id: 'researcher',
|
||||||
name: 'Instagram',
|
name: '유진',
|
||||||
role: 'Head of Instagram',
|
role: 'UX 리서처 · 데이터 분석가',
|
||||||
emoji: '📷',
|
emoji: '🔍',
|
||||||
color: '#E1306C',
|
color: '#60A5FA',
|
||||||
specialty: '인스타그램 릴스/피드 콘셉트, 캡션, 해시태그 전략, 게시 시간, 스토리, 팔로워 인게이지먼트',
|
specialty: '사용자 인터뷰 가이드, 설문 설계, 경쟁사·시장 분석, 사용성 테스트 시나리오, 데이터 수집·요약, 인사이트 추출, 사실 확인·인용 정리',
|
||||||
tagline: '인스타 콘텐츠 기획과 인게이지먼트를 끌어올립니다',
|
tagline: '사용자와 시장의 진짜 모습을 찾아냅니다',
|
||||||
roleCategory: 'planner',
|
roleCategory: 'researcher',
|
||||||
|
persona: '근거를 따지는 분석가. "체감"·"느낌"보다는 표본 크기·신뢰구간·인용 출처를 먼저 묻고 답합니다. 모르는 건 모른다고 명시. 발견 사항은 "근거 → 해석 → 시사점" 3단으로 정리. 이모지는 🔍·📊·🧪 정도.',
|
||||||
},
|
},
|
||||||
designer: {
|
designer: {
|
||||||
id: 'designer',
|
id: 'designer',
|
||||||
name: 'Designer',
|
name: '다온',
|
||||||
role: 'Lead Designer',
|
role: '프로덕트 디자이너 · UX/UI 리드',
|
||||||
emoji: '🎨',
|
emoji: '🎨',
|
||||||
color: '#A78BFA',
|
color: '#A78BFA',
|
||||||
specialty: '브랜드 디자인 브리프(컬러·타이포·레퍼런스), 썸네일 컨셉 3안, 비주얼 시스템, 디자인 가이드',
|
specialty: '정보구조(IA), 사용자 흐름(UX flow), 와이어프레임, UI 디자인 시안 3안, 디자인 시스템(컬러·타이포·컴포넌트), 인터랙션 가이드, 접근성 체크리스트',
|
||||||
tagline: '브랜드와 시각 자산 디자인을 담당합니다',
|
tagline: '사용자 흐름과 화면을 설계합니다',
|
||||||
roleCategory: 'designer',
|
roleCategory: 'designer',
|
||||||
|
persona: '사용자 관점에서 흐름을 먼저 잡는 디자이너. "이 화면에서 사용자가 다음에 뭘 해야 하나요?"·"이 정보가 여기 있어야 하는 이유는?"을 항상 검증. 시안은 항상 3안 이상 제시하고 trade-off 명시. 톤은 따뜻하지만 비주얼 디테일은 깐깐. 이모지는 🎨·✨·🖼 정도.',
|
||||||
},
|
},
|
||||||
developer: {
|
developer: {
|
||||||
id: 'developer',
|
id: 'developer',
|
||||||
@@ -67,106 +63,119 @@ export const COMPANY_AGENTS: Record<string, CompanyAgentDef> = {
|
|||||||
role: '시니어 풀스택 엔지니어',
|
role: '시니어 풀스택 엔지니어',
|
||||||
emoji: '💻',
|
emoji: '💻',
|
||||||
color: '#22D3EE',
|
color: '#22D3EE',
|
||||||
specialty: '코드 작성·편집·디버깅, 자동화 스크립트, API 통합, 웹사이트/봇, 데이터 파이프라인, git 워크플로, 자기 검증 루프',
|
specialty: '기능 구현(프론트엔드·백엔드·API), 데이터 모델링, 자동화 스크립트, 디버깅, 코드 리뷰, 리팩토링, 테스트 작성, CI/배포 파이프라인, git 워크플로, 보안·성능 검토',
|
||||||
tagline: '읽고·생각하고·짜고·검증한다 — 시니어 엔지니어',
|
tagline: '읽고·생각하고·짜고·검증하는 시니어 엔지니어',
|
||||||
roleCategory: 'developer',
|
roleCategory: 'developer',
|
||||||
persona: '시니어 풀스택 엔지니어. 코드 한 줄도 그냥 안 넘김. "왜?·어떻게?·이게 깨지나?" 늘 묻고 검증. 친근하지만 프로페셔널 톤. "확인 후 진행할게요"·"테스트 통과 확인했어요" 같은 책임감 있는 표현. 이모지는 💻·⚙️·🔧·✅·🐛 정도만.',
|
persona: '시니어 풀스택 엔지니어. 코드 한 줄도 그냥 안 넘김. "왜?·어떻게?·이게 깨지나?"를 늘 묻고 검증. 친근하지만 프로페셔널 톤. "확인 후 진행할게요"·"테스트 통과 확인했어요" 같은 책임감 있는 표현. 보안·예외처리·에러 케이스를 먼저 떠올림. 이모지는 💻·⚙️·🔧·✅·🐛 정도만.',
|
||||||
},
|
},
|
||||||
business: {
|
|
||||||
id: 'business',
|
|
||||||
name: '현빈',
|
|
||||||
role: '비즈니스 전략가 · Head of Business',
|
|
||||||
emoji: '💼',
|
|
||||||
color: '#F5C518',
|
|
||||||
specialty: '수익화 모델, 가격 전략, 시장·경쟁 분석, ROI/KPI 설계, 비즈니스 의사결정',
|
|
||||||
tagline: '수익화·가격·전략 의사결정을 같이 봅니다',
|
|
||||||
roleCategory: 'inspector',
|
|
||||||
},
|
|
||||||
secretary: {
|
|
||||||
id: 'secretary',
|
|
||||||
name: '영숙',
|
|
||||||
role: '비서 · Personal Assistant',
|
|
||||||
emoji: '📱',
|
|
||||||
color: '#84CC16',
|
|
||||||
specialty: '일정·할 일 관리, 다른 에이전트 작업 요약·보고, 데일리 브리핑, 알림',
|
|
||||||
tagline: '일정·할 일·연락을 챙기고 소통을 정리합니다',
|
|
||||||
roleCategory: 'support',
|
|
||||||
persona: '친근하고 정중한 톤. 짧고 정리된 문장. 이모지 적당히 (😊·📅·✅ 정도). 보고할 땐 한눈에 보이게 불릿 포인트 + 핵심만.',
|
|
||||||
},
|
|
||||||
editor: {
|
|
||||||
id: 'editor',
|
|
||||||
name: '루나',
|
|
||||||
role: 'Sound Director & Composer',
|
|
||||||
emoji: '🎵',
|
|
||||||
color: '#F472B6',
|
|
||||||
specialty: '영상 BGM 기획, 사운드 디자인, 영상-음악 매칭, 자막·타이틀 동기화 가이드',
|
|
||||||
tagline: '영상의 톤에 맞는 사운드 방향을 잡습니다',
|
|
||||||
roleCategory: 'designer',
|
|
||||||
persona: '음악·사운드 감각이 좋고 영상의 톤을 한 마디로 잡아냄. "이 영상은 [장르/분위기]가 어울릴 것 같아요" 식으로 제안. BPM·키·길이를 정확히 표기. 데이터 중심이지만 창작자 감수성도 있음. 이모지는 🎵·🎼·🎚 정도만.',
|
|
||||||
},
|
|
||||||
writer: {
|
|
||||||
id: 'writer',
|
|
||||||
name: 'Writer',
|
|
||||||
role: 'Copywriter',
|
|
||||||
emoji: '✍️',
|
|
||||||
color: '#FBBF24',
|
|
||||||
specialty: '카피라이팅, 영상 스크립트 초안, 인스타 캡션, 블로그 글, 메일 톤앤매너, 후크 작성',
|
|
||||||
tagline: '카피·스크립트·후크를 글로 풀어냅니다',
|
|
||||||
roleCategory: 'planner',
|
|
||||||
},
|
|
||||||
researcher: {
|
|
||||||
id: 'researcher',
|
|
||||||
name: 'Researcher',
|
|
||||||
role: 'Trend & Data Researcher',
|
|
||||||
emoji: '🔍',
|
|
||||||
color: '#60A5FA',
|
|
||||||
specialty: '트렌드 리서치, 경쟁사 분석, 데이터 수집·요약, 인용 자료 정리, 사실 확인',
|
|
||||||
tagline: '트렌드와 데이터를 모아 사실 확인까지 끝냅니다',
|
|
||||||
roleCategory: 'researcher',
|
|
||||||
},
|
|
||||||
// ── 신규 직군 에이전트 ──
|
|
||||||
// QA·Inspector 직군이 없으면 사용자가 "기획 → 개발 → QA" 파이프라인을
|
|
||||||
// 처음부터 만들 수 없어서 onboarding이 막힌다. 코드로 같이 동봉.
|
|
||||||
qa: {
|
qa: {
|
||||||
id: 'qa',
|
id: 'qa',
|
||||||
name: '재훈',
|
name: '재훈',
|
||||||
role: 'QA 엔지니어',
|
role: 'QA 엔지니어 · 품질 검증',
|
||||||
emoji: '🧪',
|
emoji: '🧪',
|
||||||
color: '#10B981',
|
color: '#10B981',
|
||||||
specialty: '기능 테스트 시나리오 작성, 버그 재현·기록, 회귀 테스트, 엣지 케이스 발굴, 통과/실패 명확히 보고',
|
specialty: '테스트 시나리오 작성(해피·엣지·실패), 회귀 테스트, 버그 재현 절차 기록, 통과/실패 기준 정의, 디바이스·브라우저 매트릭스 점검, 자동화 테스트 우선순위 추천',
|
||||||
tagline: '기능 검증과 버그 발굴을 담당합니다',
|
tagline: '기능 검증과 버그 발굴을 담당합니다',
|
||||||
roleCategory: 'qa',
|
roleCategory: 'qa',
|
||||||
persona: '꼼꼼하고 의심 많은 톤. "정상 동작합니다" 같은 모호한 표현 대신 "케이스 A: ✅ / 케이스 B: ❌ (재현 방법: ...)" 식의 검증 가능한 결론. 버그가 있으면 반드시 "❌ 버그 발견:"으로 시작 — loop-back regex가 잡을 수 있게.',
|
persona: '꼼꼼하고 의심 많은 톤. "정상 동작합니다" 같은 모호한 표현 대신 "케이스 A: ✅ / 케이스 B: ❌ (재현: 1.클릭 → 2.…)" 식의 검증 가능한 결론. 버그가 있으면 반드시 "❌ 버그 발견:"으로 시작 — loop-back regex가 잡을 수 있게. 이모지는 🧪·🐞·✅·❌ 정도.',
|
||||||
},
|
},
|
||||||
inspector: {
|
inspector: {
|
||||||
id: 'inspector',
|
id: 'inspector',
|
||||||
name: '민지',
|
name: '민지',
|
||||||
role: '기획·산출물 감리',
|
role: '프로덕트 감리 · 회고',
|
||||||
emoji: '🔎',
|
emoji: '🔎',
|
||||||
color: '#EF4444',
|
color: '#EF4444',
|
||||||
specialty: '기획서 검토, 요구사항 대비 산출물 정합성 확인, 누락된 케이스 지적, 최종 승인 또는 재작업 요청',
|
specialty: '기획서 검토, 요구사항 대비 산출물 정합성, 누락 케이스 지적, 출시 준비도 체크리스트, 출시 후 회고 진행, 다음 사이클 개선 제안',
|
||||||
tagline: '기획 의도와 산출물의 일치 여부를 감리합니다',
|
tagline: '기획 의도와 산출물이 일치하는지 감리합니다',
|
||||||
roleCategory: 'inspector',
|
roleCategory: 'inspector',
|
||||||
persona: '깐깐하지만 건설적인 톤. 무엇이 좋고 무엇이 부족한지 명확히 구분. 결론을 "✅ 승인" 또는 "❌ 재작업 필요: ..."로 명시 — loop-back regex가 잡을 수 있게. 사장님(사용자)이 시간 낭비 안 하게 핵심만.',
|
persona: '깐깐하지만 건설적인 톤. 무엇이 좋고 무엇이 부족한지 명확히 구분. 결론을 "✅ 승인" 또는 "❌ 재작업 필요: …"로 명시 — loop-back regex가 잡을 수 있게. 사장님(사용자)이 시간 낭비 안 하도록 핵심만. 이모지는 🔎·✅·❌ 정도.',
|
||||||
|
},
|
||||||
|
secretary: {
|
||||||
|
id: 'secretary',
|
||||||
|
name: '영숙',
|
||||||
|
role: '오퍼레이션 매니저 · 일정·소통',
|
||||||
|
emoji: '📅',
|
||||||
|
color: '#84CC16',
|
||||||
|
specialty: '일정·할 일 관리, 데일리 브리핑, 다른 에이전트 산출물 요약·보고, 회의 노트 정리, 알림·리마인더, 외부 연락 초안',
|
||||||
|
tagline: '일정·할 일·소통을 정리하고 챙깁니다',
|
||||||
|
roleCategory: 'support',
|
||||||
|
persona: '친근하고 정중한 톤. 짧고 정리된 문장. 보고할 때는 한눈에 보이게 불릿 + 핵심만. 이모지는 😊·📅·✅ 정도.',
|
||||||
|
},
|
||||||
|
writer: {
|
||||||
|
id: 'writer',
|
||||||
|
name: '글봄',
|
||||||
|
role: '테크니컬 라이터 · 카피라이터',
|
||||||
|
emoji: '✍️',
|
||||||
|
color: '#FBBF24',
|
||||||
|
specialty: 'UX 마이크로카피, 출시 공지·체인지로그·릴리스 노트, 사용자 가이드·도움말, 마케팅 카피·후크, 블로그 글 초안, 메일 톤앤매너, 영상 스크립트',
|
||||||
|
tagline: '제품과 사용자 사이의 모든 글을 씁니다',
|
||||||
|
roleCategory: 'planner',
|
||||||
|
persona: '간결·정확·따뜻함을 동시에 잡는 톤. 한 문장에 한 가지 메시지. 어려운 용어는 사용자 언어로 번역. 카피는 "사용자가 다음에 뭘 해야 하는가"를 명확히. 이모지 자제, 강조용으로 가끔.',
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
id: 'editor',
|
||||||
|
name: '루나',
|
||||||
|
role: '사운드 디렉터 · 영상 사운드 디자인',
|
||||||
|
emoji: '🎵',
|
||||||
|
color: '#F472B6',
|
||||||
|
specialty: '영상 BGM 기획, UI 사운드 디자인, 영상-음악 매칭, BPM·키·길이 가이드, 자막·타이틀 동기화',
|
||||||
|
tagline: '제품·영상의 톤에 맞는 사운드를 설계합니다',
|
||||||
|
roleCategory: 'designer',
|
||||||
|
persona: '음악·사운드 감각이 좋고 영상의 톤을 한 마디로 잡아냄. "이 영상/UI는 [장르/분위기]가 어울려요" 식으로 제안. BPM·키·길이를 정확히 표기. 데이터 중심이지만 창작자 감수성도 있음. 이모지는 🎵·🎼·🎚 정도.',
|
||||||
|
},
|
||||||
|
youtube: {
|
||||||
|
id: 'youtube',
|
||||||
|
name: '레오',
|
||||||
|
role: 'YouTube 콘텐츠 PD',
|
||||||
|
emoji: '📺',
|
||||||
|
color: '#FF4444',
|
||||||
|
specialty: '유튜브 영상 기획(제목·후크·구조), 썸네일 브리프, 업로드 메타데이터, 시청자 유지율 전략, 트렌드 분석, 시리즈·플레이리스트 설계',
|
||||||
|
tagline: '유튜브 채널 기획·운영 전반을 책임집니다',
|
||||||
|
roleCategory: 'planner',
|
||||||
|
persona: '데이터 중심·솔직·자신감 있는 톤. 결론을 먼저 말한 뒤 데이터 근거로 뒷받침. 추측보다 숫자. 가끔 직설적이지만 따뜻함은 잃지 않음. 이모지는 자제하되 🔥·📊·🎯 같은 핵심 강조용은 OK.',
|
||||||
|
},
|
||||||
|
instagram: {
|
||||||
|
id: 'instagram',
|
||||||
|
name: '아라',
|
||||||
|
role: 'Instagram 콘텐츠 리드',
|
||||||
|
emoji: '📷',
|
||||||
|
color: '#E1306C',
|
||||||
|
specialty: '인스타그램 릴스·피드 콘셉트, 캡션·해시태그 전략, 게시 시간 최적화, 스토리·하이라이트 기획, 팔로워 인게이지먼트 분석',
|
||||||
|
tagline: '인스타 콘텐츠와 인게이지먼트를 끌어올립니다',
|
||||||
|
roleCategory: 'planner',
|
||||||
|
persona: '시각·트렌드 감각이 빠른 콘텐츠 리드. "이 콘셉트는 지금 통합니다·아닙니다"를 짧고 분명하게 말함. 캡션은 후크 → 가치 → CTA 흐름. 이모지 적당히 (📷·✨·💬).',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Display order for the manage panel. CEO first, then specialists. */
|
/** 매니지 패널 표시 순서 — CEO가 맨 앞, 그 뒤로 제품 개발 파이프라인 순서. */
|
||||||
export const COMPANY_AGENT_ORDER: string[] = [
|
export const COMPANY_AGENT_ORDER: string[] = [
|
||||||
'ceo', 'youtube', 'instagram', 'designer', 'developer',
|
'ceo',
|
||||||
'business', 'secretary', 'editor', 'writer', 'researcher',
|
'business', // PM — 기획
|
||||||
'qa', 'inspector',
|
'researcher', // UX 리서치 — 검증
|
||||||
|
'designer', // 디자이너 — 화면 설계
|
||||||
|
'developer', // 엔지니어 — 구현
|
||||||
|
'qa', // QA — 검증
|
||||||
|
'inspector', // 감리·회고
|
||||||
|
'secretary', // 오퍼레이션
|
||||||
|
'writer', // 라이팅
|
||||||
|
'editor', // 사운드 디렉터 (선택 직군)
|
||||||
|
'youtube', // 마케팅 채널
|
||||||
|
'instagram', // 마케팅 채널
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Specialists only (everything except the CEO). */
|
/** Specialists only (everything except the CEO). */
|
||||||
export const COMPANY_SPECIALIST_IDS: string[] = COMPANY_AGENT_ORDER.filter((id) => id !== 'ceo');
|
export const COMPANY_SPECIALIST_IDS: string[] = COMPANY_AGENT_ORDER.filter((id) => id !== 'ceo');
|
||||||
|
|
||||||
/** Default activation set used when a user first opens the company panel.
|
/**
|
||||||
* 포함 기준: 13단계 풀 프로덕트 파이프라인을 그대로 돌릴 수 있는 최소 직군
|
* 처음 1인 기업 모드를 열 때 켜져 있는 디폴트 에이전트.
|
||||||
* 세트. business는 inspector 직군이지만 너무 많이 끼면 작은 모델이
|
*
|
||||||
* 헷갈리므로 빼고, 진짜 감리 역할인 inspector(민지)를 넣는다. */
|
* 기준: 제품 개발 한 사이클(기획 → 디자인 → 개발 → QA → 감리)을 그대로 돌릴 수 있는
|
||||||
|
* 최소 코어. 콘텐츠/마케팅 직군(writer / youtube / instagram / designer_sound)은
|
||||||
|
* 사용자가 필요할 때 직접 켜도록 디폴트는 OFF — 작은 모델이 너무 많은 에이전트에
|
||||||
|
* 한꺼번에 노출되면 매칭이 흔들리기 때문.
|
||||||
|
*/
|
||||||
export const DEFAULT_ACTIVE_AGENTS: string[] = [
|
export const DEFAULT_ACTIVE_AGENTS: string[] = [
|
||||||
'ceo', 'writer', 'researcher', 'designer', 'developer', 'qa', 'inspector',
|
'ceo', 'business', 'researcher', 'designer', 'developer', 'qa', 'inspector',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Lookup helper. Returns `undefined` for unknown ids instead of throwing. */
|
/** Lookup helper. Returns `undefined` for unknown ids instead of throwing. */
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ function _defaultState(): CompanyState {
|
|||||||
displayOverrides: {},
|
displayOverrides: {},
|
||||||
pipelines: {},
|
pipelines: {},
|
||||||
activePipelineId: null,
|
activePipelineId: null,
|
||||||
|
hiddenBuiltinIds: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +280,13 @@ function _normalize(raw: Partial<CompanyState> | undefined): CompanyState {
|
|||||||
&& Object.prototype.hasOwnProperty.call(pipelines, raw.activePipelineId)
|
&& Object.prototype.hasOwnProperty.call(pipelines, raw.activePipelineId)
|
||||||
? raw.activePipelineId
|
? raw.activePipelineId
|
||||||
: null;
|
: null;
|
||||||
|
// 사용자가 "삭제"한 빌트인 에이전트 목록. CEO는 절대 hide할 수 없고, 모르는 id는
|
||||||
|
// drop (예: 코드에서 사라진 옛 에이전트). pipelines 가드는 remove 시점에 적용되므로
|
||||||
|
// 여기서는 별도 정합성 검사를 하지 않음.
|
||||||
|
const hiddenBuiltinIds = Array.isArray(raw.hiddenBuiltinIds)
|
||||||
|
? raw.hiddenBuiltinIds.filter((id): id is string =>
|
||||||
|
typeof id === 'string' && id !== 'ceo' && !!getCompanyAgent(id))
|
||||||
|
: [];
|
||||||
return {
|
return {
|
||||||
enabled, companyName,
|
enabled, companyName,
|
||||||
activeAgentIds: withoutCeo,
|
activeAgentIds: withoutCeo,
|
||||||
@@ -290,6 +298,7 @@ function _normalize(raw: Partial<CompanyState> | undefined): CompanyState {
|
|||||||
displayOverrides,
|
displayOverrides,
|
||||||
pipelines,
|
pipelines,
|
||||||
activePipelineId,
|
activePipelineId,
|
||||||
|
hiddenBuiltinIds,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,25 +475,97 @@ export async function removeCustomAgent(
|
|||||||
context: vscode.ExtensionContext,
|
context: vscode.ExtensionContext,
|
||||||
agentId: string,
|
agentId: string,
|
||||||
): Promise<{ ok: true; state: CompanyState } | { ok: false; reason: string }> {
|
): Promise<{ ok: true; state: CompanyState } | { ok: false; reason: string }> {
|
||||||
if (COMPANY_AGENTS[agentId]) {
|
return removeCompanyAgent(context, agentId);
|
||||||
return { ok: false, reason: '기본 에이전트는 삭제할 수 없습니다.' };
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete *any* agent (built-in or custom). Built-ins can't actually be removed
|
||||||
|
* from the code, so we add them to `hiddenBuiltinIds` — the manage panel and
|
||||||
|
* dispatcher filters both honour that list. Custom agents are removed outright
|
||||||
|
* along with their overrides.
|
||||||
|
*
|
||||||
|
* Guards:
|
||||||
|
* - CEO은 절대 삭제 불가 — 회사 의사결정자 직군이라 항상 필요.
|
||||||
|
* - 어떤 파이프라인 stage라도 이 에이전트를 참조하면 거부. 사용자가 먼저
|
||||||
|
* 파이프라인에서 빼거나 다른 에이전트로 교체해야 함. 메시지에 사용 중인
|
||||||
|
* 파이프라인 이름을 그대로 적어 돌려준다 (사용자가 어디로 가서 고쳐야
|
||||||
|
* 하는지 바로 보이도록).
|
||||||
|
*/
|
||||||
|
export async function removeCompanyAgent(
|
||||||
|
context: vscode.ExtensionContext,
|
||||||
|
agentId: string,
|
||||||
|
): Promise<{ ok: true; state: CompanyState; kind: 'custom-removed' | 'builtin-hidden' } | { ok: false; reason: string }> {
|
||||||
|
if (!agentId) {
|
||||||
|
return { ok: false, reason: '에이전트 ID가 비어 있습니다.' };
|
||||||
|
}
|
||||||
|
if (agentId === 'ceo') {
|
||||||
|
return { ok: false, reason: 'CEO는 회사 의사결정자 직군이라 삭제할 수 없습니다.' };
|
||||||
}
|
}
|
||||||
const cur = readCompanyState(context);
|
const cur = readCompanyState(context);
|
||||||
if (!cur.customAgents || !cur.customAgents[agentId]) {
|
const isBuiltin = !!COMPANY_AGENTS[agentId];
|
||||||
|
const isCustom = !!cur.customAgents?.[agentId];
|
||||||
|
if (!isBuiltin && !isCustom) {
|
||||||
return { ok: false, reason: `'${agentId}' 에이전트를 찾을 수 없습니다.` };
|
return { ok: false, reason: `'${agentId}' 에이전트를 찾을 수 없습니다.` };
|
||||||
}
|
}
|
||||||
const { [agentId]: _gone, ...customAgents } = cur.customAgents;
|
// 파이프라인 사용 검사 — 어디든 한 곳이라도 stage.agentId === agentId면 거부.
|
||||||
|
const usedIn: string[] = [];
|
||||||
|
for (const p of Object.values(cur.pipelines ?? {})) {
|
||||||
|
if (p.stages.some((s) => s.agentId === agentId)) {
|
||||||
|
usedIn.push(p.name || p.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (usedIn.length > 0) {
|
||||||
|
const list = usedIn.map((n) => `'${n}'`).join(', ');
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
reason: `다음 워크 파이프라인에서 사용 중이라 삭제할 수 없습니다: ${list}. 먼저 파이프라인에서 이 에이전트를 빼거나 다른 에이전트로 교체한 뒤 다시 시도하세요.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 공통 override cleanup — 두 경로 모두 동일.
|
||||||
const { [agentId]: _m, ...modelOverrides } = cur.modelOverrides;
|
const { [agentId]: _m, ...modelOverrides } = cur.modelOverrides;
|
||||||
const { [agentId]: _p, ...promptOverrides } = cur.promptOverrides;
|
const { [agentId]: _p, ...promptOverrides } = cur.promptOverrides;
|
||||||
const { [agentId]: _k, ...knowledgeMixOverrides } = cur.knowledgeMixOverrides;
|
const { [agentId]: _k, ...knowledgeMixOverrides } = cur.knowledgeMixOverrides;
|
||||||
const { [agentId]: _r, ...roleCategoryOverrides } = (cur.roleCategoryOverrides ?? {});
|
const { [agentId]: _r, ...roleCategoryOverrides } = (cur.roleCategoryOverrides ?? {});
|
||||||
const { [agentId]: _d, ...displayOverrides } = (cur.displayOverrides ?? {});
|
const { [agentId]: _d, ...displayOverrides } = (cur.displayOverrides ?? {});
|
||||||
const activeAgentIds = cur.activeAgentIds.filter((id) => id !== agentId);
|
const activeAgentIds = cur.activeAgentIds.filter((id) => id !== agentId);
|
||||||
|
|
||||||
|
if (isCustom) {
|
||||||
|
const { [agentId]: _gone, ...customAgents } = (cur.customAgents ?? {});
|
||||||
const next: CompanyState = {
|
const next: CompanyState = {
|
||||||
...cur, customAgents, modelOverrides, promptOverrides, knowledgeMixOverrides,
|
...cur, customAgents, modelOverrides, promptOverrides, knowledgeMixOverrides,
|
||||||
roleCategoryOverrides, displayOverrides, activeAgentIds,
|
roleCategoryOverrides, displayOverrides, activeAgentIds,
|
||||||
};
|
};
|
||||||
await writeCompanyState(context, next);
|
await writeCompanyState(context, next);
|
||||||
|
return { ok: true, state: next, kind: 'custom-removed' };
|
||||||
|
}
|
||||||
|
// Built-in: add to hiddenBuiltinIds (idempotent) and drop overrides.
|
||||||
|
const hidden = new Set(cur.hiddenBuiltinIds ?? []);
|
||||||
|
hidden.add(agentId);
|
||||||
|
const next: CompanyState = {
|
||||||
|
...cur, modelOverrides, promptOverrides, knowledgeMixOverrides,
|
||||||
|
roleCategoryOverrides, displayOverrides, activeAgentIds,
|
||||||
|
hiddenBuiltinIds: Array.from(hidden),
|
||||||
|
};
|
||||||
|
await writeCompanyState(context, next);
|
||||||
|
return { ok: true, state: next, kind: 'builtin-hidden' };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore a previously-hidden built-in agent back into the manage panel.
|
||||||
|
* No-op if the id wasn't hidden. Custom agents have no "restore" — once
|
||||||
|
* deleted they're gone and must be re-created via the add form.
|
||||||
|
*/
|
||||||
|
export async function restoreHiddenAgent(
|
||||||
|
context: vscode.ExtensionContext,
|
||||||
|
agentId: string,
|
||||||
|
): Promise<{ ok: true; state: CompanyState } | { ok: false; reason: string }> {
|
||||||
|
if (!agentId || !COMPANY_AGENTS[agentId]) {
|
||||||
|
return { ok: false, reason: `'${agentId}'은(는) 빌트인 에이전트가 아닙니다.` };
|
||||||
|
}
|
||||||
|
const cur = readCompanyState(context);
|
||||||
|
const hidden = (cur.hiddenBuiltinIds ?? []).filter((id) => id !== agentId);
|
||||||
|
const next: CompanyState = { ...cur, hiddenBuiltinIds: hidden };
|
||||||
|
await writeCompanyState(context, next);
|
||||||
return { ok: true, state: next };
|
return { ok: true, state: next };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ export {
|
|||||||
setAgentKnowledgeMix,
|
setAgentKnowledgeMix,
|
||||||
addCustomAgent,
|
addCustomAgent,
|
||||||
removeCustomAgent,
|
removeCustomAgent,
|
||||||
|
removeCompanyAgent,
|
||||||
|
restoreHiddenAgent,
|
||||||
validateCustomAgentId,
|
validateCustomAgentId,
|
||||||
setAgentRoleCategory,
|
setAgentRoleCategory,
|
||||||
setAgentDisplayOverride,
|
setAgentDisplayOverride,
|
||||||
|
|||||||
@@ -194,6 +194,16 @@ export interface CompanyState {
|
|||||||
* planner path. Must reference a key in `pipelines` or it is ignored.
|
* planner path. Must reference a key in `pipelines` or it is ignored.
|
||||||
*/
|
*/
|
||||||
activePipelineId?: string | null;
|
activePipelineId?: string | null;
|
||||||
|
/**
|
||||||
|
* Built-in agent ids that the user has chosen to hide from the manage
|
||||||
|
* panel. We can't truly delete a code-defined agent, but we can suppress
|
||||||
|
* it from the UI / activation lists so the user perceives the same
|
||||||
|
* "삭제" outcome. The `restoreHiddenAgent` path can put it back.
|
||||||
|
*
|
||||||
|
* Pipeline guards still apply at delete time — an agent referenced by
|
||||||
|
* any pipeline stage cannot be moved into this list.
|
||||||
|
*/
|
||||||
|
hiddenBuiltinIds?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -299,13 +299,32 @@ export async function handleChatMessage(provider: SidebarChatProvider, data: any
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case 'deleteCompanyAgent': {
|
case 'deleteCompanyAgent': {
|
||||||
// Drop a user-defined agent. Built-ins refuse — backend enforces.
|
// Delete any agent (built-in via hide, custom via outright removal).
|
||||||
const { removeCustomAgent } = await import('../features/company');
|
// Backend checks pipeline usage and refuses if any stage references it.
|
||||||
|
const { removeCompanyAgent } = await import('../features/company');
|
||||||
const agentId = typeof data.agentId === 'string' ? data.agentId : '';
|
const agentId = typeof data.agentId === 'string' ? data.agentId : '';
|
||||||
if (!agentId) return true;
|
if (!agentId) return true;
|
||||||
const result = await removeCustomAgent(provider._context, agentId);
|
const result = await removeCompanyAgent(provider._context, agentId);
|
||||||
provider._view?.webview.postMessage({
|
provider._view?.webview.postMessage({
|
||||||
type: 'deleteCompanyAgentResult',
|
type: 'deleteCompanyAgentResult',
|
||||||
|
value: result.ok
|
||||||
|
? { ok: true, agentId, kind: result.kind }
|
||||||
|
: { ok: false, agentId, reason: result.reason },
|
||||||
|
});
|
||||||
|
if (result.ok) {
|
||||||
|
await provider._sendCompanyStatus();
|
||||||
|
await provider._sendCompanyAgents();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 'restoreHiddenAgent': {
|
||||||
|
// Bring a previously-hidden built-in back into the manage panel.
|
||||||
|
const { restoreHiddenAgent } = await import('../features/company');
|
||||||
|
const agentId = typeof data.agentId === 'string' ? data.agentId : '';
|
||||||
|
if (!agentId) return true;
|
||||||
|
const result = await restoreHiddenAgent(provider._context, agentId);
|
||||||
|
provider._view?.webview.postMessage({
|
||||||
|
type: 'restoreHiddenAgentResult',
|
||||||
value: result.ok ? { ok: true, agentId } : { ok: false, reason: result.reason },
|
value: result.ok ? { ok: true, agentId } : { ok: false, reason: result.reason },
|
||||||
});
|
});
|
||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
|
|||||||
+24
-2
@@ -1582,10 +1582,20 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
const globalWeight = cfg.knowledgeMixSecondBrainWeight ?? 50;
|
const globalWeight = cfg.knowledgeMixSecondBrainWeight ?? 50;
|
||||||
// Built-ins first (insertion order from agents.ts), then user-added
|
// Built-ins first (insertion order from agents.ts), then user-added
|
||||||
// customs in their own order. `custom: true` lets the UI render a
|
// customs in their own order. `custom: true` lets the UI render a
|
||||||
// delete button only for user-added entries.
|
// delete button differently for user-added entries.
|
||||||
const builtinIds = COMPANY_AGENT_ORDER.filter((id) => !!COMPANY_AGENTS[id]);
|
const hiddenSet = new Set(state.hiddenBuiltinIds ?? []);
|
||||||
|
const builtinIds = COMPANY_AGENT_ORDER.filter((id) => !!COMPANY_AGENTS[id] && !hiddenSet.has(id));
|
||||||
const customIds = state.customAgents ? Object.keys(state.customAgents) : [];
|
const customIds = state.customAgents ? Object.keys(state.customAgents) : [];
|
||||||
const orderedIds = [...builtinIds, ...customIds];
|
const orderedIds = [...builtinIds, ...customIds];
|
||||||
|
// 파이프라인에서 사용 중인 에이전트 id별로 사용처(파이프라인 이름) 목록을 미리 계산.
|
||||||
|
// 카드의 삭제 버튼 비활성화 + tooltip에 사용 중인 파이프라인 이름을 노출하는 데 사용.
|
||||||
|
const pipelineUsage: Record<string, string[]> = {};
|
||||||
|
for (const p of Object.values(state.pipelines ?? {})) {
|
||||||
|
for (const s of p.stages) {
|
||||||
|
if (!s.agentId) continue;
|
||||||
|
(pipelineUsage[s.agentId] = pipelineUsage[s.agentId] ?? []).push(p.name || p.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
const renderEntry = (id: string) => {
|
const renderEntry = (id: string) => {
|
||||||
const builtin = COMPANY_AGENTS[id];
|
const builtin = COMPANY_AGENTS[id];
|
||||||
const custom = state.customAgents?.[id];
|
const custom = state.customAgents?.[id];
|
||||||
@@ -1635,15 +1645,27 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
|||||||
roleCategoryOverridden: !!roleOverride && roleOverride !== baseDef.roleCategory,
|
roleCategoryOverridden: !!roleOverride && roleOverride !== baseDef.roleCategory,
|
||||||
knowledgeMixOverride: hasKmOverride ? kmOverride : null,
|
knowledgeMixOverride: hasKmOverride ? kmOverride : null,
|
||||||
effectiveKnowledgeMixWeight: hasKmOverride ? kmOverride : globalWeight,
|
effectiveKnowledgeMixWeight: hasKmOverride ? kmOverride : globalWeight,
|
||||||
|
// 파이프라인 사용 현황. 비어 있으면 삭제 가능, 한 개라도 있으면 UI에서
|
||||||
|
// 삭제 버튼을 disabled로 처리하고 tooltip에 사용 중인 파이프라인을 노출.
|
||||||
|
usedInPipelines: pipelineUsage[id] ? [...new Set(pipelineUsage[id])] : [],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const agents = orderedIds.map(renderEntry).filter((x): x is NonNullable<ReturnType<typeof renderEntry>> => !!x);
|
const agents = orderedIds.map(renderEntry).filter((x): x is NonNullable<ReturnType<typeof renderEntry>> => !!x);
|
||||||
|
// 숨김 처리된 빌트인 — 사용자에게 "복원" 옵션을 제공하기 위해 한 줄 메타로 같이 보낸다.
|
||||||
|
const hiddenBuiltins = (state.hiddenBuiltinIds ?? [])
|
||||||
|
.map((id) => {
|
||||||
|
const def = COMPANY_AGENTS[id];
|
||||||
|
if (!def) return null;
|
||||||
|
return { id, name: def.name, role: def.role, emoji: def.emoji };
|
||||||
|
})
|
||||||
|
.filter((x): x is { id: string; name: string; role: string; emoji: string } => !!x);
|
||||||
this._view.webview.postMessage({
|
this._view.webview.postMessage({
|
||||||
type: 'companyAgents',
|
type: 'companyAgents',
|
||||||
value: {
|
value: {
|
||||||
companyName: state.companyName,
|
companyName: state.companyName,
|
||||||
globalKnowledgeMixWeight: globalWeight,
|
globalKnowledgeMixWeight: globalWeight,
|
||||||
agents,
|
agents,
|
||||||
|
hiddenBuiltins,
|
||||||
// 직군 라벨 사전 + 표시 순서. 웹뷰는 enum 값을 모르므로
|
// 직군 라벨 사전 + 표시 순서. 웹뷰는 enum 값을 모르므로
|
||||||
// 백엔드가 정한 라벨/순서를 같이 보내 UI 일관성을 유지.
|
// 백엔드가 정한 라벨/순서를 같이 보내 UI 일관성을 유지.
|
||||||
roleCategoryLabels: ROLE_CATEGORY_LABELS,
|
roleCategoryLabels: ROLE_CATEGORY_LABELS,
|
||||||
|
|||||||
Reference in New Issue
Block a user