@tyndall/cli 0.0.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/README.md +30 -0
- package/bin/cloud-front.js +7 -0
- package/dist/adapter-registry.d.ts +9 -0
- package/dist/adapter-registry.d.ts.map +1 -0
- package/dist/adapter-registry.js +61 -0
- package/dist/args.d.ts +3 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +85 -0
- package/dist/commands/build.d.ts +24 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +59 -0
- package/dist/commands/dev.d.ts +25 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +85 -0
- package/dist/commands/format.d.ts +15 -0
- package/dist/commands/format.d.ts.map +1 -0
- package/dist/commands/format.js +26 -0
- package/dist/commands/lint.d.ts +15 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +26 -0
- package/dist/commands/preview.d.ts +14 -0
- package/dist/commands/preview.d.ts.map +1 -0
- package/dist/commands/preview.js +35 -0
- package/dist/commands/registry.d.ts +5 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +55 -0
- package/dist/commands/start.d.ts +33 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +78 -0
- package/dist/dispatcher.d.ts +3 -0
- package/dist/dispatcher.d.ts.map +1 -0
- package/dist/dispatcher.js +53 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +20 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/logging.d.ts +20 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +39 -0
- package/dist/open.d.ts +8 -0
- package/dist/open.d.ts.map +1 -0
- package/dist/open.js +35 -0
- package/dist/preview-server.d.ts +13 -0
- package/dist/preview-server.d.ts.map +1 -0
- package/dist/preview-server.js +70 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/usage.d.ts +2 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +18 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @tyndall/cli
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Command-line interface package that dispatches framework commands and normalizes execution flags.
|
|
5
|
+
|
|
6
|
+
## Responsibilities
|
|
7
|
+
- Parse and dispatch CLI commands
|
|
8
|
+
- Bridge user flags into build, dev, and runtime options
|
|
9
|
+
- Standardize CLI logging and error formatting
|
|
10
|
+
- Expose the `cloud-front` executable for app/package scripts
|
|
11
|
+
- Run the published `cloud-front` executable with Bun for dev command compatibility with TS/TSX route loading
|
|
12
|
+
|
|
13
|
+
## Public API Highlights
|
|
14
|
+
- runCli
|
|
15
|
+
- parseArgs
|
|
16
|
+
- formatUsage
|
|
17
|
+
|
|
18
|
+
## Development
|
|
19
|
+
- Build: bun run --filter @tyndall/cli build
|
|
20
|
+
- Test (from workspace root): bun test
|
|
21
|
+
|
|
22
|
+
## Documentation
|
|
23
|
+
- Package specification: [spec.md](./spec.md)
|
|
24
|
+
- Package architecture: [architecture.md](./architecture.md)
|
|
25
|
+
- Package changes: [CHANGELOG.md](./CHANGELOG.md)
|
|
26
|
+
|
|
27
|
+
## Maintenance Rules
|
|
28
|
+
- Keep this document aligned with implemented package behavior.
|
|
29
|
+
- Update spec.md and architecture.md whenever package contracts or design boundaries change.
|
|
30
|
+
- Record user-visible package changes in CHANGELOG.md.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { UIAdapterRegistry } from "@tyndall/core";
|
|
2
|
+
export interface ResolveAdapterRegistryOptions {
|
|
3
|
+
explicitRegistry?: UIAdapterRegistry;
|
|
4
|
+
reactRegistryLoader?: () => Promise<UIAdapterRegistry | undefined>;
|
|
5
|
+
webComponentsRegistryLoader?: () => Promise<UIAdapterRegistry | undefined>;
|
|
6
|
+
wasmRegistryLoader?: () => Promise<UIAdapterRegistry | undefined>;
|
|
7
|
+
}
|
|
8
|
+
export declare const resolveAdapterRegistry: (options?: ResolveAdapterRegistryOptions) => Promise<UIAdapterRegistry | undefined>;
|
|
9
|
+
//# sourceMappingURL=adapter-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-registry.d.ts","sourceRoot":"","sources":["../src/adapter-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAcvD,MAAM,WAAW,6BAA6B;IAC5C,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC;IACnE,2BAA2B,CAAC,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC;IAC3E,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC;CACnE;AA6CD,eAAO,MAAM,sBAAsB,GACjC,UAAS,6BAAkC,KAC1C,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAmBvC,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const loadReactAdapterRegistry = async () => {
|
|
2
|
+
try {
|
|
3
|
+
const module = (await import("@tyndall/react"));
|
|
4
|
+
const createRegistry = module.createReactAdapterRegistry;
|
|
5
|
+
return typeof createRegistry === "function" ? createRegistry() : undefined;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const loadWebComponentsAdapterRegistry = async () => {
|
|
12
|
+
try {
|
|
13
|
+
const module = (await import("@tyndall/webcomponents"));
|
|
14
|
+
const createRegistry = module.createWebComponentsAdapterRegistry;
|
|
15
|
+
return typeof createRegistry === "function" ? createRegistry() : undefined;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const loadWasmAdapterRegistry = async () => {
|
|
22
|
+
try {
|
|
23
|
+
const module = (await import("@tyndall/wasm"));
|
|
24
|
+
const createRegistry = module.createWasmAdapterRegistry;
|
|
25
|
+
return typeof createRegistry === "function" ? createRegistry() : undefined;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const mergeRegistries = (registries) => {
|
|
32
|
+
const merged = {};
|
|
33
|
+
for (const registry of registries) {
|
|
34
|
+
if (!registry) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
Object.assign(merged, registry);
|
|
38
|
+
}
|
|
39
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
40
|
+
};
|
|
41
|
+
export const resolveAdapterRegistry = async (options = {}) => {
|
|
42
|
+
if (options.explicitRegistry) {
|
|
43
|
+
return options.explicitRegistry;
|
|
44
|
+
}
|
|
45
|
+
const loaders = [
|
|
46
|
+
options.reactRegistryLoader ?? loadReactAdapterRegistry,
|
|
47
|
+
options.webComponentsRegistryLoader ?? loadWebComponentsAdapterRegistry,
|
|
48
|
+
options.wasmRegistryLoader ?? loadWasmAdapterRegistry,
|
|
49
|
+
];
|
|
50
|
+
const registries = [];
|
|
51
|
+
for (const load of loaders) {
|
|
52
|
+
// Keep optional UI runtime loading non-fatal so factory adapters still work.
|
|
53
|
+
try {
|
|
54
|
+
registries.push(await load());
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
registries.push(undefined);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return mergeRegistries(registries);
|
|
61
|
+
};
|
package/dist/args.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,UAAU,EAAE,MAAM,YAAY,CAAC;AA4BjE,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,KAAG,UA4D1C,CAAC"}
|
package/dist/args.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const NUMBER_PATTERN = /^-?\d+(?:\.\d+)?$/;
|
|
2
|
+
const coerceValue = (raw) => {
|
|
3
|
+
if (raw === "true") {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
if (raw === "false") {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (NUMBER_PATTERN.test(raw)) {
|
|
10
|
+
return Number(raw);
|
|
11
|
+
}
|
|
12
|
+
return raw;
|
|
13
|
+
};
|
|
14
|
+
const applyFlag = (flags, name, value) => {
|
|
15
|
+
flags[name] = value;
|
|
16
|
+
if (name.startsWith("no-") && value === true) {
|
|
17
|
+
// Keep --no-<flag> normalized to a single false entry for downstream handlers.
|
|
18
|
+
const positive = name.slice(3);
|
|
19
|
+
if (positive.length > 0) {
|
|
20
|
+
flags[positive] = false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export const parseArgs = (argv) => {
|
|
25
|
+
const flags = {};
|
|
26
|
+
const positionals = [];
|
|
27
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
28
|
+
const token = argv[index];
|
|
29
|
+
if (token === "--") {
|
|
30
|
+
positionals.push(...argv.slice(index + 1));
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
if (token.startsWith("--") && token.length > 2) {
|
|
34
|
+
const raw = token.slice(2);
|
|
35
|
+
const equalsIndex = raw.indexOf("=");
|
|
36
|
+
if (equalsIndex >= 0) {
|
|
37
|
+
const name = raw.slice(0, equalsIndex);
|
|
38
|
+
const rawValue = raw.slice(equalsIndex + 1);
|
|
39
|
+
applyFlag(flags, name, coerceValue(rawValue));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const next = argv[index + 1];
|
|
43
|
+
if (next && !next.startsWith("-")) {
|
|
44
|
+
applyFlag(flags, raw, coerceValue(next));
|
|
45
|
+
index += 1;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
applyFlag(flags, raw, true);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (token.startsWith("-") && token.length > 1) {
|
|
54
|
+
if (token === "-h") {
|
|
55
|
+
applyFlag(flags, "help", true);
|
|
56
|
+
}
|
|
57
|
+
else if (token === "-v") {
|
|
58
|
+
applyFlag(flags, "version", true);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
for (const char of token.slice(1)) {
|
|
62
|
+
if (char === "h") {
|
|
63
|
+
applyFlag(flags, "help", true);
|
|
64
|
+
}
|
|
65
|
+
else if (char === "v") {
|
|
66
|
+
applyFlag(flags, "version", true);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
applyFlag(flags, char, true);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
positionals.push(token);
|
|
76
|
+
}
|
|
77
|
+
const command = positionals.shift() ?? null;
|
|
78
|
+
return {
|
|
79
|
+
command,
|
|
80
|
+
args: positionals,
|
|
81
|
+
flags,
|
|
82
|
+
help: Boolean(flags.help),
|
|
83
|
+
version: Boolean(flags.version),
|
|
84
|
+
};
|
|
85
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CommandHandler } from "../types.js";
|
|
2
|
+
export interface BuildCommandOptions {
|
|
3
|
+
rootDir: string;
|
|
4
|
+
mode: "ssg" | "ssr";
|
|
5
|
+
outDir?: string;
|
|
6
|
+
cache: {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
dir?: string;
|
|
9
|
+
maxSizeMB?: number;
|
|
10
|
+
maxAgeDays?: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface BuildCommandDeps {
|
|
14
|
+
build: (options: BuildCommandOptions & {
|
|
15
|
+
adapterRegistry?: unknown;
|
|
16
|
+
}) => Promise<{
|
|
17
|
+
outDir: string;
|
|
18
|
+
}>;
|
|
19
|
+
cwd?: () => string;
|
|
20
|
+
resolveAdapterRegistry?: () => Promise<unknown>;
|
|
21
|
+
}
|
|
22
|
+
export declare const createBuildCommand: (deps: BuildCommandDeps) => CommandHandler;
|
|
23
|
+
export declare const runBuildCommand: CommandHandler;
|
|
24
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,aAAa,CAAC;AAE3D,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QACL,OAAO,EAAE,OAAO,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,mBAAmB,GAAG;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrG,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACjD;AAsCD,eAAO,MAAM,kBAAkB,GAAI,MAAM,gBAAgB,KAAG,cAc3D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAc7B,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const readNumber = (value) => {
|
|
2
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
3
|
+
return value;
|
|
4
|
+
}
|
|
5
|
+
if (typeof value === "string") {
|
|
6
|
+
const parsed = Number(value);
|
|
7
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
8
|
+
}
|
|
9
|
+
return undefined;
|
|
10
|
+
};
|
|
11
|
+
const resolveBuildOptions = (flags, cwd) => {
|
|
12
|
+
const mode = flags.mode === "ssr" ? "ssr" : "ssg";
|
|
13
|
+
const outDir = typeof flags.outDir === "string"
|
|
14
|
+
? flags.outDir
|
|
15
|
+
: typeof flags["out-dir"] === "string"
|
|
16
|
+
? flags["out-dir"]
|
|
17
|
+
: undefined;
|
|
18
|
+
const cacheEnabled = flags.cache !== false;
|
|
19
|
+
const cacheDir = typeof flags["cache-dir"] === "string" ? flags["cache-dir"] : undefined;
|
|
20
|
+
return {
|
|
21
|
+
rootDir: cwd,
|
|
22
|
+
mode,
|
|
23
|
+
outDir,
|
|
24
|
+
cache: {
|
|
25
|
+
enabled: cacheEnabled,
|
|
26
|
+
dir: cacheDir,
|
|
27
|
+
maxSizeMB: readNumber(flags["cache-max-size-mb"]),
|
|
28
|
+
maxAgeDays: readNumber(flags["cache-max-age-days"]),
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export const createBuildCommand = (deps) => {
|
|
33
|
+
return async ({ flags, io }) => {
|
|
34
|
+
const cwd = deps.cwd ? deps.cwd() : process.cwd();
|
|
35
|
+
const options = resolveBuildOptions(flags, cwd);
|
|
36
|
+
io.stdout.write(`Build started in ${options.rootDir}\n`);
|
|
37
|
+
if (!options.cache.enabled) {
|
|
38
|
+
io.stdout.write("Build cache disabled.\n");
|
|
39
|
+
}
|
|
40
|
+
const result = await deps.build(options);
|
|
41
|
+
io.stdout.write(`Build completed: ${result.outDir}\n`);
|
|
42
|
+
return 0;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export const runBuildCommand = async (context) => {
|
|
46
|
+
const { build } = await import("@tyndall/build");
|
|
47
|
+
const { resolveAdapterRegistry } = await import("../adapter-registry.js");
|
|
48
|
+
const command = createBuildCommand({
|
|
49
|
+
resolveAdapterRegistry,
|
|
50
|
+
build: async (options) => {
|
|
51
|
+
const adapterRegistry = await resolveAdapterRegistry();
|
|
52
|
+
return build({
|
|
53
|
+
...options,
|
|
54
|
+
adapterRegistry,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
return command(context);
|
|
59
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CommandHandler } from "../types.js";
|
|
2
|
+
import type { UIAdapterRegistry } from "@tyndall/core";
|
|
3
|
+
export interface DevCommandOptions {
|
|
4
|
+
port: number;
|
|
5
|
+
host: string;
|
|
6
|
+
open: boolean;
|
|
7
|
+
ssr: boolean;
|
|
8
|
+
adapterRegistry?: UIAdapterRegistry;
|
|
9
|
+
}
|
|
10
|
+
export interface DevCommandDeps {
|
|
11
|
+
startDevServer: (options: DevCommandOptions) => Promise<{
|
|
12
|
+
url: string;
|
|
13
|
+
close: () => Promise<void> | void;
|
|
14
|
+
}>;
|
|
15
|
+
openUrl?: (url: string) => Promise<void> | void;
|
|
16
|
+
}
|
|
17
|
+
export declare const createDevCommand: (deps: DevCommandDeps) => CommandHandler;
|
|
18
|
+
export declare const isBunRuntime: (runtime?: unknown) => boolean;
|
|
19
|
+
export declare const ensureDevRuntimeSupported: (io: {
|
|
20
|
+
stderr: {
|
|
21
|
+
write: (text: string) => void;
|
|
22
|
+
};
|
|
23
|
+
}, runtime?: unknown) => boolean;
|
|
24
|
+
export declare const runDevCommand: CommandHandler;
|
|
25
|
+
//# sourceMappingURL=dev.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGvD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,eAAe,CAAC,EAAE,iBAAiB,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC;QACtD,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;KACnC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACjD;AA2CD,eAAO,MAAM,gBAAgB,GAAI,MAAM,cAAc,KAAG,cAoBvD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,UAAS,OAAiB,YACd,CAAC;AAE1C,eAAO,MAAM,yBAAyB,GACpC,IAAI;IACF,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CAC3C,EACD,UAAS,OAAiB,YAa3B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,cAgB3B,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { resolveAdapterRegistry } from "../adapter-registry.js";
|
|
2
|
+
const DEFAULT_PORT = 3000;
|
|
3
|
+
const DEFAULT_HOST = "localhost";
|
|
4
|
+
const readRuntimeBunVersion = (runtime) => {
|
|
5
|
+
if (!runtime || typeof runtime !== "object") {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
const versions = runtime.versions;
|
|
9
|
+
if (!versions || typeof versions !== "object") {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const bunVersion = versions.bun;
|
|
13
|
+
return typeof bunVersion === "string" && bunVersion.length > 0
|
|
14
|
+
? bunVersion
|
|
15
|
+
: null;
|
|
16
|
+
};
|
|
17
|
+
const normalizePort = (flags) => {
|
|
18
|
+
const raw = flags.port ?? flags.p;
|
|
19
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
20
|
+
return raw;
|
|
21
|
+
}
|
|
22
|
+
if (typeof raw === "string") {
|
|
23
|
+
const parsed = Number(raw);
|
|
24
|
+
if (Number.isFinite(parsed)) {
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return DEFAULT_PORT;
|
|
29
|
+
};
|
|
30
|
+
const resolveDevOptions = (flags) => {
|
|
31
|
+
const host = typeof flags.host === "string" ? flags.host : DEFAULT_HOST;
|
|
32
|
+
return {
|
|
33
|
+
port: normalizePort(flags),
|
|
34
|
+
host,
|
|
35
|
+
open: Boolean(flags.open),
|
|
36
|
+
ssr: Boolean(flags.ssr),
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export const createDevCommand = (deps) => {
|
|
40
|
+
return async ({ flags, io }) => {
|
|
41
|
+
const options = resolveDevOptions(flags);
|
|
42
|
+
const server = await deps.startDevServer(options);
|
|
43
|
+
io.stdout.write(`Dev server running at ${server.url}\n`);
|
|
44
|
+
if (options.ssr) {
|
|
45
|
+
io.stdout.write("SSR preview enabled.\n");
|
|
46
|
+
}
|
|
47
|
+
if (options.open) {
|
|
48
|
+
if (deps.openUrl) {
|
|
49
|
+
await deps.openUrl(server.url);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
io.stdout.write("Open flag requested; auto-open is not configured.\n");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return 0;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export const isBunRuntime = (runtime = process) => readRuntimeBunVersion(runtime) !== null;
|
|
59
|
+
export const ensureDevRuntimeSupported = (io, runtime = process) => {
|
|
60
|
+
if (isBunRuntime(runtime)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
io.stderr.write([
|
|
64
|
+
"cloud-front dev requires Bun runtime because dev route loading imports TS/TSX modules directly.",
|
|
65
|
+
"Run the command with Bun (for example: `bun run dev` or `bun run scripts/cloud-front.ts dev`).",
|
|
66
|
+
].join(" "));
|
|
67
|
+
io.stderr.write("\n");
|
|
68
|
+
return false;
|
|
69
|
+
};
|
|
70
|
+
export const runDevCommand = async (context) => {
|
|
71
|
+
if (!ensureDevRuntimeSupported(context.io)) {
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
const { startDevServer } = await import("@tyndall/dev");
|
|
75
|
+
const { openUrl } = await import("../open.js");
|
|
76
|
+
const adapterRegistry = await resolveAdapterRegistry();
|
|
77
|
+
const command = createDevCommand({
|
|
78
|
+
startDevServer: (options) => startDevServer({
|
|
79
|
+
...options,
|
|
80
|
+
adapterRegistry,
|
|
81
|
+
}),
|
|
82
|
+
openUrl,
|
|
83
|
+
});
|
|
84
|
+
return command(context);
|
|
85
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CommandHandler } from "../types.js";
|
|
2
|
+
export interface FormatCommandOptions {
|
|
3
|
+
cwd: string;
|
|
4
|
+
write: boolean;
|
|
5
|
+
files: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface FormatCommandDeps {
|
|
8
|
+
runFormat: (options: FormatCommandOptions) => Promise<{
|
|
9
|
+
code: number;
|
|
10
|
+
}>;
|
|
11
|
+
cwd?: () => string;
|
|
12
|
+
}
|
|
13
|
+
export declare const createFormatCommand: (deps: FormatCommandDeps) => CommandHandler;
|
|
14
|
+
export declare const runFormatCommand: CommandHandler;
|
|
15
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/commands/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,aAAa,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAWD,eAAO,MAAM,mBAAmB,GAAI,MAAM,iBAAiB,KAAG,cAc7D,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,cAI9B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const resolveFormatOptions = (flags, args, cwd) => {
|
|
2
|
+
const write = Boolean(flags.write);
|
|
3
|
+
return {
|
|
4
|
+
cwd,
|
|
5
|
+
write,
|
|
6
|
+
files: args,
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export const createFormatCommand = (deps) => {
|
|
10
|
+
return async ({ flags, args, io }) => {
|
|
11
|
+
const cwd = deps.cwd ? deps.cwd() : process.cwd();
|
|
12
|
+
const options = resolveFormatOptions(flags, args, cwd);
|
|
13
|
+
const result = await deps.runFormat(options);
|
|
14
|
+
if (result.code !== 0) {
|
|
15
|
+
io.stderr.write(`Format failed with code ${result.code}.\n`);
|
|
16
|
+
return result.code;
|
|
17
|
+
}
|
|
18
|
+
io.stdout.write("Format completed.\n");
|
|
19
|
+
return 0;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export const runFormatCommand = async (context) => {
|
|
23
|
+
const { runFormat } = await import("@tyndall/lint");
|
|
24
|
+
const command = createFormatCommand({ runFormat });
|
|
25
|
+
return command(context);
|
|
26
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CommandHandler } from "../types.js";
|
|
2
|
+
export interface LintCommandOptions {
|
|
3
|
+
cwd: string;
|
|
4
|
+
fix: boolean;
|
|
5
|
+
files: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface LintCommandDeps {
|
|
8
|
+
runLint: (options: LintCommandOptions) => Promise<{
|
|
9
|
+
code: number;
|
|
10
|
+
}>;
|
|
11
|
+
cwd?: () => string;
|
|
12
|
+
}
|
|
13
|
+
export declare const createLintCommand: (deps: LintCommandDeps) => CommandHandler;
|
|
14
|
+
export declare const runLintCommand: CommandHandler;
|
|
15
|
+
//# sourceMappingURL=lint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,aAAa,CAAC;AAE3D,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAWD,eAAO,MAAM,iBAAiB,GAAI,MAAM,eAAe,KAAG,cAczD,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,cAI5B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const resolveLintOptions = (flags, args, cwd) => {
|
|
2
|
+
const fix = Boolean(flags.fix);
|
|
3
|
+
return {
|
|
4
|
+
cwd,
|
|
5
|
+
fix,
|
|
6
|
+
files: args,
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export const createLintCommand = (deps) => {
|
|
10
|
+
return async ({ flags, args, io }) => {
|
|
11
|
+
const cwd = deps.cwd ? deps.cwd() : process.cwd();
|
|
12
|
+
const options = resolveLintOptions(flags, args, cwd);
|
|
13
|
+
const result = await deps.runLint(options);
|
|
14
|
+
if (result.code !== 0) {
|
|
15
|
+
io.stderr.write(`Lint failed with code ${result.code}.\n`);
|
|
16
|
+
return result.code;
|
|
17
|
+
}
|
|
18
|
+
io.stdout.write("Lint completed.\n");
|
|
19
|
+
return 0;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export const runLintCommand = async (context) => {
|
|
23
|
+
const { runLint } = await import("@tyndall/lint");
|
|
24
|
+
const command = createLintCommand({ runLint });
|
|
25
|
+
return command(context);
|
|
26
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CommandHandler } from "../types.js";
|
|
2
|
+
import { type PreviewServer } from "../preview-server.js";
|
|
3
|
+
export interface PreviewCommandOptions {
|
|
4
|
+
outDir: string;
|
|
5
|
+
port: number;
|
|
6
|
+
host: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PreviewCommandDeps {
|
|
9
|
+
startPreviewServer: (options: PreviewCommandOptions) => Promise<PreviewServer>;
|
|
10
|
+
cwd?: () => string;
|
|
11
|
+
}
|
|
12
|
+
export declare const createPreviewCommand: (deps: PreviewCommandDeps) => CommandHandler;
|
|
13
|
+
export declare const runPreviewCommand: CommandHandler;
|
|
14
|
+
//# sourceMappingURL=preview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/commands/preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE9E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AA4BD,eAAO,MAAM,oBAAoB,GAAI,MAAM,kBAAkB,KAAG,cAQ/D,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,cAG/B,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { startPreviewServer } from "../preview-server.js";
|
|
2
|
+
const DEFAULT_PORT = 4173;
|
|
3
|
+
const DEFAULT_HOST = "localhost";
|
|
4
|
+
const resolvePreviewOptions = (flags, cwd) => {
|
|
5
|
+
const portFlag = flags.port ?? flags.p;
|
|
6
|
+
const port = typeof portFlag === "number"
|
|
7
|
+
? portFlag
|
|
8
|
+
: typeof portFlag === "string"
|
|
9
|
+
? Number(portFlag)
|
|
10
|
+
: DEFAULT_PORT;
|
|
11
|
+
const host = typeof flags.host === "string" ? flags.host : DEFAULT_HOST;
|
|
12
|
+
const outDir = typeof flags.outDir === "string"
|
|
13
|
+
? flags.outDir
|
|
14
|
+
: typeof flags["out-dir"] === "string"
|
|
15
|
+
? flags["out-dir"]
|
|
16
|
+
: "dist";
|
|
17
|
+
return {
|
|
18
|
+
port: Number.isFinite(port) ? port : DEFAULT_PORT,
|
|
19
|
+
host,
|
|
20
|
+
outDir: outDir.startsWith("/") ? outDir : `${cwd}/${outDir}`,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export const createPreviewCommand = (deps) => {
|
|
24
|
+
return async ({ flags, io }) => {
|
|
25
|
+
const cwd = deps.cwd ? deps.cwd() : process.cwd();
|
|
26
|
+
const options = resolvePreviewOptions(flags, cwd);
|
|
27
|
+
const server = await deps.startPreviewServer(options);
|
|
28
|
+
io.stdout.write(`Preview server running at ${server.url}\n`);
|
|
29
|
+
return 0;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export const runPreviewCommand = async (context) => {
|
|
33
|
+
const command = createPreviewCommand({ startPreviewServer });
|
|
34
|
+
return command(context);
|
|
35
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CommandDefinition, CommandName } from "../types.js";
|
|
2
|
+
export declare const COMMANDS: CommandDefinition[];
|
|
3
|
+
export declare const COMMAND_LOOKUP: Map<CommandName, CommandDefinition>;
|
|
4
|
+
export declare const isCommandName: (value: string) => value is CommandName;
|
|
5
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/commands/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAkB,WAAW,EAAE,MAAM,aAAa,CAAC;AAgBlF,eAAO,MAAM,QAAQ,EAAE,iBAAiB,EAsCvC,CAAC;AAEF,eAAO,MAAM,cAAc,qCAE1B,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,KAAK,IAAI,WAEtD,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { runBuildCommand } from "./build.js";
|
|
2
|
+
import { runDevCommand } from "./dev.js";
|
|
3
|
+
import { runFormatCommand } from "./format.js";
|
|
4
|
+
import { runPreviewCommand } from "./preview.js";
|
|
5
|
+
import { runStartCommand } from "./start.js";
|
|
6
|
+
import { runLintCommand } from "./lint.js";
|
|
7
|
+
const notImplemented = (name) => {
|
|
8
|
+
return ({ io }) => {
|
|
9
|
+
// Explicitly fail until each command is implemented in later milestones.
|
|
10
|
+
io.stderr.write(`Command "${name}" is not implemented yet.\n`);
|
|
11
|
+
return 1;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export const COMMANDS = [
|
|
15
|
+
{
|
|
16
|
+
name: "dev",
|
|
17
|
+
summary: "Start dev server with HMR",
|
|
18
|
+
usage: "cloud-front dev [--port <number>] [--host <host>] [--open] [--ssr]",
|
|
19
|
+
run: runDevCommand,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "build",
|
|
23
|
+
summary: "Build for production (SSG + assets)",
|
|
24
|
+
usage: "cloud-front build [--mode <ssg|ssr>] [--outDir <dir>] [--no-cache] [--cache-dir <dir>]",
|
|
25
|
+
run: runBuildCommand,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "start",
|
|
29
|
+
summary: "Start production server (SSR only)",
|
|
30
|
+
usage: "cloud-front start [--port <number>] [--adapter <node|express|fastify>]",
|
|
31
|
+
run: runStartCommand,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "preview",
|
|
35
|
+
summary: "Serve built static output locally",
|
|
36
|
+
usage: "cloud-front preview [--port <number>]",
|
|
37
|
+
run: runPreviewCommand,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "lint",
|
|
41
|
+
summary: "Run lint",
|
|
42
|
+
usage: "cloud-front lint [--fix]",
|
|
43
|
+
run: runLintCommand,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "format",
|
|
47
|
+
summary: "Run formatter",
|
|
48
|
+
usage: "cloud-front format [--write]",
|
|
49
|
+
run: runFormatCommand,
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
export const COMMAND_LOOKUP = new Map(COMMANDS.map((command) => [command.name, command]));
|
|
53
|
+
export const isCommandName = (value) => {
|
|
54
|
+
return COMMAND_LOOKUP.has(value);
|
|
55
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { CommandHandler } from "../types.js";
|
|
2
|
+
import type { UIAdapterFactory, UIAdapterRegistry } from "@tyndall/core";
|
|
3
|
+
export interface StartCommandOptions {
|
|
4
|
+
port: number;
|
|
5
|
+
host: string;
|
|
6
|
+
adapter: "node" | "express" | "fastify";
|
|
7
|
+
distDir: string;
|
|
8
|
+
}
|
|
9
|
+
export interface StartCommandRuntimeConfig {
|
|
10
|
+
adapterRegistry?: UIAdapterRegistry;
|
|
11
|
+
uiAdapter?: string | UIAdapterFactory;
|
|
12
|
+
uiOptions?: Record<string, unknown>;
|
|
13
|
+
appMode?: "ssg" | "ssr";
|
|
14
|
+
}
|
|
15
|
+
export interface StartCommandDeps {
|
|
16
|
+
createServer: (options: {
|
|
17
|
+
port?: number;
|
|
18
|
+
host?: string;
|
|
19
|
+
distDir?: string;
|
|
20
|
+
adapterRegistry?: UIAdapterRegistry;
|
|
21
|
+
uiAdapter?: string | UIAdapterFactory;
|
|
22
|
+
uiOptions?: Record<string, unknown>;
|
|
23
|
+
appMode?: "ssg" | "ssr";
|
|
24
|
+
}) => Promise<{
|
|
25
|
+
url: string;
|
|
26
|
+
close: () => Promise<void> | void;
|
|
27
|
+
}>;
|
|
28
|
+
cwd?: () => string;
|
|
29
|
+
loadRuntimeConfig?: (cwd: string) => Promise<StartCommandRuntimeConfig | undefined>;
|
|
30
|
+
}
|
|
31
|
+
export declare const createStartCommand: (deps: StartCommandDeps) => CommandHandler;
|
|
32
|
+
export declare const runStartCommand: CommandHandler;
|
|
33
|
+
//# sourceMappingURL=start.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGzE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,CAAC,OAAO,EAAE;QACtB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,eAAe,CAAC,EAAE,iBAAiB,CAAC;QACpC,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;QACtC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,OAAO,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;KACzB,KAAK,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAClE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC,CAAC;CACrF;AA+BD,eAAO,MAAM,kBAAkB,GAAI,MAAM,gBAAgB,KAAG,cA0B3D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cA4B7B,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { resolveAdapterRegistry } from "../adapter-registry.js";
|
|
2
|
+
const DEFAULT_PORT = 3000;
|
|
3
|
+
const DEFAULT_HOST = "localhost";
|
|
4
|
+
const resolveStartOptions = (flags, cwd) => {
|
|
5
|
+
const portFlag = flags.port ?? flags.p;
|
|
6
|
+
const port = typeof portFlag === "number"
|
|
7
|
+
? portFlag
|
|
8
|
+
: typeof portFlag === "string"
|
|
9
|
+
? Number(portFlag)
|
|
10
|
+
: DEFAULT_PORT;
|
|
11
|
+
const host = typeof flags.host === "string" ? flags.host : DEFAULT_HOST;
|
|
12
|
+
const adapter = flags.adapter === "express" || flags.adapter === "fastify" ? flags.adapter : "node";
|
|
13
|
+
const distDir = typeof flags.distDir === "string"
|
|
14
|
+
? flags.distDir
|
|
15
|
+
: typeof flags["dist-dir"] === "string"
|
|
16
|
+
? flags["dist-dir"]
|
|
17
|
+
: "dist";
|
|
18
|
+
return {
|
|
19
|
+
port: Number.isFinite(port) ? port : DEFAULT_PORT,
|
|
20
|
+
host,
|
|
21
|
+
adapter,
|
|
22
|
+
distDir: distDir.startsWith("/") ? distDir : `${cwd}/${distDir}`,
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export const createStartCommand = (deps) => {
|
|
26
|
+
return async ({ flags, io }) => {
|
|
27
|
+
const cwd = deps.cwd ? deps.cwd() : process.cwd();
|
|
28
|
+
const options = resolveStartOptions(flags, cwd);
|
|
29
|
+
const runtimeConfig = deps.loadRuntimeConfig
|
|
30
|
+
? await deps.loadRuntimeConfig(cwd)
|
|
31
|
+
: undefined;
|
|
32
|
+
if (options.adapter !== "node") {
|
|
33
|
+
io.stderr.write(`Adapter ${options.adapter} is not implemented yet.\n`);
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
const server = await deps.createServer({
|
|
37
|
+
port: options.port,
|
|
38
|
+
host: options.host,
|
|
39
|
+
distDir: options.distDir,
|
|
40
|
+
adapterRegistry: runtimeConfig?.adapterRegistry,
|
|
41
|
+
uiAdapter: runtimeConfig?.uiAdapter,
|
|
42
|
+
uiOptions: runtimeConfig?.uiOptions,
|
|
43
|
+
appMode: runtimeConfig?.appMode,
|
|
44
|
+
});
|
|
45
|
+
io.stdout.write(`Runtime server running at ${server.url}\n`);
|
|
46
|
+
return 0;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export const runStartCommand = async (context) => {
|
|
50
|
+
const { createServer } = await import("@tyndall/runtime");
|
|
51
|
+
const { loadConfig } = await import("@tyndall/core");
|
|
52
|
+
const adapterRegistry = await resolveAdapterRegistry();
|
|
53
|
+
const command = createStartCommand({
|
|
54
|
+
createServer,
|
|
55
|
+
loadRuntimeConfig: async (cwd) => {
|
|
56
|
+
try {
|
|
57
|
+
const config = await loadConfig(cwd);
|
|
58
|
+
return {
|
|
59
|
+
adapterRegistry,
|
|
60
|
+
uiAdapter: config.ui.adapter,
|
|
61
|
+
uiOptions: {
|
|
62
|
+
...config.ui.options,
|
|
63
|
+
navigationMode: config.routing.navigation,
|
|
64
|
+
clientRenderMode: config.routing.clientRender,
|
|
65
|
+
},
|
|
66
|
+
appMode: config.mode,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Keep runtime startup resilient when config is unavailable and rely on dist defaults.
|
|
71
|
+
return {
|
|
72
|
+
adapterRegistry,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
return command(context);
|
|
78
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AASxC,eAAO,MAAM,MAAM,GACjB,MAAM,MAAM,EAAE,EACd,KAAI,KAAiB,KACpB,OAAO,CAAC,MAAM,CA8ChB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { parseArgs } from "./args.js";
|
|
2
|
+
import { COMMAND_LOOKUP, isCommandName } from "./commands/registry.js";
|
|
3
|
+
import { formatCliError } from "./errors.js";
|
|
4
|
+
import { createCliLogger } from "./logging.js";
|
|
5
|
+
import { formatUsage } from "./usage.js";
|
|
6
|
+
const CLI_VERSION = "0.0.1";
|
|
7
|
+
const defaultIO = {
|
|
8
|
+
stdout: process.stdout,
|
|
9
|
+
stderr: process.stderr,
|
|
10
|
+
};
|
|
11
|
+
export const runCli = async (argv, io = defaultIO) => {
|
|
12
|
+
const parsed = parseArgs(argv);
|
|
13
|
+
const logger = createCliLogger({
|
|
14
|
+
ci: Boolean(process.env.CI),
|
|
15
|
+
stdout: io.stdout,
|
|
16
|
+
stderr: io.stderr,
|
|
17
|
+
});
|
|
18
|
+
if (parsed.version) {
|
|
19
|
+
io.stdout.write(`cloud-front ${CLI_VERSION}\n`);
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
|
22
|
+
if (parsed.help || !parsed.command || parsed.command === "help") {
|
|
23
|
+
io.stdout.write(formatUsage());
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
if (!isCommandName(parsed.command)) {
|
|
27
|
+
logger.error(`Unknown command: ${parsed.command}`);
|
|
28
|
+
io.stderr.write(formatUsage());
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
const command = COMMAND_LOOKUP.get(parsed.command);
|
|
32
|
+
if (!command) {
|
|
33
|
+
logger.error(`Unknown command: ${parsed.command}`);
|
|
34
|
+
io.stderr.write(formatUsage());
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const result = await command.run({
|
|
39
|
+
args: parsed.args,
|
|
40
|
+
flags: parsed.flags,
|
|
41
|
+
io,
|
|
42
|
+
});
|
|
43
|
+
return Number.isInteger(result) ? result : 0;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
logger.error(`Command failed: ${parsed.command}`);
|
|
47
|
+
const detail = formatCliError(error);
|
|
48
|
+
if (detail.length > 0) {
|
|
49
|
+
logger.error(detail);
|
|
50
|
+
}
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
};
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,MAW/C,CAAC"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { formatHyperError, HyperError, isHyperError } from "@tyndall/core";
|
|
2
|
+
const isHyperErrorShape = (error) => {
|
|
3
|
+
if (!error || typeof error !== "object") {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
const candidate = error;
|
|
7
|
+
return typeof candidate.code === "string" && typeof candidate.message === "string";
|
|
8
|
+
};
|
|
9
|
+
export const formatCliError = (error) => {
|
|
10
|
+
if (isHyperError(error)) {
|
|
11
|
+
return formatHyperError(error);
|
|
12
|
+
}
|
|
13
|
+
if (isHyperErrorShape(error)) {
|
|
14
|
+
return formatHyperError(new HyperError(error.code, error.message, error.details));
|
|
15
|
+
}
|
|
16
|
+
if (error instanceof Error) {
|
|
17
|
+
return error.message;
|
|
18
|
+
}
|
|
19
|
+
return String(error);
|
|
20
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { parseArgs } from "./args.js";
|
|
2
|
+
export { runCli } from "./dispatcher.js";
|
|
3
|
+
export { formatUsage } from "./usage.js";
|
|
4
|
+
export { COMMANDS } from "./commands/registry.js";
|
|
5
|
+
export type { CliIO, CommandContext, CommandDefinition, CommandHandler, CommandName, FlagMap, FlagValue, ParsedArgs, } from "./types.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,YAAY,EACV,KAAK,EACL,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,OAAO,EACP,SAAS,EACT,UAAU,GACX,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface LoggerOptions {
|
|
2
|
+
ci?: boolean;
|
|
3
|
+
stdout?: {
|
|
4
|
+
write: (text: string) => void;
|
|
5
|
+
};
|
|
6
|
+
stderr?: {
|
|
7
|
+
write: (text: string) => void;
|
|
8
|
+
};
|
|
9
|
+
now?: () => number;
|
|
10
|
+
}
|
|
11
|
+
export interface CliLogger {
|
|
12
|
+
info: (message: string) => void;
|
|
13
|
+
warn: (message: string) => void;
|
|
14
|
+
error: (message: string) => void;
|
|
15
|
+
success: (message: string) => void;
|
|
16
|
+
time: (label: string) => () => number;
|
|
17
|
+
}
|
|
18
|
+
export declare const formatDuration: (durationMs: number) => string;
|
|
19
|
+
export declare const createCliLogger: (options?: LoggerOptions) => CliLogger;
|
|
20
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC3C,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC3C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,MAAM,CAAC;CACvC;AAaD,eAAO,MAAM,cAAc,GAAI,YAAY,MAAM,WAKhD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,UAAS,aAAkB,KAAG,SA2B7D,CAAC"}
|
package/dist/logging.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const COLORS = {
|
|
2
|
+
reset: "\u001b[0m",
|
|
3
|
+
red: "\u001b[31m",
|
|
4
|
+
green: "\u001b[32m",
|
|
5
|
+
yellow: "\u001b[33m",
|
|
6
|
+
cyan: "\u001b[36m",
|
|
7
|
+
};
|
|
8
|
+
const colorize = (text, color, enabled) => enabled ? `${color}${text}${COLORS.reset}` : text;
|
|
9
|
+
export const formatDuration = (durationMs) => {
|
|
10
|
+
if (durationMs >= 1000) {
|
|
11
|
+
return `${(durationMs / 1000).toFixed(2)}s`;
|
|
12
|
+
}
|
|
13
|
+
return `${durationMs}ms`;
|
|
14
|
+
};
|
|
15
|
+
export const createCliLogger = (options = {}) => {
|
|
16
|
+
const stdout = options.stdout ?? process.stdout;
|
|
17
|
+
const stderr = options.stderr ?? process.stderr;
|
|
18
|
+
const now = options.now ?? Date.now;
|
|
19
|
+
const useColor = !options.ci &&
|
|
20
|
+
!process.env.NO_COLOR &&
|
|
21
|
+
Boolean(process.stdout.isTTY);
|
|
22
|
+
const writeLine = (stream, message) => {
|
|
23
|
+
stream.write(`${message}\n`);
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
info: (message) => writeLine(stdout, colorize(message, COLORS.cyan, useColor)),
|
|
27
|
+
warn: (message) => writeLine(stderr, colorize(message, COLORS.yellow, useColor)),
|
|
28
|
+
error: (message) => writeLine(stderr, colorize(message, COLORS.red, useColor)),
|
|
29
|
+
success: (message) => writeLine(stdout, colorize(message, COLORS.green, useColor)),
|
|
30
|
+
time: (label) => {
|
|
31
|
+
const startedAt = now();
|
|
32
|
+
return () => {
|
|
33
|
+
const duration = now() - startedAt;
|
|
34
|
+
writeLine(stdout, `${label} ${formatDuration(duration)}`);
|
|
35
|
+
return duration;
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
package/dist/open.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface OpenCommand {
|
|
2
|
+
command: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
}
|
|
5
|
+
export declare const shouldAutoOpen: (env: NodeJS.ProcessEnv, platform: NodeJS.Platform) => boolean;
|
|
6
|
+
export declare const resolveOpenCommand: (platform: NodeJS.Platform, url: string) => OpenCommand;
|
|
7
|
+
export declare const openUrl: (url: string, env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform) => Promise<void>;
|
|
8
|
+
//# sourceMappingURL=open.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../src/open.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAID,eAAO,MAAM,cAAc,GACzB,KAAK,MAAM,CAAC,UAAU,EACtB,UAAU,MAAM,CAAC,QAAQ,KACxB,OASF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,CAAC,QAAQ,EAAE,KAAK,MAAM,KAAG,WAQ3E,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,KAAK,MAAM,EACX,MAAK,MAAM,CAAC,UAAwB,EACpC,WAAU,MAAM,CAAC,QAA2B,KAC3C,OAAO,CAAC,IAAI,CAcd,CAAC"}
|
package/dist/open.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const isTruthy = (value) => value !== undefined && value !== "0" && value.toLowerCase() !== "false";
|
|
3
|
+
export const shouldAutoOpen = (env, platform) => {
|
|
4
|
+
// Avoid spawning openers in CI/headless environments where it will fail or hang.
|
|
5
|
+
if (isTruthy(env.CI)) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (platform === "linux" && !env.DISPLAY && !env.WAYLAND_DISPLAY) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return true;
|
|
12
|
+
};
|
|
13
|
+
export const resolveOpenCommand = (platform, url) => {
|
|
14
|
+
if (platform === "darwin") {
|
|
15
|
+
return { command: "open", args: [url] };
|
|
16
|
+
}
|
|
17
|
+
if (platform === "win32") {
|
|
18
|
+
return { command: "cmd", args: ["/c", "start", "", url] };
|
|
19
|
+
}
|
|
20
|
+
return { command: "xdg-open", args: [url] };
|
|
21
|
+
};
|
|
22
|
+
export const openUrl = async (url, env = process.env, platform = process.platform) => {
|
|
23
|
+
if (!shouldAutoOpen(env, platform)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const { command, args } = resolveOpenCommand(platform, url);
|
|
27
|
+
try {
|
|
28
|
+
const child = spawn(command, args, { stdio: "ignore", detached: true });
|
|
29
|
+
child.on("error", () => undefined);
|
|
30
|
+
child.unref();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface PreviewServerOptions {
|
|
2
|
+
outDir: string;
|
|
3
|
+
port?: number;
|
|
4
|
+
host?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface PreviewServer {
|
|
7
|
+
host: string;
|
|
8
|
+
port: number;
|
|
9
|
+
url: string;
|
|
10
|
+
close: () => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare const startPreviewServer: (options: PreviewServerOptions) => Promise<PreviewServer>;
|
|
13
|
+
//# sourceMappingURL=preview-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-server.d.ts","sourceRoot":"","sources":["../src/preview-server.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAqBD,eAAO,MAAM,kBAAkB,GAC7B,SAAS,oBAAoB,KAC5B,OAAO,CAAC,aAAa,CAuDvB,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createServer as createHttpServer } from "node:http";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { extname, join, resolve } from "node:path";
|
|
4
|
+
const CONTENT_TYPES = {
|
|
5
|
+
".html": "text/html; charset=utf-8",
|
|
6
|
+
".js": "text/javascript; charset=utf-8",
|
|
7
|
+
".css": "text/css; charset=utf-8",
|
|
8
|
+
".json": "application/json; charset=utf-8",
|
|
9
|
+
".txt": "text/plain; charset=utf-8",
|
|
10
|
+
};
|
|
11
|
+
const resolveFilePath = (root, urlPath) => {
|
|
12
|
+
const sanitized = urlPath.split("?")[0].split("#")[0];
|
|
13
|
+
const withIndex = sanitized.endsWith("/") || sanitized === "" ? `${sanitized}index.html` : sanitized;
|
|
14
|
+
const fullPath = resolve(root, `.${withIndex}`);
|
|
15
|
+
// Important: block path traversal outside the output directory.
|
|
16
|
+
if (!fullPath.startsWith(resolve(root))) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return fullPath;
|
|
20
|
+
};
|
|
21
|
+
export const startPreviewServer = async (options) => {
|
|
22
|
+
const host = options.host ?? "localhost";
|
|
23
|
+
const port = options.port ?? 4173;
|
|
24
|
+
const outDir = resolve(options.outDir ?? join(process.cwd(), "dist"));
|
|
25
|
+
const server = createHttpServer(async (request, response) => {
|
|
26
|
+
const urlPath = request.url ?? "/";
|
|
27
|
+
const filePath = resolveFilePath(outDir, urlPath);
|
|
28
|
+
if (filePath) {
|
|
29
|
+
try {
|
|
30
|
+
const fileStat = await stat(filePath);
|
|
31
|
+
if (fileStat.isFile()) {
|
|
32
|
+
const data = await readFile(filePath);
|
|
33
|
+
const ext = extname(filePath);
|
|
34
|
+
response.statusCode = 200;
|
|
35
|
+
response.setHeader("content-type", CONTENT_TYPES[ext] ?? "application/octet-stream");
|
|
36
|
+
response.end(data);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// File not found, fall through to 404.
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
response.statusCode = 404;
|
|
45
|
+
response.setHeader("content-type", "text/plain; charset=utf-8");
|
|
46
|
+
response.end("Not Found");
|
|
47
|
+
});
|
|
48
|
+
await new Promise((resolvePromise, reject) => {
|
|
49
|
+
server.once("error", reject);
|
|
50
|
+
server.listen(port, host, () => resolvePromise());
|
|
51
|
+
});
|
|
52
|
+
const address = server.address();
|
|
53
|
+
if (!address || typeof address === "string") {
|
|
54
|
+
throw new Error("Preview server did not return a TCP address.");
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
host: address.address,
|
|
58
|
+
port: address.port,
|
|
59
|
+
url: `http://${address.address}:${address.port}`,
|
|
60
|
+
close: () => new Promise((resolvePromise, reject) => {
|
|
61
|
+
server.close((error) => {
|
|
62
|
+
if (error) {
|
|
63
|
+
reject(error);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
resolvePromise();
|
|
67
|
+
});
|
|
68
|
+
}),
|
|
69
|
+
};
|
|
70
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type FlagValue = string | number | boolean;
|
|
2
|
+
export type FlagMap = Record<string, FlagValue>;
|
|
3
|
+
export interface ParsedArgs {
|
|
4
|
+
command: string | null;
|
|
5
|
+
args: string[];
|
|
6
|
+
flags: FlagMap;
|
|
7
|
+
help: boolean;
|
|
8
|
+
version: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface CliIO {
|
|
11
|
+
stdout: {
|
|
12
|
+
write: (text: string) => void;
|
|
13
|
+
};
|
|
14
|
+
stderr: {
|
|
15
|
+
write: (text: string) => void;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface CommandContext {
|
|
19
|
+
args: string[];
|
|
20
|
+
flags: FlagMap;
|
|
21
|
+
io: CliIO;
|
|
22
|
+
}
|
|
23
|
+
export type CommandHandler = (ctx: CommandContext) => Promise<number> | number;
|
|
24
|
+
export type CommandName = "dev" | "build" | "start" | "preview" | "lint" | "format";
|
|
25
|
+
export interface CommandDefinition {
|
|
26
|
+
name: CommandName;
|
|
27
|
+
summary: string;
|
|
28
|
+
usage: string;
|
|
29
|
+
run: CommandHandler;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAClD,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CAC3C;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,EAAE,EAAE,KAAK,CAAC;CACX;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;AAE/E,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEpF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,cAAc,CAAC;CACrB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/usage.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,QAAO,MA0B9B,CAAC"}
|
package/dist/usage.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { COMMANDS } from "./commands/registry.js";
|
|
2
|
+
export const formatUsage = () => {
|
|
3
|
+
const lines = [
|
|
4
|
+
"Cloud Front CLI",
|
|
5
|
+
"",
|
|
6
|
+
"Usage:",
|
|
7
|
+
" cloud-front <command> [flags]",
|
|
8
|
+
"",
|
|
9
|
+
"Commands:",
|
|
10
|
+
];
|
|
11
|
+
// Keep this list deterministic for snapshot testing and docs alignment.
|
|
12
|
+
for (const command of COMMANDS) {
|
|
13
|
+
const padded = command.name.padEnd(8, " ");
|
|
14
|
+
lines.push(` ${padded} ${command.summary}`);
|
|
15
|
+
}
|
|
16
|
+
lines.push("", "Global Flags:", " -h, --help Show help", " -v, --version Show version", "", "Run `cloud-front <command> --help` for command-specific flags.");
|
|
17
|
+
return `${lines.join("\n")}\n`;
|
|
18
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tyndall/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"cloud-front": "./bin/cloud-front.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"bun": "./src/index.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"bin"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc -p tsconfig.json"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@tyndall/core": "workspace:*",
|
|
29
|
+
"@tyndall/dev": "workspace:*",
|
|
30
|
+
"@tyndall/build": "workspace:*",
|
|
31
|
+
"@tyndall/runtime": "workspace:*",
|
|
32
|
+
"@tyndall/shared": "workspace:*",
|
|
33
|
+
"@tyndall/lint": "workspace:*",
|
|
34
|
+
"@tyndall/webcomponents": "workspace:*",
|
|
35
|
+
"@tyndall/wasm": "workspace:*"
|
|
36
|
+
}
|
|
37
|
+
}
|