@lenne.tech/cli 1.24.1 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/commands/dev/{migrate.js → init.js} +35 -47
- package/build/commands/dev/install.js +37 -132
- package/build/commands/dev/status.js +5 -5
- package/build/commands/dev/tunnel.js +1 -1
- package/build/commands/dev/up.js +80 -13
- package/build/commands/fullstack/init.js +7 -1
- package/build/lib/dev-bootstrap.js +75 -0
- package/build/lib/dev-env.js +6 -1
- package/build/lib/dev-install-helper.js +136 -0
- package/build/lib/dev-migrate-helper.js +59 -4
- package/build/lib/dev-patches.js +66 -24
- package/build/lib/dev-process.js +39 -1
- package/build/lib/hoist-workspace-pnpm-config.js +144 -18
- package/build/lib/package-name.js +99 -0
- package/docs/commands.md +11 -5
- package/package.json +15 -8
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.hoistWorkspacePnpmConfig = hoistWorkspacePnpmConfig;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const js_yaml_1 = require("js-yaml");
|
|
4
6
|
/**
|
|
5
7
|
* pnpm workspace-scoped fields that must live at the workspace root.
|
|
6
8
|
* When present in sub-project package.json files, pnpm emits:
|
|
@@ -15,6 +17,16 @@ exports.hoistWorkspacePnpmConfig = hoistWorkspacePnpmConfig;
|
|
|
15
17
|
* and the actual dependency-resolution behavior.
|
|
16
18
|
*/
|
|
17
19
|
const WORKSPACE_SCOPED_PNPM_FIELDS = ['overrides', 'onlyBuiltDependencies', 'ignoredOptionalDependencies'];
|
|
20
|
+
/**
|
|
21
|
+
* pnpm 11 renamed `onlyBuiltDependencies` (string array) to `allowBuilds`
|
|
22
|
+
* (a `{ pkg: boolean }` map). A migrated sub-project pnpm-workspace.yaml
|
|
23
|
+
* usually carries BOTH for cross-version compatibility, but we must not
|
|
24
|
+
* rely on the array twin always being present: we normalise `allowBuilds`
|
|
25
|
+
* back into `onlyBuiltDependencies` before hoisting (see
|
|
26
|
+
* `normalizeAllowBuilds`) so the build-allowlist survives into the pnpm-10
|
|
27
|
+
* monorepo root even when the file only carries the pnpm-11 object form.
|
|
28
|
+
*/
|
|
29
|
+
const PNPM11_BUILD_KEY = 'allowBuilds';
|
|
18
30
|
/**
|
|
19
31
|
* Hoist workspace-scoped pnpm config from sub-projects into the root
|
|
20
32
|
* package.json. After this runs, sub-project package.json files no
|
|
@@ -22,6 +34,27 @@ const WORKSPACE_SCOPED_PNPM_FIELDS = ['overrides', 'onlyBuiltDependencies', 'ign
|
|
|
22
34
|
* `ignoredOptionalDependencies`, and the root package.json contains
|
|
23
35
|
* the merged union.
|
|
24
36
|
*
|
|
37
|
+
* Two sources are read per sub-project, because the two starters store
|
|
38
|
+
* their pnpm config differently:
|
|
39
|
+
*
|
|
40
|
+
* 1. `<sub>/package.json` `pnpm` block — nest-server-starter, and
|
|
41
|
+
* nuxt-base-template before its pnpm-11 migration.
|
|
42
|
+
* 2. `<sub>/pnpm-workspace.yaml` — nuxt-base-template after the
|
|
43
|
+
* migration. pnpm 11 silently ignores the `pnpm` block in
|
|
44
|
+
* package.json, so the template moved overrides into
|
|
45
|
+
* pnpm-workspace.yaml. Inside a monorepo that nested file would
|
|
46
|
+
* (a) not be hoisted by the old package.json-only logic, regressing
|
|
47
|
+
* the CVE overrides, and (b) declare a nested workspace root that
|
|
48
|
+
* conflicts with the monorepo's own pnpm-workspace.yaml. We hoist
|
|
49
|
+
* its fields into the root package.json (the lt-monorepo root pins
|
|
50
|
+
* pnpm@10 via `packageManager`, where package.json#pnpm IS honored)
|
|
51
|
+
* and remove the now-redundant nested file.
|
|
52
|
+
*
|
|
53
|
+
* Symlinked sub-projects are skipped entirely: in `--frontend-link` /
|
|
54
|
+
* `--api-link` mode `projects/app` (or `projects/api`) points at the
|
|
55
|
+
* user's local framework checkout, and stripping its config or deleting
|
|
56
|
+
* its pnpm-workspace.yaml would corrupt that source repo.
|
|
57
|
+
*
|
|
25
58
|
* Idempotent: running twice has the same effect as running once.
|
|
26
59
|
*
|
|
27
60
|
* @param options.filesystem Gluegun filesystem tool
|
|
@@ -38,36 +71,106 @@ function hoistWorkspacePnpmConfig(options) {
|
|
|
38
71
|
if (!rootPkg)
|
|
39
72
|
return;
|
|
40
73
|
(_a = rootPkg.pnpm) !== null && _a !== void 0 ? _a : (rootPkg.pnpm = {});
|
|
74
|
+
const rootPnpm = rootPkg.pnpm;
|
|
41
75
|
let rootChanged = false;
|
|
42
76
|
for (const subDir of subProjects) {
|
|
43
|
-
const
|
|
44
|
-
if (!filesystem.exists(
|
|
77
|
+
const subPath = `${projectDir}/${subDir}`;
|
|
78
|
+
if (!filesystem.exists(subPath))
|
|
45
79
|
continue;
|
|
46
|
-
|
|
47
|
-
|
|
80
|
+
// Never mutate a symlinked sub-project — it points at the user's own
|
|
81
|
+
// checkout in link mode.
|
|
82
|
+
if (isSymlink(subPath))
|
|
48
83
|
continue;
|
|
49
|
-
|
|
50
|
-
for (const field of WORKSPACE_SCOPED_PNPM_FIELDS) {
|
|
51
|
-
const subValue = subPkg.pnpm[field];
|
|
52
|
-
if (subValue === undefined)
|
|
53
|
-
continue;
|
|
54
|
-
rootPkg.pnpm[field] = mergePnpmFieldValue(field, rootPkg.pnpm[field], subValue);
|
|
84
|
+
if (hoistFromSubPackageJson({ filesystem, rootPnpm, subPath })) {
|
|
55
85
|
rootChanged = true;
|
|
56
|
-
delete subPkg.pnpm[field];
|
|
57
|
-
subChanged = true;
|
|
58
86
|
}
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
if (subPkg.pnpm && Object.keys(subPkg.pnpm).length === 0) {
|
|
62
|
-
delete subPkg.pnpm;
|
|
63
|
-
}
|
|
64
|
-
filesystem.write(subPkgPath, `${JSON.stringify(subPkg, null, 2)}\n`);
|
|
87
|
+
if (hoistFromSubWorkspaceYaml({ filesystem, rootPnpm, subPath })) {
|
|
88
|
+
rootChanged = true;
|
|
65
89
|
}
|
|
66
90
|
}
|
|
67
91
|
if (rootChanged) {
|
|
68
92
|
filesystem.write(rootPkgPath, `${JSON.stringify(rootPkg, null, 2)}\n`);
|
|
69
93
|
}
|
|
70
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Move the workspace-scoped pnpm fields from `source` into `rootPnpm`,
|
|
97
|
+
* deleting each moved field from `source`. Returns true if anything moved.
|
|
98
|
+
*/
|
|
99
|
+
function hoistFields(rootPnpm, source) {
|
|
100
|
+
let changed = false;
|
|
101
|
+
for (const field of WORKSPACE_SCOPED_PNPM_FIELDS) {
|
|
102
|
+
if (source[field] === undefined)
|
|
103
|
+
continue;
|
|
104
|
+
rootPnpm[field] = mergePnpmFieldValue(field, rootPnpm[field], source[field]);
|
|
105
|
+
delete source[field];
|
|
106
|
+
changed = true;
|
|
107
|
+
}
|
|
108
|
+
return changed;
|
|
109
|
+
}
|
|
110
|
+
/** Source 1: the sub-project's package.json `pnpm` block. */
|
|
111
|
+
function hoistFromSubPackageJson(options) {
|
|
112
|
+
const { filesystem, rootPnpm, subPath } = options;
|
|
113
|
+
const subPkgPath = `${subPath}/package.json`;
|
|
114
|
+
if (!filesystem.exists(subPkgPath))
|
|
115
|
+
return false;
|
|
116
|
+
const subPkg = filesystem.read(subPkgPath, 'json');
|
|
117
|
+
if (!(subPkg === null || subPkg === void 0 ? void 0 : subPkg.pnpm))
|
|
118
|
+
return false;
|
|
119
|
+
if (!hoistFields(rootPnpm, subPkg.pnpm))
|
|
120
|
+
return false;
|
|
121
|
+
// If the sub-project's pnpm section is now empty, drop it entirely.
|
|
122
|
+
if (Object.keys(subPkg.pnpm).length === 0) {
|
|
123
|
+
delete subPkg.pnpm;
|
|
124
|
+
}
|
|
125
|
+
filesystem.write(subPkgPath, `${JSON.stringify(subPkg, null, 2)}\n`);
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
/** Source 2: the sub-project's pnpm-workspace.yaml (pnpm-11 layout). */
|
|
129
|
+
function hoistFromSubWorkspaceYaml(options) {
|
|
130
|
+
const { filesystem, rootPnpm, subPath } = options;
|
|
131
|
+
const subWsPath = `${subPath}/pnpm-workspace.yaml`;
|
|
132
|
+
if (!filesystem.exists(subWsPath))
|
|
133
|
+
return false;
|
|
134
|
+
const raw = filesystem.read(subWsPath);
|
|
135
|
+
if (!raw)
|
|
136
|
+
return false;
|
|
137
|
+
let parsed;
|
|
138
|
+
try {
|
|
139
|
+
parsed = (0, js_yaml_1.load)(raw);
|
|
140
|
+
}
|
|
141
|
+
catch (_a) {
|
|
142
|
+
// Malformed YAML — leave it untouched rather than risk data loss.
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
146
|
+
return false;
|
|
147
|
+
const ws = parsed;
|
|
148
|
+
// Fold the pnpm-11 `allowBuilds` map into `onlyBuiltDependencies` so it is
|
|
149
|
+
// hoisted rather than discarded — even when the array twin is absent.
|
|
150
|
+
normalizeAllowBuilds(ws);
|
|
151
|
+
if (!hoistFields(rootPnpm, ws))
|
|
152
|
+
return false;
|
|
153
|
+
// A settings-only file (no `packages:`) exists solely to carry these
|
|
154
|
+
// hoisted keys — once emptied it would only declare a nested workspace
|
|
155
|
+
// root, so remove it. A file that declares `packages:` is a real (rare)
|
|
156
|
+
// nested workspace; keep it minus the hoisted keys.
|
|
157
|
+
if (Array.isArray(ws.packages) && ws.packages.length > 0) {
|
|
158
|
+
filesystem.write(subWsPath, (0, js_yaml_1.dump)(ws));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
filesystem.remove(subWsPath);
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
/** Whether `path` is a symbolic link (false on any stat error). */
|
|
166
|
+
function isSymlink(path) {
|
|
167
|
+
try {
|
|
168
|
+
return (0, fs_1.lstatSync)(path).isSymbolicLink();
|
|
169
|
+
}
|
|
170
|
+
catch (_a) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
71
174
|
/**
|
|
72
175
|
* Merge two values for a pnpm workspace-scoped field.
|
|
73
176
|
*
|
|
@@ -95,3 +198,26 @@ function mergePnpmFieldValue(field, rootValue, subValue) {
|
|
|
95
198
|
const merged = Object.assign(Object.assign({}, rootObj), subObj);
|
|
96
199
|
return Object.fromEntries(Object.entries(merged).sort(([a], [b]) => a.localeCompare(b)));
|
|
97
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* Fold a pnpm-11 `allowBuilds: { pkg: boolean }` map into the pnpm-10
|
|
203
|
+
* `onlyBuiltDependencies: string[]` form (packages whose value is `true`),
|
|
204
|
+
* unioned with any existing array, then remove the `allowBuilds` key so the
|
|
205
|
+
* redundant object form does not linger. Mutates `ws` in place.
|
|
206
|
+
*
|
|
207
|
+
* No-op when `allowBuilds` is absent or not an object map — an unexpected
|
|
208
|
+
* shape is left untouched rather than risk silent data loss.
|
|
209
|
+
*/
|
|
210
|
+
function normalizeAllowBuilds(ws) {
|
|
211
|
+
const raw = ws[PNPM11_BUILD_KEY];
|
|
212
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
213
|
+
return;
|
|
214
|
+
const allowed = Object.entries(raw)
|
|
215
|
+
.filter(([, enabled]) => enabled === true)
|
|
216
|
+
.map(([pkg]) => pkg);
|
|
217
|
+
if (allowed.length > 0) {
|
|
218
|
+
const existing = Array.isArray(ws.onlyBuiltDependencies) ? ws.onlyBuiltDependencies : [];
|
|
219
|
+
// Order here is irrelevant — mergePnpmFieldValue sorts the union on hoist.
|
|
220
|
+
ws.onlyBuiltDependencies = Array.from(new Set([...allowed, ...existing]));
|
|
221
|
+
}
|
|
222
|
+
delete ws[PNPM11_BUILD_KEY];
|
|
223
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isUnmodifiedTemplateName = isUnmodifiedTemplateName;
|
|
4
|
+
exports.renameUnmodifiedTemplatePackage = renameUnmodifiedTemplatePackage;
|
|
5
|
+
exports.setPackageName = setPackageName;
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const dev_identity_1 = require("./dev-identity");
|
|
8
|
+
/**
|
|
9
|
+
* package.json `name` values that are unchanged starter-template defaults.
|
|
10
|
+
*
|
|
11
|
+
* When a user clones a template manually (`git clone lenneTech/lt-monorepo
|
|
12
|
+
* my-project`) instead of running `lt fullstack init`, the `name` field
|
|
13
|
+
* stays at the template's default. That field is what
|
|
14
|
+
* `dev-identity#projectSlug` reads to derive `<slug>.localhost`, so every
|
|
15
|
+
* cloned project would collide on `https://lt-monorepo.localhost`.
|
|
16
|
+
*
|
|
17
|
+
* `lt fullstack init` rewrites this field already (see `setPackageName`);
|
|
18
|
+
* the detection here is the safety net for projects that bypassed init.
|
|
19
|
+
*/
|
|
20
|
+
const UNMODIFIED_TEMPLATE_NAMES = new Set(['lt-monorepo']);
|
|
21
|
+
/**
|
|
22
|
+
* True when `name` matches a known unmodified starter template default.
|
|
23
|
+
*/
|
|
24
|
+
function isUnmodifiedTemplateName(name) {
|
|
25
|
+
return typeof name === 'string' && UNMODIFIED_TEMPLATE_NAMES.has(name);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* If the package.json at `<projectRoot>/package.json` still carries an
|
|
29
|
+
* unmodified starter-template `name` (e.g. `lt-monorepo` from a raw
|
|
30
|
+
* `git clone`), rewrite it to the directory basename — which is what the
|
|
31
|
+
* user actually called their project when they cloned the folder.
|
|
32
|
+
*
|
|
33
|
+
* Returns the new name if a rewrite happened, `null` otherwise. Reasons
|
|
34
|
+
* for `null`: missing/unreadable package.json, name already custom, or the
|
|
35
|
+
* directory basename itself is in the deny list (pathological case of a
|
|
36
|
+
* fresh clone into a literal `lt-monorepo` folder — leaving the file
|
|
37
|
+
* untouched is correct behaviour there).
|
|
38
|
+
*
|
|
39
|
+
* Idempotent — safe to call from every `lt dev init` invocation.
|
|
40
|
+
*/
|
|
41
|
+
function renameUnmodifiedTemplatePackage(options) {
|
|
42
|
+
const { filesystem, projectRoot } = options;
|
|
43
|
+
const packageJsonPath = filesystem.path(projectRoot, 'package.json');
|
|
44
|
+
if (!filesystem.exists(packageJsonPath))
|
|
45
|
+
return null;
|
|
46
|
+
const pkg = filesystem.read(packageJsonPath, 'json');
|
|
47
|
+
if (!pkg || typeof pkg !== 'object' || Array.isArray(pkg))
|
|
48
|
+
return null;
|
|
49
|
+
const currentName = typeof pkg.name === 'string' ? pkg.name : null;
|
|
50
|
+
if (!isUnmodifiedTemplateName(currentName))
|
|
51
|
+
return null;
|
|
52
|
+
// Slugify the directory basename: npm names must be lowercase and
|
|
53
|
+
// URL-safe, and this keeps the rewritten value consistent with what
|
|
54
|
+
// `lt fullstack init` writes (which kebab-cases its --name arg) and
|
|
55
|
+
// with `dev-identity#projectSlug` (which slugifies whatever it reads
|
|
56
|
+
// back). Anything else would produce a slug mismatch between
|
|
57
|
+
// package.json and `<slug>.localhost`.
|
|
58
|
+
const derived = (0, dev_identity_1.slugify)((0, path_1.basename)(projectRoot));
|
|
59
|
+
if (!derived || isUnmodifiedTemplateName(derived))
|
|
60
|
+
return null;
|
|
61
|
+
const written = setPackageName({ filesystem, name: derived, packageJsonPath });
|
|
62
|
+
return written ? derived : null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Set the `name` field of a package.json on disk.
|
|
66
|
+
*
|
|
67
|
+
* Used by `lt fullstack init` to rename the cloned monorepo's root package
|
|
68
|
+
* so each project gets a unique `lt dev` slug (the slug is derived from
|
|
69
|
+
* package.json `name`; without a rename every lt-monorepo-based project would
|
|
70
|
+
* register as `lt-monorepo` and collide on `https://lt-monorepo.localhost`).
|
|
71
|
+
*
|
|
72
|
+
* IMPORTANT: this reads/writes the file as parsed JSON rather than running a
|
|
73
|
+
* string regex through `patching.update`. Gluegun's `patching.update` hands
|
|
74
|
+
* the callback a *parsed object* for any `.json` file, so a String-based
|
|
75
|
+
* `content.replace(...)` callback throws `content.replace is not a function`
|
|
76
|
+
* at runtime. Going through parsed JSON here is both correct and robust: it
|
|
77
|
+
* adds a `name` field if one is missing instead of silently no-op'ing.
|
|
78
|
+
*
|
|
79
|
+
* Idempotent: if the name already equals `name`, the file is left untouched
|
|
80
|
+
* and the function returns false.
|
|
81
|
+
*
|
|
82
|
+
* @param options.filesystem Gluegun filesystem tool
|
|
83
|
+
* @param options.name New value for the `name` field
|
|
84
|
+
* @param options.packageJsonPath Absolute path to the package.json
|
|
85
|
+
* @returns true if the file was written, false otherwise (missing/unreadable/unchanged)
|
|
86
|
+
*/
|
|
87
|
+
function setPackageName(options) {
|
|
88
|
+
const { filesystem, name, packageJsonPath } = options;
|
|
89
|
+
if (!filesystem.exists(packageJsonPath))
|
|
90
|
+
return false;
|
|
91
|
+
const pkg = filesystem.read(packageJsonPath, 'json');
|
|
92
|
+
if (!pkg || typeof pkg !== 'object' || Array.isArray(pkg))
|
|
93
|
+
return false;
|
|
94
|
+
if (pkg.name === name)
|
|
95
|
+
return false;
|
|
96
|
+
pkg.name = name;
|
|
97
|
+
filesystem.write(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
package/docs/commands.md
CHANGED
|
@@ -312,10 +312,13 @@ One-time per-machine setup. Idempotent — re-run anytime to diagnose what's mis
|
|
|
312
312
|
**Usage:**
|
|
313
313
|
```bash
|
|
314
314
|
lt dev install
|
|
315
|
+
lt dev install --skip-init # do NOT auto-run `lt dev init` afterwards
|
|
315
316
|
```
|
|
316
317
|
|
|
317
318
|
**Alias:** `lt d i`
|
|
318
319
|
|
|
320
|
+
**Auto-chaining:** when run from inside an lt-dev-capable project that is not yet initialized, `lt dev install` runs `lt dev init` for that project **afterwards**. Pass `--skip-init` to opt out. This is one hop deep and never recurses — `install` calls the init *helper*, not the init command.
|
|
321
|
+
|
|
319
322
|
**What it does:**
|
|
320
323
|
1. Verifies `caddy` is on PATH (suggests `brew install caddy` if missing).
|
|
321
324
|
2. Creates `~/.lenneTech/Caddyfile` stub if absent.
|
|
@@ -355,16 +358,19 @@ lt dev uninstall --noConfirm # skip the purge prompt (keep files)
|
|
|
355
358
|
|
|
356
359
|
---
|
|
357
360
|
|
|
358
|
-
### `lt dev
|
|
361
|
+
### `lt dev init`
|
|
359
362
|
|
|
360
|
-
|
|
363
|
+
Initialize an existing project for `lt dev` and apply idempotent env-aware patches. Safe to run multiple times; safe to run after `lt fullstack init`.
|
|
361
364
|
|
|
362
365
|
**Usage:**
|
|
363
366
|
```bash
|
|
364
|
-
lt dev
|
|
367
|
+
lt dev init
|
|
368
|
+
lt dev init --skip-install # do NOT auto-run `lt dev install` first
|
|
365
369
|
```
|
|
366
370
|
|
|
367
|
-
**Alias:** `lt d m`
|
|
371
|
+
**Alias:** `lt d init`, `lt d migrate`, `lt d m` (`migrate` is the former name, kept for backwards compatibility)
|
|
372
|
+
|
|
373
|
+
**Auto-chaining:** if the machine has not been prepared yet (no `lt dev install` has run), `lt dev init` runs the install step **first**, then initializes the project. Pass `--skip-install` to opt out. This is one hop deep and never recurses — `init` calls the install *helper*, not the install command.
|
|
368
374
|
|
|
369
375
|
**What it does:**
|
|
370
376
|
1. Detects the workspace layout (monorepo `projects/api`+`projects/app`, or standalone).
|
|
@@ -538,7 +544,7 @@ lt dev test -- --ui spec.ts # everything after `--` is forwarded to playwri
|
|
|
538
544
|
| `LT_DEV_ACTIVE`, `LT_DEV_DB_NAME` | Marker keys for consumers |
|
|
539
545
|
| `NODE_EXTRA_CA_CERTS` | Path to Caddy's root CA cert (auto-detected) |
|
|
540
546
|
|
|
541
|
-
`lt dev
|
|
547
|
+
`lt dev init` injects a tiny `// >>> lt-dev:bridge >>>` block at the top of `playwright.config.ts` that loads this file at config-load time — making Playwright (CLI, IDE, VS Code extension) automatically use the `lt dev` URLs and trust the local CA, without inheriting the parent shell.
|
|
542
548
|
|
|
543
549
|
`lt dev down` removes the bridge file so subsequent runs without `lt dev up` fall back cleanly to the classic `localhost:3000`/`localhost:3001` defaults.
|
|
544
550
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "lenne.Tech CLI: lt",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lenne.Tech",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
"test:vendor-init": "bash scripts/test-vendor-init.sh",
|
|
33
33
|
"test:frontend-vendor-init": "bash scripts/test-frontend-vendor-init.sh",
|
|
34
34
|
"test:incremental-fullstack": "bash scripts/test-incremental-fullstack.sh",
|
|
35
|
+
"test:manual": "jest --testMatch '<rootDir>/*.manual.ts' --testTimeout=60000",
|
|
36
|
+
"test:e2e:service": "jest --testMatch '<rootDir>/dev-service-e2e.manual.ts' --testTimeout=60000",
|
|
35
37
|
"format": "prettier --write 'src/**/*.{js,ts,tsx,json}' '!src/templates/**/*'",
|
|
36
38
|
"lint": "eslint './src/**/*.{ts,js,vue}'",
|
|
37
39
|
"lint:fix": "eslint './src/**/*.{ts,js,vue}' --fix",
|
|
@@ -58,9 +60,9 @@
|
|
|
58
60
|
"bin"
|
|
59
61
|
],
|
|
60
62
|
"dependencies": {
|
|
61
|
-
"@aws-sdk/client-s3": "3.
|
|
63
|
+
"@aws-sdk/client-s3": "3.1053.0",
|
|
62
64
|
"@lenne.tech/cli-plugin-helper": "0.0.14",
|
|
63
|
-
"axios": "1.16.
|
|
65
|
+
"axios": "1.16.1",
|
|
64
66
|
"bcrypt": "6.0.0",
|
|
65
67
|
"defuddle": "0.18.1",
|
|
66
68
|
"glob": "13.0.6",
|
|
@@ -70,7 +72,7 @@
|
|
|
70
72
|
"jsdom": "29.1.1",
|
|
71
73
|
"lodash": "4.18.1",
|
|
72
74
|
"open": "11.0.0",
|
|
73
|
-
"playwright-core": "1.
|
|
75
|
+
"playwright-core": "1.60.0",
|
|
74
76
|
"ts-morph": "28.0.0",
|
|
75
77
|
"ts-node": "10.9.2",
|
|
76
78
|
"turndown": "7.2.4",
|
|
@@ -85,7 +87,7 @@
|
|
|
85
87
|
"@types/js-yaml": "4.0.9",
|
|
86
88
|
"@types/jsdom": "28.0.1",
|
|
87
89
|
"@types/lodash": "4.17.24",
|
|
88
|
-
"@types/node": "25.
|
|
90
|
+
"@types/node": "25.9.1",
|
|
89
91
|
"@types/turndown": "5.0.6",
|
|
90
92
|
"ejs": "5.0.2",
|
|
91
93
|
"eslint": "9.39.4",
|
|
@@ -94,18 +96,23 @@
|
|
|
94
96
|
"prettier": "3.8.3",
|
|
95
97
|
"rimraf": "6.1.3",
|
|
96
98
|
"standard-version": "9.5.0",
|
|
97
|
-
"ts-jest": "29.4.
|
|
99
|
+
"ts-jest": "29.4.11"
|
|
98
100
|
},
|
|
99
101
|
"//overrides": {
|
|
100
|
-
"
|
|
102
|
+
"brace-expansion@5.0.2 - 5.0.5": "Security fix: GHSA-jxxr-4gwj-5jf2 (large numeric range defeats max DoS protection) in brace-expansion 5.0.2-5.0.5 - transitive via minimatch under glob, @ts-morph/common, @typescript-eslint/typescript-estree. Remove once those parents resolve minimatch to a brace-expansion >=5.0.6.",
|
|
103
|
+
"semver@*": "Force latest semver 7.x across all sub-deps; gluegun@5.2.2 pins semver@7.7.0 which is stale - remove once gluegun updates its dep."
|
|
101
104
|
},
|
|
102
105
|
"overrides": {
|
|
103
|
-
"
|
|
106
|
+
"brace-expansion@5.0.2 - 5.0.5": "5.0.6",
|
|
107
|
+
"semver@*": "7.8.1"
|
|
104
108
|
},
|
|
105
109
|
"jest": {
|
|
106
110
|
"testEnvironment": "node",
|
|
107
111
|
"rootDir": "__tests__",
|
|
108
112
|
"testTimeout": 60000,
|
|
113
|
+
"testMatch": [
|
|
114
|
+
"<rootDir>/*.test.ts"
|
|
115
|
+
],
|
|
109
116
|
"transform": {
|
|
110
117
|
"^.+\\.tsx?$": [
|
|
111
118
|
"ts-jest",
|