create-glosc 0.4.0 → 0.4.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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["import prompts from \"prompts\";\r\nimport * as path from \"node:path\";\r\nimport * as os from \"node:os\";\r\nimport { scaffoldProject } from \"./scaffold\";\r\n\r\ntype Language = \"python\" | \"typescript\";\r\n\r\ntype ProjectOptions = {\r\n projectName: string;\r\n description: string;\r\n author: string;\r\n language: Language;\r\n mainFileName: string;\r\n readme: boolean;\r\n license: boolean;\r\n};\r\n\r\ntype ParsedArgs = {\r\n defaults: boolean;\r\n language?: string;\r\n mainFileName?: string;\r\n description?: string;\r\n author?: string;\r\n readme?: boolean;\r\n license?: boolean;\r\n projectName?: string;\r\n};\r\n\r\nfunction parseArgs(argv: string[]): ParsedArgs {\r\n const result: ParsedArgs = {\r\n defaults: false,\r\n language: undefined,\r\n mainFileName: undefined,\r\n description: undefined,\r\n author: undefined,\r\n readme: undefined,\r\n license: undefined,\r\n projectName: undefined,\r\n };\r\n\r\n const args = Array.from(argv);\r\n\r\n for (let i = 0; i < args.length; i++) {\r\n const a = args[i];\r\n if (!a) continue;\r\n\r\n if (a === \"--defaults\" || a === \"--yes\" || a === \"-y\") {\r\n result.defaults = true;\r\n continue;\r\n }\r\n\r\n if (a === \"--no-readme\") {\r\n result.readme = false;\r\n continue;\r\n }\r\n\r\n if (a === \"--readme\") {\r\n result.readme = true;\r\n continue;\r\n }\r\n\r\n if (a === \"--no-license\") {\r\n result.license = false;\r\n continue;\r\n }\r\n\r\n if (a === \"--license\") {\r\n result.license = true;\r\n continue;\r\n }\r\n\r\n if (a === \"--language\" && i + 1 < args.length) {\r\n result.language = args[++i];\r\n continue;\r\n }\r\n\r\n if (a === \"--main\" && i + 1 < args.length) {\r\n result.mainFileName = args[++i];\r\n continue;\r\n }\r\n\r\n if (a === \"--description\" && i + 1 < args.length) {\r\n result.description = args[++i];\r\n continue;\r\n }\r\n\r\n if (a === \"--author\" && i + 1 < args.length) {\r\n result.author = args[++i];\r\n continue;\r\n }\r\n\r\n if (!a.startsWith(\"-\") && !result.projectName) {\r\n result.projectName = a;\r\n continue;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction normalizeLanguage(value: unknown): Language | undefined {\r\n const v = String(value || \"\")\r\n .trim()\r\n .toLowerCase();\r\n if (v === \"py\" || v === \"python\") return \"python\";\r\n if (v === \"ts\" || v === \"typescript\") return \"typescript\";\r\n if (v === \"js\" || v === \"javascript\") {\r\n throw new Error(\r\n \"JavaScript template has been removed. Use --language typescript (or omit --language) instead.\"\r\n );\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction normalizeMainFileName(\r\n language: Language,\r\n mainFileNameRaw: unknown\r\n): string {\r\n const trimmed = String(mainFileNameRaw || \"\").trim();\r\n const defaultExt = language === \"python\" ? \".py\" : \".ts\";\r\n const base =\r\n trimmed.length > 0\r\n ? trimmed\r\n : language === \"python\"\r\n ? \"main.py\"\r\n : \"index.ts\";\r\n\r\n if (path.extname(base)) return base;\r\n return `${base}${defaultExt}`;\r\n}\r\n\r\nfunction normalizeProjectName(value: unknown): string {\r\n return String(value || \"\")\r\n .trim()\r\n .replace(/\\s+/g, \"-\");\r\n}\r\n\r\nfunction getDefaultAuthor(): string {\r\n const candidates = [\r\n process.env.GIT_AUTHOR_NAME,\r\n process.env.GIT_COMMITTER_NAME,\r\n process.env.USER,\r\n process.env.USERNAME,\r\n process.env.LOGNAME,\r\n ];\r\n\r\n for (const c of candidates) {\r\n const v = String(c || \"\").trim();\r\n if (v) return v;\r\n }\r\n\r\n try {\r\n const u = os.userInfo();\r\n const name = String(u?.username || \"\").trim();\r\n if (name) return name;\r\n } catch {\r\n // ignore\r\n }\r\n\r\n return \"Your Name\";\r\n}\r\n\r\nasync function run(): Promise<void> {\r\n const argv = process.argv.slice(2);\r\n const args = parseArgs(argv);\r\n\r\n if (args.defaults) {\r\n if (!args.projectName) {\r\n throw new Error(\r\n \"Project name is required (e.g. `npm create glosc@latest my-app -- --defaults`)\"\r\n );\r\n }\r\n\r\n const language = normalizeLanguage(args.language) || \"typescript\";\r\n\r\n const options: ProjectOptions = {\r\n projectName: normalizeProjectName(args.projectName),\r\n description: String(\r\n args.description || \"A brief description of your project\"\r\n ).trim(),\r\n author: String(args.author || getDefaultAuthor()).trim(),\r\n language,\r\n mainFileName: normalizeMainFileName(language, args.mainFileName),\r\n readme: args.readme !== undefined ? Boolean(args.readme) : true,\r\n license: args.license !== undefined ? Boolean(args.license) : true,\r\n };\r\n\r\n await scaffoldProject(options);\r\n return;\r\n }\r\n\r\n // allow `npm create ... <name>` to prefill\r\n prompts.override({\r\n projectName: args.projectName,\r\n author: args.author,\r\n });\r\n\r\n let selectedLanguage: Language | undefined;\r\n\r\n const response = await prompts(\r\n [\r\n {\r\n type: \"text\",\r\n name: \"projectName\",\r\n message: \"Project name:\",\r\n validate: (value: string) => {\r\n const name = String(value || \"\").trim();\r\n if (!name) return \"Project name is required\";\r\n if (name.includes(\"/\") || name.includes(\"\\\\\"))\r\n return \"Project name cannot include path separators\";\r\n return true;\r\n },\r\n },\r\n {\r\n type: \"text\",\r\n name: \"description\",\r\n message: \"Description:\",\r\n initial: \"A brief description of your project\",\r\n },\r\n {\r\n type: \"text\",\r\n name: \"author\",\r\n message: \"Author:\",\r\n initial: getDefaultAuthor(),\r\n },\r\n {\r\n type: \"select\",\r\n name: \"language\",\r\n message: \"Use Language:\",\r\n choices: [\r\n { title: \"Python\", value: \"python\" },\r\n { title: \"TypeScript\", value: \"typescript\" },\r\n ],\r\n onState: (state: { value: Language }) => {\r\n selectedLanguage = state.value;\r\n },\r\n },\r\n {\r\n type: (prev: Language) => (prev ? \"text\" : null),\r\n name: \"mainFileName\",\r\n message: \"Main File Name:\",\r\n initial: (prev: Language) =>\r\n prev === \"python\" ? \"main.py\" : \"index.ts\",\r\n validate: (value: string, values?: { language?: Language }) => {\r\n const name = String(value || \"\").trim();\r\n if (!name) return \"Main file name is required\";\r\n const ext = path.extname(name);\r\n const currentLanguage =\r\n values?.language || selectedLanguage;\r\n if (!currentLanguage) return true;\r\n const expected =\r\n currentLanguage === \"python\" ? \".py\" : \".ts\";\r\n if (ext && ext !== expected)\r\n return `Main file should end with ${expected}`;\r\n return true;\r\n },\r\n },\r\n {\r\n type: \"confirm\",\r\n name: \"readme\",\r\n message: \"Readme:\",\r\n initial: true,\r\n },\r\n {\r\n type: \"confirm\",\r\n name: \"license\",\r\n message: \"License (MIT):\",\r\n initial: true,\r\n },\r\n ],\r\n {\r\n onCancel: () => {\r\n process.exitCode = 1;\r\n return false;\r\n },\r\n }\r\n );\r\n\r\n if (!response || !response.projectName) {\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const options: ProjectOptions = {\r\n projectName: normalizeProjectName(response.projectName),\r\n description: String(response.description || \"\").trim(),\r\n author: String(response.author || \"\").trim(),\r\n language: response.language as Language,\r\n mainFileName: normalizeMainFileName(\r\n response.language as Language,\r\n response.mainFileName\r\n ),\r\n readme: Boolean(response.readme),\r\n license: Boolean(response.license),\r\n };\r\n\r\n await scaffoldProject(options);\r\n}\r\n\r\nrun().catch((err) => {\r\n // eslint-disable-next-line no-console\r\n console.error(err);\r\n process.exitCode = 1;\r\n});\r\n"],
5
+ "mappings": "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",
6
+ "names": ["options", "prompts"]
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/scaffold.ts"],
4
+ "sourcesContent": ["import * as fs from \"node:fs/promises\";\r\nimport * as path from \"node:path\";\r\nimport { spawnSync } from \"node:child_process\";\r\nimport { getProjectFiles, type ProjectOptions } from \"./templates\";\r\n\r\nasync function pathExists(p: string): Promise<boolean> {\r\n try {\r\n await fs.access(p);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nasync function ensureDir(dirPath: string): Promise<void> {\r\n await fs.mkdir(dirPath, { recursive: true });\r\n}\r\n\r\nasync function writeFileEnsuringDir(\r\n filePath: string,\r\n content: string\r\n): Promise<void> {\r\n await ensureDir(path.dirname(filePath));\r\n await fs.writeFile(filePath, content, \"utf8\");\r\n}\r\n\r\nfunction tryInitGitRepo(targetRoot: string): void {\r\n try {\r\n const version = spawnSync(\"git\", [\"--version\"], {\r\n cwd: targetRoot,\r\n stdio: \"ignore\",\r\n shell: false,\r\n });\r\n\r\n if (version.status !== 0) return;\r\n\r\n const init = spawnSync(\"git\", [\"init\"], {\r\n cwd: targetRoot,\r\n stdio: \"ignore\",\r\n shell: false,\r\n });\r\n\r\n if (init.status !== 0) return;\r\n } catch {\r\n // best-effort: do not block scaffolding if git isn't available\r\n }\r\n}\r\n\r\nexport async function scaffoldProject(options: ProjectOptions): Promise<void> {\r\n const targetRoot = path.resolve(process.cwd(), options.projectName);\r\n\r\n if (await pathExists(targetRoot)) {\r\n throw new Error(`Target directory already exists: ${targetRoot}`);\r\n }\r\n\r\n const files = getProjectFiles(options);\r\n\r\n await ensureDir(targetRoot);\r\n\r\n for (const file of files) {\r\n const absPath = path.join(targetRoot, file.relativePath);\r\n await writeFileEnsuringDir(absPath, file.content);\r\n }\r\n\r\n tryInitGitRepo(targetRoot);\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(`\\nCreated project at: ${targetRoot}`);\r\n}\r\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAoB;AACpB,WAAsB;AACtB,gCAA0B;AAC1B,uBAAqD;AAErD,eAAe,WAAW,GAA6B;AACnD,MAAI;AACA,UAAM,GAAG,OAAO,CAAC;AACjB,WAAO;AAAA,EACX,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AAEA,eAAe,UAAU,SAAgC;AACrD,QAAM,GAAG,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAC/C;AAEA,eAAe,qBACX,UACA,SACa;AACb,QAAM,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACtC,QAAM,GAAG,UAAU,UAAU,SAAS,MAAM;AAChD;AAEA,SAAS,eAAe,YAA0B;AAC9C,MAAI;AACA,UAAM,cAAU,qCAAU,OAAO,CAAC,WAAW,GAAG;AAAA,MAC5C,KAAK;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACX,CAAC;AAED,QAAI,QAAQ,WAAW,EAAG;AAE1B,UAAM,WAAO,qCAAU,OAAO,CAAC,MAAM,GAAG;AAAA,MACpC,KAAK;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACX,CAAC;AAED,QAAI,KAAK,WAAW,EAAG;AAAA,EAC3B,QAAQ;AAAA,EAER;AACJ;AAEA,eAAsB,gBAAgB,SAAwC;AAC1E,QAAM,aAAa,KAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ,WAAW;AAElE,MAAI,MAAM,WAAW,UAAU,GAAG;AAC9B,UAAM,IAAI,MAAM,oCAAoC,UAAU,EAAE;AAAA,EACpE;AAEA,QAAM,YAAQ,kCAAgB,OAAO;AAErC,QAAM,UAAU,UAAU;AAE1B,aAAW,QAAQ,OAAO;AACtB,UAAM,UAAU,KAAK,KAAK,YAAY,KAAK,YAAY;AACvD,UAAM,qBAAqB,SAAS,KAAK,OAAO;AAAA,EACpD;AAEA,iBAAe,UAAU;AAGzB,UAAQ,IAAI;AAAA,sBAAyB,UAAU,EAAE;AACrD;",
6
+ "names": []
7
+ }
package/dist/templates.js CHANGED
@@ -58,6 +58,7 @@ function packagingScriptMjs() {
58
58
  // Keep this script dependency-free and avoid nested template literals.
59
59
  return [
60
60
  'import { spawnSync } from "node:child_process";',
61
+ 'import * as fs from "node:fs";',
61
62
  'import * as fsp from "node:fs/promises";',
62
63
  'import * as path from "node:path";',
63
64
  "",
@@ -70,18 +71,61 @@ function packagingScriptMjs() {
70
71
  " });",
71
72
  "}",
72
73
  "",
73
- "function hasCommand(cmd) {",
74
- ' if (process.platform === "win32") {',
75
- ' const r = run("where", [cmd]);',
76
- " return r.status === 0;",
74
+ "function runInherit(cmd, args, opts = {}) {",
75
+ " return spawnSync(cmd, args, {",
76
+ ' stdio: "inherit",',
77
+ ' encoding: "utf8",',
78
+ " shell: false,",
79
+ " ...opts,",
80
+ " });",
81
+ "}",
82
+ "",
83
+ "function normalizeRelPath(p) {",
84
+ ' return String(p || "").replace(/\\\\/g, "/");',
85
+ "}",
86
+ "",
87
+ "function readJsonIfExists(filePath) {",
88
+ " try {",
89
+ " if (!fs.existsSync(filePath)) return undefined;",
90
+ ' const raw = fs.readFileSync(filePath, "utf8");',
91
+ " return JSON.parse(raw);",
92
+ " } catch {",
93
+ " return undefined;",
77
94
  " }",
78
- ' const check = "command -v " + cmd + " >/dev/null 2>&1";',
79
- ' const r = run("sh", ["-lc", check]);',
80
- " return r.status === 0;",
81
95
  "}",
82
96
  "",
83
- "function escapePsSingleQuotes(value) {",
84
- ' return String(value || "").replace(/\'/g, "\'\'");',
97
+ "function detectTypeScriptProject() {",
98
+ ' if (fs.existsSync("tsconfig.json")) return true;',
99
+ ' const pkg = readJsonIfExists("package.json");',
100
+ ' const buildScript = String(pkg?.scripts?.build || "");',
101
+ ' if (buildScript.includes("tsc")) return true;',
102
+ " if (pkg?.devDependencies?.typescript) return true;",
103
+ " return false;",
104
+ "}",
105
+ "",
106
+ "function detectDistEntry() {",
107
+ " // default requested: /dist/index.js",
108
+ ' const defaultEntry = "dist/index.js";',
109
+ ' const pkg = readJsonIfExists("package.json");',
110
+ ' const start = String(pkg?.scripts?.start || "").trim();',
111
+ " const m = /^node\\s+(.+)$/.exec(start);",
112
+ ' const inferred = m && m[1] ? String(m[1]).trim() : "";',
113
+ " const entry = inferred || defaultEntry;",
114
+ " return normalizeRelPath(entry);",
115
+ "}",
116
+ "",
117
+ "function ensureGitRepoRoot() {",
118
+ ' const r = run("git", ["rev-parse", "--show-toplevel"], { cwd: process.cwd() });',
119
+ " if (r.status !== 0) {",
120
+ ' const err = (r.stderr || r.stdout || "").trim();',
121
+ " throw new Error(",
122
+ ' "git repo is required for packaging (to respect .gitignore).\\n" + err,',
123
+ " );",
124
+ " }",
125
+ ' const top = String(r.stdout || "").trim();',
126
+ ' if (!top) throw new Error("Failed to resolve git repo root");',
127
+ " process.chdir(top);",
128
+ " return top;",
85
129
  "}",
86
130
  "",
87
131
  "function gitFileList() {",
@@ -101,21 +145,100 @@ function packagingScriptMjs() {
101
145
  " }",
102
146
  "",
103
147
  ' const raw = r.stdout || "";',
104
- ' return raw.split("\\u0000").filter(Boolean);',
148
+ ' return raw.split("\\u0000").filter(Boolean).map(normalizeRelPath);',
149
+ "}",
150
+ "",
151
+ "function shouldExcludeFromPackage(relPath) {",
152
+ " const p = normalizeRelPath(relPath);",
153
+ " if (!p) return true;",
154
+ " // 1) scripts/package.mjs does not need to be packaged",
155
+ ' if (p === "scripts/package.mjs") return true;',
156
+ " // temp files created by this script",
157
+ ' if (p.startsWith(".glosc-tmp/")) return true;',
158
+ " return false;",
159
+ "}",
160
+ "",
161
+ "function uniqStable(list) {",
162
+ " const seen = new Set();",
163
+ " const out = [];",
164
+ " for (const item of list) {",
165
+ " if (seen.has(item)) continue;",
166
+ " seen.add(item);",
167
+ " out.push(item);",
168
+ " }",
169
+ " return out;",
105
170
  "}",
106
171
  "",
107
172
  "async function ensureDir(p) {",
108
173
  " await fsp.mkdir(p, { recursive: true });",
109
174
  "}",
110
175
  "",
111
- "async function writeTempFileList(filePaths) {",
176
+ "async function prepareTmpDir() {",
112
177
  ' const tmpDir = path.join(process.cwd(), ".glosc-tmp");',
178
+ " await fsp.rm(tmpDir, { recursive: true, force: true });",
113
179
  " await ensureDir(tmpDir);",
114
- ' const listPath = path.join(tmpDir, "zip-file-list.txt");',
115
- ' await fsp.writeFile(listPath, filePaths.join("\\n"), "utf8");',
180
+ " return tmpDir;",
181
+ "}",
182
+ "",
183
+ "async function writeNulSeparatedList(tmpDir, filePaths) {",
184
+ " // Use NUL-separated pathspec so we can pass it to git safely (no quoting issues).",
185
+ ' const listPath = path.join(tmpDir, "pathspec.nul");',
186
+ " const normalized = filePaths.map(normalizeRelPath);",
187
+ ' const buf = Buffer.from(normalized.join("\u0000") + "\u0000", "utf8");',
188
+ " await fsp.writeFile(listPath, buf);",
116
189
  " return listPath;",
117
190
  "}",
118
191
  "",
192
+ "function gitArchiveZipFromWorkingTreeFiles(outZip, filePaths) {",
193
+ " // Create a temporary index so we can archive *tracked + untracked* files without",
194
+ " // touching the user's real index or requiring a commit.",
195
+ ' const tmpIndex = path.join(process.cwd(), ".glosc-tmp", "index");',
196
+ " const env = { ...process.env, GIT_INDEX_FILE: tmpIndex };",
197
+ "",
198
+ " // Add files (force-add so ignored build output like dist/index.js can be included).",
199
+ " const add = run(",
200
+ ' "git",',
201
+ " [",
202
+ ' "add",',
203
+ ' "-f",',
204
+ ' "--pathspec-from-file=.glosc-tmp/pathspec.nul",',
205
+ ' "--pathspec-file-nul",',
206
+ ' "--",',
207
+ " ],",
208
+ " { cwd: process.cwd(), env },",
209
+ " );",
210
+ " if (add.status !== 0) {",
211
+ " // Fallback for older Git versions without --pathspec-from-file.",
212
+ " const chunkSize = 200;",
213
+ " for (let i = 0; i < filePaths.length; i += chunkSize) {",
214
+ " const chunk = filePaths.slice(i, i + chunkSize);",
215
+ ' const r = run("git", ["add", "-f", "--", ...chunk], { cwd: process.cwd(), env });',
216
+ " if (r.status !== 0) {",
217
+ ' const err = (r.stderr || r.stdout || "").trim();',
218
+ ' throw new Error("git add (temp index) failed\\n" + err);',
219
+ " }",
220
+ " }",
221
+ " }",
222
+ "",
223
+ ' const wt = run("git", ["write-tree"], { cwd: process.cwd(), env });',
224
+ " if (wt.status !== 0) {",
225
+ ' const err = (wt.stderr || wt.stdout || "").trim();',
226
+ ' throw new Error("git write-tree failed\\n" + err);',
227
+ " }",
228
+ ' const tree = String(wt.stdout || "").trim();',
229
+ ' if (!tree) throw new Error("git write-tree produced empty tree hash");',
230
+ "",
231
+ " const ar = run(",
232
+ ' "git",',
233
+ ' ["archive", "--format=zip", "--output", outZip, tree],',
234
+ " { cwd: process.cwd() },",
235
+ " );",
236
+ " if (ar.status !== 0) {",
237
+ ' const err = (ar.stderr || ar.stdout || "").trim();',
238
+ ' throw new Error("git archive failed\\n" + err);',
239
+ " }",
240
+ "}",
241
+ "",
119
242
  "function timestamp() {",
120
243
  " const d = new Date();",
121
244
  ' const pad = (n) => String(n).padStart(2, "0");',
@@ -131,7 +254,33 @@ function packagingScriptMjs() {
131
254
  "}",
132
255
  "",
133
256
  "async function main() {",
134
- " const files = gitFileList();",
257
+ " ensureGitRepoRoot();",
258
+ " const isTs = detectTypeScriptProject();",
259
+ " const distEntry = detectDistEntry();",
260
+ ' const isWin = process.platform === "win32";',
261
+ "",
262
+ " // 2) For TypeScript, run build and package dist entry",
263
+ " if (isTs) {",
264
+ " const r = isWin",
265
+ ' ? runInherit("cmd", ["/d", "/s", "/c", "npm run build"], { cwd: process.cwd() })',
266
+ ' : runInherit("npm", ["run", "build"], { cwd: process.cwd() });',
267
+ ' if (r.error) throw new Error("Failed to run npm: " + String(r.error?.message || r.error));',
268
+ ' if (r.status !== 0) throw new Error("npm run build failed");',
269
+ " if (!fs.existsSync(distEntry)) {",
270
+ ' throw new Error("Expected build output missing: " + distEntry);',
271
+ " }",
272
+ " }",
273
+ "",
274
+ " let files = gitFileList().filter((p) => !shouldExcludeFromPackage(p));",
275
+ "",
276
+ " if (isTs) {",
277
+ " // dist/ is typically ignored; ensure we still include the built entry",
278
+ ' files = files.filter((p) => !p.startsWith("dist/"));',
279
+ " files.push(distEntry);",
280
+ " }",
281
+ "",
282
+ " files = uniqStable(files);",
283
+ "",
135
284
  " if (files.length === 0) {",
136
285
  " throw new Error(",
137
286
  ' "No files found to package. If you just created the project, make sure git is initialized and .gitignore exists.",',
@@ -142,56 +291,23 @@ function packagingScriptMjs() {
142
291
  " await ensureDir(outDir);",
143
292
  ' const outZip = path.join(outDir, "glosc-package-" + timestamp() + ".zip");',
144
293
  "",
145
- " const listPath = await writeTempFileList(files);",
146
- "",
294
+ " const tmpDir = await prepareTmpDir();",
147
295
  " try {",
148
- ' if (hasCommand("powershell")) {',
149
- " const listEsc = escapePsSingleQuotes(listPath);",
150
- " const outEsc = escapePsSingleQuotes(outZip);",
151
- " const psCommand = [",
152
- ' "$paths = Get-Content -LiteralPath \\\'" + listEsc + "\\\';",',
153
- ' "Compress-Archive -LiteralPath $paths -DestinationPath \\\'" + outEsc + "\\\' -Force -CompressionLevel Optimal;",',
154
- ' ].join(" ");',
155
- " const psArgs = [",
156
- ' "-NoProfile",',
157
- ' "-ExecutionPolicy",',
158
- ' "Bypass",',
159
- ' "-Command",',
160
- " psCommand,",
161
- " ];",
162
- ' const r = run("powershell", psArgs, { cwd: process.cwd() });',
163
- ' if (r.status !== 0) throw new Error((r.stderr || r.stdout || "").trim());',
164
- ' } else if (hasCommand("pwsh")) {',
165
- " const listEsc = escapePsSingleQuotes(listPath);",
166
- " const outEsc = escapePsSingleQuotes(outZip);",
167
- " const psCommand = [",
168
- ' "$paths = Get-Content -LiteralPath \\\'" + listEsc + "\\\';",',
169
- ' "Compress-Archive -LiteralPath $paths -DestinationPath \\\'" + outEsc + "\\\' -Force -CompressionLevel Optimal;",',
170
- ' ].join(" ");',
171
- ' const psArgs = ["-NoProfile", "-Command", psCommand];',
172
- ' const r = run("pwsh", psArgs, { cwd: process.cwd() });',
173
- ' if (r.status !== 0) throw new Error((r.stderr || r.stdout || "").trim());',
174
- ' } else if (hasCommand("zip")) {',
175
- ' const r = spawnSync("zip", ["-q", "-r", outZip, "-@"], {',
176
- " cwd: process.cwd(),",
177
- ' input: files.join("\\n"),',
178
- ' stdio: ["pipe", "pipe", "pipe"],',
179
- ' encoding: "utf8",',
180
- " });",
181
- ' if (r.status !== 0) throw new Error((r.stderr || r.stdout || "").trim());',
182
- " } else {",
183
- " throw new Error(",
184
- ' "No zip backend found. Install Git + PowerShell (Windows) or `zip` (macOS/Linux), then rerun.",',
185
- " );",
186
- " }",
296
+ " await writeNulSeparatedList(tmpDir, files);",
297
+ " gitArchiveZipFromWorkingTreeFiles(outZip, files);",
187
298
  " } finally {",
188
299
  " try {",
189
- " await fsp.rm(path.dirname(listPath), { recursive: true, force: true });",
300
+ " await fsp.rm(tmpDir, { recursive: true, force: true });",
190
301
  " } catch {",
191
302
  " // ignore",
192
303
  " }",
193
304
  " }",
194
305
  "",
306
+ " const st = await fsp.stat(outZip).catch(() => undefined);",
307
+ " if (!st || st.size <= 0) {",
308
+ ' throw new Error("Packaging failed: zip was not created: " + outZip);',
309
+ " }",
310
+ "",
195
311
  ' console.log("Created: " + outZip);',
196
312
  "}",
197
313
  "",
@@ -292,7 +408,7 @@ function nodePackageJson(options) {
292
408
  private: true,
293
409
  type: "module",
294
410
  scripts: {
295
- build: "tsc -p .",
411
+ build: `esbuild src/${mainFileName} --bundle --platform=node --format=esm --target=es2022 --packages=external --sourcemap --outfile=${distEntry}`,
296
412
  start: `node ${distEntry}`,
297
413
  package: "node scripts/package.mjs",
298
414
  },
@@ -300,6 +416,7 @@ function nodePackageJson(options) {
300
416
  "@modelcontextprotocol/sdk": "^1.24.3",
301
417
  },
302
418
  devDependencies: {
419
+ esbuild: "^0.20.2",
303
420
  typescript: "^5.9.3",
304
421
  "@types/node": "^22.19.2",
305
422
  },
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/templates.ts"],
4
+ "sourcesContent": ["export type Language = \"python\" | \"typescript\";\r\n\r\nexport type ProjectOptions = {\r\n projectName: string;\r\n description: string;\r\n author: string;\r\n language: Language;\r\n mainFileName: string;\r\n readme: boolean;\r\n license: boolean;\r\n};\r\n\r\nexport type ProjectFile = {\r\n relativePath: string;\r\n content: string;\r\n};\r\n\r\nfunction gitignoreContent(language: Language): string {\r\n const common = [\r\n \"# OS\",\r\n \".DS_Store\",\r\n \"Thumbs.db\",\r\n \"Desktop.ini\",\r\n \"\",\r\n \"# Editors\",\r\n \".vscode/\",\r\n \".idea/\",\r\n \"*.swp\",\r\n \"\",\r\n \"# Env\",\r\n \".env\",\r\n \".env.*\",\r\n \"\",\r\n \"# Logs\",\r\n \"*.log\",\r\n \"\",\r\n \"# Builds / artifacts\",\r\n \"dist/\",\r\n \"build/\",\r\n \"*.zip\",\r\n \"\",\r\n ];\r\n\r\n const node = [\r\n \"# Node\",\r\n \"node_modules/\",\r\n \"npm-debug.log*\",\r\n \"yarn-debug.log*\",\r\n \"yarn-error.log*\",\r\n \"pnpm-debug.log*\",\r\n \"\",\r\n ];\r\n\r\n const python = [\r\n \"# Python\",\r\n \"__pycache__/\",\r\n \"*.py[cod]\",\r\n \"*.pyd\",\r\n \".Python\",\r\n \".venv/\",\r\n \"venv/\",\r\n \"ENV/\",\r\n \"env/\",\r\n \".pytest_cache/\",\r\n \".mypy_cache/\",\r\n \".ruff_cache/\",\r\n \"*.egg-info/\",\r\n \"\",\r\n ];\r\n\r\n return (\r\n common.join(\"\\n\") +\r\n (language === \"typescript\" ? node.join(\"\\n\") : python.join(\"\\n\"))\r\n );\r\n}\r\n\r\nfunction packagingScriptMjs(): string {\r\n // Keep this script dependency-free and avoid nested template literals.\r\n return [\r\n 'import { spawnSync } from \"node:child_process\";',\r\n 'import * as fs from \"node:fs\";',\r\n 'import * as fsp from \"node:fs/promises\";',\r\n 'import * as path from \"node:path\";',\r\n \"\",\r\n \"function run(cmd, args, opts = {}) {\",\r\n \" return spawnSync(cmd, args, {\",\r\n ' stdio: [\"ignore\", \"pipe\", \"pipe\"],',\r\n ' encoding: \"utf8\",',\r\n \" shell: false,\",\r\n \" ...opts,\",\r\n \" });\",\r\n \"}\",\r\n \"\",\r\n \"function runInherit(cmd, args, opts = {}) {\",\r\n \" return spawnSync(cmd, args, {\",\r\n ' stdio: \"inherit\",',\r\n ' encoding: \"utf8\",',\r\n \" shell: false,\",\r\n \" ...opts,\",\r\n \" });\",\r\n \"}\",\r\n \"\",\r\n \"function normalizeRelPath(p) {\",\r\n ' return String(p || \"\").replace(/\\\\\\\\/g, \"/\");',\r\n \"}\",\r\n \"\",\r\n \"function readJsonIfExists(filePath) {\",\r\n \" try {\",\r\n \" if (!fs.existsSync(filePath)) return undefined;\",\r\n ' const raw = fs.readFileSync(filePath, \"utf8\");',\r\n \" return JSON.parse(raw);\",\r\n \" } catch {\",\r\n \" return undefined;\",\r\n \" }\",\r\n \"}\",\r\n \"\",\r\n \"function detectTypeScriptProject() {\",\r\n ' if (fs.existsSync(\"tsconfig.json\")) return true;',\r\n ' const pkg = readJsonIfExists(\"package.json\");',\r\n ' const buildScript = String(pkg?.scripts?.build || \"\");',\r\n ' if (buildScript.includes(\"tsc\")) return true;',\r\n \" if (pkg?.devDependencies?.typescript) return true;\",\r\n \" return false;\",\r\n \"}\",\r\n \"\",\r\n \"function detectDistEntry() {\",\r\n \" // default requested: /dist/index.js\",\r\n ' const defaultEntry = \"dist/index.js\";',\r\n ' const pkg = readJsonIfExists(\"package.json\");',\r\n ' const start = String(pkg?.scripts?.start || \"\").trim();',\r\n \" const m = /^node\\\\s+(.+)$/.exec(start);\",\r\n ' const inferred = m && m[1] ? String(m[1]).trim() : \"\";',\r\n \" const entry = inferred || defaultEntry;\",\r\n \" return normalizeRelPath(entry);\",\r\n \"}\",\r\n \"\",\r\n \"function ensureGitRepoRoot() {\",\r\n ' const r = run(\"git\", [\"rev-parse\", \"--show-toplevel\"], { cwd: process.cwd() });',\r\n \" if (r.status !== 0) {\",\r\n ' const err = (r.stderr || r.stdout || \"\").trim();',\r\n \" throw new Error(\",\r\n ' \"git repo is required for packaging (to respect .gitignore).\\\\n\" + err,',\r\n \" );\",\r\n \" }\",\r\n ' const top = String(r.stdout || \"\").trim();',\r\n ' if (!top) throw new Error(\"Failed to resolve git repo root\");',\r\n \" process.chdir(top);\",\r\n \" return top;\",\r\n \"}\",\r\n \"\",\r\n \"function gitFileList() {\",\r\n ' const r = run(\"git\", [',\r\n ' \"ls-files\",',\r\n ' \"-z\",',\r\n ' \"--cached\",',\r\n ' \"--others\",',\r\n ' \"--exclude-standard\",',\r\n \" ]);\",\r\n \"\",\r\n \" if (r.status !== 0) {\",\r\n ' const err = (r.stderr || r.stdout || \"\").trim();',\r\n \" throw new Error(\",\r\n ' \"git is required for packaging (and to respect .gitignore).\\\\n\" + err,',\r\n \" );\",\r\n \" }\",\r\n \"\",\r\n ' const raw = r.stdout || \"\";',\r\n ' return raw.split(\"\\\\u0000\").filter(Boolean).map(normalizeRelPath);',\r\n \"}\",\r\n \"\",\r\n \"function shouldExcludeFromPackage(relPath) {\",\r\n \" const p = normalizeRelPath(relPath);\",\r\n \" if (!p) return true;\",\r\n \" // 1) scripts/package.mjs does not need to be packaged\",\r\n ' if (p === \"scripts/package.mjs\") return true;',\r\n \" // temp files created by this script\",\r\n ' if (p.startsWith(\".glosc-tmp/\")) return true;',\r\n \" return false;\",\r\n \"}\",\r\n \"\",\r\n \"function uniqStable(list) {\",\r\n \" const seen = new Set();\",\r\n \" const out = [];\",\r\n \" for (const item of list) {\",\r\n \" if (seen.has(item)) continue;\",\r\n \" seen.add(item);\",\r\n \" out.push(item);\",\r\n \" }\",\r\n \" return out;\",\r\n \"}\",\r\n \"\",\r\n \"async function ensureDir(p) {\",\r\n \" await fsp.mkdir(p, { recursive: true });\",\r\n \"}\",\r\n \"\",\r\n \"async function prepareTmpDir() {\",\r\n ' const tmpDir = path.join(process.cwd(), \".glosc-tmp\");',\r\n \" await fsp.rm(tmpDir, { recursive: true, force: true });\",\r\n \" await ensureDir(tmpDir);\",\r\n \" return tmpDir;\",\r\n \"}\",\r\n \"\",\r\n \"async function writeNulSeparatedList(tmpDir, filePaths) {\",\r\n \" // Use NUL-separated pathspec so we can pass it to git safely (no quoting issues).\",\r\n ' const listPath = path.join(tmpDir, \"pathspec.nul\");',\r\n \" const normalized = filePaths.map(normalizeRelPath);\",\r\n ' const buf = Buffer.from(normalized.join(\"\\u0000\") + \"\\u0000\", \"utf8\");',\r\n \" await fsp.writeFile(listPath, buf);\",\r\n \" return listPath;\",\r\n \"}\",\r\n \"\",\r\n \"function gitArchiveZipFromWorkingTreeFiles(outZip, filePaths) {\",\r\n \" // Create a temporary index so we can archive *tracked + untracked* files without\",\r\n \" // touching the user's real index or requiring a commit.\",\r\n ' const tmpIndex = path.join(process.cwd(), \".glosc-tmp\", \"index\");',\r\n \" const env = { ...process.env, GIT_INDEX_FILE: tmpIndex };\",\r\n \"\",\r\n \" // Add files (force-add so ignored build output like dist/index.js can be included).\",\r\n \" const add = run(\",\r\n ' \"git\",',\r\n \" [\",\r\n ' \"add\",',\r\n ' \"-f\",',\r\n ' \"--pathspec-from-file=.glosc-tmp/pathspec.nul\",',\r\n ' \"--pathspec-file-nul\",',\r\n ' \"--\",',\r\n \" ],\",\r\n \" { cwd: process.cwd(), env },\",\r\n \" );\",\r\n \" if (add.status !== 0) {\",\r\n \" // Fallback for older Git versions without --pathspec-from-file.\",\r\n \" const chunkSize = 200;\",\r\n \" for (let i = 0; i < filePaths.length; i += chunkSize) {\",\r\n \" const chunk = filePaths.slice(i, i + chunkSize);\",\r\n ' const r = run(\"git\", [\"add\", \"-f\", \"--\", ...chunk], { cwd: process.cwd(), env });',\r\n \" if (r.status !== 0) {\",\r\n ' const err = (r.stderr || r.stdout || \"\").trim();',\r\n ' throw new Error(\"git add (temp index) failed\\\\n\" + err);',\r\n \" }\",\r\n \" }\",\r\n \" }\",\r\n \"\",\r\n ' const wt = run(\"git\", [\"write-tree\"], { cwd: process.cwd(), env });',\r\n \" if (wt.status !== 0) {\",\r\n ' const err = (wt.stderr || wt.stdout || \"\").trim();',\r\n ' throw new Error(\"git write-tree failed\\\\n\" + err);',\r\n \" }\",\r\n ' const tree = String(wt.stdout || \"\").trim();',\r\n ' if (!tree) throw new Error(\"git write-tree produced empty tree hash\");',\r\n \"\",\r\n \" const ar = run(\",\r\n ' \"git\",',\r\n ' [\"archive\", \"--format=zip\", \"--output\", outZip, tree],',\r\n \" { cwd: process.cwd() },\",\r\n \" );\",\r\n \" if (ar.status !== 0) {\",\r\n ' const err = (ar.stderr || ar.stdout || \"\").trim();',\r\n ' throw new Error(\"git archive failed\\\\n\" + err);',\r\n \" }\",\r\n \"}\",\r\n \"\",\r\n \"function timestamp() {\",\r\n \" const d = new Date();\",\r\n ' const pad = (n) => String(n).padStart(2, \"0\");',\r\n \" return (\",\r\n \" String(d.getFullYear()) +\",\r\n \" pad(d.getMonth() + 1) +\",\r\n \" pad(d.getDate()) +\",\r\n ' \"-\" +',\r\n \" pad(d.getHours()) +\",\r\n \" pad(d.getMinutes()) +\",\r\n \" pad(d.getSeconds())\",\r\n \" );\",\r\n \"}\",\r\n \"\",\r\n \"async function main() {\",\r\n \" ensureGitRepoRoot();\",\r\n \" const isTs = detectTypeScriptProject();\",\r\n \" const distEntry = detectDistEntry();\",\r\n ' const isWin = process.platform === \"win32\";',\r\n \"\",\r\n \" // 2) For TypeScript, run build and package dist entry\",\r\n \" if (isTs) {\",\r\n \" const r = isWin\",\r\n ' ? runInherit(\"cmd\", [\"/d\", \"/s\", \"/c\", \"npm run build\"], { cwd: process.cwd() })',\r\n ' : runInherit(\"npm\", [\"run\", \"build\"], { cwd: process.cwd() });',\r\n ' if (r.error) throw new Error(\"Failed to run npm: \" + String(r.error?.message || r.error));',\r\n ' if (r.status !== 0) throw new Error(\"npm run build failed\");',\r\n \" if (!fs.existsSync(distEntry)) {\",\r\n ' throw new Error(\"Expected build output missing: \" + distEntry);',\r\n \" }\",\r\n \" }\",\r\n \"\",\r\n \" let files = gitFileList().filter((p) => !shouldExcludeFromPackage(p));\",\r\n \"\",\r\n \" if (isTs) {\",\r\n \" // dist/ is typically ignored; ensure we still include the built entry\",\r\n ' files = files.filter((p) => !p.startsWith(\"dist/\"));',\r\n \" files.push(distEntry);\",\r\n \" }\",\r\n \"\",\r\n \" files = uniqStable(files);\",\r\n \"\",\r\n \" if (files.length === 0) {\",\r\n \" throw new Error(\",\r\n ' \"No files found to package. If you just created the project, make sure git is initialized and .gitignore exists.\",',\r\n \" );\",\r\n \" }\",\r\n \"\",\r\n ' const outDir = path.join(process.cwd(), \"dist\");',\r\n \" await ensureDir(outDir);\",\r\n ' const outZip = path.join(outDir, \"glosc-package-\" + timestamp() + \".zip\");',\r\n \"\",\r\n \" const tmpDir = await prepareTmpDir();\",\r\n \" try {\",\r\n \" await writeNulSeparatedList(tmpDir, files);\",\r\n \" gitArchiveZipFromWorkingTreeFiles(outZip, files);\",\r\n \" } finally {\",\r\n \" try {\",\r\n \" await fsp.rm(tmpDir, { recursive: true, force: true });\",\r\n \" } catch {\",\r\n \" // ignore\",\r\n \" }\",\r\n \" }\",\r\n \"\",\r\n \" const st = await fsp.stat(outZip).catch(() => undefined);\",\r\n \" if (!st || st.size <= 0) {\",\r\n ' throw new Error(\"Packaging failed: zip was not created: \" + outZip);',\r\n \" }\",\r\n \"\",\r\n ' console.log(\"Created: \" + outZip);',\r\n \"}\",\r\n \"\",\r\n \"main().catch((err) => {\",\r\n \" console.error(String(err?.message || err));\",\r\n \" process.exit(1);\",\r\n \"});\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nfunction entryPath(options: ProjectOptions): string {\r\n return options.language === \"python\"\r\n ? options.mainFileName\r\n : `src/${options.mainFileName}`;\r\n}\r\n\r\nfunction mcpRuntime(options: ProjectOptions): \"python\" | \"node\" {\r\n return options.language === \"python\" ? \"python\" : \"node\";\r\n}\r\n\r\nfunction mcpEntry(options: ProjectOptions): string {\r\n if (options.language === \"python\") return options.mainFileName;\r\n return `dist/${options.mainFileName.replace(/\\.ts$/i, \".js\")}`;\r\n}\r\n\r\nfunction escapeYamlString(value: unknown): string {\r\n const s = String(value ?? \"\");\r\n const escaped = s.replace(/\"/g, '\\\\\"');\r\n return `\"${escaped}\"`;\r\n}\r\n\r\nfunction mitLicenseText({ author }: Pick<ProjectOptions, \"author\">): string {\r\n const year = new Date().getFullYear();\r\n const owner = String(author || \"\").trim() || \"Copyright Holder\";\r\n return `MIT License\\n\\nCopyright (c) ${year} ${owner}\\n\\nPermission is hereby granted, free of charge, to any person obtaining a copy\\nof this software and associated documentation files (the \\\"Software\\\"), to deal\\nin the Software without restriction, including without limitation the rights\\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\ncopies of the Software, and to permit persons to whom the Software is\\nfurnished to do so, subject to the following conditions:\\n\\nThe above copyright notice and this permission notice shall be included in all\\ncopies or substantial portions of the Software.\\n\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\\nSOFTWARE.\\n`;\r\n}\r\n\r\nfunction projectReadme(options: ProjectOptions): string {\r\n const { projectName, description, author, language, mainFileName } =\r\n options;\r\n const langLabel = language === \"python\" ? \"Python\" : \"TypeScript\";\r\n\r\n const entry = entryPath(options);\r\n const runSection =\r\n language === \"python\"\r\n ? `## Run (Python)\\n\\n\\n\\n1) Install deps\\n\\n\\n\\n\\`\\`\\`sh\\npython -m pip install -r requirements.txt\\n\\`\\`\\`\\n\\n\\n\\n2) Run the MCP server (stdio)\\n\\n\\n\\n\\`\\`\\`sh\\npython ${entry}\\n\\`\\`\\`\\n\\n\\n\\nThis server speaks MCP over stdio. Connect using an MCP client (e.g. an editor integration).\\n`\r\n : `## Run (TypeScript)\\n\\n\\n\\n1) Install deps\\n\\n\\n\\n\\`\\`\\`sh\\nnpm install\\n\\`\\`\\`\\n\\n\\n\\n2) Build\\n\\n\\n\\n\\`\\`\\`sh\\nnpm run build\\n\\`\\`\\`\\n\\n\\n\\n3) Run the MCP server (stdio)\\n\\n\\n\\n\\`\\`\\`sh\\nnpm start\\n\\`\\`\\`\\n\\n\\n\\nThis server speaks MCP over stdio. Connect using an MCP client (e.g. an editor integration).\\n`;\r\n\r\n return `# ${projectName}\\n\\n${description || \"\"}\\n\\n## Author\\n\\n${\r\n author || \"\"\r\n }\\n\\n## Language\\n\\n${langLabel}\\n\\n## Entry\\n\\n- ${entry}\\n\\n## MCP Tools\\n\\n- get_current_time: Returns the current time (UTC, ISO 8601)\\n\\n${runSection}\\n\\n## Config\\n\\n- config.yml (see: mcp.runtime / mcp.entry)\\n`;\r\n}\r\n\r\nfunction packagingPackageJson(options: ProjectOptions): string {\r\n const { projectName, description, author } = options;\r\n const pkg: Record<string, unknown> = {\r\n name: projectName,\r\n version: \"0.1.0\",\r\n description: description || \"\",\r\n author: author || \"\",\r\n private: true,\r\n scripts: {\r\n package: \"node scripts/package.mjs\",\r\n },\r\n };\r\n\r\n return JSON.stringify(pkg, null, 2) + \"\\n\";\r\n}\r\n\r\nfunction configYml(options: ProjectOptions): string {\r\n const { projectName, description, author, language, mainFileName } =\r\n options;\r\n return [\r\n `name: ${escapeYamlString(projectName)}`,\r\n `description: ${escapeYamlString(description)}`,\r\n `icon: ${escapeYamlString(\"\")}`,\r\n `language: ${escapeYamlString(language)}`,\r\n `author: ${escapeYamlString(author)}`,\r\n `mcp:`,\r\n ` runtime: ${escapeYamlString(mcpRuntime(options))}`,\r\n ` entry: ${escapeYamlString(mcpEntry(options))}`,\r\n ` cwd: ${escapeYamlString(\".\")}`,\r\n ` env: {}`,\r\n ` args: []`,\r\n \"\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nfunction pythonMain({\r\n projectName,\r\n}: Pick<ProjectOptions, \"projectName\" | \"description\">): string {\r\n const safeName = String(projectName || \"mcp-server\").replace(/\"/g, '\\\\\"');\r\n\r\n return `from datetime import datetime, timezone\\n\\nfrom mcp.server.fastmcp import FastMCP\\n\\n# Minimal MCP server (stdio)\\n\\nmcp = FastMCP(\"${safeName}\")\\n\\n\\n@mcp.tool()\\nasync def get_current_time() -> str:\\n \"\"\"Return the current time in UTC (ISO 8601).\"\"\"\\n\\n return datetime.now(timezone.utc).isoformat()\\n\\n\\ndef main():\\n mcp.run(transport=\"stdio\")\\n\\n\\nif __name__ == \"__main__\":\\n main()\\n`;\r\n}\r\n\r\nfunction pythonRequirements(): string {\r\n return `mcp\\n`;\r\n}\r\n\r\nfunction pythonPyproject({\r\n projectName,\r\n author,\r\n}: Pick<ProjectOptions, \"projectName\" | \"author\">): string {\r\n const safeName = String(projectName || \"glosc-project\")\r\n .trim()\r\n .replace(/\\s+/g, \"-\");\r\n\r\n const safeAuthor = String(author || \"\").replace(/\"/g, '\\\\\"');\r\n\r\n const authorsLine = safeAuthor.trim()\r\n ? `authors = [{ name = \"${safeAuthor}\" }]\\n`\r\n : \"\";\r\n\r\n return `# Minimal pyproject.toml (adjust as needed)\\n\\n[project]\\nname = \"${safeName}\"\\nversion = \"0.1.0\"\\ndescription = \"\"\\n${authorsLine}requires-python = \">=3.10\"\\ndependencies = [\\n \"mcp\",\\n]\\n\\n[build-system]\\nrequires = [\"setuptools>=61.0\"]\\nbuild-backend = \"setuptools.build_meta\"\\n`;\r\n}\r\n\r\nfunction nodePackageJson(options: ProjectOptions): string {\r\n const { projectName, description, author, mainFileName } = options;\r\n const distEntry = `dist/${mainFileName.replace(/\\.ts$/i, \".js\")}`;\r\n\r\n const pkg: Record<string, unknown> = {\r\n name: projectName,\r\n version: \"0.1.0\",\r\n description: description || \"\",\r\n author: author || \"\",\r\n private: true,\r\n type: \"module\",\r\n scripts: {\r\n build: \"tsc -p .\",\r\n start: `node ${distEntry}`,\r\n package: \"node scripts/package.mjs\",\r\n },\r\n dependencies: {\r\n \"@modelcontextprotocol/sdk\": \"^1.24.3\",\r\n },\r\n devDependencies: {\r\n typescript: \"^5.9.3\",\r\n \"@types/node\": \"^22.19.2\",\r\n },\r\n };\r\n\r\n return JSON.stringify(pkg, null, 2) + \"\\n\";\r\n}\r\n\r\nfunction tsConfig(): string {\r\n return (\r\n JSON.stringify(\r\n {\r\n compilerOptions: {\r\n target: \"ES2022\",\r\n module: \"Node16\",\r\n strict: true,\r\n outDir: \"dist\",\r\n rootDir: \"src\",\r\n esModuleInterop: true,\r\n moduleResolution: \"Node16\",\r\n types: [\"node\"],\r\n skipLibCheck: true,\r\n forceConsistentCasingInFileNames: true,\r\n },\r\n include: [\"src/**/*.ts\"],\r\n },\r\n null,\r\n 2\r\n ) + \"\\n\"\r\n );\r\n}\r\n\r\nfunction tsMain({ projectName }: Pick<ProjectOptions, \"projectName\">): string {\r\n const safeName = String(projectName || \"mcp-server\").replace(/\"/g, '\\\\\"');\r\n\r\n return `import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\\n\\nconst server = new McpServer({\\n name: \"${safeName}\",\\n version: \"0.1.0\",\\n});\\n\\nserver.registerTool(\\n \"get_current_time\",\\n {\\n title: \"Get Current Time\",\\n description: \"Return the current time in UTC (ISO 8601)\",\\n inputSchema: {},\\n },\\n async () => {\\n return {\\n content: [\\n {\\n type: \"text\",\\n text: new Date().toISOString(),\\n },\\n ],\\n };\\n },\\n);\\n\\nasync function main() {\\n const transport = new StdioServerTransport();\\n await server.connect(transport);\\n console.error(\"MCP Server running on stdio\");\\n}\\n\\nmain().catch((error) => {\\n console.error(\"Fatal error in main():\", error);\\n process.exit(1);\\n});\\n`;\r\n}\r\n\r\nexport function getProjectFiles(options: ProjectOptions): ProjectFile[] {\r\n const files: ProjectFile[] = [];\r\n\r\n files.push({\r\n relativePath: \".gitignore\",\r\n content: gitignoreContent(options.language),\r\n });\r\n files.push({\r\n relativePath: \"scripts/package.mjs\",\r\n content: packagingScriptMjs(),\r\n });\r\n files.push({ relativePath: \"config.yml\", content: configYml(options) });\r\n\r\n if (options.readme) {\r\n files.push({\r\n relativePath: \"README.md\",\r\n content: projectReadme(options),\r\n });\r\n }\r\n\r\n if (options.license) {\r\n files.push({\r\n relativePath: \"LICENSE\",\r\n content: mitLicenseText(options),\r\n });\r\n }\r\n\r\n if (options.language === \"python\") {\r\n files.push({\r\n relativePath: options.mainFileName,\r\n content: pythonMain(options),\r\n });\r\n files.push({\r\n relativePath: \"requirements.txt\",\r\n content: pythonRequirements(),\r\n });\r\n files.push({\r\n relativePath: \"pyproject.toml\",\r\n content: pythonPyproject(options),\r\n });\r\n files.push({\r\n relativePath: \"package.json\",\r\n content: packagingPackageJson(options),\r\n });\r\n }\r\n\r\n if (options.language === \"typescript\") {\r\n files.push({\r\n relativePath: `src/${options.mainFileName}`,\r\n content: tsMain(options),\r\n });\r\n files.push({\r\n relativePath: \"package.json\",\r\n content: nodePackageJson(options),\r\n });\r\n files.push({ relativePath: \"tsconfig.json\", content: tsConfig() });\r\n }\r\n\r\n return files;\r\n}\r\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,SAAS,iBAAiB,UAA4B;AAClD,QAAM,SAAS;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AAEA,QAAM,OAAO;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AAEA,QAAM,SAAS;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AAEA,SACI,OAAO,KAAK,IAAI,KACf,aAAa,eAAe,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI;AAEvE;AAEA,SAAS,qBAA6B;AAElC,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAC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",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-glosc",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Scaffold Glosc projects (Python/TypeScript) via npm create",
5
5
  "author": "glosc-ai",
6
6
  "license": "MIT",
@@ -16,7 +16,8 @@
16
16
  "build": "tsc -p tsconfig.json",
17
17
  "start": "npm run build && node bin/index.js",
18
18
  "lint": "npm run build --silent",
19
- "prepublishOnly": "npm run build"
19
+ "prepublishOnly": "npm run build",
20
+ "publish": "npm publish"
20
21
  },
21
22
  "dependencies": {
22
23
  "prompts": "^2.4.2"
package/src/templates.ts CHANGED
@@ -78,6 +78,7 @@ function packagingScriptMjs(): string {
78
78
  // Keep this script dependency-free and avoid nested template literals.
79
79
  return [
80
80
  'import { spawnSync } from "node:child_process";',
81
+ 'import * as fs from "node:fs";',
81
82
  'import * as fsp from "node:fs/promises";',
82
83
  'import * as path from "node:path";',
83
84
  "",
@@ -90,18 +91,61 @@ function packagingScriptMjs(): string {
90
91
  " });",
91
92
  "}",
92
93
  "",
93
- "function hasCommand(cmd) {",
94
- ' if (process.platform === "win32") {',
95
- ' const r = run("where", [cmd]);',
96
- " return r.status === 0;",
94
+ "function runInherit(cmd, args, opts = {}) {",
95
+ " return spawnSync(cmd, args, {",
96
+ ' stdio: "inherit",',
97
+ ' encoding: "utf8",',
98
+ " shell: false,",
99
+ " ...opts,",
100
+ " });",
101
+ "}",
102
+ "",
103
+ "function normalizeRelPath(p) {",
104
+ ' return String(p || "").replace(/\\\\/g, "/");',
105
+ "}",
106
+ "",
107
+ "function readJsonIfExists(filePath) {",
108
+ " try {",
109
+ " if (!fs.existsSync(filePath)) return undefined;",
110
+ ' const raw = fs.readFileSync(filePath, "utf8");',
111
+ " return JSON.parse(raw);",
112
+ " } catch {",
113
+ " return undefined;",
97
114
  " }",
98
- ' const check = "command -v " + cmd + " >/dev/null 2>&1";',
99
- ' const r = run("sh", ["-lc", check]);',
100
- " return r.status === 0;",
101
115
  "}",
102
116
  "",
103
- "function escapePsSingleQuotes(value) {",
104
- ' return String(value || "").replace(/\'/g, "\'\'");',
117
+ "function detectTypeScriptProject() {",
118
+ ' if (fs.existsSync("tsconfig.json")) return true;',
119
+ ' const pkg = readJsonIfExists("package.json");',
120
+ ' const buildScript = String(pkg?.scripts?.build || "");',
121
+ ' if (buildScript.includes("tsc")) return true;',
122
+ " if (pkg?.devDependencies?.typescript) return true;",
123
+ " return false;",
124
+ "}",
125
+ "",
126
+ "function detectDistEntry() {",
127
+ " // default requested: /dist/index.js",
128
+ ' const defaultEntry = "dist/index.js";',
129
+ ' const pkg = readJsonIfExists("package.json");',
130
+ ' const start = String(pkg?.scripts?.start || "").trim();',
131
+ " const m = /^node\\s+(.+)$/.exec(start);",
132
+ ' const inferred = m && m[1] ? String(m[1]).trim() : "";',
133
+ " const entry = inferred || defaultEntry;",
134
+ " return normalizeRelPath(entry);",
135
+ "}",
136
+ "",
137
+ "function ensureGitRepoRoot() {",
138
+ ' const r = run("git", ["rev-parse", "--show-toplevel"], { cwd: process.cwd() });',
139
+ " if (r.status !== 0) {",
140
+ ' const err = (r.stderr || r.stdout || "").trim();',
141
+ " throw new Error(",
142
+ ' "git repo is required for packaging (to respect .gitignore).\\n" + err,',
143
+ " );",
144
+ " }",
145
+ ' const top = String(r.stdout || "").trim();',
146
+ ' if (!top) throw new Error("Failed to resolve git repo root");',
147
+ " process.chdir(top);",
148
+ " return top;",
105
149
  "}",
106
150
  "",
107
151
  "function gitFileList() {",
@@ -121,21 +165,100 @@ function packagingScriptMjs(): string {
121
165
  " }",
122
166
  "",
123
167
  ' const raw = r.stdout || "";',
124
- ' return raw.split("\\u0000").filter(Boolean);',
168
+ ' return raw.split("\\u0000").filter(Boolean).map(normalizeRelPath);',
169
+ "}",
170
+ "",
171
+ "function shouldExcludeFromPackage(relPath) {",
172
+ " const p = normalizeRelPath(relPath);",
173
+ " if (!p) return true;",
174
+ " // 1) scripts/package.mjs does not need to be packaged",
175
+ ' if (p === "scripts/package.mjs") return true;',
176
+ " // temp files created by this script",
177
+ ' if (p.startsWith(".glosc-tmp/")) return true;',
178
+ " return false;",
179
+ "}",
180
+ "",
181
+ "function uniqStable(list) {",
182
+ " const seen = new Set();",
183
+ " const out = [];",
184
+ " for (const item of list) {",
185
+ " if (seen.has(item)) continue;",
186
+ " seen.add(item);",
187
+ " out.push(item);",
188
+ " }",
189
+ " return out;",
125
190
  "}",
126
191
  "",
127
192
  "async function ensureDir(p) {",
128
193
  " await fsp.mkdir(p, { recursive: true });",
129
194
  "}",
130
195
  "",
131
- "async function writeTempFileList(filePaths) {",
196
+ "async function prepareTmpDir() {",
132
197
  ' const tmpDir = path.join(process.cwd(), ".glosc-tmp");',
198
+ " await fsp.rm(tmpDir, { recursive: true, force: true });",
133
199
  " await ensureDir(tmpDir);",
134
- ' const listPath = path.join(tmpDir, "zip-file-list.txt");',
135
- ' await fsp.writeFile(listPath, filePaths.join("\\n"), "utf8");',
200
+ " return tmpDir;",
201
+ "}",
202
+ "",
203
+ "async function writeNulSeparatedList(tmpDir, filePaths) {",
204
+ " // Use NUL-separated pathspec so we can pass it to git safely (no quoting issues).",
205
+ ' const listPath = path.join(tmpDir, "pathspec.nul");',
206
+ " const normalized = filePaths.map(normalizeRelPath);",
207
+ ' const buf = Buffer.from(normalized.join("\u0000") + "\u0000", "utf8");',
208
+ " await fsp.writeFile(listPath, buf);",
136
209
  " return listPath;",
137
210
  "}",
138
211
  "",
212
+ "function gitArchiveZipFromWorkingTreeFiles(outZip, filePaths) {",
213
+ " // Create a temporary index so we can archive *tracked + untracked* files without",
214
+ " // touching the user's real index or requiring a commit.",
215
+ ' const tmpIndex = path.join(process.cwd(), ".glosc-tmp", "index");',
216
+ " const env = { ...process.env, GIT_INDEX_FILE: tmpIndex };",
217
+ "",
218
+ " // Add files (force-add so ignored build output like dist/index.js can be included).",
219
+ " const add = run(",
220
+ ' "git",',
221
+ " [",
222
+ ' "add",',
223
+ ' "-f",',
224
+ ' "--pathspec-from-file=.glosc-tmp/pathspec.nul",',
225
+ ' "--pathspec-file-nul",',
226
+ ' "--",',
227
+ " ],",
228
+ " { cwd: process.cwd(), env },",
229
+ " );",
230
+ " if (add.status !== 0) {",
231
+ " // Fallback for older Git versions without --pathspec-from-file.",
232
+ " const chunkSize = 200;",
233
+ " for (let i = 0; i < filePaths.length; i += chunkSize) {",
234
+ " const chunk = filePaths.slice(i, i + chunkSize);",
235
+ ' const r = run("git", ["add", "-f", "--", ...chunk], { cwd: process.cwd(), env });',
236
+ " if (r.status !== 0) {",
237
+ ' const err = (r.stderr || r.stdout || "").trim();',
238
+ ' throw new Error("git add (temp index) failed\\n" + err);',
239
+ " }",
240
+ " }",
241
+ " }",
242
+ "",
243
+ ' const wt = run("git", ["write-tree"], { cwd: process.cwd(), env });',
244
+ " if (wt.status !== 0) {",
245
+ ' const err = (wt.stderr || wt.stdout || "").trim();',
246
+ ' throw new Error("git write-tree failed\\n" + err);',
247
+ " }",
248
+ ' const tree = String(wt.stdout || "").trim();',
249
+ ' if (!tree) throw new Error("git write-tree produced empty tree hash");',
250
+ "",
251
+ " const ar = run(",
252
+ ' "git",',
253
+ ' ["archive", "--format=zip", "--output", outZip, tree],',
254
+ " { cwd: process.cwd() },",
255
+ " );",
256
+ " if (ar.status !== 0) {",
257
+ ' const err = (ar.stderr || ar.stdout || "").trim();',
258
+ ' throw new Error("git archive failed\\n" + err);',
259
+ " }",
260
+ "}",
261
+ "",
139
262
  "function timestamp() {",
140
263
  " const d = new Date();",
141
264
  ' const pad = (n) => String(n).padStart(2, "0");',
@@ -151,7 +274,33 @@ function packagingScriptMjs(): string {
151
274
  "}",
152
275
  "",
153
276
  "async function main() {",
154
- " const files = gitFileList();",
277
+ " ensureGitRepoRoot();",
278
+ " const isTs = detectTypeScriptProject();",
279
+ " const distEntry = detectDistEntry();",
280
+ ' const isWin = process.platform === "win32";',
281
+ "",
282
+ " // 2) For TypeScript, run build and package dist entry",
283
+ " if (isTs) {",
284
+ " const r = isWin",
285
+ ' ? runInherit("cmd", ["/d", "/s", "/c", "npm run build"], { cwd: process.cwd() })',
286
+ ' : runInherit("npm", ["run", "build"], { cwd: process.cwd() });',
287
+ ' if (r.error) throw new Error("Failed to run npm: " + String(r.error?.message || r.error));',
288
+ ' if (r.status !== 0) throw new Error("npm run build failed");',
289
+ " if (!fs.existsSync(distEntry)) {",
290
+ ' throw new Error("Expected build output missing: " + distEntry);',
291
+ " }",
292
+ " }",
293
+ "",
294
+ " let files = gitFileList().filter((p) => !shouldExcludeFromPackage(p));",
295
+ "",
296
+ " if (isTs) {",
297
+ " // dist/ is typically ignored; ensure we still include the built entry",
298
+ ' files = files.filter((p) => !p.startsWith("dist/"));',
299
+ " files.push(distEntry);",
300
+ " }",
301
+ "",
302
+ " files = uniqStable(files);",
303
+ "",
155
304
  " if (files.length === 0) {",
156
305
  " throw new Error(",
157
306
  ' "No files found to package. If you just created the project, make sure git is initialized and .gitignore exists.",',
@@ -162,56 +311,23 @@ function packagingScriptMjs(): string {
162
311
  " await ensureDir(outDir);",
163
312
  ' const outZip = path.join(outDir, "glosc-package-" + timestamp() + ".zip");',
164
313
  "",
165
- " const listPath = await writeTempFileList(files);",
166
- "",
314
+ " const tmpDir = await prepareTmpDir();",
167
315
  " try {",
168
- ' if (hasCommand("powershell")) {',
169
- " const listEsc = escapePsSingleQuotes(listPath);",
170
- " const outEsc = escapePsSingleQuotes(outZip);",
171
- " const psCommand = [",
172
- ' "$paths = Get-Content -LiteralPath \\\'" + listEsc + "\\\';",',
173
- ' "Compress-Archive -LiteralPath $paths -DestinationPath \\\'" + outEsc + "\\\' -Force -CompressionLevel Optimal;",',
174
- ' ].join(" ");',
175
- " const psArgs = [",
176
- ' "-NoProfile",',
177
- ' "-ExecutionPolicy",',
178
- ' "Bypass",',
179
- ' "-Command",',
180
- " psCommand,",
181
- " ];",
182
- ' const r = run("powershell", psArgs, { cwd: process.cwd() });',
183
- ' if (r.status !== 0) throw new Error((r.stderr || r.stdout || "").trim());',
184
- ' } else if (hasCommand("pwsh")) {',
185
- " const listEsc = escapePsSingleQuotes(listPath);",
186
- " const outEsc = escapePsSingleQuotes(outZip);",
187
- " const psCommand = [",
188
- ' "$paths = Get-Content -LiteralPath \\\'" + listEsc + "\\\';",',
189
- ' "Compress-Archive -LiteralPath $paths -DestinationPath \\\'" + outEsc + "\\\' -Force -CompressionLevel Optimal;",',
190
- ' ].join(" ");',
191
- ' const psArgs = ["-NoProfile", "-Command", psCommand];',
192
- ' const r = run("pwsh", psArgs, { cwd: process.cwd() });',
193
- ' if (r.status !== 0) throw new Error((r.stderr || r.stdout || "").trim());',
194
- ' } else if (hasCommand("zip")) {',
195
- ' const r = spawnSync("zip", ["-q", "-r", outZip, "-@"], {',
196
- " cwd: process.cwd(),",
197
- ' input: files.join("\\n"),',
198
- ' stdio: ["pipe", "pipe", "pipe"],',
199
- ' encoding: "utf8",',
200
- " });",
201
- ' if (r.status !== 0) throw new Error((r.stderr || r.stdout || "").trim());',
202
- " } else {",
203
- " throw new Error(",
204
- ' "No zip backend found. Install Git + PowerShell (Windows) or `zip` (macOS/Linux), then rerun.",',
205
- " );",
206
- " }",
316
+ " await writeNulSeparatedList(tmpDir, files);",
317
+ " gitArchiveZipFromWorkingTreeFiles(outZip, files);",
207
318
  " } finally {",
208
319
  " try {",
209
- " await fsp.rm(path.dirname(listPath), { recursive: true, force: true });",
320
+ " await fsp.rm(tmpDir, { recursive: true, force: true });",
210
321
  " } catch {",
211
322
  " // ignore",
212
323
  " }",
213
324
  " }",
214
325
  "",
326
+ " const st = await fsp.stat(outZip).catch(() => undefined);",
327
+ " if (!st || st.size <= 0) {",
328
+ ' throw new Error("Packaging failed: zip was not created: " + outZip);',
329
+ " }",
330
+ "",
215
331
  ' console.log("Created: " + outZip);',
216
332
  "}",
217
333
  "",
@@ -341,7 +457,7 @@ function nodePackageJson(options: ProjectOptions): string {
341
457
  private: true,
342
458
  type: "module",
343
459
  scripts: {
344
- build: "tsc -p .",
460
+ build: `esbuild src/${mainFileName} --bundle --platform=node --format=esm --target=es2022 --packages=external --sourcemap --outfile=${distEntry}`,
345
461
  start: `node ${distEntry}`,
346
462
  package: "node scripts/package.mjs",
347
463
  },
@@ -349,6 +465,7 @@ function nodePackageJson(options: ProjectOptions): string {
349
465
  "@modelcontextprotocol/sdk": "^1.24.3",
350
466
  },
351
467
  devDependencies: {
468
+ esbuild: "^0.20.2",
352
469
  typescript: "^5.9.3",
353
470
  "@types/node": "^22.19.2",
354
471
  },