saeeol 1.0.5 → 1.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "name": "saeeol",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1,14 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── analytics: 사용량 통계 + 모델 테스트 + PR ────────────────────────
4
+ export const analytics: Addon = {
5
+ id: "analytics",
6
+ category: "analytics",
7
+ minTier: "master",
8
+ required: false,
9
+ commands: [
10
+ () => import("../cli/cmd/stats").then((m) => ({ StatsCommand: m.StatsCommand })),
11
+ () => import("../cli/cmd/pr").then((m) => ({ PrCommand: m.PrCommand })),
12
+ () => import("../saeeol/cli/cmd/roll-call").then((m) => ({ RollCallCommand: m.RollCallCommand })),
13
+ ],
14
+ }
@@ -0,0 +1,15 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── core: TUI 채팅 + 프롬프트 실행 ──────────────────────────────────
4
+ export const core: Addon = {
5
+ id: "core",
6
+ category: "core",
7
+ minTier: "light",
8
+ required: true,
9
+ commands: [
10
+ () => import("../cli/cmd/tui/thread").then((m) => ({ TuiThreadCommand: m.TuiThreadCommand })),
11
+ () => import("../cli/cmd/run").then((m) => ({ RunCommand: m.RunCommand })),
12
+ () => import("../cli/cmd/generate").then((m) => ({ GenerateCommand: m.GenerateCommand })),
13
+ () => import("../cli/cmd/session").then((m) => ({ SessionCommand: m.SessionCommand })),
14
+ ],
15
+ }
@@ -0,0 +1,14 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── data: 세션 내보내기/가져오기 + DB ───────────────────────────────
4
+ export const data: Addon = {
5
+ id: "data",
6
+ category: "data",
7
+ minTier: "code",
8
+ required: true,
9
+ commands: [
10
+ () => import("../cli/cmd/export").then((m) => ({ ExportCommand: m.ExportCommand })),
11
+ () => import("../cli/cmd/import").then((m) => ({ ImportCommand: m.ImportCommand })),
12
+ () => import("../cli/cmd/db").then((m) => ({ DbCommand: m.DbCommand })),
13
+ ],
14
+ }
@@ -0,0 +1,13 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── dev: 에이전트 관리 + 디버깅 ─────────────────────────────────────
4
+ export const dev: Addon = {
5
+ id: "dev",
6
+ category: "dev",
7
+ minTier: "code",
8
+ required: false,
9
+ commands: [
10
+ () => import("../cli/cmd/agent").then((m) => ({ AgentCommand: m.AgentCommand })),
11
+ () => import("../cli/cmd/debug").then((m) => ({ DebugCommand: m.DebugCommand })),
12
+ ],
13
+ }
@@ -0,0 +1,13 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── lifecycle: 설치/업그레이드/제거 ──────────────────────────────────
4
+ export const lifecycle: Addon = {
5
+ id: "lifecycle",
6
+ category: "lifecycle",
7
+ minTier: "light",
8
+ required: true,
9
+ commands: [
10
+ () => import("../cli/cmd/upgrade").then((m) => ({ UpgradeCommand: m.UpgradeCommand })),
11
+ () => import("../cli/cmd/uninstall").then((m) => ({ UninstallCommand: m.UninstallCommand })),
12
+ ],
13
+ }
@@ -0,0 +1,15 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── llm: LLM provider 설정 + 모델 관리 ──────────────────────────────
4
+ export const llm: Addon = {
5
+ id: "llm",
6
+ category: "llm",
7
+ minTier: "light",
8
+ required: true,
9
+ commands: [
10
+ () => import("../cli/cmd/init").then((m) => ({ InitCommand: m.InitCommand })),
11
+ () => import("../cli/cmd/providers").then((m) => ({ ProvidersCommand: m.ProvidersCommand })),
12
+ () => import("../cli/cmd/models").then((m) => ({ ModelsCommand: m.ModelsCommand })),
13
+ () => import("../cli/cmd/config").then((m) => ({ ConfigCLICommand: m.ConfigCommand })),
14
+ ],
15
+ }
@@ -0,0 +1,12 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── remote: 실시간 세션 릴레이 ──────────────────────────────────────
4
+ export const remote: Addon = {
5
+ id: "remote",
6
+ category: "remote",
7
+ minTier: "master",
8
+ required: false,
9
+ commands: [
10
+ () => import("../cli/cmd/remote").then((m) => ({ RemoteCommand: m.RemoteCommand })),
11
+ ],
12
+ }
@@ -0,0 +1,14 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── server: headless 서버 + 원격 연결 + ACP ─────────────────────────
4
+ export const server: Addon = {
5
+ id: "server",
6
+ category: "server",
7
+ minTier: "code",
8
+ required: true,
9
+ commands: [
10
+ () => import("../cli/cmd/serve").then((m) => ({ ServeCommand: m.ServeCommand })),
11
+ () => import("../cli/cmd/tui/attach").then((m) => ({ AttachCommand: m.AttachCommand })),
12
+ () => import("../cli/cmd/acp").then((m) => ({ AcpCommand: m.AcpCommand })),
13
+ ],
14
+ }
@@ -0,0 +1,13 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── tools: MCP + 플러그인 시스템 ────────────────────────────────────
4
+ export const tools: Addon = {
5
+ id: "tools",
6
+ category: "tools",
7
+ minTier: "code",
8
+ required: true,
9
+ commands: [
10
+ () => import("../cli/cmd/mcp").then((m) => ({ McpCommand: m.McpCommand })),
11
+ () => import("../cli/cmd/plug").then((m) => ({ PluginCommand: m.PluginCommand })),
12
+ ],
13
+ }
@@ -0,0 +1,12 @@
1
+ import type { Addon } from "./types"
2
+
3
+ // ── web: 브라우저 채팅 UI ───────────────────────────────────────────
4
+ export const web: Addon = {
5
+ id: "web",
6
+ category: "web",
7
+ minTier: "master",
8
+ required: true,
9
+ commands: [
10
+ () => import("../cli/cmd/web").then((m) => ({ WebCommand: m.WebCommand })),
11
+ ],
12
+ }
@@ -0,0 +1,65 @@
1
+ import type { Addon, Tier } from "./types"
2
+ import { core } from "./addon-core"
3
+ import { llm } from "./addon-llm"
4
+ import { lifecycle } from "./addon-lifecycle"
5
+ import { server } from "./addon-server"
6
+ import { tools } from "./addon-tools"
7
+ import { data } from "./addon-data"
8
+ import { dev } from "./addon-dev"
9
+ import { web } from "./addon-web"
10
+ import { remote } from "./addon-remote"
11
+ import { analytics } from "./addon-analytics"
12
+
13
+ // ╔══════════════════════════════════════════════════════════════════╗
14
+ // ║ 애드온 레지스트리 ║
15
+ // ║ ║
16
+ // ║ LIGHT = core + llm + lifecycle (3 addons, 10 cmd) ║
17
+ // ║ CODE = LIGHT + server + tools + data + dev (8 addons, 20 cmd) ║
18
+ // ║ MASTER = CODE + web + remote + analytics (11 addons, 24 cmd)║
19
+ // ╚══════════════════════════════════════════════════════════════════╝
20
+
21
+ export const allAddons: Addon[] = [
22
+ // LIGHT
23
+ core, // TUI 채팅, run, generate, session
24
+ llm, // init, auth, models, config
25
+ lifecycle, // upgrade, uninstall
26
+
27
+ // CODE
28
+ server, // serve, attach, acp
29
+ tools, // mcp, plugin
30
+ data, // export, import, db
31
+ dev, // agent, debug
32
+
33
+ // MASTER
34
+ web, // web UI
35
+ remote, // real-time relay
36
+ analytics, // stats, pr, roll-call
37
+ ]
38
+
39
+ const tierPriority: Record<Tier, number> = { light: 0, code: 1, master: 2 }
40
+
41
+ export function addonsForTier(tier: Tier): Addon[] {
42
+ return allAddons.filter((a) => tierPriority[tier] >= tierPriority[a.minTier])
43
+ }
44
+
45
+ export async function commandsForTier(tier: Tier): Promise<any[]> {
46
+ const addons = addonsForTier(tier)
47
+ const commands: any[] = []
48
+ for (const addon of addons) {
49
+ for (const loader of addon.commands) {
50
+ const mod = await loader()
51
+ commands.push(...Object.values(mod))
52
+ }
53
+ }
54
+ return commands
55
+ }
56
+
57
+ export function manifest(tier: Tier) {
58
+ const addons = addonsForTier(tier)
59
+ return addons.map((a) => ({
60
+ id: a.id,
61
+ category: a.category,
62
+ commands: a.commands.length,
63
+ required: a.required,
64
+ }))
65
+ }
@@ -0,0 +1,31 @@
1
+ // ╔══════════════════════════════════════════════════════════════════╗
2
+ // ║ SAEEOL 애드온 시스템 ║
3
+ // ║ ║
4
+ // ║ 원자 단위 기능 → 애드온 → 티어별 자동 활성화 ║
5
+ // ║ ║
6
+ // ║ LIGHT = core + llm + lifecycle ║
7
+ // ║ CODE = LIGHT + server + tools + data + dev ║
8
+ // ║ MASTER = CODE + web + remote + analytics ║
9
+ // ╚══════════════════════════════════════════════════════════════════╝
10
+
11
+ export type Tier = "light" | "code" | "master"
12
+
13
+ export interface Addon {
14
+ /** 애드온 ID */
15
+ id: string
16
+ /** 분류 */
17
+ category: "core" | "llm" | "lifecycle" | "server" | "tools" | "data" | "web" | "remote" | "analytics" | "dev"
18
+ /** 포함 명령어 */
19
+ commands: (() => Promise<Record<string, any>>)[]
20
+ /** 필요 티어 (이 티어부터 활성화) */
21
+ minTier: Tier
22
+ /** 필수/선택 */
23
+ required: boolean
24
+ }
25
+
26
+ // 티어 우선순위
27
+ const tierPriority: Record<Tier, number> = { light: 0, code: 1, master: 2 }
28
+
29
+ export function tierActive(addon: Addon, tier: Tier): boolean {
30
+ return tierPriority[tier] >= tierPriority[addon.minTier]
31
+ }
package/src/index.ts CHANGED
@@ -1,68 +1,97 @@
1
1
  import yargs from "yargs"
