newo 3.2.0 → 3.3.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/src/api.ts CHANGED
@@ -496,4 +496,60 @@ export async function getAkbTopics(
496
496
  params: { persona_id: personaId, page, per, order_by: orderBy }
497
497
  });
498
498
  return response.data;
499
+ }
500
+
501
+ // Project update
502
+ export async function updateProject(
503
+ client: AxiosInstance,
504
+ projectId: string,
505
+ updateData: Partial<{
506
+ title: string;
507
+ description: string;
508
+ is_auto_update_enabled: boolean;
509
+ registry_idn: string;
510
+ registry_item_idn: string | null;
511
+ registry_item_version: string | null;
512
+ }>
513
+ ): Promise<void> {
514
+ await client.put(`/api/v1/designer/projects/${projectId}`, updateData);
515
+ }
516
+
517
+ // Agent update
518
+ export async function updateAgent(
519
+ client: AxiosInstance,
520
+ agentId: string,
521
+ updateData: Partial<{
522
+ title: string;
523
+ description: string;
524
+ persona_id: string | null;
525
+ }>
526
+ ): Promise<void> {
527
+ await client.put(`/api/v1/designer/agents/${agentId}`, updateData);
528
+ }
529
+
530
+ // Webhook creation
531
+ export async function createOutgoingWebhook(
532
+ client: AxiosInstance,
533
+ webhookData: {
534
+ connector_idn: string;
535
+ event_idn: string;
536
+ url: string;
537
+ method: string;
538
+ headers?: Record<string, string>;
539
+ body_template?: string;
540
+ }
541
+ ): Promise<{ id: string }> {
542
+ const response = await client.post('/api/v1/webhooks', webhookData);
543
+ return response.data;
544
+ }
545
+
546
+ export async function createIncomingWebhook(
547
+ client: AxiosInstance,
548
+ webhookData: {
549
+ connector_idn: string;
550
+ event_idn: string;
551
+ }
552
+ ): Promise<{ id: string; url: string }> {
553
+ const response = await client.post('/api/v1/webhooks/incoming', webhookData);
554
+ return response.data;
499
555
  }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Webhook creation command handler
