@tulipes/cli 0.1.0-rc.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/LICENSE +21 -0
- package/README.md +46 -0
- package/dist/app-core.d.ts +33 -0
- package/dist/app-core.js +58 -0
- package/dist/app-core.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +7 -0
- package/dist/bin.js.map +1 -0
- package/dist/dev.d.ts +8 -0
- package/dist/dev.js +22 -0
- package/dist/dev.js.map +1 -0
- package/dist/env-check.d.ts +6 -0
- package/dist/env-check.js +28 -0
- package/dist/env-check.js.map +1 -0
- package/dist/init.d.ts +25 -0
- package/dist/init.js +6416 -0
- package/dist/init.js.map +1 -0
- package/dist/inspection.d.ts +8 -0
- package/dist/inspection.js +15 -0
- package/dist/inspection.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +166 -0
- package/dist/main.js.map +1 -0
- package/dist/minimal.d.ts +2 -0
- package/dist/minimal.js +2200 -0
- package/dist/minimal.js.map +1 -0
- package/dist/new-module.d.ts +19 -0
- package/dist/new-module.js +348 -0
- package/dist/new-module.js.map +1 -0
- package/dist/package-info.d.ts +18 -0
- package/dist/package-info.js +53 -0
- package/dist/package-info.js.map +1 -0
- package/dist/routes.d.ts +8 -0
- package/dist/routes.js +54 -0
- package/dist/routes.js.map +1 -0
- package/dist/spec.d.ts +19 -0
- package/dist/spec.js +101 -0
- package/dist/spec.js.map +1 -0
- package/dist/sync.d.ts +12 -0
- package/dist/sync.js +117 -0
- package/dist/sync.js.map +1 -0
- package/dist/update.d.ts +20 -0
- package/dist/update.js +240 -0
- package/dist/update.js.map +1 -0
- package/package.json +59 -0
- package/templates/CLAUDE.md +120 -0
- package/templates/browser-auth.md +120 -0
- package/templates/claude/skills/tulipes-boot-errors/SKILL.md +74 -0
- package/templates/claude/skills/tulipes-endpoint/SKILL.md +132 -0
- package/templates/claude/skills/tulipes-env-variable/SKILL.md +78 -0
- package/templates/claude/skills/tulipes-i18n/SKILL.md +98 -0
- package/templates/claude/skills/tulipes-model/SKILL.md +107 -0
- package/templates/claude/skills/tulipes-module/SKILL.md +67 -0
- package/templates/claude/skills/tulipes-permissions/SKILL.md +105 -0
- package/templates/claude/skills/tulipes-queue/SKILL.md +68 -0
- package/templates/claude/skills/tulipes-response/SKILL.md +118 -0
- package/templates/claude/skills/tulipes-settings/SKILL.md +111 -0
- package/templates/claude/skills/tulipes-socket/SKILL.md +60 -0
- package/templates/claude/skills/tulipes-spec/SKILL.md +101 -0
package/dist/spec.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { mkdirSync } from "node:fs";
|
|
4
|
+
import { importFromApp } from "./app-core.js";
|
|
5
|
+
import { inspectApp } from "./inspection.js";
|
|
6
|
+
export async function runSpec(rootDir, options) {
|
|
7
|
+
if (!options.openapi && !options.postman) {
|
|
8
|
+
console.error([
|
|
9
|
+
"nothing to write — name at least one output:",
|
|
10
|
+
"",
|
|
11
|
+
" tulipes spec --openapi openapi.json",
|
|
12
|
+
" tulipes spec --postman collection.json",
|
|
13
|
+
" tulipes spec --openapi openapi.json --postman collection.json --url https://api.example.com",
|
|
14
|
+
].join("\n"));
|
|
15
|
+
process.exitCode = 2;
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const spec = await loadGenerator(rootDir);
|
|
19
|
+
if (!spec)
|
|
20
|
+
return;
|
|
21
|
+
const handle = await inspectApp(rootDir, options.offline);
|
|
22
|
+
try {
|
|
23
|
+
const source = spec.extract(handle.ctx);
|
|
24
|
+
if (source.routes.length === 0) {
|
|
25
|
+
console.log("no routes declared — nothing to describe");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const url = options.url ?? (handle.env ? defaultUrl(handle.env) : "http://localhost:3000");
|
|
29
|
+
const warnings = new Set();
|
|
30
|
+
if (options.openapi) {
|
|
31
|
+
const { document, warnings: issues } = await spec.toOpenApi(source, { servers: [url] });
|
|
32
|
+
issues.forEach((issue) => warnings.add(issue));
|
|
33
|
+
write(options.openapi, document);
|
|
34
|
+
}
|
|
35
|
+
if (options.postman) {
|
|
36
|
+
const { document, warnings: issues } = await spec.toPostman(source, { baseUrl: url });
|
|
37
|
+
issues.forEach((issue) => warnings.add(issue));
|
|
38
|
+
write(options.postman, document);
|
|
39
|
+
}
|
|
40
|
+
console.log(`\n${source.routes.length} endpoint(s) across ${source.folders.length} folder(s): ` +
|
|
41
|
+
source.folders.join(", "));
|
|
42
|
+
// A schema that produced no shape still documents the endpoint, so
|
|
43
|
+
// this is a warning and not a failure — but it is worth saying,
|
|
44
|
+
// because the document is quietly less useful than it looks.
|
|
45
|
+
if (warnings.size > 0) {
|
|
46
|
+
console.warn(`\n${warnings.size} schema(s) could not be described:`);
|
|
47
|
+
for (const warning of warnings)
|
|
48
|
+
console.warn(` ! ${warning}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
await handle.shutdown();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Loads the generator **from the app**, not from wherever this CLI lives.
|
|
57
|
+
*
|
|
58
|
+
* `tulipes` is normally installed globally, so a bare `import("@tulipes/spec")`
|
|
59
|
+
* resolves against the CLI's own node_modules and misses the copy the app
|
|
60
|
+
* just installed — reporting it as absent while it sits right there. The
|
|
61
|
+
* app's own resolution root is the only one that can be right.
|
|
62
|
+
*/
|
|
63
|
+
async function loadGenerator(rootDir) {
|
|
64
|
+
for (const load of [() => fromApp(rootDir), fromCli]) {
|
|
65
|
+
const spec = await load();
|
|
66
|
+
if (spec)
|
|
67
|
+
return spec;
|
|
68
|
+
}
|
|
69
|
+
console.error([
|
|
70
|
+
"`tulipes spec` needs the generator package:",
|
|
71
|
+
"",
|
|
72
|
+
" yarn add -D @tulipes/spec",
|
|
73
|
+
"",
|
|
74
|
+
"It is separate so an app that never generates a spec never installs it.",
|
|
75
|
+
].join("\n"));
|
|
76
|
+
process.exitCode = 2;
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const fromApp = (rootDir) => importFromApp(rootDir, "@tulipes/spec");
|
|
80
|
+
/** A locally installed CLI, or a hoisted layout, resolves it directly. */
|
|
81
|
+
async function fromCli() {
|
|
82
|
+
try {
|
|
83
|
+
return (await import("@tulipes/spec"));
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Whatever the app itself would be reachable at, so the document is usable as written. */
|
|
90
|
+
function defaultUrl(env) {
|
|
91
|
+
const port = env.store.has("PORT") ? Number(env.get("PORT")) : 3000;
|
|
92
|
+
const domain = env.store.has("PUBLIC_DOMAIN") ? String(env.get("PUBLIC_DOMAIN")) : "localhost";
|
|
93
|
+
return domain === "localhost" ? `http://localhost:${port}` : `https://${domain}`;
|
|
94
|
+
}
|
|
95
|
+
function write(target, document) {
|
|
96
|
+
const path = resolve(target);
|
|
97
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
98
|
+
writeFileSync(path, `${JSON.stringify(document, null, 2)}\n`);
|
|
99
|
+
console.log(` wrote ${target}`);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=spec.js.map
|
package/dist/spec.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"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"}
|
package/dist/sync.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `tulipes sync` — everything derivable from the meta files, derived:
|
|
3
|
+
*
|
|
4
|
+
* types/config.d.ts KnownVariables + GlobalConfig augmentations. Config
|
|
5
|
+
* namespaces are typed as each factory's RETURN TYPE via
|
|
6
|
+
* `typeof import(...)` — the compiler does the inference,
|
|
7
|
+
* codegen never executes module code.
|
|
8
|
+
* .env.example every variable, grouped by module and `group`.
|
|
9
|
+
*
|
|
10
|
+
* Both files are committed and marked generated.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runSync(rootDir: string): Promise<void>;
|
package/dist/sync.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { BootReport } from "@tulipes/core/errors";
|
|
4
|
+
import { discoverModuleMeta } from "@tulipes/core/env";
|
|
5
|
+
import { discoverModules } from "@tulipes/core/modules";
|
|
6
|
+
import { sortModules } from "@tulipes/core/modules";
|
|
7
|
+
import { exploreModules } from "@tulipes/core/modules";
|
|
8
|
+
/**
|
|
9
|
+
* `tulipes sync` — everything derivable from the meta files, derived:
|
|
10
|
+
*
|
|
11
|
+
* types/config.d.ts KnownVariables + GlobalConfig augmentations. Config
|
|
12
|
+
* namespaces are typed as each factory's RETURN TYPE via
|
|
13
|
+
* `typeof import(...)` — the compiler does the inference,
|
|
14
|
+
* codegen never executes module code.
|
|
15
|
+
* .env.example every variable, grouped by module and `group`.
|
|
16
|
+
*
|
|
17
|
+
* Both files are committed and marked generated.
|
|
18
|
+
*/
|
|
19
|
+
export async function runSync(rootDir) {
|
|
20
|
+
const report = new BootReport();
|
|
21
|
+
const modulesDir = join(rootDir, "modules");
|
|
22
|
+
const metas = discoverModuleMeta(modulesDir, report);
|
|
23
|
+
const order = sortModules(discoverModules(modulesDir, report), report);
|
|
24
|
+
report.throwIfAny("sync");
|
|
25
|
+
const metaByModule = new Map(metas.map((meta) => [meta.module, meta]));
|
|
26
|
+
// Meta discovery walks folders; align it to load order for stable output.
|
|
27
|
+
const orderedMetas = order
|
|
28
|
+
.map((module) => metaByModule.get(module.name))
|
|
29
|
+
.filter((meta) => meta !== undefined);
|
|
30
|
+
const typesDir = join(rootDir, "types");
|
|
31
|
+
mkdirSync(typesDir, { recursive: true });
|
|
32
|
+
const dtsPath = join(typesDir, "config.d.ts");
|
|
33
|
+
writeFileSync(dtsPath, renderDts(rootDir, orderedMetas, order));
|
|
34
|
+
console.log(`wrote ${relative(rootDir, dtsPath)}`);
|
|
35
|
+
const envExamplePath = join(rootDir, ".env.example");
|
|
36
|
+
writeFileSync(envExamplePath, renderEnvExample(orderedMetas));
|
|
37
|
+
console.log(`wrote ${relative(rootDir, envExamplePath)}`);
|
|
38
|
+
}
|
|
39
|
+
function renderDts(rootDir, metas, order) {
|
|
40
|
+
const variableLines = metas.flatMap((meta) => meta.variables.flatMap((spec) => [
|
|
41
|
+
` /** [${meta.module}] ${spec.description} */`,
|
|
42
|
+
` ${spec.name}: ${tsTypeOf(spec)};`,
|
|
43
|
+
]));
|
|
44
|
+
// Only modules with a config factory get a typed namespace; the rest fall
|
|
45
|
+
// back to GlobalConfig's index signature.
|
|
46
|
+
const configLines = exploreModules(order)
|
|
47
|
+
.filter((files) => files.configFile)
|
|
48
|
+
.flatMap((files) => {
|
|
49
|
+
const specifier = "./" + relative(join(rootDir, "types"), files.configFile).replace(/\.ts$/, ".js");
|
|
50
|
+
// Optional on purpose: a namespace only exists once phase 6 has run
|
|
51
|
+
// its factory, and an empty config seed must stay assignable.
|
|
52
|
+
return [
|
|
53
|
+
` ${JSON.stringify(files.module.name)}?: Awaited<`,
|
|
54
|
+
` ReturnType<(typeof import("${specifier}"))["default"]>`,
|
|
55
|
+
` >;`,
|
|
56
|
+
];
|
|
57
|
+
});
|
|
58
|
+
return [
|
|
59
|
+
"// AUTO-GENERATED by `tulipes sync` — do not edit.",
|
|
60
|
+
"",
|
|
61
|
+
'declare module "@tulipes/core/env" {',
|
|
62
|
+
" interface KnownVariables {",
|
|
63
|
+
...variableLines,
|
|
64
|
+
" }",
|
|
65
|
+
"}",
|
|
66
|
+
"",
|
|
67
|
+
'declare module "@tulipes/core/config" {',
|
|
68
|
+
" interface GlobalConfig {",
|
|
69
|
+
...configLines,
|
|
70
|
+
" }",
|
|
71
|
+
"}",
|
|
72
|
+
"",
|
|
73
|
+
"export {};",
|
|
74
|
+
"",
|
|
75
|
+
].join("\n");
|
|
76
|
+
}
|
|
77
|
+
function tsTypeOf(spec) {
|
|
78
|
+
switch (spec.type) {
|
|
79
|
+
case "number":
|
|
80
|
+
return "number";
|
|
81
|
+
case "boolean":
|
|
82
|
+
return "boolean";
|
|
83
|
+
case "enum":
|
|
84
|
+
return spec.enum.map((value) => JSON.stringify(value)).join(" | ");
|
|
85
|
+
default: // string, url, secret
|
|
86
|
+
return "string";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function renderEnvExample(metas) {
|
|
90
|
+
const lines = [
|
|
91
|
+
"# AUTO-GENERATED by `tulipes sync` from every module's meta.variables.json.",
|
|
92
|
+
"# Copy into .envs/.env.<mode> and fill in the blanks.",
|
|
93
|
+
];
|
|
94
|
+
for (const meta of metas) {
|
|
95
|
+
if (meta.variables.length === 0)
|
|
96
|
+
continue;
|
|
97
|
+
lines.push("", `# ━━━ ${meta.module} ━━━`);
|
|
98
|
+
// Stable grouping: order of first appearance, ungrouped vars last.
|
|
99
|
+
const groups = new Map();
|
|
100
|
+
for (const spec of meta.variables) {
|
|
101
|
+
const key = spec.group ?? "";
|
|
102
|
+
(groups.get(key) ?? groups.set(key, []).get(key)).push(spec);
|
|
103
|
+
}
|
|
104
|
+
for (const [group, specs] of [...groups.entries()].sort(([a], [b]) => Number(a === "") - Number(b === ""))) {
|
|
105
|
+
if (group)
|
|
106
|
+
lines.push("", `# ── ${group} ──`);
|
|
107
|
+
for (const spec of specs) {
|
|
108
|
+
const constraint = spec.type === "enum" ? `enum: ${spec.enum.join(" | ")}` : spec.type;
|
|
109
|
+
const requirement = spec.required ? ", REQUIRED" : "";
|
|
110
|
+
lines.push(`# ${spec.description} (${constraint}${requirement})`);
|
|
111
|
+
lines.push(`${spec.name}=${spec.default ?? ""}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return lines.join("\n") + "\n";
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=sync.js.map
|
package/dist/sync.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
|
package/dist/update.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `tulipes update` — move to the latest published CLI and core.
|
|
3
|
+
*
|
|
4
|
+
* There are two things that can be out of date, and they are genuinely
|
|
5
|
+
* separate installs:
|
|
6
|
+
*
|
|
7
|
+
* the CLI the globally installed `tulipes` on your PATH (@tulipes/cli)
|
|
8
|
+
* the app @tulipes/core in the app root and in every module, since
|
|
9
|
+
* modules are workspace packages that declare it themselves,
|
|
10
|
+
* plus the app's own @tulipes/cli devDependency
|
|
11
|
+
*
|
|
12
|
+
* Provider packages (@tulipes/mongoose, /bullmq, /socket.io) follow their
|
|
13
|
+
* own lines and are not rewritten here; MIGRATING.md lists the pairing.
|
|
14
|
+
*
|
|
15
|
+
* Updating only the app leaves you typing an old CLI against a new
|
|
16
|
+
* framework; updating only the CLI leaves the app behind. This does both,
|
|
17
|
+
* and either alone when only one applies — so it is also useful outside an
|
|
18
|
+
* app, where it upgrades just the CLI.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runUpdate(rootDir: string): Promise<void>;
|
package/dist/update.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { appCoreVersion, cliVersion, packageRoot } from "./package-info.js";
|
|
5
|
+
const PACKAGE = "@tulipes/core";
|
|
6
|
+
const CLI = "@tulipes/cli";
|
|
7
|
+
const REGISTRY = "https://registry.npmjs.org";
|
|
8
|
+
/**
|
|
9
|
+
* `tulipes update` — move to the latest published CLI and core.
|
|
10
|
+
*
|
|
11
|
+
* There are two things that can be out of date, and they are genuinely
|
|
12
|
+
* separate installs:
|
|
13
|
+
*
|
|
14
|
+
* the CLI the globally installed `tulipes` on your PATH (@tulipes/cli)
|
|
15
|
+
* the app @tulipes/core in the app root and in every module, since
|
|
16
|
+
* modules are workspace packages that declare it themselves,
|
|
17
|
+
* plus the app's own @tulipes/cli devDependency
|
|
18
|
+
*
|
|
19
|
+
* Provider packages (@tulipes/mongoose, /bullmq, /socket.io) follow their
|
|
20
|
+
* own lines and are not rewritten here; MIGRATING.md lists the pairing.
|
|
21
|
+
*
|
|
22
|
+
* Updating only the app leaves you typing an old CLI against a new
|
|
23
|
+
* framework; updating only the CLI leaves the app behind. This does both,
|
|
24
|
+
* and either alone when only one applies — so it is also useful outside an
|
|
25
|
+
* app, where it upgrades just the CLI.
|
|
26
|
+
*/
|
|
27
|
+
export async function runUpdate(rootDir) {
|
|
28
|
+
const current = cliVersion();
|
|
29
|
+
let latest;
|
|
30
|
+
let latestCli;
|
|
31
|
+
try {
|
|
32
|
+
[latest, latestCli] = await Promise.all([fetchLatest(PACKAGE), fetchLatest(CLI)]);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error(`could not reach the npm registry: ${error.message}`);
|
|
36
|
+
process.exitCode = 1;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const cliRoot = packageRoot();
|
|
40
|
+
// Updatable-as-a-CLI means: an installed package (it lives under some
|
|
41
|
+
// node_modules) that is NOT this app's own copy — the app's copy is
|
|
42
|
+
// covered by the dependency update below. A source checkout matches
|
|
43
|
+
// neither and is left alone, since git owns its version, not npm.
|
|
44
|
+
const cliIsGlobal = !cliRoot.startsWith(resolve(rootDir) + sep) &&
|
|
45
|
+
cliRoot.includes(`${sep}node_modules${sep}`);
|
|
46
|
+
let didSomething = false;
|
|
47
|
+
if (cliIsGlobal) {
|
|
48
|
+
didSomething = true;
|
|
49
|
+
if (current === latestCli) {
|
|
50
|
+
console.log(`cli already on ${latestCli}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
await updateGlobalCli(cliRoot, current, latestCli);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const manifests = findManifests(rootDir);
|
|
57
|
+
if (manifests.length > 0) {
|
|
58
|
+
didSomething = true;
|
|
59
|
+
// The app's installed version, not the CLI's — they are separate
|
|
60
|
+
// installs, and reporting one as the other is how this whole confusion
|
|
61
|
+
// started.
|
|
62
|
+
await updateApp(rootDir, manifests, appCoreVersion(rootDir), latest, latestCli);
|
|
63
|
+
}
|
|
64
|
+
if (!didSomething) {
|
|
65
|
+
console.error(`no package.json in ${rootDir} depends on ${PACKAGE}, and this CLI is not a global install — run it from an app root`);
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Reinstalls the global CLI into the prefix it already lives in.
|
|
71
|
+
*
|
|
72
|
+
* That prefix matters: with a version manager, `npm install -g` installs
|
|
73
|
+
* for whichever node is *active*, which may not be the one whose bin
|
|
74
|
+
* directory holds the `tulipes` on your PATH. Deriving the prefix from the
|
|
75
|
+
* running CLI's own location updates the binary you actually type.
|
|
76
|
+
*/
|
|
77
|
+
async function updateGlobalCli(cliRoot, current, latest) {
|
|
78
|
+
console.log(`cli: ${current} → ${latest}`);
|
|
79
|
+
const prefix = globalPrefixOf(cliRoot);
|
|
80
|
+
const args = ["install", "-g", ...(prefix ? ["--prefix", prefix] : []), `${CLI}@${latest}`];
|
|
81
|
+
const code = await run("npm", args, cliRoot);
|
|
82
|
+
if (code !== 0) {
|
|
83
|
+
console.error(`\ncould not update the global cli — try: npm install -g ${CLI}@${latest}`);
|
|
84
|
+
process.exitCode = code === -1 ? 1 : code;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.log(`cli updated — the next \`tulipes\` invocation runs ${latest}\n`);
|
|
88
|
+
}
|
|
89
|
+
/** `<prefix>/lib/node_modules/@tulipes/cli` → `<prefix>`, for npm layouts. */
|
|
90
|
+
function globalPrefixOf(cliRoot) {
|
|
91
|
+
const marker = `${sep}lib${sep}node_modules${sep}`;
|
|
92
|
+
const index = cliRoot.indexOf(marker);
|
|
93
|
+
// pnpm and bun keep globals elsewhere; without a recognisable prefix we
|
|
94
|
+
// let npm pick its own, which is right for a plain npm install.
|
|
95
|
+
return index === -1 ? undefined : cliRoot.slice(0, index);
|
|
96
|
+
}
|
|
97
|
+
async function updateApp(rootDir, manifests, current, latest, latestCli) {
|
|
98
|
+
const range = `^${latest}`;
|
|
99
|
+
const changed = manifests.filter(({ path }) => rewrite(path, range));
|
|
100
|
+
// The app's own CLI devDependency moves with it, so `yarn dev` and friends
|
|
101
|
+
// keep matching the framework they generate for.
|
|
102
|
+
if (rewrite(join(rootDir, "package.json"), `^${latestCli}`, CLI))
|
|
103
|
+
changed.push({ path: join(rootDir, "package.json") });
|
|
104
|
+
if (changed.length === 0) {
|
|
105
|
+
console.log(`app already on ${PACKAGE}@${range}`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
for (const { path } of changed) {
|
|
109
|
+
console.log(` update ${relative(rootDir, path) || "package.json"} → ${range}`);
|
|
110
|
+
}
|
|
111
|
+
console.log(`\napp: ${current ?? "not installed"} → ${latest}\n`);
|
|
112
|
+
// Rewriting manifests without installing would leave the app claiming a
|
|
113
|
+
// version it does not have.
|
|
114
|
+
const manager = detectManager(rootDir);
|
|
115
|
+
console.log(`running ${manager} install…\n`);
|
|
116
|
+
const code = await run(manager, ["install"], rootDir);
|
|
117
|
+
if (code === -1) {
|
|
118
|
+
console.error(`\ncould not run "${manager}" — manifests are updated, install manually`);
|
|
119
|
+
process.exitCode = 1;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (code !== 0) {
|
|
123
|
+
process.exitCode = code;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
warnAboutBreakingChanges(current, latest);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Minor bumps below 1.0 carry breaking changes in this project, and an app
|
|
130
|
+
* skipping several of them will not boot until each is dealt with. Saying
|
|
131
|
+
* so here — where the jump is actually visible — beats leaving it to be
|
|
132
|
+
* discovered as a stack trace.
|
|
133
|
+
*/
|
|
134
|
+
function warnAboutBreakingChanges(current, latest) {
|
|
135
|
+
const from = minorOf(current);
|
|
136
|
+
const to = minorOf(latest);
|
|
137
|
+
if (from === undefined || to === undefined || from >= to)
|
|
138
|
+
return;
|
|
139
|
+
console.log([
|
|
140
|
+
"",
|
|
141
|
+
`This crossed ${to - from} minor version(s), each of which may have`,
|
|
142
|
+
"changed something breaking. Before running the app:",
|
|
143
|
+
"",
|
|
144
|
+
` https://github.com/kemora13conf/bp-backend-express/blob/v${latest}/packages/core/MIGRATING.md`,
|
|
145
|
+
"",
|
|
146
|
+
"It is ordered oldest-first, because the steps build on each other.",
|
|
147
|
+
].join("\n"));
|
|
148
|
+
}
|
|
149
|
+
/** The minor of a 0.x version — 0 for anything already at 1.0 or beyond. */
|
|
150
|
+
function minorOf(version) {
|
|
151
|
+
if (!version)
|
|
152
|
+
return undefined;
|
|
153
|
+
const [major, minor] = version.split(".").map(Number);
|
|
154
|
+
return major === 0 && Number.isInteger(minor) ? minor : undefined;
|
|
155
|
+
}
|
|
156
|
+
async function fetchLatest(name) {
|
|
157
|
+
// The scoped name has to be encoded for the registry's document route.
|
|
158
|
+
const response = await fetch(`${REGISTRY}/${name.replace("/", "%2f")}/latest`);
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
throw new Error(`registry responded ${response.status}`);
|
|
161
|
+
}
|
|
162
|
+
const body = (await response.json());
|
|
163
|
+
if (typeof body.version !== "string") {
|
|
164
|
+
throw new Error("registry returned no version");
|
|
165
|
+
}
|
|
166
|
+
return body.version;
|
|
167
|
+
}
|
|
168
|
+
/** The app root plus every module — anywhere the framework is depended on. */
|
|
169
|
+
function findManifests(rootDir) {
|
|
170
|
+
const candidates = [join(rootDir, "package.json")];
|
|
171
|
+
const modulesDir = join(rootDir, "modules");
|
|
172
|
+
try {
|
|
173
|
+
for (const entry of readdirSync(modulesDir, { withFileTypes: true })) {
|
|
174
|
+
if (entry.isDirectory()) {
|
|
175
|
+
candidates.push(join(modulesDir, entry.name, "package.json"));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// No modules directory: still a valid target if the root depends on core.
|
|
181
|
+
}
|
|
182
|
+
return candidates
|
|
183
|
+
.filter((path) => existsSync(path) && dependsOnCore(path))
|
|
184
|
+
.map((path) => ({ path }));
|
|
185
|
+
}
|
|
186
|
+
function dependsOnCore(path) {
|
|
187
|
+
try {
|
|
188
|
+
const manifest = JSON.parse(readFileSync(path, "utf8"));
|
|
189
|
+
return Boolean(manifest.dependencies?.[PACKAGE] ?? manifest.devDependencies?.[PACKAGE]);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/** Returns true when the file actually changed. */
|
|
196
|
+
function rewrite(path, range, name = PACKAGE) {
|
|
197
|
+
const manifest = JSON.parse(readFileSync(path, "utf8"));
|
|
198
|
+
let touched = false;
|
|
199
|
+
for (const field of ["dependencies", "devDependencies"]) {
|
|
200
|
+
const deps = manifest[field];
|
|
201
|
+
if (deps?.[name] !== undefined && deps[name] !== range) {
|
|
202
|
+
deps[name] = range;
|
|
203
|
+
touched = true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (!touched)
|
|
207
|
+
return false;
|
|
208
|
+
writeFileSync(path, JSON.stringify(manifest, null, 2) + "\n");
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
/** Resolves to the exit code, or -1 when the command could not be spawned. */
|
|
212
|
+
async function run(command, args, cwd) {
|
|
213
|
+
return new Promise((resolve_) => {
|
|
214
|
+
const child = spawn(command, args, { cwd, stdio: "inherit" });
|
|
215
|
+
child.on("error", () => resolve_(-1));
|
|
216
|
+
child.on("exit", (status) => resolve_(status ?? 1));
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function detectManager(rootDir) {
|
|
220
|
+
if (existsSync(join(rootDir, "yarn.lock")))
|
|
221
|
+
return "yarn";
|
|
222
|
+
if (existsSync(join(rootDir, "pnpm-lock.yaml")))
|
|
223
|
+
return "pnpm";
|
|
224
|
+
if (existsSync(join(rootDir, "package-lock.json")))
|
|
225
|
+
return "npm";
|
|
226
|
+
// No lockfile yet (a fresh scaffold): fall back to the pinned manager.
|
|
227
|
+
try {
|
|
228
|
+
const manifest = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"));
|
|
229
|
+
const pinned = manifest.packageManager ?? "";
|
|
230
|
+
if (pinned.startsWith("pnpm"))
|
|
231
|
+
return "pnpm";
|
|
232
|
+
if (pinned.startsWith("npm"))
|
|
233
|
+
return "npm";
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
// fall through
|
|
237
|
+
}
|
|
238
|
+
return "yarn";
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tulipes/cli",
|
|
3
|
+
"version": "0.1.0-rc.1",
|
|
4
|
+
"description": "The tulipes command line: scaffold, sync, inspect, describe and run Tulipes apps",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"tulipes": "./dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/main.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"templates",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"build": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
|
|
21
|
+
"prepack": "yarn build"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"bin": {
|
|
26
|
+
"tulipes": "./dist/bin.js"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
".": "./dist/main.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@tulipes/core": "^0.10.0-rc.3",
|
|
34
|
+
"tsx": "^4"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^24.2.0",
|
|
38
|
+
"typescript": "^7.0.2"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/kemora13conf/bp-backend-express.git",
|
|
43
|
+
"directory": "packages/cli"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"tulipes",
|
|
47
|
+
"cli",
|
|
48
|
+
"scaffold",
|
|
49
|
+
"express"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=24.0.0 <25"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/kemora13conf/bp-backend-express/tree/master/packages/cli#readme",
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/kemora13conf/bp-backend-express/issues"
|
|
58
|
+
}
|
|
59
|
+
}
|