2
2
  import { hideBin } from "yargs/helpers"
3
+
4
+ // ╔══════════════════════════════════════════════════════════════════╗
5
+ // ║ SAEEOL CLI — 애드온 아키텍처 ║
6
+ // ║ ║
7
+ // ║ 원자 단위 애드온 → 티어별 자동 활성화 ║
8
+ // ║ ║
9
+ // ║ LIGHT = core + llm + lifecycle ║
10
+ // ║ CODE = LIGHT + server + tools + data + dev ║
11
+ // ║ MASTER = CODE + web + remote + analytics ║
12
+ // ╚══════════════════════════════════════════════════════════════════╝
13
+
14
+ // ── LIGHT: core ────────────────────────────────────────────────────
15
+ import { TuiThreadCommand } from "./cli/cmd/tui/thread"
3
16
  import { RunCommand } from "./cli/cmd/run"
4
17
  import { GenerateCommand } from "./cli/cmd/generate"
5
- import * as Log from "@saeeol/core/util/log"
6
- // import { LoginCommand, LogoutCommand, SwitchCommand, OrgsCommand } from "./cli/cmd/account"
7
- // import { ConsoleCommand } from "./cli/cmd/account"
8
- import { ConsoleCommand } from "./cli/cmd/account"
18
+ import { SessionCommand } from "./cli/cmd/session"
19
+
20
+ // ── LIGHT: llm ─────────────────────────────────────────────────────
21
+ import { InitCommand } from "./cli/cmd/init"
9
22
  import { ProvidersCommand } from "./cli/cmd/providers"
