@airmcp-dev/cli 0.1.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 (122) hide show
  1. package/LICENSE +17 -0
  2. package/dist/commands/add.d.ts +3 -0
  3. package/dist/commands/add.d.ts.map +1 -0
  4. package/dist/commands/add.js +192 -0
  5. package/dist/commands/add.js.map +1 -0
  6. package/dist/commands/check.d.ts +3 -0
  7. package/dist/commands/check.d.ts.map +1 -0
  8. package/dist/commands/check.js +218 -0
  9. package/dist/commands/check.js.map +1 -0
  10. package/dist/commands/connect.d.ts +3 -0
  11. package/dist/commands/connect.d.ts.map +1 -0
  12. package/dist/commands/connect.js +135 -0
  13. package/dist/commands/connect.js.map +1 -0
  14. package/dist/commands/create.d.ts +3 -0
  15. package/dist/commands/create.d.ts.map +1 -0
  16. package/dist/commands/create.js +150 -0
  17. package/dist/commands/create.js.map +1 -0
  18. package/dist/commands/dev.d.ts +3 -0
  19. package/dist/commands/dev.d.ts.map +1 -0
  20. package/dist/commands/dev.js +184 -0
  21. package/dist/commands/dev.js.map +1 -0
  22. package/dist/commands/disconnect.d.ts +3 -0
  23. package/dist/commands/disconnect.d.ts.map +1 -0
  24. package/dist/commands/disconnect.js +69 -0
  25. package/dist/commands/disconnect.js.map +1 -0
  26. package/dist/commands/index.d.ts +13 -0
  27. package/dist/commands/index.d.ts.map +1 -0
  28. package/dist/commands/index.js +16 -0
  29. package/dist/commands/index.js.map +1 -0
  30. package/dist/commands/inspect.d.ts +3 -0
  31. package/dist/commands/inspect.d.ts.map +1 -0
  32. package/dist/commands/inspect.js +159 -0
  33. package/dist/commands/inspect.js.map +1 -0
  34. package/dist/commands/license.d.ts +3 -0
  35. package/dist/commands/license.d.ts.map +1 -0
  36. package/dist/commands/license.js +113 -0
  37. package/dist/commands/license.js.map +1 -0
  38. package/dist/commands/list.d.ts +3 -0
  39. package/dist/commands/list.d.ts.map +1 -0
  40. package/dist/commands/list.js +101 -0
  41. package/dist/commands/list.js.map +1 -0
  42. package/dist/commands/start.d.ts +3 -0
  43. package/dist/commands/start.d.ts.map +1 -0
  44. package/dist/commands/start.js +130 -0
  45. package/dist/commands/start.js.map +1 -0
  46. package/dist/commands/status.d.ts +3 -0
  47. package/dist/commands/status.d.ts.map +1 -0
  48. package/dist/commands/status.js +83 -0
  49. package/dist/commands/status.js.map +1 -0
  50. package/dist/commands/stop.d.ts +3 -0
  51. package/dist/commands/stop.d.ts.map +1 -0
  52. package/dist/commands/stop.js +56 -0
  53. package/dist/commands/stop.js.map +1 -0
  54. package/dist/index.d.ts +3 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +46 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/templates/agent/.ai/context.md +36 -0
  59. package/dist/templates/agent/.vscode/air.code-snippets +178 -0
  60. package/dist/templates/agent/package.json +17 -0
  61. package/dist/templates/agent/src/index.ts +98 -0
  62. package/dist/templates/agent/tsconfig.json +14 -0
  63. package/dist/templates/agent-ko/.ai/context.md +36 -0
  64. package/dist/templates/agent-ko/.vscode/air.code-snippets +178 -0
  65. package/dist/templates/agent-ko/package.json +17 -0
  66. package/dist/templates/agent-ko/src/index.ts +92 -0
  67. package/dist/templates/agent-ko/tsconfig.json +14 -0
  68. package/dist/templates/api/.ai/context.md +36 -0
  69. package/dist/templates/api/.vscode/air.code-snippets +178 -0
  70. package/dist/templates/api/package.json +17 -0
  71. package/dist/templates/api/src/index.ts +76 -0
  72. package/dist/templates/api/tsconfig.json +14 -0
  73. package/dist/templates/api-ko/.ai/context.md +36 -0
  74. package/dist/templates/api-ko/.vscode/air.code-snippets +178 -0
  75. package/dist/templates/api-ko/package.json +17 -0
  76. package/dist/templates/api-ko/src/index.ts +70 -0
  77. package/dist/templates/api-ko/tsconfig.json +14 -0
  78. package/dist/templates/basic/.ai/context.md +36 -0
  79. package/dist/templates/basic/.vscode/air.code-snippets +178 -0
  80. package/dist/templates/basic/package.json +17 -0
  81. package/dist/templates/basic/src/index.ts +39 -0
  82. package/dist/templates/basic/tsconfig.json +15 -0
  83. package/dist/templates/basic-ko/.ai/context.md +36 -0
  84. package/dist/templates/basic-ko/.vscode/air.code-snippets +178 -0
  85. package/dist/templates/basic-ko/package.json +17 -0
  86. package/dist/templates/basic-ko/src/index.ts +39 -0
  87. package/dist/templates/basic-ko/tsconfig.json +14 -0
  88. package/dist/templates/crud/.ai/context.md +36 -0
  89. package/dist/templates/crud/.vscode/air.code-snippets +178 -0
  90. package/dist/templates/crud/package.json +17 -0
  91. package/dist/templates/crud/src/index.ts +82 -0
  92. package/dist/templates/crud/tsconfig.json +14 -0
  93. package/dist/templates/crud-ko/.ai/context.md +36 -0
  94. package/dist/templates/crud-ko/.vscode/air.code-snippets +178 -0
  95. package/dist/templates/crud-ko/package.json +17 -0
  96. package/dist/templates/crud-ko/src/index.ts +81 -0
  97. package/dist/templates/crud-ko/tsconfig.json +14 -0
  98. package/dist/utils/index.d.ts +7 -0
  99. package/dist/utils/index.d.ts.map +1 -0
  100. package/dist/utils/index.js +8 -0
  101. package/dist/utils/index.js.map +1 -0
  102. package/dist/utils/json-editor.d.ts +45 -0
  103. package/dist/utils/json-editor.d.ts.map +1 -0
  104. package/dist/utils/json-editor.js +122 -0
  105. package/dist/utils/json-editor.js.map +1 -0
  106. package/dist/utils/path-resolver.d.ts +30 -0
  107. package/dist/utils/path-resolver.d.ts.map +1 -0
  108. package/dist/utils/path-resolver.js +121 -0
  109. package/dist/utils/path-resolver.js.map +1 -0
  110. package/dist/utils/printer.d.ts +26 -0
  111. package/dist/utils/printer.d.ts.map +1 -0
  112. package/dist/utils/printer.js +65 -0
  113. package/dist/utils/printer.js.map +1 -0
  114. package/dist/utils/process-manager.d.ts +36 -0
  115. package/dist/utils/process-manager.d.ts.map +1 -0
  116. package/dist/utils/process-manager.js +143 -0
  117. package/dist/utils/process-manager.js.map +1 -0
  118. package/dist/utils/test-console.d.ts +8 -0
  119. package/dist/utils/test-console.d.ts.map +1 -0
  120. package/dist/utils/test-console.js +198 -0
  121. package/dist/utils/test-console.js.map +1 -0
  122. package/package.json +52 -0
