feat(core): 자기지식 접지·웹 접근·환경 자가점검 — 할루시네이션 방어 3중화 (v2.2.247)
- Alignment Self-Learning: 자가 조사(질문 전 두뇌 검색)·사용자 답변 두뇌 저장·핵심메시지/프로젝트 컨텍스트 주입 (alignmentResearch.ts 신규)
- 웹 접근: Bridge 폴백 직접 fetch(webFetch.ts 신규)·<fetch_url> 액션 태그·기업 모드 URL/아키텍처 컨텍스트 주입·bare 도메인 인식
- 트리거 버그 수정: startsWith('/') 가 절대경로를 슬래시 명령으로 오인 — 분석 지시·URL 주입 전멸 원인 (회귀 테스트 고정)
- 자기지식 접지: 기능 인벤토리 lazy 재생성·학습 메커니즘 정본 섹션·[인벤토리 대조] 태그 의무화·결정론적 재구현 제안 정정 훅(featureConceptMap.ts 신규)
- 환경 자가점검: HealthCheckMonitor 에 Bridge/두뇌 볼륨/git 자격증명/확장 버전 검사 4종 + readyBar ⚠ 표시
- 두뇌 동기화: 원격 미설정 시 로컬 새로고침 모드·staged 기준 commit 판정·인증 부재 안내
- 기타: outputFormat 기본 markdown(제목 렌더 복구)·레슨/행동제약 truncation 보호 구역 이동·[CONTEXT] 절단 우선순위 재정렬
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
# Alignment Self-Learning 개선 계획 (v2 — 적대적 리뷰 반영)
|
||||
|
||||
## v1 → v2 변경 (리뷰 지적 반영)
|
||||
1. **[❌→해결] webview 렌더링**: 2-C를 "권장"이 아닌 필수 구현으로 격상. 삽입 위치 media/sidebar.js 의 openQuestions 렌더 블록(~1228) 직후. `c.answeredQuestions` 중 자가 조사 marker 필터 후 최대 3건 표시.
|
||||
2. **[❌→해결] selfAnswerQuestions 시스템 프롬프트 전문 명시** (아래 2-A에 추가).
|
||||
3. **[❌→해결] `companyAlignmentKnowledgeSave` package.json 명세 추가** (3-C에 키 이름·기본값·설명 명시).
|
||||
4. **[⚠→해결] contract mutation → 비파괴적 변경**: `analysis.contract`를 직접 mutate하지 않고 spread로 새 객체 생성(`enrichedContract`). 이후 모든 경로(payload·_alignment.set·_runCompanyTurn)에 enriched를 전달.
|
||||
5. **[⚠→해결] 자가 조사 marker 명확화**: `(자가 조사) ` → `(자가 조사로 두뇌에서 확인) ` — dispatcher의 LLM이 사용자 직접 답변과 구분 가능하도록 의미를 텍스트에 내장. formatContractForPrompt 수정 불필요.
|
||||
6. **[⚠→확인완료] 파일 쓰기 권한**: 기존 lessons.ts(line 64, 82)가 이미 fs.writeFileSync로 brain 폴더에 직접 쓰고 있음 — extension host는 로컬 fs 권한 제약 없음. 위험 아님.
|
||||
7. **[⚠→영향없음] alignment 'off' 모드**: 자가 조사는 `_runIntentAlignment` 내부에서만 작동 — alignment 자체가 안 돌면 자가 조사도 비활성. 추가 처리 불필요.
|
||||
|
||||
## 목표
|
||||
1인 기업 모드의 Intent Alignment(요청 분석) 단계가:
|
||||
1. 묻기 전에 **프로젝트 컨텍스트를 먼저 본다** (Phase 1)
|
||||
2. 그래도 비는 항목은 **두뇌를 스스로 검색해 답을 찾는다** (Phase 2)
|
||||
3. 정말 모르는 것만 사용자에게 묻고, **받은 답을 두뇌에 저장**해 다음부터 안 묻는다 (Phase 3)
|
||||
|
||||
## 확인된 코드 사실
|
||||
- `analyzeIntent` 입력(`IntentAnalysisInput`)에 프로젝트/두뇌 정보가 전혀 없음 — [intentAlignment.ts:51-74]
|
||||
- `_buildProjectArchitectureContext()`가 이미 존재, `.astra/project-context/architecture.md`를 16,000자 cap으로 포맷 — [sidebarProvider.ts:1781, architecturePayloads.ts:97]
|
||||
- 분석기 모델은 `companyIntentClassifierModel || defaultModel` (작은 모델) — [sidebarProvider.ts:1942]
|
||||
- 두뇌 검색 빌딩블록: `findBrainFiles`(utils, 5s cache) + `getBrainTokenIndex` + `tokenize/expandQuery/scoreTfIdfPreTokenized` + `extractBestExcerpt` — [retrieval/]
|
||||
- `RetrievalOrchestrator`는 `MemoryManager` 의존이라 alignment에서 직접 쓰기 무거움 → 빌딩블록 직접 조합
|
||||
- webview alignment 카드는 `openQuestions`만 렌더, `answeredQuestions`는 미표시 — [media/sidebar.js:1209]
|
||||
- Lesson 시스템(kind: qa-finding)은 "실수 회피" 용도로 의미가 다름 → **일반 노트로 저장** (lesson frontmatter 사용 안 함)
|
||||
- `analyzeIntent`는 throw하지 않는 패턴 (실패 시 low-conf fallback) — 신규 코드도 동일 패턴 준수
|
||||
- alignment 흐름: `_runIntentAlignment` → `shouldAutoProceedAlignment` 판정 → auto-proceed 또는 카드 표시 → `_handleAlignmentAnswer`(답변 라운드) / `_proceedWithCurrentAlignment`(진행 버튼)
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — 프로젝트 컨텍스트 주입
|
||||
|
||||
### 1-A. `src/features/company/intentAlignment.ts`
|
||||
- `IntentAnalysisInput`에 `projectContext?: string` 추가 (doc comment 포함)
|
||||
- `_buildUserMessage`: projectContext 있으면 블록 추가:
|
||||
```
|
||||
[프로젝트 컨텍스트 — 현재 워크스페이스에서 자동 수집]
|
||||
아래는 현재 열려 있는 프로젝트의 아키텍처 요약입니다. 여기서 직접 확인되는
|
||||
사실(프로젝트가 무엇인지·기술 스택·구조)은 이미 알려진 정보로 취급해 context
|
||||
슬롯에 반영하고, openQuestions에 다시 넣지 마세요.
|
||||
---
|
||||
<내용>
|
||||
---
|
||||
```
|
||||
- `SYSTEM_PROMPT`에 규칙 1줄 추가: "[프로젝트 컨텍스트] 블록이 있으면 그 내용으로 context를 채우고, 거기서 답이 확인되는 질문은 openQuestions에 만들지 마세요."
|
||||
|
||||
### 1-B. `src/sidebarProvider.ts` `_runIntentAlignment`
|
||||
- 첫 라운드만(`!opts.previousContract`) — priorChatSummary와 동일 패턴:
|
||||
```ts
|
||||
let projectContext: string | undefined;
|
||||
if (!opts.previousContract) {
|
||||
try {
|
||||
const arch = this._buildProjectArchitectureContext();
|
||||
if (arch) {
|
||||
projectContext = arch.length > 3000
|
||||
? arch.slice(0, 3000) + '\n…(이하 생략 — 전체는 architecture.md 참조)'
|
||||
: arch;
|
||||
}
|
||||
} catch { /* alignment는 계속 */ }
|
||||
}
|
||||
```
|
||||
- `analyzeIntent` 입력에 `projectContext` 전달
|
||||
- 주의: architecture detach(autoAttach=false) 사용자는 빈 문자열 → Phase 1 효과 없음 (의도된 동작)
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — 자가 조사(Self-Research) 패스
|
||||
|
||||
### 2-A. 신규 `src/features/company/alignmentResearch.ts`
|
||||
```ts
|
||||
export const SELF_RESEARCH_PREFIX = '(자가 조사) ';
|
||||
|
||||
export interface QuestionEvidence {
|
||||
question: string;
|
||||
excerpts: Array<{ title: string; relativePath: string; excerpt: string }>;
|
||||
}
|
||||
|
||||
// 두뇌 TF-IDF 검색 — 질문별 top 2 파일에서 발췌. 전체 합계 4,000자 cap.
|
||||
// brainPath 없음/빈 두뇌/에러 → 빈 excerpts (throw 금지)
|
||||
export function gatherEvidenceForQuestions(
|
||||
brainPath: string,
|
||||
questions: string[],
|
||||
): QuestionEvidence[]
|
||||
|
||||
// LLM 1회 호출 — 근거만으로 답할 수 있는 질문 판별.
|
||||
// JSON: { answers: [{ question, status: 'answered'|'unanswered', answer }] }
|
||||
// 4-stage 관용 파서 (intentAlignment 패턴 복제). 실패 시 전원 unanswered.
|
||||
export async function selfAnswerQuestions(
|
||||
ai: IAIService,
|
||||
input: { userPrompt: string; evidence: QuestionEvidence[]; model?: string },
|
||||
): Promise<Array<{ question: string; answered: boolean; answer: string }>>
|
||||
```
|
||||
|
||||
### 2-B. `_runIntentAlignment` 통합 (순서 변경 포함)
|
||||
analyzeIntent 직후, `shouldAutoProceedAlignment` 판정 **전에** 삽입:
|
||||
```ts
|
||||
const contract = analysis.contract;
|
||||
const reachedLimit = opts.roundsAsked >= opts.roundsLimit;
|
||||
|
||||
// ── 자가 조사: 사용자에게 묻기 전에 두뇌에서 스스로 답 찾기 ──
|
||||
if (cfg.companyAlignmentSelfResearch !== false
|
||||
&& contract.openQuestions.length > 0 && !reachedLimit) {
|
||||
try {
|
||||
const brain = getActiveBrainProfile();
|
||||
const evidence = gatherEvidenceForQuestions(brain.localBrainPath, contract.openQuestions);
|
||||
if (evidence.some((e) => e.excerpts.length > 0)) {
|
||||
const answers = await selfAnswerQuestions(new AIService(), {
|
||||
userPrompt: opts.userPrompt, evidence,
|
||||
model: cfg.companyIntentClassifierModel || cfg.defaultModel,
|
||||
});
|
||||
const solved = answers.filter((a) => a.answered && a.answer.trim());
|
||||
if (solved.length > 0) {
|
||||
const solvedSet = new Set(solved.map((s) => s.question));
|
||||
contract.answeredQuestions.push(
|
||||
...solved.map((s) => ({ q: s.question, a: SELF_RESEARCH_PREFIX + s.answer })));
|
||||
contract.openQuestions = contract.openQuestions.filter((q) => !solvedSet.has(q));
|
||||
// pixelOffice 로그
|
||||
}
|
||||
}
|
||||
} catch { /* 실패해도 원래 질문 그대로 진행 */ }
|
||||
}
|
||||
|
||||
if (shouldAutoProceedAlignment(...)) { ... } // 기존 흐름 — openQuestions가 비면 자연히 confirm/진행
|
||||
```
|
||||
- 라운드 카운트 소비 없음 (사용자 응답이 아니므로)
|
||||
- latency: 질문 있을 때만 LLM 1회 추가
|
||||
|
||||
### 2-C. webview `media/sidebar.js` (line ~1209 부근)
|
||||
- `answeredQuestions` 중 `(자가 조사)` prefix 항목이 있으면 카드에 소섹션 추가:
|
||||
"🔎 스스로 확인한 정보" + q/a 목록 (최대 3건, a는 150자 cap)
|
||||
|
||||
### 2-D. config
|
||||
- `src/config.ts`: `companyAlignmentSelfResearch: boolean` (default true) — 기존 company* 키 패턴
|
||||
- `package.json`: `g1nation.company.alignmentSelfResearch` boolean default true + 설명
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — 지식 요청 답변의 두뇌 저장 (학습 루프 완성)
|
||||
|
||||
### 3-A. `alignmentResearch.ts`에 추가
|
||||
```ts
|
||||
// 사용자가 직접 답한 Q/A만 (SELF_RESEARCH_PREFIX 제외, a.length >= 20)
|
||||
// 저장: <brain>/Alignment Knowledge/YYYY-MM-DD <slug30>.md (일반 노트, frontmatter 없음)
|
||||
// 동일 경로 존재 시 skip (중복 방지). 반환: 저장 경로 | null. throw 금지.
|
||||
export function saveAlignmentKnowledge(
|
||||
brainPath: string,
|
||||
input: { userPrompt: string; qaList: Array<{ q: string; a: string }> },
|
||||
): string | null
|
||||
```
|
||||
본문 형식:
|
||||
```md
|
||||
# {userPrompt 앞 50자}
|
||||
|
||||
> 1인 기업 모드 Intent Alignment에서 사용자가 직접 제공한 정보. ({date})
|
||||
|
||||
## 원본 요청
|
||||
{userPrompt}
|
||||
|
||||
## 확인된 정보
|
||||
### Q. {q}
|
||||
{a}
|
||||
```
|
||||
|
||||
### 3-B. 트리거 2곳 (fire-and-forget)
|
||||
- `_runIntentAlignment`의 auto-proceed 분기: `_runCompanyTurn` 직전
|
||||
- `_proceedWithCurrentAlignment`: `_runCompanyTurn` 직전
|
||||
- 조건: `cfg.companyAlignmentKnowledgeSave !== false` && 사용자 직접 답변 존재
|
||||
- try/catch + void (alignment 흐름 차단 금지), pixelOffice 로그 "💾 확인된 정보 두뇌 저장"
|
||||
|
||||
### 3-C. config
|
||||
- `companyAlignmentKnowledgeSave: boolean` default true + package.json 노출
|
||||
|
||||
### 효과 (루프 완성)
|
||||
저장된 노트는 일반 brain 노트 → 다음 turn에서 Phase 2 자가 조사가 TF-IDF로 발견 → 같은 질문 재발 시 스스로 해결 → 사용자에게 두 번 묻지 않음.
|
||||
|
||||
---
|
||||
|
||||
## 구현 순서
|
||||
1. intentAlignment.ts (Phase 1-A) — 순수 추가
|
||||
2. alignmentResearch.ts 신규 (2-A + 3-A) — 독립 모듈
|
||||
3. config.ts + package.json (2-D + 3-C)
|
||||
4. sidebarProvider.ts 통합 (1-B + 2-B + 3-B)
|
||||
5. media/sidebar.js (2-C)
|
||||
6. tests/alignmentResearch.test.ts 신규 — 파서 관용성, marker 필터, slug 생성, 저장 skip, 빈 두뇌 안전성
|
||||
7. `npx tsc --noEmit` + `npm test`
|
||||
|
||||
## 리스크 및 완화
|
||||
| 리스크 | 완화 |
|
||||
|---|---|
|
||||
| 작은 모델 토큰 폭주 (arch 16K) | 3,000자 재절단 |
|
||||
| 자가 조사 LLM이 엉뚱한 답을 "answered" 처리 | 프롬프트에 "근거에 명시된 것만, 불확실하면 unanswered" + 근거 출처 표기 |
|
||||
| 두뇌 오염 (자동 저장) | 사용자 직접 답변만, 20자 미만 제외, 전용 폴더, config로 off 가능 |
|
||||
| alignment latency 증가 | 질문 존재 시에만 작동, 검색은 캐시된 인덱스 |
|
||||
| 기존 테스트 파손 | SYSTEM_PROMPT 변경은 순수 추가, 기존 입력 필드 시그니처 유지 |
|
||||
@@ -0,0 +1,102 @@
|
||||
# 웹 접근 + 모드 동등성 수정 계획 (v2 — 적대적 리뷰 + 재검증 반영)
|
||||
|
||||
## v1 → v2 핵심 변화: 근본 원인 재진단
|
||||
|
||||
리뷰 과정에서 **일반 챗에는 URL 주입 기능이 이미 존재**함이 확인됨
|
||||
(`src/lib/contextBuilders/urlContext.ts`, agent.ts:557-569에서 호출).
|
||||
|
||||
### 그런데 왜 실패했나 (정확한 원인)
|
||||
1. **일반 챗**: `buildUrlContext`가 **Datacollect Bridge(127.0.0.1:3002)에 100% 의존**.
|
||||
확장은 Bridge를 자동 시작하지 않음 → Bridge 꺼져 있으면 '접근 실패' 정직 블록
|
||||
→ 모델이 "사이트 방문 불가"라고 답함. (Bridge 추출 실패/JS 렌더링 페이지도 동일)
|
||||
2. **기업 모드**: dispatcher 경로에 URL 주입이 **아예 없음** → 항상 불가.
|
||||
3. 검증 완료된 사실:
|
||||
- `isCasualConversation` 게이트는 40자 초과 프롬프트에 영향 없음 (문제 아님)
|
||||
- `buildRequestHistory`는 internal 메시지를 필터링하지 않음 → internal push가 LLM에 도달
|
||||
- continuation loop 트리거 = "action이 chatHistory를 늘렸는가" (agent.ts:1238) → read_file과 동일 패턴이면 fetch_url도 자동 재분석
|
||||
- `_handleCompanyCasual`은 일반 챗 경로(_handlePrompt)를 타므로 별도 처리 불필요
|
||||
- BASE_SYSTEM_PROMPT/DispatcherDeps를 단언하는 기존 테스트 없음 (안전)
|
||||
|
||||
---
|
||||
|
||||
## 수정 설계 (v2)
|
||||
|
||||
### A. 신규 `src/features/web/webFetch.ts` — Bridge 무관 직접 fetch (vscode 의존 없음)
|
||||
```ts
|
||||
export function extractUrls(text: string, max = 2): string[]
|
||||
// http(s)만, dedupe, trailing 구두점 제거, 슬래시 명령(/...)으로 시작하면 빈 배열
|
||||
|
||||
export interface WebFetchResult { ok: boolean; url: string; title: string; text: string; error?: string }
|
||||
export async function fetchUrlDirect(url: string, opts?: { timeoutMs?: number /*15s*/; maxChars?: number /*20000*/ }): Promise<WebFetchResult>
|
||||
// global fetch (bridgeClient가 이미 사용 — 호스트 지원 확인됨) + typeof 가드
|
||||
// AbortController timeout / html이면 script·style·noscript 제거 → 태그 strip →
|
||||
// 엔티티 최소 디코드 → 공백 정리 + <title> 추출 / html 아니면 raw cap / throw 금지
|
||||
```
|
||||
|
||||
### B. `urlContext.ts` 개선 — Bridge → 직접 fetch 폴백 (기존 인터페이스 유지)
|
||||
- `buildUrlContext(url)`: ① Bridge `/api/web-extract` 시도 (타임아웃 45s→**15s** 단축)
|
||||
→ ② 실패/빈 본문이면 `fetchUrlDirect` 폴백 → ③ 둘 다 실패 시 기존 정직 블록
|
||||
- **모듈 레벨 TTL 캐시** (URL→블록, 5분, 최대 10개) — chat/alignment/dispatcher가
|
||||
같은 URL을 연달아 요청해도 네트워크 1회
|
||||
- `extractUrlFromPrompt`는 유지하되 호출부는 `extractUrls`(최대 2개)로 확장
|
||||
- 실패 안내 문구에서 "브리지 실행 확인" → "직접 접속도 실패" 반영
|
||||
|
||||
### C. `<fetch_url>` 액션 태그 (LLM 주도 — 양 모드 광고)
|
||||
- 신규 `src/agent/actions/webFetch.ts`: `<fetch_url url="..."/>` (회당 최대 2개)
|
||||
- fileDeleteRead.ts의 read_file 패턴 복제: regex → `buildUrlContext(url)` →
|
||||
`ctx.report.push('🌐 Fetched: <url>')` + `ctx.chatHistory.push({role:'system', internal:true})`
|
||||
- chatHistory push → 일반 챗 continuation loop 자동 트리거 (검증됨)
|
||||
- transactionManager 불필요 (read-only)
|
||||
- agent.ts `executeActions`에 `applyWebFetchActions(ctx)` 등록 (listFiles 다음)
|
||||
- `utils.ts` BASE_SYSTEM_PROMPT: [ACTION 15: FETCH URL] — 라인 401 부근, 기존 포맷 준수
|
||||
("링크의 실제 내용이 필요할 때만, 일반 지식 질문에는 사용 금지" 지침 포함)
|
||||
- `promptBuilder.ts` specialist 액션 목록(129-142)에 fetch_url 추가
|
||||
|
||||
### D. 기업 모드 — DispatcherDeps에 **2개 별도 필드** (리뷰 권고 반영)
|
||||
```ts
|
||||
// dispatcher.ts DispatcherDeps에 추가:
|
||||
architectureContextBlock?: string; // 현재 워크스페이스 아키텍처 (문제 2 해소)
|
||||
webContextBlock?: string; // 사용자 프롬프트 URL pre-fetch 결과
|
||||
```
|
||||
- 4개 합성 지점(planner ~358, specialist ~671, verifier ~699, inspector/CEO ~1053)에서:
|
||||
```ts
|
||||
const prefix = [deps.architectureContextBlock, deps.webContextBlock, contract...]
|
||||
.filter(Boolean).join('\n\n');
|
||||
```
|
||||
contract **앞에** 배치 (둘 다 optional — 미전달 시 기존 동작 100% 동일)
|
||||
- `_runCompanyTurn`(sidebarProvider:2189) deps 빌드 시:
|
||||
- `architectureContextBlock` = `this._buildProjectArchitectureContext()` 6,000자 절단
|
||||
- `webContextBlock` = `extractUrls(userPrompt)` → `buildUrlContext` (캐시 적중) → 8,000자 cap
|
||||
- 빌드는 try/catch — 실패해도 turn 진행
|
||||
|
||||
### E. Alignment 웹 컨텍스트
|
||||
- `_runIntentAlignment` 첫 라운드: URL 있으면 `buildUrlContext`(캐시) 결과를
|
||||
기존 `projectContext` 입력에 append (합계 3,000자 cap 유지 — web 부분은 별도 2,000자 cap 후 합산이 아니라, arch 먼저 + web 이어붙이고 총 5,000자로 상향)
|
||||
- 효과: "그 사이트가 뭐냐"는 alignment 질문 차단
|
||||
|
||||
### F. config + package.json
|
||||
- `webAutoFetchEnabled: boolean` 기본 true — `g1nation.web.autoFetchUrls`
|
||||
(pre-fetch 게이트: 일반 챗 주입부 + _runCompanyTurn + alignment 모두 이 키 확인.
|
||||
기존 일반 챗 주입부에도 게이트 추가 — 현재는 무조건 실행)
|
||||
|
||||
---
|
||||
|
||||
## 구현 순서
|
||||
1. `src/features/web/webFetch.ts` 신규 + `tests/webFetch.test.ts`
|
||||
2. `urlContext.ts` 폴백 + 캐시 + 타임아웃 단축
|
||||
3. config.ts + package.json 키
|
||||
4. `src/agent/actions/webFetch.ts` + agent.ts 등록 + BASE_SYSTEM_PROMPT + promptBuilder
|
||||
5. dispatcher.ts deps 2필드 + 4지점 합성
|
||||
6. sidebarProvider.ts: `_runCompanyTurn` + `_runIntentAlignment`
|
||||
7. agent.ts 일반 챗 주입부: extractUrls(2개) + config 게이트
|
||||
8. `npx tsc --noEmit` + `npm test`
|
||||
|
||||
## 리스크 (v2)
|
||||
| 리스크 | 완화 |
|
||||
|---|---|
|
||||
| Bridge 타임아웃 45→15s 단축으로 느린 추출 실패 ↑ | 직접 fetch 폴백이 받아줌 (총 최대 ~30s) |
|
||||
| EUC-KR 등 비UTF-8 직접 fetch 깨짐 | Bridge 우선 경로가 1차 방어, 한계 문서화 |
|
||||
| 거대 페이지 토큰 폭주 | 직접 20,000자 / 기업 블록 8,000자 / alignment 총 5,000자 cap |
|
||||
| dispatcher 테스트 파손 | 신규 필드 optional — 미전달 시 기존과 동일 |
|
||||
| 캐시 오염 (실패 결과 캐시) | 실패 블록은 캐시하지 않음 — 성공 결과만 TTL 캐시 |
|
||||
| LLM의 fetch_url 남발 | 회당 최대 2개 처리 + "필요할 때만" 프롬프트 지침 |
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"projectId": "connectai",
|
||||
"projectName": "connectai",
|
||||
"projectRoot": "E:\\Wiki\\connectai",
|
||||
"recordRoot": "E:\\Wiki\\connectai\\docs\\records\\connectai",
|
||||
"projectName": "ConnectAI",
|
||||
"projectRoot": "/Volumes/Data/project/Antigravity/ConnectAI",
|
||||
"recordRoot": "/Volumes/Data/project/Antigravity/ConnectAI/docs/records/ConnectAI",
|
||||
"description": "Auto-created by Project Architecture activation.",
|
||||
"corePurpose": "",
|
||||
"detailLevel": "standard",
|
||||
"createdAt": "2026-05-20T09:42:40.003Z",
|
||||
"updatedAt": "2026-06-12T07:39:22.751Z"
|
||||
"createdAt": "2026-05-23T03:51:11.620Z",
|
||||
"updatedAt": "2026-06-12T14:21:27.301Z"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user