companionbot 0.7.0 β†’ 0.8.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.
Files changed (2) hide show
  1. package/dist/cli/main.js +178 -27
  2. package/package.json +3 -1
package/dist/cli/main.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as readline from "readline";
2
+ import { checkbox, Separator } from "@inquirer/prompts";
2
3
  import { getSecret, setSecret } from "../config/secrets.js";
3
4
  import { isWorkspaceInitialized, initWorkspace, getWorkspacePath, } from "../workspace/index.js";
4
5
  import { createBot } from "../telegram/bot.js";
@@ -20,51 +21,167 @@ async function question(rl, prompt) {
20
21
  }
21
22
  async function interactiveSetup() {
22
23
  const rl = createPrompt();
23
- console.log("\nπŸ€– CompanionBot 첫 μ‹€ν–‰μž…λ‹ˆλ‹€!\n");
24
+ console.log(`
25
+ ╔═══════════════════════════════════════════════════════════════╗
26
+ β•‘ πŸ€– CompanionBot 첫 μ‹€ν–‰ κ°€μ΄λ“œ β•‘
27
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
28
+
29
+ CompanionBot은 Telegramμ—μ„œ λ™μž‘ν•˜λŠ” 개인 AI λΉ„μ„œμ˜ˆμš”.
30
+
31
+ πŸ’‘ μ–Έμ œλ“ μ§€ 'q'λ₯Ό μž…λ ₯ν•˜λ©΄ 섀정을 μ·¨μ†Œν•  수 μžˆμ–΄μš”.
32
+ `);
24
33
  try {
34
+ // ===== STEP 1: κΈ°λŠ₯ 선택 =====
35
+ console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
36
+ [STEP 1] μ‚¬μš©ν•  κΈ°λŠ₯ 선택
37
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
38
+
39
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
40
+ β”‚ [ν•„μˆ˜] κΈ°λ³Έ κΈ°λŠ₯ (μžλ™ 포함) β”‚
41
+ β”‚ β”œβ”€ πŸ’¬ AI λŒ€ν™” μžμ—°μŠ€λŸ¬μš΄ ν•œκ΅­μ–΄ λŒ€ν™” β”‚
42
+ β”‚ β”œβ”€ πŸ“ 파일 관리 λ¬Έμ„œ/μ½”λ“œ 읽기·쓰기 β”‚
43
+ β”‚ β”œβ”€ ⏰ λ¦¬λ§ˆμΈλ” μ•Œλ¦Ό μ„€μ • ("3μ‹œμ— μ•Œλ €μ€˜") β”‚
44
+ β”‚ └─ 🧠 λ©”λͺ¨λ¦¬ λŒ€ν™” κΈ°μ–΅, μž₯κΈ° κΈ°μ–΅ μ €μž₯ β”‚
45
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
46
+ `);
47
+ const features = {
48
+ webSearch: false,
49
+ calendar: false,
50
+ weather: false,
51
+ };
52
+ let selectedValues = [];
53
+ try {
54
+ selectedValues = await checkbox({
55
+ message: "μΆ”κ°€ κΈ°λŠ₯ 선택 (Space=선택, Enter=ν™•μ •)",
56
+ choices: [
57
+ { name: "πŸ” μ›Ή 검색 - Brave API, 무료 2000/μ›”", value: "webSearch" },
58
+ { name: "πŸ“… μΊ˜λ¦°λ” - Google Calendar 연동", value: "calendar" },
59
+ { name: "🌀️ 날씨 - OpenWeatherMap, 무료", value: "weather" },
60
+ new Separator(" ● λ‹€μŒ λ‹¨κ³„λ‘œ"),
61
+ ],
62
+ });
63
+ }
64
+ catch {
65
+ console.log("\nπŸ‘‹ 섀정을 μ·¨μ†Œν–ˆμŠ΅λ‹ˆλ‹€.");
66
+ rl.close();
67
+ return false;
68
+ }
69
+ features.webSearch = selectedValues.includes("webSearch");
70
+ features.calendar = selectedValues.includes("calendar");
71
+ features.weather = selectedValues.includes("weather");
72
+ // 선택 μš”μ•½
73
+ const selectedFeatures = [];
74
+ if (features.webSearch)
75
+ selectedFeatures.push("πŸ” μ›Ή 검색");
76
+ if (features.calendar)
77
+ selectedFeatures.push("πŸ“… μΊ˜λ¦°λ”");
78
+ if (features.weather)
79
+ selectedFeatures.push("🌀️ 날씨");
80
+ console.log(`
81
+ βœ“ 선택됨: ${selectedFeatures.length > 0 ? selectedFeatures.join(", ") : "κΈ°λ³Έ κΈ°λŠ₯만"}
82
+ `);
83
+ // ===== STEP 2: ν•„μˆ˜ API ν‚€ =====
84
+ console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
85
+ [STEP 2] ν•„μˆ˜ API ν‚€ μž…λ ₯
86
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
87
+ `);
25
88
  // Telegram Bot Token
26
- console.log("[1/2] Telegram Bot Token");
27
- console.log(" @BotFatherμ—μ„œ 봇 생성 ν›„ 토큰을 λΆ™μ—¬λ„£μœΌμ„Έμš”.");
28
- console.log(" (https://t.me/BotFather)\n");
89
+ console.log(` πŸ“± Telegram Bot Token
90
+
91
+ 1. Telegramμ—μ„œ @BotFather 검색
92
+ 2. /newbot β†’ 이름 μž…λ ₯ β†’ μœ μ €λ„€μž„ μž…λ ₯ (_bot으둜 λλ‚˜μ•Ό 함)
93
+ 3. 토큰 볡사 (예: 123456:ABC-DEF...)
94
+ πŸ”— https://t.me/BotFather
95
+ `);
29
96
  const token = await question(rl, " Token: ");
30
- if (!token) {
31
- console.log("\n❌ 토큰이 ν•„μš”ν•©λ‹ˆλ‹€.");
97
+ if (!token || token.toLowerCase() === "q") {
98
+ console.log("\nπŸ‘‹ 섀정을 μ·¨μ†Œν–ˆμŠ΅λ‹ˆλ‹€.");
32
99
  rl.close();
33
100
  return false;
34
101
  }
35
102
  await setSecret("telegram-token", token);
36
103
  console.log(" βœ“ μ €μž₯됨\n");
37
104
  // Anthropic API Key
38
- console.log("[2/2] Anthropic API Key");
39
- console.log(" console.anthropic.comμ—μ„œ λ°œκΈ‰λ°›μœΌμ„Έμš”.");
40
- console.log(" (https://console.anthropic.com/settings/keys)\n");
105
+ console.log(` 🧠 Anthropic API Key
106
+
107
+ 1. https://console.anthropic.com 접속 (νšŒμ›κ°€μž…/둜그인)
108
+ 2. Settings > API Keys > Create Key
109
+ 3. ν‚€ 볡사 (sk-ant-...)
110
+ πŸ”— https://console.anthropic.com/settings/keys
111
+ `);
41
112
  const apiKey = await question(rl, " API Key: ");
42
- if (!apiKey) {
43
- console.log("\n❌ API ν‚€κ°€ ν•„μš”ν•©λ‹ˆλ‹€.");
113
+ if (!apiKey || apiKey.toLowerCase() === "q") {
114
+ console.log("\nπŸ‘‹ 섀정을 μ·¨μ†Œν–ˆμŠ΅λ‹ˆλ‹€. (Telegram 토큰은 μ €μž₯됨)");
44
115
  rl.close();
45
116
  return false;
46
117
  }
47
118
  await setSecret("anthropic-api-key", apiKey);
48
119
  console.log(" βœ“ μ €μž₯됨\n");
49
- // 선택적 κΈ°λŠ₯ μ„€μ •
50
- const setupOptional = await question(rl, "[선택] μΆ”κ°€ κΈ°λŠ₯을 μ„€μ •ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ? (y/n): ");
51
- if (setupOptional.toLowerCase() === "y") {
52
- console.log("");
53
- // 날씨 κΈ°λŠ₯
54
- const useWeather = await question(rl, " 날씨 κΈ°λŠ₯을 μ‚¬μš©ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ? (y/n): ");
55
- if (useWeather.toLowerCase() === "y") {
56
- console.log("\n OpenWeatherMap API Keyκ°€ ν•„μš”ν•©λ‹ˆλ‹€.");
57
- console.log(" (https://openweathermap.org)\n");
58
- const weatherKey = await question(rl, " API Key: ");
120
+ // ===== STEP 3: 선택 API ν‚€ =====
121
+ if (features.webSearch || features.calendar || features.weather) {
122
+ console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
123
+ [STEP 3] μ„ νƒν•œ κΈ°λŠ₯ API ν‚€ μž…λ ₯
124
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
125
+
126
+ Enterλ₯Ό λˆ„λ₯΄λ©΄ ν•΄λ‹Ή κΈ°λŠ₯을 κ±΄λ„ˆλ›Έ 수 μžˆμ–΄μš”.
127
+ `);
128
+ // μ›Ή 검색 API
129
+ if (features.webSearch) {
130
+ console.log(` πŸ” Brave Search API (무료 2000회/μ›”)
131
+
132
+ 1. https://brave.com/search/api 접속
133
+ 2. Get Started > κ°€μž… > API ν‚€ 생성
134
+ `);
135
+ const braveKey = await question(rl, " API Key (Enter=κ±΄λ„ˆλ›°κΈ°, q=μ·¨μ†Œ): ");
136
+ if (braveKey.toLowerCase() === "q") {
137
+ console.log("\nπŸ‘‹ 섀정을 μ·¨μ†Œν–ˆμŠ΅λ‹ˆλ‹€.");
138
+ rl.close();
139
+ return false;
140
+ }
141
+ if (braveKey) {
142
+ await setSecret("brave-api-key", braveKey);
143
+ console.log(" βœ“ μ €μž₯됨\n");
144
+ }
145
+ else {
146
+ console.log(" β†’ κ±΄λ„ˆλœ€ (λ‚˜μ€‘μ—: companionbot setup brave <KEY>)\n");
147
+ }
148
+ }
149
+ // 날씨 API
150
+ if (features.weather) {
151
+ console.log(` 🌀️ OpenWeatherMap API (무료)
152
+
153
+ 1. https://openweathermap.org 접속 > Sign Up
154
+ 2. API Keys λ©”λ‰΄μ—μ„œ ν‚€ 확인/생성
155
+ `);
156
+ const weatherKey = await question(rl, " API Key (Enter=κ±΄λ„ˆλ›°κΈ°, q=μ·¨μ†Œ): ");
157
+ if (weatherKey.toLowerCase() === "q") {
158
+ console.log("\nπŸ‘‹ 섀정을 μ·¨μ†Œν–ˆμŠ΅λ‹ˆλ‹€.");
159
+ rl.close();
160
+ return false;
161
+ }
59
162
  if (weatherKey) {
60
163
  await setSecret("openweathermap-api-key", weatherKey);
61
164
  console.log(" βœ“ μ €μž₯됨\n");
62
165
  }
63
166
  else {
64
- console.log(" β†’ κ±΄λ„ˆλœ€\n");
167
+ console.log(" β†’ κ±΄λ„ˆλœ€ (λ‚˜μ€‘μ—: companionbot setup weather <KEY>)\n");
65
168
  }
66
169
  }
170
+ // μΊ˜λ¦°λ”
171
+ if (features.calendar) {
172
+ console.log(` πŸ“… Google Calendar
173
+
174
+ μΊ˜λ¦°λ”λŠ” 봇 μ‹€ν–‰ ν›„ /calendar_setup λͺ…λ Ήμ–΄λ‘œ μ„€μ •ν•©λ‹ˆλ‹€.
175
+ (OAuth 인증이 ν•„μš”ν•΄μ„œ λΈŒλΌμš°μ €κ°€ μ—΄λ €μš”)
176
+ `);
177
+ await question(rl, " Enterλ₯Ό 눌러 계속...");
178
+ console.log("");
179
+ }
67
180
  }
181
+ console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
182
+ βœ… μ„€μ • μ™„λ£Œ!
183
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
184
+ `);
68
185
  rl.close();
69
186
  return true;
70
187
  }
@@ -93,15 +210,35 @@ async function main() {
93
210
  }
94
211
  // 3. μ›Œν¬μŠ€νŽ˜μ΄μŠ€ μ΄ˆκΈ°ν™”
95
212
  const workspaceReady = await isWorkspaceInitialized();
213
+ const workspacePath = getWorkspacePath();
96
214
  if (!workspaceReady) {
97
- console.log("πŸ“ μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 생성 쀑...");
215
+ console.log(`
216
+ ╔═══════════════════════════════════════════════════════════════╗
217
+ β•‘ πŸ“ μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 생성 β•‘
218
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
219
+ `);
98
220
  await initWorkspace();
99
- console.log(` β†’ ${getWorkspacePath()} 생성 μ™„λ£Œ\n`);
221
+ console.log(` 경둜: ${workspacePath}
222
+
223
+ μƒμ„±λœ νŒŒμΌλ“€:
224
+ β”œβ”€β”€ IDENTITY.md ← λ΄‡μ˜ 이름과 성격 μ„€μ •
225
+ β”œβ”€β”€ SOUL.md ← λ΄‡μ˜ 행동 원칙
226
+ β”œβ”€β”€ USER.md ← 당신에 λŒ€ν•œ 정보 (봇이 μ°Έκ³ )
227
+ β”œβ”€β”€ AGENTS.md ← 봇 행동 κ°€μ΄λ“œ
228
+ β”œβ”€β”€ MEMORY.md ← μž₯κΈ° κΈ°μ–΅ μ €μž₯μ†Œ
229
+ └── memory/ ← 일일 λ©”λͺ¨λ¦¬ 폴더
230
+
231
+ πŸ’‘ 팁: IDENTITY.md와 USER.mdλ₯Ό νŽΈμ§‘ν•΄μ„œ 봇을 μ»€μŠ€ν„°λ§ˆμ΄μ¦ˆν•˜μ„Έμš”!
232
+ `);
100
233
  }
101
234
  // 4. ν™˜κ²½λ³€μˆ˜ μ„€μ •
102
235
  process.env.ANTHROPIC_API_KEY = apiKey;
103
236
  // 5. 봇 μ‹œμž‘
104
- console.log("πŸš€ 봇을 μ‹œμž‘ν•©λ‹ˆλ‹€!\n");
237
+ console.log(`
238
+ ╔═══════════════════════════════════════════════════════════════╗
239
+ β•‘ πŸš€ 봇 μ‹œμž‘! β•‘
240
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
241
+ `);
105
242
  const bot = createBot(token);
106
243
  // Graceful shutdown
107
244
  async function shutdown() {
@@ -117,8 +254,22 @@ async function main() {
117
254
  process.once("SIGTERM", () => void shutdown());
118
255
  bot.start({
119
256
  onStart: (botInfo) => {
120
- console.log(`βœ“ @${botInfo.username} μ‹œμž‘λ¨`);
121
- console.log(` ν…”λ ˆκ·Έλž¨μ—μ„œ λŒ€ν™”λ₯Ό μ‹œμž‘ν•˜μ„Έμš”!\n`);
257
+ console.log(` βœ“ @${botInfo.username} 연결됨!
258
+
259
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
260
+ 이제 Telegramμ—μ„œ @${botInfo.username} κ²€μƒ‰ν•΄μ„œ λŒ€ν™”ν•΄λ³΄μ„Έμš”!
261
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
262
+
263
+ πŸ“± λͺ…λ Ήμ–΄ λͺ©λ‘:
264
+ /help - 도움말
265
+ /model - AI λͺ¨λΈ λ³€κ²½ (haiku/sonnet/opus)
266
+ /compact - λŒ€ν™” μš”μ•½ (토큰 μ ˆμ•½)
267
+ /health - 봇 μƒνƒœ 확인
268
+ /calendar - μΊ˜λ¦°λ” 연동 (Google)
269
+
270
+ ⌨️ Ctrl+C둜 μ’…λ£Œ
271
+ πŸ“‚ μ›Œν¬μŠ€νŽ˜μ΄μŠ€: ${workspacePath}
272
+ `);
122
273
  },
123
274
  });
124
275
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "companionbot",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "AI 친ꡬ ν…”λ ˆκ·Έλž¨ 봇 - Claude API 기반 κ°œμΈν™”λœ λŒ€ν™” μƒλŒ€",
5
5
  "keywords": [
6
6
  "telegram",
@@ -46,10 +46,12 @@
46
46
  "@anthropic-ai/sdk": "^0.39.0",
47
47
  "@googleapis/calendar": "^14.2.0",
48
48
  "@grammyjs/ratelimiter": "^1.2.1",
49
+ "@inquirer/prompts": "^8.2.0",
49
50
  "@xenova/transformers": "^2.17.2",
50
51
  "cheerio": "^1.2.0",
51
52
  "google-auth-library": "^9.15.1",
52
53
  "grammy": "^1.31.0",
54
+ "inquirer": "^13.2.2",
53
55
  "keytar": "^7.9.0",
54
56
  "node-cron": "^4.2.1"
55
57
  },