@tokmo/create-buildroom 0.0.0-stage → 0.2.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.
- package/dist/cli.js +418 -0
- package/package.json +19 -4
- package/README.md +0 -3
package/dist/cli.js
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
|
|
4
|
+
// src/cli.ts
|
|
5
|
+
import { mkdir, readFile, writeFile, access } from "fs/promises";
|
|
6
|
+
import { dirname, resolve } from "path";
|
|
7
|
+
import { parseArgs } from "util";
|
|
8
|
+
// package.json
|
|
9
|
+
var package_default = {
|
|
10
|
+
name: "@tokmo/create-buildroom",
|
|
11
|
+
version: "0.2.0",
|
|
12
|
+
type: "module",
|
|
13
|
+
bin: {
|
|
14
|
+
"create-buildroom": "dist/cli.js"
|
|
15
|
+
},
|
|
16
|
+
files: ["dist"],
|
|
17
|
+
publishConfig: {
|
|
18
|
+
access: "public"
|
|
19
|
+
},
|
|
20
|
+
scripts: {
|
|
21
|
+
test: "bun test",
|
|
22
|
+
typecheck: "tsc --noEmit",
|
|
23
|
+
build: "bun build src/cli.ts --target bun --outfile dist/cli.js"
|
|
24
|
+
},
|
|
25
|
+
devDependencies: {
|
|
26
|
+
typescript: "^5.0.0",
|
|
27
|
+
"@types/bun": "latest"
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// src/text.ts
|
|
32
|
+
function toLF(text) {
|
|
33
|
+
return text.replace(/^\uFEFF/, "").replace(/\r\n?/g, `
|
|
34
|
+
`);
|
|
35
|
+
}
|
|
36
|
+
function toLines(text) {
|
|
37
|
+
if (text === null)
|
|
38
|
+
return [];
|
|
39
|
+
const lf = toLF(text);
|
|
40
|
+
if (lf === "")
|
|
41
|
+
return [];
|
|
42
|
+
return (lf.endsWith(`
|
|
43
|
+
`) ? lf.slice(0, -1) : lf).split(`
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
function fromLines(lines) {
|
|
47
|
+
return lines.length === 0 ? "" : lines.join(`
|
|
48
|
+
`) + `
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/bunfig.ts
|
|
53
|
+
var SECTION = "[install.scopes]";
|
|
54
|
+
function upsertScope(existing, scope, url, tokenVar) {
|
|
55
|
+
const lines = toLines(existing);
|
|
56
|
+
const entry = `"${scope}" = { url = "${url}", token = "$${tokenVar}" }`;
|
|
57
|
+
const tableForms = new Set([`[install.scopes."${scope}"]`, `[install.scopes.'${scope}']`]);
|
|
58
|
+
if (lines.some((l) => tableForms.has(l.trim())))
|
|
59
|
+
return fromLines(lines);
|
|
60
|
+
const header = lines.findIndex((l) => l.trim() === SECTION);
|
|
61
|
+
if (header === -1) {
|
|
62
|
+
const body = [...lines];
|
|
63
|
+
while (body.length > 0 && body[body.length - 1].trim() === "")
|
|
64
|
+
body.pop();
|
|
65
|
+
return fromLines([...body, ...body.length > 0 ? [""] : [], SECTION, entry]);
|
|
66
|
+
}
|
|
67
|
+
let end = lines.length;
|
|
68
|
+
for (let i = header + 1;i < lines.length; i++) {
|
|
69
|
+
if (lines[i].trimStart().startsWith("[")) {
|
|
70
|
+
end = i;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const keyForms = [`"${scope}"`, `'${scope}'`];
|
|
75
|
+
const present = lines.slice(header + 1, end).some((l) => {
|
|
76
|
+
const t = l.trimStart();
|
|
77
|
+
return keyForms.some((k) => t.startsWith(k) && t.slice(k.length).trimStart().startsWith("="));
|
|
78
|
+
});
|
|
79
|
+
if (present)
|
|
80
|
+
return fromLines(lines);
|
|
81
|
+
return fromLines([...lines.slice(0, header + 1), entry, ...lines.slice(header + 1)]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/config.ts
|
|
85
|
+
var REGISTRY_URL = "https://gitlab.com/api/v4/projects/tokmo%2Fbuildroom/packages/npm/";
|
|
86
|
+
var SCOPE = "@tokmo";
|
|
87
|
+
var TOKEN_VAR = "BUILDROOM_TOKEN";
|
|
88
|
+
var PACKAGE = "@tokmo/buildroom";
|
|
89
|
+
var ENV_EXAMPLE_BLOCK = [
|
|
90
|
+
"# Jeton GitLab pour installer @tokmo/buildroom (scope read_api).",
|
|
91
|
+
"# Copie ce fichier en .env et colle ton jeton : https://gitlab.com/-/user_settings/personal_access_tokens",
|
|
92
|
+
`${TOKEN_VAR}=`
|
|
93
|
+
].join(`
|
|
94
|
+
`);
|
|
95
|
+
|
|
96
|
+
// src/dotenv.ts
|
|
97
|
+
function definesVar(line, name) {
|
|
98
|
+
const t = line.trimStart();
|
|
99
|
+
if (t === "" || t.startsWith("#"))
|
|
100
|
+
return false;
|
|
101
|
+
return t.startsWith(`${name}=`);
|
|
102
|
+
}
|
|
103
|
+
function unquote(raw) {
|
|
104
|
+
const v = raw.trim();
|
|
105
|
+
if (v.length >= 2) {
|
|
106
|
+
const q = v[0];
|
|
107
|
+
if ((q === '"' || q === "'") && v[v.length - 1] === q)
|
|
108
|
+
return v.slice(1, -1).trim();
|
|
109
|
+
}
|
|
110
|
+
return v;
|
|
111
|
+
}
|
|
112
|
+
function readEnvVar(content, name) {
|
|
113
|
+
for (const line of toLines(content)) {
|
|
114
|
+
if (!definesVar(line, name))
|
|
115
|
+
continue;
|
|
116
|
+
const value = unquote(line.trimStart().slice(name.length + 1));
|
|
117
|
+
return value === "" ? null : value;
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
function upsertEnvVar(existing, name, value) {
|
|
122
|
+
const out = [];
|
|
123
|
+
let done = false;
|
|
124
|
+
for (const line of toLines(existing)) {
|
|
125
|
+
if (definesVar(line, name)) {
|
|
126
|
+
if (!done)
|
|
127
|
+
out.push(`${name}=${value}`);
|
|
128
|
+
done = true;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
out.push(line);
|
|
132
|
+
}
|
|
133
|
+
if (!done)
|
|
134
|
+
out.push(`${name}=${value}`);
|
|
135
|
+
return fromLines(out);
|
|
136
|
+
}
|
|
137
|
+
function ensureEnvExample(existing) {
|
|
138
|
+
const lines = toLines(existing);
|
|
139
|
+
if (lines.some((l) => definesVar(l, TOKEN_VAR)))
|
|
140
|
+
return fromLines(lines);
|
|
141
|
+
return fromLines([...lines, ...ENV_EXAMPLE_BLOCK.split(`
|
|
142
|
+
`)]);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/lines.ts
|
|
146
|
+
function ensureLine(existing, line, equivalents = []) {
|
|
147
|
+
const lines = toLines(existing);
|
|
148
|
+
const wanted = new Set([line, ...equivalents]);
|
|
149
|
+
if (lines.some((l) => wanted.has(l.trim())))
|
|
150
|
+
return fromLines(lines);
|
|
151
|
+
return fromLines([...lines, line]);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/package-json.ts
|
|
155
|
+
function minimalPackageJson(folderName) {
|
|
156
|
+
const name = folderName.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "project";
|
|
157
|
+
return JSON.stringify({ name, private: true }, null, 2) + `
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/steps.ts
|
|
162
|
+
var FOREIGN_LOCKFILES = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock"];
|
|
163
|
+
function sanitizeToken(raw) {
|
|
164
|
+
let value = raw.trim();
|
|
165
|
+
if (value.length >= 2) {
|
|
166
|
+
const q = value[0];
|
|
167
|
+
if ((q === '"' || q === "'") && value[value.length - 1] === q)
|
|
168
|
+
value = value.slice(1, -1).trim();
|
|
169
|
+
}
|
|
170
|
+
if (!/^[A-Za-z0-9_.-]+$/.test(value))
|
|
171
|
+
return null;
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
function sameContent(current, next) {
|
|
175
|
+
const norm = (s) => toLF(s).replace(/\n$/, "");
|
|
176
|
+
return norm(current) === norm(next);
|
|
177
|
+
}
|
|
178
|
+
function folderNameOf(cwd) {
|
|
179
|
+
return cwd.split(/[\\/]/).filter(Boolean).pop() ?? "";
|
|
180
|
+
}
|
|
181
|
+
async function runInstaller(io, args) {
|
|
182
|
+
const writeIfChanged = async (path, current, next) => {
|
|
183
|
+
if (current !== null && sameContent(current, next))
|
|
184
|
+
return false;
|
|
185
|
+
await io.writeFile(path, next);
|
|
186
|
+
return true;
|
|
187
|
+
};
|
|
188
|
+
for (const lock of FOREIGN_LOCKFILES) {
|
|
189
|
+
if (await io.exists(lock)) {
|
|
190
|
+
io.err(`Attention : ${lock} d\xE9tect\xE9. Buildroom s'installe avec Bun ; l'installation continue avec Bun.`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const envRaw = io.env[TOKEN_VAR];
|
|
194
|
+
const envFile = await io.readFile(".env");
|
|
195
|
+
let raw = envRaw !== undefined && envRaw.trim() !== "" ? envRaw : null;
|
|
196
|
+
if (raw === null && envFile !== null)
|
|
197
|
+
raw = readEnvVar(envFile, TOKEN_VAR);
|
|
198
|
+
const fromEnv = raw !== null && envRaw !== undefined && envRaw.trim() !== "";
|
|
199
|
+
let typed = false;
|
|
200
|
+
if (raw === null) {
|
|
201
|
+
if (!io.isTTY) {
|
|
202
|
+
io.err(`${TOKEN_VAR} est absent et ce terminal n'est pas interactif : rien n'a \xE9t\xE9 \xE9crit.`);
|
|
203
|
+
io.err("D\xE9finis la variable, puis relance la commande :");
|
|
204
|
+
io.err(` macOS / WSL : export ${TOKEN_VAR}=\u2026`);
|
|
205
|
+
io.err(` Windows : setx ${TOKEN_VAR} "\u2026" (puis ouvre un nouveau terminal)`);
|
|
206
|
+
io.err(` ou ajoute la ligne ${TOKEN_VAR}=\u2026 dans le fichier .env du dossier courant.`);
|
|
207
|
+
return 1;
|
|
208
|
+
}
|
|
209
|
+
const answer = await io.readSecret(`Jeton GitLab (${TOKEN_VAR}, scope read_api) : `);
|
|
210
|
+
if (answer === null) {
|
|
211
|
+
io.err("Saisie annul\xE9e : rien n'a \xE9t\xE9 \xE9crit.");
|
|
212
|
+
return 1;
|
|
213
|
+
}
|
|
214
|
+
raw = answer;
|
|
215
|
+
typed = true;
|
|
216
|
+
}
|
|
217
|
+
const token = sanitizeToken(raw);
|
|
218
|
+
if (token === null) {
|
|
219
|
+
io.err(`${TOKEN_VAR} est vide ou invalide (seuls lettres, chiffres, \xAB _ \xBB, \xAB . \xBB et \xAB - \xBB sont permis) : rien n'a \xE9t\xE9 \xE9crit.`);
|
|
220
|
+
io.err("V\xE9rifie le jeton copi\xE9 depuis GitLab, puis relance la commande.");
|
|
221
|
+
return 1;
|
|
222
|
+
}
|
|
223
|
+
const gitignore = await io.readFile(".gitignore");
|
|
224
|
+
if (await writeIfChanged(".gitignore", gitignore, ensureLine(gitignore, ".env", ["/.env"]))) {
|
|
225
|
+
io.out(".gitignore : ligne .env ajout\xE9e");
|
|
226
|
+
}
|
|
227
|
+
if (typed) {
|
|
228
|
+
if (await writeIfChanged(".env", envFile, upsertEnvVar(envFile, TOKEN_VAR, token))) {
|
|
229
|
+
io.out(`.env : ${TOKEN_VAR} enregistr\xE9`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const example = await io.readFile(".env.example");
|
|
233
|
+
if (await writeIfChanged(".env.example", example, ensureEnvExample(example))) {
|
|
234
|
+
io.out(".env.example : compl\xE9t\xE9");
|
|
235
|
+
}
|
|
236
|
+
if (!await io.exists("package.json")) {
|
|
237
|
+
await io.writeFile("package.json", minimalPackageJson(folderNameOf(io.cwd)));
|
|
238
|
+
io.out("package.json : cr\xE9\xE9");
|
|
239
|
+
}
|
|
240
|
+
const bunfig = await io.readFile("bunfig.toml");
|
|
241
|
+
if (await writeIfChanged("bunfig.toml", bunfig, upsertScope(bunfig, SCOPE, REGISTRY_URL, TOKEN_VAR))) {
|
|
242
|
+
io.out(`bunfig.toml : registre ${SCOPE} configur\xE9`);
|
|
243
|
+
}
|
|
244
|
+
const env = {};
|
|
245
|
+
for (const [k, v] of Object.entries(io.env))
|
|
246
|
+
if (v !== undefined)
|
|
247
|
+
env[k] = v;
|
|
248
|
+
env[TOKEN_VAR] = token;
|
|
249
|
+
io.out(`Installation de ${PACKAGE}\u2026`);
|
|
250
|
+
const add = await io.spawn(["bun", "add", "-d", PACKAGE], env);
|
|
251
|
+
if (add.code !== 0) {
|
|
252
|
+
if (/\b40[13]\b/.test(add.output)) {
|
|
253
|
+
const where = fromEnv ? "(variable d'environnement)" : "dans .env";
|
|
254
|
+
io.err(`Jeton refus\xE9 par GitLab : v\xE9rifie ${TOKEN_VAR} ${where} (scope read_api).`);
|
|
255
|
+
} else if (/\b404\b/.test(add.output)) {
|
|
256
|
+
io.err(`Paquet ${PACKAGE} introuvable : le jeton a-t-il acc\xE8s au projet tokmo/buildroom ?`);
|
|
257
|
+
} else {
|
|
258
|
+
io.err(add.output.split(token).join("***").trimEnd());
|
|
259
|
+
}
|
|
260
|
+
return 1;
|
|
261
|
+
}
|
|
262
|
+
const init = await io.spawn(["bun", "x", "build-room", "init", ...args.key ? ["--key", args.key] : []], env, {
|
|
263
|
+
inherit: true
|
|
264
|
+
});
|
|
265
|
+
return init.code;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/cli.ts
|
|
269
|
+
var HELP = `Installateur Buildroom (${package_default.name} ${package_default.version})
|
|
270
|
+
|
|
271
|
+
Usage :
|
|
272
|
+
bun create @tokmo/buildroom [--key <CL\xC9>]
|
|
273
|
+
|
|
274
|
+
Options :
|
|
275
|
+
--key <CL\xC9> Cl\xE9 du projet (ex. YT), transmise \xE0 \`build-room init\`.
|
|
276
|
+
--help Affiche cette aide.
|
|
277
|
+
|
|
278
|
+
Le jeton GitLab est lu dans BUILDROOM_TOKEN (environnement ou .env),
|
|
279
|
+
sinon il est demand\xE9 en saisie masqu\xE9e.`;
|
|
280
|
+
function readSecretFromStdin(question) {
|
|
281
|
+
const stdin = process.stdin;
|
|
282
|
+
if (!stdin.isTTY || typeof stdin.setRawMode !== "function")
|
|
283
|
+
return Promise.resolve(null);
|
|
284
|
+
return new Promise((done) => {
|
|
285
|
+
let value = "";
|
|
286
|
+
const finish = (result) => {
|
|
287
|
+
stdin.off("data", onData);
|
|
288
|
+
stdin.off("end", onEnd);
|
|
289
|
+
stdin.off("close", onEnd);
|
|
290
|
+
stdin.off("error", onEnd);
|
|
291
|
+
stdin.setRawMode(false);
|
|
292
|
+
stdin.pause();
|
|
293
|
+
process.stdout.write(`
|
|
294
|
+
`);
|
|
295
|
+
done(result);
|
|
296
|
+
};
|
|
297
|
+
const onData = (chunk) => {
|
|
298
|
+
for (const ch of chunk.toString()) {
|
|
299
|
+
if (ch === "\x03")
|
|
300
|
+
return finish(null);
|
|
301
|
+
if (ch === "\r" || ch === `
|
|
302
|
+
`)
|
|
303
|
+
return finish(value);
|
|
304
|
+
if (ch === "\b" || ch === "\x7F") {
|
|
305
|
+
if (value.length > 0) {
|
|
306
|
+
value = value.slice(0, -1);
|
|
307
|
+
process.stdout.write("\b \b");
|
|
308
|
+
}
|
|
309
|
+
} else if (ch >= " ") {
|
|
310
|
+
value += ch;
|
|
311
|
+
process.stdout.write("*");
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
const onEnd = () => finish(null);
|
|
316
|
+
process.stdout.write(question);
|
|
317
|
+
stdin.setRawMode(true);
|
|
318
|
+
stdin.resume();
|
|
319
|
+
stdin.on("data", onData);
|
|
320
|
+
stdin.on("end", onEnd);
|
|
321
|
+
stdin.on("close", onEnd);
|
|
322
|
+
stdin.on("error", onEnd);
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
function createNodeInstallerIo() {
|
|
326
|
+
const cwd = process.cwd();
|
|
327
|
+
const abs = (p) => resolve(cwd, p);
|
|
328
|
+
return {
|
|
329
|
+
cwd,
|
|
330
|
+
env: process.env,
|
|
331
|
+
isTTY: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
332
|
+
out: (line) => void process.stdout.write(line + `
|
|
333
|
+
`),
|
|
334
|
+
err: (line) => void process.stderr.write(line + `
|
|
335
|
+
`),
|
|
336
|
+
readSecret: readSecretFromStdin,
|
|
337
|
+
async readFile(path) {
|
|
338
|
+
try {
|
|
339
|
+
return await readFile(abs(path), "utf8");
|
|
340
|
+
} catch (e) {
|
|
341
|
+
if (e.code === "ENOENT")
|
|
342
|
+
return null;
|
|
343
|
+
throw e;
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
async writeFile(path, content) {
|
|
347
|
+
await mkdir(dirname(abs(path)), { recursive: true });
|
|
348
|
+
await writeFile(abs(path), content, "utf8");
|
|
349
|
+
},
|
|
350
|
+
async exists(path) {
|
|
351
|
+
try {
|
|
352
|
+
await access(abs(path));
|
|
353
|
+
return true;
|
|
354
|
+
} catch {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
async spawn(cmd, env, opts) {
|
|
359
|
+
try {
|
|
360
|
+
if (opts?.inherit) {
|
|
361
|
+
const p = Bun.spawn(cmd, { cwd, env, stdin: "inherit", stdout: "inherit", stderr: "inherit" });
|
|
362
|
+
return { code: await p.exited, output: "" };
|
|
363
|
+
}
|
|
364
|
+
const p = Bun.spawn(cmd, { cwd, env, stdin: "ignore", stdout: "pipe", stderr: "pipe" });
|
|
365
|
+
const [stdout, stderr, code] = await Promise.all([new Response(p.stdout).text(), new Response(p.stderr).text(), p.exited]);
|
|
366
|
+
return { code, output: stdout + stderr };
|
|
367
|
+
} catch (e) {
|
|
368
|
+
return { code: 1, output: e instanceof Error ? e.message : String(e) };
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function translateParseError(error) {
|
|
374
|
+
const raw = error instanceof Error ? error.message : String(error);
|
|
375
|
+
const code = error?.code;
|
|
376
|
+
const flag = /'(-[^'\s]+)/.exec(raw)?.[1];
|
|
377
|
+
if (code === "ERR_PARSE_ARGS_UNKNOWN_OPTION" && flag)
|
|
378
|
+
return `Option inconnue : ${flag}`;
|
|
379
|
+
if (code === "ERR_PARSE_ARGS_INVALID_OPTION_VALUE" && flag)
|
|
380
|
+
return `L'option ${flag} attend une valeur.`;
|
|
381
|
+
if (code === "ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL") {
|
|
382
|
+
const arg = /'([^']*)'/.exec(raw)?.[1];
|
|
383
|
+
return `Argument inattendu${arg === undefined ? "" : ` : \xAB ${arg} \xBB`}. Lance la commande depuis le dossier du projet.`;
|
|
384
|
+
}
|
|
385
|
+
return `Arguments invalides : ${raw}`;
|
|
386
|
+
}
|
|
387
|
+
async function main(argv, io) {
|
|
388
|
+
let values;
|
|
389
|
+
try {
|
|
390
|
+
values = parseArgs({
|
|
391
|
+
args: argv,
|
|
392
|
+
options: { key: { type: "string" }, help: { type: "boolean" } },
|
|
393
|
+
strict: true,
|
|
394
|
+
allowPositionals: false
|
|
395
|
+
}).values;
|
|
396
|
+
} catch (e) {
|
|
397
|
+
io.err(translateParseError(e));
|
|
398
|
+
io.err(HELP);
|
|
399
|
+
return 2;
|
|
400
|
+
}
|
|
401
|
+
if (values.help) {
|
|
402
|
+
io.out(HELP);
|
|
403
|
+
return 0;
|
|
404
|
+
}
|
|
405
|
+
try {
|
|
406
|
+
return await runInstaller(io, { key: values.key });
|
|
407
|
+
} catch (e) {
|
|
408
|
+
io.err(`Erreur inattendue : ${e instanceof Error ? e.message : String(e)}`);
|
|
409
|
+
return 1;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (import.meta.main) {
|
|
413
|
+
process.exit(await main(process.argv.slice(2), createNodeInstallerIo()));
|
|
414
|
+
}
|
|
415
|
+
export {
|
|
416
|
+
createNodeInstallerIo,
|
|
417
|
+
main
|
|
418
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokmo/create-buildroom",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-buildroom": "dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": ["dist"],
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "bun test",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"build": "bun build src/cli.ts --target bun --outfile dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.0.0",
|
|
19
|
+
"@types/bun": "latest"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/README.md
DELETED