10
- import { AgentCommand } from "./cli/cmd/agent"
23
+ import { ModelsCommand } from "./cli/cmd/models"
24
+ import { ConfigCommand as ConfigCLICommand } from "./cli/cmd/config"
25
+
26
+ // ── LIGHT: lifecycle ───────────────────────────────────────────────
11
27
  import { UpgradeCommand } from "./cli/cmd/upgrade"
12
28
  import { UninstallCommand } from "./cli/cmd/uninstall"
13
- import { ModelsCommand } from "./cli/cmd/models"
29
+
30
+ // ── CODE: server ───────────────────────────────────────────────────
31
+ import { ServeCommand } from "./cli/cmd/serve"
32
+ import { AttachCommand } from "./cli/cmd/tui/attach"
33
+ import { AcpCommand } from "./cli/cmd/acp"
34
+
35
+ // ── CODE: tools ────────────────────────────────────────────────────
36
+ import { McpCommand } from "./cli/cmd/mcp"
37
+ import { PluginCommand } from "./cli/cmd/plug"
38
+
39
+ // ── CODE: data ─────────────────────────────────────────────────────
40
+ import { ExportCommand } from "./cli/cmd/export"
41
+ import { ImportCommand } from "./cli/cmd/import"
42
+ import { DbCommand } from "./cli/cmd/db"
43
+
44
+ // ── CODE: dev (선택) ───────────────────────────────────────────────
45
+ import { AgentCommand } from "./cli/cmd/agent"
46
+ import { DebugCommand } from "./cli/cmd/debug"
47
+
48
+ // ── MASTER: web ────────────────────────────────────────────────────
49
+ import { WebCommand } from "./cli/cmd/web"
50
+
51
+ // ── MASTER: remote (선택) ──────────────────────────────────────────
52
+ import { RemoteCommand } from "./cli/cmd/remote"
53
+
54
+ // ── MASTER: analytics (선택) ───────────────────────────────────────
55
+ import { StatsCommand } from "./cli/cmd/stats"
56
+ import { PrCommand } from "./cli/cmd/pr"
57
+ import { RollCallCommand } from "./saeeol/cli/cmd/roll-call"
58
+
59
+ // ── DEV 전용 ───────────────────────────────────────────────────────
60
+ import { DevSetupCommand, DevAliasCommand } from "./saeeol/cli/dev-setup"
61
+
62
+ // ── 공통 ────────────────────────────────────────────────────────────
63
+ import * as Log from "@saeeol/core/util/log"
14
64
  import { UI } from "./cli/ui"
