@forge-ts/cli 0.15.0 → 0.17.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/{chunk-CINQWGH7.js → chunk-57QAENSK.js} +67 -35
- package/dist/chunk-57QAENSK.js.map +1 -0
- package/dist/chunk-CNINN7IQ.js +28 -0
- package/dist/chunk-CNINN7IQ.js.map +1 -0
- package/dist/forge-logger-RTOBEKWH.js +10 -0
- package/dist/index.d.ts +112 -90
- package/dist/index.js +98 -133
- package/dist/index.js.map +1 -1
- package/dist/{init-project-5DESIZ73.js → init-project-PT4XOWV2.js} +3 -3
- package/package.json +7 -7
- package/dist/chunk-7UPSAG3L.js +0 -44
- package/dist/chunk-7UPSAG3L.js.map +0 -1
- package/dist/chunk-CINQWGH7.js.map +0 -1
- package/dist/logger-MMBBZG6U.js +0 -8
- /package/dist/{init-project-5DESIZ73.js.map → forge-logger-RTOBEKWH.js.map} +0 -0
- /package/dist/{logger-MMBBZG6U.js.map → init-project-PT4XOWV2.js.map} +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
forgeLogger
|
|
4
|
+
} from "./chunk-CNINN7IQ.js";
|
|
2
5
|
import {
|
|
3
6
|
emitResult,
|
|
4
7
|
resolveExitCode
|
|
5
8
|
} from "./chunk-ZFFY4AQX.js";
|
|
6
|
-
import {
|
|
7
|
-
createLogger
|
|
8
|
-
} from "./chunk-7UPSAG3L.js";
|
|
9
9
|
|
|
10
10
|
// src/commands/init-project.ts
|
|
11
11
|
import { existsSync, readFileSync } from "fs";
|
|
12
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
12
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
13
13
|
import { join } from "path";
|
|
14
14
|
import { defineCommand } from "citty";
|
|
15
15
|
function readJsonSafe(filePath) {
|
|
@@ -84,18 +84,8 @@ var DEFAULT_CONFIG_CONTENT = `import { defineConfig } from "@forge-ts/core";
|
|
|
84
84
|
|
|
85
85
|
export default defineConfig({
|
|
86
86
|
rootDir: ".",
|
|
87
|
-
tsconfig: "tsconfig.json",
|
|
88
87
|
outDir: "docs/generated",
|
|
89
|
-
enforce: {
|
|
90
|
-
enabled: true,
|
|
91
|
-
minVisibility: "public",
|
|
92
|
-
strict: false,
|
|
93
|
-
},
|
|
94
88
|
gen: {
|
|
95
|
-
enabled: true,
|
|
96
|
-
formats: ["mdx"],
|
|
97
|
-
llmsTxt: true,
|
|
98
|
-
readmeSync: false,
|
|
99
89
|
ssgTarget: "mintlify",
|
|
100
90
|
},
|
|
101
91
|
});
|
|
@@ -103,11 +93,22 @@ export default defineConfig({
|
|
|
103
93
|
var DEFAULT_TSDOC_CONTENT = JSON.stringify(
|
|
104
94
|
{
|
|
105
95
|
$schema: "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
|
|
106
|
-
extends: ["@forge-ts/tsdoc-
|
|
96
|
+
extends: ["@forge-ts/core/tsdoc-preset/tsdoc.json"]
|
|
107
97
|
},
|
|
108
98
|
null,
|
|
109
99
|
" "
|
|
110
100
|
);
|
|
101
|
+
var FORGE_SCRIPTS = {
|
|
102
|
+
"forge:check": "forge-ts check",
|
|
103
|
+
"forge:test": "forge-ts test",
|
|
104
|
+
"forge:build": "forge-ts build",
|
|
105
|
+
"forge:doctor": "forge-ts doctor",
|
|
106
|
+
prepublishOnly: "forge-ts prepublish"
|
|
107
|
+
};
|
|
108
|
+
function detectJsonIndent(raw) {
|
|
109
|
+
const match = raw.match(/\n(\s+)"/);
|
|
110
|
+
return match ? match[1] : " ";
|
|
111
|
+
}
|
|
111
112
|
async function runInitProject(args) {
|
|
112
113
|
const start = Date.now();
|
|
113
114
|
const rootDir = args.cwd ?? process.cwd();
|
|
@@ -130,7 +131,8 @@ async function runInitProject(args) {
|
|
|
130
131
|
skipped: [],
|
|
131
132
|
warnings: [],
|
|
132
133
|
environment,
|
|
133
|
-
nextSteps: []
|
|
134
|
+
nextSteps: [],
|
|
135
|
+
scriptsAdded: []
|
|
134
136
|
},
|
|
135
137
|
errors: [err],
|
|
136
138
|
duration: Date.now() - start
|
|
@@ -161,14 +163,45 @@ async function runInitProject(args) {
|
|
|
161
163
|
`, "utf8");
|
|
162
164
|
created.push("tsdoc.json");
|
|
163
165
|
}
|
|
166
|
+
const scriptsAdded = [];
|
|
167
|
+
const pkgPathForScripts = join(rootDir, "package.json");
|
|
168
|
+
if (environment.packageJsonExists) {
|
|
169
|
+
try {
|
|
170
|
+
const pkgRaw = await readFile(pkgPathForScripts, "utf8");
|
|
171
|
+
const pkgObj = JSON.parse(pkgRaw);
|
|
172
|
+
const existingScripts = pkgObj.scripts ?? {};
|
|
173
|
+
let modified = false;
|
|
174
|
+
for (const [key, value] of Object.entries(FORGE_SCRIPTS)) {
|
|
175
|
+
if (!(key in existingScripts)) {
|
|
176
|
+
existingScripts[key] = value;
|
|
177
|
+
scriptsAdded.push(key);
|
|
178
|
+
modified = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (modified) {
|
|
182
|
+
pkgObj.scripts = existingScripts;
|
|
183
|
+
const indent = detectJsonIndent(pkgRaw);
|
|
184
|
+
const trailingNewline = pkgRaw.endsWith("\n") ? "\n" : "";
|
|
185
|
+
await writeFile(
|
|
186
|
+
pkgPathForScripts,
|
|
187
|
+
JSON.stringify(pkgObj, null, indent) + trailingNewline,
|
|
188
|
+
"utf8"
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
warnings.push("package.json: failed to wire scripts \u2014 file may be malformed.");
|
|
193
|
+
cliWarnings.push({
|
|
194
|
+
code: "INIT_SCRIPTS_FAILED",
|
|
195
|
+
message: "package.json: failed to wire scripts \u2014 file may be malformed."
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
164
199
|
if (environment.tsconfigExists) {
|
|
165
200
|
const tsconfigPath = join(rootDir, "tsconfig.json");
|
|
166
201
|
const tsconfig = readJsonSafe(tsconfigPath);
|
|
167
202
|
if (tsconfig) {
|
|
168
203
|
if (!tsconfig.compilerOptions || tsconfig.compilerOptions.strict !== true) {
|
|
169
|
-
warnings.push(
|
|
170
|
-
"tsconfig.json: 'strict' is not enabled. forge-ts recommends strict mode."
|
|
171
|
-
);
|
|
204
|
+
warnings.push("tsconfig.json: 'strict' is not enabled. forge-ts recommends strict mode.");
|
|
172
205
|
cliWarnings.push({
|
|
173
206
|
code: "INIT_TSCONFIG_NOT_STRICT",
|
|
174
207
|
message: "tsconfig.json: 'strict' is not enabled. forge-ts recommends strict mode."
|
|
@@ -180,9 +213,7 @@ async function runInitProject(args) {
|
|
|
180
213
|
const pkg = readJsonSafe(pkgPath);
|
|
181
214
|
if (pkg) {
|
|
182
215
|
if (pkg.type !== "module") {
|
|
183
|
-
warnings.push(
|
|
184
|
-
'package.json: missing "type": "module". forge-ts uses ESM.'
|
|
185
|
-
);
|
|
216
|
+
warnings.push('package.json: missing "type": "module". forge-ts uses ESM.');
|
|
186
217
|
cliWarnings.push({
|
|
187
218
|
code: "INIT_NO_ESM",
|
|
188
219
|
message: 'package.json: missing "type": "module". forge-ts uses ESM.'
|
|
@@ -197,9 +228,7 @@ async function runInitProject(args) {
|
|
|
197
228
|
}
|
|
198
229
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
199
230
|
if (!("@forge-ts/cli" in allDeps)) {
|
|
200
|
-
warnings.push(
|
|
201
|
-
"package.json: @forge-ts/cli not in devDependencies (running via npx?)."
|
|
202
|
-
);
|
|
231
|
+
warnings.push("package.json: @forge-ts/cli not in devDependencies (running via npx?).");
|
|
203
232
|
cliWarnings.push({
|
|
204
233
|
code: "INIT_CLI_NOT_INSTALLED",
|
|
205
234
|
message: "package.json: @forge-ts/cli not in devDependencies (running via npx?)."
|
|
@@ -218,7 +247,8 @@ async function runInitProject(args) {
|
|
|
218
247
|
skipped,
|
|
219
248
|
warnings,
|
|
220
249
|
environment,
|
|
221
|
-
nextSteps
|
|
250
|
+
nextSteps,
|
|
251
|
+
scriptsAdded
|
|
222
252
|
};
|
|
223
253
|
return {
|
|
224
254
|
operation: "init",
|
|
@@ -248,6 +278,13 @@ function formatInitProjectHuman(result) {
|
|
|
248
278
|
lines.push(" Already exists (skipped):");
|
|
249
279
|
lines.push(" (none)");
|
|
250
280
|
}
|
|
281
|
+
if (result.scriptsAdded.length > 0) {
|
|
282
|
+
lines.push("");
|
|
283
|
+
lines.push(" Scripts added to package.json:");
|
|
284
|
+
for (const script of result.scriptsAdded) {
|
|
285
|
+
lines.push(` ${script}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
251
288
|
if (result.warnings.length > 0) {
|
|
252
289
|
lines.push("");
|
|
253
290
|
lines.push(" Warnings:");
|
|
@@ -258,12 +295,8 @@ function formatInitProjectHuman(result) {
|
|
|
258
295
|
const env = result.environment;
|
|
259
296
|
lines.push("");
|
|
260
297
|
lines.push(" Environment:");
|
|
261
|
-
lines.push(
|
|
262
|
-
|
|
263
|
-
);
|
|
264
|
-
lines.push(
|
|
265
|
-
` Biome: ${env.biomeDetected ? "detected" : "not detected"}`
|
|
266
|
-
);
|
|
298
|
+
lines.push(` TypeScript: ${env.typescriptVersion ?? "not detected"}`);
|
|
299
|
+
lines.push(` Biome: ${env.biomeDetected ? "detected" : "not detected"}`);
|
|
267
300
|
const hookLabel = env.hookManager === "none" ? "not detected" : `${env.hookManager} detected`;
|
|
268
301
|
lines.push(` Git hooks: ${hookLabel}`);
|
|
269
302
|
if (env.monorepo) {
|
|
@@ -325,9 +358,8 @@ var initProjectCommand = defineCommand({
|
|
|
325
358
|
};
|
|
326
359
|
emitResult(output, flags, (data, cmd) => {
|
|
327
360
|
if (!cmd.success) {
|
|
328
|
-
const logger = createLogger();
|
|
329
361
|
const msg = cmd.errors?.[0]?.message ?? "Init failed";
|
|
330
|
-
|
|
362
|
+
forgeLogger.error(msg);
|
|
331
363
|
return "";
|
|
332
364
|
}
|
|
333
365
|
return formatInitProjectHuman(data);
|
|
@@ -341,4 +373,4 @@ export {
|
|
|
341
373
|
runInitProject,
|
|
342
374
|
initProjectCommand
|
|
343
375
|
};
|
|
344
|
-
//# sourceMappingURL=chunk-
|
|
376
|
+
//# sourceMappingURL=chunk-57QAENSK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/init-project.ts"],"sourcesContent":["/**\n * `forge-ts init` command — full project setup.\n *\n * Detects the project environment, writes default config files, validates\n * tsconfig/package.json, and prints a summary with next steps.\n *\n * @packageDocumentation\n * @internal\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { defineCommand } from \"citty\";\nimport { forgeLogger } from \"../forge-logger.js\";\nimport {\n\ttype CommandOutput,\n\temitResult,\n\ttype ForgeCliError,\n\ttype ForgeCliWarning,\n\ttype OutputFlags,\n\tresolveExitCode,\n} from \"../output.js\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Detected project environment from Step 1 of the init flow.\n *\n * @public\n */\nexport interface InitProjectEnvironment {\n\t/** Whether package.json exists. */\n\tpackageJsonExists: boolean;\n\t/** Whether tsconfig.json exists. */\n\ttsconfigExists: boolean;\n\t/** Whether biome.json or biome.jsonc exists. */\n\tbiomeDetected: boolean;\n\t/** TypeScript version from dependencies, or null if not found. */\n\ttypescriptVersion: string | null;\n\t/** Detected hook manager. */\n\thookManager: \"husky\" | \"lefthook\" | \"none\";\n\t/** Whether the project is a monorepo. */\n\tmonorepo: boolean;\n\t/** Monorepo type if detected. */\n\tmonorepoType: \"pnpm\" | \"npm/yarn\" | null;\n}\n\n/**\n * Result of the `init` (project setup) command.\n *\n * @example\n * ```typescript\n * import { runInitProject } from \"@forge-ts/cli/commands/init-project\";\n * const output = await runInitProject({ cwd: process.cwd() });\n * console.log(output.data.created); // list of created files\n * ```\n * @public\n */\nexport interface InitProjectResult {\n\t/** Whether the init succeeded. */\n\tsuccess: boolean;\n\t/** Files that were created. */\n\tcreated: string[];\n\t/** Files that already existed and were skipped. */\n\tskipped: string[];\n\t/** Warning messages collected during init. */\n\twarnings: string[];\n\t/** Detected project environment. */\n\tenvironment: InitProjectEnvironment;\n\t/** Next steps for the user. */\n\tnextSteps: string[];\n\t/** Scripts that were added to package.json (empty if none were added). */\n\tscriptsAdded: string[];\n}\n\n/**\n * Arguments for the `init` (project setup) command.\n * @internal\n */\nexport interface InitProjectArgs {\n\t/** Project root directory (default: cwd). */\n\tcwd?: string;\n\t/** MVI verbosity level for structured output. */\n\tmvi?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Reads and parses a package.json file.\n * @internal\n */\ninterface PackageJsonShape {\n\ttype?: string;\n\tengines?: { node?: string };\n\tdependencies?: Record<string, string>;\n\tdevDependencies?: Record<string, string>;\n\tscripts?: Record<string, string>;\n\tworkspaces?: string[] | { packages: string[] };\n}\n\n/**\n * Safely reads and parses a JSON file.\n * @internal\n */\nfunction readJsonSafe<T>(filePath: string): T | null {\n\tif (!existsSync(filePath)) {\n\t\treturn null;\n\t}\n\ttry {\n\t\tconst raw = readFileSync(filePath, \"utf8\");\n\t\treturn JSON.parse(raw) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Environment detection\n// ---------------------------------------------------------------------------\n\n/**\n * Detects the project environment by checking for files and dependencies.\n *\n * @param rootDir - Absolute path to the project root.\n * @returns The detected environment.\n * @internal\n */\nexport function detectEnvironment(rootDir: string): InitProjectEnvironment {\n\tconst packageJsonPath = join(rootDir, \"package.json\");\n\tconst tsconfigPath = join(rootDir, \"tsconfig.json\");\n\tconst biomePath = join(rootDir, \"biome.json\");\n\tconst biomecPath = join(rootDir, \"biome.jsonc\");\n\tconst pnpmWorkspacePath = join(rootDir, \"pnpm-workspace.yaml\");\n\tconst huskyDir = join(rootDir, \".husky\");\n\tconst lefthookYml = join(rootDir, \"lefthook.yml\");\n\n\tconst packageJsonExists = existsSync(packageJsonPath);\n\tconst tsconfigExists = existsSync(tsconfigPath);\n\tconst biomeDetected = existsSync(biomePath) || existsSync(biomecPath);\n\n\t// TypeScript version detection\n\tlet typescriptVersion: string | null = null;\n\tif (packageJsonExists) {\n\t\tconst pkg = readJsonSafe<PackageJsonShape>(packageJsonPath);\n\t\tif (pkg) {\n\t\t\tconst tsVersion = pkg.devDependencies?.typescript ?? pkg.dependencies?.typescript ?? null;\n\t\t\ttypescriptVersion = tsVersion;\n\t\t}\n\t}\n\n\t// Hook manager detection\n\tlet hookManager: \"husky\" | \"lefthook\" | \"none\" = \"none\";\n\tif (existsSync(huskyDir)) {\n\t\thookManager = \"husky\";\n\t} else if (existsSync(lefthookYml)) {\n\t\thookManager = \"lefthook\";\n\t} else if (packageJsonExists) {\n\t\tconst pkg = readJsonSafe<PackageJsonShape>(packageJsonPath);\n\t\tif (pkg) {\n\t\t\tconst allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n\t\t\tif (\"husky\" in allDeps) {\n\t\t\t\thookManager = \"husky\";\n\t\t\t} else if (\"lefthook\" in allDeps) {\n\t\t\t\thookManager = \"lefthook\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Monorepo detection\n\tlet monorepo = false;\n\tlet monorepoType: \"pnpm\" | \"npm/yarn\" | null = null;\n\tif (existsSync(pnpmWorkspacePath)) {\n\t\tmonorepo = true;\n\t\tmonorepoType = \"pnpm\";\n\t} else if (packageJsonExists) {\n\t\tconst pkg = readJsonSafe<PackageJsonShape>(packageJsonPath);\n\t\tif (pkg?.workspaces) {\n\t\t\tmonorepo = true;\n\t\t\tmonorepoType = \"npm/yarn\";\n\t\t}\n\t}\n\n\treturn {\n\t\tpackageJsonExists,\n\t\ttsconfigExists,\n\t\tbiomeDetected,\n\t\ttypescriptVersion,\n\t\thookManager,\n\t\tmonorepo,\n\t\tmonorepoType,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Config file content\n// ---------------------------------------------------------------------------\n\n/**\n * Default forge-ts.config.ts content for new projects.\n *\n * Only overrides that differ from built-in defaults are included.\n * The full defaults (enforce rules, doctest, etc.) are merged\n * automatically by `loadConfig()` → `mergeWithDefaults()`.\n * @internal\n */\nconst DEFAULT_CONFIG_CONTENT = `import { defineConfig } from \"@forge-ts/core\";\n\nexport default defineConfig({\n rootDir: \".\",\n outDir: \"docs/generated\",\n gen: {\n ssgTarget: \"mintlify\",\n },\n});\n`;\n\n/**\n * Default tsdoc.json content.\n * @internal\n */\nconst DEFAULT_TSDOC_CONTENT = JSON.stringify(\n\t{\n\t\t$schema: \"https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json\",\n\t\textends: [\"@forge-ts/core/tsdoc-preset/tsdoc.json\"],\n\t},\n\tnull,\n\t\"\\t\",\n);\n\n/**\n * Default npm scripts wired by `forge-ts init`.\n *\n * Each entry is only added when the key does **not** already exist in\n * the user's `package.json`, making the operation idempotent.\n * @internal\n */\nconst FORGE_SCRIPTS: Record<string, string> = {\n\t\"forge:check\": \"forge-ts check\",\n\t\"forge:test\": \"forge-ts test\",\n\t\"forge:build\": \"forge-ts build\",\n\t\"forge:doctor\": \"forge-ts doctor\",\n\tprepublishOnly: \"forge-ts prepublish\",\n};\n\n/**\n * Detects the indentation style of a JSON file by inspecting the\n * first indented line. Returns the indent string (tabs or spaces).\n * Falls back to two spaces when detection fails.\n * @internal\n */\nfunction detectJsonIndent(raw: string): string {\n\tconst match = raw.match(/\\n(\\s+)\"/);\n\treturn match ? match[1] : \" \";\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Runs the full project init flow.\n *\n * Steps:\n * 1. Detect project environment\n * 2. Write forge-ts.config.ts (if not exists)\n * 3. Write tsdoc.json (if not exists)\n * 4. Wire package.json scripts (idempotent)\n * 5. Validate tsconfig.json strictness\n * 6. Validate package.json\n * 7. Report summary\n *\n * @param args - CLI arguments for the init command.\n * @returns A typed `CommandOutput<InitProjectResult>`.\n * @example\n * ```typescript\n * import { runInitProject } from \"@forge-ts/cli/commands/init-project\";\n * const output = await runInitProject({ cwd: process.cwd() });\n * console.log(output.data.created); // [\"forge-ts.config.ts\", \"tsdoc.json\"]\n * ```\n * @public\n */\nexport async function runInitProject(\n\targs: InitProjectArgs,\n): Promise<CommandOutput<InitProjectResult>> {\n\tconst start = Date.now();\n\tconst rootDir = args.cwd ?? process.cwd();\n\n\tconst created: string[] = [];\n\tconst skipped: string[] = [];\n\tconst warnings: string[] = [];\n\tconst cliWarnings: ForgeCliWarning[] = [];\n\n\t// -----------------------------------------------------------------------\n\t// Step 1: Detect project environment\n\t// -----------------------------------------------------------------------\n\n\tconst environment = detectEnvironment(rootDir);\n\n\tif (!environment.packageJsonExists) {\n\t\tconst err: ForgeCliError = {\n\t\t\tcode: \"INIT_NO_PACKAGE_JSON\",\n\t\t\tmessage: \"package.json not found. Run `npm init` or `pnpm init` first.\",\n\t\t};\n\t\treturn {\n\t\t\toperation: \"init\",\n\t\t\tsuccess: false,\n\t\t\tdata: {\n\t\t\t\tsuccess: false,\n\t\t\t\tcreated: [],\n\t\t\t\tskipped: [],\n\t\t\t\twarnings: [],\n\t\t\t\tenvironment,\n\t\t\t\tnextSteps: [],\n\t\t\t\tscriptsAdded: [],\n\t\t\t},\n\t\t\terrors: [err],\n\t\t\tduration: Date.now() - start,\n\t\t};\n\t}\n\n\tif (!environment.tsconfigExists) {\n\t\twarnings.push(\"tsconfig.json not found. forge-ts requires TypeScript.\");\n\t\tcliWarnings.push({\n\t\t\tcode: \"INIT_NO_TSCONFIG\",\n\t\t\tmessage: \"tsconfig.json not found. forge-ts requires TypeScript.\",\n\t\t});\n\t}\n\n\tif (!environment.biomeDetected) {\n\t\t// Informational — not a warning\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 2: Write forge-ts.config.ts\n\t// -----------------------------------------------------------------------\n\n\tconst configPath = join(rootDir, \"forge-ts.config.ts\");\n\tif (existsSync(configPath)) {\n\t\tskipped.push(\"forge-ts.config.ts\");\n\t} else {\n\t\tawait mkdir(rootDir, { recursive: true });\n\t\tawait writeFile(configPath, DEFAULT_CONFIG_CONTENT, \"utf8\");\n\t\tcreated.push(\"forge-ts.config.ts\");\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 3: Write tsdoc.json\n\t// -----------------------------------------------------------------------\n\n\tconst tsdocPath = join(rootDir, \"tsdoc.json\");\n\tif (existsSync(tsdocPath)) {\n\t\tskipped.push(\"tsdoc.json\");\n\t} else {\n\t\tawait writeFile(tsdocPath, `${DEFAULT_TSDOC_CONTENT}\\n`, \"utf8\");\n\t\tcreated.push(\"tsdoc.json\");\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 4: Wire package.json scripts (idempotent)\n\t// -----------------------------------------------------------------------\n\n\tconst scriptsAdded: string[] = [];\n\tconst pkgPathForScripts = join(rootDir, \"package.json\");\n\tif (environment.packageJsonExists) {\n\t\ttry {\n\t\t\tconst pkgRaw = await readFile(pkgPathForScripts, \"utf8\");\n\t\t\tconst pkgObj = JSON.parse(pkgRaw) as Record<string, unknown>;\n\t\t\tconst existingScripts = (pkgObj.scripts ?? {}) as Record<string, string>;\n\t\t\tlet modified = false;\n\n\t\t\tfor (const [key, value] of Object.entries(FORGE_SCRIPTS)) {\n\t\t\t\tif (!(key in existingScripts)) {\n\t\t\t\t\texistingScripts[key] = value;\n\t\t\t\t\tscriptsAdded.push(key);\n\t\t\t\t\tmodified = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (modified) {\n\t\t\t\tpkgObj.scripts = existingScripts;\n\t\t\t\tconst indent = detectJsonIndent(pkgRaw);\n\t\t\t\tconst trailingNewline = pkgRaw.endsWith(\"\\n\") ? \"\\n\" : \"\";\n\t\t\t\tawait writeFile(\n\t\t\t\t\tpkgPathForScripts,\n\t\t\t\t\tJSON.stringify(pkgObj, null, indent) + trailingNewline,\n\t\t\t\t\t\"utf8\",\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\twarnings.push(\"package.json: failed to wire scripts — file may be malformed.\");\n\t\t\tcliWarnings.push({\n\t\t\t\tcode: \"INIT_SCRIPTS_FAILED\",\n\t\t\t\tmessage: \"package.json: failed to wire scripts — file may be malformed.\",\n\t\t\t});\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 5: Validate tsconfig.json strictness\n\t// -----------------------------------------------------------------------\n\n\tif (environment.tsconfigExists) {\n\t\tconst tsconfigPath = join(rootDir, \"tsconfig.json\");\n\t\tconst tsconfig = readJsonSafe<{\n\t\t\tcompilerOptions?: { strict?: boolean };\n\t\t}>(tsconfigPath);\n\n\t\tif (tsconfig) {\n\t\t\tif (!tsconfig.compilerOptions || tsconfig.compilerOptions.strict !== true) {\n\t\t\t\twarnings.push(\"tsconfig.json: 'strict' is not enabled. forge-ts recommends strict mode.\");\n\t\t\t\tcliWarnings.push({\n\t\t\t\t\tcode: \"INIT_TSCONFIG_NOT_STRICT\",\n\t\t\t\t\tmessage: \"tsconfig.json: 'strict' is not enabled. forge-ts recommends strict mode.\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 6: Validate package.json\n\t// -----------------------------------------------------------------------\n\n\tconst pkgPath = join(rootDir, \"package.json\");\n\tconst pkg = readJsonSafe<PackageJsonShape>(pkgPath);\n\n\tif (pkg) {\n\t\tif (pkg.type !== \"module\") {\n\t\t\twarnings.push('package.json: missing \"type\": \"module\". forge-ts uses ESM.');\n\t\t\tcliWarnings.push({\n\t\t\t\tcode: \"INIT_NO_ESM\",\n\t\t\t\tmessage: 'package.json: missing \"type\": \"module\". forge-ts uses ESM.',\n\t\t\t});\n\t\t}\n\n\t\tif (!pkg.engines?.node) {\n\t\t\twarnings.push(\"package.json: missing engines.node field.\");\n\t\t\tcliWarnings.push({\n\t\t\t\tcode: \"INIT_NO_ENGINES\",\n\t\t\t\tmessage: \"package.json: missing engines.node field.\",\n\t\t\t});\n\t\t}\n\n\t\tconst allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n\t\tif (!(\"@forge-ts/cli\" in allDeps)) {\n\t\t\twarnings.push(\"package.json: @forge-ts/cli not in devDependencies (running via npx?).\");\n\t\t\tcliWarnings.push({\n\t\t\t\tcode: \"INIT_CLI_NOT_INSTALLED\",\n\t\t\t\tmessage: \"package.json: @forge-ts/cli not in devDependencies (running via npx?).\",\n\t\t\t});\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 7: Build result\n\t// -----------------------------------------------------------------------\n\n\tconst nextSteps: string[] = [\n\t\t\"Run: forge-ts check (lint TSDoc coverage)\",\n\t\t\"Run: forge-ts init docs (scaffold documentation site)\",\n\t\t\"Run: forge-ts init hooks (scaffold pre-commit hooks)\",\n\t\t\"Run: forge-ts lock (lock config to prevent drift)\",\n\t];\n\n\tconst data: InitProjectResult = {\n\t\tsuccess: true,\n\t\tcreated,\n\t\tskipped,\n\t\twarnings,\n\t\tenvironment,\n\t\tnextSteps,\n\t\tscriptsAdded,\n\t};\n\n\treturn {\n\t\toperation: \"init\",\n\t\tsuccess: true,\n\t\tdata,\n\t\twarnings: cliWarnings.length > 0 ? cliWarnings : undefined,\n\t\tduration: Date.now() - start,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Human formatter\n// ---------------------------------------------------------------------------\n\n/**\n * Formats an InitProjectResult as human-readable text.\n * @internal\n */\nfunction formatInitProjectHuman(result: InitProjectResult): string {\n\tconst lines: string[] = [];\n\n\tlines.push(\"\\nforge-ts init: project setup complete\\n\");\n\n\t// Created files\n\tif (result.created.length > 0) {\n\t\tlines.push(\" Created:\");\n\t\tfor (const file of result.created) {\n\t\t\tlines.push(` ${file}`);\n\t\t}\n\t}\n\n\t// Skipped files\n\tif (result.skipped.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Already exists (skipped):\");\n\t\tfor (const file of result.skipped) {\n\t\t\tlines.push(` ${file}`);\n\t\t}\n\t} else if (result.created.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Already exists (skipped):\");\n\t\tlines.push(\" (none)\");\n\t}\n\n\t// Scripts added\n\tif (result.scriptsAdded.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Scripts added to package.json:\");\n\t\tfor (const script of result.scriptsAdded) {\n\t\t\tlines.push(` ${script}`);\n\t\t}\n\t}\n\n\t// Warnings\n\tif (result.warnings.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Warnings:\");\n\t\tfor (const warning of result.warnings) {\n\t\t\tlines.push(` ${warning}`);\n\t\t}\n\t}\n\n\t// Environment\n\tconst env = result.environment;\n\tlines.push(\"\");\n\tlines.push(\" Environment:\");\n\tlines.push(` TypeScript: ${env.typescriptVersion ?? \"not detected\"}`);\n\tlines.push(` Biome: ${env.biomeDetected ? \"detected\" : \"not detected\"}`);\n\n\tconst hookLabel = env.hookManager === \"none\" ? \"not detected\" : `${env.hookManager} detected`;\n\tlines.push(` Git hooks: ${hookLabel}`);\n\n\tif (env.monorepo) {\n\t\tlines.push(\n\t\t\t` Monorepo: ${env.monorepoType === \"pnpm\" ? \"pnpm workspaces\" : \"npm/yarn workspaces\"}`,\n\t\t);\n\t} else {\n\t\tlines.push(\" Monorepo: no\");\n\t}\n\n\t// Next steps\n\tif (result.nextSteps.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Next steps:\");\n\t\tfor (const [idx, step] of result.nextSteps.entries()) {\n\t\t\tlines.push(` ${idx + 1}. ${step}`);\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Citty command definition\n// ---------------------------------------------------------------------------\n\n/**\n * Citty command definition for `forge-ts init` (bare — full project setup).\n *\n * Detects the project environment, writes default configuration files,\n * validates tsconfig/package.json, and reports a summary.\n *\n * @example\n * ```typescript\n * import { initProjectCommand } from \"@forge-ts/cli/commands/init-project\";\n * // Registered as the default handler for `forge-ts init`\n * ```\n * @public\n */\nexport const initProjectCommand = defineCommand({\n\tmeta: {\n\t\tname: \"init\",\n\t\tdescription: \"Full project setup for forge-ts\",\n\t},\n\targs: {\n\t\tcwd: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Project root directory\",\n\t\t},\n\t\tjson: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Output as LAFS JSON envelope\",\n\t\t\tdefault: false,\n\t\t},\n\t\thuman: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Output as formatted text\",\n\t\t\tdefault: false,\n\t\t},\n\t\tquiet: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Suppress non-essential output\",\n\t\t\tdefault: false,\n\t\t},\n\t\tmvi: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"MVI verbosity level: minimal, standard, full\",\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst output = await runInitProject({\n\t\t\tcwd: args.cwd,\n\t\t\tmvi: args.mvi,\n\t\t});\n\n\t\tconst flags: OutputFlags = {\n\t\t\tjson: args.json,\n\t\t\thuman: args.human,\n\t\t\tquiet: args.quiet,\n\t\t\tmvi: args.mvi,\n\t\t};\n\n\t\temitResult(output, flags, (data, cmd) => {\n\t\t\tif (!cmd.success) {\n\t\t\t\tconst msg = cmd.errors?.[0]?.message ?? \"Init failed\";\n\t\t\t\tforgeLogger.error(msg);\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\treturn formatInitProjectHuman(data);\n\t\t});\n\n\t\tprocess.exit(resolveExitCode(output));\n\t},\n});\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/forge-logger.ts
|
|
4
|
+
import { createConsola } from "consola";
|
|
5
|
+
var forgeLogger = createConsola({
|
|
6
|
+
defaults: { tag: "forge-ts" }
|
|
7
|
+
});
|
|
8
|
+
function configureLogger(options) {
|
|
9
|
+
if (options.quiet) {
|
|
10
|
+
forgeLogger.level = 0;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (options.json) {
|
|
14
|
+
forgeLogger.level = 0;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (options.verbose) {
|
|
18
|
+
forgeLogger.level = 4;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
forgeLogger.level = 3;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
forgeLogger,
|
|
26
|
+
configureLogger
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=chunk-CNINN7IQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forge-logger.ts"],"sourcesContent":["/**\n * Forge-ts branded logger built on consola from the UnJS ecosystem.\n *\n * Provides a singleton logger instance (`forgeLogger`) and a configuration\n * function (`configureLogger`) that respects CLI flags (`--quiet`, `--json`,\n * `--verbose`) and TTY detection.\n *\n * @packageDocumentation\n * @internal\n */\n\nimport { createConsola } from \"consola\";\n\n// ---------------------------------------------------------------------------\n// Singleton logger\n// ---------------------------------------------------------------------------\n\n/**\n * Pre-configured consola instance branded for forge-ts.\n *\n * @example\n * ```typescript\n * import { forgeLogger } from \"./forge-logger.js\";\n * forgeLogger.info(\"Checking 42 files...\");\n * forgeLogger.success(\"All checks passed\");\n * forgeLogger.warn(\"Deprecated import detected\");\n * forgeLogger.error(\"Build failed\");\n * forgeLogger.debug(\"Resolved config from forge-ts.config.ts\");\n * ```\n * @internal\n */\nexport const forgeLogger = createConsola({\n\tdefaults: { tag: \"forge-ts\" },\n});\n\n// ---------------------------------------------------------------------------\n// Configuration\n// ---------------------------------------------------------------------------\n\n/**\n * Options for configuring the forge-ts logger at CLI startup.\n *\n * @internal\n */\nexport interface ForgeLoggerOptions {\n\t/** Suppress all consola output (--quiet flag). */\n\tquiet?: boolean;\n\t/** JSON output mode (--json flag). LAFS handles JSON; suppress consola. */\n\tjson?: boolean;\n\t/** Enable debug-level output (--verbose flag). */\n\tverbose?: boolean;\n}\n\n/**\n * Configures the global {@link forgeLogger} based on CLI flags.\n *\n * Call this once at the start of a command's `run()` handler to align\n * consola's output level with the user's intent:\n *\n * - `quiet` or `json` sets level to 0 (silent) so only LAFS output appears.\n * - `verbose` sets level to 4 (debug) for maximum detail.\n * - Default level is 3 (info) which covers info, warn, error, and success.\n *\n * @param options - Flag-driven configuration.\n *\n * @example\n * ```typescript\n * import { configureLogger, forgeLogger } from \"./forge-logger.js\";\n * configureLogger({ quiet: args.quiet, json: args.json, verbose: args.verbose });\n * forgeLogger.info(\"This respects the configured level\");\n * ```\n * @internal\n */\nexport function configureLogger(options: ForgeLoggerOptions): void {\n\tif (options.quiet) {\n\t\tforgeLogger.level = 0;\n\t\treturn;\n\t}\n\tif (options.json) {\n\t\t// LAFS handles JSON output — suppress consola's informal logging\n\t\tforgeLogger.level = 0;\n\t\treturn;\n\t}\n\tif (options.verbose) {\n\t\tforgeLogger.level = 4; // debug\n\t\treturn;\n\t}\n\t// Default: info level (covers info, warn, error, success)\n\tforgeLogger.level = 3;\n}\n"],"mappings":";;;AAWA,SAAS,qBAAqB;AAoBvB,IAAM,cAAc,cAAc;AAAA,EACxC,UAAU,EAAE,KAAK,WAAW;AAC7B,CAAC;AAwCM,SAAS,gBAAgB,SAAmC;AAClE,MAAI,QAAQ,OAAO;AAClB,gBAAY,QAAQ;AACpB;AAAA,EACD;AACA,MAAI,QAAQ,MAAM;AAEjB,gBAAY,QAAQ;AACpB;AAAA,EACD;AACA,MAAI,QAAQ,SAAS;AACpB,gBAAY,QAAQ;AACpB;AAAA,EACD;AAEA,cAAY,QAAQ;AACrB;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as citty from 'citty';
|
|
2
2
|
import { AuditEvent, BypassRecord } from '@forge-ts/core';
|
|
3
3
|
import { SSGTarget } from '@forge-ts/gen';
|
|
4
|
+
import * as consola from 'consola';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Central output layer for forge-ts CLI.
|
|
@@ -521,6 +522,63 @@ declare const checkCommand: citty.CommandDef<{
|
|
|
521
522
|
};
|
|
522
523
|
}>;
|
|
523
524
|
|
|
525
|
+
/**
|
|
526
|
+
* The `forge-ts docs dev` command — starts a local doc preview server.
|
|
527
|
+
*
|
|
528
|
+
* Reads the ssgTarget from forge-ts config, looks up the adapter,
|
|
529
|
+
* and spawns the correct dev server automatically.
|
|
530
|
+
*
|
|
531
|
+
* @packageDocumentation
|
|
532
|
+
* @public
|
|
533
|
+
*/
|
|
534
|
+
/**
|
|
535
|
+
* Starts the local dev server for the configured SSG target.
|
|
536
|
+
*
|
|
537
|
+
* Reads `gen.ssgTarget` from the forge-ts config, resolves the adapter,
|
|
538
|
+
* and spawns the platform's dev server in the output directory.
|
|
539
|
+
*
|
|
540
|
+
* @param args - Command arguments.
|
|
541
|
+
* @returns A promise that resolves when the server exits.
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```typescript
|
|
545
|
+
* import { runDocsDev } from "@forge-ts/cli";
|
|
546
|
+
* await runDocsDev({ cwd: "./my-project" });
|
|
547
|
+
* ```
|
|
548
|
+
* @public
|
|
549
|
+
*/
|
|
550
|
+
declare function runDocsDev(args: {
|
|
551
|
+
/** Project root directory. */
|
|
552
|
+
cwd?: string;
|
|
553
|
+
/** Override the SSG target from config. */
|
|
554
|
+
target?: string;
|
|
555
|
+
/** Port to run the dev server on. */
|
|
556
|
+
port?: string;
|
|
557
|
+
}): Promise<void>;
|
|
558
|
+
/**
|
|
559
|
+
* Citty command definition for `forge-ts docs dev`.
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```typescript
|
|
563
|
+
* import { docsDevCommand } from "@forge-ts/cli";
|
|
564
|
+
* ```
|
|
565
|
+
* @public
|
|
566
|
+
*/
|
|
567
|
+
declare const docsDevCommand: citty.CommandDef<{
|
|
568
|
+
readonly cwd: {
|
|
569
|
+
readonly type: "string";
|
|
570
|
+
readonly description: "Project root directory";
|
|
571
|
+
};
|
|
572
|
+
readonly target: {
|
|
573
|
+
readonly type: "string";
|
|
574
|
+
readonly description: "SSG target override (reads from config by default)";
|
|
575
|
+
};
|
|
576
|
+
readonly port: {
|
|
577
|
+
readonly type: "string";
|
|
578
|
+
readonly description: "Port for the dev server";
|
|
579
|
+
};
|
|
580
|
+
}>;
|
|
581
|
+
|
|
524
582
|
/**
|
|
525
583
|
* Status of a single doctor check.
|
|
526
584
|
* @public
|
|
@@ -584,8 +642,8 @@ interface DoctorArgs {
|
|
|
584
642
|
*
|
|
585
643
|
* Checks:
|
|
586
644
|
* 1. forge-ts.config.ts — exists and loadable
|
|
587
|
-
* 2. tsdoc.json — exists and extends @forge-ts/tsdoc-
|
|
588
|
-
* 3. @forge-ts/
|
|
645
|
+
* 2. tsdoc.json — exists and extends @forge-ts/core/tsdoc-preset
|
|
646
|
+
* 3. @forge-ts/core — installed in node_modules
|
|
589
647
|
* 4. TypeScript — installed
|
|
590
648
|
* 5. tsconfig.json — exists and has strict mode
|
|
591
649
|
* 6. biome.json — exists (informational)
|
|
@@ -649,63 +707,6 @@ declare const doctorCommand: citty.CommandDef<{
|
|
|
649
707
|
};
|
|
650
708
|
}>;
|
|
651
709
|
|
|
652
|
-
/**
|
|
653
|
-
* The `forge-ts docs dev` command — starts a local doc preview server.
|
|
654
|
-
*
|
|
655
|
-
* Reads the ssgTarget from forge-ts config, looks up the adapter,
|
|
656
|
-
* and spawns the correct dev server automatically.
|
|
657
|
-
*
|
|
658
|
-
* @packageDocumentation
|
|
659
|
-
* @public
|
|
660
|
-
*/
|
|
661
|
-
/**
|
|
662
|
-
* Starts the local dev server for the configured SSG target.
|
|
663
|
-
*
|
|
664
|
-
* Reads `gen.ssgTarget` from the forge-ts config, resolves the adapter,
|
|
665
|
-
* and spawns the platform's dev server in the output directory.
|
|
666
|
-
*
|
|
667
|
-
* @param args - Command arguments.
|
|
668
|
-
* @returns A promise that resolves when the server exits.
|
|
669
|
-
*
|
|
670
|
-
* @example
|
|
671
|
-
* ```typescript
|
|
672
|
-
* import { runDocsDev } from "@forge-ts/cli";
|
|
673
|
-
* await runDocsDev({ cwd: "./my-project" });
|
|
674
|
-
* ```
|
|
675
|
-
* @public
|
|
676
|
-
*/
|
|
677
|
-
declare function runDocsDev(args: {
|
|
678
|
-
/** Project root directory. */
|
|
679
|
-
cwd?: string;
|
|
680
|
-
/** Override the SSG target from config. */
|
|
681
|
-
target?: string;
|
|
682
|
-
/** Port to run the dev server on. */
|
|
683
|
-
port?: string;
|
|
684
|
-
}): Promise<void>;
|
|
685
|
-
/**
|
|
686
|
-
* Citty command definition for `forge-ts docs dev`.
|
|
687
|
-
*
|
|
688
|
-
* @example
|
|
689
|
-
* ```typescript
|
|
690
|
-
* import { docsDevCommand } from "@forge-ts/cli";
|
|
691
|
-
* ```
|
|
692
|
-
* @public
|
|
693
|
-
*/
|
|
694
|
-
declare const docsDevCommand: citty.CommandDef<{
|
|
695
|
-
readonly cwd: {
|
|
696
|
-
readonly type: "string";
|
|
697
|
-
readonly description: "Project root directory";
|
|
698
|
-
};
|
|
699
|
-
readonly target: {
|
|
700
|
-
readonly type: "string";
|
|
701
|
-
readonly description: "SSG target override (reads from config by default)";
|
|
702
|
-
};
|
|
703
|
-
readonly port: {
|
|
704
|
-
readonly type: "string";
|
|
705
|
-
readonly description: "Port for the dev server";
|
|
706
|
-
};
|
|
707
|
-
}>;
|
|
708
|
-
|
|
709
710
|
/**
|
|
710
711
|
* Result of the `init docs` command.
|
|
711
712
|
*
|
|
@@ -939,6 +940,8 @@ interface InitProjectResult {
|
|
|
939
940
|
environment: InitProjectEnvironment;
|
|
940
941
|
/** Next steps for the user. */
|
|
941
942
|
nextSteps: string[];
|
|
943
|
+
/** Scripts that were added to package.json (empty if none were added). */
|
|
944
|
+
scriptsAdded: string[];
|
|
942
945
|
}
|
|
943
946
|
/**
|
|
944
947
|
* Arguments for the `init` (project setup) command.
|
|
@@ -957,9 +960,10 @@ interface InitProjectArgs {
|
|
|
957
960
|
* 1. Detect project environment
|
|
958
961
|
* 2. Write forge-ts.config.ts (if not exists)
|
|
959
962
|
* 3. Write tsdoc.json (if not exists)
|
|
960
|
-
* 4.
|
|
961
|
-
* 5. Validate
|
|
962
|
-
* 6.
|
|
963
|
+
* 4. Wire package.json scripts (idempotent)
|
|
964
|
+
* 5. Validate tsconfig.json strictness
|
|
965
|
+
* 6. Validate package.json
|
|
966
|
+
* 7. Report summary
|
|
963
967
|
*
|
|
964
968
|
* @param args - CLI arguments for the init command.
|
|
965
969
|
* @returns A typed `CommandOutput<InitProjectResult>`.
|
|
@@ -1332,45 +1336,63 @@ declare const unlockCommand: citty.CommandDef<{
|
|
|
1332
1336
|
}>;
|
|
1333
1337
|
|
|
1334
1338
|
/**
|
|
1335
|
-
*
|
|
1339
|
+
* Forge-ts branded logger built on consola from the UnJS ecosystem.
|
|
1336
1340
|
*
|
|
1337
|
-
*
|
|
1341
|
+
* Provides a singleton logger instance (`forgeLogger`) and a configuration
|
|
1342
|
+
* function (`configureLogger`) that respects CLI flags (`--quiet`, `--json`,
|
|
1343
|
+
* `--verbose`) and TTY detection.
|
|
1338
1344
|
*
|
|
1339
1345
|
* @packageDocumentation
|
|
1340
1346
|
* @internal
|
|
1341
1347
|
*/
|
|
1342
1348
|
/**
|
|
1343
|
-
*
|
|
1349
|
+
* Pre-configured consola instance branded for forge-ts.
|
|
1350
|
+
*
|
|
1351
|
+
* @example
|
|
1352
|
+
* ```typescript
|
|
1353
|
+
* import { forgeLogger } from "./forge-logger.js";
|
|
1354
|
+
* forgeLogger.info("Checking 42 files...");
|
|
1355
|
+
* forgeLogger.success("All checks passed");
|
|
1356
|
+
* forgeLogger.warn("Deprecated import detected");
|
|
1357
|
+
* forgeLogger.error("Build failed");
|
|
1358
|
+
* forgeLogger.debug("Resolved config from forge-ts.config.ts");
|
|
1359
|
+
* ```
|
|
1360
|
+
* @internal
|
|
1361
|
+
*/
|
|
1362
|
+
declare const forgeLogger: consola.ConsolaInstance;
|
|
1363
|
+
/**
|
|
1364
|
+
* Options for configuring the forge-ts logger at CLI startup.
|
|
1365
|
+
*
|
|
1344
1366
|
* @internal
|
|
1345
1367
|
*/
|
|
1346
|
-
interface
|
|
1347
|
-
/**
|
|
1348
|
-
|
|
1349
|
-
/**
|
|
1350
|
-
|
|
1351
|
-
/**
|
|
1352
|
-
|
|
1353
|
-
/** Print an error message (red ✗ prefix when colours are on). */
|
|
1354
|
-
error(msg: string): void;
|
|
1355
|
-
/**
|
|
1356
|
-
* Print a build-step line.
|
|
1357
|
-
*
|
|
1358
|
-
* @param label - Short category label (e.g. "API", "Gen").
|
|
1359
|
-
* @param detail - Description of what was produced.
|
|
1360
|
-
* @param duration - Optional wall-clock time in milliseconds.
|
|
1361
|
-
*/
|
|
1362
|
-
step(label: string, detail: string, duration?: number): void;
|
|
1368
|
+
interface ForgeLoggerOptions {
|
|
1369
|
+
/** Suppress all consola output (--quiet flag). */
|
|
1370
|
+
quiet?: boolean;
|
|
1371
|
+
/** JSON output mode (--json flag). LAFS handles JSON; suppress consola. */
|
|
1372
|
+
json?: boolean;
|
|
1373
|
+
/** Enable debug-level output (--verbose flag). */
|
|
1374
|
+
verbose?: boolean;
|
|
1363
1375
|
}
|
|
1364
1376
|
/**
|
|
1365
|
-
*
|
|
1377
|
+
* Configures the global {@link forgeLogger} based on CLI flags.
|
|
1378
|
+
*
|
|
1379
|
+
* Call this once at the start of a command's `run()` handler to align
|
|
1380
|
+
* consola's output level with the user's intent:
|
|
1381
|
+
*
|
|
1382
|
+
* - `quiet` or `json` sets level to 0 (silent) so only LAFS output appears.
|
|
1383
|
+
* - `verbose` sets level to 4 (debug) for maximum detail.
|
|
1384
|
+
* - Default level is 3 (info) which covers info, warn, error, and success.
|
|
1366
1385
|
*
|
|
1367
|
-
* @param options -
|
|
1368
|
-
*
|
|
1369
|
-
* @
|
|
1386
|
+
* @param options - Flag-driven configuration.
|
|
1387
|
+
*
|
|
1388
|
+
* @example
|
|
1389
|
+
* ```typescript
|
|
1390
|
+
* import { configureLogger, forgeLogger } from "./forge-logger.js";
|
|
1391
|
+
* configureLogger({ quiet: args.quiet, json: args.json, verbose: args.verbose });
|
|
1392
|
+
* forgeLogger.info("This respects the configured level");
|
|
1393
|
+
* ```
|
|
1370
1394
|
* @internal
|
|
1371
1395
|
*/
|
|
1372
|
-
declare function
|
|
1373
|
-
colors?: boolean;
|
|
1374
|
-
}): Logger;
|
|
1396
|
+
declare function configureLogger(options: ForgeLoggerOptions): void;
|
|
1375
1397
|
|
|
1376
|
-
export { type AuditResult, type BuildResult, type BuildStep, type BypassCreateResult, type BypassStatusResult, type CheckFileError, type CheckFileGroup, type CheckFileWarning, type CheckPage, type CheckResult, type CheckRuleCount, type CheckTriage, type CommandOutput, type DoctorCheckResult, type DoctorCheckStatus, type DoctorResult, type ForgeCliError, type ForgeCliWarning, type HookManager, type InitDocsResult, type InitHooksResult, type InitProjectEnvironment, type InitProjectResult, type LockResult, type
|
|
1398
|
+
export { type AuditResult, type BuildResult, type BuildStep, type BypassCreateResult, type BypassStatusResult, type CheckFileError, type CheckFileGroup, type CheckFileWarning, type CheckPage, type CheckResult, type CheckRuleCount, type CheckTriage, type CommandOutput, type DoctorCheckResult, type DoctorCheckStatus, type DoctorResult, type ForgeCliError, type ForgeCliWarning, type ForgeLoggerOptions, type HookManager, type InitDocsResult, type InitHooksResult, type InitProjectEnvironment, type InitProjectResult, type LockResult, type OutputFlags, type PrepublishResult, type TestFailure, type TestResult, type UnlockResult, auditCommand, buildCommand, bypassCommand, checkCommand, configureLogger, docsDevCommand, doctorCommand, emitResult, forgeLogger, initDocsCommand, initHooksCommand, initProjectCommand, lockCommand, prepublishCommand, resolveExitCode, runBypassCreate, runBypassStatus, runDocsDev, runDoctor, runInitHooks, runInitProject, runLock, runPrepublish, runUnlock, testCommand, unlockCommand };
|