API reference·skills/ignifx/references/api/cli.md
@ignifx/cli
@ignifx/cli public barrel. Explicit named re-exports only — no export *
(coding standards §4).
Remarks#
The create-ignifx executable is src/bin.ts; it is not part of this barrel because it is a
process entry point, not a library API.
Classes#
CliError#
The error type every @ignifx/cli API throws for misuse (CONSTITUTION.md §3.9). It always
carries a stable IGX-#### code so the process boundary can report a machine-readable failure.
Example#
try { await copyTemplate({ templateDir, targetDir });} catch (error) { if (error instanceof CliError && error.code === "IGX-1401") { console.error("pass --overwrite to write into a non-empty directory"); }}Extends#
Error
Constructors#
Constructor#
new CliError(
code,message,options?):CliError
Creates a CLI error.
Parameters#
code#
The stable IGX-14## code for the failure.
message#
string
An actionable description of what went wrong and how to fix it.
options?#
ErrorOptions
Standard Error options; use cause to keep the original failure.
Returns#
Overrides#
Error.constructor
Properties#
cause?#
optionalcause?:unknown
Inherited from#
Error.cause
code#
readonlycode:CliErrorCode
The stable diagnostic code for this failure.
message#
message:
string
Inherited from#
Error.message
name#
name:
string
Inherited from#
Error.name
stack?#
optionalstack?:string
Inherited from#
Error.stack
stackTraceLimit#
staticstackTraceLimit:number
The Error.stackTraceLimit property specifies the number of stack frames
collected by a stack trace (whether generated by new Error().stack or
Error.captureStackTrace(obj)).
The default value is 10 but may be set to any valid JavaScript number. Changes
will affect any stack trace captured after the value has been changed.
If set to a non-number value, or set to a negative number, stack traces will not capture any frames.
Inherited from#
Error.stackTraceLimit
Methods#
captureStackTrace()#
staticcaptureStackTrace(targetObject,constructorOpt?):void
Creates a .stack property on targetObject, which when accessed returns
a string representing the location in the code at which
Error.captureStackTrace() was called.
const myObject = {};Error.captureStackTrace(myObject);myObject.stack; // Similar to `new Error().stack`The first line of the trace will be prefixed with
${myObject.name}: ${myObject.message}.
The optional constructorOpt argument accepts a function. If given, all frames
above constructorOpt, including constructorOpt, will be omitted from the
generated stack trace.
The constructorOpt argument is useful for hiding implementation
details of error generation from the user. For instance:
function a() { b();}function b() { c();}function c() { // Create an error without stack trace to avoid calculating the stack trace twice. const { stackTraceLimit } = Error; Error.stackTraceLimit = 0; const error = new Error(); Error.stackTraceLimit = stackTraceLimit; // Capture the stack trace above function b Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace throw error;}a();Parameters#
targetObject#
object
constructorOpt?#
Function
Returns#
void
Inherited from#
Error.captureStackTrace
prepareStackTrace()#
staticprepareStackTrace(err,stackTraces):any
Parameters#
err#
Error
stackTraces#
CallSite[]
Returns#
any
See#
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
Inherited from#
Error.prepareStackTrace
Interfaces#
CopyTemplateOptions#
Options for copyTemplate.
Properties#
dependencyRange?#
readonlyoptionaldependencyRange?:string|null
The range that replaces a workspace: dependency specifier in the copied package.json.
Remarks#
workspace:* and workspace:^ become ^<range>; workspace:~ becomes ~<range>; any other
workspace:<something> keeps whatever followed the colon, which is what pnpm itself does when
it publishes. Pass null to copy package.json byte for byte.
Default Value#
desktop?#
readonlyoptionaldesktop?:boolean
Whether the template's desktop variant is copied.
Remarks#
false skips DESKTOP_ONLY_ENTRIES and strips the desktop scripts and dependencies from
the copied package.json; true copies the template whole. This is what --desktop sets.
Default Value#
false
ignore?#
readonlyoptionalignore?: readonlystring[]
Entry names that are skipped, together with everything below them.
Default Value#
overwrite?#
readonlyoptionaloverwrite?:boolean
Whether to write into a target directory that already contains entries.
Default Value#
false — an existing, non-empty target throws IGX-1401 instead.
projectName?#
readonlyoptionalprojectName?:string|null
The name written into the copied package.json. Defaults to the target directory's base
name, lower-cased, with any run of characters outside a-z0-9._- replaced by -; null keeps
the template's own name.
rename?#
readonlyoptionalrename?:Readonly<Record<string,string>>
Map of source file name to the name it is written under, applied to every entry at every depth.
Default Value#
signal?#
readonlyoptionalsignal?:AbortSignal
Signal that cancels the copy (coding standards §8). An already-aborted signal rejects with the signal's reason before anything is written.
Default Value#
no signal — the copy runs to completion.targetDir#
readonlytargetDir:string
Absolute or relative path of the directory to write into; created if it does not exist.
templateDir#
readonlytemplateDir:string
Absolute or relative path of the template directory to read from.
CopyTemplateResult#
What copyTemplate wrote.
Properties#
files#
readonlyfiles: readonlystring[]
Paths of the files written, relative to targetDir, /-separated on every platform and
sorted lexicographically. Directories are not listed.
CreateCommand#
A parsed create-ignifx invocation.
Properties#
desktop#
readonlydesktop:boolean
Whether --desktop was given, which copies the template's Electron variant
(docs/architecture/14-platform-electron.md §3).
overwrite#
readonlyoverwrite:boolean
Whether --overwrite was given, allowing a non-empty target directory.
targetDir#
readonlytargetDir:string
Directory the project is scaffolded into, exactly as the user typed it.
template#
readonlytemplate:string
Template name to copy; DEFAULT_TEMPLATE when --template was not given.
CreateIo#
The side-effecting surface runCreate is allowed to touch.
Remarks#
Everything the command needs from the outside world is injected, so runCreate never reads
process and unit tests never spawn one (CONSTITUTION.md §3.6). Only src/bin.ts builds an
implementation backed by the real process.
Properties#
stderr#
readonlystderr: (line) =>void
Writes one line of diagnostic output. Used by the process boundary to report a failure.
Parameters#
line#
string
The line to write, without a trailing newline.
Returns#
void
stdout#
readonlystdout: (line) =>void
Writes one line of progress output.
Parameters#
line#
string
The line to write, without a trailing newline.
Returns#
void
templatesRoot#
readonlytemplatesRoot:string
Directory that holds one subdirectory per template.
Type Aliases#
CliErrorCode#
CliErrorCode = typeof
CliErrorCode[keyof typeofCliErrorCode]
The union of the error codes this package can throw.
Variables#
CliErrorCode#
constCliErrorCode:object
Error codes owned by @ignifx/cli. They live in the 14xx platform range reserved by
docs/architecture/15-devtools-and-diagnostics.md §1.
Type Declaration#
invalidArguments#
readonlyinvalidArguments:"IGX-1403"="IGX-1403"
The command line could not be parsed, or an argument is not usable.
targetNotEmpty#
readonlytargetNotEmpty:"IGX-1401"="IGX-1401"
The target directory already exists and is not empty, and overwrite was not requested.
templateNotFound#
readonlytemplateNotFound:"IGX-1402"="IGX-1402"
The requested template directory does not exist.
Remarks#
The CLI runs before an App exists, so it cannot throw core's IgnifxError. Phase 1 introduces
the full IgnifxError registry described in that document; when it lands, these codes are
expected to fold into it and CliError becomes a thin alias or is removed.
DEFAULT_DEPENDENCY_RANGE#
constDEFAULT_DEPENDENCY_RANGE:string
The version a scaffolded project's @ignifx/* dependencies are pinned to.
Remarks#
A template inside this repository declares "@ignifx/core": "workspace:*", which is pnpm's
workspace protocol: it means "whatever the checkout has" and is meaningless outside a workspace.
A generated project has to name a published range instead, and because the whole @ignifx scope
ships one version line (docs/architecture/00-overview.md §2) that range is this package's own
version.
DEFAULT_IGNORED_ENTRIES#
constDEFAULT_IGNORED_ENTRIES: readonlystring[]
Directory and file names copyTemplate skips by default: build and tooling output that a
template checkout may contain locally but that must never reach a generated project.
DEFAULT_TEMPLATE#
constDEFAULT_TEMPLATE:"2d-topdown"="2d-topdown"
The template used when --template is not given.
DEFAULT_TEMPLATE_RENAMES#
constDEFAULT_TEMPLATE_RENAMES:Readonly<Record<string,string>>
File names that copyTemplate rewrites by default.
Remarks#
npm refuses to publish a .gitignore inside a package and rewrites a nested package.json
during packing, so template files that must arrive under those names are stored with an
underscore prefix and restored on copy. This is the convention used by every scaffolder that
ships its templates inside an npm package.
DESKTOP_ONLY_DEPENDENCIES#
constDESKTOP_ONLY_DEPENDENCIES: readonlystring[]
The devDependencies a template declares only for its desktop variant, removed from a
browser-only scaffold.
Remarks#
@ignifx/electron is deliberately not on this list. A template's src/main.ts registers
electron() unconditionally — the extension is inert without a preload bridge, which is what
gives one renderer bundle both builds — so removing the package would break the browser scaffold
it was meant to slim down. What is removed is the three build tools, which are large binary
downloads a browser game never runs.
DESKTOP_ONLY_ENTRIES#
constDESKTOP_ONLY_ENTRIES: readonlystring[]
Entries that belong to a template's desktop variant and are skipped unless the scaffold asked
for one (docs/architecture/14-platform-electron.md §3).
Remarks#
A browser-only project should not carry them, and not only for tidiness: electron and
electron-builder are large binary downloads that a browser game never runs, and an
electron.vite.config.ts in a project with no desktop/ directory is a config that names files
that are not there.
DESKTOP_SCRIPT_SUFFIX#
constDESKTOP_SCRIPT_SUFFIX:":desktop"=":desktop"
The suffix marking a package.json script that belongs to the desktop variant.
TEMPLATE_ROOT_CANDIDATES#
constTEMPLATE_ROOT_CANDIDATES: readonlystring[]
Where create-ignifx looks for its templates, in order.
Remarks#
Both entries are relative to the directory holding the running bin.js.
../templatesis the published layout:prepackcopiestemplates/*into the package, so the tarball ships<package>/dist/bin.jsbeside<package>/templates/<name>.../../../templatesis the development layout:packages/cli/dist/bin.jssits three directories below the repository root, where the realtemplates/workspace members live. It is what makesnode packages/cli/dist/bin.js my-gamework from a checkout, without a pack.
USAGE#
constUSAGE:"Usage: create-ignifx <target-dir> [--template <name>] [--overwrite] [--desktop]"="Usage: create-ignifx <target-dir> [--template <name>] [--overwrite] [--desktop]"
The one-line usage string printed with every argument error.
VERSION#
constVERSION:"0.0.0"="0.0.0"
The @ignifx/cli version this build was cut from. It is also the version a scaffolded project's
@ignifx/* dependencies are pinned to, because the scope is released as one line
(docs/architecture/00-overview.md §2).
Functions#
copyTemplate()#
copyTemplate(
options):Promise<CopyTemplateResult>
Copies a template directory recursively into a target directory.
Parameters#
options#
Source, destination, and the documented defaults in CopyTemplateOptions.
Returns#
Promise<CopyTemplateResult>
The relative paths of the files written, sorted.
Remarks#
The template tree is copied verbatim apart from four things: the rename map, the ignore
list, package.json — whose workspace: dependency specifiers are rewritten to
dependencyRange so that the generated project installs from the registry — and the desktop
variant, which is skipped unless desktop is true. Symbolic links are followed and written as
regular files, which is what a scaffolded project wants.
Throws#
A CliError with code IGX-1402 when templateDir is not an existing directory,
or IGX-1401 when targetDir already holds entries and overwrite was not requested.
Example#
const result = await copyTemplate({ templateDir: "/path/to/templates/2d-topdown", targetDir: "./my-game",});console.log(`${String(result.files.length)} files written`);parseArgs()#
parseArgs(
argv):CreateCommand
Parses a create-ignifx command line.
Parameters#
argv#
readonly string[]
Arguments after the executable and script name, as process.argv.slice(2) gives them.
Returns#
The parsed command with defaults applied.
Remarks#
--desktop copies the template's Electron variant — its desktop/ directory,
electron.vite.config.ts, electron-builder.yml, and the *:desktop scripts and dependencies
that go with them. Without it the scaffold is browser-only, which is what keeps a browser game
from downloading an Electron binary it never runs.
Throws#
A CliError with code IGX-1403 when the command line is unparseable, the target
directory is missing, or extra positionals are given.
Example#
const command = parseArgs(["my-game", "--template", "3d-first-person", "--desktop"]);// { targetDir: "my-game", template: "3d-first-person", overwrite: false, desktop: true }resolveTemplateDir()#
resolveTemplateDir(
name,templatesRoot):Promise<string>
Maps a template name to its directory under templatesRoot.
Parameters#
name#
string
Template name, a single path segment such as "2d-topdown".
templatesRoot#
string
Directory that holds one subdirectory per template.
Returns#
Promise<string>
The absolute or relative path of the template directory, which is known to exist.
Throws#
A CliError with code IGX-1402 when name is not a single path segment or no
such directory exists.
resolveTemplatesRoot()#
resolveTemplatesRoot(
binDirectory):Promise<string>
Finds the directory that holds the templates.
Parameters#
binDirectory#
string
The directory of the running executable, normally import.meta.dirname.
Returns#
Promise<string>
The first of TEMPLATE_ROOT_CANDIDATES that exists as a directory; the first candidate when none does, so the failure names the published location rather than the checkout.
Example#
const templatesRoot = await resolveTemplatesRoot(import.meta.dirname);runCreate()#
runCreate(
argv,io):Promise<CopyTemplateResult>
Parses a command line, resolves the template, and copies it into the target directory.
Parameters#
argv#
readonly string[]
Arguments after the executable and script name.
io#
The injected output sinks and templates root.
Returns#
Promise<CopyTemplateResult>
The files written, relative to the target directory.
Throws#
A CliError for every expected failure; see parseArgs, resolveTemplateDir, and copyTemplate.
Example#
await runCreate(["my-game"], { stdout: (line) => lines.push(line), stderr: (line) => lines.push(line), templatesRoot: "/path/to/templates",});