Skip to content

Latest commit

 

History

History
301 lines (231 loc) · 20.6 KB

File metadata and controls

301 lines (231 loc) · 20.6 KB
created 2026-03-28
tags
cli-jaw
server
api
express
aliases
CLI-JAW Server API
server.ts reference
server_api

📚 INDEX · 체크리스트 ↗ · 커맨드 ↗ · 서버 API

server.ts — Glue + Route Registration (741L)

Express/WS bootstrap + localhost/LAN opt-in 보안 가드 + base route 13개 + src/routes/* 12개 registrar 등록. 현재 라이브 surface는 총 134개 route handler이며, 이 중 /를 제외한 API 엔드포인트는 133개다. mutation route(POST/PUT/DELETE)는 총 71개고 모두 requireAuth를 거친다. 단, requireAuth()는 loopback 요청을 토큰 없이 통과시키고, lanAllowed()가 true일 때 private IP도 LAN bypass로 통과시킨다. GET /api/auth/token은 Bearer bootstrap 전용이며 Sec-Fetch-Sitesame-origin 또는 none이 아닐 때 403을 반환한다.


Route Module Architecture

Module Lines Routes 역할
server.ts 741L 13 Helmet/CORS/Host/rate-limit/WS/bootstrap + base routes + module registration
src/routes/settings.ts 316L 18 settings/prompt/heartbeat-md/MCP/CLI registry/quota/copilot
src/routes/memory.ts 185L 13 memory runtime + KV memory + memory files
src/routes/browser.ts 475L 41 browser primitive/tab/debug/doctor/cleanup routes + adaptive fetch + web-ai render/send/poll/watch/sessions/capabilities/context routes
src/routes/jaw-memory.ts 239L 11 jaw memory search/read/save/list/init/reflect/flush/soul/soul-activate/bootstrap
src/routes/orchestrate.ts 394L 11 reset/state/workers/snapshot/queue cancel/hold/queue steer/dispatch/worker result/state PUT
src/routes/messaging.ts 222L 6 upload/file-open/voice/telegram/channel/discord send
src/routes/employees.ts 96L 5 employee CRUD + reset
src/routes/skills.ts 74L 5 skills list/read/enable/disable/reset
src/routes/avatar.ts 146L 4 avatar summary + agent/user image upload/delete/read
src/routes/traces.ts 80L 3 public trace summary/event read routes
src/routes/heartbeat.ts 43L 2 heartbeat GET + validated PUT
src/routes/i18n.ts 26L 2 language list + locale bundle
src/routes/quota.ts 459L settings.ts가 호출하는 quota/auth/status reader helper
src/routes/types.ts 3L shared AuthMiddleware type

등록 순서 (server.ts)

employees → heartbeat → skills → jaw-memory → orchestrate
→ memory → settings → messaging → avatar → traces
→ dashboard board/schedule → browser → i18n

라우트 모듈은 server.ts:543-561 부근에서 등록된다.


Base Route Surface (server.ts)

Method Path 설명
GET / public/dist/index.html이 있으면 Vite build를 서빙, 없으면 static fallback
GET /api/health { ok, version, uptime }
GET /api/session 현재 main session row 반환
GET /api/messages `includeTrace=1
GET /api/messages/latest 가장 최근 메시지 스냅샷 반환
GET /api/runtime uptime, activeAgent, queuePending
GET /api/auth/token same-origin/CLI용 Bearer token bootstrap
POST /api/command slash command 실행
GET /api/commands 인터페이스별 command palette 데이터
POST /api/message 일반 프롬프트 제출
POST /api/stop 현재 실행 중 agent 모두 종료
POST /api/clear UI-only clear broadcast, DB 메시지는 유지
POST /api/session/reset 메시지 삭제 + session reset

서버 헬퍼

Function 역할
findProjectRoot() package.json 기준 프로젝트 루트 탐색
getRuntimeSnapshot() uptime/activeAgent/queuePending 스냅샷
clearSessionState() ownership generation 증가 + 메시지 삭제 + clear broadcast
resetSessionOnly() session ID만 비우고 history 유지 + session_reset broadcast
resolveRequestLocale() body/query/Accept-Language/settings 순으로 locale 확정
applySettingsPatch() runtime patch 적용 + fallback state reset hook
makeWebCommandCtx() Web용 makeCommandCtx('web', ...) 래퍼
requireAuth() loopback bypass + optional private-LAN bypass + non-local Bearer 검사

Startup / Shutdown

초기화 순서

ensureDirs()
→ mkdir public
→ runMigration(projectRoot)
→ loadSettings()
→ DB quick_check
→ stale employee sessions clear
→ orphan jaw-emp-* tmp dir cleanup
→ syncMainSessionToSettings()
→ ensureMemoryRuntimeReady()
→ permissions safe→auto migration
→ initPromptFiles() / regenerateB()
→ stale/non-default orc_state reset/prune
→ express/http/ws 생성
→ middleware + base routes + route modules + errorHandler
→ watchHeartbeatFile()
→ server.listen(bindHost)
→ loadLocales()
→ initMcpConfig() / ensureWorkingDirSkillsLinks() / copyDefaultSkills()
→ hydrateTargetsFromSettings() / initActiveMessagingRuntime()
→ seedDefaultEmployees()
→ startHeartbeat()
→ employee name/model migration

listen 시점 후처리

  • settings.port를 실제 listen port로 다시 저장한다.
  • JAW_OPEN_BROWSER=1이면 테스트 환경이 아닐 때만 브라우저를 auto-open 한다.
  • MCP/skills 링크 충돌이 있으면 ~/.cli-jaw/backups/skills-conflicts로 백업 이동한다.
  • 직원이 비어 있으면 default employees를 seed 한다.
  • 한국어 직원명(프런트, 백엔드, 문서 등)을 영문명으로 마이그레이션한다.
  • 레거시 Claude employee model 값을 alias(sonnet, opus, sonnet[1m], opus[1m])로 정규화한다.

종료 처리

  • SIGTERM/SIGINT에서 heartbeat 중지, 모든 agent 종료, active orc_state reset, messaging runtime shutdown 시도, WebSocket/HTTP close, SQLite close를 수행한다.
  • 5초 내 종료가 끝나지 않으면 force exit 한다.

Security / Guards

네트워크 가드

  • 기본 서버 bind는 127.0.0.1이지만 settings.network.bindHost, JAW_LAN_MODE=1, reverse-proxy mode에 따라 0.0.0.0 bind가 가능하다.
  • ALLOWED_HOSTS/ALLOWED_ORIGINS는 loopback을 기본 허용하고, LAN mode/bypass가 켜졌을 때 private network origin/host를 허용한다.
  • WebSocket handshake도 동일한 host/origin 검사를 거친다.

인증

  • mutation route 71개는 모두 requireAuth로 보호된다.
  • 다만 로컬 동일 머신 사용성을 위해 loopback 요청은 Bearer 없이 허용된다. LAN bypass가 켜진 private IP 요청도 토큰 없이 통과할 수 있으므로 trusted network 전용이다.
  • /api/auth/token은 cross-origin token theft 방지를 위해 Sec-Fetch-Site를 검사한다.

경로/파일 보안

Surface Guard
Jaw Memory assertMemoryRelPath() + normalizeAdvancedReadPath()
Memory files assertMemoryRelPath() / assertFilename() / safeResolveUnder()
Skills assertSkillId()
Upload / avatar decodeFilenameSafe()
Telegram / channel send assertSendFilePath()
Avatar image serve safeResolveUnder(UPLOADS_DIR, basename(...))

기타

  • Rate limit: in-memory, IP 기준 120 req/min.
  • helmet() 사용, CSP/COEP는 현재 비활성.

REST API

Category Endpoints
Core/Auth GET /api/health GET /api/session GET /api/messages GET /api/messages/latest GET /api/runtime GET /api/auth/token POST /api/message POST /api/stop POST /api/clear POST /api/session/reset
Commands POST /api/command GET /api/commands?interface=
Settings/Prompt GET/PUT /api/settings GET /api/codex-context GET/PUT /api/prompt GET /api/prompt-templates PUT /api/prompt-templates/:id GET/PUT /api/heartbeat-md
MCP/CLI/Quota GET/PUT /api/mcp POST /api/mcp/sync POST /api/mcp/install POST /api/mcp/reset GET /api/cli-registry GET /api/cli-status GET /api/quota POST /api/copilot/refresh
Heartbeat GET/PUT /api/heartbeat
Browser POST /api/browser/start POST /api/browser/stop GET /api/browser/status GET /api/browser/doctor POST /api/browser/cleanup-runtimes GET /api/browser/snapshot POST /api/browser/screenshot POST /api/browser/act POST /api/browser/vision-click POST /api/browser/navigate POST /api/browser/reload POST /api/browser/resize GET /api/browser/tabs GET /api/browser/active-tab POST /api/browser/tab-switch POST /api/browser/tab-new POST /api/browser/tab-close POST /api/browser/tab-cleanup POST /api/browser/evaluate GET /api/browser/text GET /api/browser/dom GET /api/browser/console GET /api/browser/network POST /api/browser/fetch POST /api/browser/wait-for-selector POST /api/browser/wait-for-text POST /api/browser/web-ai/render POST /api/browser/web-ai/context-dry-run POST /api/browser/web-ai/context-render GET /api/browser/web-ai/status POST /api/browser/web-ai/send GET /api/browser/web-ai/poll GET /api/browser/web-ai/watch GET /api/browser/web-ai/watchers GET /api/browser/web-ai/sessions POST /api/browser/web-ai/sessions/prune GET /api/browser/web-ai/notifications GET /api/browser/web-ai/capabilities POST /api/browser/web-ai/query POST /api/browser/web-ai/stop GET /api/browser/web-ai/diagnose
Orchestrate POST /api/orchestrate/reset GET /api/orchestrate/state GET /api/orchestrate/workers GET /api/orchestrate/snapshot DELETE /api/orchestrate/queue/:id POST /api/orchestrate/queue/:id/hold DELETE /api/orchestrate/queue/:id/hold POST /api/orchestrate/queue/:id/steer POST /api/orchestrate/dispatch GET /api/orchestrate/worker/:agentId/result PUT /api/orchestrate/state
Employees GET /api/employees POST /api/employees PUT /api/employees/:id DELETE /api/employees/:id POST /api/employees/reset
Skills GET /api/skills GET /api/skills/:id POST /api/skills/enable POST /api/skills/disable POST /api/skills/reset
Memory Runtime / KV / Files GET /api/memory/status POST /api/memory/reindex POST /api/memory/bootstrap GET /api/memory/files GET /api/memory POST /api/memory DELETE /api/memory/:key GET /api/memory-files GET /api/memory-file GET /api/memory-files/:filename DELETE /api/memory-file DELETE /api/memory-files/:filename PUT /api/memory-files/settings
Jaw Memory GET /api/jaw-memory/search GET /api/jaw-memory/read POST /api/jaw-memory/save GET /api/jaw-memory/list POST /api/jaw-memory/init POST /api/jaw-memory/reflect POST /api/jaw-memory/flush GET /api/jaw-memory/soul POST /api/jaw-memory/soul/activate POST /api/jaw-memory/soul POST /api/soul/bootstrap
Messaging POST /api/upload POST /api/file/open POST /api/voice POST /api/telegram/send POST /api/channel/send POST /api/discord/send
Avatar GET /api/avatar POST /api/avatar/:target/upload DELETE /api/avatar/:target/image GET /api/avatar/:target/image
Traces GET /api/traces/:runId GET /api/traces/:runId/events GET /api/traces/:runId/events/:seq
i18n GET /api/i18n/languages GET /api/i18n/:lang

실제 코드(server.ts + src/routes/*.ts)에서 추출한 총 134개 route handler 기준이다. 이 중 API 엔드포인트는 133개이고, 나머지 1개는 / 엔트리이다. Browser API 41개는 src/routes/browser.ts에서 등록된다. 이 중 POST/PUT/DELETE mutation endpoint 74개는 모두 requireAuth 보호를 받고, GET /api/auth/tokenSec-Fetch-Sitesame-origin|none이 아닐 때 403을 반환한다.

최근 surface drift

  • jaw-memory는 이제 flush, soul read/write, soul/activate, POST /api/soul/bootstrap까지 포함한 11개 route다.
  • avatar API가 registerAvatarRoutes()로 연결되어 agent/user custom image를 관리한다.
  • /api/session/reset이 base route로 추가되어 /clear와 의미가 분리됐다.
  • orchestrate API는 queue cancel / queue hold / queue steer / worker result 조회까지 포함한 11개 route이며, 이전 continue route는 현재 코드 표면에 없다.
  • browser API는 primitive/tab/debug/doctor/runtime-cleanup, adaptive URL fetch, web-ai provider automation 라우트를 합쳐 41개 route로 확장됐다.
  • trace API는 public trace summary와 bounded event page/read를 GET /api/traces/:runId* 3개 route로 노출한다.
  • /api/cli-registry, /api/cli-status, /api/quota는 registry/detectAllCli/CLI_KEYS 기준으로 AGY(agy) top-level runtime을 포함한다. /api/quota에서 quota API가 없는 runtime은 quotaCapable:false status-only metadata로 반환한다.

Selected Route Notes

/api/command

  • body text를 500자까지 자른 뒤 parseCommand()로 해석한다.
  • locale은 body/query/Accept-Language/settings 순으로 정해지고 Content-Language가 세팅된다.
  • command가 아니면 400 { code: 'not_command' }.

/api/commands

  • COMMANDS에서 hidden 제외 + interface 매칭 결과만 내려준다.
  • 응답에는 name, desc, args, category, aliases가 포함된다.

/api/settings

  • GET은 live settings를 반환하되 STT secrets(geminiApiKey, openaiApiKey)를 비우고 *KeySet/*KeyLast4 메타만 노출한다.
  • PUTapplyRuntimeSettingsPatch()를 거치며 perCli, activeOverrides, telegram, discord, memory, stt, tui, messaging, network 같은 nested object는 merge semantics를 따른다.
  • showReasoning은 top-level scalar setting이며 /thought command와 Gemini thought visibility가 이 값을 공유한다.

/api/cli-registry / /api/cli-status

  • /api/cli-registrysrc/cli/registry.tsCLI_REGISTRY를 그대로 내려준다. AGY는 top-level key agy이며 ai-e.providers에는 포함되지 않는다.
  • /api/cli-statussrc/core/config.tsdetectAllCli() 결과를 내려준다. AGY는 registry binary agy 기준으로 설치 상태가 표시되고, auth hint는 frontend가 "run time check"로 렌더한다. 자동 기본 CLI 선정은 별도 src/cli/readiness.ts의 installed/authenticated tier를 쓴다.

/api/message

  • submitMessage()를 통해 idle 즉시 실행 / busy 큐잉 / reset/continue intent 분기를 공통 처리한다.
  • reject 시 409 busy 또는 400 reason을 반환한다.

/api/clear vs /api/session/reset

  • /api/clear: UI-only clear broadcast. DB 메시지 삭제 없음.
  • /api/session/reset: clearMainSessionState() 호출. 메시지 삭제 + session cleared.

/api/file/open

  • :line[:col] suffix가 붙은 문서형 경로를 허용한다.
  • exact path가 없을 때만 suffix를 strip 해 fallback 해석한다.
  • 문서형 확장자는 reveal, 일반 파일은 상위 폴더 open, 디렉터리는 디렉터리 자체 open 전략을 쓴다.

/api/heartbeat

  • PUTjobs 배열 전체를 검증한다.
  • invalid schedule이면 400과 함께 code, detail, index, jobId를 포함해 반환한다.

/api/quota

  • 응답 키: agy, ai-e, claude, claude-e, codex, codex-app, gemini, grok, opencode, copilot (CLI_KEYS 순서).
  • claude-e는 underlying Claude quota/auth를, codex-app은 underlying Codex quota/auth를, ai-e는 현재 선택 provider의 quota/auth를 delegated metadata와 함께 반환한다.
  • agyopencode는 현재 { authenticated:true, quotaCapable:false } status-only 응답이다.
  • grokgrok models 기반 auth/status-only 응답이다. Grok CLI는 남은 할당량을 노출하지 않으므로 quotaCapable:false, quotaSource:'not-exposed-by-grok-cli', displayTier:'Grok Heavy'를 반환하고, 있으면 최신 ~/.grok/sessions/**/signals.json의 세션 context 사용량만 best-effort로 붙인다.
  • AGY는 현 runtime에서 quota/auth API가 분리되어 있지 않아 real quota window를 만들지 않는다. 상태 표시는 /api/cli-status 설치 상태와 /api/quotanot-exposed-by-agy-cli metadata가 함께 담당한다.

