@lenne.tech/cli 1.50.5 → 1.51.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/claude/plugins.js +29 -16
- package/build/commands/cli/create.js +11 -3
- package/build/commands/cli/rename.js +10 -2
- package/build/commands/dev/prune.js +1 -1
- package/build/commands/dev/up.js +9 -0
- package/build/commands/directus/docker-setup.js +2 -2
- package/build/commands/directus/remove.js +1 -1
- package/build/commands/directus/typegen.js +31 -4
- package/build/commands/frontend/convert-mode.js +16 -0
- package/build/commands/frontend/nuxt.js +1 -1
- package/build/commands/fullstack/add-api.js +1 -2
- package/build/commands/fullstack/add-app.js +1 -1
- package/build/commands/fullstack/convert-mode.js +20 -0
- package/build/commands/fullstack/init.js +9 -6
- package/build/commands/git/clean.js +3 -2
- package/build/commands/git/create.js +7 -2
- package/build/commands/git/force-pull.js +4 -2
- package/build/commands/git/get.js +19 -6
- package/build/commands/git/rebase.js +13 -3
- package/build/commands/git/rename.js +5 -4
- package/build/commands/git/reset.js +18 -10
- package/build/commands/git/squash.js +4 -2
- package/build/commands/git/update.js +2 -1
- package/build/commands/npm/reinit.js +3 -3
- package/build/commands/server/add-property.js +10 -0
- package/build/commands/server/convert-mode.js +16 -0
- package/build/commands/server/permissions.js +10 -10
- package/build/commands/starter/chrome-extension.js +8 -2
- package/build/commands/typescript/create.js +3 -2
- package/build/extensions/api-mode.js +1 -1
- package/build/extensions/frontend-helper.js +25 -13
- package/build/extensions/git.js +25 -14
- package/build/extensions/server.js +14 -5
- package/build/extensions/template.js +8 -5
- package/build/extensions/typescript.js +4 -3
- package/build/lib/caddy.js +72 -2
- package/build/lib/claude-cli.js +17 -2
- package/build/lib/dev-ticket.js +8 -1
- package/build/lib/exec-args.js +117 -0
- package/build/lib/plugin-permissions.js +201 -0
- package/build/lib/plugin-utils.js +96 -36
- package/build/lib/safe-paths.js +57 -0
- package/build/lib/unknown-options.js +53 -0
- package/build/lib/workspace-integration.js +4 -2
- package/build/templates/check/check.mjs +1 -1
- package/build/templates/check/lib/audit-report.mjs +12 -9
- package/build/templates/check/lt-monorepo-pin.json +5 -5
- package/docs/commands.md +12 -0
- package/package.json +10 -10
|
@@ -56,25 +56,38 @@ function installPlugin(plugin, cli, toolbox) {
|
|
|
56
56
|
info('');
|
|
57
57
|
info(`Warning: No skills or commands found for ${plugin.pluginName}. Plugin may not be installed correctly.`);
|
|
58
58
|
}
|
|
59
|
-
// Step 3:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
permSpinner.succeed(`Permissions already configured for ${plugin.pluginName}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
permSpinner.fail(`Failed to configure permissions for ${plugin.pluginName}`);
|
|
59
|
+
// Step 3: Sync permissions. Also for a plugin that ships no rules (any more): rules an
|
|
60
|
+
// earlier run wrote for it, and the ones it names in formerPatterns, still have to go.
|
|
61
|
+
const permSpinner = spin(`Configuring permissions for ${plugin.pluginName}`);
|
|
62
|
+
const permResult = (0, plugin_utils_1.setupPermissions)(plugin, pluginContents, error);
|
|
63
|
+
if (!permResult.success) {
|
|
64
|
+
permSpinner.fail(`Failed to configure permissions for ${plugin.pluginName}`);
|
|
65
|
+
if (permResult.written.length > 0) {
|
|
73
66
|
info('');
|
|
74
|
-
info(
|
|
75
|
-
info(JSON.stringify({ permissions: { allow:
|
|
67
|
+
info(`Add manually to ${permResult.settingsPath}:`);
|
|
68
|
+
info(JSON.stringify({ permissions: { allow: permResult.written } }, null, 2));
|
|
76
69
|
}
|
|
77
70
|
}
|
|
71
|
+
else if (permResult.added.length > 0 || permResult.removed.length > 0) {
|
|
72
|
+
const changes = [
|
|
73
|
+
permResult.added.length > 0 ? `${permResult.added.length} added` : '',
|
|
74
|
+
permResult.removed.length > 0 ? `${permResult.removed.length} removed` : '',
|
|
75
|
+
].filter(Boolean);
|
|
76
|
+
permSpinner.succeed(`Permissions configured for ${plugin.pluginName} (${changes.join(', ')})`);
|
|
77
|
+
for (const rule of permResult.removed) {
|
|
78
|
+
info(` removed: ${rule}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else if (permResult.written.length > 0) {
|
|
82
|
+
permSpinner.succeed(`Permissions already configured for ${plugin.pluginName}`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
permSpinner.stop();
|
|
86
|
+
}
|
|
87
|
+
if (permResult.success && permResult.skipped.length > 0) {
|
|
88
|
+
// ${CLAUDE_PLUGIN_ROOT} cannot be scoped safely (see plugin-permissions.ts); Claude asks instead.
|
|
89
|
+
info(` not written (uses \${CLAUDE_PLUGIN_ROOT}, Claude will ask): ${permResult.skipped.length} rule(s)`);
|
|
90
|
+
}
|
|
78
91
|
// Step 4: Process post-installation requirements (for LSP plugins, etc.)
|
|
79
92
|
const postInstallResult = (0, plugin_utils_1.processPostInstall)(plugin.pluginName, toolbox);
|
|
80
93
|
return { action: pluginAction, contents: pluginContents, postInstall: postInstallResult, success: true };
|
|
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
12
13
|
/**
|
|
13
14
|
* Create a new CLI
|
|
14
15
|
*/
|
|
@@ -105,7 +106,7 @@ const NewCommand = {
|
|
|
105
106
|
// Clone git repository
|
|
106
107
|
const cloneSpinner = spin('Clone https://github.com/lenneTech/cli-starter.git');
|
|
107
108
|
try {
|
|
108
|
-
yield
|
|
109
|
+
yield (0, exec_args_1.execArgs)('git', ['clone', '--', 'https://github.com/lenneTech/cli-starter.git', projectDir]);
|
|
109
110
|
if (filesystem.isDirectory(`./${projectDir}`)) {
|
|
110
111
|
filesystem.remove(`./${projectDir}/.git`);
|
|
111
112
|
cloneSpinner.succeed('Repository cloned from https://github.com/lenneTech/cli-starter.git');
|
|
@@ -123,7 +124,7 @@ const NewCommand = {
|
|
|
123
124
|
const detectedPm = toolbox.pm.detect(projectDir);
|
|
124
125
|
const installSpinner = spin('Install packages');
|
|
125
126
|
try {
|
|
126
|
-
yield system.run(
|
|
127
|
+
yield system.run(toolbox.pm.install(detectedPm), { cwd: projectDir });
|
|
127
128
|
installSpinner.succeed('Packages installed');
|
|
128
129
|
}
|
|
129
130
|
catch (err) {
|
|
@@ -133,7 +134,14 @@ const NewCommand = {
|
|
|
133
134
|
// Rename files and data
|
|
134
135
|
const renameSpinner = spin(`Rename files & data ${link ? ' and link' : ''}`);
|
|
135
136
|
try {
|
|
136
|
-
|
|
137
|
+
// Argument list, no shell: name and author come from flags and lt.config (see exec-args.ts).
|
|
138
|
+
if ([name, author].some((value) => (0, exec_args_1.hasCmdShimHazard)(String(value)))) {
|
|
139
|
+
throw new Error('name and author must not contain ", % or line breaks on Windows');
|
|
140
|
+
}
|
|
141
|
+
const [runner, ...runArgs] = toolbox.pm.run('rename', detectedPm).split(' ');
|
|
142
|
+
yield (0, exec_args_1.spawnArgs)(runner, [...runArgs, '--', String(name), '--author', String(author), `--${link ? 'link' : 'nolink'}`], {
|
|
143
|
+
cwd: projectDir,
|
|
144
|
+
});
|
|
137
145
|
renameSpinner.succeed(`Files & data renamed${link ? ' and linked' : ''}`);
|
|
138
146
|
}
|
|
139
147
|
catch (err) {
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const path_1 = require("path");
|
|
13
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
13
14
|
/**
|
|
14
15
|
* Rename current CLI
|
|
15
16
|
*/
|
|
@@ -20,7 +21,7 @@ const NewCommand = {
|
|
|
20
21
|
name: 'rename',
|
|
21
22
|
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
23
|
// Retrieve the tools we need
|
|
23
|
-
const { npm, parameters, print: { error, info },
|
|
24
|
+
const { npm, parameters, print: { error, info }, } = toolbox;
|
|
24
25
|
// Info
|
|
25
26
|
info('Rename current CLI');
|
|
26
27
|
// Get root path
|
|
@@ -35,7 +36,14 @@ const NewCommand = {
|
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
38
|
// Run rename script
|
|
38
|
-
|
|
39
|
+
// Argument list, no shell: the arguments are passed through from the command line (see exec-args.ts).
|
|
40
|
+
const renameArgs = (parameters.array || []).map(String);
|
|
41
|
+
if (renameArgs.some((value) => (0, exec_args_1.hasCmdShimHazard)(value))) {
|
|
42
|
+
error('Arguments must not contain ", % or line breaks on Windows.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const [runner, ...runArgs] = toolbox.pm.run('rename', toolbox.pm.detect(rootPath)).split(' ');
|
|
46
|
+
yield (0, exec_args_1.spawnArgs)(runner, [...runArgs, '--', ...renameArgs], { cwd: rootPath });
|
|
39
47
|
// Exit if not running from menu
|
|
40
48
|
if (!toolbox.parameters.options.fromGluegunMenu) {
|
|
41
49
|
process.exit();
|
|
@@ -62,7 +62,7 @@ const PruneCommand = {
|
|
|
62
62
|
// driver; the api dir merely improves the driver fallback when present.
|
|
63
63
|
const observed = (0, dev_ticket_1.listDatabaseNames)(undefined, [mainLayout.apiDir, mainRepoRoot].filter(Boolean));
|
|
64
64
|
if (observed === null) {
|
|
65
|
-
warning('Could not list databases (mongosh missing or
|
|
65
|
+
warning('Could not list databases (mongosh missing, MongoDB unreachable, or mongosh slower than 10 s) — only the registry is pruned. Re-run to sweep the databases.');
|
|
66
66
|
}
|
|
67
67
|
const plan = (0, dev_prune_1.collectDevPrunePlan)({
|
|
68
68
|
loadRegistry: dev_state_1.loadRegistry,
|
package/build/commands/dev/up.js
CHANGED
|
@@ -313,6 +313,15 @@ const UpCommand = {
|
|
|
313
313
|
// that nothing listens on.
|
|
314
314
|
dbName: identity.subdomains.api ? ((_e = existingEntry === null || existingEntry === void 0 ? void 0 : existingEntry.dbName) !== null && _e !== void 0 ? _e : dbName) : undefined,
|
|
315
315
|
});
|
|
316
|
+
// A Caddyfile from before the loopback bind would keep this running stack on the LAN until
|
|
317
|
+
// its next restart, because the upsert below is never reached on this path.
|
|
318
|
+
if ((0, caddy_1.healLoopbackBind)()) {
|
|
319
|
+
const reload = yield (0, caddy_1.reloadCaddy)();
|
|
320
|
+
if (reload.ok)
|
|
321
|
+
info('Caddy now listens on this machine only (default_bind 127.0.0.1 [::1]).');
|
|
322
|
+
else
|
|
323
|
+
warning(`caddy reload failed:\n${reload.stderr}`);
|
|
324
|
+
}
|
|
316
325
|
info('Run `lt dev down` first to force a full restart.');
|
|
317
326
|
if (!parameters.options.fromGluegunMenu)
|
|
318
327
|
process.exit();
|
|
@@ -431,7 +431,7 @@ const NewCommand = {
|
|
|
431
431
|
if (instanceExists) {
|
|
432
432
|
const stopSpin = spin('Stopping existing containers');
|
|
433
433
|
try {
|
|
434
|
-
yield system.run(
|
|
434
|
+
yield system.run('docker-compose down', { cwd: directusDir });
|
|
435
435
|
stopSpin.succeed();
|
|
436
436
|
}
|
|
437
437
|
catch (stopError) {
|
|
@@ -444,7 +444,7 @@ const NewCommand = {
|
|
|
444
444
|
// Start Directus with docker-compose
|
|
445
445
|
const startSpin = spin('Starting Directus instance');
|
|
446
446
|
try {
|
|
447
|
-
yield system.run(
|
|
447
|
+
yield system.run('docker-compose up -d', { cwd: directusDir });
|
|
448
448
|
startSpin.succeed();
|
|
449
449
|
}
|
|
450
450
|
catch (startError) {
|
|
@@ -93,7 +93,7 @@ const NewCommand = {
|
|
|
93
93
|
if (filesystem.exists(composePath)) {
|
|
94
94
|
const stopSpin = spin('Stopping and removing containers');
|
|
95
95
|
try {
|
|
96
|
-
yield system.run(
|
|
96
|
+
yield system.run('docker-compose down -v', { cwd: instanceDir });
|
|
97
97
|
stopSpin.succeed();
|
|
98
98
|
}
|
|
99
99
|
catch (stopError) {
|
|
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
12
13
|
/**
|
|
13
14
|
* Generate TypeScript types from Directus collections
|
|
14
15
|
*/
|
|
@@ -134,13 +135,39 @@ const NewCommand = {
|
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
}
|
|
138
|
+
// url, token and output come from flags or lt.config, which a cloned repository can supply,
|
|
139
|
+
// and they used to sit in double quotes in a shell string, where `$(…)` ran. They are now an
|
|
140
|
+
// argument list (see exec-args.ts). On Windows the runner is a `.cmd` shim that re-parses its
|
|
141
|
+
// arguments through cmd.exe, so values that could break out there are refused first.
|
|
142
|
+
let directusUrl;
|
|
143
|
+
try {
|
|
144
|
+
const parsed = new URL(url);
|
|
145
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
146
|
+
throw new Error(parsed.protocol);
|
|
147
|
+
}
|
|
148
|
+
// The value as given: `href` would append a "/" and change the URL the generator sees.
|
|
149
|
+
directusUrl = url;
|
|
150
|
+
}
|
|
151
|
+
catch (_m) {
|
|
152
|
+
error(`Invalid Directus URL "${url}": expected http:// or https://.`);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (!/^[\w.~+/=-]+$/.test(token)) {
|
|
156
|
+
error('Invalid Directus token: only letters, digits and . _ ~ + / = - are allowed.');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if ([directusUrl, output].some((value) => (0, exec_args_1.hasCmdShimHazard)(value))) {
|
|
160
|
+
error('URL and output path must not contain ", % or line breaks on Windows.');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const [runner, ...runnerArgs] = useGlobalTypegen
|
|
164
|
+
? ['directus-sdk-typegen']
|
|
165
|
+
: toolbox.pm.exec('directus-sdk-typegen').split(' ');
|
|
137
166
|
// Generate types
|
|
138
167
|
const generateSpin = spin('Generating TypeScript types from Directus');
|
|
139
|
-
const command = useGlobalTypegen
|
|
140
|
-
? `directus-sdk-typegen -u "${url}" -t "${token}" -o "${output}"`
|
|
141
|
-
: `${toolbox.pm.exec(`directus-sdk-typegen -u "${url}" -t "${token}" -o "${output}"`)}`;
|
|
142
168
|
try {
|
|
143
|
-
|
|
169
|
+
// Asynchronous: a synchronous spawn under the spinner would block Ctrl+C until it exits.
|
|
170
|
+
yield (0, exec_args_1.spawnArgs)(runner, [...runnerArgs, '-u', directusUrl, '-t', token, '-o', output]);
|
|
144
171
|
generateSpin.succeed();
|
|
145
172
|
success(`TypeScript types generated successfully at ${output}`);
|
|
146
173
|
}
|
|
@@ -10,7 +10,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.help = void 0;
|
|
13
|
+
const fail_run_1 = require("../../lib/fail-run");
|
|
13
14
|
const frontend_framework_detection_1 = require("../../lib/frontend-framework-detection");
|
|
15
|
+
const unknown_options_1 = require("../../lib/unknown-options");
|
|
16
|
+
/** The flag names `lt fullstack convert-mode` uses for the same thing, mapped to the real ones for the error message. */
|
|
17
|
+
const RENAMED_FLAGS = {
|
|
18
|
+
'frontend-framework-upstream-branch': 'upstream-branch',
|
|
19
|
+
'frontend-framework-version': 'version',
|
|
20
|
+
};
|
|
14
21
|
/**
|
|
15
22
|
* Convert an existing frontend project between npm mode and vendor mode.
|
|
16
23
|
*
|
|
@@ -67,6 +74,15 @@ const ConvertModeCommand = {
|
|
|
67
74
|
if (toolbox.tools.helpJson(exports.help)) {
|
|
68
75
|
return;
|
|
69
76
|
}
|
|
77
|
+
// Refuse flags this command does not know: a misspelt --skip-* would otherwise be ignored
|
|
78
|
+
// and the conversion would touch what the caller asked to leave alone (see unknown-options.ts).
|
|
79
|
+
const declaredFlags = exports.help.options.map((option) => option.flag);
|
|
80
|
+
const unknownFlags = (0, unknown_options_1.findUnknownOptions)(parameters.options, declaredFlags);
|
|
81
|
+
if (unknownFlags.length > 0) {
|
|
82
|
+
error((0, unknown_options_1.formatUnknownOptions)(unknownFlags, declaredFlags, RENAMED_FLAGS));
|
|
83
|
+
(0, fail_run_1.failRun)(toolbox);
|
|
84
|
+
return 'convert-mode: unknown option';
|
|
85
|
+
}
|
|
70
86
|
const targetMode = parameters.options.to;
|
|
71
87
|
if (!targetMode || !['npm', 'vendor'].includes(targetMode)) {
|
|
72
88
|
error('Missing or invalid --to flag. Use: --to vendor or --to npm');
|
|
@@ -225,7 +225,7 @@ const NewCommand = {
|
|
|
225
225
|
// leaving pnpm-lock.yaml stale. Resync it — otherwise the first
|
|
226
226
|
// `pnpm install --frozen-lockfile` (CI, Docker build) fails with
|
|
227
227
|
// ERR_PNPM_OUTDATED_LOCKFILE and the project cannot be built/deployed.
|
|
228
|
-
yield toolbox.system.run(
|
|
228
|
+
yield toolbox.system.run('pnpm install --no-frozen-lockfile', { cwd: projectDir });
|
|
229
229
|
vendorSpinner.succeed('Frontend converted to vendor mode (app/core/)');
|
|
230
230
|
}
|
|
231
231
|
catch (err) {
|
|
@@ -300,7 +300,6 @@ const NewCommand = {
|
|
|
300
300
|
apiDir: apiDest,
|
|
301
301
|
patching,
|
|
302
302
|
projectDir,
|
|
303
|
-
system,
|
|
304
303
|
});
|
|
305
304
|
if (renameResult.error) {
|
|
306
305
|
renameSpinner.warn(`Auto-rename failed (${renameResult.error.message}). Run \`bun run rename ${projectDir}\` manually inside projects/api.`);
|
|
@@ -341,7 +340,7 @@ const NewCommand = {
|
|
|
341
340
|
const installSpinner = spin('Install workspace packages');
|
|
342
341
|
try {
|
|
343
342
|
const detectedPm = toolbox.pm.detect(workspaceDir);
|
|
344
|
-
yield system.run(
|
|
343
|
+
yield system.run(toolbox.pm.install(detectedPm), { cwd: workspaceDir });
|
|
345
344
|
installSpinner.succeed('Successfully installed workspace packages');
|
|
346
345
|
}
|
|
347
346
|
catch (err) {
|
|
@@ -268,7 +268,7 @@ const NewCommand = {
|
|
|
268
268
|
const installSpinner = spin('Install workspace packages');
|
|
269
269
|
try {
|
|
270
270
|
const detectedPm = toolbox.pm.detect(workspaceDir);
|
|
271
|
-
yield system.run(
|
|
271
|
+
yield system.run(toolbox.pm.install(detectedPm), { cwd: workspaceDir });
|
|
272
272
|
installSpinner.succeed('Successfully installed workspace packages');
|
|
273
273
|
}
|
|
274
274
|
catch (err) {
|
|
@@ -11,9 +11,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.help = void 0;
|
|
13
13
|
const path_1 = require("path");
|
|
14
|
+
const fail_run_1 = require("../../lib/fail-run");
|
|
14
15
|
const framework_detection_1 = require("../../lib/framework-detection");
|
|
15
16
|
const frontend_framework_detection_1 = require("../../lib/frontend-framework-detection");
|
|
17
|
+
const unknown_options_1 = require("../../lib/unknown-options");
|
|
16
18
|
const vendor_claude_md_1 = require("../../lib/vendor-claude-md");
|
|
19
|
+
/** The names older lenne.tech plugin docs used for this command's flags, mapped to the real ones for the error message. */
|
|
20
|
+
const RENAMED_FLAGS = {
|
|
21
|
+
'api-ref': 'framework-upstream-branch',
|
|
22
|
+
'api-version': 'framework-version',
|
|
23
|
+
'app-ref': 'frontend-framework-upstream-branch',
|
|
24
|
+
'app-version': 'frontend-framework-version',
|
|
25
|
+
'skip-api': 'skip-backend',
|
|
26
|
+
'skip-app': 'skip-frontend',
|
|
27
|
+
};
|
|
17
28
|
/**
|
|
18
29
|
* Convert both backend and frontend of a fullstack monorepo between
|
|
19
30
|
* npm mode and vendor mode in a single command.
|
|
@@ -103,6 +114,15 @@ const ConvertModeCommand = {
|
|
|
103
114
|
if (toolbox.tools.helpJson(exports.help)) {
|
|
104
115
|
return;
|
|
105
116
|
}
|
|
117
|
+
// Refuse flags this command does not know: a misspelt --skip-* would otherwise be ignored
|
|
118
|
+
// and the conversion would touch what the caller asked to leave alone (see unknown-options.ts).
|
|
119
|
+
const declaredFlags = exports.help.options.map((option) => option.flag);
|
|
120
|
+
const unknownFlags = (0, unknown_options_1.findUnknownOptions)(parameters.options, declaredFlags);
|
|
121
|
+
if (unknownFlags.length > 0) {
|
|
122
|
+
error((0, unknown_options_1.formatUnknownOptions)(unknownFlags, declaredFlags, RENAMED_FLAGS));
|
|
123
|
+
(0, fail_run_1.failRun)(toolbox);
|
|
124
|
+
return 'convert-mode: unknown option';
|
|
125
|
+
}
|
|
106
126
|
const targetMode = parameters.options.to;
|
|
107
127
|
if (!targetMode || !['npm', 'vendor'].includes(targetMode)) {
|
|
108
128
|
error('Missing or invalid --to flag. Use: --to vendor or --to npm');
|
|
@@ -16,6 +16,7 @@ const gluegun_1 = require("gluegun");
|
|
|
16
16
|
const caddy_1 = require("../../lib/caddy");
|
|
17
17
|
const dev_migrate_helper_1 = require("../../lib/dev-migrate-helper");
|
|
18
18
|
const dev_project_1 = require("../../lib/dev-project");
|
|
19
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
19
20
|
const fail_run_1 = require("../../lib/fail-run");
|
|
20
21
|
const package_name_1 = require("../../lib/package-name");
|
|
21
22
|
const vendor_claude_md_1 = require("../../lib/vendor-claude-md");
|
|
@@ -419,7 +420,7 @@ const NewCommand = {
|
|
|
419
420
|
const workspaceSpinner = spin(`Create fullstack workspace with ${frontend} in ${projectDir} with ${name} app`);
|
|
420
421
|
// Clone monorepo
|
|
421
422
|
try {
|
|
422
|
-
yield
|
|
423
|
+
yield (0, exec_args_1.execArgs)('git', ['clone', '--', 'https://github.com/lenneTech/lt-monorepo.git', projectDir]);
|
|
423
424
|
}
|
|
424
425
|
catch (err) {
|
|
425
426
|
workspaceSpinner.fail(`Failed to clone monorepo: ${err.message}`);
|
|
@@ -485,7 +486,8 @@ const NewCommand = {
|
|
|
485
486
|
(0, package_name_1.setPackageName)({ filesystem, name: projectDir, packageJsonPath: `${projectDir}/package.json` });
|
|
486
487
|
// Always initialize git
|
|
487
488
|
try {
|
|
488
|
-
|
|
489
|
+
// Argument lists, no shell: projectDir comes from --name, gitLink from a flag or lt.config.
|
|
490
|
+
yield (0, exec_args_1.execArgs)('git', ['init', '--initial-branch=dev'], { cwd: projectDir });
|
|
489
491
|
}
|
|
490
492
|
catch (err) {
|
|
491
493
|
ngBaseSpinner.fail(`Failed to initialize git: ${err.message}`);
|
|
@@ -495,7 +497,7 @@ const NewCommand = {
|
|
|
495
497
|
// Add remote if push is configured
|
|
496
498
|
if (pushToRemote && gitLink) {
|
|
497
499
|
try {
|
|
498
|
-
yield
|
|
500
|
+
yield (0, exec_args_1.execArgs)('git', ['remote', 'add', '--', 'origin', gitLink], { cwd: projectDir });
|
|
499
501
|
}
|
|
500
502
|
catch (err) {
|
|
501
503
|
ngBaseSpinner.fail(`Failed to add remote: ${err.message}`);
|
|
@@ -600,7 +602,7 @@ const NewCommand = {
|
|
|
600
602
|
}
|
|
601
603
|
const renameSpinner = spin(`Rename nest-base → ${projectDir}`);
|
|
602
604
|
try {
|
|
603
|
-
yield
|
|
605
|
+
yield (0, exec_args_1.spawnArgs)('bun', ['run', 'rename', projectDir], { cwd: apiDest });
|
|
604
606
|
renameSpinner.succeed(`Renamed nest-base → ${projectDir} in projects/api`);
|
|
605
607
|
}
|
|
606
608
|
catch (err) {
|
|
@@ -701,7 +703,8 @@ const NewCommand = {
|
|
|
701
703
|
});
|
|
702
704
|
// Create initial commit after everything is set up
|
|
703
705
|
try {
|
|
704
|
-
yield
|
|
706
|
+
yield (0, exec_args_1.execArgs)('git', ['add', '.'], { cwd: projectDir });
|
|
707
|
+
yield (0, exec_args_1.execArgs)('git', ['commit', '-m', 'Initial commit'], { cwd: projectDir });
|
|
705
708
|
}
|
|
706
709
|
catch (err) {
|
|
707
710
|
error(`Failed to create initial commit: ${err.message}`);
|
|
@@ -711,7 +714,7 @@ const NewCommand = {
|
|
|
711
714
|
// Push to remote if configured
|
|
712
715
|
if (pushToRemote) {
|
|
713
716
|
try {
|
|
714
|
-
yield
|
|
717
|
+
yield (0, exec_args_1.execArgs)('git', ['push', '-u', 'origin', 'dev'], { cwd: projectDir });
|
|
715
718
|
}
|
|
716
719
|
catch (err) {
|
|
717
720
|
error(`Failed to push to remote: ${err.message}`);
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const gluegun_1 = require("gluegun");
|
|
13
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
13
14
|
/**
|
|
14
15
|
* Removed local merged branches
|
|
15
16
|
*/
|
|
@@ -89,7 +90,7 @@ const NewCommand = {
|
|
|
89
90
|
spin: true,
|
|
90
91
|
});
|
|
91
92
|
}
|
|
92
|
-
yield
|
|
93
|
+
yield (0, exec_args_1.execArgs)('git', ['checkout', (0, exec_args_1.safeRef)(branch)]);
|
|
93
94
|
info(`Changed Branch to ${branch}`);
|
|
94
95
|
}
|
|
95
96
|
// Start timer
|
|
@@ -114,7 +115,7 @@ const NewCommand = {
|
|
|
114
115
|
info(`Deleting branches: ${branches.join(', ')}`);
|
|
115
116
|
// Delete branches
|
|
116
117
|
for (const branchToDelete of branches) {
|
|
117
|
-
yield
|
|
118
|
+
yield (0, exec_args_1.execArgs)('git', ['branch', '-d', (0, exec_args_1.safeRef)(branchToDelete)]);
|
|
118
119
|
success(`Deleted branch: ${branchToDelete}`);
|
|
119
120
|
}
|
|
120
121
|
undoSpinner.succeed();
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const path_1 = require("path");
|
|
13
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
13
14
|
/**
|
|
14
15
|
* Create a new branch
|
|
15
16
|
*/
|
|
@@ -139,7 +140,11 @@ const NewCommand = {
|
|
|
139
140
|
const timer = system.startTimer();
|
|
140
141
|
// Checkout
|
|
141
142
|
const createSpin = spin(`Create ${branch}`);
|
|
142
|
-
|
|
143
|
+
// Argument lists, no shell: both branch names come from the user or lt.config (see exec-args.ts).
|
|
144
|
+
yield (0, exec_args_1.execArgs)('git', ['fetch']);
|
|
145
|
+
yield (0, exec_args_1.execArgs)('git', ['checkout', (0, exec_args_1.safeRef)(baseBranch)]);
|
|
146
|
+
yield (0, exec_args_1.execArgs)('git', ['pull']);
|
|
147
|
+
yield (0, exec_args_1.execArgs)('git', ['checkout', '-b', (0, exec_args_1.safeRef)(branch)]);
|
|
143
148
|
createSpin.succeed();
|
|
144
149
|
// Install packages with correctly detected package manager (supports monorepo lockfiles)
|
|
145
150
|
const { path: pkgPath } = yield npm.getPackageJson();
|
|
@@ -147,7 +152,7 @@ const NewCommand = {
|
|
|
147
152
|
const projectDir = (0, path_1.dirname)(pkgPath);
|
|
148
153
|
const detectedPm = toolbox.pm.detect(projectDir);
|
|
149
154
|
const installSpin = spin(`Install packages using ${detectedPm}`);
|
|
150
|
-
yield system.run(
|
|
155
|
+
yield system.run(toolbox.pm.install(detectedPm), { cwd: projectDir });
|
|
151
156
|
installSpin.succeed();
|
|
152
157
|
}
|
|
153
158
|
// Success info
|
|
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
12
13
|
/**
|
|
13
14
|
* Pull branch with losing changes
|
|
14
15
|
*/
|
|
@@ -61,7 +62,7 @@ const NewCommand = {
|
|
|
61
62
|
// silently claimed there was nothing ahead. try/catch behaves the same on every platform.
|
|
62
63
|
let localCommits = '';
|
|
63
64
|
try {
|
|
64
|
-
localCommits = yield
|
|
65
|
+
localCommits = yield (0, exec_args_1.execArgs)('git', ['log', `origin/${(0, exec_args_1.safeRef)(branch)}..HEAD`, '--oneline']);
|
|
65
66
|
}
|
|
66
67
|
catch (_d) {
|
|
67
68
|
// ignore - no upstream ref, so nothing ahead to report
|
|
@@ -84,7 +85,8 @@ const NewCommand = {
|
|
|
84
85
|
const timer = startTimer();
|
|
85
86
|
// Reset soft
|
|
86
87
|
const pullSpinner = spin(`Fetch and pull ${branch}`);
|
|
87
|
-
yield
|
|
88
|
+
yield (0, exec_args_1.execArgs)('git', ['fetch']);
|
|
89
|
+
yield (0, exec_args_1.execArgs)('git', ['reset', `origin/${(0, exec_args_1.safeRef)(branch)}`, '--hard']);
|
|
88
90
|
pullSpinner.succeed();
|
|
89
91
|
// Success
|
|
90
92
|
success(`Force pulled ${branch} in ${helper.msToMinutesAndSeconds(timer())}m.`);
|
|
@@ -10,6 +10,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const path_1 = require("path");
|
|
13
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
14
|
+
/**
|
|
15
|
+
* Run git steps one after another, each without a shell; stops at the first failure like the
|
|
16
|
+
* former `a && b && c` chain did.
|
|
17
|
+
*/
|
|
18
|
+
function gitSteps(...steps) {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
for (const args of steps) {
|
|
21
|
+
yield (0, exec_args_1.execArgs)('git', args);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
13
25
|
/**
|
|
14
26
|
* Checkout git branch
|
|
15
27
|
*/
|
|
@@ -74,7 +86,8 @@ const NewCommand = {
|
|
|
74
86
|
success(`Branch ${branchName} found`);
|
|
75
87
|
}
|
|
76
88
|
// Checkout branch
|
|
77
|
-
|
|
89
|
+
// Argument lists, no shell: branch names come from the user and from the remote (see exec-args.ts).
|
|
90
|
+
yield (0, exec_args_1.execArgs)('git', ['checkout', (0, exec_args_1.safeRef)((yield git.getDefaultBranch()) || 'main')]);
|
|
78
91
|
let checkoutSpin;
|
|
79
92
|
// Handling for remote
|
|
80
93
|
if (remoteBranch) {
|
|
@@ -99,7 +112,7 @@ const NewCommand = {
|
|
|
99
112
|
}
|
|
100
113
|
if (mode === 'hard') {
|
|
101
114
|
const prepareSpin = spin(`Refresh ${branch}`);
|
|
102
|
-
yield
|
|
115
|
+
yield (0, exec_args_1.execArgs)('git', ['branch', '-D', (0, exec_args_1.safeRef)(branch)]);
|
|
103
116
|
removed = true;
|
|
104
117
|
prepareSpin.succeed();
|
|
105
118
|
}
|
|
@@ -111,17 +124,17 @@ const NewCommand = {
|
|
|
111
124
|
checkoutSpin = spin(`Checkout ${branch}`);
|
|
112
125
|
// Checkout remote if local branch not exists
|
|
113
126
|
if (removed || !(yield git.getBranch(branch, { local: true }))) {
|
|
114
|
-
yield
|
|
127
|
+
yield gitSteps(['fetch'], ['checkout', '--track', `origin/${(0, exec_args_1.safeRef)(branch)}`], ['reset', '--hard'], ['clean', '-fd'], ['pull']);
|
|
115
128
|
// Checkout local branch
|
|
116
129
|
}
|
|
117
130
|
else {
|
|
118
|
-
yield
|
|
131
|
+
yield gitSteps(['fetch'], ['checkout', (0, exec_args_1.safeRef)(branch)], ['reset', '--hard'], ['clean', '-fd'], ['pull']);
|
|
119
132
|
}
|
|
120
133
|
// Handling for local only
|
|
121
134
|
}
|
|
122
135
|
else if (branch) {
|
|
123
136
|
checkoutSpin = spin(`Checkout ${branch}`);
|
|
124
|
-
yield
|
|
137
|
+
yield gitSteps(['fetch'], ['checkout', (0, exec_args_1.safeRef)(branch)], ['reset', '--hard'], ['clean', '-fd']);
|
|
125
138
|
// No branch found
|
|
126
139
|
}
|
|
127
140
|
else {
|
|
@@ -136,7 +149,7 @@ const NewCommand = {
|
|
|
136
149
|
const projectDir = (0, path_1.dirname)(pkgPath);
|
|
137
150
|
const detectedPm = toolbox.pm.detect(projectDir);
|
|
138
151
|
const installSpin = spin(`Install packages using ${detectedPm}`);
|
|
139
|
-
yield system.run(
|
|
152
|
+
yield system.run(toolbox.pm.install(detectedPm), { cwd: projectDir });
|
|
140
153
|
installSpin.succeed();
|
|
141
154
|
}
|
|
142
155
|
// Init lerna projects
|
|
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const exec_args_1 = require("../../lib/exec-args");
|
|
12
13
|
/**
|
|
13
14
|
* Rebase branch
|
|
14
15
|
*/
|
|
@@ -20,7 +21,7 @@ const NewCommand = {
|
|
|
20
21
|
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
22
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
22
23
|
// Retrieve the tools we need
|
|
23
|
-
const { config, git, helper, parameters, print: { error, info, spin, success, warning }, prompt: { confirm }, system: {
|
|
24
|
+
const { config, git, helper, parameters, print: { error, info, spin, success, warning }, prompt: { confirm }, system: { startTimer }, } = toolbox;
|
|
24
25
|
// Load configuration
|
|
25
26
|
const ltConfig = config.loadConfig();
|
|
26
27
|
const configBaseBranch = (_d = (_c = (_b = (_a = ltConfig === null || ltConfig === void 0 ? void 0 : ltConfig.commands) === null || _a === void 0 ? void 0 : _a.git) === null || _b === void 0 ? void 0 : _b.rebase) === null || _c === void 0 ? void 0 : _c.base) !== null && _d !== void 0 ? _d : (_f = (_e = ltConfig === null || ltConfig === void 0 ? void 0 : ltConfig.commands) === null || _e === void 0 ? void 0 : _e.git) === null || _f === void 0 ? void 0 : _f.baseBranch;
|
|
@@ -60,7 +61,7 @@ const NewCommand = {
|
|
|
60
61
|
// what the real command will do.
|
|
61
62
|
let commitsToRebase = '';
|
|
62
63
|
try {
|
|
63
|
-
commitsToRebase = yield
|
|
64
|
+
commitsToRebase = yield (0, exec_args_1.execArgs)('git', ['log', `${(0, exec_args_1.safeRef)(baseBranchPreview)}..HEAD`, '--oneline']);
|
|
64
65
|
}
|
|
65
66
|
catch (_k) {
|
|
66
67
|
// Unknown base ref — nothing to preview, which the check below handles.
|
|
@@ -139,7 +140,16 @@ const NewCommand = {
|
|
|
139
140
|
const timer = startTimer();
|
|
140
141
|
// Rebase
|
|
141
142
|
const rebaseSpin = spin(`Set ${baseBranch} as base of ${branch}`);
|
|
142
|
-
|
|
143
|
+
// Argument lists, no shell: both names come from flags, lt.config and the remote (see exec-args.ts).
|
|
144
|
+
for (const args of [
|
|
145
|
+
['fetch'],
|
|
146
|
+
['checkout', (0, exec_args_1.safeRef)(baseBranch)],
|
|
147
|
+
['pull'],
|
|
148
|
+
['checkout', (0, exec_args_1.safeRef)(branch)],
|
|
149
|
+
['rebase', (0, exec_args_1.safeRef)(baseBranch)],
|
|
150
|
+
]) {
|
|
151
|
+
yield (0, exec_args_1.execArgs)('git', args);
|
|
152
|
+
}
|
|
143
153
|
rebaseSpin.succeed();
|
|
144
154
|
// Success
|
|
145
155
|
success(`Rebased ${branch} in ${helper.msToMinutesAndSeconds(timer())}m.`);
|