casabot 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +28 -0
- package/LICENSE +190 -0
- package/README.md +112 -0
- package/dist/agent/base.d.ts +5 -0
- package/dist/agent/base.js +82 -0
- package/dist/agent/tools.d.ts +4 -0
- package/dist/agent/tools.js +36 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +70 -0
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.js +356 -0
- package/dist/config/manager.d.ts +14 -0
- package/dist/config/manager.js +46 -0
- package/dist/config/types.d.ts +38 -0
- package/dist/config/types.js +2 -0
- package/dist/history/store.d.ts +7 -0
- package/dist/history/store.js +52 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/providers/anthropic.d.ts +10 -0
- package/dist/providers/anthropic.js +98 -0
- package/dist/providers/base.d.ts +11 -0
- package/dist/providers/base.js +2 -0
- package/dist/providers/custom.d.ts +4 -0
- package/dist/providers/custom.js +9 -0
- package/dist/providers/huggingface.d.ts +6 -0
- package/dist/providers/huggingface.js +8 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.js +25 -0
- package/dist/providers/openai.d.ts +10 -0
- package/dist/providers/openai.js +76 -0
- package/dist/providers/openrouter.d.ts +6 -0
- package/dist/providers/openrouter.js +8 -0
- package/dist/skills/loader.d.ts +4 -0
- package/dist/skills/loader.js +48 -0
- package/dist/tui/app.d.ts +4 -0
- package/dist/tui/app.js +88 -0
- package/package.json +40 -0
- package/skills/agent/SKILL.md +180 -0
- package/skills/chat/SKILL.md +165 -0
- package/skills/config/SKILL.md +168 -0
- package/skills/memory/SKILL.md +245 -0
- package/skills/service/SKILL.md +224 -0
- package/src/agent/base.ts +98 -0
- package/src/agent/tools.ts +40 -0
- package/src/cli/index.ts +81 -0
- package/src/cli/setup.ts +378 -0
- package/src/config/manager.ts +53 -0
- package/src/config/types.ts +49 -0
- package/src/history/store.ts +59 -0
- package/src/index.ts +22 -0
- package/src/providers/anthropic.ts +115 -0
- package/src/providers/base.ts +12 -0
- package/src/providers/custom.ts +11 -0
- package/src/providers/huggingface.ts +10 -0
- package/src/providers/index.ts +29 -0
- package/src/providers/openai.ts +87 -0
- package/src/providers/openrouter.ts +10 -0
- package/src/skills/loader.ts +52 -0
- package/src/tui/app.tsx +158 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 시스템 서비스 등록
|
|
3
|
+
description: 자동 시작 및 서비스 연동을 설정하기 위한 매뉴얼
|
|
4
|
+
metadata:
|
|
5
|
+
casabot:
|
|
6
|
+
requires:
|
|
7
|
+
bins: [systemctl]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 시스템 서비스 등록
|
|
11
|
+
|
|
12
|
+
이 매뉴얼은 CasAbot을 systemd 서비스로 등록하고, 에이전트 자동 재시작 및 cron 스케줄링을 설정하는 방법을 설명합니다.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. base 자동 시작 (systemd 사용자 서비스)
|
|
17
|
+
|
|
18
|
+
CasAbot base 에이전트를 systemd 사용자 서비스로 등록하면 로그인 시 자동으로 시작됩니다.
|
|
19
|
+
|
|
20
|
+
### 서비스 파일 생성
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# 디렉토리 생성
|
|
24
|
+
mkdir -p ~/.config/systemd/user
|
|
25
|
+
|
|
26
|
+
# 서비스 파일 작성
|
|
27
|
+
cat > ~/.config/systemd/user/casabot.service << 'EOF'
|
|
28
|
+
[Unit]
|
|
29
|
+
Description=CasAbot Base Agent
|
|
30
|
+
After=network.target
|
|
31
|
+
|
|
32
|
+
[Service]
|
|
33
|
+
Type=simple
|
|
34
|
+
ExecStart=/usr/bin/env casabot
|
|
35
|
+
Restart=on-failure
|
|
36
|
+
RestartSec=10
|
|
37
|
+
WorkingDirectory=%h/casabot
|
|
38
|
+
Environment=NODE_ENV=production
|
|
39
|
+
|
|
40
|
+
[Install]
|
|
41
|
+
WantedBy=default.target
|
|
42
|
+
EOF
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 서비스 활성화 및 시작
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 데몬 리로드
|
|
49
|
+
systemctl --user daemon-reload
|
|
50
|
+
|
|
51
|
+
# 서비스 활성화 (부팅 시 자동 시작)
|
|
52
|
+
systemctl --user enable casabot
|
|
53
|
+
|
|
54
|
+
# 서비스 시작
|
|
55
|
+
systemctl --user start casabot
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 로그인 없이도 서비스 유지
|
|
59
|
+
|
|
60
|
+
기본적으로 사용자 서비스는 로그인 세션이 없으면 종료됩니다. 항상 실행되게 하려면:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# lingering 활성화 (로그아웃 후에도 서비스 유지)
|
|
64
|
+
loginctl enable-linger $(whoami)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 2. 서비스 상태 확인 및 관리
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# 상태 확인
|
|
71
|
+
systemctl --user status casabot
|
|
72
|
+
|
|
73
|
+
# 실시간 로그 보기
|
|
74
|
+
journalctl --user -u casabot -f
|
|
75
|
+
|
|
76
|
+
# 최근 100줄 로그
|
|
77
|
+
journalctl --user -u casabot -n 100
|
|
78
|
+
|
|
79
|
+
# 오늘 로그만
|
|
80
|
+
journalctl --user -u casabot --since today
|
|
81
|
+
|
|
82
|
+
# 서비스 재시작
|
|
83
|
+
systemctl --user restart casabot
|
|
84
|
+
|
|
85
|
+
# 서비스 중지
|
|
86
|
+
systemctl --user stop casabot
|
|
87
|
+
|
|
88
|
+
# 서비스 비활성화 (자동 시작 해제)
|
|
89
|
+
systemctl --user disable casabot
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 3. 서브에이전트 자동 재시작
|
|
93
|
+
|
|
94
|
+
podman 컨테이너의 `--restart` 옵션을 사용하여 서브에이전트가 자동으로 재시작되도록 설정합니다.
|
|
95
|
+
|
|
96
|
+
### 컨테이너 생성 시 설정
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 항상 재시작 (수동 중지 전까지)
|
|
100
|
+
podman run -d \
|
|
101
|
+
--restart=always \
|
|
102
|
+
--name <agent-name> \
|
|
103
|
+
--label casabot=true \
|
|
104
|
+
-v ~/casabot/workspaces/<agent-name>:/workspace \
|
|
105
|
+
-v ~/casabot/skills:/skills:ro \
|
|
106
|
+
node:20-slim sleep infinity
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 재시작 정책 옵션
|
|
110
|
+
|
|
111
|
+
| 옵션 | 설명 |
|
|
112
|
+
|------|------|
|
|
113
|
+
| `no` | 재시작하지 않음 (기본값) |
|
|
114
|
+
| `on-failure` | 비정상 종료 시에만 재시작 |
|
|
115
|
+
| `always` | 항상 재시작 (수동 중지 제외) |
|
|
116
|
+
| `unless-stopped` | 수동 중지 전까지 항상 재시작 |
|
|
117
|
+
|
|
118
|
+
### 기존 컨테이너에 재시작 정책 변경
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
podman update --restart=always <agent-name>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 서브에이전트를 systemd 서비스로 등록
|
|
125
|
+
|
|
126
|
+
특정 서브에이전트를 개별 systemd 서비스로 등록할 수도 있습니다:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# podman에서 systemd 서비스 파일 자동 생성
|
|
130
|
+
podman generate systemd --name <agent-name> --new > \
|
|
131
|
+
~/.config/systemd/user/casabot-<agent-name>.service
|
|
132
|
+
|
|
133
|
+
systemctl --user daemon-reload
|
|
134
|
+
systemctl --user enable casabot-<agent-name>
|
|
135
|
+
systemctl --user start casabot-<agent-name>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 4. cron 스케줄링
|
|
139
|
+
|
|
140
|
+
주기적으로 실행해야 하는 작업은 cron 또는 systemd timer를 사용합니다.
|
|
141
|
+
|
|
142
|
+
### cron을 사용한 주기적 작업
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# crontab 편집
|
|
146
|
+
crontab -e
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### 예시: 모니터링 에이전트 주기적 실행
|
|
150
|
+
|
|
151
|
+
```cron
|
|
152
|
+
# 매 5분마다 모니터링 에이전트 실행
|
|
153
|
+
*/5 * * * * podman exec monitor node /workspace/check.js >> ~/casabot/workspaces/monitor/cron.log 2>&1
|
|
154
|
+
|
|
155
|
+
# 매일 자정에 정리 작업 실행
|
|
156
|
+
0 0 * * * podman exec cleaner node /workspace/cleanup.js >> ~/casabot/workspaces/cleaner/cron.log 2>&1
|
|
157
|
+
|
|
158
|
+
# 매주 월요일 오전 9시에 주간 보고서 생성
|
|
159
|
+
0 9 * * 1 podman exec reporter node /workspace/weekly-report.js >> ~/casabot/workspaces/reporter/cron.log 2>&1
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### systemd timer를 사용한 주기적 작업
|
|
163
|
+
|
|
164
|
+
cron 대신 systemd timer를 사용하면 로그 관리가 더 편리합니다.
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# 타이머 서비스 파일 생성
|
|
168
|
+
cat > ~/.config/systemd/user/casabot-monitor.service << 'EOF'
|
|
169
|
+
[Unit]
|
|
170
|
+
Description=CasAbot Monitor Check
|
|
171
|
+
|
|
172
|
+
[Service]
|
|
173
|
+
Type=oneshot
|
|
174
|
+
ExecStart=/usr/bin/podman exec monitor node /workspace/check.js
|
|
175
|
+
EOF
|
|
176
|
+
|
|
177
|
+
# 타이머 파일 생성
|
|
178
|
+
cat > ~/.config/systemd/user/casabot-monitor.timer << 'EOF'
|
|
179
|
+
[Unit]
|
|
180
|
+
Description=CasAbot Monitor Timer
|
|
181
|
+
|
|
182
|
+
[Timer]
|
|
183
|
+
OnCalendar=*:0/5
|
|
184
|
+
Persistent=true
|
|
185
|
+
|
|
186
|
+
[Install]
|
|
187
|
+
WantedBy=timers.target
|
|
188
|
+
EOF
|
|
189
|
+
|
|
190
|
+
# 타이머 활성화
|
|
191
|
+
systemctl --user daemon-reload
|
|
192
|
+
systemctl --user enable casabot-monitor.timer
|
|
193
|
+
systemctl --user start casabot-monitor.timer
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### 타이머 상태 확인
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# 활성 타이머 목록
|
|
200
|
+
systemctl --user list-timers
|
|
201
|
+
|
|
202
|
+
# 특정 타이머 상태
|
|
203
|
+
systemctl --user status casabot-monitor.timer
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 5. 서비스 문제 해결
|
|
207
|
+
|
|
208
|
+
### 서비스가 시작되지 않을 때
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# 상세 로그 확인
|
|
212
|
+
journalctl --user -u casabot -n 50 --no-pager
|
|
213
|
+
|
|
214
|
+
# 서비스 파일 문법 검증
|
|
215
|
+
systemd-analyze verify ~/.config/systemd/user/casabot.service
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 서비스 파일 변경 후
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# 반드시 daemon-reload 실행
|
|
222
|
+
systemctl --user daemon-reload
|
|
223
|
+
systemctl --user restart casabot
|
|
224
|
+
```
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { ChatProvider } from "../providers/base.js";
|
|
2
|
+
import type { Message, Skill, ConversationHistory } from "../config/types.js";
|
|
3
|
+
import { TERMINAL_TOOL, executeCommand } from "./tools.js";
|
|
4
|
+
import { appendMessage } from "../history/store.js";
|
|
5
|
+
import { formatSkillsForPrompt } from "../skills/loader.js";
|
|
6
|
+
import { CASABOT_HOME } from "../config/manager.js";
|
|
7
|
+
|
|
8
|
+
const MAX_ITERATIONS = 20;
|
|
9
|
+
|
|
10
|
+
export function buildSystemPrompt(skills: Skill[]): string {
|
|
11
|
+
const skillList = formatSkillsForPrompt(skills);
|
|
12
|
+
|
|
13
|
+
return `당신은 CasAbot의 base 에이전트입니다. Cassiopeia A — 초신성 폭발과 같이 모든 것을 자유롭게 창조합니다.
|
|
14
|
+
|
|
15
|
+
## 핵심 원칙
|
|
16
|
+
1. 당신은 오케스트레이터입니다. 실제 작업을 직접 수행하지 마세요.
|
|
17
|
+
2. 스킬 문서를 우선적으로 참조하세요. 필요한 스킬의 SKILL.md를 읽고 지침을 따르세요.
|
|
18
|
+
3. 적합한 서브에이전트가 있으면 위임하고, 없으면 새로 만들어서 위임하세요.
|
|
19
|
+
4. 오케스트레이션(에이전트 생성/위임/관리)만 직접 수행하세요.
|
|
20
|
+
|
|
21
|
+
## 사용 가능한 도구
|
|
22
|
+
- \`run_command\`: 터미널 명령어를 실행합니다. 이 도구 하나로 스킬을 읽고, 서브에이전트를 관리하고, 모든 오케스트레이션을 수행합니다.
|
|
23
|
+
|
|
24
|
+
## 작업 순서
|
|
25
|
+
1. 사용자의 요청을 분석합니다.
|
|
26
|
+
2. 관련 스킬 문서를 읽습니다: \`cat <스킬경로>\`
|
|
27
|
+
3. 스킬 지침에 따라 서브에이전트를 생성하거나 기존 에이전트에 위임합니다.
|
|
28
|
+
4. 결과를 수집하여 사용자에게 보고합니다.
|
|
29
|
+
|
|
30
|
+
## CasAbot 디렉토리 구조
|
|
31
|
+
- 홈: ${CASABOT_HOME}
|
|
32
|
+
- 스킬: ${CASABOT_HOME}/skills/
|
|
33
|
+
- 워크스페이스: ${CASABOT_HOME}/workspaces/
|
|
34
|
+
- 대화 기록: ${CASABOT_HOME}/history/
|
|
35
|
+
- 기록(메모): ${CASABOT_HOME}/memory/
|
|
36
|
+
- 설정: ${CASABOT_HOME}/casabot.json
|
|
37
|
+
|
|
38
|
+
## ${skillList}
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function* runAgent(
|
|
43
|
+
provider: ChatProvider,
|
|
44
|
+
userMessage: string,
|
|
45
|
+
conversation: ConversationHistory,
|
|
46
|
+
skills: Skill[],
|
|
47
|
+
): AsyncGenerator<Message> {
|
|
48
|
+
const systemPrompt = buildSystemPrompt(skills);
|
|
49
|
+
|
|
50
|
+
const userMsg: Message = { role: "user", content: userMessage };
|
|
51
|
+
await appendMessage(conversation, userMsg);
|
|
52
|
+
|
|
53
|
+
const tools = [TERMINAL_TOOL];
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
|
56
|
+
const messagesWithSystem: Message[] = [
|
|
57
|
+
{ role: "system", content: systemPrompt },
|
|
58
|
+
...conversation.messages,
|
|
59
|
+
];
|
|
60
|
+
const assistantMsg = await provider.chat(messagesWithSystem, tools);
|
|
61
|
+
await appendMessage(conversation, assistantMsg);
|
|
62
|
+
yield assistantMsg;
|
|
63
|
+
|
|
64
|
+
if (!assistantMsg.toolCalls?.length) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (const toolCall of assistantMsg.toolCalls) {
|
|
69
|
+
let result: string;
|
|
70
|
+
|
|
71
|
+
if (toolCall.name === "run_command") {
|
|
72
|
+
try {
|
|
73
|
+
const args = JSON.parse(toolCall.arguments) as { command: string };
|
|
74
|
+
result = await executeCommand(args.command);
|
|
75
|
+
} catch {
|
|
76
|
+
result = `오류: 도구 인자 파싱 실패 — ${toolCall.arguments}`;
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
result = `알 수 없는 도구: ${toolCall.name}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const toolMsg: Message = {
|
|
83
|
+
role: "tool",
|
|
84
|
+
content: result,
|
|
85
|
+
toolCallId: toolCall.id,
|
|
86
|
+
};
|
|
87
|
+
await appendMessage(conversation, toolMsg);
|
|
88
|
+
yield toolMsg;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const limitMsg: Message = {
|
|
93
|
+
role: "assistant",
|
|
94
|
+
content: "⚠️ 최대 반복 횟수에 도달했습니다. 요청을 다시 시도해 주세요.",
|
|
95
|
+
};
|
|
96
|
+
await appendMessage(conversation, limitMsg);
|
|
97
|
+
yield limitMsg;
|
|
98
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { exec } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import type { ToolDefinition } from "../providers/base.js";
|
|
4
|
+
|
|
5
|
+
const execAsync = promisify(exec);
|
|
6
|
+
|
|
7
|
+
const MAX_BUFFER = 10 * 1024 * 1024;
|
|
8
|
+
const TIMEOUT_MS = 60_000;
|
|
9
|
+
|
|
10
|
+
export const TERMINAL_TOOL: ToolDefinition = {
|
|
11
|
+
name: "run_command",
|
|
12
|
+
description:
|
|
13
|
+
"터미널에서 명령어를 실행합니다. 스킬 문서를 읽거나, 서브에이전트를 관리하거나, 시스템 작업을 수행할 때 사용합니다.",
|
|
14
|
+
parameters: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
command: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "실행할 터미널 명령어",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["command"],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export async function executeCommand(command: string): Promise<string> {
|
|
27
|
+
try {
|
|
28
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
29
|
+
timeout: TIMEOUT_MS,
|
|
30
|
+
maxBuffer: MAX_BUFFER,
|
|
31
|
+
shell: "/bin/bash",
|
|
32
|
+
});
|
|
33
|
+
const output = [stdout, stderr].filter(Boolean).join("\n");
|
|
34
|
+
return output || "(명령어가 출력 없이 완료되었습니다)";
|
|
35
|
+
} catch (err: unknown) {
|
|
36
|
+
const error = err as { stdout?: string; stderr?: string; message: string };
|
|
37
|
+
const parts = [error.stdout, error.stderr, error.message].filter(Boolean);
|
|
38
|
+
return `오류 발생:\n${parts.join("\n")}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { loadConfig, saveConfig, getDefaultConfig, ensureDirectories } from "../config/manager.js";
|
|
5
|
+
import { createProvider } from "../providers/index.js";
|
|
6
|
+
import { loadSkills } from "../skills/loader.js";
|
|
7
|
+
import { createConversation } from "../history/store.js";
|
|
8
|
+
import { startTUI } from "../tui/app.js";
|
|
9
|
+
import { setupWizard } from "./setup.js";
|
|
10
|
+
|
|
11
|
+
const program = new Command();
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.name("casabot")
|
|
15
|
+
.description("CasAbot — 스킬 중심 멀티에이전트 오케스트레이터")
|
|
16
|
+
.version("1.0.0");
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.command("setup")
|
|
20
|
+
.description("최초 설정 (공급자, 모델 등 전체 설정)")
|
|
21
|
+
.action(async () => {
|
|
22
|
+
try {
|
|
23
|
+
await setupWizard();
|
|
24
|
+
} catch (err: unknown) {
|
|
25
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
26
|
+
console.error(`❌ 설정 중 오류 발생: ${msg}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
program
|
|
32
|
+
.command("reset")
|
|
33
|
+
.description("초기 설정으로 되돌리기")
|
|
34
|
+
.action(async () => {
|
|
35
|
+
try {
|
|
36
|
+
await saveConfig(getDefaultConfig());
|
|
37
|
+
console.log("✅ 설정이 초기화되었습니다.");
|
|
38
|
+
console.log("'casabot setup' 명령어로 다시 설정하세요.");
|
|
39
|
+
} catch (err: unknown) {
|
|
40
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
41
|
+
console.error(`❌ 초기화 중 오류 발생: ${msg}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
program
|
|
47
|
+
.action(async () => {
|
|
48
|
+
try {
|
|
49
|
+
await ensureDirectories();
|
|
50
|
+
|
|
51
|
+
const config = await loadConfig();
|
|
52
|
+
|
|
53
|
+
if (!config.activeProvider || config.providers.length === 0) {
|
|
54
|
+
console.log("⚠️ 공급자가 설정되지 않았습니다.");
|
|
55
|
+
console.log("'casabot setup' 명령어로 먼저 설정하세요.\n");
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const providerConfig = config.providers.find(
|
|
60
|
+
(p) => p.name === config.activeProvider,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (!providerConfig) {
|
|
64
|
+
console.error(`❌ 활성 공급자 '${config.activeProvider}'를 찾을 수 없습니다.`);
|
|
65
|
+
console.error("'casabot setup' 명령어로 다시 설정하세요.");
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const provider = createProvider(providerConfig);
|
|
70
|
+
const skills = await loadSkills();
|
|
71
|
+
const conversation = createConversation();
|
|
72
|
+
|
|
73
|
+
startTUI(provider, conversation, skills);
|
|
74
|
+
} catch (err: unknown) {
|
|
75
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
76
|
+
console.error(`❌ 시작 중 오류 발생: ${msg}`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
program.parse();
|