3
+ */
4
+ import { makeClient } from '../../api.js';
5
+ import { getValidAccessToken } from '../../auth.js';
6
+ import { selectSingleCustomer } from '../customer-selection.js';
7
+ import { customerDir } from '../../fsutil.js';
8
+ import fs from 'fs-extra';
9
+ import yaml from 'js-yaml';
10
+ import path from 'path';
11
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
12
+
13
+ export async function handleCreateWebhooksCommand(
14
+ customerConfig: MultiCustomerConfig,
15
+ args: CliArgs,
16
+ verbose: boolean
17
+ ): Promise<void> {
18
+ const { selectedCustomer } = selectSingleCustomer(
19
+ customerConfig,
20
+ args.customer as string | undefined
21
+ );
22
+
23
+ if (!selectedCustomer) {
24
+ console.error('āŒ No customer selected');
25
+ process.exit(1);
26
+ }
27
+
28
+ const accessToken = await getValidAccessToken(selectedCustomer);
29
+ const client = await makeClient(verbose, accessToken);
30
+
31
+ console.log(`\nšŸ“” Creating webhooks for ${selectedCustomer.idn}...\n`);
32
+
33
+ const custDir = customerDir(selectedCustomer.idn);
34
+ let outgoingCreated = 0;
35
+ let incomingCreated = 0;
36
+
37
+ // Create outgoing webhooks
38
+ const outgoingFile = path.join(custDir, 'integrations/api/connectors/webhook/webhooks/outgoing.yaml');
39
+ if (await fs.pathExists(outgoingFile)) {
40
+ const outgoingData = yaml.load(await fs.readFile(outgoingFile, 'utf8')) as any;
41
+ const webhooks = outgoingData.webhooks || [];
42
+
43
+ console.log(`Found ${webhooks.length} outgoing webhooks in YAML file`);
44
+
45
+ for (const webhook of webhooks) {
46
+ try {
47
+ await client.post('/api/v1/webhooks', {
48
+ idn: webhook.idn,
49
+ description: webhook.description || '',
50
+ connector_idn: webhook.connector_idn,
51
+ url: webhook.url,
52
+ command_idns: webhook.command_idns || []
53
+ });
54
+ outgoingCreated++;
55
+ console.log(` āœ… Created outgoing: ${webhook.idn}`);
56
+ } catch (error: any) {
57
+ const status = error.response?.status;
58
+
59
+ if (status === 409) {
60
+ console.log(` ā„¹ļø Already exists: ${webhook.idn}`);
61
+ } else {
62
+ console.error(` āŒ Failed: ${webhook.idn} - ${error.response?.data?.reason || error.message}`);
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ // Create incoming webhooks
69
+ const incomingFile = path.join(custDir, 'integrations/api/connectors/webhook/webhooks/incoming.yaml');
70
+ if (await fs.pathExists(incomingFile)) {
71
+ const incomingData = yaml.load(await fs.readFile(incomingFile, 'utf8')) as any;
72
+ const webhooks = incomingData.webhooks || [];
73
+
74
+ console.log(`\nFound ${webhooks.length} incoming webhooks in YAML file`);
75
+
76
+ for (const webhook of webhooks) {
77
+ try {
78
+ await client.post('/api/v1/webhooks/incoming', {
79
+ idn: webhook.idn,
80
+ description: webhook.description || '',
81
+ connector_idn: webhook.connector_idn,
82
+ event_idns: webhook.event_idns || [],
83
+ allowed_ips: webhook.allowed_ips || []
84
+ });
85
+ incomingCreated++;
86
+ console.log(` āœ… Created incoming: ${webhook.idn}`);
87
+ } catch (error: any) {
88
+ const status = error.response?.status;
89
+
90
+ if (status === 409) {
91
+ console.log(` ā„¹ļø Already exists: ${webhook.idn}`);
92
+ } else {
93
+ console.error(` āŒ Failed: ${webhook.idn} - ${error.response?.data?.reason || error.message}`);
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ console.log(`\nāœ… Created ${outgoingCreated} outgoing and ${incomingCreated} incoming webhooks\n`);
100
+ }
@@ -49,6 +49,11 @@ Enterprise Features:
49
49
  newo pull-akb [--customer <idn>] # download AKB articles for all personas with agents → ./newo_customers/<idn>/akb/
50
50
  newo push-akb [--customer <idn>] # upload AKB articles from local YAML files to platform
51
51
 
52
+ Account Migration (NEW):
53
+ newo migrate-account --source <idn> --dest <idn> [--yes] # migrate complete account from source to destination
54
+ newo verify --source <idn> --dest <idn> # verify migration by comparing entity counts
55
+ newo create-webhooks [--customer <idn>] # create webhooks from YAML files
56
+
52
57
  Flags:
53
58
  --customer <idn> # specify customer (if not set, uses default or interactive selection)
54
59
  --all # include all available data (for conversations: all personas and acts)
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Account migration command handler
3
+ */
4
+ import { makeClient } from '../../api.js';
5
+ import { migrateAccount } from '../../sync/migrate.js';
6
+ import { getValidAccessToken } from '../../auth.js';
7
+ import { getCustomer } from '../../customer.js';
8
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
9
+
10
+ export async function handleMigrateAccountCommand(
11
+ customerConfig: MultiCustomerConfig,
12
+ args: CliArgs,
13
+ verbose: boolean
14
+ ): Promise<void> {
15
+ // Get source and destination customer IDNs
16
+ const sourceIdn = args.source as string | undefined;
17
+ const destIdn = args.dest as string | undefined;
18
+
19
+ if (!sourceIdn || !destIdn) {
20
+ console.error('āŒ Usage: newo migrate-account --source <sourceIdn> --dest <destIdn>');
21
+ console.error('Example: newo migrate-account --source NEWO_bb5lmJjg --dest NEq9OCwSXw');
22
+ process.exit(1);
23
+ }
24
+
25
+ const sourceCustomer = getCustomer(customerConfig, sourceIdn);
26
+ const destCustomer = getCustomer(customerConfig, destIdn);
27
+
28
+ if (!sourceCustomer) {
29
+ console.error(`āŒ Source customer ${sourceIdn} not found in configuration`);
30
+ process.exit(1);
31
+ }
32
+
33
+ if (!destCustomer) {
34
+ console.error(`āŒ Destination customer ${destIdn} not found in configuration`);
35
+ process.exit(1);
36
+ }
37
+
38
+ console.log('\nšŸ”„ Account Migration');
39
+ console.log(`Source: ${sourceIdn}`);
40
+ console.log(`Destination: ${destIdn}`);
41
+ console.log('\nāš ļø This will copy ALL data from source to destination');
42
+ console.log('āš ļø Source account will NOT be modified (read-only)');
43
+
44
+ // Confirm migration
45
+ if (!args.yes && !args.y) {
46
+ const readline = await import('readline');
47
+ const rl = readline.createInterface({
48
+ input: process.stdin,
49
+ output: process.stdout
50
+ });
51
+
52
+ const answer = await new Promise<string>((resolve) => {
53
+ rl.question('\nProceed with migration? (yes/NO): ', resolve);
54
+ });
55
+ rl.close();
56
+
57
+ if (answer.toLowerCase() !== 'yes') {
58
+ console.log('āŒ Migration cancelled');
59
+ return;
60
+ }
61
+ }
62
+
63
+ // Authenticate
64
+ const sourceToken = await getValidAccessToken(sourceCustomer);
65
+ const destToken = await getValidAccessToken(destCustomer);
66
+
67
+ const sourceClient = await makeClient(verbose, sourceToken);
68
+ const destClient = await makeClient(verbose, destToken);
69
+
70
+ // Run migration
71
+ const result = await migrateAccount({
72
+ sourceCustomer,
73
+ destCustomer,
74
+ sourceClient,
75
+ destClient,
76
+ verbose
77
+ });
78
+
79
+ // Print summary
80
+ console.log('\nšŸ“Š MIGRATION SUMMARY\n');
81
+ console.log(`Projects created: ${result.projectsCreated}`);
82
+ console.log(`Agents created: ${result.agentsCreated}`);
83
+ console.log(`Flows created: ${result.flowsCreated}`);
84
+ console.log(`Skills created: ${result.skillsCreated}`);
85
+ console.log(`Attributes migrated: ${result.attributesMigrated}`);
86
+ console.log(`Personas created: ${result.personasCreated}`);
87
+ console.log(`AKB articles imported: ${result.articlesImported}`);
88
+ console.log(`Connectors created: ${result.connectorsCreated}`);
89
+ console.log(`Webhooks created: ${result.webhooksCreated}`);
90
+
91
+ if (result.errors.length > 0) {
92
+ console.log(`\nāš ļø Errors: ${result.errors.length}`);
93
+ result.errors.forEach(err => console.error(` - ${err}`));
94
+ }
95
+
96
+ console.log(`\n${result.success ? 'āœ… Migration completed successfully!' : 'āŒ Migration completed with errors'}\n`);
97
+
98
+ if (result.success) {
99
+ console.log('šŸ“‹ Next steps:');
100
+ console.log(` 1. Push skill content: npx newo push --customer ${destIdn}`);
101
+ console.log(` 2. Verify migration: npx newo verify --source ${sourceIdn} --dest ${destIdn}`);
102
+ console.log(` 3. Test agent: npx newo sandbox "test message" --customer ${destIdn}\n`);
103
+ }
104
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Migration verification command handler
3
+ */
4
+ import { makeClient, listProjects, listAgents, listFlowSkills } from '../../api.js';
5
+ import { getValidAccessToken } from '../../auth.js';
6
+ import { getCustomer } from '../../customer.js';
7
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
8
+
9
+ export async function handleVerifyMigrationCommand(
10
+ customerConfig: MultiCustomerConfig,
11
+ args: CliArgs,
12
+ verbose: boolean
13
+ ): Promise<void> {
14
+ const sourceIdn = args.source as string | undefined;
15
+ const destIdn = args.dest as string | undefined;
16
+
17
+ if (!sourceIdn || !destIdn) {
18
+ console.error('āŒ Usage: newo verify --source <sourceIdn> --dest <destIdn>');
19
+ console.error('Example: newo verify --source NEWO_bb5lmJjg --dest NEq9OCwSXw');
20
+ process.exit(1);
21
+ }
22
+
23
+ const sourceCustomer = getCustomer(customerConfig, sourceIdn);
24
+ const destCustomer = getCustomer(customerConfig, destIdn);
25
+
26
+ if (!sourceCustomer || !destCustomer) {
27
+ console.error('āŒ Customer not found in configuration');
28
+ process.exit(1);
29
+ }
30
+
31
+ console.log('\nšŸ” Migration Verification');
32
+ console.log(`Source: ${sourceIdn}`);
33
+ console.log(`Destination: ${destIdn}\n`);
34
+
35
+ const sourceToken = await getValidAccessToken(sourceCustomer);
36
+ const destToken = await getValidAccessToken(destCustomer);
37
+
38
+ const sourceClient = await makeClient(verbose, sourceToken);
39
+ const destClient = await makeClient(verbose, destToken);
40
+
41
+ // Count entities
42
+ const sourceProjects = await listProjects(sourceClient);
43
+ const destProjects = await listProjects(destClient);
44
+
45
+ let srcAgents = 0, srcFlows = 0, srcSkills = 0;
46
+ let dstAgents = 0, dstFlows = 0, dstSkills = 0;
47
+
48
+ for (const proj of sourceProjects) {
49
+ const agents = await listAgents(sourceClient, proj.id);
50
+ srcAgents += agents.length;
51
+
52
+ for (const agent of agents) {
53
+ srcFlows += (agent.flows || []).length;
54
+
55
+ for (const flow of agent.flows || []) {
56
+ const skills = await listFlowSkills(sourceClient, flow.id);
57
+ srcSkills += skills.length;
58
+ }
59
+ }
60
+ }
61
+
62
+ for (const proj of destProjects.filter(p => p.idn !== 'test')) {
63
+ const agents = await listAgents(destClient, proj.id);
64
+ dstAgents += agents.length;
65
+
66
+ for (const agent of agents) {
67
+ dstFlows += (agent.flows || []).length;
68
+
69
+ for (const flow of agent.flows || []) {
70
+ const skills = await listFlowSkills(destClient, flow.id);
71
+ dstSkills += skills.length;
72
+ }
73
+ }
74
+ }
75
+
76
+ console.log('šŸ“Š Entity Counts:\n');
77
+ console.log(`Projects: ${sourceProjects.length} → ${destProjects.filter(p => p.idn !== 'test').length} ${sourceProjects.length === destProjects.filter(p => p.idn !== 'test').length ? 'āœ…' : 'āŒ'}`);
78
+ console.log(`Agents: ${srcAgents} → ${dstAgents} ${srcAgents === dstAgents ? 'āœ…' : 'āŒ'}`);
79
+ console.log(`Flows: ${srcFlows} → ${dstFlows} ${srcFlows === dstFlows ? 'āœ…' : 'āŒ'}`);
80
+ console.log(`Skills: ${srcSkills} → ${dstSkills} ${srcSkills === dstSkills ? 'āœ…' : 'āŒ'}\n`);
81
+
82
+ if (srcAgents === dstAgents && srcFlows === dstFlows && srcSkills === dstSkills) {
83
+ console.log('āœ… All entity counts match - Migration successful!\n');
84
+ } else {
85
+ console.log('āš ļø Entity counts differ - Migration may be incomplete\n');
86
+ process.exit(1);
87
+ }
88
+ }
package/src/cli.ts CHANGED
@@ -35,6 +35,9 @@ import { handleListActionsCommand } from './cli/commands/list-actions.js';
35
35
  import { handleProfileCommand } from './cli/commands/profile.js';
36
36
  import { handlePullAkbCommand } from './cli/commands/pull-akb.js';
37
37
  import { handlePushAkbCommand } from './cli/commands/push-akb.js';
38
+ import { handleMigrateAccountCommand } from './cli/commands/migrate-account.js';
39
+ import { handleVerifyMigrationCommand } from './cli/commands/verify-migration.js';
40
+ import { handleCreateWebhooksCommand } from './cli/commands/create-webhooks.js';
38
41
  import type { CliArgs, NewoApiError } from './types.js';
39
42
 
40
43
  dotenv.config();
@@ -188,6 +191,19 @@ async function main(): Promise<void> {
188
191
  await handlePushAkbCommand(customerConfig, args, verbose);
189
192
  break;
190
193
 
194
+ case 'migrate-account':
195
+ await handleMigrateAccountCommand(customerConfig, args, verbose);
196
+ break;
197
+
198
+ case 'verify':
199
+ case 'verify-migration':
200
+ await handleVerifyMigrationCommand(customerConfig, args, verbose);
201
+ break;
202
+
203
+ case 'create-webhooks':
204
+ await handleCreateWebhooksCommand(customerConfig, args, verbose);
205
+ break;
206
+
191
207
  default:
192
208
  console.error('Unknown command:', cmd);
193
209
  console.error('Run "newo --help" for usage information');