@kyuujs/cli 0.1.0-alpha.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/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +13 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/build.d.ts +16 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +40 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/dev.d.ts +15 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +53 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/new.d.ts +12 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +83 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/start.d.ts +22 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +64 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/dispatcher.d.ts +20 -0
- package/dist/dispatcher.d.ts.map +1 -0
- package/dist/dispatcher.js +51 -0
- package/dist/dispatcher.js.map +1 -0
- package/dist/help.d.ts +5 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +24 -0
- package/dist/help.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/project/git.d.ts +12 -0
- package/dist/project/git.d.ts.map +1 -0
- package/dist/project/git.js +23 -0
- package/dist/project/git.js.map +1 -0
- package/dist/project/options.d.ts +11 -0
- package/dist/project/options.d.ts.map +1 -0
- package/dist/project/options.js +2 -0
- package/dist/project/options.js.map +1 -0
- package/dist/project/package-manager.d.ts +13 -0
- package/dist/project/package-manager.d.ts.map +1 -0
- package/dist/project/package-manager.js +25 -0
- package/dist/project/package-manager.js.map +1 -0
- package/dist/project/scaffolder.d.ts +6 -0
- package/dist/project/scaffolder.d.ts.map +1 -0
- package/dist/project/scaffolder.js +113 -0
- package/dist/project/scaffolder.js.map +1 -0
- package/dist/project/validation.d.ts +10 -0
- package/dist/project/validation.d.ts.map +1 -0
- package/dist/project/validation.js +54 -0
- package/dist/project/validation.js.map +1 -0
- package/dist/project/wizard.d.ts +17 -0
- package/dist/project/wizard.d.ts.map +1 -0
- package/dist/project/wizard.js +72 -0
- package/dist/project/wizard.js.map +1 -0
- package/dist/runner/app-runner.d.ts +2 -0
- package/dist/runner/app-runner.d.ts.map +1 -0
- package/dist/runner/app-runner.js +54 -0
- package/dist/runner/app-runner.js.map +1 -0
- package/dist/runner/dev-runner.d.ts +15 -0
- package/dist/runner/dev-runner.d.ts.map +1 -0
- package/dist/runner/dev-runner.js +209 -0
- package/dist/runner/dev-runner.js.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +16 -0
- package/dist/version.js.map +1 -0
- package/package.json +21 -0
- package/src/bin.ts +13 -0
- package/src/commands/build.ts +59 -0
- package/src/commands/dev.ts +73 -0
- package/src/commands/new.ts +107 -0
- package/src/commands/start.ts +91 -0
- package/src/dispatcher.ts +79 -0
- package/src/help.ts +23 -0
- package/src/index.ts +90 -0
- package/src/project/git.ts +31 -0
- package/src/project/options.ts +11 -0
- package/src/project/package-manager.ts +37 -0
- package/src/project/scaffolder.ts +140 -0
- package/src/project/validation.ts +67 -0
- package/src/project/wizard.ts +89 -0
- package/src/runner/app-runner.ts +61 -0
- package/src/runner/dev-runner.ts +256 -0
- package/src/version.ts +15 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { fork } from "node:child_process";
|
|
2
|
+
import { existsSync, watch as fsWatch } from "node:fs";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
function getRunnerPathAndArgs() {
|
|
6
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
7
|
+
const currentDir = dirname(currentFile);
|
|
8
|
+
const jsInSameDir = resolve(currentDir, "app-runner.js");
|
|
9
|
+
if (existsSync(jsInSameDir)) {
|
|
10
|
+
return { execPath: jsInSameDir, execArgs: ["--experimental-strip-types"] };
|
|
11
|
+
}
|
|
12
|
+
const jsInDist = resolve(currentDir, "..", "..", "dist", "runner", "app-runner.js");
|
|
13
|
+
if (existsSync(jsInDist)) {
|
|
14
|
+
return { execPath: jsInDist, execArgs: ["--experimental-strip-types"] };
|
|
15
|
+
}
|
|
16
|
+
const tsInSameDir = resolve(currentDir, "app-runner.ts");
|
|
17
|
+
if (existsSync(tsInSameDir)) {
|
|
18
|
+
return { execPath: tsInSameDir, execArgs: ["--experimental-strip-types"] };
|
|
19
|
+
}
|
|
20
|
+
return { execPath: jsInSameDir, execArgs: ["--experimental-strip-types"] };
|
|
21
|
+
}
|
|
22
|
+
export async function startDevServer(options) {
|
|
23
|
+
const writeOut = options.stdout ?? ((msg) => process.stdout.write(msg + "\n"));
|
|
24
|
+
const writeErr = options.stderr ?? ((msg) => process.stderr.write(msg + "\n"));
|
|
25
|
+
const shouldWatch = options.watch ?? true;
|
|
26
|
+
const projectRoot = resolve(options.projectRoot);
|
|
27
|
+
let currentChild = null;
|
|
28
|
+
let watchers = [];
|
|
29
|
+
let debounceTimer = null;
|
|
30
|
+
let currentUrl;
|
|
31
|
+
let currentPort;
|
|
32
|
+
let currentHost;
|
|
33
|
+
const { execPath, execArgs } = getRunnerPathAndArgs();
|
|
34
|
+
const stopChild = async () => {
|
|
35
|
+
if (!currentChild)
|
|
36
|
+
return;
|
|
37
|
+
const child = currentChild;
|
|
38
|
+
currentChild = null;
|
|
39
|
+
if (child.exitCode !== null || child.killed) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
await new Promise((res) => {
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
try {
|
|
45
|
+
child.kill("SIGKILL");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Ignore kill error
|
|
49
|
+
}
|
|
50
|
+
res();
|
|
51
|
+
}, 2000);
|
|
52
|
+
child.once("exit", () => {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
res();
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
if (child.connected) {
|
|
58
|
+
child.send("shutdown");
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
child.kill("SIGINT");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
child.kill("SIGINT");
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const spawnChild = async () => {
|
|
70
|
+
await stopChild();
|
|
71
|
+
return new Promise((res) => {
|
|
72
|
+
const child = fork(execPath, [], {
|
|
73
|
+
execArgv: execArgs,
|
|
74
|
+
env: {
|
|
75
|
+
...process.env,
|
|
76
|
+
KYUU_PROJECT_ROOT: projectRoot,
|
|
77
|
+
NODE_ENV: "development",
|
|
78
|
+
},
|
|
79
|
+
stdio: ["inherit", "pipe", "pipe", "ipc"],
|
|
80
|
+
});
|
|
81
|
+
currentChild = child;
|
|
82
|
+
let handled = false;
|
|
83
|
+
child.stdout?.on("data", (chunk) => {
|
|
84
|
+
writeOut(chunk.toString("utf8").trimEnd());
|
|
85
|
+
});
|
|
86
|
+
child.stderr?.on("data", (chunk) => {
|
|
87
|
+
writeErr(chunk.toString("utf8").trimEnd());
|
|
88
|
+
});
|
|
89
|
+
child.on("message", (msg) => {
|
|
90
|
+
if (typeof msg === "object" && msg !== null && "type" in msg) {
|
|
91
|
+
const payload = msg;
|
|
92
|
+
if (payload.type === "started") {
|
|
93
|
+
handled = true;
|
|
94
|
+
currentPort = payload.port;
|
|
95
|
+
currentHost = payload.host;
|
|
96
|
+
currentUrl = payload.url;
|
|
97
|
+
const banner = [
|
|
98
|
+
"Kyuu",
|
|
99
|
+
"",
|
|
100
|
+
"✓ Configuration loaded",
|
|
101
|
+
"✓ Routes loaded",
|
|
102
|
+
"✓ Server started",
|
|
103
|
+
"",
|
|
104
|
+
`Local: ${payload.url}`,
|
|
105
|
+
].join("\n");
|
|
106
|
+
writeOut(banner);
|
|
107
|
+
res(true);
|
|
108
|
+
}
|
|
109
|
+
else if (payload.type === "error") {
|
|
110
|
+
handled = true;
|
|
111
|
+
writeErr(`Unable to start Kyuu server.\n\n${payload.error}`);
|
|
112
|
+
res(false);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
child.on("exit", (code) => {
|
|
117
|
+
if (!handled) {
|
|
118
|
+
handled = true;
|
|
119
|
+
if (code !== 0) {
|
|
120
|
+
writeErr(`Application process exited with code ${code}.`);
|
|
121
|
+
}
|
|
122
|
+
res(false);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
const restart = async () => {
|
|
128
|
+
writeOut("\nFile change detected. Restarting application...");
|
|
129
|
+
const success = await spawnChild();
|
|
130
|
+
if (!success) {
|
|
131
|
+
writeErr("\n✗ Failed to restart Kyuu application.\nWaiting for changes...");
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
// Initial spawn
|
|
135
|
+
await spawnChild();
|
|
136
|
+
// Watcher setup
|
|
137
|
+
if (shouldWatch) {
|
|
138
|
+
const handleFileChange = (_eventType, filename) => {
|
|
139
|
+
if (filename) {
|
|
140
|
+
const lower = filename.toLowerCase();
|
|
141
|
+
if (lower.includes("node_modules") ||
|
|
142
|
+
lower.includes(".git") ||
|
|
143
|
+
lower.includes("dist") ||
|
|
144
|
+
lower.includes("coverage")) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (debounceTimer) {
|
|
149
|
+
clearTimeout(debounceTimer);
|
|
150
|
+
}
|
|
151
|
+
debounceTimer = setTimeout(() => {
|
|
152
|
+
void restart();
|
|
153
|
+
}, 150);
|
|
154
|
+
};
|
|
155
|
+
try {
|
|
156
|
+
// Watch project root for kyuu.config changes
|
|
157
|
+
const rootWatcher = fsWatch(projectRoot, { recursive: false }, handleFileChange);
|
|
158
|
+
watchers.push(rootWatcher);
|
|
159
|
+
// Watch src directory for app route changes
|
|
160
|
+
const srcDir = join(projectRoot, "src");
|
|
161
|
+
if (existsSync(srcDir)) {
|
|
162
|
+
const srcWatcher = fsWatch(srcDir, { recursive: true }, handleFileChange);
|
|
163
|
+
watchers.push(srcWatcher);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Fallback if watching fails
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const cleanupAll = async () => {
|
|
171
|
+
if (debounceTimer) {
|
|
172
|
+
clearTimeout(debounceTimer);
|
|
173
|
+
}
|
|
174
|
+
for (const w of watchers) {
|
|
175
|
+
try {
|
|
176
|
+
w.close();
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Ignore close error
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
watchers = [];
|
|
183
|
+
await stopChild();
|
|
184
|
+
};
|
|
185
|
+
// Signal handlers
|
|
186
|
+
const sigintHandler = () => {
|
|
187
|
+
void cleanupAll().then(() => process.exit(0));
|
|
188
|
+
};
|
|
189
|
+
process.once("SIGINT", sigintHandler);
|
|
190
|
+
process.once("SIGTERM", sigintHandler);
|
|
191
|
+
return {
|
|
192
|
+
get url() {
|
|
193
|
+
return currentUrl;
|
|
194
|
+
},
|
|
195
|
+
get port() {
|
|
196
|
+
return currentPort;
|
|
197
|
+
},
|
|
198
|
+
get host() {
|
|
199
|
+
return currentHost;
|
|
200
|
+
},
|
|
201
|
+
stop: async () => {
|
|
202
|
+
process.removeListener("SIGINT", sigintHandler);
|
|
203
|
+
process.removeListener("SIGTERM", sigintHandler);
|
|
204
|
+
await cleanupAll();
|
|
205
|
+
},
|
|
206
|
+
restart,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=dev-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-runner.js","sourceRoot":"","sources":["../../src/runner/dev-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CASnC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the authoritative version string from package.json.
|
|
4
|
+
*/
|
|
5
|
+
export function getVersion() {
|
|
6
|
+
try {
|
|
7
|
+
const pkgUrl = new URL("../package.json", import.meta.url);
|
|
8
|
+
const pkgContent = readFileSync(pkgUrl, "utf8");
|
|
9
|
+
const pkg = JSON.parse(pkgContent);
|
|
10
|
+
return pkg.version ?? "0.0.0";
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return "0.0.0";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3D,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAyB,CAAC;QAC3D,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kyuujs/cli",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "CLI tooling for Kyuu applications",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"kyuu": "./dist/bin.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@kyuujs/core": "0.1.0-alpha.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/bin.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runCli } from "./dispatcher.js";
|
|
3
|
+
|
|
4
|
+
runCli(process.argv.slice(2))
|
|
5
|
+
.then(({ exitCode }) => {
|
|
6
|
+
if (exitCode !== 0) {
|
|
7
|
+
process.exit(exitCode);
|
|
8
|
+
}
|
|
9
|
+
})
|
|
10
|
+
.catch((err: unknown) => {
|
|
11
|
+
console.error(err);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { BUILD_OUTPUT_DIR, BuildOrchestrator, type BuildResult } from "@kyuujs/core";
|
|
3
|
+
import type { BaseCliOptions, CliResult } from "../dispatcher.js";
|
|
4
|
+
|
|
5
|
+
export interface BuildCommandOptions extends BaseCliOptions {
|
|
6
|
+
/** Target project root directory */
|
|
7
|
+
projectRoot?: string;
|
|
8
|
+
/** Working directory override */
|
|
9
|
+
cwd?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface BuildCommandResult extends CliResult {
|
|
13
|
+
buildResult?: BuildResult;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Handles the "kyuu build" command execution pipeline.
|
|
18
|
+
*/
|
|
19
|
+
export async function handleBuildCommand(
|
|
20
|
+
args: string[] = [],
|
|
21
|
+
options: BuildCommandOptions = {},
|
|
22
|
+
): Promise<BuildCommandResult> {
|
|
23
|
+
void args;
|
|
24
|
+
const writeOut = options.stdout ?? ((msg: string) => process.stdout.write(msg + "\n"));
|
|
25
|
+
const writeErr = options.stderr ?? ((msg: string) => process.stderr.write(msg + "\n"));
|
|
26
|
+
|
|
27
|
+
const rawRoot = options.projectRoot ?? options.cwd ?? process.cwd();
|
|
28
|
+
const projectRoot = resolve(rawRoot);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const orchestrator = new BuildOrchestrator({ projectRoot });
|
|
32
|
+
const buildResult = await orchestrator.build();
|
|
33
|
+
|
|
34
|
+
const outputLines = [
|
|
35
|
+
"Kyuu build complete.",
|
|
36
|
+
"",
|
|
37
|
+
` Build output: ${BUILD_OUTPUT_DIR}`,
|
|
38
|
+
` Language: ${buildResult.language}`,
|
|
39
|
+
` Routes: ${buildResult.manifest.routes.length}`,
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const message = outputLines.join("\n");
|
|
43
|
+
writeOut(message);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
exitCode: 0,
|
|
47
|
+
output: message,
|
|
48
|
+
buildResult,
|
|
49
|
+
};
|
|
50
|
+
} catch (err: unknown) {
|
|
51
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
52
|
+
const errText = `Kyuu build failed.\n\n${errMessage}`;
|
|
53
|
+
writeErr(errText);
|
|
54
|
+
return {
|
|
55
|
+
exitCode: 1,
|
|
56
|
+
output: errText,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { findConfigFile } from "@kyuujs/core";
|
|
4
|
+
import type { BaseCliOptions, CliResult } from "../dispatcher.js";
|
|
5
|
+
import { startDevServer, type DevServerController } from "../runner/dev-runner.js";
|
|
6
|
+
|
|
7
|
+
export interface DevCommandOptions extends BaseCliOptions {
|
|
8
|
+
projectRoot?: string;
|
|
9
|
+
cwd?: string;
|
|
10
|
+
watch?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface DevCommandResult extends CliResult {
|
|
14
|
+
controller?: DevServerController;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Handles the "kyuu dev" command execution pipeline.
|
|
19
|
+
*/
|
|
20
|
+
export async function handleDevCommand(
|
|
21
|
+
args: string[] = [],
|
|
22
|
+
options: DevCommandOptions = {},
|
|
23
|
+
): Promise<DevCommandResult> {
|
|
24
|
+
void args;
|
|
25
|
+
const writeOut = options.stdout ?? ((msg: string) => process.stdout.write(msg + "\n"));
|
|
26
|
+
const writeErr = options.stderr ?? ((msg: string) => process.stderr.write(msg + "\n"));
|
|
27
|
+
|
|
28
|
+
const rawRoot = options.projectRoot ?? options.cwd ?? process.cwd();
|
|
29
|
+
const projectRoot = resolve(rawRoot);
|
|
30
|
+
|
|
31
|
+
const configFile = findConfigFile(projectRoot);
|
|
32
|
+
const hasPkgJson = existsSync(join(projectRoot, "package.json"));
|
|
33
|
+
|
|
34
|
+
if (!configFile && !hasPkgJson) {
|
|
35
|
+
const errText = [
|
|
36
|
+
"Kyuu project not found.",
|
|
37
|
+
"",
|
|
38
|
+
"Could not locate kyuu.config.ts from:",
|
|
39
|
+
` ${projectRoot}`,
|
|
40
|
+
"",
|
|
41
|
+
'Run "kyuu new <name>" to create a new project.',
|
|
42
|
+
].join("\n");
|
|
43
|
+
writeErr(errText);
|
|
44
|
+
return { exitCode: 3, output: errText };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let controller: DevServerController;
|
|
48
|
+
try {
|
|
49
|
+
controller = await startDevServer({
|
|
50
|
+
projectRoot,
|
|
51
|
+
watch: options.watch ?? true,
|
|
52
|
+
stdout: writeOut,
|
|
53
|
+
stderr: writeErr,
|
|
54
|
+
});
|
|
55
|
+
} catch (err: unknown) {
|
|
56
|
+
const errText = `Failed to start development server: ${err instanceof Error ? err.message : String(err)}`;
|
|
57
|
+
writeErr(errText);
|
|
58
|
+
return { exitCode: 4, output: errText };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!controller.url) {
|
|
62
|
+
await controller.stop();
|
|
63
|
+
const errText = "Failed to start development server.";
|
|
64
|
+
return { exitCode: 4, output: errText };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (options.watch === false) {
|
|
68
|
+
await controller.stop();
|
|
69
|
+
return { exitCode: 0, output: "Development server started and stopped cleanly.", controller };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return { exitCode: 0, output: `Development server running at ${controller.url}`, controller };
|
|
73
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { BaseCliOptions, CliResult } from "../dispatcher.js";
|
|
2
|
+
import { initializeGitRepo } from "../project/git.js";
|
|
3
|
+
import { installDependencies } from "../project/package-manager.js";
|
|
4
|
+
import { scaffoldProject } from "../project/scaffolder.js";
|
|
5
|
+
import { validateProjectName } from "../project/validation.js";
|
|
6
|
+
import { CancelledError, runWizard } from "../project/wizard.js";
|
|
7
|
+
import type { ProjectCreationOptions } from "../project/options.js";
|
|
8
|
+
|
|
9
|
+
export interface NewCommandOptions extends BaseCliOptions {
|
|
10
|
+
cwd?: string;
|
|
11
|
+
defaults?: Partial<ProjectCreationOptions>;
|
|
12
|
+
interactive?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Handles the "kyuu new <name>" command execution pipeline.
|
|
17
|
+
*/
|
|
18
|
+
export async function handleNewCommand(
|
|
19
|
+
args: string[] = [],
|
|
20
|
+
options: NewCommandOptions = {},
|
|
21
|
+
): Promise<CliResult> {
|
|
22
|
+
const writeOut = options.stdout ?? ((msg: string) => process.stdout.write(msg + "\n"));
|
|
23
|
+
const writeErr = options.stderr ?? ((msg: string) => process.stderr.write(msg + "\n"));
|
|
24
|
+
|
|
25
|
+
const rawName = args[0];
|
|
26
|
+
|
|
27
|
+
if (!rawName || rawName.trim().length === 0) {
|
|
28
|
+
const errText = "Error: Missing project name.\nUsage: kyuu new <name>";
|
|
29
|
+
writeErr(errText);
|
|
30
|
+
return { exitCode: 1, output: errText };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const validation = validateProjectName(rawName, options.cwd);
|
|
34
|
+
if (!validation.valid || !validation.targetDirectory) {
|
|
35
|
+
const errText = `Error: ${validation.error}`;
|
|
36
|
+
writeErr(errText);
|
|
37
|
+
return { exitCode: 3, output: errText };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let creationOptions: ProjectCreationOptions;
|
|
41
|
+
try {
|
|
42
|
+
creationOptions = await runWizard({
|
|
43
|
+
name: rawName.trim(),
|
|
44
|
+
directory: validation.targetDirectory,
|
|
45
|
+
defaults: options.defaults,
|
|
46
|
+
interactive: options.interactive,
|
|
47
|
+
});
|
|
48
|
+
} catch (err) {
|
|
49
|
+
if (err instanceof CancelledError) {
|
|
50
|
+
const cancelText = "Operation cancelled. No project was created.";
|
|
51
|
+
writeOut(cancelText);
|
|
52
|
+
return { exitCode: 0, output: cancelText };
|
|
53
|
+
}
|
|
54
|
+
const errText = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
55
|
+
writeErr(errText);
|
|
56
|
+
return { exitCode: 1, output: errText };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 1. Scaffold files
|
|
60
|
+
try {
|
|
61
|
+
await scaffoldProject(creationOptions);
|
|
62
|
+
} catch (err: unknown) {
|
|
63
|
+
const errText = `Scaffolding failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
64
|
+
writeErr(errText);
|
|
65
|
+
return { exitCode: 1, output: errText };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let installSuccess = true;
|
|
69
|
+
// 2. Install dependencies (unless skipInstall is true)
|
|
70
|
+
if (!creationOptions.skipInstall) {
|
|
71
|
+
const installResult = await installDependencies(
|
|
72
|
+
creationOptions.directory,
|
|
73
|
+
creationOptions.packageManager,
|
|
74
|
+
);
|
|
75
|
+
if (!installResult.success) {
|
|
76
|
+
installSuccess = false;
|
|
77
|
+
writeErr(`Warning: Dependency installation failed.\n${installResult.error}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 3. Initialize Git if requested
|
|
82
|
+
if (creationOptions.initializeGit) {
|
|
83
|
+
const gitResult = await initializeGitRepo(creationOptions.directory);
|
|
84
|
+
if (!gitResult.success) {
|
|
85
|
+
writeErr("Warning: Git initialization failed. You can initialize Git manually.");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 4. Report final success and next steps
|
|
90
|
+
const successLines = [
|
|
91
|
+
`✔ Kyuu project "${creationOptions.name}" created successfully.`,
|
|
92
|
+
"",
|
|
93
|
+
"Next steps:",
|
|
94
|
+
` cd ${creationOptions.name}`,
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
if (creationOptions.skipInstall || !installSuccess) {
|
|
98
|
+
successLines.push(` ${creationOptions.packageManager} install`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
successLines.push(` ${creationOptions.packageManager} run dev`);
|
|
102
|
+
|
|
103
|
+
const successText = successLines.join("\n");
|
|
104
|
+
writeOut(successText);
|
|
105
|
+
|
|
106
|
+
return { exitCode: 0, output: successText };
|
|
107
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { BUILD_OUTPUT_DIR, startProductionServer, type ProductionRunnerResult } from "@kyuujs/core";
|
|
3
|
+
import type { BaseCliOptions, CliResult } from "../dispatcher.js";
|
|
4
|
+
|
|
5
|
+
export interface StartCommandOptions extends BaseCliOptions {
|
|
6
|
+
/** Target project root directory */
|
|
7
|
+
projectRoot?: string;
|
|
8
|
+
/** Working directory override */
|
|
9
|
+
cwd?: string;
|
|
10
|
+
/** Port override for production HTTP server */
|
|
11
|
+
port?: number;
|
|
12
|
+
/** Host override for production HTTP server */
|
|
13
|
+
host?: string;
|
|
14
|
+
/** If true, attaches SIGINT/SIGTERM process signal handlers for graceful shutdown */
|
|
15
|
+
attachSignalHandlers?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface StartCommandResult extends CliResult {
|
|
19
|
+
runnerResult?: ProductionRunnerResult;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Handles the "kyuu start" command execution pipeline.
|
|
24
|
+
*/
|
|
25
|
+
export async function handleStartCommand(
|
|
26
|
+
args: string[] = [],
|
|
27
|
+
options: StartCommandOptions = {},
|
|
28
|
+
): Promise<StartCommandResult> {
|
|
29
|
+
void args;
|
|
30
|
+
const writeOut = options.stdout ?? ((msg: string) => process.stdout.write(msg + "\n"));
|
|
31
|
+
const writeErr = options.stderr ?? ((msg: string) => process.stderr.write(msg + "\n"));
|
|
32
|
+
|
|
33
|
+
const rawRoot = options.projectRoot ?? options.cwd ?? process.cwd();
|
|
34
|
+
const projectRoot = resolve(rawRoot);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const runnerResult = await startProductionServer({
|
|
38
|
+
projectRoot,
|
|
39
|
+
port: options.port,
|
|
40
|
+
host: options.host,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const host = runnerResult.config.server.host;
|
|
44
|
+
const port = runnerResult.config.server.port;
|
|
45
|
+
const displayHost = host === "0.0.0.0" ? "localhost" : host;
|
|
46
|
+
const serverUrl = `http://${displayHost}:${port}`;
|
|
47
|
+
|
|
48
|
+
const outputLines = [
|
|
49
|
+
`Kyuu production server running at ${serverUrl}`,
|
|
50
|
+
"",
|
|
51
|
+
` Build output: ${BUILD_OUTPUT_DIR}`,
|
|
52
|
+
` Language: ${runnerResult.manifest.metadata.language}`,
|
|
53
|
+
` Routes: ${runnerResult.manifest.routes.length}`,
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const message = outputLines.join("\n");
|
|
57
|
+
writeOut(message);
|
|
58
|
+
|
|
59
|
+
if (options.attachSignalHandlers !== false) {
|
|
60
|
+
const shutdown = async () => {
|
|
61
|
+
try {
|
|
62
|
+
await runnerResult.app.close();
|
|
63
|
+
writeOut("Kyuu server shut down gracefully.");
|
|
64
|
+
} catch {
|
|
65
|
+
// ignore shutdown errors on exit
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
process.once("SIGINT", () => {
|
|
70
|
+
void shutdown();
|
|
71
|
+
});
|
|
72
|
+
process.once("SIGTERM", () => {
|
|
73
|
+
void shutdown();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
exitCode: 0,
|
|
79
|
+
output: message,
|
|
80
|
+
runnerResult,
|
|
81
|
+
};
|
|
82
|
+
} catch (err: unknown) {
|
|
83
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
84
|
+
const errText = `Kyuu production server failed to start.\n\n${errMessage}`;
|
|
85
|
+
writeErr(errText);
|
|
86
|
+
return {
|
|
87
|
+
exitCode: 1,
|
|
88
|
+
output: errText,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|