@cyanheads/mcp-ts-core 0.1.0 → 0.1.2
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/CLAUDE.md +2 -2
- package/README.md +1 -1
- package/dist/cli/init.js +41 -18
- package/dist/cli/init.js.map +1 -1
- package/dist/core/app.d.ts.map +1 -1
- package/dist/core/app.js +16 -3
- package/dist/core/app.js.map +1 -1
- package/dist/mcp-server/transports/http/httpTransport.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/httpTransport.js +4 -2
- package/dist/mcp-server/transports/http/httpTransport.js.map +1 -1
- package/dist/storage/core/storageFactory.d.ts +1 -1
- package/dist/storage/core/storageFactory.d.ts.map +1 -1
- package/dist/storage/core/storageFactory.js +2 -2
- package/dist/storage/core/storageFactory.js.map +1 -1
- package/dist/utils/telemetry/instrumentation.d.ts.map +1 -1
- package/dist/utils/telemetry/instrumentation.js +3 -1
- package/dist/utils/telemetry/instrumentation.js.map +1 -1
- package/package.json +6 -9
- package/scripts/build.ts +129 -0
- package/scripts/clean.ts +90 -0
- package/scripts/devcheck.ts +962 -0
- package/scripts/tree.ts +324 -0
- package/skills/design-mcp-server/SKILL.md +191 -0
- package/skills/setup/SKILL.md +11 -6
- package/templates/AGENTS.md +26 -8
- package/templates/CLAUDE.md +26 -8
- package/templates/_tsconfig.json +2 -22
- package/templates/biome.template.json +1 -41
- package/templates/package.json +33 -11
- package/templates/vitest.config.ts +13 -11
package/scripts/build.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Build script with progress feedback and output stats.
|
|
3
|
+
* @module scripts/build
|
|
4
|
+
*
|
|
5
|
+
* Wraps tsc + tsc-alias with timing, file counts, and size reporting.
|
|
6
|
+
* Exits non-zero on failure with captured compiler output.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // Standard build:
|
|
10
|
+
* // bun run scripts/build.ts
|
|
11
|
+
*
|
|
12
|
+
* // With a specific tsconfig:
|
|
13
|
+
* // bun run scripts/build.ts --project tsconfig.custom.json
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { execFile } from 'node:child_process';
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
19
|
+
import { dirname, join } from 'node:path';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
|
|
22
|
+
const ROOT_DIR = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
23
|
+
const DIST_DIR = join(ROOT_DIR, 'dist');
|
|
24
|
+
|
|
25
|
+
async function exec(
|
|
26
|
+
cmd: string[],
|
|
27
|
+
label: string,
|
|
28
|
+
): Promise<{ ok: boolean; stdout: string; stderr: string; ms: number }> {
|
|
29
|
+
const start = performance.now();
|
|
30
|
+
const [bin, ...args] = cmd;
|
|
31
|
+
|
|
32
|
+
const { stdout, stderr, exitCode } = await new Promise<{
|
|
33
|
+
stdout: string;
|
|
34
|
+
stderr: string;
|
|
35
|
+
exitCode: number;
|
|
36
|
+
}>((resolve) => {
|
|
37
|
+
execFile(bin ?? '', args, { cwd: ROOT_DIR }, (error, stdout, stderr) => {
|
|
38
|
+
resolve({
|
|
39
|
+
stdout: (stdout ?? '').trim(),
|
|
40
|
+
stderr: (stderr ?? '').trim(),
|
|
41
|
+
exitCode: error ? Number(error.code) || 1 : 0,
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const ms = Math.round(performance.now() - start);
|
|
47
|
+
|
|
48
|
+
if (exitCode !== 0) {
|
|
49
|
+
console.error(` \x1b[31m✗ ${label} failed (${ms}ms)\x1b[0m`);
|
|
50
|
+
if (stdout) console.error(stdout);
|
|
51
|
+
if (stderr) console.error(stderr);
|
|
52
|
+
} else {
|
|
53
|
+
console.log(` \x1b[32m✓\x1b[0m ${label} \x1b[2m(${ms}ms)\x1b[0m`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return { ok: exitCode === 0, stdout, stderr, ms };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Recursively count files and total size under a directory. */
|
|
60
|
+
async function dirStats(dir: string): Promise<{ files: number; bytes: number }> {
|
|
61
|
+
let files = 0;
|
|
62
|
+
let bytes = 0;
|
|
63
|
+
try {
|
|
64
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
65
|
+
await Promise.all(
|
|
66
|
+
entries.map(async (entry) => {
|
|
67
|
+
const full = join(dir, entry.name);
|
|
68
|
+
if (entry.isDirectory()) {
|
|
69
|
+
const sub = await dirStats(full);
|
|
70
|
+
files += sub.files;
|
|
71
|
+
bytes += sub.bytes;
|
|
72
|
+
} else {
|
|
73
|
+
files++;
|
|
74
|
+
const s = await stat(full);
|
|
75
|
+
bytes += s.size;
|
|
76
|
+
}
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
} catch {
|
|
80
|
+
// dist doesn't exist yet — fine
|
|
81
|
+
}
|
|
82
|
+
return { files, bytes };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function formatBytes(bytes: number): string {
|
|
86
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
87
|
+
const kb = bytes / 1024;
|
|
88
|
+
if (kb < 1024) return `${kb.toFixed(1)} KB`;
|
|
89
|
+
return `${(kb / 1024).toFixed(1)} MB`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function main() {
|
|
93
|
+
// Read package info
|
|
94
|
+
const pkg = JSON.parse(readFileSync(join(ROOT_DIR, 'package.json'), 'utf-8'));
|
|
95
|
+
const projectIdx = process.argv.indexOf('--project');
|
|
96
|
+
const project =
|
|
97
|
+
projectIdx !== -1
|
|
98
|
+
? (process.argv[projectIdx + 1] ?? 'tsconfig.build.json')
|
|
99
|
+
: 'tsconfig.build.json';
|
|
100
|
+
|
|
101
|
+
console.log(`\x1b[1mBuilding ${pkg.name}@${pkg.version}\x1b[0m`);
|
|
102
|
+
console.log(`\x1b[2m tsconfig: ${project}\x1b[0m`);
|
|
103
|
+
|
|
104
|
+
const totalStart = performance.now();
|
|
105
|
+
|
|
106
|
+
// Step 1: tsc
|
|
107
|
+
const tsc = await exec([join(ROOT_DIR, 'node_modules', '.bin', 'tsc'), '-p', project], 'tsc');
|
|
108
|
+
if (!tsc.ok) process.exit(1);
|
|
109
|
+
|
|
110
|
+
// Step 2: tsc-alias
|
|
111
|
+
const alias = await exec(
|
|
112
|
+
[join(ROOT_DIR, 'node_modules', '.bin', 'tsc-alias'), '-p', project],
|
|
113
|
+
'tsc-alias',
|
|
114
|
+
);
|
|
115
|
+
if (!alias.ok) process.exit(1);
|
|
116
|
+
|
|
117
|
+
const totalMs = Math.round(performance.now() - totalStart);
|
|
118
|
+
|
|
119
|
+
// Output stats
|
|
120
|
+
const stats = await dirStats(DIST_DIR);
|
|
121
|
+
console.log(
|
|
122
|
+
`\n\x1b[32m\x1b[1mBuild complete\x1b[0m \x1b[2m— ${stats.files} files, ${formatBytes(stats.bytes)}, ${totalMs}ms\x1b[0m`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
main().catch((err) => {
|
|
127
|
+
console.error('\x1b[31mBuild script failed:\x1b[0m', err);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
});
|
package/scripts/clean.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Utility script to clean build artifacts and temporary directories.
|
|
3
|
+
* @module scripts/clean
|
|
4
|
+
* By default, it removes the 'dist' and 'logs' directories.
|
|
5
|
+
* Custom directories can be specified as command-line arguments.
|
|
6
|
+
* Works on all platforms using Node.js path normalization.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // Default directories (dist, logs):
|
|
10
|
+
* // bun run scripts/clean.ts
|
|
11
|
+
*
|
|
12
|
+
* // Custom directories:
|
|
13
|
+
* // bun run scripts/clean.ts temp coverage
|
|
14
|
+
*/
|
|
15
|
+
import { rm } from 'node:fs/promises';
|
|
16
|
+
import { resolve, sep } from 'node:path';
|
|
17
|
+
|
|
18
|
+
interface CleanResult {
|
|
19
|
+
dir: string;
|
|
20
|
+
reason?: string;
|
|
21
|
+
status: 'cleaned' | 'skipped' | 'error';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validates that a resolved path stays within the project root.
|
|
26
|
+
* Rejects absolute paths, '..' traversal, and paths that escape cwd.
|
|
27
|
+
*/
|
|
28
|
+
function validatePath(dir: string, root: string): string {
|
|
29
|
+
if (!dir || dir.trim() === '') {
|
|
30
|
+
throw new Error('Empty directory name not allowed');
|
|
31
|
+
}
|
|
32
|
+
if (/^[a-zA-Z]:/.test(dir) || dir.startsWith('/') || dir.startsWith('\\')) {
|
|
33
|
+
throw new Error(`Absolute paths not allowed: ${dir}`);
|
|
34
|
+
}
|
|
35
|
+
if (dir.split(/[/\\]/).includes('..')) {
|
|
36
|
+
throw new Error(`Path traversal not allowed: ${dir}`);
|
|
37
|
+
}
|
|
38
|
+
const resolved = resolve(root, dir);
|
|
39
|
+
if (!resolved.startsWith(root + sep)) {
|
|
40
|
+
throw new Error(`Path escapes project root: ${dir}`);
|
|
41
|
+
}
|
|
42
|
+
return resolved;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const clean = async (): Promise<void> => {
|
|
46
|
+
try {
|
|
47
|
+
const root = process.cwd();
|
|
48
|
+
const args = process.argv.slice(2);
|
|
49
|
+
const dirsToClean = [...new Set(args.length > 0 ? args : ['dist', 'logs', '.tsbuildinfo'])];
|
|
50
|
+
|
|
51
|
+
console.log(`Cleaning directories: ${dirsToClean.join(', ')}`);
|
|
52
|
+
|
|
53
|
+
const results = await Promise.all(
|
|
54
|
+
dirsToClean.map(async (dir): Promise<CleanResult> => {
|
|
55
|
+
try {
|
|
56
|
+
const dirPath = validatePath(dir, root);
|
|
57
|
+
await rm(dirPath, { recursive: true });
|
|
58
|
+
return { dir, status: 'cleaned' };
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
61
|
+
return { dir, status: 'skipped', reason: 'does not exist' };
|
|
62
|
+
}
|
|
63
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
64
|
+
return { dir, status: 'error', reason: message };
|
|
65
|
+
}
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
let hasErrors = false;
|
|
70
|
+
for (const { dir, status, reason } of results) {
|
|
71
|
+
if (status === 'cleaned') {
|
|
72
|
+
console.log(` ✓ ${dir}`);
|
|
73
|
+
} else if (status === 'skipped') {
|
|
74
|
+
console.log(` - ${dir} (${reason})`);
|
|
75
|
+
} else {
|
|
76
|
+
console.error(` ✗ ${dir}: ${reason}`);
|
|
77
|
+
hasErrors = true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (hasErrors) {
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
} catch (error: unknown) {
|
|
85
|
+
console.error('Clean script failed:', error instanceof Error ? error.message : error);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
void clean();
|