@@ -0,0 +1,150 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // air CLI — commands/create.ts
3
+ //
4
+ // air create <name> [--template basic|crud|api|agent] [--lang en|ko]
5
+ //
6
+ // 새 MCP 서버 프로젝트를 스캐폴딩한다.
7
+ // 언어를 선택하면 해당 언어의 템플릿(주석/설명)이 적용된다.
8
+ //
9
+ // @example
10
+ // npx air create my-tool
11
+ // npx air create my-tool --lang ko
12
+ // npx air create db-server --template crud --lang en
13
+ import { Command } from 'commander';
14
+ import { cp, readFile, writeFile, access } from 'node:fs/promises';
15
+ import { join, resolve } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { dirname } from 'node:path';
18
+ import { createInterface } from 'node:readline';
19
+ import { printer } from '../utils/printer.js';
20
+ const TEMPLATES = ['basic', 'crud', 'api', 'agent'];
21
+ /** 인터랙티브 언어 선택 */
22
+ async function askLanguage() {
23
+ const rl = createInterface({
24
+ input: process.stdin,
25
+ output: process.stdout,
26
+ });
27
+ return new Promise((resolve) => {
28
+ console.log();
29
+ console.log(' Select language / 언어를 선택하세요:');
30
+ console.log();
31
+ console.log(' 1) English');
32
+ console.log(' 2) 한국어');
33
+ console.log();
34
+ rl.question(' > ', (answer) => {
35
+ rl.close();
36
+ const trimmed = answer.trim();
37
+ if (trimmed === '2' || trimmed.toLowerCase() === 'ko' || trimmed === '한국어') {
38
+ resolve('ko');
39
+ }
40
+ else {
41
+ resolve('en');
42
+ }
43
+ });
44
+ });
45
+ }
46
+ /** 언어별 메시지 */
47
+ const MESSAGES = {
48
+ en: {
49
+ creating: (name) => `Creating MCP server: ${name}`,
50
+ copying: 'Copying template files...',
51
+ configuring: 'Configuring project...',
52
+ done: 'Done!',
53
+ created: (name, template) => `Project "${name}" created with "${template}" template.`,
54
+ nextSteps: 'Next steps:',
55
+ },
56
+ ko: {
57
+ creating: (name) => `MCP 서버 생성: ${name}`,
58
+ copying: '템플릿 파일 복사 중...',
59
+ configuring: '프로젝트 설정 중...',
60
+ done: '완료!',
61
+ created: (name, template) => `"${name}" 프로젝트가 "${template}" 템플릿으로 생성되었습니다.`,
62
+ nextSteps: '다음 단계:',
63
+ },
64
+ };
65
+ /** 템플릿 디렉토리 절대 경로 (빌드 후 dist/ 기준) */
66
+ function templatesRoot() {
67
+ const __filename = fileURLToPath(import.meta.url);
68
+ const __dirname = dirname(__filename);
69
+ return resolve(__dirname, '..', 'templates');
70
+ }
71
+ export const createCommand = new Command('create')
72
+ .description('Create a new MCP server project')
73
+ .argument('<name>', 'Project name (directory name)')
74
+ .option('-t, --template <template>', 'Template to use', 'basic')
75
+ .option('-l, --lang <lang>', 'Language: en | ko')
76
+ .action(async (name, opts) => {
77
+ const template = opts.template;
78
+ // ── 1. 템플릿 유효성 검사 ──
79
+ if (!TEMPLATES.includes(template)) {
80
+ printer.error(`Unknown template "${template}". Available: ${TEMPLATES.join(', ')}`);
81
+ process.exit(1);
82
+ }
83
+ // ── 2. 언어 선택 ──
84
+ let lang;
85
+ if (opts.lang === 'ko' || opts.lang === 'en') {
86
+ lang = opts.lang;
87
+ }
88
+ else {
89
+ lang = await askLanguage();
90
+ }
91
+ const msg = MESSAGES[lang];
92
+ // ── 3. 대상 디렉토리 확인 ──
93
+ const targetDir = resolve(process.cwd(), name);
94
+ try {
95
+ await access(targetDir);
96
+ printer.error(`Directory "${name}" already exists.`);
97
+ process.exit(1);
98
+ }
99
+ catch {
100
+ // 존재하지 않으면 정상
101
+ }
102
+ const totalSteps = 3;
103
+ printer.blank();
104
+ printer.heading(msg.creating(name));
105
+ // ── 4. 언어별 템플릿 디렉토리 결정 ──
106
+ // ko면 basic-ko, en이면 basic
107
+ const templateDirName = lang === 'ko' ? `${template}-ko` : template;
108
+ let templateDir = join(templatesRoot(), templateDirName);
109
+ // 한글 템플릿이 없으면 영어로 폴백
110
+ try {
111
+ await access(templateDir);
112
+ }
113
+ catch {
114
+ templateDir = join(templatesRoot(), template);
115
+ }
116
+ try {
117
+ await access(templateDir);
118
+ }
119
+ catch {
120
+ printer.error(`Template "${template}" not found at ${templateDir}`);
121
+ process.exit(1);
122
+ }
123
+ // ── 5. 템플릿 복사 ──
124
+ printer.step(1, totalSteps, msg.copying);
125
+ await cp(templateDir, targetDir, { recursive: true });
126
+ // ── 6. package.json name 교체 ──
127
+ printer.step(2, totalSteps, msg.configuring);
128
+ const pkgPath = join(targetDir, 'package.json');
129
+ try {
130
+ const raw = await readFile(pkgPath, 'utf-8');
131
+ const pkg = JSON.parse(raw);
132
+ pkg.name = name;
133
+ await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
134
+ }
135
+ catch {
136
+ // package.json이 없는 템플릿이면 스킵
137
+ }
138
+ // ── 7. 완료 안내 ──
139
+ printer.step(3, totalSteps, msg.done);
140
+ printer.blank();
141
+ printer.success(msg.created(name, template));
142
+ printer.blank();
143
+ printer.info(msg.nextSteps);
144
+ printer.blank();
145
+ console.log(` cd ${name}`);
146
+ console.log(' npm install');
147
+ console.log(' air dev');
148
+ printer.blank();
149
+ });
150
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const devCommand: Command;
3
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+CpC,eAAO,MAAM,UAAU,SAwInB,CAAC"}
@@ -0,0 +1,184 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // air CLI — commands/dev.ts
3
+ //
4
+ // air dev [--port <port>] [--transport stdio|http|sse]
5
+ //
6
+ // 개발 모드로 MCP 서버를 실행한다.
7
+ // - 소스 변경 감지 → 자동 재시작 (fs.watch)
8
+ // - 빌드 없이 tsx/ts-node로 직접 실행
9
+ // - 종료 시 graceful shutdown
10
+ //
11
+ // @example
12
+ // air dev
13
+ // air dev --port 3100
14
+ // air dev --transport http
15
+ import { Command } from 'commander';
16
+ import { spawn } from 'node:child_process';
17
+ import { watch } from 'node:fs';
18
+ import { resolve, extname } from 'node:path';
19
+ import { access } from 'node:fs/promises';
20
+ import { printer } from '../utils/printer.js';
21
+ /** 감시 대상 확장자 */
22
+ const WATCH_EXTENSIONS = new Set(['.ts', '.js', '.json']);
23
+ /** 재시작 디바운스 (ms) */
24
+ const DEBOUNCE_MS = 300;
25
+ /**
26
+ * 엔트리 파일을 찾는다.
27
+ * air.config.ts → src/index.ts → index.ts 순서.
28
+ */
29
+ async function findEntry(cwd) {
30
+ const candidates = ['src/index.ts', 'src/index.js', 'index.ts', 'index.js'];
31
+ for (const candidate of candidates) {
32
+ const full = resolve(cwd, candidate);
33
+ try {
34
+ await access(full);
35
+ return full;
36
+ }
37
+ catch {
38
+ continue;
39
+ }
40
+ }
41
+ throw new Error('No entry file found. Expected src/index.ts or index.ts');
42
+ }
43
+ /**
44
+ * tsx로 서버 프로세스를 실행한다.
45
+ * tsx가 없으면 ts-node/esm, 그것도 없으면 node 사용.
46
+ */
47
+ function spawnServer(entry, env, cwd) {
48
+ const child = spawn('npx', ['tsx', entry], {
49
+ cwd,
50
+ stdio: 'inherit',
51
+ env: { ...process.env, ...env },
52
+ shell: true,
53
+ });
54
+ return child;
55
+ }
56
+ export const devCommand = new Command('dev')
57
+ .description('Start MCP server in development mode (hot reload)')
58
+ .option('-p, --port <port>', 'HTTP/SSE port', '3000')
59
+ .option('-t, --transport <type>', 'Transport: stdio | http | sse', 'stdio')
60
+ .option('-c, --console', 'Open interactive test console (requires SSE transport)')
61
+ .action(async (opts) => {
62
+ const cwd = process.cwd();
63
+ // 콘솔 모드는 SSE transport가 필요
64
+ if (opts.console && opts.transport === 'stdio') {
65
+ opts.transport = 'sse';
66
+ printer.info('Console mode requires SSE transport — switching to SSE.');
67
+ }
68
+ // ── 1. 엔트리 파일 찾기 ──
69
+ let entry;
70
+ try {
71
+ entry = await findEntry(cwd);
72
+ }
73
+ catch (err) {
74
+ printer.error(err.message);
75
+ process.exit(1);
76
+ }
77
+ const env = {
78
+ NODE_ENV: 'development',
79
+ AIR_TRANSPORT: opts.transport,
80
+ AIR_PORT: opts.port,
81
+ };
82
+ printer.blank();
83
+ printer.banner('dev');
84
+ printer.kv('entry', entry);
85
+ printer.kv('transport', opts.transport);
86
+ if (opts.transport !== 'stdio') {
87
+ printer.kv('port', opts.port);
88
+ }
89
+ if (opts.console) {
90
+ printer.kv('console', 'enabled');
91
+ }
92
+ printer.blank();
93
+ // ── 2. 서버 시작 ──
94
+ let child = null;
95
+ let restarting = false;
96
+ function startServer() {
97
+ printer.info('Starting server...');
98
+ child = spawnServer(entry, env, cwd);
99
+ child.on('exit', (code, signal) => {
100
+ if (!restarting) {
101
+ if (signal === 'SIGTERM' || signal === 'SIGINT') {
102
+ printer.info('Server stopped.');
103
+ }
104
+ else if (code !== 0) {
105
+ printer.error(`Server exited with code ${code}`);
106
+ }
107
+ }
108
+ child = null;
109
+ });
110
+ }
111
+ function stopServer() {
112
+ return new Promise((resolve) => {
113
+ if (!child) {
114
+ resolve();
115
+ return;
116
+ }
117
+ restarting = true;
118
+ child.once('exit', () => {
119
+ restarting = false;
120
+ resolve();
121
+ });
122
+ child.kill('SIGTERM');
123
+ // 강제 종료 타이머
124
+ setTimeout(() => {
125
+ if (child) {
126
+ child.kill('SIGKILL');
127
+ }
128
+ }, 3000);
129
+ });
130
+ }
131
+ async function restart() {
132
+ printer.blank();
133
+ printer.info('Change detected, restarting...');
134
+ await stopServer();
135
+ startServer();
136
+ }
137
+ startServer();
138
+ // ── 3. 파일 감시 (디바운스) ──
139
+ let debounceTimer = null;
140
+ let watcher = null;
141
+ try {
142
+ const srcDir = resolve(cwd, 'src');
143
+ watcher = watch(srcDir, { recursive: true }, (_event, filename) => {
144
+ if (!filename)
145
+ return;
146
+ const ext = extname(filename);
147
+ if (!WATCH_EXTENSIONS.has(ext))
148
+ return;
149
+ if (debounceTimer)
150
+ clearTimeout(debounceTimer);
151
+ debounceTimer = setTimeout(() => restart(), DEBOUNCE_MS);
152
+ });
153
+ printer.success('Watching src/ for changes...');
154
+ }
155
+ catch {
156
+ printer.warn('Could not watch src/ — hot reload disabled.');
157
+ }
158
+ // ── 4. 테스트 콘솔 (--console) ──
159
+ if (opts.console) {
160
+ // 서버가 뜰 시간 대기
161
+ const { startTestConsole } = await import('../utils/test-console.js');
162
+ await startTestConsole({
163
+ serverUrl: `http://localhost:${opts.port}`,
164
+ onQuit: async () => {
165
+ await shutdown();
166
+ },
167
+ });
168
+ }
169
+ // ── 5. Graceful shutdown ──
170
+ async function shutdown() {
171
+ printer.blank();
172
+ printer.info('Shutting down...');
173
+ if (watcher)
174
+ watcher.close();
175
+ if (debounceTimer)
176
+ clearTimeout(debounceTimer);
177
+ await stopServer();
178
+ process.exit(0);
179
+ }
180
+ process.on('SIGTERM', shutdown);
181
+ process.on('SIGINT', shutdown);
182
+ });
183
+ ;
184
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const disconnectCommand: Command;
3
+ //# sourceMappingURL=disconnect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disconnect.d.ts","sourceRoot":"","sources":["../../src/commands/disconnect.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,eAAO,MAAM,iBAAiB,SA8C1B,CAAC"}
@@ -0,0 +1,69 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // air CLI — commands/disconnect.ts
3
+ //
4
+ // air disconnect <client> [--name <n>]
5
+ //
6
+ // MCP 클라이언트의 설정 파일에서 서버 등록을 제거한다.
7
+ //
8
+ // @example
9
+ // air disconnect claude-desktop
10
+ // air disconnect cursor --name my-db-tool
11
+ import { Command } from 'commander';
12
+ import { resolve } from 'node:path';
13
+ import { readFile } from 'node:fs/promises';
14
+ import { printer } from '../utils/printer.js';
15
+ import { resolveClientConfig, listClients } from '../utils/path-resolver.js';
16
+ import { JsonEditor } from '../utils/json-editor.js';
17
+ /** package.json에서 서버 이름을 읽는다 */
18
+ async function readServerName(cwd) {
19
+ try {
20
+ const raw = await readFile(resolve(cwd, 'package.json'), 'utf-8');
21
+ const pkg = JSON.parse(raw);
22
+ return pkg.name || 'air-server';
23
+ }
24
+ catch {
25
+ return 'air-server';
26
+ }
27
+ }
28
+ export const disconnectCommand = new Command('disconnect')
29
+ .description('Remove this MCP server from a client')
30
+ .argument('<client>', 'Client to disconnect: claude-desktop, cursor, vscode, ...')
31
+ .option('-n, --name <n>', 'Server name to remove (default: from package.json)')
32
+ .action(async (client, opts) => {
33
+ const cwd = process.cwd();
34
+ // ── 1. 클라이언트 경로 해석 ──
35
+ let clientInfo;
36
+ try {
37
+ clientInfo = resolveClientConfig(client);
38
+ }
39
+ catch (err) {
40
+ printer.error(err.message);
41
+ printer.blank();
42
+ printer.info('Available clients:');
43
+ printer.blank();
44
+ printer.list(listClients().map((c) => ({ name: c.id, description: c.name })));
45
+ printer.blank();
46
+ process.exit(1);
47
+ }
48
+ // ── 2. 서버 이름 결정 ──
49
+ const serverName = opts.name || (await readServerName(cwd));
50
+ // ── 3. 설정 파일 로드 ──
51
+ printer.blank();
52
+ printer.step(1, 2, `Loading ${clientInfo.displayName} config...`);
53
+ const editor = await JsonEditor.load(clientInfo.configPath);
54
+ const entryPath = `${clientInfo.mcpKey}.${serverName}`;
55
+ // ── 4. 등록 제거 ──
56
+ if (!editor.has(entryPath)) {
57
+ printer.warn(`"${serverName}" is not registered in ${clientInfo.displayName}.`);
58
+ printer.blank();
59
+ return;
60
+ }
61
+ printer.step(2, 2, `Removing "${serverName}"...`);
62
+ editor.delete(entryPath);
63
+ await editor.save();
64
+ printer.blank();
65
+ printer.success(`Disconnected "${serverName}" from ${clientInfo.displayName}`);
66
+ printer.kv('config', clientInfo.configPath);
67
+ printer.blank();
68
+ });
69
+ //# sourceMappingURL=disconnect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disconnect.js","sourceRoot":"","sources":["../../src/commands/disconnect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export { createCommand } from './create.js';
2
+ export { addCommand } from './add.js';
3
+ export { devCommand } from './dev.js';
4
+ export { startCommand } from './start.js';
5
+ export { stopCommand } from './stop.js';
6
+ export { statusCommand } from './status.js';
7
+ export { listCommand } from './list.js';
8
+ export { inspectCommand } from './inspect.js';
9
+ export { connectCommand } from './connect.js';
10
+ export { disconnectCommand } from './disconnect.js';
11
+ export { checkCommand } from './check.js';
12
+ export { licenseCommand } from './license.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,16 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // air CLI — commands/index.ts
3
+ // re-export only. 로직 없음.
4
+ export { createCommand } from './create.js';
5
+ export { addCommand } from './add.js';
6
+ export { devCommand } from './dev.js';
7
+ export { startCommand } from './start.js';
8
+ export { stopCommand } from './stop.js';
9
+ export { statusCommand } from './status.js';
10
+ export { listCommand } from './list.js';
11
+ export { inspectCommand } from './inspect.js';
12
+ export { connectCommand } from './connect.js';
13
+ export { disconnectCommand } from './disconnect.js';
14
+ export { checkCommand } from './check.js';
15
+ export { licenseCommand } from './license.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,8BAA8B;AAC9B,yBAAyB;AAEzB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const inspectCommand: Command;
3
+ //# sourceMappingURL=inspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../src/commands/inspect.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwEpC,eAAO,MAAM,cAAc,SA2FvB,CAAC"}
@@ -0,0 +1,159 @@
1
+ // Copyright 2026 CodePedia Labs. Licensed under Apache-2.0.
2
+ // air CLI — commands/inspect.ts
3
+ //
4
+ // air inspect <tool>
5
+ //
6
+ // 특정 도구의 상세 스키마를 출력한다.
7
+ // - 파라미터 이름, 타입, 설명, 필수 여부
8
+ // - JSON 스키마 형태로도 출력 가능 (--json)
9
+ //
10
+ // @example
11
+ // air inspect hello
12
+ // air inspect search --json
13
+ import { Command } from 'commander';
14
+ import { resolve } from 'node:path';
15
+ import { access } from 'node:fs/promises';
16
+ import { printer } from '../utils/printer.js';
17
+ /** 엔트리 파일 탐색 */
18
+ async function findEntry(cwd) {
19
+ const candidates = ['src/index.ts', 'src/index.js', 'dist/index.js', 'index.ts', 'index.js'];
20
+ for (const candidate of candidates) {
21
+ const full = resolve(cwd, candidate);
22
+ try {
23
+ await access(full);
24
+ return full;
25
+ }
26
+ catch {
27
+ continue;
28
+ }
29
+ }
30
+ throw new Error('No entry file found. Expected src/index.ts or index.ts');
31
+ }
32
+ /** zod 스키마에서 파라미터 정보를 추출한다 */
33
+ function extractParams(schema) {
34
+ const params = [];
35
+ if (!schema || !schema.shape)
36
+ return params;
37
+ const shape = schema.shape;
38
+ for (const [key, field] of Object.entries(shape)) {
39
+ let type = 'unknown';
40
+ let required = true;
41
+ let description;
42
+ // zod 타입 추출
43
+ if (field?._def) {
44
+ const typeName = field._def.typeName;
45
+ if (typeName === 'ZodString')
46
+ type = 'string';
47
+ else if (typeName === 'ZodNumber')
48
+ type = 'number';
49
+ else if (typeName === 'ZodBoolean')
50
+ type = 'boolean';
51
+ else if (typeName === 'ZodArray')
52
+ type = 'array';
53
+ else if (typeName === 'ZodObject')
54
+ type = 'object';
55
+ else if (typeName === 'ZodEnum')
56
+ type = `enum(${field._def.values?.join('|')})`;
57
+ else if (typeName === 'ZodOptional') {
58
+ required = false;
59
+ // 내부 타입 확인
60
+ const inner = field._def.innerType?._def?.typeName;
61
+ if (inner === 'ZodString')
62
+ type = 'string';
63
+ else if (inner === 'ZodNumber')
64
+ type = 'number';
65
+ else if (inner === 'ZodBoolean')
66
+ type = 'boolean';
67
+ else
68
+ type = inner?.replace('Zod', '').toLowerCase() || 'any';
69
+ }
70
+ description = field._def.description || field.description;
71
+ }
72
+ params.push({ name: key, type, required, description });
73
+ }
74
+ return params;
75
+ }
76
+ export const inspectCommand = new Command('inspect')
77
+ .description("Inspect a tool's schema and parameters")
78
+ .argument('<tool>', 'Tool name to inspect')
79
+ .option('--json', 'Output as JSON schema', false)
80
+ .action(async (toolName, opts) => {
81
+ const cwd = process.cwd();
82
+ // ── 1. 엔트리 로드 ──
83
+ let entry;
84
+ try {
85
+ entry = await findEntry(cwd);
86
+ }
87
+ catch (err) {
88
+ printer.error(err.message);
89
+ process.exit(1);
90
+ }
91
+ let server;
92
+ try {
93
+ const mod = await import(entry);
94
+ server = mod.default || mod;
95
+ }
96
+ catch (err) {
97
+ printer.error(`Failed to load server: ${err.message}`);
98
+ process.exit(1);
99
+ }
100
+ // ── 2. 도구 찾기 ──
101
+ if (typeof server.tools !== 'function') {
102
+ printer.error('Server does not expose tools().');
103
+ process.exit(1);
104
+ }
105
+ const tools = server.tools();
106
+ const tool = tools.find((t) => t.name === toolName);
107
+ if (!tool) {
108
+ printer.error(`Tool "${toolName}" not found.`);
109
+ printer.blank();
110
+ printer.info('Available tools:');
111
+ printer.blank();
112
+ printer.list(tools.map((t) => ({ name: t.name, description: t.description })));
113
+ printer.blank();
114
+ process.exit(1);
115
+ }
116
+ // ── 3. JSON 출력 ──
117
+ if (opts.json) {
118
+ const output = {
119
+ name: tool.name,
120
+ description: tool.description,
121
+ };
122
+ // JSON Schema 변환 시도
123
+ if (tool.schema && typeof tool.schema.toJsonSchema === 'function') {
124
+ output.inputSchema = tool.schema.toJsonSchema();
125
+ }
126
+ else if (tool.jsonSchema) {
127
+ output.inputSchema = tool.jsonSchema;
128
+ }
129
+ else {
130
+ output.inputSchema = null;
131
+ }
132
+ console.log(JSON.stringify(output, null, 2));
133
+ return;
134
+ }
135
+ // ── 4. 사람용 출력 ──
136
+ printer.blank();
137
+ printer.heading(tool.name);
138
+ if (tool.description) {
139
+ printer.kv('description', tool.description);
140
+ }
141
+ // 파라미터 추출
142
+ const params = extractParams(tool.schema);
143
+ if (params.length > 0) {
144
+ printer.blank();
145
+ printer.info(`Parameters (${params.length}):`);
146
+ printer.blank();
147
+ for (const p of params) {
148
+ const req = p.required ? ' *' : '';
149
+ const desc = p.description ? ` ${p.description}` : '';
150
+ console.log(` ${p.name}${req} (${p.type})${desc}`);
151
+ }
152
+ }
153
+ else {
154
+ printer.blank();
155
+ printer.info('No parameters.');
156
+ }
157
+ printer.blank();
158
+ });
159
+ //# sourceMappingURL=inspect.js.map