newo 3.3.3 → 3.4.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/api.d.ts +6 -1
  3. package/dist/api.js +63 -1
  4. package/dist/application/migration/MigrationEngine.d.ts +141 -0
  5. package/dist/application/migration/MigrationEngine.js +322 -0
  6. package/dist/application/migration/index.d.ts +5 -0
  7. package/dist/application/migration/index.js +5 -0
  8. package/dist/application/sync/SyncEngine.d.ts +134 -0
  9. package/dist/application/sync/SyncEngine.js +335 -0
  10. package/dist/application/sync/index.d.ts +5 -0
  11. package/dist/application/sync/index.js +5 -0
  12. package/dist/cli/commands/add-project.d.ts +3 -0
  13. package/dist/cli/commands/add-project.js +136 -0
  14. package/dist/cli/commands/create-customer.d.ts +3 -0
  15. package/dist/cli/commands/create-customer.js +159 -0
  16. package/dist/cli/commands/diff.d.ts +6 -0
  17. package/dist/cli/commands/diff.js +288 -0
  18. package/dist/cli/commands/help.js +75 -4
  19. package/dist/cli/commands/list-registries.d.ts +3 -0
  20. package/dist/cli/commands/list-registries.js +39 -0
  21. package/dist/cli/commands/list-registry-items.d.ts +3 -0
  22. package/dist/cli/commands/list-registry-items.js +112 -0
  23. package/dist/cli/commands/logs.d.ts +18 -0
  24. package/dist/cli/commands/logs.js +283 -0
  25. package/dist/cli/commands/pull.js +114 -10
  26. package/dist/cli/commands/push.js +122 -12
  27. package/dist/cli/commands/watch.d.ts +6 -0
  28. package/dist/cli/commands/watch.js +195 -0
  29. package/dist/cli-new/bootstrap.d.ts +74 -0
  30. package/dist/cli-new/bootstrap.js +154 -0
  31. package/dist/cli-new/di/Container.d.ts +64 -0
  32. package/dist/cli-new/di/Container.js +122 -0
  33. package/dist/cli-new/di/tokens.d.ts +77 -0
  34. package/dist/cli-new/di/tokens.js +76 -0
  35. package/dist/cli.js +28 -0
  36. package/dist/domain/resources/common/types.d.ts +71 -0
  37. package/dist/domain/resources/common/types.js +42 -0
  38. package/dist/domain/strategies/sync/AkbSyncStrategy.d.ts +63 -0
  39. package/dist/domain/strategies/sync/AkbSyncStrategy.js +274 -0
  40. package/dist/domain/strategies/sync/AttributeSyncStrategy.d.ts +87 -0
  41. package/dist/domain/strategies/sync/AttributeSyncStrategy.js +378 -0
  42. package/dist/domain/strategies/sync/ConversationSyncStrategy.d.ts +61 -0
  43. package/dist/domain/strategies/sync/ConversationSyncStrategy.js +232 -0
  44. package/dist/domain/strategies/sync/ISyncStrategy.d.ts +149 -0
  45. package/dist/domain/strategies/sync/ISyncStrategy.js +24 -0
  46. package/dist/domain/strategies/sync/IntegrationSyncStrategy.d.ts +68 -0
  47. package/dist/domain/strategies/sync/IntegrationSyncStrategy.js +413 -0
  48. package/dist/domain/strategies/sync/ProjectSyncStrategy.d.ts +111 -0
  49. package/dist/domain/strategies/sync/ProjectSyncStrategy.js +523 -0
  50. package/dist/domain/strategies/sync/index.d.ts +13 -0
  51. package/dist/domain/strategies/sync/index.js +19 -0
  52. package/dist/sync/migrate.js +99 -23
  53. package/dist/types.d.ts +162 -0
  54. package/package.json +3 -1
  55. package/src/api.ts +77 -2
  56. package/src/application/migration/MigrationEngine.ts +492 -0
  57. package/src/application/migration/index.ts +5 -0
  58. package/src/application/sync/SyncEngine.ts +467 -0
  59. package/src/application/sync/index.ts +5 -0
  60. package/src/cli/commands/add-project.ts +159 -0
  61. package/src/cli/commands/create-customer.ts +185 -0
  62. package/src/cli/commands/diff.ts +360 -0
  63. package/src/cli/commands/help.ts +75 -4
  64. package/src/cli/commands/list-registries.ts +53 -0
  65. package/src/cli/commands/list-registry-items.ts +149 -0
  66. package/src/cli/commands/logs.ts +329 -0
  67. package/src/cli/commands/pull.ts +128 -11
  68. package/src/cli/commands/push.ts +131 -13
  69. package/src/cli/commands/watch.ts +227 -0
  70. package/src/cli-new/bootstrap.ts +252 -0
  71. package/src/cli-new/di/Container.ts +152 -0
  72. package/src/cli-new/di/tokens.ts +105 -0
  73. package/src/cli.ts +35 -0
  74. package/src/domain/resources/common/types.ts +106 -0
  75. package/src/domain/strategies/sync/AkbSyncStrategy.ts +358 -0
  76. package/src/domain/strategies/sync/AttributeSyncStrategy.ts +508 -0
  77. package/src/domain/strategies/sync/ConversationSyncStrategy.ts +299 -0
  78. package/src/domain/strategies/sync/ISyncStrategy.ts +182 -0
  79. package/src/domain/strategies/sync/IntegrationSyncStrategy.ts +522 -0
  80. package/src/domain/strategies/sync/ProjectSyncStrategy.ts +747 -0
  81. package/src/domain/strategies/sync/index.ts +46 -0
  82. package/src/sync/migrate.ts +103 -24
  83. package/src/types.ts +178 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * SyncEngine - Core synchronization orchestrator