/api/orchestrate/dispatch

  • boss-scoped x-jaw-boss-token이 필수다. employee spawn 환경에서는 이 토큰이 제거되므로 직원이 다시 dispatch하는 흐름은 서버에서 403으로 막힌다.
  • PABCD A/B/C 상태에서는 phase가 각각 Plan Audit/Verifier 쪽으로 매핑된다. 특히 B phase에서는 implementation wording을 delegation guard가 차단하고, worker는 READ-ONLY verifier로만 동작해야 한다.
  • 현재 plan이 있으면 dispatch body 상단에 ## Approved Plan으로 자동 주입된다. worker에게 별도 plan 파일을 읽으라고 지시하지 않는다.
  • PABCD Approved Plan 자동 주입 블록에는 Project root: <absolute path>와 path guard가 포함된다. A/B dispatch 예시도 task body 첫 줄에 Project root를 명시해 ~/.cli-jaw*/JAW_HOME/employee temp cwd를 repo root로 착각하지 않게 한다.

WebSocket Events

연결 시 서버는 현재 상태 스냅샷을 먼저 보낸다: agent_status, queue_update, 비-IDLE orc_state. 현재 브로드캐스트되는 WebSocket 이벤트는 23종이다.

Type 설명
agent_status running/done/error/evaluating + agentId/phase
agent_tool tool/thinking/search 진행 step
agent_output 라이브 text chunk preview
agent_done 최종 응답 + toolLog + origin
agent_retry / agent_fallback retry/fallback 안내
alert_escalation repeated failure / capacity fallback escalation alert
agent_smoke smoke auto-continue 안내
queue_update 대기열 길이 갱신
clear / session_reset UI clear / session reset broadcast
new_message Telegram/Discord inbound message
orc_state PABCD 상태 변경
orchestrate_done orchestration 완료/실패
agent_added / agent_updated / agent_deleted employee CRUD 반영
memory_status memory sidebar / runtime 상태 갱신 신호
system_notice compact refresh 같은 시스템 공지
heartbeat_pending pending heartbeat job 수
worker_stalled / worker_disconnected / worker_timeout distributed worker 상태 변화
  • 새 연결 시 서버는 필요하면 agent_status, queue_update, non-IDLE orc_state를 먼저 push 한다.
  • 실제 broadcast 함수는 src/core/bus.tsbroadcast(type, data) 하나다. WebSocket 전송과 내부 listener fan-out을 동시에 처리한다.
  • Web UI가 소비하는 이벤트별 상세 흐름은 stream-events.md에 정리한다.