15
65
  import { Installation } from "./installation"
16
66
  import { InstallationBuildKind, InstallationVersion } from "@saeeol/core/installation/version"
17
67
  import { NamedError } from "@saeeol/core/util/error"
18
68
  import { FormatError } from "./cli/error"
19
- import { ServeCommand } from "./cli/cmd/serve"
20
69
  import { Filesystem } from "@/util/filesystem"
21
- import { ConfigCommand as ConfigCLICommand } from "./cli/cmd/config"
22
- import { DebugCommand } from "./cli/cmd/debug"
23
- import { StatsCommand } from "./cli/cmd/stats"
24
- import { McpCommand } from "./cli/cmd/mcp"
25
- // import { GithubCommand } from "./cli/cmd/github"
26
- import { ExportCommand } from "./cli/cmd/export"
27
- import { ImportCommand } from "./cli/cmd/import"
28
- import { AttachCommand } from "./cli/cmd/tui/attach"
29
- import { TuiThreadCommand } from "./cli/cmd/tui/thread"
30
- import { AcpCommand } from "./cli/cmd/acp"
31
70
  import { EOL } from "os"
32
- // import { WebCommand } from "./cli/cmd/web"
33
- import { PrCommand } from "./cli/cmd/pr"
34
- import { SessionCommand } from "./cli/cmd/session"
35
- import { RemoteCommand } from "./cli/cmd/remote"
36
- import { RollCallCommand } from "./saeeol/cli/cmd/roll-call"
37
- import { DevSetupCommand, DevAliasCommand } from "./saeeol/cli/dev-setup"
38
- import { WebCommand } from "./cli/cmd/web"
39
71
  import { Telemetry } from "@saeeol/telemetry"
