newo 3.4.0 → 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 (74) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/api.d.ts +3 -1
  3. package/dist/api.js +49 -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/create-customer.d.ts +3 -0
  13. package/dist/cli/commands/create-customer.js +159 -0
  14. package/dist/cli/commands/diff.d.ts +6 -0
  15. package/dist/cli/commands/diff.js +288 -0
  16. package/dist/cli/commands/help.js +63 -3
  17. package/dist/cli/commands/logs.d.ts +18 -0
  18. package/dist/cli/commands/logs.js +283 -0
  19. package/dist/cli/commands/pull.js +114 -10
  20. package/dist/cli/commands/push.js +122 -12
  21. package/dist/cli/commands/watch.d.ts +6 -0
  22. package/dist/cli/commands/watch.js +195 -0
  23. package/dist/cli-new/bootstrap.d.ts +74 -0
  24. package/dist/cli-new/bootstrap.js +154 -0
  25. package/dist/cli-new/di/Container.d.ts +64 -0
  26. package/dist/cli-new/di/Container.js +122 -0
  27. package/dist/cli-new/di/tokens.d.ts +77 -0
  28. package/dist/cli-new/di/tokens.js +76 -0
  29. package/dist/cli.js +16 -0
  30. package/dist/domain/resources/common/types.d.ts +71 -0
  31. package/dist/domain/resources/common/types.js +42 -0
  32. package/dist/domain/strategies/sync/AkbSyncStrategy.d.ts +63 -0
  33. package/dist/domain/strategies/sync/AkbSyncStrategy.js +274 -0
  34. package/dist/domain/strategies/sync/AttributeSyncStrategy.d.ts +87 -0
  35. package/dist/domain/strategies/sync/AttributeSyncStrategy.js +378 -0
  36. package/dist/domain/strategies/sync/ConversationSyncStrategy.d.ts +61 -0
  37. package/dist/domain/strategies/sync/ConversationSyncStrategy.js +232 -0
  38. package/dist/domain/strategies/sync/ISyncStrategy.d.ts +149 -0
  39. package/dist/domain/strategies/sync/ISyncStrategy.js +24 -0
  40. package/dist/domain/strategies/sync/IntegrationSyncStrategy.d.ts +68 -0
  41. package/dist/domain/strategies/sync/IntegrationSyncStrategy.js +413 -0
  42. package/dist/domain/strategies/sync/ProjectSyncStrategy.d.ts +111 -0
  43. package/dist/domain/strategies/sync/ProjectSyncStrategy.js +523 -0
  44. package/dist/domain/strategies/sync/index.d.ts +13 -0
  45. package/dist/domain/strategies/sync/index.js +19 -0
  46. package/dist/sync/migrate.js +99 -23
  47. package/dist/types.d.ts +124 -0
  48. package/package.json +3 -1
  49. package/src/api.ts +53 -2
  50. package/src/application/migration/MigrationEngine.ts +492 -0
  51. package/src/application/migration/index.ts +5 -0
  52. package/src/application/sync/SyncEngine.ts +467 -0
  53. package/src/application/sync/index.ts +5 -0
  54. package/src/cli/commands/create-customer.ts +185 -0
  55. package/src/cli/commands/diff.ts +360 -0
  56. package/src/cli/commands/help.ts +63 -3
  57. package/src/cli/commands/logs.ts +329 -0
  58. package/src/cli/commands/pull.ts +128 -11
  59. package/src/cli/commands/push.ts +131 -13
  60. package/src/cli/commands/watch.ts +227 -0
  61. package/src/cli-new/bootstrap.ts +252 -0
  62. package/src/cli-new/di/Container.ts +152 -0
  63. package/src/cli-new/di/tokens.ts +105 -0
  64. package/src/cli.ts +20 -0
  65. package/src/domain/resources/common/types.ts +106 -0
  66. package/src/domain/strategies/sync/AkbSyncStrategy.ts +358 -0
  67. package/src/domain/strategies/sync/AttributeSyncStrategy.ts +508 -0
  68. package/src/domain/strategies/sync/ConversationSyncStrategy.ts +299 -0
  69. package/src/domain/strategies/sync/ISyncStrategy.ts +182 -0
  70. package/src/domain/strategies/sync/IntegrationSyncStrategy.ts +522 -0
  71. package/src/domain/strategies/sync/ProjectSyncStrategy.ts +747 -0
  72. package/src/domain/strategies/sync/index.ts +46 -0
  73. package/src/sync/migrate.ts +103 -24
  74. package/src/types.ts +135 -0
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Sync Strategies Module Exports
3
+ *
4
+ * This module exports all sync strategies that implement ISyncStrategy.
5
+ * Each strategy handles synchronization for a specific resource type.
6
+ */
7
+
8
+ // Core interface
9
+ export * from './ISyncStrategy.js';
10
+
11
+ // Project strategy (projects, agents, flows, skills)
12
+ export {
13
+ ProjectSyncStrategy,
14
+ createProjectSyncStrategy,
15
+ type LocalProjectData,
16
+ type LocalFlowData,
17
+ type LocalSkillData
18
+ } from './ProjectSyncStrategy.js';
19
+
20
+ // Attribute strategy (customer and project attributes)
21
+ export {
22
+ AttributeSyncStrategy,
23
+ createAttributeSyncStrategy,
24
+ type LocalAttributeData
25
+ } from './AttributeSyncStrategy.js';
26
+
27
+ // Integration strategy (integrations, connectors, webhooks)
28
+ export {
29
+ IntegrationSyncStrategy,
30
+ createIntegrationSyncStrategy,
31
+ type LocalIntegrationData
32
+ } from './IntegrationSyncStrategy.js';
33
+
34
+ // AKB strategy (knowledge base articles)
35
+ export {
36
+ AkbSyncStrategy,
37
+ createAkbSyncStrategy,
38
+ type LocalAkbData
39
+ } from './AkbSyncStrategy.js';
40
+
41
+ // Conversation strategy (conversation history - pull only)
42
+ export {
43
+ ConversationSyncStrategy,
44
+ createConversationSyncStrategy,
45
+ type LocalConversationData
46
+ } from './ConversationSyncStrategy.js';
@@ -216,48 +216,102 @@ async function migrateProjectStructure(
216
216
  idn: sourceFlow.idn,
217
217
  title: sourceFlow.title
218
218
  });