Manager Dashboard Server Surface

jaw dashboard serve가 띄우는 별도 manager 서버(src/manager/server.ts)는 core server.ts route count에 포함하지 않는다. 현재 manager 전용 API는 scan/proxy/lifecycle 외에 board, notes, schedule, reminders를 함께 제공한다.

Surface Endpoints
Manager health/scan GET /api/dashboard/health GET /api/dashboard/instances GET /api/dashboard/instances/:port
Notes GET /api/dashboard/notes/info GET /api/dashboard/notes/version GET /api/dashboard/notes/tree GET /api/dashboard/notes/index GET /api/dashboard/notes/capabilities GET /api/dashboard/notes/search GET/POST/PUT /api/dashboard/notes/file POST /api/dashboard/notes/asset
Board GET/POST/PATCH/DELETE /api/dashboard/board/tasks and lane/task ordering routes under /api/dashboard/board
Schedule GET/POST/PATCH/DELETE /api/dashboard/schedule plus schedule runner-backed dispatch
Reminders GET /api/dashboard/reminders POST /api/dashboard/reminders POST /api/dashboard/reminders/from-message PATCH /api/dashboard/reminders/:id
Desktop/Electron GET /api/dashboard/desktop-status GET/POST /api/dashboard/electron-metrics
Memory federation GET /api/dashboard/memory/search GET /api/dashboard/memory/instances GET /api/dashboard/memory/read
Memory embedding GET /api/dashboard/memory/embed-config POST /api/dashboard/memory/embed-config GET /api/dashboard/memory/embed-state GET /api/dashboard/memory/embed-estimate GET /api/dashboard/memory/reindex-stream (SSE) POST /api/dashboard/memory/reindex

Memory embedding routes are served by src/manager/routes/dashboard-memory.ts. The embed-config POST doubles as connection test when body.test=true. The reindex-stream returns SSE events ({done,total} progress, {complete:true} on finish, {error} on failure). Auto-sync triggers on memory save broadcasts with 2s debounce, plus a 30-minute background catchall sync.

Reminders are backed by src/manager/reminders/store.ts and normalized through src/manager/reminders/api.ts. The scheduler checks due reminders, dispatches channel notifications, and records notificationStatus/attempt metadata.