@lakutata/cli 3.0.0 → 3.1.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 CHANGED
@@ -1,5 +1,7 @@
1
1
  # @lakutata/cli
2
2
 
3
+ English | [中文](README.zh-CN.md)
4
+
3
5
  The command line tool of the [lakutata](https://github.com/lakutata/lakutata) framework.
4
6
 
5
7
  ```bash
@@ -12,159 +14,190 @@ lakutata create --name my-app
12
14
 
13
15
  ### `lakutata create`
14
16
 
15
- Create a project from a template. The options are given on the command line; in a terminal, the missing ones are asked,
16
- and the project is created once it is confirmed (`--yes` skips the confirmation).
17
+ Create a project from a template. The options are given on the command line. In a terminal, the tool asks for the
18
+ name when it is missing, offers the features of the template, and creates the project once you confirm (`--yes` skips
19
+ both the features and the confirmation).
17
20
 
18
21
  | Option | |
19
22
  |---|---|
20
23
  | `--name <name>` | the name of the application (required) |
21
- | `--id <id>` | the ID of the application (a package name), its name in lower case by default |
22
- | `--template <template>` | the template, `default` by default: an official template (`lakutata templates` lists them), `npm:<package>[@<version>]`, `github:<owner>/<repo>[#<ref>]` or a directory |
23
- | `--path <directory>` | the directory the project directory is created in, the current one by default |
24
- | `--init` | create the project in the directory itself (it may exist and not be empty) |
25
- | `--description`, `--author`, `--license` | the information of the application |
26
- | `--with <features>` | the optional features of the template enabled, separated by commas (`lakutata templates` lists them): `i18n`. In a terminal without `--with`, they are chosen |
27
- | `--package-manager <npm\|pnpm\|yarn\|none>` | the package manager installing the dependencies, the one running the tool by default |
24
+ | `--id <id>` | the ID of the application (a package name), by default its name in lower case |
25
+ | `--template <template>` | the template (`default` when it is not given): an official template (listed by `lakutata templates`), `npm:<package>[@<version>]`, `github:<owner>/<repo>[#<ref>]` or a directory |
26
+ | `--path <directory>` | the directory in which the project directory is created, by default the current one |
27
+ | `--init` | create the project in the `--path` directory itself, which must exist and may hold files: the files it already has are kept (a warning lists those that the template also has, to merge by hand), and only the files the tool writes are filled with the information of the project |
28
+ | `--description`, `--author`, `--license` | information about the application |
29
+ | `--with <features>` | the optional features of the template to enable, separated by commas (listed by `lakutata templates`): `i18n`, `installer`. In a terminal, without `--with` or `--yes`, you choose them from a list |
30
+ | `--package-manager <npm\|pnpm\|yarn\|none>` | the package manager that installs the dependencies (`none` installs nothing): npm by default, or pnpm or yarn when one of them started the tool |
28
31
  | `--no-git` | do not initialize a git repository |
29
- | `--yes` | create the project without confirmation |
32
+ | `--yes` | create the project without asking for the features or for a confirmation |
30
33
 
31
34
  ```bash
32
35
  lakutata create --name my-service --template service --package-manager pnpm --yes
33
36
  lakutata create --name my-service --template service --with i18n --yes
34
37
  ```
35
38
 
36
- The official templates have the feature `i18n`: the messages of the application in several languages
37
- (`lakutata/com/i18n`), in `src/locales` (`en.json`, `zh-CN.json`), bundled with the code; each request answered in its
38
- language (the language of the environment for the command line tools and the Electron applications), its validation
39
- errors too; the scripts `i18n:check` and `i18n:types`.
39
+ Every official template has the `i18n` feature: the messages of the application in several languages
40
+ (`lakutata/com/i18n`), in `src/locales` (`en.json`, `zh-CN.json`) and bundled with the code. Each request is answered in
41
+ its own language, including its validation errors (command line tools and Electron applications use the language of the
42
+ environment). The feature also adds the `i18n:check` and `i18n:types` scripts. The `cli`, `service` and `web-*`
43
+ templates also have the `installer` feature: the `lakutata.installer` configuration of the application and the scripts
44
+ that make its installers (on the machine, and for Linux in Docker), and, in the `service` and `web-*` templates, a
45
+ system service.
40
46
 
41
47
  ### `lakutata templates`
42
48
 
43
- List the official templates. They are npm packages (`@lakutata/template-<name>`) listed by the catalog package
44
- `@lakutata/templates`, downloaded from the npm registry of the user (a mirror such as npmmirror works as it does for the
45
- dependencies): no access to GitHub is needed. The catalog is kept for a day (`--refresh` fetches it again).
49
+ List the official templates. They are npm packages (`@lakutata/template-<name>`), listed by the catalog package
50
+ `@lakutata/templates` and downloaded from the user's npm registry (a mirror such as npmmirror works, as it does for the
51
+ dependencies), so no access to GitHub is needed. The catalog is cached for a day (`--refresh` fetches it again).
46
52
 
47
- The version of an official template is the newest one of the major version of the tool. The downloaded templates are
48
- kept: when the registry cannot be reached, the kept ones are used.
53
+ The tool uses the newest release of an official template within its own major version. Downloaded templates are
54
+ cached: when the registry cannot be reached, the newest cached release of that major version is used, and without one
55
+ the command fails.
49
56
 
50
- A template package has its files in its `template/` directory. The npm packages cannot hold some files under their
51
- name: `_gitignore`, `_npmrc`… are renamed `.gitignore`, `.npmrc`… when the project is created. The text files are filled
52
- with the information of the project: `{$APP_NAME}`, `{$APP_ID}`, `{$APP_DESC}`, `{$APP_AUTHOR}`, `{$APP_LICENSE}` and
53
- `{$LAKUTATA_VERSION}` (the version of the framework).
57
+ A template package keeps its files in its `template/` directory. npm packages cannot hold some files under their real
58
+ names, so `_gitignore`, `_npmrc`… are renamed `.gitignore`, `.npmrc`… when the project is created. The text files are
59
+ filled with the information of the project: `{$APP_NAME}`, `{$APP_ID}`, `{$APP_DESC}`, `{$APP_AUTHOR}`,
60
+ `{$APP_LICENSE}` and `{$LAKUTATA_VERSION}` (the version of the framework).
54
61
 
55
- A template has optional features, which `lakutata create --with <features>` enables (or the user chooses in a terminal):
62
+ A template can have optional features, which `lakutata create --with <features>` enables (or which the user chooses in
63
+ a terminal):
56
64
 
57
- - they are declared by the `package.json` of the template package, their names and their descriptions:
65
+ - the `package.json` of the template package declares them, with their names and descriptions:
58
66
  `"lakutata": {"template": "default", "features": {"i18n": "The messages in several languages"}}`;
59
- - the files of a feature are in `features/<name>/`, beside `template/` (published with it, in the `files` of the
60
- package): they are added to the project when the feature is enabled; a JSON file the project has is merged into its
61
- one (the scripts of `package.json`, the options of `tsconfig.json`);
62
- - the files of the template have the blocks of the features, the lines between `//@if <feature>` and `//@end` (or
63
- `//@else`; `//@if !<feature>` when the feature is not enabled), kept when the feature is enabled and removed
64
- otherwise; the lines of the markers are removed. The markers are comments of their languages: `//@if i18n`,
65
- `#@if i18n`, `<!--@if i18n-->`, `/*@if i18n*/`.
67
+ - the files of a feature are in `features/<name>/`, beside `template/` (and published with it, in the `files` of the
68
+ package). They are added to the project when the feature is enabled: a JSON file that the project already has is
69
+ merged into it (its objects merged by key, such as the scripts of `package.json` and the options of `tsconfig.json`,
70
+ and its arrays replaced), and any other file replaces the one of the template;
71
+ - the files of the template can hold blocks for a feature: the lines between `//@if <feature>` and `//@end` (or
72
+ `//@else`; `//@if !<feature>` for when the feature is not enabled) are kept when the feature is enabled and removed
73
+ otherwise, and the marker lines are always removed. The markers are written as comments of the file's language:
74
+ `//@if i18n`, `#@if i18n`, `<!--@if i18n-->`, `/*@if i18n*/`.
66
75
 
67
76
  ### `lakutata info`
68
77
 
69
- Show the versions of the tool, of the framework (and their latest versions), of Node.js, and of the framework of the
70
- project of the current directory.
78
+ Show the versions of the tool and of the framework (with their latest versions), of Node.js, and the version of the
79
+ framework that the project in the current directory uses.
71
80
 
72
81
  ### `lakutata clean [paths...]`
73
82
 
74
- Remove paths of the package of the current directory, on every platform (as `rm -rf`, without `shx` or `rimraf`):
75
- `lakutata clean build dist`. Without paths, the output directories of its `tsconfig.json` are removed (`outDir`, and
76
- `declarationDir` when it has one, read through the configurations it extends): `"clean": "lakutata clean"`. A missing
77
- path is skipped; the paths outside of the package, the package itself, `src`, `node_modules`, `.git` and `package.json`
78
- are never removed. In a workspace, `lakutata run clean` runs the `clean` script of each package.
83
+ Remove paths of the package in the current directory, on every platform (like `rm -rf`, without `shx` or `rimraf`):
84
+ `lakutata clean build dist`. Without paths, it removes the output directories of its `tsconfig.json` (`outDir`, and
85
+ `declarationDir` when there is one, following the configurations it extends): `"clean": "lakutata clean"`. A missing
86
+ path is skipped. Paths outside the package, the package itself, `src`, `node_modules`, `.git` and `package.json` are
87
+ never removed. In a workspace, `lakutata run clean` runs the `clean` script of each package.
79
88
 
80
89
  ## Workspaces
81
90
 
82
- The projects made of several packages (`app`, `ui`, `proxy`…) are npm workspaces (the `workspaces` of the root
83
- `package.json`, or a `pnpm-workspace.yaml`). The tool builds and versions their packages; it is the part of lerna the
84
- projects use, without lerna.
91
+ Projects made of several packages (`app`, `ui`, `proxy`…) are npm workspaces. The workspace of a directory is the
92
+ nearest one, from that directory up, whose `package.json` has a `workspaces` field (a list of patterns, or
93
+ `{"packages": [...]}`), or whose `package.json` is next to a `pnpm-workspace.yaml` (its `packages:` list). The patterns
94
+ match directories (`*` within one name, `**` any number of directories, `!` leaves one out), and the ones holding a
95
+ `package.json` with a name are the packages. The tool builds and versions their packages: it covers the part of lerna
96
+ that these projects use, without lerna.
85
97
 
86
98
  ### `lakutata run <script>`
87
99
 
88
- Run a script in the packages having it, in the order of their dependencies (a package runs once the packages it depends
89
- on ran); the packages independent of each other run at the same time. The output is prefixed by the name of the package.
100
+ Run a script in every package that has it, in the order of their dependencies (in `dependencies`, `devDependencies`,
101
+ `peerDependencies` and `optionalDependencies`): a package starts once the packages it depends on, directly or not, have
102
+ finished, and packages that do not depend on each other run at the same time. The scripts run with the package manager
103
+ of the project: the `packageManager` field of the root `package.json`, else the files at the root (`pnpm-lock.yaml` or
104
+ `pnpm-workspace.yaml` for pnpm, `yarn.lock`, `package-lock.json`); npm by default. Each line of output starts with the
105
+ name of its package. The scripts take no extra arguments. When no package has the script, the command says so and
106
+ succeeds.
90
107
 
91
108
  | Option | |
92
109
  |---|---|
93
- | `--concurrency <n>` | how many packages run at a time, the number of the processors by default |
94
- | `--parallel` | run all the packages at once, without waiting for their dependencies: the long-running scripts (`lakutata run dev --parallel`) |
95
- | `--no-bail` | do not stop at the first failure: the packages which do not depend on the failed ones run |
96
- | `--scope <names...>` | the packages run, by name (`*` wildcards) |
110
+ | `--concurrency <n>` | how many packages run at a time, by default the number of processors |
111
+ | `--parallel` | run all the packages at once, without waiting for their dependencies: for scripts that keep running (`lakutata run dev --parallel`) |
112
+ | `--no-bail` | go on after a failure: the packages that do not depend on a failed one still run (by default, no package starts after the first failure, and the ones running finish) |
113
+ | `--scope <names...>` | only the packages with these names (`*` is a wildcard); the packages they depend on are neither run nor waited for, and a scope matching no package is an error |
97
114
 
98
115
  ### `lakutata version <bump>`
99
116
 
100
- Give all the packages the next version (`major`, `minor`, `patch`, `premajor`, `preminor`, `prepatch`, `prerelease`
101
- with `--preid <id>`, or a version), update the dependencies between them (`^0.0.16` becomes `^0.0.17`: with the `0.x`
102
- versions a range matches its version only) and the lock file (`npm ci` fails otherwise). The version of the workspace is
103
- the one of `lerna.json` when there is one, of the root `package.json` otherwise. `--git` commits the changes and tags
104
- them `v<version>`; `--yes` gives the version without confirmation.
117
+ Give every package the next version (`major`, `minor`, `patch`, `premajor`, `preminor`, `prepatch`, `prerelease`, or a
118
+ version; `--preid <id>` names the prerelease of the `pre…` bumps), the private packages and the ones without a version
119
+ included, and update the dependencies between them, in the packages and the root `package.json` (`^0.0.16` becomes
120
+ `^0.0.17`, and so do `~`, `>=`, `=` and `workspace:^` ranges, while `*`, `workspace:*` and `file:` are kept). With `0.x`
121
+ versions this matters, as a range matches only its own version. The command also updates `package-lock.json` or
122
+ `pnpm-lock.yaml`, without which `npm ci` would fail. A `yarn.lock` is not updated (the command warns you to run
123
+ `yarn install`), and a failed update is only a warning. The version of the workspace is the `version` of `lerna.json`
124
+ when that file gives one, else that of the root `package.json`, else the highest version of the packages, a prerelease
125
+ included (`0.0.0` when none has one), and the new version is written back there. `--git` commits the files of the
126
+ version, and only them, with the message `v<version>`, and tags the commit `v<version>` (a lightweight tag, not pushed);
127
+ the repository and the tag are checked before a file is changed. The command asks for a confirmation in a terminal only,
128
+ and `--yes` gives the version without asking.
105
129
 
106
130
  ### `lakutata add <name>`
107
131
 
108
- Add a package to the workspace: `packages/<name>` (without its scope), of the version of the workspace, with its
109
- `clean`, `build`, `rebuild` and `test` scripts and a test; `--to <package>` makes a package of the workspace depend on it.
110
- Then `npm install` links it.
111
-
112
- - `lakutata add greeting`: a TypeScript package (`src/index.ts` compiled into `build`, its declarations emitted).
113
- - `lakutata add @acme/capture --native [gyp|cmake|rust]`: a native addon, by its build system:
114
- - `gyp` (by default): C++ with [node-addon-api](https://github.com/nodejs/node-addon-api), built by node-gyp from
132
+ Add a package to the workspace, in its directory of packages (without its scope): the directory of the first pattern of
133
+ the workspace of the form `<directory>/*`, such as `apps/*`, or `packages/*` when there is one, so that the other
134
+ commands see the package; a workspace without such a pattern (its packages named one by one, or `packages/**`) is
135
+ refused. Its version is that of the workspace (`lerna.json`, else the root `package.json`, else the highest version of
136
+ the packages; `0.0.1` without one, or with the independent versions of lerna). It is private (remove `"private": true`
137
+ to publish it), has `clean`, `build`, `rebuild` and `test` scripts and a test, and `--to <package>` adds it to the
138
+ dependencies of another package of the workspace, as `^<version>`. The command installs nothing: run the install of the
139
+ package manager of the project afterwards, as its output says, to link the package.
140
+
141
+ - `lakutata add greeting`: a TypeScript package (`src/index.ts` compiled into `build`, with its declarations).
142
+ - `lakutata add @acme/capture --native [gyp|cmake|rust]`: a native addon, with one of these build systems:
143
+ - `gyp` (the default): C++ with [node-addon-api](https://github.com/nodejs/node-addon-api), built by node-gyp from
115
144
  `binding.gyp`;
116
145
  - `cmake`: C++ with node-addon-api, built by [cmake-js](https://github.com/cmake-js/cmake-js) from `CMakeLists.txt`;
117
146
  - `rust`: Rust with [napi-rs](https://napi.rs), built by cargo (`Cargo.toml`, `build.rs`, `rust/lib.rs`).
118
147
 
119
- Node-API is stable across the versions of Node.js and Electron: the same addon runs in both without being rebuilt.
120
- The addon is built into `build/Release` (`npm run build:native`, and when the package is installed), loaded by
121
- node-gyp-build from `src/index.ts`, compiled into `dist`; the C++ ones are built for the Macs with Intel and with Apple
122
- silicon in one file. `lakutata native` links their libraries; `binding.gyp` and `CMakeLists.txt` also show in their
123
- comments how the libraries and the options of the build are given: the libraries of the system, pkg-config, the
124
- static libraries of the package, the dynamic libraries shipped with the addon (copied next to it, found there by its
125
- rpath), the standard of C++, the options of each platform; a library built by its own Makefile is built before by a
126
- script (`build:deps`).
127
- `lakutata package bundle` and `lakutata package exe` ship the addon with the application, its dynamic libraries too. Building
128
- it needs a C++ toolchain (with CMake for `cmake`), or Rust for `rust`.
148
+ Node-API is stable across versions of Node.js and Electron, so the same addon runs in both without being rebuilt. The
149
+ addon is built into `build/Release` (by `npm run build:native`, and by its `install` script when the package is
150
+ installed) and loaded by node-gyp-build from `src/index.ts`, which is compiled into `dist`. The C++ addons are built
151
+ for Intel and Apple silicon Macs in one file, a Rust addon for the architecture of the machine. `lakutata native`
152
+ links their libraries. The comments of `binding.gyp` and `CMakeLists.txt` also show how to give libraries and build
153
+ options: system libraries, pkg-config, static libraries of the package, dynamic libraries shipped with the addon
154
+ (copied next to it and found there through its rpath), and in `binding.gyp` the C++ standard and the options of each
155
+ platform (`CMakeLists.txt` sets C++20). A library with its own Makefile is built before the addon by a script, as the
156
+ README of the package shows (`build:deps`). `lakutata package bundle` and `lakutata package exe` ship the addon, and
157
+ its dynamic libraries, with the application. Building it needs a C++ toolchain (with CMake for `cmake`), or Rust for
158
+ `rust`.
129
159
 
130
160
  ### `lakutata native <action> <value>`
131
161
 
132
- Change the build of the native addon of the current directory, found by its build file (`binding.gyp`,
133
- `CMakeLists.txt`, `Cargo.toml`): its text is edited in place, its comments and its layout kept; the sources of the
134
- addon are not changed. A change already made changes nothing.
162
+ Change the build of the native addon in the current directory, found by its build file (`binding.gyp`,
163
+ `CMakeLists.txt` or `Cargo.toml`). The file is edited in place, keeping its comments and layout; the sources of the
164
+ addon are not changed. Repeating a change changes nothing.
135
165
 
136
166
  - `lakutata native link <library>`: link a library:
137
- - a library of the system: `lakutata native link pcap` (`ws2_32` with `--platform win`);
167
+ - a system library: `lakutata native link pcap` (`ws2_32` with `--platform win`);
138
168
  - `--pkg-config`: a library found by pkg-config (`lakutata native link libpcap --pkg-config`; not on Windows);
139
- - `--framework`: a framework of macOS (`lakutata native link CoreFoundation --framework`);
169
+ - `--framework`: a macOS framework (`lakutata native link CoreFoundation --framework`);
140
170
  - a file of the package: a static library (`deps/lib/libfoo.a`; `foo.lib` on Windows) is linked into the addon; a
141
- dynamic one (`deps/lib/libfoo.dylib`, `libfoo.so`, `foo.dll` with its import library `foo.lib`) is copied next to
142
- the addon and found there at run time by its rpath (`@loader_path` on macOS, `$ORIGIN` on Linux). On macOS, its
143
- install name must be `@rpath/libfoo.dylib` (`install_name_tool -id`): the command tells it otherwise;
144
- - `--crate`: a crate of a Rust addon (`cargo add`).
145
- - `lakutata native include <directory>`: a directory of headers (C++).
146
- - `lakutata native define <NAME[=value]>`: a definition of the preprocessor (C++).
147
-
148
- `--platform mac|linux|win` makes the change for one platform (the files of the libraries give theirs: `.dylib` macOS,
149
- `.so` Linux, `.dll` and `.lib` Windows, `.a` every platform but Windows); `--target <name>` names the target changed
150
- when the build file has several. What is written, by build system:
171
+ dynamic library (`deps/lib/libfoo.dylib`, `libfoo.so`, or `foo.dll` with its import library `foo.lib`) is copied
172
+ next to the addon and found there at run time through its rpath (`@loader_path` on macOS, `$ORIGIN` on Linux). On
173
+ macOS, its install name must be `@rpath/libfoo.dylib` (set with `install_name_tool -id`): the command says so when
174
+ it is not;
175
+ - `--crate`: a crate, for a Rust addon (`cargo add`).
176
+ - `lakutata native include <directory>`: a directory of headers (C++), of the package or an absolute directory of the
177
+ system.
178
+ - `lakutata native define <NAME[=value]>`: a preprocessor definition (C++).
179
+
180
+ `--platform mac|linux|win` makes the change for one platform only (a library file sets its own platform: `.dylib` macOS,
181
+ `.so` Linux, `.dll` and `.lib` Windows, `.a` every platform but Windows, like pkg-config). `--target <name>` names the
182
+ target to change when the build file has several. What is written, by build system:
151
183
 
152
184
  | | gyp | CMake | Rust |
153
185
  |---|---|---|---|
154
- | File | `binding.gyp`, or the `.gypi` it includes declaring the target | `CMakeLists.txt` | `.cargo/config.toml` (`[env]`), read by `build.rs` |
186
+ | File | `binding.gyp`, or the `.gypi` it includes that declares the target | `CMakeLists.txt` | `.cargo/config.toml` (`[env]`), read by `build.rs` |
155
187
  | Library | `libraries` | `target_link_libraries` | `rustc-link-lib` |
156
188
  | pkg-config | `<!@(pkg-config ...)` | `pkg_check_modules(... IMPORTED_TARGET ...)` | the `-sys` crates |
157
189
  | Framework | `xcode_settings.OTHER_LDFLAGS` | `-framework` in `if(APPLE)` | `rustc-link-lib=framework=` |
158
- | Dynamic library | `copies`, the rpath | `BUILD_RPATH`, a `POST_BUILD` copy | `rustc-cdylib-link-arg`, a `postbuild:native` copy |
190
+ | Dynamic library | `copies`, the rpath | `INSTALL_RPATH` (`BUILD_WITH_INSTALL_RPATH`), a `POST_BUILD` copy | `rustc-cdylib-link-arg`, a copy in `build:native` |
159
191
  | Headers, definitions | `include_dirs`, `defines` | `target_include_directories`, `target_compile_definitions` | none (crates) |
160
- | Platform | `conditions` (`OS=="mac"`) | `if(APPLE)`, `if(WIN32)`, `if(CMAKE_SYSTEM_NAME STREQUAL "Linux")` | `LAKUTATA_NATIVE_MACOS`, `_LINUX`, `_WINDOWS`, `_UNIX` |
192
+ | Platform | `conditions` (`OS=="mac"`, `OS!="win"`) | `if(APPLE)`, `if(WIN32)`, `if(NOT WIN32)`, `if(CMAKE_SYSTEM_NAME STREQUAL "Linux")` | `LAKUTATA_NATIVE_MACOS`, `_LINUX`, `_WINDOWS`, `_UNIX` |
161
193
 
162
- The Rust libraries are given to `build.rs` (by `lakutata add --native rust`), which gives them to cargo for the addon
163
- only: the flags of rustc would be given to every crate it builds.
194
+ For a Rust addon, the libraries are passed to `build.rs` (written by `lakutata add --native rust`), which passes them
195
+ to cargo for the addon only: flags given to rustc would apply to every crate it builds.
164
196
 
165
197
  ### `lakutata list`
166
198
 
167
- List the packages, their versions and the packages they depend on.
199
+ List the packages: the first line gives their number and the version of the workspace, then each package has its
200
+ version, ` (private)` when it is private, its directory and the packages of the workspace it depends on.
168
201
 
169
202
  ### From lerna
170
203
 
@@ -174,142 +207,158 @@ List the packages, their versions and the packages they depend on.
174
207
  | `lerna version patch --no-git-tag-version --no-push -y` | `lakutata version patch --yes` |
175
208
  | `lerna version patch` | `lakutata version patch --git` (the tag is not pushed) |
176
209
 
177
- The publication stays `npm publish -w <package>`. The tool does not bump the packages independently, does not write
178
- changelogs from the commits and does not cache the builds: the workspaces needing it keep lerna (or nx, turborepo) next
179
- to it.
210
+ Packages are still published with `npm publish -w <package>` (the packages `lakutata add` makes are private: remove
211
+ `"private": true` first). From `lerna.json`, the tool reads and writes only `version`: the packages come from the
212
+ `workspaces` of the root `package.json`, or from `pnpm-workspace.yaml`. It does not version packages independently (a
213
+ `lerna.json` with `"version": "independent"` cannot be bumped), write changelogs from the commits or cache builds:
214
+ workspaces that need these keep lerna (or nx, turborepo) alongside it.
180
215
 
181
216
  ## Bundles and executables
182
217
 
183
- The application of the current directory, compiled (`tsc`, which emits the metadata of the decorators), is packed by
184
- `@lakutata/builder`: the one installed in the project (`npm install --save-dev @lakutata/builder`, as the templates
185
- packing their applications do), else the one installed with the tool. Its functions (`bundleProject`,
186
- `buildExecutable`) pack the applications from the scripts too.
218
+ These commands pack the application in the current directory, which must be compiled first (by `tsc`, which emits the
219
+ metadata of the decorators). The work is done by `@lakutata/builder`: the copy installed in the project
220
+ (`npm install --save-dev @lakutata/builder`, as the templates that pack their application do), else the one installed
221
+ with the tool (a global install of the tool does not include it, as the builder is an optional peer dependency). Scripts
222
+ can also pack applications with its functions (`bundleProject`, `buildExecutable`).
187
223
 
188
224
  ### `lakutata package bundle`
189
225
 
190
- Bundle the application and its dependencies into one CommonJS file (esbuild), run by node without `node_modules`:
191
- `dist/<name>.cjs`, the name being the first `bin` of the `package.json`, or its name without its scope. The entry is the
192
- `main` of the `package.json` (`--entry` changes it), the bundle is minified with the names of the classes kept
193
- (`--no-minify`), `import.meta.url` is the URL of the bundle.
226
+ Bundle the application and its dependencies into one CommonJS file (with esbuild) that node runs without
227
+ `node_modules`: `dist/<name>.cjs`, where the name is the first `bin` of the `package.json`, else the package name
228
+ without its scope. The entry is the `main` of the `package.json`, else `build/App.js` (`--entry` changes it). The
229
+ bundle is minified, keeping the names of the classes (`--no-minify` turns minifying off), and `import.meta.url` is the
230
+ URL of the bundle.
194
231
 
195
232
  | Option | |
196
233
  |---|---|
197
- | `--entry <file>` | the compiled entry, the `main` of the `package.json` by default |
234
+ | `--entry <file>` | the compiled entry, by default the `main` of the `package.json`, else `build/App.js` |
198
235
  | `--outfile <file>` | the bundle, `dist/<name>.cjs` by default |
199
236
  | `--no-minify` | do not minify the bundle |
200
237
  | `--external <modules...>` | the modules left out of the bundle, loaded at run time from a `node_modules` next to it |
201
238
 
202
- The bundles are CommonJS modules (the executables of Node.js run them): the ES modules of the application are converted,
203
- without top-level `await` (await in an async function).
204
-
205
- The native addons (`.node` files) cannot be bundled: their packages are found while the application is bundled (the
206
- packages holding addons, and the packages loading them with computed paths, such as sharp) and left out of the bundle,
207
- with what they load at run time (the JavaScript they require, the packages of the shared libraries linked with their
208
- addons, such as libvips), laid out as in `node_modules`: `dist/<name>.native/`, distributed with the bundle. The tree
209
- holds the files loaded at run time: the packages of the addons and of the shared libraries have all their files, the
210
- other packages the JavaScript they load (traced) and their other files (the data they read), the packages loading their
211
- files by paths which cannot be followed (`require(path.join(__dirname, name))`) all their files; the types, the source
212
- maps, the TypeScript sources and the documentation of the packages are left out. The addons of
213
- the application itself (`require('./x.node')`, `createRequire(import.meta.url)('./x.node')`) are there too. The
214
- packages of the framework, and the ones built on it, are bundled with the application whatever they depend on (one copy
215
- of the framework, its classes and its container): their native dependencies are in the tree. The optional dependencies
216
- of a package which are not installed (the drivers of the stores the application does not use: `peerDependenciesMeta`
217
- optional, `optionalDependencies`) are left out: loading one throws at run time, as without the bundle.
218
-
219
- The files the application reads by their paths are not followed by the bundler: the scripts it runs on their own (its
220
- workers, `new Worker()`, the pools of workers given a file; its child processes, `fork()`; the modules it loads by their
221
- paths, `require(path.join(__dirname, 'x.js'))`), its data (`fs.readFileSync(path.join(__dirname, 'defaults.json'))`, a
222
- directory of schemas). And the bundle is not where its modules were: `path.resolve(__dirname, '../../schema')` of a
223
- module of `build/config/` is the `schema/` of the project, not once bundled in `dist/`. A path to a file given from its
224
- module is found wherever it is written, in the modules of the application and in the ones of its packages, and the
225
- expression rewritten to the file in the native tree (`dist/<name>.native/.lakutata/files/`, the directories as in the
226
- project, the packages linked from outside of it under `node_modules/`):
239
+ Bundles are CommonJS modules, because the executables of Node.js run them. The ES modules of the application are
240
+ converted, so they cannot use top-level `await`: await inside an async function instead.
241
+
242
+ Native addons (`.node` files) cannot be bundled. While bundling, the tool finds the packages that hold addons, and the
243
+ packages that load them through computed paths (such as sharp). It leaves them out of the bundle, with what they load at
244
+ run time (the JavaScript they require, and the packages of the shared libraries linked with their addons, such as
245
+ libvips), and lays them out as in `node_modules` in `dist/<name>.native/`, which is distributed with the bundle. This
246
+ tree holds the files loaded at run time: all the files of the packages of addons and shared libraries; for the other
247
+ packages, the JavaScript they load (traced) and their other files (the data they read); and all the files of the
248
+ packages that load their files through paths that cannot be followed (`require(path.join(__dirname, name))`). The type
249
+ declarations, source maps, TypeScript sources and documentation of the packages are left out, and so are the C and C++
250
+ sources and objects of the addons (better-sqlite3 holds the source of SQLite) and what built them: the files of node-gyp
251
+ and of CMake in `build/`, the `target` directory of cargo, the static and import libraries. The addons of the
252
+ application itself (`require('./x.node')`, `createRequire(import.meta.url)('./x.node')`) go into the tree too. The
253
+ packages of the framework, and those built on it, are always bundled with the application, whatever they depend on, so
254
+ that there is one copy of the framework, its classes and its container; their native dependencies go into the tree.
255
+ Optional dependencies that are not installed (the drivers of stores the application does not use: `peerDependenciesMeta`
256
+ optional, `optionalDependencies`) are left out: loading one throws at run time, as it would without the bundle.
257
+
258
+ The bundler does not follow the files that the application reads by path: the scripts it runs on their own (workers,
259
+ `new Worker()`, worker pools given a file; child processes, `fork()`; modules loaded by path,
260
+ `require(path.join(__dirname, 'x.js'))`) and its data (`fs.readFileSync(path.join(__dirname, 'defaults.json'))`, a
261
+ directory of schemas). Also, the bundle is not where the modules were: in a module of `build/config/`,
262
+ `path.resolve(__dirname, '../../schema')` is the `schema/` directory of the project, but no longer once bundled into
263
+ `dist/`. The tool finds every path to a file built from the location of its module, wherever it is written, in the
264
+ modules of the application and in those of its packages, and rewrites the expression to point to the file in the
265
+ native tree (`dist/<name>.native/.lakutata/files/`, with the directories as in the project, and the packages linked
266
+ from outside it under `node_modules/`):
227
267
 
228
268
  | The path names | |
229
269
  |---|---|
230
- | a script (`.js`, `.cjs`) | bundled on its own with what it loads (a CommonJS file, whatever the type of the project) |
231
- | another file | copied (a `package.json` its type CommonJS, as the scripts next to it) |
270
+ | a script (`.js`, `.cjs`) | bundled on its own with what it loads (as a CommonJS file, whatever the module type of the project) |
271
+ | another file | copied (a `package.json` gets the type CommonJS, like the scripts next to it) |
232
272
  | a directory of data | its files copied |
233
- | a directory holding the module (`path.join(__dirname, '..')`: the application, its packages) | not shipped, warned of: its files are declared as resources (`lakutata.resources`, below) |
234
- | a directory holding scripts or packages (`package.json`, `node_modules`) | not shipped, warned of: its scripts need their packages at run time |
273
+ | a directory holding the module (`path.join(__dirname, '..')`: the application, its packages) | not shipped, with a warning: declare its files as resources (`lakutata.resources`, below) |
274
+ | a directory holding scripts or packages (`package.json`, `node_modules`) | not shipped, with a warning: its scripts would need their packages at run time |
235
275
  | nothing yet (a directory the application creates) | left as it is |
236
276
 
237
- The paths followed:
277
+ The paths that are followed:
238
278
 
239
279
  | Path | |
240
280
  |---|---|
241
- | `new URL('./worker.js', import.meta.url)` | the URL of the module (as Vite); `pathToFileURL(__filename)` too |
242
- | `import.meta.url + '/../worker.js'` | a text of the URL of the module |
243
- | `path.join(__dirname, 'worker.js')`, `path.resolve(__dirname, …)` | `import.meta.dirname`, `path.dirname(fileURLToPath(import.meta.url))` too |
281
+ | `new URL('./worker.js', import.meta.url)` | the URL of the module (as in Vite); also `pathToFileURL(__filename)` |
282
+ | `import.meta.url + '/../worker.js'` | the URL of the module as a string |
283
+ | `path.join(__dirname, 'worker.js')`, `path.resolve(__dirname, …)` | also with `import.meta.dirname` or `path.dirname(fileURLToPath(import.meta.url))` |
244
284
  | `__dirname + '/worker.js'`, `` `${__dirname}/worker.js` `` | |
245
- | `require.resolve('./worker')`, `require.resolve(path.resolve(__dirname, '../lib/worker'))` | the extension found as node finds it |
246
- | `` path.join(__dirname, 'locales', `${lang}.json`) ``, `` new URL(`./jobs/${name}.js`, import.meta.url) `` | known in part: every file and directory its pattern matches (an expression matches a part of a name), its expression kept |
247
-
248
- The code of tsc (`(0, node_path_1.join)(__dirname, 'worker.js')`) is followed. A script also imported by the application
249
- is warned of: it is bundled twice, its module apart in each (its state, its classes). The workers of node
250
- (`worker_threads`) whose scripts cannot be followed are warned of with their file and line, in the modules of the
251
- application (the packages start workers from the paths their users give): a path known at run time only
252
- (`new Worker(file)`, a variable or a property of a class holding one of the paths above is followed), or a path relative
253
- to the current directory of the process (`new Worker('./worker.js')`, which node reads from there, not from the module);
254
- their scripts are given from the directory of their module, or shipped as resources. The workers running a source
255
- (`eval: true`) need nothing. The warnings name the modules of the application only, with their file and line.
285
+ | `require.resolve('./worker')`, `require.resolve(path.resolve(__dirname, '../lib/worker'))` | the extension is found as node finds it |
286
+ | `` path.join(__dirname, 'locales', `${lang}.json`) ``, `` new URL(`./jobs/${name}.js`, import.meta.url) `` | partly known: every file and directory its pattern matches (an expression matches part of a name), with the expression kept |
287
+
288
+ The code emitted by tsc (`(0, node_path_1.join)(__dirname, 'worker.js')`) is followed too. A script that the
289
+ application also imports gets a warning: it is bundled twice, with a separate copy of its module (its state, its
290
+ classes) in each. Node.js workers (`worker_threads`) whose scripts cannot be followed get a warning in the modules of
291
+ the application (packages start workers from the paths their users give): a path known only at run time
292
+ (`new Worker(file)`; a variable or a class property holding one of the paths above is followed), or a path relative
293
+ to the current directory of the process (`new Worker('./worker.js')`, which node resolves from there, not from the
294
+ module). Build the paths of their scripts from the directory of their module, or ship the scripts as resources.
295
+ Workers that run source code (`eval: true`) need nothing. The warnings name only the modules of the application,
296
+ with their file and line.
256
297
 
257
298
  The resources of the application, the files it reads at run time (the built pages of a web application, templates,
258
- data), are declared by the `lakutata.resources` of its `package.json`, as the `extraResources` of electron-builder:
299
+ data), are declared in the `lakutata.resources` of its `package.json`, as a list of `{from, to}` objects (like the
300
+ `extraResources` of electron-builder, but without its strings, globs or filters):
259
301
 
260
302
  ```json
261
303
  "lakutata": {"resources": [{"from": "../ui/dist", "to": "ui"}]}
262
304
  ```
263
305
 
264
- `from` is a file or a directory of the project, `to` its path in the resources: `dist/<name>.resources/`, distributed
265
- with the bundle. The application finds them by `resourcesPath()` of lakutata (`undefined` when it does not run packed,
266
- `isPackaged()` tells it).
306
+ `from` is a file or a directory of the project, and `to` its path among the resources, in `dist/<name>.resources/`,
307
+ which is distributed with the bundle. The application finds them through `resourcesPath()` of lakutata (`undefined`
308
+ when it does not run packed, which `isPackaged()` tells).
267
309
 
268
310
  ### `lakutata package exe`
269
311
 
270
- Make the executable of the application for the platform it runs on, which runs without Node.js installed: the bundle
271
- embedded in the Node.js binary running the tool (the single executable applications of Node.js), `dist/<name>`
272
- (`dist/<name>.exe` on Windows), with the code cache of the bundle (V8). The Node.js embedded is the version running the
273
- tool.
274
-
275
- With `--runtime bun`, the bundle is compiled by Bun (`bun build --compile --bytecode`, its bytecode is not parsed at
276
- start) instead: the Bun of the project (the `bun`
277
- package of npm, `npm install --save-dev bun`), else the one of the system. Its executables are smaller, start faster and
278
- use less memory; the runtime is Bun's (JavaScriptCore, its implementation of the APIs of Node.js). The bundle and its
279
- native addons are the ones of the executables of Node.js, which do not change for it. As them, the executables of Bun do
280
- not load the `.env` and the `bunfig.toml` of the directory they run in (the application loads its `.env`), and the
281
- mode is the one of their run: Bun replaces `process.env.NODE_ENV` with the mode of its build, the bundle reads it.
282
-
283
- The executables of the other platforms are made on them, as the applications are built there: their native addons are
284
- built for them, and they are tried there. The CI gives the machines of the platforms (a matrix of the Linux, macOS and
285
- Windows runners); the Linux architectures are also made in a container of the architecture (`docker run --platform
286
- linux/arm64`, as the cross builds of the templates).
312
+ Make an executable of the application for the platform it runs on, which runs without Node.js installed: `dist/<name>`
313
+ (`dist/<name>.exe` on Windows). The bundle is embedded, with its V8 code cache, in a copy of the Node.js binary running
314
+ the tool (a single executable application of Node.js), so the embedded Node.js is the version running the tool. In an
315
+ executable, `import.meta.url` is the URL of the executable itself.
316
+
317
+ With `--runtime bun`, Bun compiles the bundle instead (`bun build --compile --bytecode`: the code is compiled to
318
+ bytecode, so it is not parsed at start), using the Bun of the project (the `bun` package of npm,
319
+ `npm install --save-dev bun`), else the one of the system. Its executables are smaller, start faster and use less
320
+ memory; the runtime is then Bun (JavaScriptCore, with its implementation of the Node.js APIs). The native addons are
321
+ those of Node.js, not rebuilt for Bun. Bun loads the addons of Node-API, but may not load those built on the V8 API of
322
+ Node.js: the tool warns of them (with better-sqlite3, the executable builds, and fails when it loads the package). Like
323
+ the executables of Node.js, the executables of Bun do not load the `.env` or the `bunfig.toml` of the directory they run
324
+ in (an application that needs one loads it itself, or uses `LAKUTATA_ENV_FILE`), and the mode is that of the run: Bun
325
+ would replace `process.env.NODE_ENV` with the mode of its build, but the bundle reads it at run time.
326
+
327
+ Make the executables of other platforms on those platforms: the native addons of the application are built there for
328
+ them, and the executables can be tested there. A CI provides the machines (a matrix of Linux, macOS and Windows
329
+ runners); the Linux architectures can also be built in a container of the architecture
330
+ (`docker run --platform linux/arm64`, as the cross builds of the templates do).
287
331
 
288
332
  | Option | |
289
333
  |---|---|
290
334
  | `--outdir <directory>` | the directory of the executable, `dist` by default |
291
- | `--runtime <node\|bun>` | the runtime embedded: `node` (by default) or `bun` |
292
- | `--layout <file\|directory>` | one file (by default), or a directory: `dist/<name>/` holding the executable, its native addons (`native/`) and its resources (`resources/`), loaded from there without extraction (the installers, the images) |
293
- | `--entry`, `--no-minify`, `--external` | as `lakutata package bundle` |
294
-
295
- The native addons, the files read by their paths and the resources are embedded in the executable (`--layout file`): at its
296
- first run, it extracts them into its cache directory (`~/.cache/<name>`, `~/Library/Caches/<name>` on macOS,
297
- `%LOCALAPPDATA%\<name>\Cache` on Windows, or `LAKUTATA_NATIVE_DIR`; the temporary directory when it cannot be written),
298
- in a directory named after their content:
299
- the next runs load them from there, the versions of the program do not share it. The addons need the system libraries they were built for (the
300
- glibc version of the Linux prebuilt addons). The child processes of an executable run it (`process.execPath`): started
301
- for one of its scripts (`fork(path.join(__dirname, 'child.js'))`, `spawn(process.execPath, [script])`), it runs the
302
- script as node does (its arguments, `require.main`), not the application.
303
-
304
- The executables of macOS are signed ad hoc. The ones of Windows made by Node.js keep the signature of `node.exe`, which
305
- does not match anymore: sign them before distributing them.
335
+ | `--runtime <node\|bun>` | the embedded runtime: `node` (the default) or `bun` |
336
+ | `--layout <file\|directory>` | one file (the default), or a directory: `dist/<name>/` holds the executable, its native addons (`native/`) and its resources (`resources/`), loaded from there without extraction (for the installers and the images) |
337
+ | `--entry`, `--no-minify`, `--external` | as for `lakutata package bundle`: the external modules are loaded from a `node_modules` next to the executable |
338
+
339
+ With `--layout file`, the native addons, the files read by path and the resources are embedded in the executable. At its
340
+ first run, the executable extracts them into `native/<hash>`, a directory named after their content, in its cache
341
+ directory: `~/Library/Caches/<name>` on macOS, `%LOCALAPPDATA%\<name>\Cache` on Windows, `$XDG_CACHE_HOME/<name>` or
342
+ else `~/.cache/<name>` on Linux, or the directory given by `LAKUTATA_NATIVE_DIR`. When the cache directory cannot be
343
+ written, it uses `<name>` in the temporary directory (not when `LAKUTATA_NATIVE_DIR` is given). The next runs load them
344
+ from there, and different versions of the program do not share it. The addons need the system libraries they were built
345
+ for (the glibc version of the Linux prebuilt addons).
346
+
347
+ The child processes of an executable run the executable itself (`process.execPath`). In both layouts, an executable
348
+ started for one of its scripts (`fork(path.join(__dirname, 'child.js'))`, `spawn(process.execPath, [script])`) runs that
349
+ script with its arguments, not the application: with Node.js, `require.main` is that script, as with node; with Bun, it
350
+ is not.
351
+
352
+ The executables for macOS are signed ad hoc. Those for Windows made with Node.js keep the signature of `node.exe`,
353
+ which no longer matches: sign them before distributing them.
306
354
 
307
355
  ### `lakutata package installer`
308
356
 
309
- Make the installers of the application for the platform it runs on (as electron-builder): its executable in a directory
310
- (`lakutata package exe --layout directory`) installed with its native addons and its resources, its program in the PATH,
311
- its service registered. The installers of the other platforms are made on them (the ones of Linux in a container).
312
- They are configured by the `lakutata.installer` of the `package.json`:
357
+ Make the installers of the application for the platform it runs on (as electron-builder does). They install its
358
+ executable in the directory layout (`lakutata package exe --layout directory`) with its native addons and its
359
+ resources, put its program in the PATH and register its service. Make the installers of other platforms on those
360
+ platforms (the Linux ones can be made in a container). They are configured by the `lakutata.installer` of the
361
+ `package.json`:
313
362
 
314
363
  ```json
315
364
  "lakutata": {
@@ -322,61 +371,68 @@ They are configured by the `lakutata.installer` of the `package.json`:
322
371
 
323
372
  | Option | |
324
373
  |---|---|
325
- | `name` | the name of the package (lower case), the one of the program by default |
326
- | `appId` | the identifier of the application (reverse DNS, `com.acme.app`), its name by default: the identifier of the package of macOS and the label of its service, the key of its uninstaller and of its upgrades on Windows |
327
- | `productName` | the name shown to the users (the installers, the programs of Windows), its name by default |
328
- | `description`, `maintainer`, `homepage`, `license`, `vendor` | the ones of the `package.json` by default (the maintainer is its author) |
329
- | `runtime` | the runtime of the executable: `node` (by default) or `bun`; `electron` for an Electron application (below) |
330
- | `addToPath` | the program in the PATH (`/usr/bin/<program>`, the PATH of the machine on Windows), by default |
374
+ | `name` | the name of the package (lower case), by default that of the program (for an Electron application, the name of the package without its scope) |
375
+ | `appId` | the identifier of the application (reverse DNS, `com.acme.app`), by default its name: on macOS, the identifier of the package and the label of the service; on Windows, the key of its uninstaller and of its upgrades |
376
+ | `productName` | the name shown to users (in the installers, and in the list of programs on Windows), by default the `productName` of the `package.json`, else the name |
377
+ | `description`, `maintainer`, `homepage`, `license` | by default those of the `package.json` (the maintainer is its author) |
378
+ | `vendor` | its vendor, none by default (on Windows, the publisher is the vendor, else the maintainer) |
379
+ | `runtime` | the runtime of the executable: `node` (the default) or `bun`; `electron` for an Electron application (below) |
380
+ | `addToPath` | put the program in the PATH (`/usr/bin/<program>`, `/usr/local/bin/<program>` on macOS; on Windows, the PATH of the machine), `true` by default |
331
381
  | `service` | `true` or the options of the service (below), none by default |
332
- | `linux.targets` | `deb`, `rpm`, `archlinux`, `tar.gz` on the systems of the glibc (`deb`, `rpm`, `tar.gz` by default), `apk`, `tar.gz` on Alpine (musl) |
333
- | `linux.depends`, `linux.recommends`, `linux.section`, `linux.priority` | the packages of the system it needs, recommends, its section and priority (deb) |
382
+ | `linux.targets` | `deb`, `rpm`, `archlinux`, `tar.gz` on glibc systems (`deb`, `rpm`, `tar.gz` by default); `apk`, `tar.gz` on Alpine (musl) |
383
+ | `linux.depends`, `linux.recommends`, `linux.section`, `linux.priority` | the system packages it needs and recommends, its section and its priority (deb) |
334
384
  | `mac.targets` | `pkg`, `tar.gz` (both by default) |
335
385
  | `win.targets` | `nsis`, `msi`, `zip` (all by default) |
336
- | `electron` | the configuration of electron-builder of an Electron application, merged over the one made from these options |
337
-
338
- The packages of Linux are made by nFPM (downloaded once into the cache of lakutata, `LAKUTATA_NFPM` gives another one),
339
- in `dist/installer` (`--outdir`): the application is installed in `/opt/<name>`, the C++ library of the runtime is a
340
- dependency. The executables link the C library of the system they are made on: the packages of the systems of the glibc
341
- are made on one of them, the `apk` packages on Alpine, with Bun (`"runtime": "bun"`) when the application has native
342
- addons: the executables of Node.js do not load them on musl.
343
-
344
- The installers of macOS are made by its tools (`pkgbuild`, `productbuild`): the `pkg` package installs the application in
345
- `/usr/local/lib/<name>`, its program in `/usr/local/bin`; the packages of macOS are not removed by the system:
346
- `sudo /usr/local/lib/<name>/uninstall` removes it. They are signed ad hoc (the Developer ID signature and the
347
- notarization, which the distribution out of the machines of the organization needs, are not made yet).
348
-
349
- The installers of Windows are made on Windows: the installer of NSIS (`<name>-<version>-<arch>-setup.exe`) and the
350
- package of Windows Installer (`.msi`, made by WiX, for the deployments of the organizations) install the application in
351
- `C:\Program Files\<name>`, its data in `C:\ProgramData\<name>`; they are removed as the programs of Windows. Their tools
352
- are downloaded once into the cache of lakutata (NSIS 3, WiX 3, WinSW; `LAKUTATA_NSIS`, `LAKUTATA_WIX`, `LAKUTATA_WINSW`
353
- give other ones). The executables keep the signature of Node.js, which does not match anymore: sign them (signtool)
354
- before distributing them.
355
-
356
- The service runs the application at the start of the system: systemd (`/usr/lib/systemd/system/<service>.service`),
357
- OpenRC on Alpine (`/etc/init.d/<service>`), launchd on macOS (`/Library/LaunchDaemons/<appId>.plist`), or WinSW on Windows
358
- (`<name>-service.exe` next to the application, a service of Windows: `Restart-Service <service>`). It is started by the
359
- installation, restarted by the upgrades, stopped and disabled before the removal.
386
+ | `electron` | the electron-builder configuration of an Electron application, merged over the one made from these options |
387
+
388
+ The configuration is checked before anything is built, the options of the installers that are not made included.
389
+
390
+ The Linux packages are made by nFPM (downloaded once into the cache of lakutata, for x64 and arm64; `LAKUTATA_NFPM`
391
+ gives another copy, and one for the other architectures) in `dist/installer` (`--outdir`). They install the application
392
+ in `/opt/<name>`, with the C++ runtime library as a dependency. The executables link the C library of the system they
393
+ are made on, so make the packages for glibc systems on a glibc system, and the `apk` packages on Alpine, with Bun
394
+ (`"runtime": "bun"`) when the application has native addons: the executables of Node.js do not load them on musl.
395
+
396
+ The macOS installers are made with the tools of macOS (`pkgbuild`, `productbuild`). The `pkg` package installs the
397
+ application in `/usr/local/lib/<name>` and its program in `/usr/local/bin`, on the Macs of the architecture of the
398
+ program only. macOS does not remove packages: `sudo /usr/local/lib/<name>/uninstall` removes the application (its data,
399
+ its environment file, its user and its log are kept). The `pkg` package is not signed, and the executable it installs is
400
+ signed ad hoc only (the Developer ID signature and the notarization, which distribution outside the machines of the
401
+ organization needs, are not made yet).
402
+
403
+ The Windows installers are made on Windows: the NSIS installer (`<name>-<version>-<arch>-setup.exe`) and the Windows
404
+ Installer package (`.msi`, made by WiX, for deployment in organizations) install the application in
405
+ `C:\Program Files\<name>` and its data in `C:\ProgramData\<name>`; they are removed like other Windows programs. Their
406
+ tools are downloaded once into the cache of lakutata (NSIS 3, WiX 3, WinSW; `LAKUTATA_NSIS`, `LAKUTATA_WIX` and
407
+ `LAKUTATA_WINSW` give other copies). The executables made with Node.js (`"runtime": "node"`) keep the signature of
408
+ Node.js, which no longer matches: sign them (signtool) before distributing them.
409
+
410
+ The service runs the application when the system starts: systemd (`/usr/lib/systemd/system/<service>.service`), OpenRC
411
+ on Alpine (`/etc/init.d/<service>`), launchd on macOS (`/Library/LaunchDaemons/<appId>.plist`), or WinSW on Windows
412
+ (`<name>-service.exe` next to the application, registered as a Windows service: `Restart-Service <service>`). The
413
+ installation starts it, an upgrade restarts it, and the removal stops and disables it first.
360
414
 
361
415
  | Service option | |
362
416
  |---|---|
363
- | `name`, `description` | the ones of the package by default |
417
+ | `name`, `description` | those of the package by default |
364
418
  | `args` | the arguments of the application |
365
- | `env` | its environment (`MODE=production` by default), written to `/etc/<name>/<name>.env` (`/usr/local/etc/<name>/<name>.env` on macOS, `C:\ProgramData\<name>\<name>.env` on Windows), which the administrators change (kept by the upgrades) |
366
- | `user` | its user: a system user named after the package by default (`_<name>` on macOS, hidden), created by the installation, or `root`; on Windows its virtual account by default (`NT SERVICE\<service>`), `LocalService`, `NetworkService` or `LocalSystem` |
367
- | `restart` | `on-failure` (by default), `always` or `no` |
368
- | `autoStart` | enabled and started by the installation, by default |
419
+ | `env` | its environment (`MODE=production` by default), written to `/etc/<name>/<name>.env` (`/usr/local/etc/<name>/<name>.env` on macOS, `C:\ProgramData\<name>\<name>.env` on Windows), which administrators may edit (upgrades keep it) |
420
+ | `user` | its user: by default a system user named after the package (`_<name>` on macOS, hidden), created by the installation, or `root`; on Windows, by default its virtual account (`NT SERVICE\<service>`), or `LocalService`, `NetworkService` or `LocalSystem` |
421
+ | `restart` | `on-failure` (the default), `always` or `no` (on Windows and with OpenRC, `on-failure` and `always` behave alike) |
422
+ | `autoStart` | enabled and started by the installation, `true` by default; otherwise the administrator enables and starts it (`systemctl enable --now <service>`; on macOS, `launchctl enable system/<appId>`, then `launchctl bootstrap system /Library/LaunchDaemons/<appId>.plist`) |
369
423
 
370
- Its working directory is `/var/lib/<name>` (`/usr/local/var/lib/<name>` on macOS, its log `/usr/local/var/log/<name>.log`;
371
- `C:\ProgramData\<name>` on Windows, its logs in `logs`), owned by its user (its data). `SIGTERM` ends it gracefully (on
372
- Windows, the stop of the service: Ctrl+C, `SIGINT` for Node.js).
424
+ Its working directory, which holds its data and is owned by its user, is `/var/lib/<name>` (`/usr/local/var/lib/<name>`
425
+ on macOS, with its log in `/usr/local/var/log/<name>.log`; `C:\ProgramData\<name>` on Windows, with its logs in `logs`).
426
+ `SIGTERM` ends it gracefully (on Windows, stopping the service sends a Ctrl+C, which Node.js receives as `SIGINT`).
373
427
 
374
- The executables load the environment file given by the `LAKUTATA_ENV_FILE` environment variable before the application
375
- starts (the service of Windows, whose wrapper has none): its lines `NAME=value` or `NAME="value"`, its comments (`#`).
428
+ Every bundle and executable, and so every installed application, loads the environment file named by the
429
+ `LAKUTATA_ENV_FILE` environment variable before the application starts (the Windows service gets its environment this
430
+ way, as its wrapper has no environment file): lines `NAME=value` or `NAME="value"`, and comments (`#`). The values of
431
+ the file override the variables that are already set.
376
432
 
377
- The installers run the scripts of the application (files of the project), as the ones of electron-builder: the ones of a
378
- platform, which its installers run, replaced by the ones of an installer (a moment each), the native ones of a package of
379
- Linux, the file of NSIS included by its installer:
433
+ The installers run scripts of the application (files of the project), as with electron-builder: the scripts of a
434
+ platform, which all its installers run; the scripts of one installer, each replacing the platform's script for the
435
+ same moment; the native scripts of a Linux package; and an NSIS file included by the NSIS installer:
380
436
 
381
437
  ```json
382
438
  "installer": {
@@ -392,123 +448,136 @@ Linux, the file of NSIS included by its installer:
392
448
 
393
449
  | Script | |
394
450
  |---|---|
395
- | `preinstall` | before the files of the application are installed (on Windows Installer, an upgrade has removed the version it replaces) |
396
- | `postinstall` | after they are installed, before the service is started (on an upgrade, the one of the version replaced may still run) |
451
+ | `preinstall` | before the files of the application are installed (with Windows Installer, an upgrade has already removed the version it replaces) |
452
+ | `postinstall` | after they are installed, before the service starts (during an upgrade, the service of the version replaced may still run) |
397
453
  | `preremove` | before the removal, once the service is stopped |
398
454
  | `postremove` | after the files are removed |
399
455
 
400
- They are given what the installer does: `install` or `upgrade` (`preinstall`, `postinstall`), `remove` (`preremove`,
401
- `postremove`; an upgrade runs no removal script), as their first argument (`$1`, `$args[0]` in PowerShell), and the
402
- directory of the application (`LAKUTATA_INSTALL_DIR`). They run as root (as the system on Windows). Their failure is the
403
- one of the installation (or of the removal). Each package manager tells it in its own way (dpkg `configure <version>`,
404
- rpm the number of the versions, apk and pacman their upgrade scripts): the installers translate them.
405
-
406
- - Linux (`linux.scripts`, `linux.<deb|rpm|apk|archlinux>.scripts`): scripts run by the interpreter of their first line
407
- (`#!/bin/sh` by default), embedded in the scripts of the packages. `linux.<package>.nativeScripts` are run as the
408
- package manager runs the scripts of the package, with its own arguments (`preinstall`, `postinstall`, `preremove`,
409
- `postremove`; `preupgrade`, `postupgrade` for apk and archlinux).
410
- - macOS (`mac.scripts`, `mac.pkg.scripts`): sh scripts as on Linux; the removal ones are run by the `uninstall` script of
411
- the application (the packages of macOS are not removed by the system).
412
- - Windows (`win.scripts`, `win.<nsis|msi>.scripts`): scripts of PowerShell (`.ps1`, run by Windows PowerShell; Windows
413
- Installer runs them by a command line, which they must fit in: about 23 KB each). `win.nsis.include` is a file of NSIS
414
- (`.nsh`) included by the installer of NSIS, whose macros are inserted: `customHeader`, `customInit`, `customInstall` (at
456
+ Their first argument (`$1`, `$args[0]` in PowerShell) tells what the installer does: `install` or `upgrade`
457
+ (`preinstall`, `postinstall`), or `remove` (`preremove`, `postremove`; an upgrade runs no removal script).
458
+ `LAKUTATA_INSTALL_DIR` gives the directory of the application. They run as root (on Windows, as an administrator with
459
+ NSIS and as the system account with Windows Installer). When a script fails, the installation (or the removal) fails.
460
+ Each package manager signals an upgrade in its own way (dpkg with `configure <version>`, rpm with the number of
461
+ installed versions, apk and pacman with their upgrade scripts): the installers translate them into these arguments.
462
+
463
+ - Linux (`linux.scripts`, `linux.<deb|rpm|apk|archlinux>.scripts`): scripts run by the interpreter named on their first
464
+ line (`#!/bin/sh` by default), embedded in the scripts of the packages. `linux.<package>.nativeScripts` are run the
465
+ way the package manager runs the scripts of the package, with its own arguments (`preinstall`, `postinstall`,
466
+ `preremove`, `postremove`; `preupgrade`, `postupgrade` for apk and archlinux).
467
+ - macOS (`mac.scripts`, `mac.pkg.scripts`): sh scripts, as on Linux; the `uninstall` script of the application runs
468
+ the removal scripts (macOS does not remove packages).
469
+ - Windows (`win.scripts`, `win.<nsis|msi>.scripts`): PowerShell scripts (`.ps1`, run by Windows PowerShell; Windows
470
+ Installer runs them through a command line, which each must fit in: about 23 KB). `win.nsis.include` is an NSIS file
471
+ (`.nsh`) included by the NSIS installer, which inserts its macros: `customHeader`, `customInit`, `customInstall` (at
415
472
  the end of the installation), `customUnInit`, `customUnInstall` (at the start of the removal).
416
- - The archives (`tar.gz`, `zip`) run none.
417
-
418
- The installers of an Electron application (`"runtime": "electron"`) are made by electron-builder (a dependency of the
419
- project): its main process bundled with its dependencies (Electron left out) in the archive of the application, its
420
- native addons and its resources (`lakutata.resources`: its renderer, its preload script, read from `resourcesPath()`)
421
- next to it, in the resources of Electron. Its installers are the targets of electron-builder (`deb` on Linux, `dmg` on
422
- macOS, `nsis` on Windows by default: `linux.targets`, `mac.targets`, `win.targets`); `name`, `appId`, `productName`, its
423
- description, maintainer, homepage and license are given to electron-builder, `electron` gives the rest (its icons, its
424
- file associations, its signature, its updates…). It is not a service. Its scripts are run by:
473
+ - Archives (`tar.gz`, `zip`) run no scripts.
474
+
475
+ The installers of an Electron application (`"runtime": "electron"`) are made by electron-builder, a dependency of the
476
+ project. Its main process is bundled with its dependencies (Electron left out) into the archive of the application, and
477
+ its native addons and resources (`lakutata.resources`: its renderer and its preload script, read from `resourcesPath()`)
478
+ go next to it, in the resources of Electron. Its installers are targets of electron-builder (by default `deb` on Linux,
479
+ `dmg` on macOS and `nsis` on Windows: `linux.targets`, `mac.targets`, `win.targets`). `name`, `appId`, `productName`,
480
+ the description, maintainer, homepage and license are given to electron-builder, and `electron` gives the rest (icons,
481
+ file associations, signature, updates…); `addToPath` and the `linux` options other than `targets` and the scripts are
482
+ not used, and `vendor` is used on Linux only. Its native addons are copied as they are installed (electron-builder does
483
+ not rebuild them): the addons of Node-API run in Electron as they are; install the Electron builds of the others before
484
+ packing (`electron-rebuild`). An Electron application is not a service. Its scripts are run by:
425
485
 
426
486
  | Installer | Scripts |
427
487
  |---|---|
428
- | `deb`, `rpm` (the packages of fpm) | all (embedded after the scripts of electron-builder) |
429
- | `pkg` (macOS) | `preinstall`, `postinstall` (an application of macOS is removed by its user) |
430
- | `nsis` (Windows) | `preinstall`, `postinstall`, `preremove` (its uninstaller ends with the removal of the files); the file of NSIS of `win.nsis.include` defines the other macros |
488
+ | `deb`, `rpm` (packages made by fpm) | all (`postinstall` and `postremove` after the scripts of electron-builder) |
489
+ | `pkg` (macOS) | `preinstall`, `postinstall` (a macOS application is removed by its user) |
490
+ | `nsis` (Windows) | `preinstall`, `postinstall`, `preremove` (its uninstaller ends by removing the files); the NSIS file of `win.nsis.include` defines the other macros |
431
491
  | the others (`AppImage`, `dmg`, `portable`, `msi`…) | none |
432
492
 
433
- The packages of fpm made on Linux arm64 need the fpm of the system (`gem install fpm`, `USE_SYSTEM_FPM=true`): the one
434
- electron-builder downloads is the one of x64. On Windows arm64, the installers of NSIS filter the executables by the BCJ
435
- filter (`ELECTRON_BUILDER_7Z_FILTER`): the ARM64 one, which 7-Zip chooses, is not extracted by them.
493
+ On Linux arm64, the fpm packages need the fpm of the system (`gem install fpm`, `USE_SYSTEM_FPM=true`), because the
494
+ one electron-builder downloads is built for x64. On Windows arm64, the NSIS installers compress the executables with
495
+ the BCJ filter (`ELECTRON_BUILDER_7Z_FILTER`), because they cannot extract files compressed with the ARM64 filter,
496
+ which 7-Zip would choose.
436
497
 
437
498
  | Command option | |
438
499
  |---|---|
439
- | `--target <targets...>` | the installers made, the ones of the configuration by default |
500
+ | `--target <targets...>` | the installers to make, by default those of the configuration |
440
501
  | `--outdir <directory>` | the directory of the installers, `dist/installer` by default |
441
- | `--entry`, `--no-minify`, `--external` | as `lakutata package bundle` |
502
+ | `--entry`, `--no-minify`, `--external` | as for `lakutata package exe` |
442
503
 
443
504
  ## Migrations
444
505
 
445
506
  ### `lakutata migration <action>`
446
507
 
447
- The migrations of the databases of the application (its Database components and providers): `generate`, `run`, `revert`
448
- and `show` run the script of the package building and starting the application (`dev` by default) with an environment
449
- variable (`MIGRATION_GENERATE`, `MIGRATION_RUN`, `MIGRATION_REVERT`, `MIGRATION_SHOW`): the application connects its
450
- databases with their options, without synchronizing their schemas nor running their migrations, does the command,
451
- tells what it did and exits, without starting its components nor its entrypoints. `create` writes a file.
508
+ Manage the migrations of the databases of the application (its Database components and providers). `generate`, `run`,
509
+ `revert` and `show` run the package script that builds and starts the application (`dev` by default, run by the package
510
+ manager of the project) with an environment variable (`MIGRATION_GENERATE`, `MIGRATION_RUN`, `MIGRATION_REVERT`,
511
+ `MIGRATION_SHOW`). The application then connects to its databases with their options, without synchronizing their
512
+ schemas or running their migrations, runs the command, reports what it did and exits, without starting its components or
513
+ its entrypoints. `create` only writes a file.
452
514
 
453
515
  | Action | |
454
516
  |---|---|
455
- | `generate` | the migrations of the changes of the entities: the application compares them with its databases and writes the migrations into the directory, one file `<timestamp>-<name of the database>.ts` per database changed (`cross-env MIGRATION_GENERATE=./src/migrations npm run dev` of lakutata 2.x); without change, nothing is generated and the command fails |
456
- | `create <name>` | an empty migration, written by hand (`up` and `down`): `<timestamp>-<name>.ts`, its class `<Name><timestamp>` |
457
- | `show` | the migrations of the options of the databases, run `[X]` or pending `[ ]` |
517
+ | `generate` | migrations for the changes of the entities: the application compares the entities with its databases and writes the migrations into the directory, one file `<timestamp>-<database name>.ts` per changed database (what `cross-env MIGRATION_GENERATE=./src/migrations npm run dev` did in lakutata 2.x); when nothing changed, nothing is generated and the command fails |
518
+ | `create <name>` | an empty migration to write by hand (`up` and `down`): `<timestamp>-<name>.ts`, with the class `<Name><timestamp>` |
519
+ | `show` | the migrations in the options of the databases, run (`[X]`) or pending (`[ ]`) |
458
520
  | `run` | the pending migrations (`up`) |
459
- | `revert` | the last migration run (`down`), one at a time; the application having several databases, `--database` is required |
521
+ | `revert` | the last migration run (`down`), one at a time; when the application has several databases, `--database` is required |
460
522
 
461
523
  | Option | |
462
524
  |---|---|
463
525
  | `--dir <directory>` | the directory of the migrations, relative to the package, `src/migrations` by default (`generate`, `create`) |
464
- | `--script <script>` | the script building and starting the application, `dev` by default |
465
- | `--package <name>` | the package of the workspace of the application, run from the workspace (the current directory by default) |
466
- | `--database <name>` | the database: the name of its Database component or provider, all by default (`MIGRATION_DATABASE`) |
467
- | `--transaction <mode>` | the transactions of the migrations run or reverted: `all` (one, by default), `each` or `none` (`MIGRATION_TRANSACTION`) |
526
+ | `--script <script>` | the script that builds and starts the application, `dev` by default |
527
+ | `--package <name>` | the package of the application in the workspace, when the command runs from elsewhere in the workspace (by default, the package in the current directory) |
528
+ | `--database <name>` | the database: the name of its Database component or provider, all of them by default (`MIGRATION_DATABASE`) |
529
+ | `--transaction <mode>` | the transactions of the migrations run or reverted: `all` (one for all), `each` or `none`; by default the `migrationsTransactionMode` of the database, else `all` (`MIGRATION_TRANSACTION`) |
468
530
  | `--fake` | mark the migrations as run or reverted without executing them (`MIGRATION_FAKE`) |
469
531
 
470
- The migrations are compiled with the application and given to the options of their database (`migrations: [...]`,
471
- run when it connects with `migrationsRun: true`). The commands fail (exit code 1) when the application has no database
472
- (but `generate`, which generates nothing), when the database given is not one of the application, and when a migration
473
- fails.
532
+ The migrations are compiled with the application and listed in the options of their database (`migrations: [...]`;
533
+ they run when it connects with `migrationsRun: true`). The commands fail (exit code 1) when the application has no
534
+ database (except `generate`, which then generates nothing), when the given database is not one of the application,
535
+ and when a migration fails.
474
536
 
475
537
  ## Languages
476
538
 
477
539
  ### `lakutata i18n <action> [locale]`
478
540
 
479
- The messages of the languages of the application (`lakutata/com/i18n`), in a directory (`--dir`, `locales` by
480
- default; several separated by commas): a file by language (`zh-CN.json`) or a directory by language (`zh-CN/`).
481
-
482
- - `lakutata i18n check`: checks the messages of the languages against the ones of the default language (`--default`,
483
- `en` by default), and fails on their errors:
484
- - errors: a syntax error of ICU MessageFormat, a key the default language does not have, an argument the default
485
- message does not have (missing when the message is formatted), a validation message of an unknown code or with the
486
- variables of another code;
487
- - warnings: a message missing (the one of a fallback is given), an argument of the default message not used, a
488
- message the same as the default one (not translated yet). `--strict` fails on them too, for the CI.
489
- - `lakutata i18n types`: declares the keys of the messages of the default language and their arguments
490
- (`--out`, `src/i18n.d.ts` by default): a key misspelled or an argument missing is then an error of the compilation.
491
- `--module @lakutata/i18n` declares them for the applications importing `@lakutata/i18n` rather than
541
+ Manage the messages of the languages of the application (`lakutata/com/i18n`), kept in a directory (`--dir`, `locales`
542
+ by default; several separated by commas) with one file (`zh-CN.json`) or one directory (`zh-CN/`) per language.
543
+
544
+ - `lakutata i18n check`: checks the messages of each language against those of the default language (`--default`,
545
+ `en` by default), and fails on errors:
546
+ - errors: an ICU MessageFormat syntax error, a key the default language does not have, an argument the default
547
+ message does not have (missing when the message is formatted), a validation message with an unknown code or with
548
+ the variables of another code;
549
+ - warnings: a missing message (the message of a fallback language is given instead), an argument of the default
550
+ message that is not used, a message identical to the default one (not translated yet). `--strict` fails on
551
+ warnings too, for CI.
552
+ - `lakutata i18n types`: declares the message keys of the default language and their arguments (`--out`,
553
+ `src/i18n.d.ts` by default), so that a misspelled key or a missing argument is a compile error.
554
+ `--module @lakutata/i18n` declares them for applications that import `@lakutata/i18n` rather than
492
555
  `lakutata/com/i18n`.
493
- - `lakutata i18n add <locale>`: adds a language, made of the messages of the default language, as a file or a directory
494
- as the default language has (its validation messages left: the language has its built-in ones). They are to be
495
- translated; `check` tells the ones which are not.
556
+ - `lakutata i18n add <locale>`: adds a language as a copy of the messages of the default language, in a file or a
557
+ directory like the default language (without its validation messages: the language has built-in ones). Translate
558
+ them; `check` reports the ones that are not translated yet.
496
559
 
497
560
  ## The language of the tool
498
561
 
499
- The help of the tool (the descriptions of its commands and of their options) and its prompts are in English, Chinese
500
- (Simplified, `zh-CN`) or Chinese (Traditional, `zh-TW`): the language of `LAKUTATA_LANG` (`LAKUTATA_LANG=zh-CN`), then
501
- of the environment (`LC_ALL`, `LC_MESSAGES`, `LANG`), then of the system; English otherwise. The names of the commands
502
- and of the options, the results and the errors are in English.
562
+ The help of the tool (the descriptions of its commands and options), its prompts, the validation errors of the
563
+ options and a few results (the plan of `lakutata version`, a declined confirmation) are in English, Simplified Chinese
564
+ (`zh-CN`) or Traditional Chinese (`zh-TW`). The language comes from `LAKUTATA_LANG` (`LAKUTATA_LANG=zh-CN`), then from
565
+ the environment (`LANGUAGE`, `LC_ALL`, `LC_MESSAGES`, `LANG`), then from the system; English is used when none of them
566
+ matches. The names of the commands and options, and the other results and errors, are in English.
503
567
 
504
568
  ## Environment
505
569
 
506
570
  | Variable | |
507
571
  |---|---|
508
- | `LAKUTATA_NPM_REGISTRY` | the npm registry of the templates (`npm_config_registry`, or `https://registry.npmjs.org`) |
509
- | `LAKUTATA_GITHUB_DOWNLOAD` | a mirror of GitHub for the `github:` templates (`https://github.com`) |
510
- | `LAKUTATA_CACHE_DIR` | the directory of the cache (`$XDG_CACHE_HOME/lakutata`, or `~/.cache/lakutata`) |
511
- | `LAKUTATA_LANG` | the language of the help and of the prompts of the tool (`zh-CN`, `zh-TW`, `en`), the one of the environment by default |
572
+ | `LAKUTATA_NPM_REGISTRY` | the npm registry of the templates (by default `npm_config_registry`, else `https://registry.npmjs.org`) |
573
+ | `LAKUTATA_GITHUB_DOWNLOAD` | a GitHub mirror for the `github:` templates (`https://github.com` by default) |
574
+ | `LAKUTATA_CACHE_DIR` | the cache directory (by default `$XDG_CACHE_HOME/lakutata`, else `~/.cache/lakutata`) |
575
+ | `LAKUTATA_LANG` | the language of the tool (`zh-CN`, `zh-TW`, `en`), by default that of the environment |
576
+
577
+ The tool is itself a lakutata application: its commands are the CLI actions of its controllers, served by the
578
+ commander adapter of the entrypoint.
579
+
580
+ ## See also
512
581
 
513
- The tool is itself a lakutata application: its commands are the CLI actions of a controller, served by the commander
514
- adapter of the entrypoint.
582
+ - The guides on the website: [Command Line Tool](https://lakutata.com/guide/Command) and
583
+ [Workspaces](https://lakutata.com/guide/Workspaces).