40
72
  import { InstanceStore } from "./project/instance-store"
41
73
  import { migrateLegacySaeeolAuth, ENV_FEATURE, ENV_VERSION } from "@saeeol/gateway"
42
- // (extension, cloud) which set their own SAEEOL_FEATURE env var. Direct CLI use
43
- // (any command other than 'serve') is tagged as 'cli'. If 'serve' is spawned without
44
- // the env var, it gets 'unknown' so the misconfiguration is visible in data.
45
- if (!process.env[ENV_FEATURE]) {
46
- const isServe = process.argv.includes("serve")
47
- process.env[ENV_FEATURE] = isServe ? "unknown" : "cli"
48
- }
49
- if (!process.env[ENV_VERSION]) {
50
- process.env[ENV_VERSION] = InstallationVersion
51
- }
52
74
  import { Config } from "./config/config"
53
75
  import { Auth } from "./auth"
54
- import { DbCommand } from "./cli/cmd/db"
55
76
  import path from "path"
56
77
  import { Global } from "@saeeol/core/global"
57
78
  import { createHelpCommand } from "./saeeol/help-command"
58
79
  import { JsonMigration } from "@/storage/json-migration"
59
80
  import { Database } from "@/storage/db"
60
81
  import { errorMessage } from "./util/error"
61
- import { PluginCommand } from "./cli/cmd/plug"
62
- import { InitCommand } from "./cli/cmd/init"
63
82
  import { Heap } from "./cli/heap"
64
83
  import { drizzle } from "drizzle-orm/bun-sqlite"
65
84
  import { ensureProcessMetadata } from "@saeeol/core/util/saeeol-process"
85
+ import type { Tier } from "./addons/types"
86
+ import { addonsForTier, manifest } from "./addons/registry"
87
+
88
+ if (!process.env[ENV_FEATURE]) {
89
+ const isServe = process.argv.includes("serve")
90
+ process.env[ENV_FEATURE] = isServe ? "unknown" : "cli"
91
+ }
92
+ if (!process.env[ENV_VERSION]) {
93
+ process.env[ENV_VERSION] = InstallationVersion
94
+ }
66
95
 
67
96
  const processMetadata = ensureProcessMetadata("main")
68
97
 
@@ -205,38 +234,71 @@ let cli = yargs(args)
205
234
  })
206
235
  .usage("")
207
236
  .completion("completion", "generate shell completion script")
