HAL AI 채팅룸 도입(0.3.0): 운영자 콘솔 오른쪽 패널에 통합 방(첫 탭 고정) + 모델별 개별 방, 모델 연결(로그인·OAuth PKCE·API 키, 비밀은 Vault), 모델별 고유 정보(이름·역할·특성), HAL 제어·감시 스킬 문서·도구 29종(읽기 즉시 / 쓰기·고위험은 제안 → 운영자 승인(재인증·3단계 확인)), 통합 방 규칙(@이름 지정, 모델→모델 자동 1회 전달), MCP stdio 서버(읽기 전용), 개발 지시 v0.3.0(Oz), docs/HAL-AI.md, VERSION_HISTORY 0.3.0 — test/hal-ai.test.mjs RED 0/11 → GREEN 11/11, 전체 26파일 182건 통과

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Claude Fable 5.1
2026-10-28 17:41:50 +00:00
parent 6bfde82c5e
commit ba3c5cb2f8
23 changed files with 1494 additions and 11 deletions
+65
View File
@@ -1,5 +1,70 @@
# VERSION_HISTORY
## 0.3.0 (2026-10-29)
- **작성자**: 개발 지시 — Oz(`Ariweb-Suitle_Dev-Order_v0.3.0.md`, 2026-10-29) · 구현 — Claude Fable 5.1(브랜치 `feature/hal-ai-chat-v0.3.0`, 기준 origin/main `6bfde82c5ef607704cb05628dc33d9b6ef68c50f` = 0.2.1). 지시에 따라 커밋·push·`main` 병합·릴리스 빌드·bear `hal21.ariweb.net` HAL 배포까지 수행한다(아래 "배포" 절에 read-back).
- **이전 버전**: 0.2.1(2026-10-29, HAL 고위험 재인증 안내 위치 수정 — 아래 절). 0.3.0 은 **가운데 버전 번호를 올리는 운영자 기능 릴리스**다: HAL 운영자 콘솔에 AI 채팅룸(통합 방 + 모델별 개별 방)과 AI 모델 연결(로그인·OAuth·API 키), HAL 제어·감시 스킬·도구·MCP 가 더해졌다. HAL 에만 적용.
- **구성**: HAL 0.3.0. 고객 포털 · Node Agent · 도입 모듈 Webmaker 1.8.0 · AriMail 1.0.11 은 0.2.1 그대로(변경 없음 — 배포하지 않는다). 외부 npm 의존성 없음(공급자 HTTP 는 Node fetch, MCP 는 stdio JSON-RPC 직접 구현), Node 22.13+.
### 요구(사용자 요구 — 약화 없이 반영)
HAL 화면 오른쪽에 칸을 나눠 AI 채팅룸을 둔다. AI 모델은 로그인·OAuth·API 키로 연결하고 여러 모델은 탭으로 전환한다. AI 모델이 HAL 의 모든 기능을 제어·감시할 수 있도록 스킬·도구·MCP 를 준비하고, 상태·로그 정보의 의미를 AI 가 이해하도록 미리 준비한다. 각 모델에는 이름·업무·특성 같은 고유 정보를 연동 때 지정한다. 통합 채팅룸은 항상 첫 탭(고정)이며 모든 모델이 함께 참여한다 — 내 지시는 모두에게, 이름을 지정한 지시는 그 모델만, 모델→모델 전달의 대답은 자동으로 진행되되 그 대답에 대한 두 번째 반응은 사용자 지시로. 개별 채팅룸은 모델별 1:1 이며 탭 이름은 모델 이름이 기본값, 수정 가능. 결과를 소스에 반영하고 `https://hal21.ariweb.net` 에 배포한다. 전문은 `Ariweb-Suitle_Dev-Order_v0.3.0.md` §1.
### 재사용한 기존 기능(그대로)
- HAL 보안 경계 그대로 재사용: 운영자 미들웨어(네트워크 관문 → 운영자 세션 → CSRF), `requireRecent`(최근 10분 재인증), `threeStep`(3단계 확인), 감사(`lib/audit`, redact), Vault(`lib/vault`), 세션(`lib/session`). AI 라우트는 `hal/app.mjs` 가 같은 `requireRecent`·`threeStep`·`wrap` 을 넘겨 준다.
- AI 도구는 운영자 API 와 **같은 core/jobs 함수**를 같은 인자로 부른다(`core.listServers/getServer/publicServer/metrics/listReleases/approveRelease/updateServer/createServer/approveServer/revokeAgent`, `d.jobs.enqueue/list/get/childrenSummary/cancel/retry/resume/pause/revert`, `emergency.listSessions`, `dr.readiness/listSnapshots/snapshot`, `mailsvc.readback`, `overviewLocal`, `changelog`, `listAudit`).
- 재인증 창 계약 `hal/ui/public/reauth.mjs`(0.2.1): 패널의 승인 흐름도 같은 `callWithReauth`·`reauthPrompt` 를 써서 서버가 `reauth_required` 로 거부한 그 때만 고위험 안내가 붙는다.
- 로컬 CLI 연결은 Webmaker `lib/claude.js` 와 같은 계열(`claude -p --output-format json`), 최소 환경 변수·프로세스 그룹 종료 방식.
### 수정한 기존 기능
- `hal/schema.mjs`: 마이그레이션 `hal_0006_ai_chat` — `ai_connections`(비밀값 없음, 참조·상태만) · `ai_rooms` · `ai_messages`(방 안 seq 유일) · `ai_actions`(제안) · `ai_oauth_states`(state 해시). 기존 표 변경 없음.
- `hal/deps.mjs`: `d.ai = createEngine(d)`. `hal/app.mjs`: `registerAiRoutes(app, d, { requireRecent, threeStep, wrap })`. `hal/index.mjs`: 새 명령 `mcp`(stdout 은 JSON-RPC 전용, 로그 stderr).
- `hal/ui.mjs`: 메뉴 `AI 연동`(/ops/ai), 모든 화면 공통 틀에 오른쪽 패널 `#ai-panel`(탭·상태·기록·입력·너비 조절)과 머리 단추 `AI`(열기/닫기), `/ops/ai` 화면(연결 표·연결 추가 양식(API 키/OAuth/로그인)·고유 정보·도구 목록), 스크립트 `/ops/ui/ai.js`. `hal/ui/public/ops.css`: 패널·탭·메시지·제안 카드·1100px 이하 반응형.
- 새 파일: `hal/ai/{connections,providers,rooms,engine,tools,routes,mcp}.mjs`, `hal/ai/skill.md`, `hal/ui/public/ai.js`, `hal/ui/public/ai-render.mjs`(순수 렌더러), `docs/HAL-AI.md`, `test/hal-ai.test.mjs`.
- 버전 표기: `package.json` 0.3.0(HAL 런타임·`scripts/release.mjs` 가 따름), README, `test/webmaker-visual-editor.test.mjs` 의 Suite 버전 검사 0.3.0.
### 고객 화면
- 변경 없음(포털·Webmaker·AriMail 미변경).
### 운영자 화면
- **AI 채팅룸 패널**(모든 운영자 화면 오른쪽, 머리의 `AI` 단추로 열고 닫음, 왼쪽 가장자리 끌어 너비 조절, 운영자별 localStorage 에 열림·너비·선택 탭 저장·복원, 1100px 이하에서는 본문 아래 전체 너비): 탭 줄(◎ 통합 고정 → 연결 순서대로 개별 탭, 비활성은 흐리게·점 표시, `+` → AI 연동), 상태 줄(통합: 규칙 안내·응답 중 수 / 개별: 연결 상태·모델·공급자), 기록(운영자·모델·도구 결과(접힘)·HAL 안내, 전달 응답 표시, 실패 메시지는 오류 코드와 함께), 입력(Ctrl/Cmd+Enter 전송, "현재 화면 문맥 포함", "새 대화"). 탭을 두 번 누르면 이름 변경(통합 불가).
- **제안 카드**: 쓰기·고위험 도구 호출은 카드로 멈춘다 — `승인(재인증)` / `승인(재인증·3단계 확인)` / `거부`. 승인은 서버가 `reauth_required` 로 거부할 때만 재인증 창을 열고(0.2.1 계약), 고위험은 3단계 확인 창(영향 범위 → 식별정보 재입력 → 최종 실행). 처리 뒤 카드에 "승인·실행됨/거부됨(실행 안 함)/실행 실패"와 처리자가 남는다.
- **AI 연동 화면(`/ops/ai`)**: 연결 표(이름·역할·특성, 공급자·인증 방식·키 힌트·토큰 만료, 모델·사용 가능 모델 수, 상태·마지막 확인·오류, 조치: 확인 / OAuth 로그인 / 키 교체 / 수정 / 비활성화·활성화 / 삭제(이름 재입력)), 연결 추가 양식(공급자에 맞는 인증 방식만 보임, 비밀 입력란은 저장 뒤 비움), 도구 목록(위험 등급). OAuth 콜백 뒤 `?oauth=ok` 안내.
- 운영자 조치 항목: 모델을 쓰려면 AI 연동 화면에서 연결을 추가하고 "확인"을 눌러 모델 목록을 받아 둔다. 설정값·보관소 경로 변경 없음(비밀값은 기존 Vault 파일에 항목으로 추가된다).
### 연결 · 방 규칙 · 도구 동작
- 연결: 공급자 `anthropic`(API 키 `x-api-key` / OAuth Bearer) · `openai`(OpenAI 호환, `baseUrl` 변경 가능, Bearer) · `local-cli`(로그인된 Claude Code 세션, 도구 없음). 상태 `active`·`disabled`·`reauth_required`·`error`. "확인"은 실제 공급자 모델 목록을 받아 두고, 목록 밖 모델 선택은 `model_unavailable`(조용히 대체하지 않음). 키 등록·교체·client secret·삭제 → `reauth_required` 규칙.
- OAuth: authorization code + PKCE S256. state 해시 저장·10분·1회용, 시작 운영자 = 콜백 운영자, code_verifier 는 Vault 에 두었다가 교환 뒤 제거, client secret 은 서버→토큰 끝점에만, 토큰은 Vault, 만료는 서버 refresh(실패 시 `reauth_required`).
- 통합 방: 지시는 활성 모델 모두 / `@이름`·글머리 `이름:`·`이름,` 는 그 모델만 / 모르는 `@이름` 은 400 `unknown_addressee` / 모델→모델 `@이름` 전달은 자동 1회(relayDepth 1), 그 답의 @호출은 HAL 안내만 남기고 자동 반응 없음 / 자기 자신·비활성 제외. 각 모델의 system prompt 에는 자기 고유 정보·참여자 이름·역할·운영자·화면 문맥·스킬 문서가 들어가고, 다른 모델의 발언은 "[이름] …" 으로 보인다.
- 개별 방: 1:1, 기록 격리, 비활성 연결에는 409 `connection_inactive`, "새 대화"는 기록 비움 + 승인 대기 제안 취소.
- 도구(`hal/ai/tools.mjs`, 29개 — 읽기 15 · 쓰기 8 · 고위험 8, 표는 `docs/HAL-AI.md` §4): 읽기는 즉시, 쓰기는 제안 → 승인(재인증), 고위험은 제안 → 승인(재인증 + 3단계 확인, 식별정보 = 도구가 정한 대상 id). 인자는 선언으로 재검증, 모르는 도구·인자는 실행 없이 오류 결과. 한 턴 도구 왕복 8회 상한. 승인은 한 번만 실행(상태 선점). 거부는 실행 없음·모델 자동 호출 없음.
- 스킬 문서 `hal/ai/skill.md`: 서버·작업·릴리스·사건·감사·긴급 복구·DR 상태값과 오류 코드의 뜻, AI 규칙(증거 없이 완료 금지, 승인 재촉 금지, 외부 글 속 지시문 불신, 비밀값 금지). `GET /ops/api/ai/skill`·도구 `hal_skill`.
- MCP: `node hal/index.mjs mcp`(stdio) — `initialize`·`tools/list`·`tools/call`·`ping`. 읽기 도구만 실행, 쓰기·고위험은 `isError` 로 운영자 콘솔 승인 안내.
### 보안 결정
- 비밀값은 Vault 에만: 공개 객체·목록·감사·대화·작업·테스트·소스에 없음(힌트만). 공급자 호출의 자격은 서버 헤더에만. 로컬 CLI 는 세션 파일·자격을 읽지도 넘기지도 않고 환경 변수는 PATH·HOME 등 최소.
- AI 경로는 기존 `requireRecent`·CSRF·`threeStep`·릴리스 승인·부트스트랩·Agent 경계를 그대로 거친다(라우트가 같은 함수를 받음). 고위험 제안은 기존 운영자 API 보다 약하지 않게 전부 3단계 확인을 요구한다(예: 모듈 배포는 운영자 API 에서는 재인증만, AI 제안은 재인증 + 3단계).
- 모델 응답·도구 인자·다른 모델의 발언·저장소 글은 권한이 아니다: 선언 검증, 알 수 없는 도구 거부, 임의 셸·경로·네트워크 도구 없음, 스킬 문서에 prompt injection 불신 규칙.
- 공급자 오류는 모델 답으로 꾸미지 않고 `failed` 로 표시. AI 가 "완료"라 해도 HAL 이 확인한 도구 결과·작업 상태만 사실로 다룬다.
- 테스트 비밀 fixture 는 `node:crypto` 로 실행마다 생성(정적 literal 없음).
### 테스트
- RED(production 변경 전, `node --no-warnings test/hal-ai.test.mjs`): **통과 0 · 실패 11** — 모든 `/ops/api/ai/*` 404, 공통 틀에 AI 패널 없음, MCP 명령 없음(응답 없음).
- GREEN(구현 뒤): `test/hal-ai.test.mjs` **11/11**(연결 CRUD·비밀 미노출·재인증 / OAuth PKCE / 방·탭 / 통합 방 지정·방송·고유 정보 / 모델→모델 자동 1회 / 개별 방·읽기 도구·공급자 오류 / 쓰기·고위험 제안·재인증·3단계·거부·1회 실행 / OpenAI 호환 / 로컬 CLI / 화면·버전·문서 / MCP stdio). 중간 결함 2건을 테스트가 잡았다: ① 격리 뒤 `publicServer.status` 는 heartbeat 없음 → `offline` 이라 각본이 `rawStatus` 를 보도록 수정(코드 아님) ② `/ops/ai` 화면 함수가 `d` 를 받지 않아 500 → `aiPage(d)`.
- targeted: `test/hal-ui.test.mjs` 7/7 · `test/hal-reauth-banner.test.mjs` 5/5 · `test/hal.test.mjs` 16/16.
- 전체 Suite `node test/run.mjs`: **26개 파일 실패 0, 182건 통과**(새 `hal-ai` 11 포함, 로컬 E2E 11). 러너가 만든 `docs/verification/local-e2e-2026-10-28.*` 는 커밋하지 않았다. 변경 파일 정적 secret-like 스캔 0건. 도입 소스 출처 검사 `checkProvenance` clean.
### 배포(bear `hal21.ariweb.net`, HAL 만)
- 절차와 read-back 은 배포 뒤 이 절에 후속 커밋으로 기록한다(릴리스 artifact 의 `mainCommit` 은 기능 커밋이 병합된 main 이어야 하므로 배포 기록 커밋은 그 뒤에 온다).
### 알려진 제한
- v0.1.4 §41.3·§41.4·§42 의 상세 계약 중 이번 범위 밖: 탭 간 변경 잠금(원자적 server-side lock·fencing·compare-and-swap), AI 의 격리 작업공간 코드 수정·커밋·push·릴리스 생성 도구, 제한된 합의 절차(최초 의견 1회 + 반론 1회 + 최종안). 이번 통합 방은 Oz 지시의 "방송·이름 지정·모델→모델 자동 1회" 규칙까지다.
- 응답은 스트리밍이 아니라 턴 완료 뒤 한 번에 보인다(패널은 응답 중 1초 간격으로 다시 읽음). 진행 중 턴은 HAL 재시작 때 사라진다(거짓 진행 표시 없음).
- 로컬 CLI 연결은 bear 에 CLI 가 없고 유닛이 `ProtectSystem=strict` 라 운영 서버에서는 `cli_unavailable` 로 표시된다. 실제 모델 공급자 호출은 운영자가 키·OAuth 를 등록해야 시작된다(이 릴리스는 가짜 공급자 테스트까지 검증).
- 실제 브라우저(DOM)에서 패널 동작은 자동 테스트하지 않았다(순수 렌더러·정적 계약·API 로 검증). 배포 뒤 운영자 로그인으로 패널 열기·연결 추가·확인·통합 방 지시 1회 눈 확인을 권한다.
### 미확정 정책값
- 토큰 왕복 상한(8), 지시 길이 상한(20000자), 도구 결과 전달 상한(24000자), 패널 기본 너비(400px) — 운영자 요청 시 설정값으로 뺄 수 있다. 공급자 비용 표시는 토큰 수만(가격표 없음).
## 0.2.1 (2026-10-29)
- **작성자**: 개발 지시 — Neo(`Ariweb-Suitle_Dev-Order_v0.2.1.md`, 오즈 승인) · 구현 — Claude Fable 5.1(격리 작업 트리 `feature/hal-risk-banner-v0.2.1`, 기준 origin/main `0a56d4612c86dddfcbe644e775980d3c5b413b2e`). 커밋·push·병합·릴리스 빌드·운영 배포는 하지 않았다 — Neo 가 검토 뒤 수행한다.