219
- flowId = flowResponse.id;
219
+
220
+ // Handle "pending-sync" response - re-fetch to get actual flow ID
221
+ if (flowResponse.id === 'pending-sync' || !flowResponse.id.match(/^[0-9a-f-]{36}$/i)) {
222
+ // Retry with increasing wait times
223
+ let createdFlow: any = null;
224
+ for (const waitMs of [1500, 3000, 5000]) {
225
+ await new Promise(resolve => setTimeout(resolve, waitMs));
226
+ const refreshedAgents = await listAgents(destClient, projectId);
227
+ const refreshedAgent = refreshedAgents.find(a => a.id === agentId);
228
+ createdFlow = refreshedAgent?.flows?.find(f => f.idn === sourceFlow.idn);
229
+ if (createdFlow) break;
230
+ }
231
+
232
+ if (createdFlow) {
233
+ flowId = createdFlow.id;
234
+ } else {
235
+ if (verbose) console.error(` ⚠️ Flow ${sourceFlow.idn} created but could not retrieve ID after retries`);
236
+ continue; // Skip this flow
237
+ }
238
+ } else {
239
+ flowId = flowResponse.id;
240
+ }
220
241
  flowsCreated++;
221
242
  }
222
243
 
223
- // Read flow metadata for events and states
224
- const flowMetaPath = path.join(
244
+ // Flow directory path
245
+ const flowDirPath = path.join(
225
246
  customerProjectsDir(sourceCustomer.idn),
226
247
  sourceProj.idn,
227
248
  sourceAgent.idn,
228
- sourceFlow.idn,
229
- 'metadata.yaml'
249
+ sourceFlow.idn
230
250
  );
231
251
 
232
- if (await fs.pathExists(flowMetaPath)) {
233
- const flowMeta = yaml.load(await fs.readFile(flowMetaPath, 'utf8')) as any;
234
-
235
- // Create skills
236
- const destSkills = await listFlowSkills(destClient, flowId);
252
+ if (await fs.pathExists(flowDirPath)) {
253
+ // Read flow metadata for events and states
254
+ const flowMetaPath = path.join(flowDirPath, 'metadata.yaml');
255
+ const flowMeta = await fs.pathExists(flowMetaPath)
256
+ ? yaml.load(await fs.readFile(flowMetaPath, 'utf8')) as any
257
+ : {};
258
+
259
+ // Create skills by reading skill subdirectories
260
+ let destSkills: any[];
261
+ try {
262
+ destSkills = await listFlowSkills(destClient, flowId);
263
+ } catch (err: any) {
264
+ if (verbose) console.error(` ⚠️ Failed to list skills for flow ${sourceFlow.idn} (${flowId}): ${err.message}`);
265
+ continue; // Skip this flow if we can't list skills
266
+ }
237
267
  const destSkillMap = new Map(destSkills.map(s => [s.idn, s]));
238
268
 
239
- for (const sourceSkill of flowMeta.skills || []) {
240
- if (destSkillMap.has(sourceSkill.idn)) continue;
269
+ // Get all subdirectories in flow directory (these are skills)
270
+ const flowDirContents = await fs.readdir(flowDirPath, { withFileTypes: true });
271
+ const skillDirs = flowDirContents.filter(d => d.isDirectory());
272
+
273
+ for (const skillDir of skillDirs) {
274
+ const skillIdn = skillDir.name;
275
+ if (destSkillMap.has(skillIdn)) continue;
276
+
277
+ // Read skill metadata
278
+ const skillMetaPath = path.join(flowDirPath, skillIdn, 'metadata.yaml');
279
+ if (!await fs.pathExists(skillMetaPath)) continue;
280
+
281
+ const skillMeta = yaml.load(await fs.readFile(skillMetaPath, 'utf8')) as any;
241
282
 
242
283
  try {
243
284
  await createSkill(destClient, flowId, {
244
- idn: sourceSkill.idn,
245
- title: sourceSkill.title,
246
- runner_type: sourceSkill.runner_type,
247
- model: sourceSkill.model,
285
+ idn: skillMeta.idn || skillIdn,
286
+ title: skillMeta.title || skillIdn,
287
+ runner_type: skillMeta.runner_type || 'guidance',
288
+ model: skillMeta.model,
248
289
  prompt_script: ''
249
290
  });
250
291
  skillsCreated++;
292
+ if (verbose) console.log(` ✅ Created skill: ${skillIdn}`);
251
293
  } catch (error: any) {
252
294
  if (verbose && error.response?.status !== 409) {
253
- console.error(` ⚠️ Failed to create skill ${sourceSkill.idn}: ${error.message}`);
295
+ console.error(` ⚠️ Failed to create skill ${skillIdn}: ${error.message}`);
254
296
  }
255
297
  }
256
298
  }
257
299
 
258
- // Create events with full metadata
300
+ // Get current skills in destination to validate event references
301
+ const currentDestSkills = await listFlowSkills(destClient, flowId);
302
+ const destSkillIdnSet = new Set(currentDestSkills.map(s => s.idn));
303
+
304
+ // Create events with full metadata (only if referenced skill exists)
259
305
  for (const event of flowMeta.events || []) {
260
306
  try {
307
+ // Skip events that reference skills not yet created
308
+ if (event.skill_idn && !destSkillIdnSet.has(event.skill_idn)) {
309
+ if (verbose) {
310
+ console.log(` ⏭️ Skipping event ${event.idn} - skill ${event.skill_idn} not yet created`);
311
+ }
312
+ continue;
313
+ }
314
+
261
315
  const eventRequest: CreateFlowEventRequest = {
262
316
  idn: event.idn,
263
317
  description: event.description || event.idn,
@@ -276,8 +330,9 @@ async function migrateProjectStructure(
276
330
 
277
331
  await createFlowEvent(destClient, flowId, eventRequest);
278
332
  } catch (error: any) {
279
- if (verbose && error.response?.status !== 409 && error.response?.status !== 422) {
280
- console.error(` ⚠️ Failed to create event ${event.idn}: ${error.message}`);
333
+ // Don't log 409 (already exists) or 422 (validation) errors as they're expected
334
+ if (error.response?.status !== 409 && error.response?.status !== 422) {
335
+ if (verbose) console.error(` ⚠️ Failed to create event ${event.idn}: ${error.message}`);
281
336
  }
282
337
  }
283
338
  }
@@ -448,7 +503,6 @@ async function migrateAKB(
448
503
  async function migrateIntegrationConnectors(
449
504
  sourceClient: AxiosInstance,
450
505
  destClient: AxiosInstance,
451
- // @ts-ignore - Parameter kept for future use
452
506
  verbose: boolean
453
507
  ): Promise<number> {
454
508
  const sourceIntegrations = await listIntegrations(sourceClient);
@@ -461,6 +515,11 @@ async function migrateIntegrationConnectors(
461
515
  const destInt = destIntMap.get(sourceInt.idn);
462
516
  if (!destInt) continue;
463
517
 
518
+ // Build set of allowed setting idns from destination integration schema
519
+ const destSettingIdns = new Set(
520
+ (destInt.connector_settings_descriptions || []).map(s => s.idn)
521
+ );
522
+
464
523
  const sourceConnectors = await listConnectors(sourceClient, sourceInt.id);
465
524
  const destConnectors = await listConnectors(destClient, destInt.id);
466
525
  const destConnMap = new Map(destConnectors.map(c => [c.connector_idn, c]));
@@ -468,17 +527,37 @@ async function migrateIntegrationConnectors(
468
527
  for (const sourceConn of sourceConnectors) {
469
528
  if (destConnMap.has(sourceConn.connector_idn)) continue;
470
529
 
530
+ // Filter settings to only include those that exist in destination schema
531
+ const filteredSettings = sourceConn.settings.filter(s => {
532
+ const allowed = destSettingIdns.size === 0 || destSettingIdns.has(s.idn);
533
+ if (!allowed && verbose) {
534
+ console.log(` ⏭️ Skipping setting ${s.idn} for ${sourceConn.connector_idn} (not in dest schema)`);
535
+ }
536
+ return allowed;
537
+ });
538
+
539
+ // Log if settings were filtered
540
+ if (filteredSettings.length !== sourceConn.settings.length && verbose) {
541
+ const skippedCount = sourceConn.settings.length - filteredSettings.length;
542
+ console.log(` 📋 Filtered ${skippedCount} settings for ${sourceConn.connector_idn}`);
543
+ }
544
+
471
545
  try {
472
546
  await createConnector(destClient, destInt.id, {
473
547
  title: sourceConn.title,
474
548
  connector_idn: sourceConn.connector_idn,
475
549
  integration_idn: sourceInt.idn,
476
- settings: sourceConn.settings
550
+ settings: filteredSettings
477
551
  });
478
552
  connectorsCreated++;
553
+ if (verbose) {
554
+ console.log(` ✅ Created connector: ${sourceConn.connector_idn} (${sourceInt.idn})`);
555
+ }
479
556
  } catch (error: any) {
480
- if (verbose && error.response?.status !== 409) {
481
- console.error(` ⚠️ Failed to create connector ${sourceConn.connector_idn}: ${error.message}`);
557
+ // Always log connector creation failures (not just in verbose mode)
558
+ const errMsg = error.response?.data?.reason || error.message;
559
+ if (error.response?.status !== 409) {
560
+ console.error(` ⚠️ Failed to create connector ${sourceConn.connector_idn} (${sourceInt.idn}): ${errMsg}`);
482
561
  }
483
562
  }
484
563
  }
package/src/types.ts CHANGED
@@ -587,6 +587,21 @@ export interface PublishFlowResponse {
587
587
 
588
588
  // Sandbox Chat Types
589
589
 
590
+ export interface IntegrationSettingDescription {
591
+ readonly title: string;
592
+ readonly idn: string;
593
+ readonly control_type: string;
594
+ readonly value_type: string;
595
+ readonly is_required: boolean;
596
+ readonly is_readonly: boolean;
597
+ readonly default_value?: string | null;
598
+ readonly description?: string | null;
599
+ readonly group?: string | null;
600
+ readonly possible_values?: readonly string[] | null;
601
+ readonly possible_values_only?: boolean;
602
+ readonly possible_values_url?: string | null;
603
+ }
604
+
590
605
  export interface Integration {
591
606
  readonly id: string;
592
607
  readonly title: string;
@@ -594,6 +609,8 @@ export interface Integration {
594
609
  readonly description: string;
595
610
  readonly is_disabled: boolean;
596
611
  readonly channel: string;
612
+ readonly integration_settings_descriptions?: readonly IntegrationSettingDescription[];
613
+ readonly connector_settings_descriptions?: readonly IntegrationSettingDescription[];
597
614
  }
598
615
 
599
616
  export interface IntegrationSetting {
@@ -874,4 +891,122 @@ export interface AddProjectFromRegistryRequest {
874
891
  registry_idn: string;
875
892
  registry_item_idn: string;
876
893
  registry_item_version: string | null;
894
+ }
895
+
896
+ // Create NEWO Customer Types (v3 API)
897
+
898
+ export interface CustomerMember {
899
+ email: string;
900
+ role: 'owner' | 'account_manager' | 'technical_owner' | 'referral';
901
+ tenants?: string[];
902
+ first_name?: string;
903
+ external_account_id?: string;
904
+ contact_email?: string;
905
+ }
906
+
907
+ export interface CustomerAttributeInput {
908
+ idn: string;
909
+ value: string;
910
+ is_hidden?: boolean;
911
+ group?: string;
912
+ }
913
+
914
+ export interface CustomerProjectInput {
915
+ idn: string;
916
+ title?: string;
917
+ registry_idn?: string;
918
+ registry_item_idn?: string;
919
+ registry_item_version?: string;
920
+ is_auto_update_enabled?: boolean;
921
+ }
922
+
923
+ export interface CreateNewoCustomerRequest {
924
+ secret: string;
925
+ customer: {
926
+ organization_name: string;
927
+ tenant: string;
928
+ comment?: string;
929
+ query_params?: string;
930
+ members: CustomerMember[];
931
+ contact_email: string;
932
+ contact_phone?: string;
933
+ external_customer_id?: string;
934
+ organization_type?: 'customer' | 'partner';
935
+ organization_status?: 'temporal' | 'permanent';
936
+ billing_method?: string;
937
+ platform_links?: {
938
+ portal?: string;
939
+ builder?: string;
940
+ creator?: string;
941
+ chat_widget?: string;
942
+ };
943
+ organization_logo?: {
944
+ title?: string;
945
+ external_logo_id?: string;
946
+ };
947
+ attributes?: CustomerAttributeInput[];
948
+ a_service?: {
949
+ partner_idn: string;
950
+ member_idn: string;
951
+ };
952
+ };
953
+ projects?: CustomerProjectInput[];
954
+ }
955
+
956
+ export interface CreateNewoCustomerResponse {
957
+ id: string;
958
+ idn: string;
959
+ }
960
+
961
+ // Analytics Logs Types
962
+
963
+ export type LogLevel = 'info' | 'warning' | 'error';
964
+ export type LogType = 'system' | 'operation' | 'call';
965
+
966
+ export interface LogEntry {
967
+ readonly log_id: string;
968
+ readonly level: LogLevel;
969
+ readonly log_type: LogType;
970
+ readonly project_idn: string;
971
+ readonly data: {
972
+ readonly external_event_id?: string;
973
+ readonly reference_idn?: string;
974
+ readonly operation_type?: string;
975
+ readonly arguments?: readonly { name: string; value: string }[];
976
+ readonly user_actor_id?: string;
977
+ readonly integration_idn?: string;
978
+ readonly connector_idn?: string;
979
+ readonly to_integration_idn?: string;
980
+ readonly to_connector_idn?: string;
981
+ readonly flow_idn?: string;
982
+ readonly skill_idn?: string;
983
+ readonly agent_idn?: string;
984
+ readonly line?: number;
985
+ readonly runtime_context_id?: string;
986
+ readonly [key: string]: unknown;
987
+ };
988
+ readonly message: string;
989
+ readonly datetime: string;
990
+ }
991
+
992
+ export interface LogsResponse {
993
+ readonly items: readonly LogEntry[];
994
+ }
995
+
996
+ export interface LogsQueryParams {
997
+ page?: number;
998
+ per?: number;
999
+ from_datetime?: string;
1000
+ to_datetime?: string;
1001
+ levels?: LogLevel | LogLevel[];
1002
+ log_types?: LogType | LogType[];
1003
+ message?: string;
1004
+ project_idn?: string;
1005
+ flow_idn?: string;
1006
+ skill_idn?: string;
1007
+ external_event_id?: string;
1008
+ runtime_context_id?: string;
1009
+ user_persona_ids?: string;
1010
+ user_actor_ids?: string;
1011
+ agent_persona_ids?: string;
877
1012
  }