208
- .command(AcpCommand)
209
- .command(McpCommand)
210
- .command(TuiThreadCommand)
211
- .command(AttachCommand)
212
- .command(RunCommand)
213
- .command(GenerateCommand)
214
- .command(DebugCommand)
215
- // .command(LoginCommand)
216
- // .command(LogoutCommand)
217
- // .command(SwitchCommand)
218
- // .command(OrgsCommand)
219
- // .command(ConsoleCommand)
220
- .command(ProvidersCommand)
221
- .command(AgentCommand)
222
- .command(UpgradeCommand)
223
- .command(UninstallCommand)
224
- .command(ServeCommand)
225
- .command(WebCommand)
226
- // .command(WebCommand)
227
- .command(ModelsCommand)
228
- .command(RollCallCommand)
229
- .command(StatsCommand)
230
- .command(ExportCommand)
231
- .command(ImportCommand)
232
- // .command(GithubCommand)
233
- .command(PrCommand)
234
- .command(SessionCommand)
235
- .command(RemoteCommand)
236
- .command(ConfigCLICommand)
237
- .command(PluginCommand)
238
- .command(InitCommand)
239
- .command(DbCommand)
237
+
238
+ // ════════════════════════════════════════════════════════════════
239
+ // LIGHT: core (TUI 채팅 + 프롬프트 + 세션)
240
+ // ════════════════════════════════════════════════════════════════
241
+ .command(TuiThreadCommand) // [default] TUI 채팅
242
+ .command(RunCommand) // run 프롬프트 실행
243
+ .command(GenerateCommand) // generate 코드 생성
244
+ .command(SessionCommand) // session 세션 관리
245
+
246
+ // ════════════════════════════════════════════════════════════════
247
+ // LIGHT: llm (provider + 모델 + 설정)
248
+ // ════════════════════════════════════════════════════════════════
249
+ .command(InitCommand) // init 최초 설정
250
+ .command(ProvidersCommand) // auth provider 인증
251
+ .command(ModelsCommand) // models 모델 목록
252
+ .command(ConfigCLICommand) // config 설정 관리
253
+
254
+ // ════════════════════════════════════════════════════════════════
255
+ // LIGHT: lifecycle (설치/업그레이드/제거)
256
+ // ════════════════════════════════════════════════════════════════
257
+ .command(UpgradeCommand) // upgrade 버전 업그레이드
258
+ .command(UninstallCommand) // uninstall 제거
259
+
260
+ // ════════════════════════════════════════════════════════════════
261
+ // CODE: server (headless + 원격 + ACP)
262
+ // ════════════════════════════════════════════════════════════════
263
+ .command(ServeCommand) // serve headless 서버
264
+ .command(AttachCommand) // attach 원격 연결
265
+ .command(AcpCommand) // acp ACP 서버
266
+
267
+ // ════════════════════════════════════════════════════════════════
268
+ // CODE: tools (MCP + 플러그인)
269
+ // ════════════════════════════════════════════════════════════════
270
+ .command(McpCommand) // mcp MCP 서버 관리
271
+ .command(PluginCommand) // plugin 플러그인
272
+
273
+ // ════════════════════════════════════════════════════════════════
274
+ // CODE: data (export + import + db)
275
+ // ════════════════════════════════════════════════════════════════
276
+ .command(ExportCommand) // export 세션 내보내기
277
+ .command(ImportCommand) // import 세션 가져오기
278
+ .command(DbCommand) // db 데이터베이스
279
+
280
+ // ════════════════════════════════════════════════════════════════
281
+ // CODE: dev (선택)
282
+ // ════════════════════════════════════════════════════════════════
283
+ .command(AgentCommand) // agent 에이전트 관리
284
+ .command(DebugCommand) // debug 디버깅
285
+
286
+ // ════════════════════════════════════════════════════════════════
287
+ // MASTER: web (브라우저 채팅 UI)
288
+ // ════════════════════════════════════════════════════════════════
289
+ .command(WebCommand) // web 웹 UI + 브라우저
290
+
291
+ // ════════════════════════════════════════════════════════════════
292
+ // MASTER: remote (선택)
293
+ // ════════════════════════════════════════════════════════════════
294
+ .command(RemoteCommand) // remote 실시간 릴레이
295
+
296
+ // ════════════════════════════════════════════════════════════════
297
+ // MASTER: analytics (선택)
298
+ // ════════════════════════════════════════════════════════════════
299
+ .command(StatsCommand) // stats 사용량 통계
300
+ .command(PrCommand) // pr GitHub PR
301
+ .command(RollCallCommand) // roll-call 모델 연결 테스트
240
302
  if (InstallationBuildKind !== "release") {
241
303
  cli = cli.command(DevSetupCommand).command(DevAliasCommand)
242
304
  }