@team-semicolon/semo-cli 3.0.15 → 3.0.17
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 +164 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -59,7 +59,7 @@ const child_process_1 = require("child_process");
|
|
|
59
59
|
const fs = __importStar(require("fs"));
|
|
60
60
|
const path = __importStar(require("path"));
|
|
61
61
|
const os = __importStar(require("os"));
|
|
62
|
-
const VERSION = "3.0.
|
|
62
|
+
const VERSION = "3.0.17";
|
|
63
63
|
const PACKAGE_NAME = "@team-semicolon/semo-cli";
|
|
64
64
|
// === 버전 비교 유틸리티 ===
|
|
65
65
|
/**
|
|
@@ -103,6 +103,134 @@ function isVersionLower(current, latest) {
|
|
|
103
103
|
return true;
|
|
104
104
|
return false;
|
|
105
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* GitHub raw URL에서 패키지 버전 가져오기
|
|
108
|
+
*/
|
|
109
|
+
async function getRemotePackageVersion(packagePath) {
|
|
110
|
+
try {
|
|
111
|
+
const url = `https://raw.githubusercontent.com/semicolon-devteam/semo/main/packages/${packagePath}/VERSION`;
|
|
112
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
|
|
113
|
+
if (!response.ok)
|
|
114
|
+
return null;
|
|
115
|
+
const version = await response.text();
|
|
116
|
+
return version.trim();
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* semo-core/semo-skills 원격 버전 가져오기
|
|
124
|
+
*/
|
|
125
|
+
async function getRemoteCoreVersion(type) {
|
|
126
|
+
try {
|
|
127
|
+
const url = `https://raw.githubusercontent.com/semicolon-devteam/semo/main/${type}/VERSION`;
|
|
128
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
|
|
129
|
+
if (!response.ok)
|
|
130
|
+
return null;
|
|
131
|
+
const version = await response.text();
|
|
132
|
+
return version.trim();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* init/update 시작 시 버전 비교 결과 출력
|
|
140
|
+
*/
|
|
141
|
+
async function showVersionComparison(cwd) {
|
|
142
|
+
console.log(chalk_1.default.cyan("📊 버전 확인\n"));
|
|
143
|
+
const spinner = (0, ora_1.default)(" 버전 정보 조회 중...").start();
|
|
144
|
+
try {
|
|
145
|
+
// 1. CLI 버전 비교
|
|
146
|
+
const currentCliVersion = VERSION;
|
|
147
|
+
const latestCliVersion = await getLatestVersion();
|
|
148
|
+
// 2. semo-core, semo-skills 버전 비교
|
|
149
|
+
const semoSystemDir = path.join(cwd, "semo-system");
|
|
150
|
+
const hasSemoSystem = fs.existsSync(semoSystemDir);
|
|
151
|
+
const versionInfos = [];
|
|
152
|
+
// CLI
|
|
153
|
+
versionInfos.push({
|
|
154
|
+
name: "semo-cli (npm)",
|
|
155
|
+
local: currentCliVersion,
|
|
156
|
+
remote: latestCliVersion,
|
|
157
|
+
needsUpdate: latestCliVersion ? isVersionLower(currentCliVersion, latestCliVersion) : false,
|
|
158
|
+
});
|
|
159
|
+
if (hasSemoSystem) {
|
|
160
|
+
// semo-core는 semo-system 바깥에 있음
|
|
161
|
+
const corePath = path.join(cwd, "semo-core", "VERSION");
|
|
162
|
+
const localCore = fs.existsSync(corePath) ? fs.readFileSync(corePath, "utf-8").trim() : null;
|
|
163
|
+
const remoteCore = await getRemoteCoreVersion("semo-core");
|
|
164
|
+
if (localCore) {
|
|
165
|
+
versionInfos.push({
|
|
166
|
+
name: "semo-core",
|
|
167
|
+
local: localCore,
|
|
168
|
+
remote: remoteCore,
|
|
169
|
+
needsUpdate: remoteCore ? isVersionLower(localCore, remoteCore) : false,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// semo-skills
|
|
173
|
+
const skillsPath = path.join(cwd, "semo-skills", "VERSION");
|
|
174
|
+
const localSkills = fs.existsSync(skillsPath) ? fs.readFileSync(skillsPath, "utf-8").trim() : null;
|
|
175
|
+
const remoteSkills = await getRemoteCoreVersion("semo-skills");
|
|
176
|
+
if (localSkills) {
|
|
177
|
+
versionInfos.push({
|
|
178
|
+
name: "semo-skills",
|
|
179
|
+
local: localSkills,
|
|
180
|
+
remote: remoteSkills,
|
|
181
|
+
needsUpdate: remoteSkills ? isVersionLower(localSkills, remoteSkills) : false,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// Extensions (semo-system 내부)
|
|
185
|
+
for (const key of Object.keys(EXTENSION_PACKAGES)) {
|
|
186
|
+
const extVersionPath = path.join(semoSystemDir, key, "VERSION");
|
|
187
|
+
if (fs.existsSync(extVersionPath)) {
|
|
188
|
+
const localExt = fs.readFileSync(extVersionPath, "utf-8").trim();
|
|
189
|
+
const remoteExt = await getRemotePackageVersion(key);
|
|
190
|
+
versionInfos.push({
|
|
191
|
+
name: key,
|
|
192
|
+
local: localExt,
|
|
193
|
+
remote: remoteExt,
|
|
194
|
+
needsUpdate: remoteExt ? isVersionLower(localExt, remoteExt) : false,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
spinner.stop();
|
|
200
|
+
// 결과 출력
|
|
201
|
+
const needsUpdateCount = versionInfos.filter(v => v.needsUpdate).length;
|
|
202
|
+
console.log(chalk_1.default.gray(" ┌────────────────────────┬──────────┬──────────┬────────┐"));
|
|
203
|
+
console.log(chalk_1.default.gray(" │ 패키지 │ 설치됨 │ 최신 │ 상태 │"));
|
|
204
|
+
console.log(chalk_1.default.gray(" ├────────────────────────┼──────────┼──────────┼────────┤"));
|
|
205
|
+
for (const info of versionInfos) {
|
|
206
|
+
const name = info.name.padEnd(22);
|
|
207
|
+
const local = (info.local || "-").padEnd(8);
|
|
208
|
+
const remote = (info.remote || "-").padEnd(8);
|
|
209
|
+
const status = info.needsUpdate
|
|
210
|
+
? chalk_1.default.yellow("⬆ 업데이트")
|
|
211
|
+
: chalk_1.default.green("✓ 최신");
|
|
212
|
+
if (info.needsUpdate) {
|
|
213
|
+
console.log(chalk_1.default.yellow(` │ ${name} │ ${local} │ ${remote} │ ${status} │`));
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
console.log(chalk_1.default.gray(` │ ${name} │ ${local} │ ${remote} │ `) + status + chalk_1.default.gray(" │"));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
console.log(chalk_1.default.gray(" └────────────────────────┴──────────┴──────────┴────────┘"));
|
|
220
|
+
if (needsUpdateCount > 0) {
|
|
221
|
+
console.log(chalk_1.default.yellow(`\n ⚠ ${needsUpdateCount}개 패키지 업데이트 가능`));
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
console.log(chalk_1.default.green("\n ✓ 모든 패키지가 최신 버전입니다"));
|
|
225
|
+
}
|
|
226
|
+
console.log("");
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
spinner.fail(" 버전 정보 조회 실패");
|
|
230
|
+
console.log(chalk_1.default.gray(` ${error}`));
|
|
231
|
+
console.log("");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
106
234
|
// === Windows 지원 유틸리티 ===
|
|
107
235
|
const isWindows = os.platform() === "win32";
|
|
108
236
|
/**
|
|
@@ -420,7 +548,9 @@ program
|
|
|
420
548
|
console.log(chalk_1.default.cyan.bold("\n🚀 SEMO 설치 시작\n"));
|
|
421
549
|
console.log(chalk_1.default.gray("Gemini 하이브리드 전략: White Box + Black Box\n"));
|
|
422
550
|
const cwd = process.cwd();
|
|
423
|
-
// 0.
|
|
551
|
+
// 0. 버전 비교
|
|
552
|
+
await showVersionComparison(cwd);
|
|
553
|
+
// 1. 필수 도구 확인
|
|
424
554
|
const shouldContinue = await showToolsStatus();
|
|
425
555
|
if (!shouldContinue) {
|
|
426
556
|
console.log(chalk_1.default.yellow("\n설치가 취소되었습니다. 필수 도구 설치 후 다시 시도하세요.\n"));
|
|
@@ -1625,6 +1755,35 @@ async function setupClaudeMd(cwd, extensions, force) {
|
|
|
1625
1755
|
console.log(chalk_1.default.gray(` + ${pkg}/CLAUDE.md 병합됨`));
|
|
1626
1756
|
}
|
|
1627
1757
|
}
|
|
1758
|
+
// 4. Orchestrator 참조 경로 결정 (Extension 패키지 우선)
|
|
1759
|
+
// Extension 패키지 중 orchestrator가 있는 첫 번째 패키지를 Primary로 설정
|
|
1760
|
+
let primaryOrchestratorPath = "semo-core/agents/orchestrator/orchestrator.md";
|
|
1761
|
+
const orchestratorPaths = [];
|
|
1762
|
+
for (const pkg of extensions) {
|
|
1763
|
+
const pkgOrchestratorPath = path.join(semoSystemDir, pkg, "agents/orchestrator/orchestrator.md");
|
|
1764
|
+
if (fs.existsSync(pkgOrchestratorPath)) {
|
|
1765
|
+
orchestratorPaths.push(`semo-system/${pkg}/agents/orchestrator/orchestrator.md`);
|
|
1766
|
+
// 첫 번째 Extension 패키지의 orchestrator를 Primary로 설정
|
|
1767
|
+
if (primaryOrchestratorPath === "semo-core/agents/orchestrator/orchestrator.md") {
|
|
1768
|
+
primaryOrchestratorPath = `${pkg}/agents/orchestrator/orchestrator.md`;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
// semo-core orchestrator는 항상 포함
|
|
1773
|
+
orchestratorPaths.unshift("semo-system/semo-core/agents/orchestrator/orchestrator.md");
|
|
1774
|
+
// Orchestrator 참조 섹션 생성
|
|
1775
|
+
const orchestratorRefSection = orchestratorPaths.length > 1
|
|
1776
|
+
? `**Primary Orchestrator**: \`semo-system/${primaryOrchestratorPath}\`
|
|
1777
|
+
|
|
1778
|
+
> Extension 패키지가 설치되어 해당 패키지의 Orchestrator를 우선 참조합니다.
|
|
1779
|
+
|
|
1780
|
+
**모든 Orchestrator 파일** (라우팅 테이블 병합됨):
|
|
1781
|
+
${orchestratorPaths.map(p => `- \`${p}\``).join("\n")}
|
|
1782
|
+
|
|
1783
|
+
이 파일들에서 라우팅 테이블, 의도 분류, 메시지 포맷을 확인하세요.`
|
|
1784
|
+
: `**반드시 읽어야 할 파일**: \`semo-system/semo-core/agents/orchestrator/orchestrator.md\`
|
|
1785
|
+
|
|
1786
|
+
이 파일에서 라우팅 테이블, 의도 분류, 메시지 포맷을 확인하세요.`;
|
|
1628
1787
|
const claudeMdContent = `# SEMO Project Configuration
|
|
1629
1788
|
|
|
1630
1789
|
> SEMO (Semicolon Orchestrate) - AI Agent Orchestration Framework v${VERSION}
|
|
@@ -1654,9 +1813,7 @@ async function setupClaudeMd(cwd, extensions, force) {
|
|
|
1654
1813
|
|
|
1655
1814
|
### Orchestrator 참조
|
|
1656
1815
|
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
이 파일에서 라우팅 테이블, 의도 분류, 메시지 포맷을 확인하세요.
|
|
1816
|
+
${orchestratorRefSection}
|
|
1660
1817
|
|
|
1661
1818
|
---
|
|
1662
1819
|
|
|
@@ -1972,6 +2129,8 @@ program
|
|
|
1972
2129
|
const cwd = process.cwd();
|
|
1973
2130
|
const semoSystemDir = path.join(cwd, "semo-system");
|
|
1974
2131
|
const claudeDir = path.join(cwd, ".claude");
|
|
2132
|
+
// 0. 버전 비교
|
|
2133
|
+
await showVersionComparison(cwd);
|
|
1975
2134
|
// --only 옵션 파싱
|
|
1976
2135
|
const onlyPackages = options.only
|
|
1977
2136
|
? options.only.split(",").map((p) => p.trim())
|