n8nac 2.3.5 → 2.3.6
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 +4 -24
- package/dist/commands/base.d.ts.map +1 -1
- package/dist/commands/base.js +36 -90
- package/dist/commands/base.js.map +1 -1
- package/dist/commands/update-ai.d.ts.map +1 -1
- package/dist/commands/update-ai.js +27 -12
- package/dist/commands/update-ai.js.map +1 -1
- package/dist/index.js +19 -271
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +1 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +0 -1
- package/dist/lib.js.map +1 -1
- package/dist/services/config-service.d.ts +1 -155
- package/dist/services/config-service.d.ts.map +1 -1
- package/dist/services/config-service.js +53 -992
- package/dist/services/config-service.js.map +1 -1
- package/package.json +2 -2
- package/dist/services/workspace-migration-facade.d.ts +0 -21
- package/dist/services/workspace-migration-facade.d.ts.map +0 -1
- package/dist/services/workspace-migration-facade.js +0 -28
- package/dist/services/workspace-migration-facade.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -19,7 +19,6 @@ import { parsePositiveIntegerOption } from './utils/option-parsers.js';
|
|
|
19
19
|
import { spawn } from 'child_process';
|
|
20
20
|
import { createN8nManagerFacade } from '@n8n-as-code/manager-adapter';
|
|
21
21
|
import { ConfigService } from './services/config-service.js';
|
|
22
|
-
import { WorkspaceMigrationFacade } from './services/workspace-migration-facade.js';
|
|
23
22
|
import { N8N_FACADE_SETUP_MODES, isN8nFacadeSetupMode, } from '@n8n-as-code/workflow-core';
|
|
24
23
|
import { createTelemetryClient, getTelemetryStatus, setTelemetryEnabled, classifyTelemetryError, shouldShowTelemetryNotice, markTelemetryNoticeShown, } from '@n8n-as-code/telemetry';
|
|
25
24
|
async function readSecretFromStdin() {
|
|
@@ -77,88 +76,12 @@ function hideCommand(command) {
|
|
|
77
76
|
command.hidden = true;
|
|
78
77
|
return command;
|
|
79
78
|
}
|
|
80
|
-
function formatLegacyMigrationResult(result) {
|
|
81
|
-
if (result.status === 'not-needed') {
|
|
82
|
-
return chalk.green(`No legacy n8nac workspace config detected at ${result.configPath}.`);
|
|
83
|
-
}
|
|
84
|
-
const plan = result.plan;
|
|
85
|
-
const instanceLines = plan.instances.length > 0
|
|
86
|
-
? plan.instances.map((instance) => `- ${instance.name} (${instance.id})${instance.host ? ` -> ${instance.host}` : ''}${instance.hasApiKey ? ' [API key found]' : ''}`)
|
|
87
|
-
: ['- No instances found in the legacy config.'];
|
|
88
|
-
const workspaceLines = [
|
|
89
|
-
plan.workspace.syncFolder ? `- Sync folder: ${plan.workspace.syncFolder}` : undefined,
|
|
90
|
-
plan.workspace.projectName || plan.workspace.projectId ? `- Project: ${plan.workspace.projectName || plan.workspace.projectId}` : undefined,
|
|
91
|
-
plan.activeInstanceId ? `- Workspace-pinned instance: ${plan.activeInstanceId}` : undefined,
|
|
92
|
-
].filter(Boolean);
|
|
93
|
-
const header = result.status === 'dry-run'
|
|
94
|
-
? chalk.yellow('Legacy n8nac workspace config detected. No files changed.')
|
|
95
|
-
: chalk.green('Legacy n8nac workspace config migrated.');
|
|
96
|
-
const footer = result.status === 'dry-run'
|
|
97
|
-
? ['Run `n8nac workspace migrate-v1 --write` to migrate and create a backup first.']
|
|
98
|
-
: [`Backup: ${result.backupPath}`, 'Run `n8nac workspace status --json` to verify the resolved context.'];
|
|
99
|
-
return [
|
|
100
|
-
header,
|
|
101
|
-
`Config: ${plan.configPath}`,
|
|
102
|
-
plan.version ? `Legacy version: ${plan.version}` : undefined,
|
|
103
|
-
'',
|
|
104
|
-
'Instances:',
|
|
105
|
-
...instanceLines,
|
|
106
|
-
workspaceLines.length ? '' : undefined,
|
|
107
|
-
workspaceLines.length ? 'Workspace overrides:' : undefined,
|
|
108
|
-
...workspaceLines,
|
|
109
|
-
'',
|
|
110
|
-
'Notes:',
|
|
111
|
-
...plan.warnings.map((warning) => `- ${warning}`),
|
|
112
|
-
'',
|
|
113
|
-
...footer,
|
|
114
|
-
].filter(Boolean).join('\n');
|
|
115
|
-
}
|
|
116
|
-
function formatWorkspaceMigrationReport(report) {
|
|
117
|
-
if (report.status === 'not-needed') {
|
|
118
|
-
return chalk.green(`No n8n workspace migration required at ${report.configPath}.`);
|
|
119
|
-
}
|
|
120
|
-
const header = report.status === 'dry-run'
|
|
121
|
-
? chalk.yellow('n8n workspace migration required. No files changed.')
|
|
122
|
-
: chalk.green('n8n workspace migration completed.');
|
|
123
|
-
const footer = report.status === 'dry-run'
|
|
124
|
-
? ['Run `n8nac workspace migrate --write` to apply the migration.']
|
|
125
|
-
: [
|
|
126
|
-
report.backupPath ? `Backup: ${report.backupPath}` : undefined,
|
|
127
|
-
`Migrated environments: ${report.migratedEnvironmentIds?.length || 0}`,
|
|
128
|
-
`Removed global external instances: ${report.deletedGlobalInstanceIds?.length || 0}`,
|
|
129
|
-
'Run `n8nac workspace status --json` to verify the resolved context.',
|
|
130
|
-
].filter(Boolean);
|
|
131
|
-
return [
|
|
132
|
-
header,
|
|
133
|
-
`Config: ${report.configPath}`,
|
|
134
|
-
'',
|
|
135
|
-
'Migration operations:',
|
|
136
|
-
...report.operations.map((operation) => `- ${operation.label}: ${operation.instanceCount} instance${operation.instanceCount === 1 ? '' : 's'}`),
|
|
137
|
-
report.warnings.length ? '' : undefined,
|
|
138
|
-
report.warnings.length ? 'Notes:' : undefined,
|
|
139
|
-
...report.warnings.map((warning) => `- ${warning}`),
|
|
140
|
-
'',
|
|
141
|
-
...footer,
|
|
142
|
-
].filter(Boolean).join('\n');
|
|
143
|
-
}
|
|
144
79
|
function redactResolvedEnvironment(environment) {
|
|
145
80
|
if (!environment)
|
|
146
81
|
return environment;
|
|
147
82
|
const { apiKey: _apiKey, ...safeEnvironment } = environment;
|
|
148
83
|
return safeEnvironment;
|
|
149
84
|
}
|
|
150
|
-
function abortIfWorkspaceMigrationRequired(configService, options = {}) {
|
|
151
|
-
const payload = new WorkspaceMigrationFacade({ configService }).inspect();
|
|
152
|
-
if (!payload)
|
|
153
|
-
return;
|
|
154
|
-
printJsonOrText(options, payload, [
|
|
155
|
-
chalk.yellow('n8n workspace migration required before environment commands can run.'),
|
|
156
|
-
`Config: ${payload.configPath}`,
|
|
157
|
-
'Run `n8nac workspace migrate --json` to inspect it.',
|
|
158
|
-
'After explicit confirmation, run `n8nac workspace migrate --write` to apply it.',
|
|
159
|
-
].join('\n'));
|
|
160
|
-
process.exit(1);
|
|
161
|
-
}
|
|
162
85
|
/**
|
|
163
86
|
* Get version from package.json
|
|
164
87
|
*/
|
|
@@ -217,11 +140,11 @@ const getFirstPositionalToken = (args, startIndex = 0) => {
|
|
|
217
140
|
if (token === '--') {
|
|
218
141
|
return args[index + 1];
|
|
219
142
|
}
|
|
220
|
-
if (token === '--
|
|
143
|
+
if (token === '--env' || token === '--environment') {
|
|
221
144
|
index += 1;
|
|
222
145
|
continue;
|
|
223
146
|
}
|
|
224
|
-
if (token.startsWith('--
|
|
147
|
+
if (token.startsWith('--env=') || token.startsWith('--environment=')) {
|
|
225
148
|
continue;
|
|
226
149
|
}
|
|
227
150
|
if (token.startsWith('-')) {
|
|
@@ -338,8 +261,7 @@ program
|
|
|
338
261
|
.description('N8N Sync Command Line Interface - Manage n8n workflows as code')
|
|
339
262
|
.version(getVersion())
|
|
340
263
|
.option('--env <name>', 'Target a specific workspace environment by name or ID')
|
|
341
|
-
.addOption(new Option('--environment <name>', 'Alias for --env').hideHelp())
|
|
342
|
-
.addOption(new Option('--instance <name>', 'Deprecated; use --env').hideHelp());
|
|
264
|
+
.addOption(new Option('--environment <name>', 'Alias for --env').hideHelp());
|
|
343
265
|
// Inject --env into the environment only for the lifetime of the command action
|
|
344
266
|
// so BaseCommand can pick it up without leaking process-wide state afterwards.
|
|
345
267
|
let previousEnvironmentEnv;
|
|
@@ -410,7 +332,7 @@ telemetryProgram.command('disable')
|
|
|
410
332
|
printJsonOrText(options, status, chalk.green('Anonymous telemetry disabled.'));
|
|
411
333
|
});
|
|
412
334
|
const workspaceProgram = program.command('workspace')
|
|
413
|
-
.description('Inspect
|
|
335
|
+
.description('Inspect n8n workspace configuration');
|
|
414
336
|
workspaceProgram.command('status')
|
|
415
337
|
.alias('get')
|
|
416
338
|
.description('Show the effective n8n workspace context resolved by the backend')
|
|
@@ -418,179 +340,24 @@ workspaceProgram.command('status')
|
|
|
418
340
|
.action(async (options) => {
|
|
419
341
|
const configService = new ConfigService();
|
|
420
342
|
const selectedEnvironment = process.env.N8NAC_ENVIRONMENT?.trim() || undefined;
|
|
421
|
-
const migration = new WorkspaceMigrationFacade({ configService }).inspect();
|
|
422
|
-
if (migration) {
|
|
423
|
-
printJsonOrText(options, migration, [
|
|
424
|
-
chalk.yellow('n8n workspace migration required.'),
|
|
425
|
-
`Config: ${migration.configPath}`,
|
|
426
|
-
'Run `n8nac workspace migrate --json` to inspect it.',
|
|
427
|
-
'After confirmation, run `n8nac workspace migrate --write` to apply it.',
|
|
428
|
-
].join('\n'));
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
343
|
const workspaceConfig = configService.getWorkspaceConfig();
|
|
432
344
|
const resolvedEnvironment = selectedEnvironment
|
|
433
345
|
? await configService.prepareEnvironment(selectedEnvironment)
|
|
434
|
-
:
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
} })()
|
|
441
|
-
: undefined;
|
|
346
|
+
: await (async () => { try {
|
|
347
|
+
return await configService.prepareEnvironment();
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return undefined;
|
|
351
|
+
} })();
|
|
442
352
|
printJsonOrText(options, resolvedEnvironment ? { ...workspaceConfig, selectedEnvironment: redactResolvedEnvironment(resolvedEnvironment) } : workspaceConfig, [
|
|
443
353
|
chalk.cyan('\nEffective n8n workspace context:\n'),
|
|
444
354
|
workspaceConfig.activeEnvironmentId ? `Env : ${chalk.bold(resolvedEnvironment?.environmentName || workspaceConfig.activeEnvironment?.name || workspaceConfig.activeEnvironmentId)}` : undefined,
|
|
445
355
|
`Instance: ${chalk.bold(resolvedEnvironment?.activeInstanceName || workspaceConfig.activeInstanceId || '(none)')}`,
|
|
446
356
|
`Project : ${chalk.bold(resolvedEnvironment?.projectName || workspaceConfig.projectName || workspaceConfig.projectId || '(none)')}`,
|
|
447
|
-
`Workflows path: ${chalk.bold(resolvedEnvironment?.workflowsPath || workspaceConfig.workflowsPath ||
|
|
357
|
+
`Workflows path: ${chalk.bold(resolvedEnvironment?.workflowsPath || workspaceConfig.workflowsPath || '(none)')}`,
|
|
448
358
|
'',
|
|
449
359
|
].filter(Boolean).join('\n'));
|
|
450
360
|
});
|
|
451
|
-
workspaceProgram.command('migrate')
|
|
452
|
-
.description('Inspect or run required workspace migrations')
|
|
453
|
-
.option('--write', 'Apply the migration. Without this flag, the command only reports what would change.')
|
|
454
|
-
.option('--json', 'Output migration result as JSON')
|
|
455
|
-
.action(async (options) => {
|
|
456
|
-
const report = await new WorkspaceMigrationFacade().migrate({ write: Boolean(options.write) });
|
|
457
|
-
printJsonOrText(options, report, formatWorkspaceMigrationReport(report));
|
|
458
|
-
});
|
|
459
|
-
workspaceProgram.command('migrate-v1')
|
|
460
|
-
.description('Inspect or migrate a legacy v1/v2 n8nac-config.json into the v2 manager-backed storage model')
|
|
461
|
-
.option('--write', 'Apply the migration. Without this flag, the command only reports what would change.')
|
|
462
|
-
.option('--json', 'Output migration result as JSON')
|
|
463
|
-
.action((options) => {
|
|
464
|
-
const configService = new ConfigService();
|
|
465
|
-
const result = configService.migrateLegacyWorkspaceConfig({ write: Boolean(options.write) });
|
|
466
|
-
printJsonOrText(options, result, formatLegacyMigrationResult(result));
|
|
467
|
-
});
|
|
468
|
-
hideCommand(workspaceProgram.command('pin-instance'))
|
|
469
|
-
.description('Pin the effective n8n instance for this workspace')
|
|
470
|
-
.requiredOption('--instance-id <id>', 'Global n8n instance ID to pin')
|
|
471
|
-
.option('--json', 'Output workspace config as JSON')
|
|
472
|
-
.action((options) => {
|
|
473
|
-
const configService = new ConfigService();
|
|
474
|
-
const instance = configService.pinWorkspaceInstance(options.instanceId);
|
|
475
|
-
const workspaceConfig = configService.getWorkspaceConfig();
|
|
476
|
-
printJsonOrText(options, workspaceConfig, chalk.green(`✔ Workspace pinned to n8n instance: ${instance.name}`));
|
|
477
|
-
});
|
|
478
|
-
hideCommand(workspaceProgram.command('clear-instance'))
|
|
479
|
-
.description('Clear the workspace n8n instance pin and fall back to the global active instance')
|
|
480
|
-
.option('--json', 'Output workspace config as JSON')
|
|
481
|
-
.action((options) => {
|
|
482
|
-
const configService = new ConfigService();
|
|
483
|
-
configService.clearWorkspaceInstanceOverride();
|
|
484
|
-
const workspaceConfig = configService.getWorkspaceConfig();
|
|
485
|
-
printJsonOrText(options, workspaceConfig, chalk.green('✔ Workspace instance override cleared.'));
|
|
486
|
-
});
|
|
487
|
-
hideCommand(workspaceProgram.command('set-sync-folder'))
|
|
488
|
-
.description('Set the n8n sync folder override for this workspace')
|
|
489
|
-
.argument('<path>', 'Workspace sync folder path')
|
|
490
|
-
.option('--json', 'Output workspace config as JSON')
|
|
491
|
-
.action((syncFolder, options) => {
|
|
492
|
-
const configService = new ConfigService();
|
|
493
|
-
configService.setWorkspaceSyncFolder(syncFolder);
|
|
494
|
-
const workspaceConfig = configService.getWorkspaceConfig();
|
|
495
|
-
printJsonOrText(options, workspaceConfig, chalk.green(`✔ Workspace sync folder set to: ${syncFolder}`));
|
|
496
|
-
});
|
|
497
|
-
hideCommand(workspaceProgram.command('clear-sync-folder'))
|
|
498
|
-
.description('Clear the workspace n8n sync folder override and fall back to the global default')
|
|
499
|
-
.option('--json', 'Output workspace config as JSON')
|
|
500
|
-
.action((options) => {
|
|
501
|
-
const configService = new ConfigService();
|
|
502
|
-
configService.clearWorkspaceSyncFolderOverride();
|
|
503
|
-
const workspaceConfig = configService.getWorkspaceConfig();
|
|
504
|
-
printJsonOrText(options, workspaceConfig, chalk.green('✔ Workspace sync folder override cleared.'));
|
|
505
|
-
});
|
|
506
|
-
hideCommand(workspaceProgram.command('set-project'))
|
|
507
|
-
.description('Set the n8n project override for this workspace from known project values')
|
|
508
|
-
.requiredOption('--project-id <id>', 'n8n project ID to store in this workspace')
|
|
509
|
-
.requiredOption('--project-name <name>', 'n8n project display name to store in this workspace')
|
|
510
|
-
.option('--json', 'Output workspace config as JSON')
|
|
511
|
-
.action((options) => {
|
|
512
|
-
const configService = new ConfigService();
|
|
513
|
-
configService.setWorkspaceProject({
|
|
514
|
-
projectId: options.projectId,
|
|
515
|
-
projectName: options.projectName,
|
|
516
|
-
});
|
|
517
|
-
const workspaceConfig = configService.getWorkspaceConfig();
|
|
518
|
-
printJsonOrText(options, workspaceConfig, chalk.green(`✔ Workspace project set to: ${options.projectName}`));
|
|
519
|
-
});
|
|
520
|
-
hideCommand(workspaceProgram.command('clear-project'))
|
|
521
|
-
.description('Clear the workspace n8n project override and fall back to the instance default project')
|
|
522
|
-
.option('--json', 'Output workspace config as JSON')
|
|
523
|
-
.action((options) => {
|
|
524
|
-
const configService = new ConfigService();
|
|
525
|
-
configService.clearWorkspaceProjectOverride();
|
|
526
|
-
const workspaceConfig = configService.getWorkspaceConfig();
|
|
527
|
-
printJsonOrText(options, workspaceConfig, chalk.green('✔ Workspace project override cleared.'));
|
|
528
|
-
});
|
|
529
|
-
const environmentTargetProgram = hideCommand(program.command('instance-target')
|
|
530
|
-
.alias('target')
|
|
531
|
-
.description('Compatibility: manage low-level workspace targets used by environments'));
|
|
532
|
-
environmentTargetProgram.command('list')
|
|
533
|
-
.description('List workspace instance targets')
|
|
534
|
-
.option('--json', 'Output targets as JSON')
|
|
535
|
-
.action((options) => {
|
|
536
|
-
const configService = new ConfigService();
|
|
537
|
-
const targets = configService.listInstanceTargets();
|
|
538
|
-
printJsonOrText(options, targets, targets.length
|
|
539
|
-
? targets.map((target) => `${target.id}\t${target.name}\t${target.kind}\t${target.kind === 'managed-instance' ? target.managedInstanceId : target.url}`).join('\n')
|
|
540
|
-
: 'No workspace instance targets configured.');
|
|
541
|
-
});
|
|
542
|
-
environmentTargetProgram.command('add')
|
|
543
|
-
.description('Compatibility: add a low-level workspace target. Prefer `n8nac env add --base-url ...`.')
|
|
544
|
-
.argument('<name>', 'Target display name')
|
|
545
|
-
.option('--id <id>', 'Stable target ID')
|
|
546
|
-
.option('--instance-ref <id>', 'Global n8n-manager instance ID to reference')
|
|
547
|
-
.option('--base-url <url>', 'Public externalInstance n8n URL to embed without secrets')
|
|
548
|
-
.option('--description <text>', 'Target description')
|
|
549
|
-
.option('--json', 'Output target as JSON')
|
|
550
|
-
.action(async (name, options) => {
|
|
551
|
-
const configService = new ConfigService();
|
|
552
|
-
const managedInstanceId = options.managedInstanceId || options.instanceRef;
|
|
553
|
-
const url = options.url || options.baseUrl;
|
|
554
|
-
if (managedInstanceId) {
|
|
555
|
-
const instance = (await createManagerFacadeFromOptions({}).listInstances()).find((item) => item.id === managedInstanceId);
|
|
556
|
-
if (!instance)
|
|
557
|
-
throw new Error(`Unknown managed local n8n instance: ${managedInstanceId}`);
|
|
558
|
-
if (instance.mode !== 'managed-local-docker') {
|
|
559
|
-
throw new Error(`Instance "${instance.name || instance.id}" is not managed locally. Prefer \`n8nac env add <name> --base-url <url> --workflows-path workflows/<name>\` for remote n8n environments.`);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
const target = configService.addInstanceTarget({
|
|
563
|
-
name,
|
|
564
|
-
id: options.id,
|
|
565
|
-
managedInstanceId,
|
|
566
|
-
url,
|
|
567
|
-
description: options.description,
|
|
568
|
-
});
|
|
569
|
-
printJsonOrText(options, target, chalk.green(`✔ Workspace instance target added: ${target.name}`));
|
|
570
|
-
});
|
|
571
|
-
environmentTargetProgram.command('update')
|
|
572
|
-
.description('Update a workspace instance target')
|
|
573
|
-
.argument('<name-or-id>', 'Target name or ID')
|
|
574
|
-
.option('--name <name>', 'New display name')
|
|
575
|
-
.option('--instance-ref <id>', 'New global n8n-manager instance reference for managedInstance targets')
|
|
576
|
-
.option('--base-url <url>', 'New public URL for externalInstance targets')
|
|
577
|
-
.option('--description <text>', 'New description')
|
|
578
|
-
.option('--json', 'Output target as JSON')
|
|
579
|
-
.action((nameOrId, options) => {
|
|
580
|
-
const configService = new ConfigService();
|
|
581
|
-
const target = configService.updateInstanceTarget(nameOrId, options);
|
|
582
|
-
printJsonOrText(options, target, chalk.green(`✔ Workspace instance target updated: ${target.name}`));
|
|
583
|
-
});
|
|
584
|
-
environmentTargetProgram.command('remove')
|
|
585
|
-
.alias('rm')
|
|
586
|
-
.description('Remove an unused workspace instance target')
|
|
587
|
-
.argument('<name-or-id>', 'Target name or ID')
|
|
588
|
-
.option('--json', 'Output removed target as JSON')
|
|
589
|
-
.action((nameOrId, options) => {
|
|
590
|
-
const configService = new ConfigService();
|
|
591
|
-
const target = configService.removeInstanceTarget(nameOrId);
|
|
592
|
-
printJsonOrText(options, target, chalk.green(`✔ Workspace instance target removed: ${target.name}`));
|
|
593
|
-
});
|
|
594
361
|
const environmentProgram = program.command('env')
|
|
595
362
|
.alias('environment')
|
|
596
363
|
.description('Manage n8n workspace environments');
|
|
@@ -599,7 +366,6 @@ environmentProgram.command('list')
|
|
|
599
366
|
.option('--json', 'Output environments as JSON')
|
|
600
367
|
.action((options) => {
|
|
601
368
|
const configService = new ConfigService();
|
|
602
|
-
abortIfWorkspaceMigrationRequired(configService, options);
|
|
603
369
|
const config = configService.getWorkspaceConfig();
|
|
604
370
|
const environments = configService.listEnvironments().map((environment) => {
|
|
605
371
|
const resolved = (() => { try {
|
|
@@ -617,7 +383,7 @@ environmentProgram.command('list')
|
|
|
617
383
|
environment.name,
|
|
618
384
|
environment.resolved?.environmentTargetName || environment.environmentTargetId,
|
|
619
385
|
environment.projectName || environment.projectId || '(no project)',
|
|
620
|
-
environment.workflowsPath
|
|
386
|
+
environment.workflowsPath,
|
|
621
387
|
].join('\t')).join('\n')
|
|
622
388
|
: 'No workspace environments configured.');
|
|
623
389
|
});
|
|
@@ -626,14 +392,11 @@ environmentProgram.command('add')
|
|
|
626
392
|
.argument('<name>', 'Environment display name')
|
|
627
393
|
.option('--base-url <url>', 'Remote n8n URL to store in this workspace environment')
|
|
628
394
|
.option('--managed-instance <id>', 'Local managed n8n instance ID to reference')
|
|
629
|
-
.option('--instance-target <name-or-id>', 'Compatibility: workspace target name or ID')
|
|
630
395
|
.option('--api-key <key>', 'Store a local API key for --base-url without committing it')
|
|
631
396
|
.option('--api-key-stdin', 'Read the local API key for --base-url from stdin')
|
|
632
397
|
.option('--project-id <id>', 'n8n project ID')
|
|
633
398
|
.option('--project-name <name>', 'n8n project display name')
|
|
634
399
|
.option('--workflows-path <path>', 'Directory that contains this environment workflows')
|
|
635
|
-
.option('--workflow-dir <path>', 'Compatibility alias for --workflows-path')
|
|
636
|
-
.option('--sync-folder <path>', 'Compatibility alias for --workflows-path')
|
|
637
400
|
.option('--id <id>', 'Stable environment ID')
|
|
638
401
|
.option('--folder-sync', 'Enable folder sync for this environment')
|
|
639
402
|
.option('--custom-nodes-path <path>', 'Custom nodes path for this environment')
|
|
@@ -642,17 +405,15 @@ environmentProgram.command('add')
|
|
|
642
405
|
.action(async (name, options) => {
|
|
643
406
|
await hydrateApiKeyFromStdin(options);
|
|
644
407
|
const configService = new ConfigService();
|
|
645
|
-
abortIfWorkspaceMigrationRequired(configService, options);
|
|
646
|
-
const environmentTargetOption = options.environmentTarget || options.instanceTarget;
|
|
647
408
|
const urlOption = options.url || options.baseUrl;
|
|
648
|
-
const selectors = [
|
|
409
|
+
const selectors = [urlOption, options.managedInstance].filter(Boolean);
|
|
649
410
|
if (selectors.length !== 1) {
|
|
650
|
-
throw new Error('Provide exactly one of --base-url
|
|
411
|
+
throw new Error('Provide exactly one of --base-url or --managed-instance.');
|
|
651
412
|
}
|
|
652
413
|
if ((options.projectId && !options.projectName) || (!options.projectId && options.projectName)) {
|
|
653
414
|
throw new Error('Provide both --project-id and --project-name, or omit both.');
|
|
654
415
|
}
|
|
655
|
-
let environmentTarget
|
|
416
|
+
let environmentTarget;
|
|
656
417
|
if (urlOption) {
|
|
657
418
|
const target = configService.ensureEmbeddedInstanceTarget({
|
|
658
419
|
name,
|
|
@@ -676,8 +437,6 @@ environmentProgram.command('add')
|
|
|
676
437
|
projectId: options.projectId || (urlOption ? 'personal' : undefined),
|
|
677
438
|
projectName: options.projectName || (urlOption ? 'Personal' : undefined),
|
|
678
439
|
workflowsPath: options.workflowsPath,
|
|
679
|
-
workflowDir: options.workflowDir,
|
|
680
|
-
syncFolder: options.syncFolder,
|
|
681
440
|
folderSync: Boolean(options.folderSync),
|
|
682
441
|
customNodesPath: options.customNodesPath,
|
|
683
442
|
description: options.description,
|
|
@@ -690,14 +449,11 @@ environmentProgram.command('update')
|
|
|
690
449
|
.option('--name <name>', 'New display name')
|
|
691
450
|
.option('--base-url <url>', 'Move this environment to a remote n8n URL')
|
|
692
451
|
.option('--managed-instance <id>', 'Move this environment to a local managed n8n instance')
|
|
693
|
-
.option('--instance-target <name-or-id>', 'Workspace instance target name or ID')
|
|
694
452
|
.option('--api-key <key>', 'Store a local API key for --base-url without committing it')
|
|
695
453
|
.option('--api-key-stdin', 'Read the local API key for --base-url from stdin')
|
|
696
454
|
.option('--project-id <id>', 'n8n project ID')
|
|
697
455
|
.option('--project-name <name>', 'n8n project display name')
|
|
698
456
|
.option('--workflows-path <path>', 'Directory that contains this environment workflows')
|
|
699
|
-
.option('--workflow-dir <path>', 'Compatibility alias for --workflows-path')
|
|
700
|
-
.option('--sync-folder <path>', 'Compatibility alias for --workflows-path')
|
|
701
457
|
.option('--folder-sync', 'Enable folder sync for this environment')
|
|
702
458
|
.option('--no-folder-sync', 'Disable folder sync for this environment')
|
|
703
459
|
.option('--custom-nodes-path <path>', 'Custom nodes path for this environment')
|
|
@@ -706,14 +462,12 @@ environmentProgram.command('update')
|
|
|
706
462
|
.action(async (nameOrId, options) => {
|
|
707
463
|
await hydrateApiKeyFromStdin(options);
|
|
708
464
|
const configService = new ConfigService();
|
|
709
|
-
abortIfWorkspaceMigrationRequired(configService, options);
|
|
710
|
-
const environmentTargetOption = options.environmentTarget || options.instanceTarget;
|
|
711
465
|
const urlOption = options.url || options.baseUrl;
|
|
712
|
-
const selectors = [
|
|
466
|
+
const selectors = [urlOption, options.managedInstance].filter(Boolean);
|
|
713
467
|
if (selectors.length > 1) {
|
|
714
|
-
throw new Error('Provide at most one of --base-url
|
|
468
|
+
throw new Error('Provide at most one of --base-url or --managed-instance.');
|
|
715
469
|
}
|
|
716
|
-
let environmentTarget
|
|
470
|
+
let environmentTarget;
|
|
717
471
|
if (urlOption) {
|
|
718
472
|
const target = configService.ensureEmbeddedInstanceTarget({
|
|
719
473
|
name: options.name || nameOrId,
|
|
@@ -733,8 +487,6 @@ environmentProgram.command('update')
|
|
|
733
487
|
projectId: options.projectId,
|
|
734
488
|
projectName: options.projectName,
|
|
735
489
|
workflowsPath: options.workflowsPath,
|
|
736
|
-
workflowDir: options.workflowDir,
|
|
737
|
-
syncFolder: options.syncFolder,
|
|
738
490
|
folderSync: typeof options.folderSync === 'boolean' ? options.folderSync : undefined,
|
|
739
491
|
customNodesPath: options.customNodesPath,
|
|
740
492
|
description: options.description,
|
|
@@ -749,7 +501,6 @@ environmentProgram.command('pin')
|
|
|
749
501
|
.option('--json', 'Output environment as JSON')
|
|
750
502
|
.action((nameOrId, options) => {
|
|
751
503
|
const configService = new ConfigService();
|
|
752
|
-
abortIfWorkspaceMigrationRequired(configService, options);
|
|
753
504
|
const environment = configService.pinEnvironment(nameOrId);
|
|
754
505
|
printJsonOrText(options, environment, chalk.green(`✔ Workspace environment pinned: ${environment.name}`));
|
|
755
506
|
});
|
|
@@ -761,7 +512,6 @@ environmentProgram.command('remove')
|
|
|
761
512
|
.option('--json', 'Output removed environment as JSON')
|
|
762
513
|
.action((nameOrId, options) => {
|
|
763
514
|
const configService = new ConfigService();
|
|
764
|
-
abortIfWorkspaceMigrationRequired(configService, options);
|
|
765
515
|
const environment = configService.removeEnvironment(nameOrId, { force: Boolean(options.force) });
|
|
766
516
|
printJsonOrText(options, environment, chalk.green(`✔ Workspace environment removed: ${environment.name}`));
|
|
767
517
|
});
|
|
@@ -778,7 +528,6 @@ environmentAuthProgram.command('set')
|
|
|
778
528
|
throw new Error('Provide --api-key or --api-key-stdin.');
|
|
779
529
|
}
|
|
780
530
|
const configService = new ConfigService();
|
|
781
|
-
abortIfWorkspaceMigrationRequired(configService, options);
|
|
782
531
|
const environment = configService.resolveEnvironment(nameOrId);
|
|
783
532
|
if (environment.sourceKind === 'managed-instance') {
|
|
784
533
|
throw new Error(`Environment "${environment.environmentName}" uses managed instance "${environment.managedInstanceId}". Configure credentials through the managed n8n instance instead.`);
|
|
@@ -797,7 +546,6 @@ environmentProgram.command('status')
|
|
|
797
546
|
.option('--json', 'Output resolved environment as JSON')
|
|
798
547
|
.action((nameOrId, options) => {
|
|
799
548
|
const configService = new ConfigService();
|
|
800
|
-
abortIfWorkspaceMigrationRequired(configService, options);
|
|
801
549
|
const environment = configService.resolveEnvironment(nameOrId || process.env.N8NAC_ENVIRONMENT?.trim() || undefined);
|
|
802
550
|
printJsonOrText(options, redactResolvedEnvironment(environment), [
|
|
803
551
|
chalk.cyan(`\nWorkspace environment: ${environment.environmentName}\n`),
|
|
@@ -805,7 +553,7 @@ environmentProgram.command('status')
|
|
|
805
553
|
`Instance: ${chalk.bold(environment.activeInstanceName || environment.managedInstanceId || '(externalInstance)')}`,
|
|
806
554
|
`Host : ${chalk.bold(environment.host)}`,
|
|
807
555
|
`Project : ${chalk.bold(environment.projectName || environment.projectId || '(none)')}`,
|
|
808
|
-
`Workflows path: ${chalk.bold(environment.workflowsPath ||
|
|
556
|
+
`Workflows path: ${chalk.bold(environment.workflowsPath || '(unresolved)')}`,
|
|
809
557
|
`API key : ${chalk.bold(environment.apiKeyAvailable ? environment.apiKeySource : 'missing')}`,
|
|
810
558
|
'',
|
|
811
559
|
].join('\n'));
|