@team-semicolon/semo-cli 3.7.4 → 3.8.1
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/dist/index.js +154 -54
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1163,24 +1163,42 @@ async function createStandardSymlinks(cwd) {
|
|
|
1163
1163
|
}
|
|
1164
1164
|
console.log(chalk_1.default.green(` ✓ .claude/skills/ (${skills.length}개 skill 링크됨)`));
|
|
1165
1165
|
}
|
|
1166
|
-
// commands 링크
|
|
1166
|
+
// commands 링크 (개별 파일 심볼릭 링크 방식 - 여러 패키지 지원)
|
|
1167
1167
|
const commandsDir = path.join(claudeDir, "commands");
|
|
1168
1168
|
fs.mkdirSync(commandsDir, { recursive: true });
|
|
1169
|
-
const
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
fs.unlinkSync(semoCommandsLink);
|
|
1169
|
+
const semoCommandsDir = path.join(commandsDir, "SEMO");
|
|
1170
|
+
// 기존 링크/디렉토리가 있으면 삭제 후 재생성
|
|
1171
|
+
if (fs.existsSync(semoCommandsDir)) {
|
|
1172
|
+
if (fs.lstatSync(semoCommandsDir).isSymbolicLink()) {
|
|
1173
|
+
fs.unlinkSync(semoCommandsDir);
|
|
1175
1174
|
}
|
|
1176
1175
|
else {
|
|
1177
|
-
removeRecursive(
|
|
1176
|
+
removeRecursive(semoCommandsDir);
|
|
1178
1177
|
}
|
|
1179
1178
|
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1179
|
+
// SEMO 커맨드 디렉토리 생성 (실제 디렉토리)
|
|
1180
|
+
fs.mkdirSync(semoCommandsDir, { recursive: true });
|
|
1181
|
+
// 커맨드 소스 디렉토리 목록 (semo-core + semo-remote)
|
|
1182
|
+
const commandSources = [
|
|
1183
|
+
{ name: "semo-core", dir: path.join(semoSystemDir, "semo-core", "commands", "SEMO") },
|
|
1184
|
+
{ name: "semo-remote", dir: path.join(semoSystemDir, "semo-remote", "commands", "SEMO") },
|
|
1185
|
+
];
|
|
1186
|
+
let totalCommands = 0;
|
|
1187
|
+
for (const source of commandSources) {
|
|
1188
|
+
if (fs.existsSync(source.dir)) {
|
|
1189
|
+
const commandFiles = fs.readdirSync(source.dir).filter(f => f.endsWith(".md"));
|
|
1190
|
+
for (const cmdFile of commandFiles) {
|
|
1191
|
+
const cmdTarget = path.join(source.dir, cmdFile);
|
|
1192
|
+
const cmdLink = path.join(semoCommandsDir, cmdFile);
|
|
1193
|
+
// 이미 링크가 있으면 건너뛰기 (semo-core 우선)
|
|
1194
|
+
if (!fs.existsSync(cmdLink)) {
|
|
1195
|
+
createSymlinkOrJunction(cmdTarget, cmdLink);
|
|
1196
|
+
totalCommands++;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1183
1200
|
}
|
|
1201
|
+
console.log(chalk_1.default.green(` ✓ .claude/commands/SEMO (${totalCommands}개 command 링크됨)`));
|
|
1184
1202
|
}
|
|
1185
1203
|
/**
|
|
1186
1204
|
* 설치 상태를 검증하고 문제점을 리포트
|
|
@@ -1261,15 +1279,26 @@ function verifyInstallation(cwd, installedExtensions = []) {
|
|
|
1261
1279
|
}
|
|
1262
1280
|
}
|
|
1263
1281
|
}
|
|
1264
|
-
// 4. commands 검증 (
|
|
1265
|
-
const
|
|
1282
|
+
// 4. commands 검증 (디렉토리 또는 개별 파일 심볼릭 링크 방식)
|
|
1283
|
+
const semoCommandsDir = path.join(claudeDir, "commands", "SEMO");
|
|
1266
1284
|
try {
|
|
1267
|
-
const
|
|
1268
|
-
result.stats.commands.exists =
|
|
1269
|
-
if (
|
|
1270
|
-
|
|
1271
|
-
if (
|
|
1272
|
-
|
|
1285
|
+
const dirExists = fs.existsSync(semoCommandsDir);
|
|
1286
|
+
result.stats.commands.exists = dirExists;
|
|
1287
|
+
if (dirExists) {
|
|
1288
|
+
// 디렉토리인 경우: 내부 파일 검증
|
|
1289
|
+
if (fs.lstatSync(semoCommandsDir).isDirectory() && !fs.lstatSync(semoCommandsDir).isSymbolicLink()) {
|
|
1290
|
+
const cmdFiles = fs.readdirSync(semoCommandsDir).filter(f => f.endsWith(".md"));
|
|
1291
|
+
result.stats.commands.valid = cmdFiles.length > 0;
|
|
1292
|
+
if (!result.stats.commands.valid) {
|
|
1293
|
+
result.warnings.push("commands/SEMO 디렉토리가 비어 있습니다");
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
else if (fs.lstatSync(semoCommandsDir).isSymbolicLink()) {
|
|
1297
|
+
// 심볼릭 링크인 경우 (구버전 호환)
|
|
1298
|
+
result.stats.commands.valid = isSymlinkValid(semoCommandsDir);
|
|
1299
|
+
if (!result.stats.commands.valid) {
|
|
1300
|
+
result.warnings.push("깨진 링크: .claude/commands/SEMO");
|
|
1301
|
+
}
|
|
1273
1302
|
}
|
|
1274
1303
|
}
|
|
1275
1304
|
}
|
|
@@ -2968,9 +2997,71 @@ program
|
|
|
2968
2997
|
}
|
|
2969
2998
|
}
|
|
2970
2999
|
}
|
|
2971
|
-
// === 6.
|
|
2972
|
-
|
|
2973
|
-
|
|
3000
|
+
// === 6. semo-hooks 체크 및 업데이트 ===
|
|
3001
|
+
console.log(chalk_1.default.cyan("\n🪝 semo-hooks 상태 확인"));
|
|
3002
|
+
const hooksDir = path.join(semoSystemDir, "semo-hooks");
|
|
3003
|
+
if (!fs.existsSync(hooksDir)) {
|
|
3004
|
+
console.log(chalk_1.default.gray(" ⏭️ semo-hooks 미설치 (선택 패키지)"));
|
|
3005
|
+
console.log(chalk_1.default.gray(" 💡 설치: semo add hooks"));
|
|
3006
|
+
}
|
|
3007
|
+
else {
|
|
3008
|
+
const hooksVersionPath = path.join(hooksDir, "VERSION");
|
|
3009
|
+
const hooksVersion = fs.existsSync(hooksVersionPath)
|
|
3010
|
+
? fs.readFileSync(hooksVersionPath, "utf-8").trim()
|
|
3011
|
+
: "?";
|
|
3012
|
+
console.log(chalk_1.default.green(` ✓ semo-hooks v${hooksVersion} 설치됨`));
|
|
3013
|
+
// hooks 빌드 및 설정 업데이트
|
|
3014
|
+
await setupHooks(cwd, true);
|
|
3015
|
+
}
|
|
3016
|
+
// === 7. semo-mcp 체크 ===
|
|
3017
|
+
console.log(chalk_1.default.cyan("\n📡 semo-mcp 상태 확인"));
|
|
3018
|
+
const userHomeDir2 = process.env.HOME || process.env.USERPROFILE || "";
|
|
3019
|
+
const claudeSettingsPath = path.join(userHomeDir2, ".claude", "settings.local.json");
|
|
3020
|
+
if (!fs.existsSync(claudeSettingsPath)) {
|
|
3021
|
+
console.log(chalk_1.default.gray(" ⏭️ MCP 설정 없음 (선택사항)"));
|
|
3022
|
+
console.log(chalk_1.default.gray(" 💡 장기 기억이 필요하면 settings.local.json 설정 추가"));
|
|
3023
|
+
}
|
|
3024
|
+
else {
|
|
3025
|
+
try {
|
|
3026
|
+
const settings = JSON.parse(fs.readFileSync(claudeSettingsPath, "utf-8"));
|
|
3027
|
+
const mcpServers = settings.mcpServers || {};
|
|
3028
|
+
const semoMcp = mcpServers["semo-integrations"];
|
|
3029
|
+
if (!semoMcp) {
|
|
3030
|
+
console.log(chalk_1.default.gray(" ⏭️ semo-integrations 미등록 (선택사항)"));
|
|
3031
|
+
console.log(chalk_1.default.gray(" 💡 장기 기억/원격 제어가 필요하면 MCP 설정 추가"));
|
|
3032
|
+
}
|
|
3033
|
+
else {
|
|
3034
|
+
console.log(chalk_1.default.green(" ✓ semo-integrations MCP 서버 등록됨"));
|
|
3035
|
+
// v3.0: SEMO_DB_PASSWORD만 체크
|
|
3036
|
+
const env = semoMcp.env || {};
|
|
3037
|
+
if (env["SEMO_DB_PASSWORD"]) {
|
|
3038
|
+
console.log(chalk_1.default.green(" ✓ 장기 기억: 활성화"));
|
|
3039
|
+
}
|
|
3040
|
+
else {
|
|
3041
|
+
console.log(chalk_1.default.gray(" ⏭️ 장기 기억: 비활성화 (SEMO_DB_PASSWORD 미설정)"));
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
catch {
|
|
3046
|
+
console.log(chalk_1.default.yellow(" ⚠ settings.local.json 파싱 오류"));
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
// CLI 도구 체크 (v3.0: 스킬에서 CLI 직접 호출)
|
|
3050
|
+
console.log(chalk_1.default.cyan("\n🔧 CLI 도구 확인"));
|
|
3051
|
+
const cliToolsUpdate = [
|
|
3052
|
+
{ name: "gh", desc: "GitHub CLI" },
|
|
3053
|
+
{ name: "supabase", desc: "Supabase CLI" },
|
|
3054
|
+
];
|
|
3055
|
+
for (const tool of cliToolsUpdate) {
|
|
3056
|
+
try {
|
|
3057
|
+
(0, child_process_1.execSync)(`${tool.name} --version`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
3058
|
+
console.log(chalk_1.default.green(` ✓ ${tool.name} 설치됨`));
|
|
3059
|
+
}
|
|
3060
|
+
catch {
|
|
3061
|
+
console.log(chalk_1.default.yellow(` ⚠ ${tool.name} 미설치 (${tool.desc})`));
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
// === 8. 설치 검증 ===
|
|
2974
3065
|
const verificationResult = verifyInstallation(cwd, installedExtensions);
|
|
2975
3066
|
printVerificationResult(verificationResult);
|
|
2976
3067
|
if (verificationResult.success) {
|
|
@@ -3180,13 +3271,15 @@ program
|
|
|
3180
3271
|
}
|
|
3181
3272
|
}
|
|
3182
3273
|
// 5. semo-mcp (MCP 서버) 상태 확인
|
|
3183
|
-
|
|
3274
|
+
// v3.0: semo-mcp는 Memory + Remote만 제공 (선택사항)
|
|
3275
|
+
// Slack/GitHub/Supabase는 스킬에서 CLI 직접 호출
|
|
3276
|
+
console.log(chalk_1.default.cyan("\n5. semo-mcp (MCP 서버) - 선택사항"));
|
|
3184
3277
|
const userHomeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
3185
3278
|
const claudeSettingsPath = path.join(userHomeDir, ".claude", "settings.local.json");
|
|
3186
3279
|
// MCP 서버 설정 확인
|
|
3187
3280
|
if (!fs.existsSync(claudeSettingsPath)) {
|
|
3188
|
-
console.log(chalk_1.default.
|
|
3189
|
-
console.log(chalk_1.default.gray(" 💡
|
|
3281
|
+
console.log(chalk_1.default.gray(" ⏭️ settings.local.json 없음 (MCP 미사용)"));
|
|
3282
|
+
console.log(chalk_1.default.gray(" 💡 장기 기억이 필요하면 semo-mcp 설정 추가"));
|
|
3190
3283
|
}
|
|
3191
3284
|
else {
|
|
3192
3285
|
try {
|
|
@@ -3195,8 +3288,8 @@ program
|
|
|
3195
3288
|
// semo-integrations MCP 서버 확인
|
|
3196
3289
|
const semoMcp = mcpServers["semo-integrations"];
|
|
3197
3290
|
if (!semoMcp) {
|
|
3198
|
-
console.log(chalk_1.default.
|
|
3199
|
-
console.log(chalk_1.default.gray(" 💡
|
|
3291
|
+
console.log(chalk_1.default.gray(" ⏭️ semo-integrations 미등록 (선택사항)"));
|
|
3292
|
+
console.log(chalk_1.default.gray(" 💡 장기 기억/원격 제어가 필요하면 MCP 설정 추가"));
|
|
3200
3293
|
}
|
|
3201
3294
|
else {
|
|
3202
3295
|
console.log(chalk_1.default.green(" ✅ semo-integrations MCP 서버 등록됨"));
|
|
@@ -3215,37 +3308,25 @@ program
|
|
|
3215
3308
|
console.log(chalk_1.default.red(` ❌ 스크립트 경로 없음: ${scriptPath}`));
|
|
3216
3309
|
}
|
|
3217
3310
|
}
|
|
3218
|
-
// 환경변수 확인
|
|
3311
|
+
// v3.0: 환경변수 체크 - SEMO_DB_PASSWORD만 확인 (장기 기억용)
|
|
3219
3312
|
const env = semoMcp.env || {};
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
const configuredEnvVars = [];
|
|
3223
|
-
for (const envVar of requiredEnvVars) {
|
|
3224
|
-
if (env[envVar]) {
|
|
3225
|
-
configuredEnvVars.push(envVar);
|
|
3226
|
-
}
|
|
3227
|
-
else {
|
|
3228
|
-
missingEnvVars.push(envVar);
|
|
3229
|
-
}
|
|
3230
|
-
}
|
|
3231
|
-
if (configuredEnvVars.length > 0) {
|
|
3232
|
-
console.log(chalk_1.default.green(` ✅ 환경변수: ${configuredEnvVars.join(", ")}`));
|
|
3313
|
+
if (env["SEMO_DB_PASSWORD"]) {
|
|
3314
|
+
console.log(chalk_1.default.green(" ✅ 장기 기억: 활성화 (SEMO_DB_PASSWORD 설정됨)"));
|
|
3233
3315
|
}
|
|
3234
|
-
|
|
3235
|
-
console.log(chalk_1.default.
|
|
3236
|
-
console.log(chalk_1.default.gray(" 💡
|
|
3316
|
+
else {
|
|
3317
|
+
console.log(chalk_1.default.gray(" ⏭️ 장기 기억: 비활성화"));
|
|
3318
|
+
console.log(chalk_1.default.gray(" 💡 SEMO_DB_PASSWORD 설정 시 활성화"));
|
|
3237
3319
|
}
|
|
3238
|
-
// 도구 목록 (
|
|
3239
|
-
const
|
|
3240
|
-
|
|
3241
|
-
"
|
|
3242
|
-
"
|
|
3243
|
-
"
|
|
3244
|
-
|
|
3245
|
-
"
|
|
3246
|
-
"supabase_query",
|
|
3320
|
+
// v3.0: 도구 목록 업데이트 (Memory + Remote만)
|
|
3321
|
+
const v3Tools = [
|
|
3322
|
+
// Memory
|
|
3323
|
+
"semo_remember", "semo_recall", "semo_save_fact",
|
|
3324
|
+
"semo_get_facts", "semo_get_history", "semo_memory_status",
|
|
3325
|
+
"semo_process_embeddings", "semo_recall_smart",
|
|
3326
|
+
// Remote
|
|
3327
|
+
"semo_remote_request", "semo_remote_respond", "semo_remote_pending",
|
|
3247
3328
|
];
|
|
3248
|
-
console.log(chalk_1.default.gray(` 📦 제공 도구: ${
|
|
3329
|
+
console.log(chalk_1.default.gray(` 📦 제공 도구: ${v3Tools.length}개 (Memory ${8}, Remote ${3})`));
|
|
3249
3330
|
}
|
|
3250
3331
|
// 다른 MCP 서버 확인
|
|
3251
3332
|
const otherServers = Object.keys(mcpServers).filter(k => k !== "semo-integrations");
|
|
@@ -3257,6 +3338,25 @@ program
|
|
|
3257
3338
|
console.log(chalk_1.default.red(" ❌ settings.local.json 파싱 오류"));
|
|
3258
3339
|
}
|
|
3259
3340
|
}
|
|
3341
|
+
// 5-1. CLI 도구 확인 (v3.0: 스킬에서 CLI 직접 호출)
|
|
3342
|
+
console.log(chalk_1.default.cyan("\n5-1. CLI 도구 (Skill용)"));
|
|
3343
|
+
const cliTools = [
|
|
3344
|
+
{ name: "gh", desc: "GitHub CLI", check: "gh --version" },
|
|
3345
|
+
{ name: "supabase", desc: "Supabase CLI", check: "supabase --version" },
|
|
3346
|
+
];
|
|
3347
|
+
for (const tool of cliTools) {
|
|
3348
|
+
try {
|
|
3349
|
+
const { execSync } = require("child_process");
|
|
3350
|
+
const version = execSync(tool.check, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n")[0];
|
|
3351
|
+
console.log(chalk_1.default.green(` ✅ ${tool.name}: ${version}`));
|
|
3352
|
+
}
|
|
3353
|
+
catch {
|
|
3354
|
+
console.log(chalk_1.default.yellow(` ⚠️ ${tool.name} 미설치 (${tool.desc})`));
|
|
3355
|
+
console.log(chalk_1.default.gray(` 💡 일부 스킬 기능이 제한될 수 있습니다`));
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
// Slack은 curl로 호출하므로 별도 체크 불필요
|
|
3359
|
+
console.log(chalk_1.default.gray(" ℹ️ Slack: curl 사용 (별도 CLI 불필요)"));
|
|
3260
3360
|
// 6. 전체 설치 검증
|
|
3261
3361
|
console.log(chalk_1.default.cyan("\n6. 전체 설치 검증"));
|
|
3262
3362
|
const verificationResult = verifyInstallation(cwd, []);
|