mobilecoder-mcp 2.1.0 → 2.1.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/cli.js +1 -1
- package/package.json +2 -2
- package/src/agent.ts +0 -384
- package/src/cli.ts +0 -35
- package/src/types.d.ts +0 -8
- package/tsconfig.json +0 -28
package/dist/cli.js
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mobilecoder-mcp",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Secure Zero-Knowledge Terminal Relay for MobileCoder",
|
|
5
5
|
"main": "dist/agent.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"mobilecoder-mcp": "
|
|
7
|
+
"mobilecoder-mcp": "dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node dist/cli.js",
|
package/src/agent.ts
DELETED
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { io, Socket } from 'socket.io-client';
|
|
3
|
-
import * as os from 'os';
|
|
4
|
-
import * as pty from 'node-pty';
|
|
5
|
-
import * as crypto from 'crypto';
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import ora from 'ora';
|
|
8
|
-
import * as fs from 'fs';
|
|
9
|
-
import * as path from 'path';
|
|
10
|
-
|
|
11
|
-
// 🚨 BURAYI KENDİ DOMAIN ADRESİNLE DEĞİŞTİR!
|
|
12
|
-
const RELAY_SERVER_URL = 'https://api.mobilecoder.xyz';
|
|
13
|
-
|
|
14
|
-
// Security Constants
|
|
15
|
-
const PBKDF2_ITERATIONS = 100000;
|
|
16
|
-
const KEY_LENGTH = 32; // 256 bits
|
|
17
|
-
const SALT = 'mobilecoder-salt-v2';
|
|
18
|
-
const KEY_ROTATION_INTERVAL = 600000; // 10 minutes
|
|
19
|
-
const MESSAGE_MAX_AGE = 300000; // 5 minutes
|
|
20
|
-
|
|
21
|
-
export class ZKRelayAgent {
|
|
22
|
-
private socket: Socket;
|
|
23
|
-
private ptyProcess: any;
|
|
24
|
-
private secretCode: string;
|
|
25
|
-
private roomId: string;
|
|
26
|
-
|
|
27
|
-
// 🔐 Güçlendirilmiş Güvenlik Değişkenleri
|
|
28
|
-
private masterKey: Buffer;
|
|
29
|
-
private sessionKey: Buffer;
|
|
30
|
-
private sessionCounter: number = 0;
|
|
31
|
-
private seenNonces: Set<string> = new Set();
|
|
32
|
-
private nonceCleanupInterval: NodeJS.Timeout | null = null;
|
|
33
|
-
private keyRotationInterval: NodeJS.Timeout | null = null;
|
|
34
|
-
|
|
35
|
-
private spinner = ora('Initializing Secure Tunnel...');
|
|
36
|
-
|
|
37
|
-
constructor() {
|
|
38
|
-
this.setupSecurity();
|
|
39
|
-
this.initPTY();
|
|
40
|
-
this.connectToRelay();
|
|
41
|
-
this.startSecurityMaintenance();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 1. Güvenlik Katmanı: PBKDF2 ile Güçlendirilmiş Anahtar Türetme
|
|
45
|
-
private setupSecurity() {
|
|
46
|
-
// 6 Haneli rastgele kod (Kullanıcının göreceği)
|
|
47
|
-
const randomNum = Math.floor(100000 + Math.random() * 900000);
|
|
48
|
-
this.secretCode = randomNum.toString();
|
|
49
|
-
|
|
50
|
-
// Oda ID'si: Kodun Hash'i (Sunucu sadece bunu görür, kodu göremez)
|
|
51
|
-
this.roomId = crypto.createHash('sha256').update(this.secretCode).digest('hex');
|
|
52
|
-
|
|
53
|
-
// 🔐 PBKDF2 ile Master Key Türetme (Brute-force'a karşı savunma)
|
|
54
|
-
this.masterKey = crypto.pbkdf2Sync(
|
|
55
|
-
this.secretCode,
|
|
56
|
-
SALT,
|
|
57
|
-
PBKDF2_ITERATIONS,
|
|
58
|
-
KEY_LENGTH,
|
|
59
|
-
'sha256'
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
// Session Key (PFS için rotasyonlu)
|
|
63
|
-
this.sessionKey = this.deriveSessionKey(0);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// 🔐 Session Key Türetme (Perfect Forward Secrecy)
|
|
67
|
-
private deriveSessionKey(counter: number): Buffer {
|
|
68
|
-
return crypto.pbkdf2Sync(
|
|
69
|
-
this.masterKey,
|
|
70
|
-
`session-${counter}`,
|
|
71
|
-
10000,
|
|
72
|
-
KEY_LENGTH,
|
|
73
|
-
'sha256'
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// 🔄 Key Rotation (Her 10 dakikada bir)
|
|
78
|
-
private rotateKey() {
|
|
79
|
-
this.sessionCounter++;
|
|
80
|
-
this.sessionKey = this.deriveSessionKey(this.sessionCounter);
|
|
81
|
-
console.log(chalk.cyan(`🔄 Session key rotated to #${this.sessionCounter}`));
|
|
82
|
-
|
|
83
|
-
// Notify peer about key rotation
|
|
84
|
-
this.sendSecurePayload('key_rotation', { counter: this.sessionCounter });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// 🧹 Güvenlik Bakımı
|
|
88
|
-
private startSecurityMaintenance() {
|
|
89
|
-
// Nonce temizliği (5 dakikadan eski nonce'ları sil)
|
|
90
|
-
this.nonceCleanupInterval = setInterval(() => {
|
|
91
|
-
this.seenNonces.clear();
|
|
92
|
-
}, MESSAGE_MAX_AGE);
|
|
93
|
-
|
|
94
|
-
// Key rotation
|
|
95
|
-
this.keyRotationInterval = setInterval(() => {
|
|
96
|
-
this.rotateKey();
|
|
97
|
-
}, KEY_ROTATION_INTERVAL);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// 2. Terminal (PTY) Başlatma
|
|
101
|
-
private initPTY() {
|
|
102
|
-
const shell = os.platform() === 'win32' ? 'powershell.exe' : (process.env.SHELL || 'bash');
|
|
103
|
-
|
|
104
|
-
this.ptyProcess = pty.spawn(shell, [], {
|
|
105
|
-
name: 'xterm-256color',
|
|
106
|
-
cols: 80,
|
|
107
|
-
rows: 24,
|
|
108
|
-
cwd: process.cwd(),
|
|
109
|
-
env: process.env
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// Terminalden çıkan veriyi şifrele ve yolla
|
|
113
|
-
this.ptyProcess.onData((data: string) => {
|
|
114
|
-
this.sendSecurePayload('term_data', data);
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// 3. Relay Sunucusuna Bağlanma
|
|
119
|
-
private connectToRelay() {
|
|
120
|
-
this.spinner.start('Connecting to MobileCoder Relay Network...');
|
|
121
|
-
|
|
122
|
-
this.socket = io(RELAY_SERVER_URL, {
|
|
123
|
-
transports: ['websocket'], // Hız için sadece websocket
|
|
124
|
-
reconnection: true,
|
|
125
|
-
reconnectionAttempts: Infinity
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
this.socket.on('connect', () => {
|
|
129
|
-
this.spinner.succeed(chalk.green('Connected to Relay Node!'));
|
|
130
|
-
|
|
131
|
-
// Odaya Katıl (Sadece Hash ID gönderilir)
|
|
132
|
-
this.socket.emit('join_room', { code: this.roomId, type: 'agent' });
|
|
133
|
-
|
|
134
|
-
this.printBanner();
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
this.socket.on('disconnect', () => {
|
|
138
|
-
this.spinner.warn(chalk.yellow('Connection lost. Reconnecting...'));
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// Mobilden biri bağlandığında
|
|
142
|
-
this.socket.on('peer_joined', () => {
|
|
143
|
-
console.log(chalk.green('\n📱 Mobile Client Connected via Encrypted Tunnel!'));
|
|
144
|
-
this.sendEnvInfo();
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// Mobilden şifreli veri geldiğinde
|
|
148
|
-
this.socket.on('relay_data', (message: { room: string, payload: any }) => {
|
|
149
|
-
this.handleIncomingMessage(message as any);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// Also listen for connect_error
|
|
153
|
-
this.socket.on('connect_error', (err) => {
|
|
154
|
-
// console.error(err);
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 🔐 AES-256-CBC ile Şifreleme (Nonce tabanlı)
|
|
159
|
-
private encrypt(data: string): { nonce: string; data: string; timestamp: number } {
|
|
160
|
-
const nonce = crypto.randomBytes(16);
|
|
161
|
-
const cipher = crypto.createCipheriv('aes-256-cbc', this.sessionKey, nonce);
|
|
162
|
-
|
|
163
|
-
const encrypted = Buffer.concat([
|
|
164
|
-
cipher.update(data, 'utf8'),
|
|
165
|
-
cipher.final()
|
|
166
|
-
]);
|
|
167
|
-
|
|
168
|
-
return {
|
|
169
|
-
nonce: nonce.toString('base64'),
|
|
170
|
-
data: encrypted.toString('base64'),
|
|
171
|
-
timestamp: Date.now()
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// 🔐 AES-256-CBC ile Şifre Çözme (Replay Attack Korumalı)
|
|
176
|
-
private decrypt(packet: { nonce: string; data: string; timestamp: number }): string {
|
|
177
|
-
// Timestamp kontrolü (5 dakikadan eski mesajları reddet)
|
|
178
|
-
if (Date.now() - packet.timestamp > MESSAGE_MAX_AGE) {
|
|
179
|
-
throw new Error('Message too old - potential replay attack');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Nonce uniqueness kontrolü (Replay attack önleme)
|
|
183
|
-
if (this.seenNonces.has(packet.nonce)) {
|
|
184
|
-
throw new Error('Replay attack detected - duplicate nonce');
|
|
185
|
-
}
|
|
186
|
-
this.seenNonces.add(packet.nonce);
|
|
187
|
-
|
|
188
|
-
const decipher = crypto.createDecipheriv(
|
|
189
|
-
'aes-256-cbc',
|
|
190
|
-
this.sessionKey,
|
|
191
|
-
Buffer.from(packet.nonce, 'base64')
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
return Buffer.concat([
|
|
195
|
-
decipher.update(Buffer.from(packet.data, 'base64')),
|
|
196
|
-
decipher.final()
|
|
197
|
-
]).toString('utf8');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Gelen veriyi çöz ve işle
|
|
201
|
-
private handleIncomingMessage(encryptedPayload: any) {
|
|
202
|
-
try {
|
|
203
|
-
let decryptedText: string;
|
|
204
|
-
|
|
205
|
-
// Yeni format: { nonce, data, timestamp }
|
|
206
|
-
if (typeof encryptedPayload === 'object' && encryptedPayload.nonce) {
|
|
207
|
-
decryptedText = this.decrypt(encryptedPayload);
|
|
208
|
-
}
|
|
209
|
-
// Legacy format: { e: ciphertext } (CryptoJS uyumluluğu)
|
|
210
|
-
else if (typeof encryptedPayload === 'object' && encryptedPayload.e) {
|
|
211
|
-
// Legacy CryptoJS decrypt fallback
|
|
212
|
-
const CryptoJS = require('crypto-js');
|
|
213
|
-
const bytes = CryptoJS.AES.decrypt(encryptedPayload.e, this.secretCode);
|
|
214
|
-
decryptedText = bytes.toString(CryptoJS.enc.Utf8);
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (!decryptedText) return;
|
|
221
|
-
|
|
222
|
-
// Veri JSON mu? (Resize komutu vs olabilir)
|
|
223
|
-
try {
|
|
224
|
-
const cmd = JSON.parse(decryptedText);
|
|
225
|
-
|
|
226
|
-
// Handle key rotation from peer
|
|
227
|
-
if (cmd.type === 'key_rotation') {
|
|
228
|
-
this.sessionCounter = cmd.counter;
|
|
229
|
-
this.sessionKey = this.deriveSessionKey(this.sessionCounter);
|
|
230
|
-
console.log(chalk.cyan(`🔄 Key synced to session #${this.sessionCounter}`));
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// 1. Terminal Input (Keystrokes)
|
|
235
|
-
if (cmd.type === 'input') {
|
|
236
|
-
this.ptyProcess.write(cmd.data);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// 2. Terminal Resize
|
|
241
|
-
if (cmd.type === 'resize') {
|
|
242
|
-
this.ptyProcess.resize(cmd.cols, cmd.rows);
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// 3. Chat Commands (e.g. "ls -la")
|
|
247
|
-
if (cmd.type === 'command') {
|
|
248
|
-
this.ptyProcess.write(cmd.text + '\r');
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// 4. CLI Tool/Button Commands (e.g. "git status")
|
|
253
|
-
if (cmd.type === 'cli_command') {
|
|
254
|
-
this.ptyProcess.write(cmd.command + '\r');
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// 5. Tool Calls (File System Access)
|
|
259
|
-
if (cmd.type === 'tool_call') {
|
|
260
|
-
this.handleToolCall(cmd.tool, cmd.data, cmd.id);
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
} catch (e) {
|
|
265
|
-
// JSON değilse saf terminal girdisidir
|
|
266
|
-
this.ptyProcess.write(decryptedText);
|
|
267
|
-
}
|
|
268
|
-
} catch (error) {
|
|
269
|
-
// Şifre çözülemezse (Yanlış anahtar vb.) sessizce yut
|
|
270
|
-
console.error(chalk.red('Decryption failed:'), (error as Error).message);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
private async handleToolCall(tool: string, args: any, id: string) {
|
|
275
|
-
try {
|
|
276
|
-
let result: any = null;
|
|
277
|
-
|
|
278
|
-
if (tool === 'list_directory') {
|
|
279
|
-
const dirPath = args.path ? path.resolve(args.path) : process.cwd();
|
|
280
|
-
const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
|
|
281
|
-
|
|
282
|
-
const files = entries.map(entry => ({
|
|
283
|
-
name: entry.name,
|
|
284
|
-
type: entry.isDirectory() ? 'directory' : 'file',
|
|
285
|
-
size: 0 // Simplification for speed
|
|
286
|
-
}));
|
|
287
|
-
|
|
288
|
-
result = { files };
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
else if (tool === 'read_file') {
|
|
292
|
-
const filePath = path.resolve(args.path);
|
|
293
|
-
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
294
|
-
result = { content };
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
throw new Error(`Unknown tool: ${tool}`);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
this.sendSecurePayload('tool_result', {
|
|
301
|
-
id,
|
|
302
|
-
result
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
} catch (error: any) {
|
|
306
|
-
this.sendSecurePayload('tool_result', {
|
|
307
|
-
id,
|
|
308
|
-
error: error.message,
|
|
309
|
-
type: 'error'
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Veriyi şifrele ve gönder
|
|
315
|
-
private sendSecurePayload(type: string, data: any) {
|
|
316
|
-
let payloadStr = '';
|
|
317
|
-
|
|
318
|
-
if (type === 'meta' || type === 'tool_result' || type === 'key_rotation') {
|
|
319
|
-
// Standardize format
|
|
320
|
-
if (type === 'tool_result') {
|
|
321
|
-
if (data.type === 'error') {
|
|
322
|
-
payloadStr = JSON.stringify({ ...data });
|
|
323
|
-
} else {
|
|
324
|
-
payloadStr = JSON.stringify({ type: 'result', ...data });
|
|
325
|
-
}
|
|
326
|
-
} else if (type === 'key_rotation') {
|
|
327
|
-
payloadStr = JSON.stringify({ type: 'key_rotation', ...data });
|
|
328
|
-
} else {
|
|
329
|
-
payloadStr = JSON.stringify(data);
|
|
330
|
-
}
|
|
331
|
-
} else if (type === 'term_data') {
|
|
332
|
-
// Wrap output in { type: 'output', data: ... }
|
|
333
|
-
if (typeof data === 'string') {
|
|
334
|
-
payloadStr = JSON.stringify({ type: 'output', data: data });
|
|
335
|
-
} else {
|
|
336
|
-
payloadStr = JSON.stringify(data);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Fallback if empty (shouldn't happen with above logic)
|
|
341
|
-
if (!payloadStr) payloadStr = JSON.stringify(data);
|
|
342
|
-
|
|
343
|
-
// 🔐 Yeni şifreleme formatı ile gönder
|
|
344
|
-
const encrypted = this.encrypt(payloadStr);
|
|
345
|
-
|
|
346
|
-
this.socket.emit('relay_data', {
|
|
347
|
-
room: this.roomId,
|
|
348
|
-
payload: encrypted
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
private sendEnvInfo() {
|
|
353
|
-
const info = {
|
|
354
|
-
type: 'host_info',
|
|
355
|
-
username: os.userInfo().username,
|
|
356
|
-
hostname: os.hostname(),
|
|
357
|
-
platform: os.platform(),
|
|
358
|
-
cwd: process.cwd()
|
|
359
|
-
};
|
|
360
|
-
this.sendSecurePayload('meta', info);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
private printBanner() {
|
|
364
|
-
console.log('\n' + chalk.bgBlue.bold(' MOBILECODER ZK-RELAY v2.1.0 '));
|
|
365
|
-
console.log(chalk.gray('🔐 PBKDF2-SHA256 + AES-256-CBC + Nonce-Based Replay Protection'));
|
|
366
|
-
console.log(chalk.gray('🔄 Perfect Forward Secrecy with 10-min Key Rotation\n'));
|
|
367
|
-
|
|
368
|
-
console.log(chalk.yellow('┌──────────────────────────────────────┐'));
|
|
369
|
-
console.log(chalk.yellow('│ 🔑 CONNECTION CODE (ENTER ON APP) │'));
|
|
370
|
-
console.log(chalk.yellow('│ │'));
|
|
371
|
-
console.log(chalk.yellow(`│ ${chalk.white.bold.bgBlack(` ${this.secretCode.slice(0, 3)} - ${this.secretCode.slice(3)} `)} │`));
|
|
372
|
-
console.log(chalk.yellow('│ │'));
|
|
373
|
-
console.log(chalk.yellow('└──────────────────────────────────────┘'));
|
|
374
|
-
console.log(chalk.cyan('\nWaiting for mobile connection...'));
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Cleanup
|
|
378
|
-
public destroy() {
|
|
379
|
-
if (this.nonceCleanupInterval) clearInterval(this.nonceCleanupInterval);
|
|
380
|
-
if (this.keyRotationInterval) clearInterval(this.keyRotationInterval);
|
|
381
|
-
if (this.socket) this.socket.disconnect();
|
|
382
|
-
if (this.ptyProcess) this.ptyProcess.kill();
|
|
383
|
-
}
|
|
384
|
-
}
|
package/src/cli.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
import { ZKRelayAgent } from './agent.js';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
|
|
6
|
-
const program = new Command();
|
|
7
|
-
|
|
8
|
-
program
|
|
9
|
-
.name('mobilecoder-mcp')
|
|
10
|
-
.description('MobileCoder Desktop Agent - ZK-Relay Edition')
|
|
11
|
-
.version('2.0.0');
|
|
12
|
-
|
|
13
|
-
program
|
|
14
|
-
.command('init')
|
|
15
|
-
.description('Start the secure relay agent')
|
|
16
|
-
.action(() => {
|
|
17
|
-
try {
|
|
18
|
-
new ZKRelayAgent();
|
|
19
|
-
} catch (error) {
|
|
20
|
-
console.error(chalk.red('Fatal Error:'), error);
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Varsayılan komut (argüman girilmezse init çalışsın)
|
|
26
|
-
if (!process.argv.slice(2).length) {
|
|
27
|
-
try {
|
|
28
|
-
new ZKRelayAgent();
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.error(chalk.red('Fatal Error:'), error);
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
program.parse(process.argv);
|
|
35
|
-
}
|
package/src/types.d.ts
DELETED
package/tsconfig.json
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": [
|
|
7
|
-
"ES2022"
|
|
8
|
-
],
|
|
9
|
-
"outDir": "./dist",
|
|
10
|
-
"rootDir": "./src",
|
|
11
|
-
"strict": false,
|
|
12
|
-
"noImplicitAny": false,
|
|
13
|
-
"esModuleInterop": true,
|
|
14
|
-
"skipLibCheck": true,
|
|
15
|
-
"forceConsistentCasingInFileNames": true,
|
|
16
|
-
"resolveJsonModule": true,
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"declarationMap": true,
|
|
19
|
-
"sourceMap": true
|
|
20
|
-
},
|
|
21
|
-
"include": [
|
|
22
|
-
"src/**/*"
|
|
23
|
-
],
|
|
24
|
-
"exclude": [
|
|
25
|
-
"node_modules",
|
|
26
|
-
"dist"
|
|
27
|
-
]
|
|
28
|
-
}
|