3
+ *
4
+ * This is the central engine that coordinates sync operations across all resource types.
5
+ * It uses the Strategy pattern to handle different resources uniformly.
6
+ *
7
+ * Key benefits:
8
+ * - One engine handles projects, integrations, AKB, attributes, conversations
9
+ * - Adding new resource = implement one strategy class
10
+ * - No duplicate pull/push logic
11
+ * - Easy to test (mock strategies)
12
+ */
13
+ import type { ISyncStrategy, PullOptions, PullResult, PushResult, StatusSummary, ValidationResult } from '../../domain/strategies/sync/ISyncStrategy.js';
14
+ import type { CustomerConfig, ILogger } from '../../domain/resources/common/types.js';
15
+ /**
16
+ * Combined pull result from all strategies
17
+ */
18
+ export interface SyncPullResult {
19
+ customer: string;
20
+ resources: Array<{
21
+ resourceType: string;
22
+ displayName: string;
23
+ result: PullResult;
24
+ }>;
25
+ totalItems: number;
26
+ errors: string[];
27
+ }
28
+ /**
29
+ * Combined push result from all strategies
30
+ */
31
+ export interface SyncPushResult {
32
+ customer: string;
33
+ resources: Array<{
34
+ resourceType: string;
35
+ displayName: string;
36
+ result: PushResult;
37
+ }>;
38
+ totalCreated: number;
39
+ totalUpdated: number;
40
+ totalDeleted: number;
41
+ errors: string[];
42
+ }
43
+ /**
44
+ * Status report for all resources
45
+ */
46
+ export interface StatusReport {
47
+ customer: string;
48
+ resources: StatusSummary[];
49
+ totalChanges: number;
50
+ }
51
+ /**
52
+ * Sync error with context
53
+ */
54
+ export declare class SyncError extends Error {
55
+ resourceType: string;
56
+ cause?: Error | undefined;
57
+ constructor(message: string, resourceType: string, cause?: Error | undefined);
58
+ }
59
+ /**
60
+ * Validation error with details
61
+ */
62
+ export declare class ValidationError extends Error {
63
+ results: ValidationResult[];
64
+ constructor(message: string, results: ValidationResult[]);
65
+ }
66
+ /**
67
+ * SyncEngine Options
68
+ */
69
+ export interface SyncEngineOptions {
70
+ /**
71
+ * Stop on first error instead of continuing
72
+ */
73
+ stopOnError?: boolean;
74
+ /**
75
+ * Run strategies in parallel where possible
76
+ */
77
+ parallel?: boolean;
78
+ }
79
+ /**
80
+ * SyncEngine - Generic synchronization orchestrator
81
+ *
82
+ * Orchestrates pull/push/status operations across all registered strategies.
83
+ */
84
+ export declare class SyncEngine {
85
+ private logger;
86
+ private options;
87
+ private strategies;
88
+ constructor(strategies: ISyncStrategy[], logger: ILogger, options?: SyncEngineOptions);
89
+ /**
90
+ * Register a new strategy
91
+ */
92
+ registerStrategy(strategy: ISyncStrategy): void;
93
+ /**
94
+ * Get a specific strategy by resource type
95
+ */
96
+ getStrategy(resourceType: string): ISyncStrategy | undefined;
97
+ /**
98
+ * Get all registered strategies
99
+ */
100
+ getStrategies(): ISyncStrategy[];
101
+ /**
102
+ * Pull ALL resources using registered strategies
103
+ */
104
+ pullAll(customer: CustomerConfig, options?: PullOptions): Promise<SyncPullResult>;
105
+ /**
106
+ * Pull specific resource types
107
+ */
108
+ pullSelected(customer: CustomerConfig, resourceTypes: string[], options?: PullOptions): Promise<SyncPullResult>;
109
+ /**
110
+ * Push ALL changed resources using registered strategies
111
+ */
112
+ pushAll(customer: CustomerConfig): Promise<SyncPushResult>;
113
+ /**
114
+ * Push specific resource types
115
+ */
116
+ pushSelected(customer: CustomerConfig, resourceTypes: string[]): Promise<SyncPushResult>;
117
+ /**
118
+ * Get status for ALL resources
119
+ */
120
+ getStatus(customer: CustomerConfig): Promise<StatusReport>;
121
+ /**
122
+ * Get status for specific resource types
123
+ */
124
+ getStatusSelected(customer: CustomerConfig, resourceTypes: string[]): Promise<StatusReport>;
125
+ /**
126
+ * Helper to execute pull with a single strategy
127
+ */
128
+ private pullWithStrategy;
129
+ }
130
+ /**
131
+ * Factory function for creating SyncEngine with default strategies
132
+ */
133
+ export declare function createSyncEngine(strategies: ISyncStrategy[], logger: ILogger, options?: SyncEngineOptions): SyncEngine;
134
+ //# sourceMappingURL=SyncEngine.d.ts.map
@@ -0,0 +1,335 @@
1
+ /**
2
+ * SyncEngine - Core synchronization orchestrator
3
+ *
4
+ * This is the central engine that coordinates sync operations across all resource types.
5
+ * It uses the Strategy pattern to handle different resources uniformly.
6
+ *
7
+ * Key benefits:
8
+ * - One engine handles projects, integrations, AKB, attributes, conversations
9
+ * - Adding new resource = implement one strategy class
10
+ * - No duplicate pull/push logic
11
+ * - Easy to test (mock strategies)
12
+ */
13
+ /**
14
+ * Sync error with context
15
+ */
16
+ export class SyncError extends Error {
17
+ resourceType;
18
+ cause;
19
+ constructor(message, resourceType, cause) {
20
+ super(message);
21
+ this.resourceType = resourceType;
22
+ this.cause = cause;
23
+ this.name = 'SyncError';
24
+ }
25
+ }
26
+ /**
27
+ * Validation error with details
28
+ */
29
+ export class ValidationError extends Error {
30
+ results;
31
+ constructor(message, results) {
32
+ super(message);
33
+ this.results = results;
34
+ this.name = 'ValidationError';
35
+ }
36
+ }
37
+ /**
38
+ * SyncEngine - Generic synchronization orchestrator
39
+ *
40
+ * Orchestrates pull/push/status operations across all registered strategies.
41
+ */
42
+ export class SyncEngine {
43
+ logger;
44
+ options;
45
+ strategies = new Map();
46
+ constructor(strategies, logger, options = {}) {
47
+ this.logger = logger;
48
+ this.options = options;
49
+ for (const strategy of strategies) {
50
+ this.strategies.set(strategy.resourceType, strategy);
51
+ }
52
+ }
53
+ /**
54
+ * Register a new strategy
55
+ */
56
+ registerStrategy(strategy) {
57
+ this.strategies.set(strategy.resourceType, strategy);
58
+ }
59
+ /**
60
+ * Get a specific strategy by resource type
61
+ */
62
+ getStrategy(resourceType) {
63
+ return this.strategies.get(resourceType);
64
+ }
65
+ /**
66
+ * Get all registered strategies
67
+ */
68
+ getStrategies() {
69
+ return Array.from(this.strategies.values());
70
+ }
71
+ /**
72
+ * Pull ALL resources using registered strategies
73
+ */
74
+ async pullAll(customer, options = {}) {
75
+ this.logger.info(`📥 Pulling all resources for customer: ${customer.idn}`);
76
+ const result = {
77
+ customer: customer.idn,
78
+ resources: [],
79
+ totalItems: 0,
80
+ errors: []
81
+ };
82
+ const strategies = Array.from(this.strategies.values());
83
+ if (this.options.parallel) {
84
+ // Parallel execution
85
+ const pullPromises = strategies.map(async (strategy) => {
86
+ try {
87
+ return await this.pullWithStrategy(strategy, customer, options);
88
+ }
89
+ catch (error) {
90
+ const message = `Failed to pull ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
91
+ if (this.options.stopOnError) {
92
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
93
+ }
94
+ result.errors.push(message);
95
+ return null;
96
+ }
97
+ });
98
+ const pullResults = await Promise.all(pullPromises);
99
+ for (const pullResult of pullResults) {
100
+ if (pullResult) {
101
+ result.resources.push(pullResult);
102
+ result.totalItems += pullResult.result.count;
103
+ }
104
+ }
105
+ }
106
+ else {
107
+ // Sequential execution
108
+ for (const strategy of strategies) {
109
+ this.logger.info(` 📦 Pulling ${strategy.displayName}...`);
110
+ try {
111
+ const pullResult = await this.pullWithStrategy(strategy, customer, options);
112
+ result.resources.push(pullResult);
113
+ result.totalItems += pullResult.result.count;
114
+ this.logger.info(` ✅ Pulled ${pullResult.result.count} ${strategy.displayName}`);
115
+ }
116
+ catch (error) {
117
+ const message = `Failed to pull ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
118
+ this.logger.error(message, error);
119
+ if (this.options.stopOnError) {
120
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
121
+ }
122
+ result.errors.push(message);
123
+ }
124
+ }
125
+ }
126
+ this.logger.info(`✅ Pull completed: ${result.totalItems} items from ${result.resources.length} resource types`);
127
+ return result;
128
+ }
129
+ /**
130
+ * Pull specific resource types
131
+ */
132
+ async pullSelected(customer, resourceTypes, options = {}) {
133
+ this.logger.info(`📥 Pulling selected resources for customer: ${customer.idn}`);
134
+ const result = {
135
+ customer: customer.idn,
136
+ resources: [],
137
+ totalItems: 0,
138
+ errors: []
139
+ };
140
+ for (const resourceType of resourceTypes) {
141
+ const strategy = this.strategies.get(resourceType);
142
+ if (!strategy) {
143
+ result.errors.push(`Unknown resource type: ${resourceType}`);
144
+ continue;
145
+ }
146
+ this.logger.info(` 📦 Pulling ${strategy.displayName}...`);
147
+ try {
148
+ const pullResult = await this.pullWithStrategy(strategy, customer, options);
149
+ result.resources.push(pullResult);
150
+ result.totalItems += pullResult.result.count;
151
+ this.logger.info(` ✅ Pulled ${pullResult.result.count} ${strategy.displayName}`);
152
+ }
153
+ catch (error) {
154
+ const message = `Failed to pull ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
155
+ this.logger.error(message, error);
156
+ if (this.options.stopOnError) {
157
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
158
+ }
159
+ result.errors.push(message);
160
+ }
161
+ }
162
+ return result;
163
+ }
164
+ /**
165
+ * Push ALL changed resources using registered strategies
166
+ */
167
+ async pushAll(customer) {
168
+ this.logger.info(`📤 Pushing changes for customer: ${customer.idn}`);
169
+ const result = {
170
+ customer: customer.idn,
171
+ resources: [],
172
+ totalCreated: 0,
173
+ totalUpdated: 0,
174
+ totalDeleted: 0,
175
+ errors: []
176
+ };
177
+ for (const strategy of this.strategies.values()) {
178
+ this.logger.info(` 🔍 Checking changes for ${strategy.displayName}...`);
179
+ try {
180
+ const changes = await strategy.getChanges(customer);
181
+ if (changes.length === 0) {
182
+ this.logger.verbose(` No changes for ${strategy.displayName}`);
183
+ continue;
184
+ }
185
+ this.logger.info(` Found ${changes.length} changes in ${strategy.displayName}`);
186
+ // Validate before push
187
+ const items = changes.map(c => c.item);
188
+ const validation = await strategy.validate(customer, items);
189
+ if (!validation.valid) {
190
+ const errorMessages = validation.errors.map(e => `${e.field}: ${e.message}`).join(', ');
191
+ throw new ValidationError(`Validation failed: ${errorMessages}`, [validation]);
192
+ }
193
+ // Push changes
194
+ const pushResult = await strategy.push(customer, changes);
195
+ result.resources.push({
196
+ resourceType: strategy.resourceType,
197
+ displayName: strategy.displayName,
198
+ result: pushResult
199
+ });
200
+ result.totalCreated += pushResult.created;
201
+ result.totalUpdated += pushResult.updated;
202
+ result.totalDeleted += pushResult.deleted;
203
+ result.errors.push(...pushResult.errors);
204
+ this.logger.info(` ✅ Pushed: ${pushResult.created} created, ${pushResult.updated} updated, ${pushResult.deleted} deleted`);
205
+ }
206
+ catch (error) {
207
+ const message = `Failed to push ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
208
+ this.logger.error(message, error);
209
+ if (this.options.stopOnError) {
210
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
211
+ }
212
+ result.errors.push(message);
213
+ }
214
+ }
215
+ this.logger.info(`✅ Push completed: ${result.totalCreated} created, ${result.totalUpdated} updated, ${result.totalDeleted} deleted`);
216
+ return result;
217
+ }
218
+ /**
219
+ * Push specific resource types
220
+ */
221
+ async pushSelected(customer, resourceTypes) {
222
+ this.logger.info(`📤 Pushing selected resources for customer: ${customer.idn}`);
223
+ const result = {
224
+ customer: customer.idn,
225
+ resources: [],
226
+ totalCreated: 0,
227
+ totalUpdated: 0,
228
+ totalDeleted: 0,
229
+ errors: []
230
+ };
231
+ for (const resourceType of resourceTypes) {
232
+ const strategy = this.strategies.get(resourceType);
233
+ if (!strategy) {
234
+ result.errors.push(`Unknown resource type: ${resourceType}`);
235
+ continue;
236
+ }
237
+ try {
238
+ const changes = await strategy.getChanges(customer);
239
+ if (changes.length === 0) {
240
+ continue;
241
+ }
242
+ // Validate before push
243
+ const items = changes.map(c => c.item);
244
+ const validation = await strategy.validate(customer, items);
245
+ if (!validation.valid) {
246
+ const errorMessages = validation.errors.map(e => `${e.field}: ${e.message}`).join(', ');
247
+ throw new ValidationError(`Validation failed: ${errorMessages}`, [validation]);
248
+ }
249
+ const pushResult = await strategy.push(customer, changes);
250
+ result.resources.push({
251
+ resourceType: strategy.resourceType,
252
+ displayName: strategy.displayName,
253
+ result: pushResult
254
+ });
255
+ result.totalCreated += pushResult.created;
256
+ result.totalUpdated += pushResult.updated;
257
+ result.totalDeleted += pushResult.deleted;
258
+ result.errors.push(...pushResult.errors);
259
+ }
260
+ catch (error) {
261
+ const message = `Failed to push ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
262
+ this.logger.error(message, error);
263
+ if (this.options.stopOnError) {
264
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
265
+ }
266
+ result.errors.push(message);
267
+ }
268
+ }
269
+ return result;
270
+ }
271
+ /**
272
+ * Get status for ALL resources
273
+ */
274
+ async getStatus(customer) {
275
+ const report = {
276
+ customer: customer.idn,
277
+ resources: [],
278
+ totalChanges: 0
279
+ };
280
+ for (const strategy of this.strategies.values()) {
281
+ try {
282
+ const status = await strategy.getStatus(customer);
283
+ report.resources.push(status);
284
+ report.totalChanges += status.changedCount;
285
+ }
286
+ catch (error) {
287
+ this.logger.error(`Failed to get status for ${strategy.displayName}`, error);
288
+ }
289
+ }
290
+ return report;
291
+ }
292
+ /**
293
+ * Get status for specific resource types
294
+ */
295
+ async getStatusSelected(customer, resourceTypes) {
296
+ const report = {
297
+ customer: customer.idn,
298
+ resources: [],
299
+ totalChanges: 0
300
+ };
301
+ for (const resourceType of resourceTypes) {
302
+ const strategy = this.strategies.get(resourceType);
303
+ if (!strategy) {
304
+ continue;
305
+ }
306
+ try {
307
+ const status = await strategy.getStatus(customer);
308
+ report.resources.push(status);
309
+ report.totalChanges += status.changedCount;
310
+ }
311
+ catch (error) {
312
+ this.logger.error(`Failed to get status for ${strategy.displayName}`, error);
313
+ }
314
+ }
315
+ return report;
316
+ }
317
+ /**
318
+ * Helper to execute pull with a single strategy
319
+ */
320
+ async pullWithStrategy(strategy, customer, options) {
321
+ const result = await strategy.pull(customer, options);
322
+ return {
323
+ resourceType: strategy.resourceType,
324
+ displayName: strategy.displayName,
325
+ result
326
+ };
327
+ }
328
+ }
329
+ /**
330
+ * Factory function for creating SyncEngine with default strategies
331
+ */
332
+ export function createSyncEngine(strategies, logger, options) {
333
+ return new SyncEngine(strategies, logger, options);
334
+ }
335
+ //# sourceMappingURL=SyncEngine.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Sync Application Layer Exports
3
+ */
4
+ export * from './SyncEngine.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Sync Application Layer Exports
3
+ */
4
+ export * from './SyncEngine.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handleAddProjectCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose?: boolean): Promise<void>;
3
+ //# sourceMappingURL=add-project.d.ts.map
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Add Project from Registry Command Handler - Installs a project template from registry
3
+ */
4
+ import { makeClient, listRegistries, listRegistryItems, addProjectFromRegistry } from '../../api.js';
5
+ import { getValidAccessToken } from '../../auth.js';
6
+ import { requireSingleCustomer } from '../customer-selection.js';
7
+ export async function handleAddProjectCommand(customerConfig, args, verbose = false) {
8
+ try {
9
+ const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
10
+ // Parse arguments
11
+ const projectIdn = args._[1];
12
+ const registryIdn = args.registry || 'production';
13
+ const registryItemIdn = args.item;
14
+ const registryItemVersion = args.version || null;
15
+ const title = args.title || projectIdn || registryItemIdn;
16
+ const description = args.description || '';
17
+ const isAutoUpdateEnabled = Boolean(args['auto-update']);
18
+ // Validate required arguments
19
+ if (!registryItemIdn) {
20
+ console.error('Error: Registry item IDN is required');
21
+ console.error('');
22
+ console.error('Usage: newo add-project <project-idn> --item <registry-item-idn> [options]');
23
+ console.error('');
24
+ console.error('Options:');
25
+ console.error(' --item <idn> Registry item/template IDN (required)');
26
+ console.error(' --registry <idn> Registry to use (default: production)');
27
+ console.error(' --version <version> Specific version to install (default: latest)');
28
+ console.error(' --title <title> Project title (default: project IDN)');
29
+ console.error(' --description <desc> Project description');
30
+ console.error(' --auto-update Enable automatic updates from registry');
31
+ console.error('');
32
+ console.error('Examples:');
33
+ console.error(' newo add-project my_weather --item weather_integration');
34
+ console.error(' newo add-project my_calcom --item cal_com_integration --registry production');
35
+ console.error(' newo add-project my_zoho --item zoho_integration --version 1.0.2 --auto-update');
36
+ console.error('');
37
+ console.error('Run "newo list-registries" to see available registries');
38
+ console.error('Run "newo list-registry-items <registry-idn>" to see available project templates');
39
+ process.exit(1);
40
+ }
41
+ // Use registry item IDN as project IDN if not specified
42
+ const finalProjectIdn = projectIdn || registryItemIdn;
43
+ if (verbose) {
44
+ console.log(`📦 Adding project from registry`);
45
+ console.log(` Project IDN: ${finalProjectIdn}`);
46
+ console.log(` Title: ${title}`);
47
+ console.log(` Registry: ${registryIdn}`);
48
+ console.log(` Item: ${registryItemIdn}`);
49
+ console.log(` Version: ${registryItemVersion || 'latest'}`);
50
+ console.log(` Auto-update: ${isAutoUpdateEnabled}`);
51
+ console.log(` Customer: ${selectedCustomer.idn}`);
52
+ }
53
+ // Get access token and create client
54
+ const accessToken = await getValidAccessToken(selectedCustomer);
55
+ const client = await makeClient(verbose, accessToken);
56
+ // Validate registry exists
57
+ console.log(`🔍 Validating registry "${registryIdn}"...`);
58
+ const registries = await listRegistries(client);
59
+ const registry = registries.find((r) => r.idn === registryIdn);
60
+ if (!registry) {
61
+ console.error(`❌ Registry "${registryIdn}" not found`);
62
+ console.error('');
63
+ console.error('Available registries:');
64
+ for (const r of registries) {
65
+ console.error(` • ${r.idn}`);
66
+ }
67
+ process.exit(1);
68
+ }
69
+ // Validate registry item exists and find version
70
+ console.log(`🔍 Validating project template "${registryItemIdn}"...`);
71
+ const items = await listRegistryItems(client, registry.id);
72
+ const matchingItems = items.filter((item) => item.idn === registryItemIdn);
73
+ if (matchingItems.length === 0) {
74
+ console.error(`❌ Project template "${registryItemIdn}" not found in "${registryIdn}" registry`);
75
+ console.error('');
76
+ console.error('Run "newo list-registry-items ' + registryIdn + '" to see available templates');
77
+ process.exit(1);
78
+ }
79
+ // Find the specific version or latest
80
+ let selectedItem;
81
+ if (registryItemVersion) {
82
+ selectedItem = matchingItems.find((item) => item.version === registryItemVersion);
83
+ if (!selectedItem) {
84
+ console.error(`❌ Version "${registryItemVersion}" not found for "${registryItemIdn}"`);
85
+ console.error('');
86
+ console.error('Available versions:');
87
+ const sortedItems = [...matchingItems].sort((a, b) => new Date(b.published_at).getTime() - new Date(a.published_at).getTime());
88
+ for (const item of sortedItems.slice(0, 10)) {
89
+ console.error(` • ${item.version} (published: ${new Date(item.published_at).toISOString().split('T')[0]})`);
90
+ }
91
+ if (sortedItems.length > 10) {
92
+ console.error(` ... and ${sortedItems.length - 10} more`);
93
+ }
94
+ process.exit(1);
95
+ }
96
+ }
97
+ else {
98
+ // Get latest version (sorted by published_at desc)
99
+ const sortedItems = [...matchingItems].sort((a, b) => new Date(b.published_at).getTime() - new Date(a.published_at).getTime());
100
+ selectedItem = sortedItems[0];
101
+ }
102
+ if (!selectedItem) {
103
+ console.error(`❌ Could not determine version for "${registryItemIdn}"`);
104
+ process.exit(1);
105
+ }
106
+ console.log(`📥 Installing "${registryItemIdn}" v${selectedItem.version} as "${finalProjectIdn}"...`);
107
+ // Create project from registry
108
+ const projectData = {
109
+ idn: finalProjectIdn,
110
+ title,
111
+ version: '',
112
+ description,
113
+ is_auto_update_enabled: isAutoUpdateEnabled,
114
+ registry_idn: registryIdn,
115
+ registry_item_idn: registryItemIdn,
116
+ registry_item_version: registryItemVersion
117
+ };
118
+ const response = await addProjectFromRegistry(client, projectData);
119
+ console.log('');
120
+ console.log(`✅ Project installed successfully!`);
121
+ console.log(` Project IDN: ${finalProjectIdn}`);
122
+ console.log(` Project ID: ${response.id}`);
123
+ console.log(` Source: ${registryItemIdn} v${selectedItem.version}`);
124
+ console.log(` Registry: ${registryIdn}`);
125
+ if (isAutoUpdateEnabled) {
126
+ console.log(` Auto-update: Enabled`);
127
+ }
128
+ console.log('');
129
+ console.log(`💡 Run "newo pull" to sync the project locally`);
130
+ }
131
+ catch (error) {
132
+ console.error('❌ Failed to add project from registry:', error instanceof Error ? error.message : String(error));
133
+ process.exit(1);
134
+ }
135
+ }
136
+ //# sourceMappingURL=add-project.js.map
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handleCreateCustomerCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose?: boolean): Promise<void>;
3
+ //# sourceMappingURL=create-customer.d.ts.map