// v1.5.11: 실행 파일뿐 아니라 인증(서버 로그인·OAuth 토큰·API 키)까지 본다 — 설치 직후 "실행 파일은 있는데 로그인이 없어" 작업이 실패하던 상태를 미리 보이게
letclaude=null;try{constc=require('./claude').claudeInfo();consta=awaitrequire('./setupstate').claudeAuth();claude={ok:!!c.bin&&a.ok,bin:c.bin,version:c.version,searched:c.searched,auth:a,detail:c.bin?`claude ${c.version||''} (${c.bin}) · ${a.detail}${a.ok?'':` — ${a.hint||''}`}`:`claude 실행 파일을 찾지 못했습니다 (탐색: ${(c.searched||[]).join(', ')})`};}catch(e){claude={ok:false,detail:e.message};}
letcodex=null;try{constc=require('./engine-codex').codexInfo();constsb=c.sandbox||{};codex={ok:!!c.bin,bin:c.bin,version:c.version,loggedIn:c.loggedIn,mode:c.mode,sandbox:sb,detail:c.bin?`${c.version||'codex'} · ${c.loggedIn?`로그인됨 (${c.mode})`:'로그인 안 됨 (codex login)'} · 샌드박스 ${sb.mode==='none'?'없음':sb.mode||'?'}${sb.restricted?' — '+sb.reason:''}`:'codex 실행 파일 없음 (선택 — OpenAI 서버 로그인을 쓸 때만)'};}catch(e){codex={ok:false,detail:e.message};}
letresend=null;try{constm=awaitrequire('./mailer').status();resend={ok:!!m.configured,detail:m.configured?`메일 발송 키 있음 (${m.source})${m.verifiedDomains&&m.verifiedDomains.length?` · 검증 도메인 ${m.verifiedDomains.join(', ')}`:''}`:(m.error||'메일 발송 키 없음 — 관리자 콘솔 › 설정 › 메일 발송')};}catch(e){resend={ok:false,detail:e.message};}
// v1.5.11: 설치 점검표·관리자 계정·AI 인증 방식·접속 주소 — 설정 페이지 맨 위 카드들이 쓴다
if(action==='bootstrap'){constr=auth.bootstrapAdmin(by||'setup');setupstate.invalidate();if(r.created)try{require('./audit').log({by:by||'setup',action:'admin.bootstrap',targetType:'user',target:auth.BOOTSTRAP_ID});}catch(_){}return{ok:true,password:r.created?r.password:undefined,created:r.created,user:r.user,detail:r.created?`기본 관리자 ${auth.BOOTSTRAP_ID} / ${auth.BOOTSTRAP_PASSWORD} 를 만들었습니다. 로그인 뒤 비밀번호를 바꿔야 합니다`:`${auth.BOOTSTRAP_ID} 계정이 이미 있습니다${r.user.mustChangePassword?' (비밀번호 기본값 — 바꾸거나 아래에서 재설정하세요)':''}`};}
if(action==='create'){constid=String(b.id||'').trim().toLowerCase();if(!id)throwhttpError('아이디를 입력하세요');constu=auth.createUser({id,password:String(b.password||''),name:String(b.name||id),role:'admin'});setupstate.invalidate();return{ok:true,user:u,detail:`관리자 ${u.id} 를 만들었습니다`};}
if(action==='password'){constid=String(b.id||'').trim().toLowerCase();if(!id)throwhttpError('아이디를 입력하세요');constu0=auth.getUser(id);if(!u0)throwhttpError('사용자가 없습니다',404);if(u0.role!=='admin')throwhttpError('관리자 계정만 여기서 재설정할 수 있습니다 (일반 회원은 관리자 콘솔 › 사용자)');constu=auth.resetPassword(id,String(b.password||''));setupstate.invalidate();return{ok:true,user:u,detail:`${u.id} 의 비밀번호를 바꿨습니다. 이제 이 계정으로 로그인할 수 있습니다`};}
throwhttpError('지원하지 않는 작업입니다');
}
/** v1.5.11 AI 엔진 인증 저장 — 관리자 콘솔 › AI 연결 탭(settings.auth / providers.openai, v1.5.16 에 설정 탭에서 옮김)과 같은 저장소 */
// v1.9.0 (Ariweb Suite HAL 0.4.0 대응): HAL 이 관리하는 설정 파일 항목은 설정 페이지·관리자 콘솔에서 바꿀 수 없다(409 managed_by_hal). HAL 의 적용(by 'hal')은 lib/hal-managed 가 config.set 을 직접 부른다
constr=config.set(values,by);try{require('./setupstate').invalidate();}catch(_){}// v1.5.11 점검표(공개 주소 등) 다시 계산
return{ok:true,changed:r.changed,restart:r.restart,note:r.changed.length?(r.restart?`저장했습니다 (${r.changed.length}개). 재시작해야 적용되는 항목이 있습니다 — "서비스 재시작" 을 누르세요.`:`저장했습니다 (${r.changed.length}개). 바로 적용됩니다.`):'바뀐 값이 없습니다.'};
if(kind==='source'&&action==='ensure-repo'&&m.ensureRepo){constr=awaitm.ensureRepo();return{ok:true,detail:r.created?`저장소 ${r.repo} 를 만들었습니다`:`저장소 ${r.repo} 가 이미 있습니다`,...r};}
if(kind==='source'&&action==='register-key'&&m.registerKey){constr=awaitm.registerKey();return{ok:true,detail:r.registered?`이 서버의 공개키를 등록했습니다 (${r.title})`:'공개키가 이미 등록되어 있습니다',...r};}
throwhttpError('지원하지 않는 작업입니다');
}
/**
* 서비스 재시작. 실행 계정에 `sudo -n systemctl restart <유닛>` 권한이 있어야 한다
* (설치 스크립트가 /etc/sudoers.d/webmaker-setup 에 넣는다). 실행 중인 AI 작업이 있으면 끝날 때까지(최대 10분) 기다린다.
if(a==='migrate-env'&&method==='POST'){constmoved=require('./config').migrateFromEnv(`migrate:${by||'setup'}`);return{status:200,body:{ok:true,moved,detail:moved.length?`${moved.length}개 항목을 환경 변수에서 옮겼습니다: ${moved.join(', ')}`:'옮길 항목이 없습니다 (이미 설정 파일에 있거나 환경 변수가 비어 있음)'}};}