newo 3.0.0 → 3.2.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +475 -347
  2. package/README.md +111 -0
  3. package/dist/api.d.ts +20 -1
  4. package/dist/api.js +110 -0
  5. package/dist/auth.js +4 -0
  6. package/dist/cli/commands/help.js +30 -1
  7. package/dist/cli/commands/list-actions.d.ts +3 -0
  8. package/dist/cli/commands/list-actions.js +89 -0
  9. package/dist/cli/commands/profile.d.ts +3 -0
  10. package/dist/cli/commands/profile.js +62 -0
  11. package/dist/cli/commands/pull-akb.d.ts +3 -0
  12. package/dist/cli/commands/pull-akb.js +19 -0
  13. package/dist/cli/commands/pull-attributes.js +7 -0
  14. package/dist/cli/commands/pull-integrations.d.ts +3 -0
  15. package/dist/cli/commands/pull-integrations.js +19 -0
  16. package/dist/cli/commands/push-akb.d.ts +3 -0
  17. package/dist/cli/commands/push-akb.js +19 -0
  18. package/dist/cli/commands/push-integrations.d.ts +3 -0
  19. package/dist/cli/commands/push-integrations.js +19 -0
  20. package/dist/cli/commands/sandbox.d.ts +14 -0
  21. package/dist/cli/commands/sandbox.js +306 -0
  22. package/dist/cli.js +33 -0
  23. package/dist/sandbox/chat.d.ts +40 -0
  24. package/dist/sandbox/chat.js +280 -0
  25. package/dist/sync/akb.d.ts +14 -0
  26. package/dist/sync/akb.js +175 -0
  27. package/dist/sync/attributes.d.ts +19 -0
  28. package/dist/sync/attributes.js +221 -2
  29. package/dist/sync/integrations.d.ts +23 -0
  30. package/dist/sync/integrations.js +340 -0
  31. package/dist/sync/projects.js +171 -1
  32. package/dist/sync/push.js +15 -0
  33. package/dist/sync/skill-files.js +1 -1
  34. package/dist/sync/status.js +4 -2
  35. package/dist/types.d.ts +209 -0
  36. package/package.json +14 -3
  37. package/src/api.ts +186 -1
  38. package/src/auth.ts +7 -2
  39. package/src/cli/commands/help.ts +30 -1
  40. package/src/cli/commands/list-actions.ts +112 -0
  41. package/src/cli/commands/profile.ts +79 -0
  42. package/src/cli/commands/pull-akb.ts +27 -0
  43. package/src/cli/commands/pull-attributes.ts +8 -0
  44. package/src/cli/commands/pull-integrations.ts +27 -0
  45. package/src/cli/commands/push-akb.ts +27 -0
  46. package/src/cli/commands/push-integrations.ts +27 -0
  47. package/src/cli/commands/sandbox.ts +365 -0
  48. package/src/cli.ts +41 -0
  49. package/src/sandbox/chat.ts +339 -0
  50. package/src/sync/akb.ts +205 -0
  51. package/src/sync/attributes.ts +269 -2
  52. package/src/sync/integrations.ts +403 -0
  53. package/src/sync/projects.ts +207 -1
  54. package/src/sync/push.ts +17 -0
  55. package/src/sync/skill-files.ts +1 -1
  56. package/src/sync/status.ts +4 -2
  57. package/src/types.ts +248 -0
package/README.md CHANGED
@@ -20,6 +20,7 @@ Sync NEWO "Project → Agent → Flow → Skills" structure to local files with:
20
20
  - 🧠 **AI skill formats** - Support for `.guidance` (AI prompts) and `.jinja` (NSL templates)
21
21
  - 📊 **Knowledge base import** - Bulk import AKB articles from structured text files
22
22
  - 💬 **Conversation history** - Extract and sync user conversations and personas
23
+ - 🧪 **Sandbox testing** - Interactive agent testing with conversation continuation (NEW v3.1.0)
23
24
  - 🔧 **CI/CD ready** - GitHub Actions integration for automated deployments
24
25
 
25
26
  ---
@@ -142,6 +143,7 @@ NEWO_REFRESH_URL=custom_refresh_endpoint # Custom refresh endpoint
142
143
  | `newo pull` | Download projects + attributes + metadata | • Real-time progress tracking (966+ skills)<br>• IDN-based file naming<br>• Automatic attributes.yaml generation<br>• `--force` for silent overwrite |
143
144
  | `newo push` | Upload local changes to NEWO | • Smart file validation<br>• Multiple file detection<br>• Hash-based change detection<br>• Safe error handling |
144
145
  | `newo status` | Show modified files with details | • Multiple file warnings<br>• Detailed change analysis<br>• Clean state validation<br>• Per-customer status |
146
+ | `newo sandbox` | Test agents in sandbox chat mode | • Single-command mode for automation<br>• Multi-turn conversation support<br>• Debug info for agent development<br>• Conversation continuation |
145
147
  | `newo conversations` | Pull conversation history | • User personas and chat history<br>• YAML format output<br>• Pagination support |
146
148
  | `newo list-customers` | List configured customers | • Shows default customer<br>• Multi-customer discovery |
147
149
  | `newo import-akb` | Import knowledge base articles | • Structured text parsing<br>• Bulk article import<br>• Validation and error reporting |
@@ -476,6 +478,107 @@ Add these secrets to your repository:
476
478
  node ./dist/cli.js push
477
479
  ```
478
480
 
481
+ ## Sandbox Testing (NEW v3.1.0)
482
+
483
+ Test your NEWO agents in real-time with sandbox chat mode. Perfect for development, debugging, and automated testing workflows.
484
+
485
+ ### Features
486
+ - **Single-command mode** - Send a message and get a response (ideal for automation)
487
+ - **Multi-turn conversations** - Continue chats with conversation context preserved
488
+ - **Debug information** - View flow execution, skill invocation, and session tracking
489
+ - **Unique sessions** - Each test creates a fresh persona for isolation
490
+
491
+ ### Usage
492
+
493
+ **Start a new conversation:**
494
+ ```bash
495
+ newo sandbox "Hello, I want to order a pizza"
496
+ ```
497
+
498
+ **Continue an existing conversation:**
499
+ ```bash
500
+ newo sandbox --actor <chat-id> "I want 2 large pepperoni pizzas"
501
+ ```
502
+
503
+ **With verbose debugging:**
504
+ ```bash
505
+ newo sandbox "Test message" --verbose
506
+ ```
507
+
508
+ ### Example: Multi-Turn Conversation
509
+
510
+ ```bash
511
+ # Turn 1: Start conversation
512
+ $ newo sandbox "I want to order delivery"
513
+
514
+ 📋 Chat Session Created:
515
+ Chat ID (actor_id): abc123...
516
+ Persona ID: xyz789...
517
+ Connector: convo_agent_sandbox
518
+ External ID: 2f99f7
519
+
520
+ 📤 You: I want to order delivery
521
+
522
+ 🤖 Agent:
523
+ Awesome! We can definitely get a delivery order started for you! What's your zip code, please?
524
+
525
+ 📊 Debug Summary:
526
+ Flow: CAMainFlow
527
+ Skill: _userMessageFastReplySkill
528
+ Session: 816c769a-8e1c-43e7-b22d-766c7bf63c33
529
+ Acts Processed: 1 (1 agent, 0 system)
530
+
531
+ 💡 To continue this conversation:
532
+ npx newo sandbox --actor abc123... "your next message"
533
+
534
+
535
+ # Turn 2: Continue conversation
536
+ $ newo sandbox --actor abc123... "90210"
537
+
538
+ 📤 You: 90210
539
+
540
+ 🤖 Agent:
541
+ Perfect! Now, could you please provide your delivery address?
542
+
543
+ 📊 Debug Summary:
544
+ Flow: CAMainFlow
545
+ Skill: CollectAddressSkill
546
+ Session: 816c769a-8e1c-43e7-b22d-766c7bf63c33
547
+ Acts Processed: 1 (1 agent, 0 user)
548
+ ```
549
+
550
+ ### Debug Information
551
+
552
+ **Standard Mode** shows:
553
+ - Flow execution path
554
+ - Skill invocation
555
+ - Session ID
556
+ - Act counts (agent vs. system messages)
557
+
558
+ **Verbose Mode** (`--verbose`) shows:
559
+ - All API requests and responses
560
+ - Complete act structure with arguments
561
+ - Runtime context IDs
562
+ - Detailed polling progress
563
+
564
+ ### Automated Testing Integration
565
+
566
+ Perfect for CI/CD workflows:
567
+
568
+ ```bash
569
+ # Test agent responses
570
+ RESPONSE=$(newo sandbox "test query" | grep "Agent:" | cut -d: -f2-)
571
+
572
+ # Validate response contains expected content
573
+ echo "$RESPONSE" | grep -q "expected text" && echo "✓ Test passed"
574
+
575
+ # Multi-turn testing
576
+ ACTOR_ID=$(newo sandbox "start conversation" | grep "Chat ID" | awk '{print $NF}')
577
+ newo sandbox --actor "$ACTOR_ID" "follow up message"
578
+ ```
579
+
580
+ ---
581
+
479
582
  ## AKB Import
480
583
 
481
584
  Import knowledge base articles from structured text files into NEWO personas:
@@ -1097,6 +1200,14 @@ NEWO CLI integrates with these NEWO platform endpoints:
1097
1200
  - `GET /api/v1/bff/customer/attributes?include_hidden=true` - Get customer attributes
1098
1201
  - `PUT /api/v1/customer/attributes/{attributeId}` - Update customer attribute
1099
1202
 
1203
+ ### Sandbox Testing (NEW v3.1.0)
1204
+ - `GET /api/v1/integrations` - List available integrations
1205
+ - `GET /api/v1/integrations/{id}/connectors` - List integration connectors
1206
+ - `POST /api/v1/customer/personas` - Create user persona for chat
1207
+ - `POST /api/v1/customer/personas/{id}/actors` - Create actor (chat session)
1208
+ - `POST /api/v1/chat/user/{actorId}` - Send chat message
1209
+ - `GET /api/v1/chat/history` - Poll for agent responses
1210
+
1100
1211
  ### Knowledge Base
1101
1212
  - `POST /api/v1/akb/append-manual` - Import AKB articles to persona
1102
1213
 
package/dist/api.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type AxiosInstance } from 'axios';
2
- import type { ProjectMeta, Agent, Skill, FlowEvent, FlowState, AkbImportArticle, CustomerProfile, CustomerAttribute, CustomerAttributesResponse, UserPersonaResponse, UserPersona, ChatHistoryParams, ChatHistoryResponse, CreateAgentRequest, CreateAgentResponse, CreateFlowRequest, CreateFlowResponse, CreateSkillRequest, CreateSkillResponse, CreateFlowEventRequest, CreateFlowEventResponse, CreateFlowStateRequest, CreateFlowStateResponse, CreateSkillParameterRequest, CreateSkillParameterResponse, CreateCustomerAttributeRequest, CreateCustomerAttributeResponse, CreatePersonaRequest, CreatePersonaResponse, CreateProjectRequest, CreateProjectResponse, PublishFlowRequest, PublishFlowResponse } from './types.js';
2
+ import type { ProjectMeta, Agent, Skill, FlowEvent, FlowState, AkbImportArticle, CustomerProfile, CustomerAttribute, CustomerAttributesResponse, UserPersonaResponse, UserPersona, ChatHistoryParams, ChatHistoryResponse, CreateAgentRequest, CreateAgentResponse, CreateFlowRequest, CreateFlowResponse, CreateSkillRequest, CreateSkillResponse, CreateFlowEventRequest, CreateFlowEventResponse, CreateFlowStateRequest, CreateFlowStateResponse, CreateSkillParameterRequest, CreateSkillParameterResponse, CreateCustomerAttributeRequest, CreateCustomerAttributeResponse, CreatePersonaRequest, CreatePersonaResponse, CreateProjectRequest, CreateProjectResponse, PublishFlowRequest, PublishFlowResponse, Integration, Connector, CreateSandboxPersonaRequest, CreateSandboxPersonaResponse, CreateActorRequest, CreateActorResponse, SendChatMessageRequest, ConversationActsParams, ConversationActsResponse, ScriptAction, IntegrationSetting, CreateConnectorRequest, CreateConnectorResponse, UpdateConnectorRequest, OutgoingWebhook, IncomingWebhook, PersonaSearchResponse, AkbTopicsResponse } from './types.js';
3
3
  export declare function makeClient(verbose?: boolean, token?: string): Promise<AxiosInstance>;
4
4
  export declare function listProjects(client: AxiosInstance): Promise<ProjectMeta[]>;
5
5
  export declare function listAgents(client: AxiosInstance, projectId: string): Promise<Agent[]>;
@@ -13,6 +13,10 @@ export declare function importAkbArticle(client: AxiosInstance, articleData: Akb
13
13
  export declare function getCustomerProfile(client: AxiosInstance): Promise<CustomerProfile>;
14
14
  export declare function getCustomerAttributes(client: AxiosInstance, includeHidden?: boolean): Promise<CustomerAttributesResponse>;
15
15
  export declare function updateCustomerAttribute(client: AxiosInstance, attribute: CustomerAttribute): Promise<void>;
16
+ export declare function getProjectAttributes(client: AxiosInstance, projectId: string, includeHidden?: boolean): Promise<CustomerAttributesResponse>;
17
+ export declare function updateProjectAttribute(client: AxiosInstance, projectId: string, attribute: CustomerAttribute): Promise<void>;
18
+ export declare function createProjectAttribute(client: AxiosInstance, projectId: string, attributeData: CreateCustomerAttributeRequest): Promise<CreateCustomerAttributeResponse>;
19
+ export declare function deleteProjectAttribute(client: AxiosInstance, projectId: string, attributeId: string): Promise<void>;
16
20
  export declare function listUserPersonas(client: AxiosInstance, page?: number, per?: number): Promise<UserPersonaResponse>;
17
21
  export declare function getUserPersona(client: AxiosInstance, personaId: string): Promise<UserPersona>;
18
22
  export declare function getAccount(client: AxiosInstance): Promise<{
@@ -36,4 +40,19 @@ export declare function createProject(client: AxiosInstance, projectData: Create
36
40
  export declare function deleteProject(client: AxiosInstance, projectId: string): Promise<void>;
37
41
  export declare function createPersona(client: AxiosInstance, personaData: CreatePersonaRequest): Promise<CreatePersonaResponse>;
38
42
  export declare function publishFlow(client: AxiosInstance, flowId: string, publishData: PublishFlowRequest): Promise<PublishFlowResponse>;
43
+ export declare function listIntegrations(client: AxiosInstance): Promise<Integration[]>;
44
+ export declare function listConnectors(client: AxiosInstance, integrationId: string): Promise<Connector[]>;
45
+ export declare function createSandboxPersona(client: AxiosInstance, personaData: CreateSandboxPersonaRequest): Promise<CreateSandboxPersonaResponse>;
46
+ export declare function createActor(client: AxiosInstance, personaId: string, actorData: CreateActorRequest): Promise<CreateActorResponse>;
47
+ export declare function sendChatMessage(client: AxiosInstance, actorId: string, messageData: SendChatMessageRequest): Promise<void>;
48
+ export declare function getConversationActs(client: AxiosInstance, params: ConversationActsParams): Promise<ConversationActsResponse>;
49
+ export declare function getScriptActions(client: AxiosInstance): Promise<ScriptAction[]>;
50
+ export declare function getIntegrationSettings(client: AxiosInstance, integrationId: string): Promise<IntegrationSetting[]>;
51
+ export declare function createConnector(client: AxiosInstance, integrationId: string, connectorData: CreateConnectorRequest): Promise<CreateConnectorResponse>;
52
+ export declare function updateConnector(client: AxiosInstance, connectorId: string, updateData: UpdateConnectorRequest): Promise<void>;
53
+ export declare function deleteConnector(client: AxiosInstance, connectorId: string): Promise<void>;
54
+ export declare function listOutgoingWebhooks(client: AxiosInstance): Promise<OutgoingWebhook[]>;
55
+ export declare function listIncomingWebhooks(client: AxiosInstance): Promise<IncomingWebhook[]>;
56
+ export declare function searchPersonas(client: AxiosInstance, isLinkedToAgent?: boolean, page?: number, per?: number): Promise<PersonaSearchResponse>;
57
+ export declare function getAkbTopics(client: AxiosInstance, personaId: string, page?: number, per?: number, orderBy?: string): Promise<AkbTopicsResponse>;
39
58
  //# sourceMappingURL=api.d.ts.map
package/dist/api.js CHANGED
@@ -121,6 +121,37 @@ export async function updateCustomerAttribute(client, attribute) {
121
121
  value_type: attribute.value_type
122
122
  });
123
123
  }
124
+ export async function getProjectAttributes(client, projectId, includeHidden = false) {
125
+ const response = await client.get(`/api/v1/bff/projects/${projectId}/attributes`, {
126
+ params: {
127
+ query: '',
128
+ include_hidden: includeHidden
129
+ }
130
+ });
131
+ return response.data;
132
+ }
133
+ export async function updateProjectAttribute(client, projectId, attribute) {
134
+ if (!attribute.id) {
135
+ throw new Error(`Project attribute ${attribute.idn} is missing ID - cannot update`);
136
+ }
137
+ await client.put(`/api/v1/designer/projects/${projectId}/attributes/${attribute.id}`, {
138
+ idn: attribute.idn,
139
+ value: attribute.value,
140
+ title: attribute.title,
141
+ description: attribute.description,
142
+ group: attribute.group,
143
+ is_hidden: attribute.is_hidden,
144
+ possible_values: attribute.possible_values,
145
+ value_type: attribute.value_type
146
+ });
147
+ }
148
+ export async function createProjectAttribute(client, projectId, attributeData) {
149
+ const response = await client.post(`/api/v1/designer/projects/${projectId}/attributes`, attributeData);
150
+ return response.data;
151
+ }
152
+ export async function deleteProjectAttribute(client, projectId, attributeId) {
153
+ await client.delete(`/api/v1/designer/projects/${projectId}/attributes/${attributeId}`);
154
+ }
124
155
  // Conversation API Functions
125
156
  export async function listUserPersonas(client, page = 1, per = 50) {
126
157
  const response = await client.get('/api/v1/bff/conversations/user-personas', {
@@ -229,4 +260,83 @@ export async function publishFlow(client, flowId, publishData) {
229
260
  const response = await client.post(`/api/v1/designer/flows/${flowId}/publish`, publishData);
230
261
  return response.data;
231
262
  }
263
+ // Sandbox Chat API Functions
264
+ export async function listIntegrations(client) {
265
+ const response = await client.get('/api/v1/integrations');
266
+ return response.data;
267
+ }
268
+ export async function listConnectors(client, integrationId) {
269
+ const response = await client.get(`/api/v1/integrations/${integrationId}/connectors`);
270
+ return response.data;
271
+ }
272
+ export async function createSandboxPersona(client, personaData) {
273
+ const response = await client.post('/api/v1/customer/personas', personaData);
274
+ return response.data;
275
+ }
276
+ export async function createActor(client, personaId, actorData) {
277
+ const response = await client.post(`/api/v1/customer/personas/${personaId}/actors`, actorData);
278
+ return response.data;
279
+ }
280
+ export async function sendChatMessage(client, actorId, messageData) {
281
+ await client.post(`/api/v1/chat/user/${actorId}`, messageData);
282
+ }
283
+ export async function getConversationActs(client, params) {
284
+ const queryParams = {
285
+ user_persona_id: params.user_persona_id,
286
+ user_actor_id: params.user_actor_id,
287
+ per: params.per || 100,
288
+ page: params.page || 1
289
+ };
290
+ // Only add agent_persona_id if provided
291
+ if (params.agent_persona_id) {
292
+ queryParams.agent_persona_id = params.agent_persona_id;
293
+ }
294
+ const response = await client.get('/api/v1/bff/conversations/acts', {
295
+ params: queryParams
296
+ });
297
+ return response.data;
298
+ }
299
+ // Script Actions API Functions
300
+ export async function getScriptActions(client) {
301
+ const response = await client.get('/api/v1/script/actions');
302
+ return response.data;
303
+ }
304
+ // Integration API Functions
305
+ export async function getIntegrationSettings(client, integrationId) {
306
+ const response = await client.get(`/api/v1/integrations/${integrationId}/settings`);
307
+ return response.data;
308
+ }
309
+ // Connector CRUD API Functions
310
+ export async function createConnector(client, integrationId, connectorData) {
311
+ const response = await client.post(`/api/v1/integrations/${integrationId}/connectors`, connectorData);
312
+ return response.data;
313
+ }
314
+ export async function updateConnector(client, connectorId, updateData) {
315
+ await client.put(`/api/v1/integrations/connectors/${connectorId}`, updateData);
316
+ }
317
+ export async function deleteConnector(client, connectorId) {
318
+ await client.delete(`/api/v1/integrations/connectors/${connectorId}`);
319
+ }
320
+ // Webhook API Functions
321
+ export async function listOutgoingWebhooks(client) {
322
+ const response = await client.get('/api/v1/webhooks');
323
+ return response.data;
324
+ }
325
+ export async function listIncomingWebhooks(client) {
326
+ const response = await client.get('/api/v1/webhooks/incoming');
327
+ return response.data;
328
+ }
329
+ // AKB (Knowledge Base) API Functions
330
+ export async function searchPersonas(client, isLinkedToAgent = true, page = 1, per = 30) {
331
+ const response = await client.get('/api/v1/bff/personas/search', {
332
+ params: { is_linked_to_agent: isLinkedToAgent, page, per }
333
+ });
334
+ return response.data;
335
+ }
336
+ export async function getAkbTopics(client, personaId, page = 1, per = 100, orderBy = 'created_at') {
337
+ const response = await client.get('/api/v1/akb/topics', {
338
+ params: { persona_id: personaId, page, per, order_by: orderBy }
339
+ });
340
+ return response.data;
341
+ }
232
342
  //# sourceMappingURL=api.js.map
package/dist/auth.js CHANGED
@@ -48,6 +48,10 @@ function validateUrl(url, name) {
48
48
  }
49
49
  // Enhanced logging function
50
50
  function logAuthEvent(level, message, meta) {
51
+ // Skip all logging if in quiet mode
52
+ if (process.env.NEWO_QUIET_MODE === 'true') {
53
+ return;
54
+ }
51
55
  const timestamp = new Date().toISOString();
52
56
  const logEntry = {
53
57
  timestamp,
@@ -10,7 +10,9 @@ Core Commands:
10
10
  newo push [--customer <idn>] [--no-publish] # upload modified *.guidance/*.jinja + attributes back to NEWO, publish flows by default
11
11
  newo status [--customer <idn>] # show modified files that would be pushed
12
12
  newo conversations [--customer <idn>] [--all] # download user conversations -> ./newo_customers/<idn>/conversations.yaml
13
- newo pull-attributes [--customer <idn>] # download customer attributes -> ./newo_customers/<idn>/attributes.yaml
13
+ newo sandbox "<message>" [--customer <idn>] # test agent in sandbox - single message mode (NEW v3.1.0)
14
+ newo sandbox --actor <id> "message" # continue existing sandbox conversation with chat ID
15
+ newo pull-attributes [--customer <idn>] # download customer + project attributes -> ./newo_customers/<idn>/attributes.yaml + projects/{project}/attributes.yaml
14
16
  newo list-customers # list available customers and their configuration
15
17
  newo meta [--customer <idn>] # get project metadata (debug command)
16
18
  newo import-akb <file> <persona_id> [--customer <idn>] # import AKB articles from structured text file
@@ -39,12 +41,20 @@ Enterprise Features:
39
41
  newo conversations [--customer <idn>] [--all] # download conversation history
40
42
  newo pull-attributes [--customer <idn>] # sync customer attributes
41
43
  newo import-akb <file> <persona_id> # import knowledge base articles
44
+ newo pull-integrations [--customer <idn>] # download integrations and connectors → ./newo_customers/<idn>/integrations/
45
+ newo push-integrations [--customer <idn>] # upload integration and connector changes to platform
46
+ newo list-actions [--customer <idn>] # list all available NSL/Jinja script actions with parameters
47
+ newo profile [--customer <idn>] # display customer profile information
48
+ newo pull-akb [--customer <idn>] # download AKB articles for all personas with agents → ./newo_customers/<idn>/akb/
49
+ newo push-akb [--customer <idn>] # upload AKB articles from local YAML files to platform
42
50
 
43
51
  Flags:
44
52
  --customer <idn> # specify customer (if not set, uses default or interactive selection)
45
53
  --all # include all available data (for conversations: all personas and acts)
46
54
  --force, -f # force overwrite without prompting (for pull command)
47
55
  --verbose, -v # enable detailed logging and progress information
56
+ --quiet, -q # minimal output for automation (sandbox only)
57
+ --actor <id> # continue existing sandbox chat with actor/chat ID
48
58
  --confirm # confirm destructive operations without prompting
49
59
  --no-publish # skip automatic flow publishing during push operations
50
60
 
@@ -107,13 +117,32 @@ Usage Examples:
107
117
  # Import AKB articles:
108
118
  newo import-akb articles.txt da4550db-2b95-4500-91ff-fb4b60fe7be9
109
119
 
120
+ # Sandbox testing (NEW v3.1.0):
121
+ newo sandbox "Hello, I want to order pizza" # Start new conversation
122
+ newo sandbox --actor abc123... "I want 2 large pizzas" # Continue conversation
123
+ newo sandbox "Test query" --verbose # With debug info
124
+ newo sandbox "Test query" --quiet # For automation/scripts
125
+
110
126
  File Structure:
111
127
  newo_customers/
112
128
  ├── <customer-idn>/
113
129
  │ ├── attributes.yaml # Customer attributes (pull-attributes)
114
130
  │ ├── conversations.yaml # User conversations and personas
131
+ │ ├── akb/ # AKB knowledge base articles (pull-akb)
132
+ │ │ └── <agent-idn>.yaml # AKB articles per agent persona
133
+ │ ├── integrations/ # Integration configurations (pull-integrations)
134
+ │ │ ├── integrations.yaml # Master integrations list
135
+ │ │ └── <integration-idn>/
136
+ │ │ ├── <integration-idn>.yaml # Integration metadata + settings (combined)
137
+ │ │ └── connectors/
138
+ │ │ └── <connector-idn>/ # Each connector in own directory
139
+ │ │ ├── <connector-idn>.yaml # Connector config
140
+ │ │ └── webhooks/ # Webhooks subdirectory (if any)
141
+ │ │ ├── outgoing.yaml # Outgoing webhooks
142
+ │ │ └── incoming.yaml # Incoming webhooks
115
143
  │ └── projects/
116
144
  │ └── <project-idn>/
145
+ │ ├── attributes.yaml # Project attributes (pull-attributes)
117
146
  │ ├── flows.yaml # Auto-generated project structure
118
147
  │ ├── metadata.yaml # Project metadata
119
148
  │ └── <agent-idn>/
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handleListActionsCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose: boolean): Promise<void>;
3
+ //# sourceMappingURL=list-actions.d.ts.map
@@ -0,0 +1,89 @@
1
+ /**
2
+ * List actions command handler
3
+ * Displays all available NSL/Jinja script actions
4
+ */
5
+ import { makeClient, getScriptActions } from '../../api.js';
6
+ import { getValidAccessToken } from '../../auth.js';
7
+ import { requireSingleCustomer } from '../customer-selection.js';
8
+ export async function handleListActionsCommand(customerConfig, args, verbose) {
9
+ const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
10
+ const accessToken = await getValidAccessToken(selectedCustomer);
11
+ const client = await makeClient(verbose, accessToken);
12
+ console.log(`📋 Fetching available script actions...\n`);
13
+ const actions = await getScriptActions(client);
14
+ console.log(`✅ Found ${actions.length} script actions\n`);
15
+ // Group actions by category
16
+ const categories = new Map();
17
+ for (const action of actions) {
18
+ // Categorize by prefix (e.g., Get, Create, Delete, Gen, etc.)
19
+ const category = getCategoryFromActionTitle(action.title);
20
+ if (!categories.has(category)) {
21
+ categories.set(category, []);
22
+ }
23
+ categories.get(category).push(action);
24
+ }
25
+ // Display actions by category
26
+ const sortedCategories = Array.from(categories.entries()).sort(([a], [b]) => a.localeCompare(b));
27
+ for (const [category, categoryActions] of sortedCategories) {
28
+ console.log(`\n${category}:`);
29
+ for (const action of categoryActions.sort((a, b) => a.title.localeCompare(b.title))) {
30
+ console.log(` • ${action.title}`);
31
+ // Show parameters if verbose
32
+ if (verbose && Object.keys(action.arguments).length > 0) {
33
+ console.log(` Parameters:`);
34
+ for (const [paramName, paramSchema] of Object.entries(action.arguments)) {
35
+ const required = paramSchema.default === undefined && !paramSchema.anyOf ? ' (required)' : '';
36
+ console.log(` - ${paramName}: ${paramSchema.type}${required}`);
37
+ }
38
+ }
39
+ }
40
+ }
41
+ console.log(`\n💡 Use --verbose flag to see parameter details\n`);
42
+ }
43
+ /**
44
+ * Categorize action by its title prefix
45
+ */
46
+ function getCategoryFromActionTitle(title) {
47
+ // Common prefixes
48
+ const prefixes = [
49
+ 'Gen',
50
+ 'Get',
51
+ 'Create',
52
+ 'Delete',
53
+ 'Update',
54
+ 'Set',
55
+ 'Send',
56
+ 'Append',
57
+ 'Build',
58
+ 'Parse',
59
+ 'Validate',
60
+ 'Format',
61
+ 'Convert',
62
+ 'Filter',
63
+ 'Sort',
64
+ 'Search'
65
+ ];
66
+ for (const prefix of prefixes) {
67
+ if (title.startsWith(prefix)) {
68
+ return `${prefix} Actions`;
69
+ }
70
+ }
71
+ // Special cases
72
+ if (title.includes('Array') || title.includes('JSON')) {
73
+ return 'Data Manipulation';
74
+ }
75
+ if (title.includes('Actor') || title.includes('Persona')) {
76
+ return 'User Management';
77
+ }
78
+ if (title.includes('Message') || title.includes('Chat')) {
79
+ return 'Communication';
80
+ }
81
+ if (title.includes('Akb') || title.includes('Knowledge')) {
82
+ return 'Knowledge Base';
83
+ }
84
+ if (title.includes('Attribute')) {
85
+ return 'Attributes';
86
+ }
87
+ return 'Other Actions';
88
+ }
89
+ //# sourceMappingURL=list-actions.js.map
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handleProfileCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose: boolean): Promise<void>;
3
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Profile command handler
3
+ * Displays customer profile information
4
+ */
5
+ import { makeClient, getCustomerProfile } from '../../api.js';
6
+ import { getValidAccessToken } from '../../auth.js';
7
+ import { requireSingleCustomer } from '../customer-selection.js';
8
+ export async function handleProfileCommand(customerConfig, args, verbose) {
9
+ const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
10
+ const accessToken = await getValidAccessToken(selectedCustomer);
11
+ const client = await makeClient(verbose, accessToken);
12
+ console.log(`👤 Fetching customer profile for ${selectedCustomer.idn}...\n`);
13
+ const profile = await getCustomerProfile(client);
14
+ // Display formatted profile information
15
+ console.log(`Organization: ${profile.organization_name || 'N/A'}`);
16
+ console.log(`Customer IDN: ${profile.idn}`);
17
+ console.log(`Email: ${profile.email || 'N/A'}`);
18
+ console.log(`Status: ${profile.status || 'N/A'} ${profile.is_active ? '(active)' : '(inactive)'}`);
19
+ if (profile.phone_number) {
20
+ console.log(`Phone: ${profile.phone_number}`);
21
+ }
22
+ if (profile.website) {
23
+ console.log(`Website: ${profile.website}`);
24
+ }
25
+ if (profile.referral_code) {
26
+ console.log(`Referral Code: ${profile.referral_code}`);
27
+ }
28
+ // Platform links
29
+ if (profile.platform_links) {
30
+ console.log(`\nPlatform Links:`);
31
+ if (profile.platform_links.portal) {
32
+ console.log(` Portal: ${profile.platform_links.portal}`);
33
+ }
34
+ if (profile.platform_links.builder) {
35
+ console.log(` Builder: ${profile.platform_links.builder}`);
36
+ }
37
+ if (profile.platform_links.creator) {
38
+ console.log(` Creator: ${profile.platform_links.creator}`);
39
+ }
40
+ if (profile.platform_links.chat_widget) {
41
+ console.log(` Chat Widget: ${profile.platform_links.chat_widget}`);
42
+ }
43
+ }
44
+ // Show additional fields if verbose
45
+ if (verbose) {
46
+ console.log(`\nAdditional Information:`);
47
+ console.log(` Customer ID: ${profile.id}`);
48
+ console.log(` Tenant: ${profile.tenant || 'N/A'}`);
49
+ console.log(` Organization Type: ${profile.organization_type || 'N/A'}`);
50
+ console.log(` External Customer ID: ${profile.external_customer_id || 'N/A'}`);
51
+ if (profile.industry && profile.industry.length > 0) {
52
+ console.log(` Industry: ${profile.industry.join(', ')}`);
53
+ }
54
+ if (profile.billing_email) {
55
+ console.log(` Billing Email: ${profile.billing_email}`);
56
+ }
57
+ console.log(` BAA Signed: ${profile.is_baa_signed ? 'Yes' : 'No'}`);
58
+ console.log(` Marked for Deletion: ${profile.is_marked_for_deletion ? 'Yes' : 'No'}`);
59
+ }
60
+ console.log();
61
+ }
62
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handlePullAkbCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose: boolean): Promise<void>;
3
+ //# sourceMappingURL=pull-akb.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Pull AKB command handler
3
+ * Downloads AKB (knowledge base) articles for all personas linked to agents
4
+ */
5
+ import path from 'path';
6
+ import { makeClient } from '../../api.js';
7
+ import { pullAkb } from '../../sync/akb.js';
8
+ import { getValidAccessToken } from '../../auth.js';
9
+ import { requireSingleCustomer } from '../customer-selection.js';
10
+ export async function handlePullAkbCommand(customerConfig, args, verbose) {
11
+ const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
12
+ const accessToken = await getValidAccessToken(selectedCustomer);
13
+ const client = await makeClient(verbose, accessToken);
14
+ const customerDir = path.join(process.cwd(), 'newo_customers', selectedCustomer.idn);
15
+ console.log(`📚 Fetching AKB articles for ${selectedCustomer.idn}...`);
16
+ await pullAkb(client, customerDir, verbose);
17
+ console.log(`✅ AKB articles saved to newo_customers/${selectedCustomer.idn}/akb/`);
18
+ }
19
+ //# sourceMappingURL=pull-akb.js.map
@@ -1,16 +1,23 @@
1
1
  /**
2
2
  * Pull attributes command handler
3
+ * Pulls both customer and project attributes
3
4
  */
4
5
  import { makeClient } from '../../api.js';
5
6
  import { saveCustomerAttributes } from '../../sync.js';
7
+ import { pullAllProjectAttributes } from '../../sync/attributes.js';
6
8
  import { getValidAccessToken } from '../../auth.js';
7
9
  import { requireSingleCustomer } from '../customer-selection.js';
8
10
  export async function handlePullAttributesCommand(customerConfig, args, verbose) {
9
11
  const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
10
12
  const accessToken = await getValidAccessToken(selectedCustomer);
11
13
  const client = await makeClient(verbose, accessToken);
14
+ // Pull customer attributes
12
15
  console.log(`🔍 Fetching customer attributes for ${selectedCustomer.idn}...`);
13
16
  await saveCustomerAttributes(client, selectedCustomer, verbose);
14
17
  console.log(`✅ Customer attributes saved to newo_customers/${selectedCustomer.idn}/attributes.yaml`);
18
+ // Pull project attributes
19
+ console.log(`\n📋 Fetching project attributes for ${selectedCustomer.idn}...`);
20
+ await pullAllProjectAttributes(client, selectedCustomer, verbose);
21
+ console.log(`✅ Project attributes saved to newo_customers/${selectedCustomer.idn}/projects/{project_idn}/attributes.yaml`);
15
22
  }
16
23
  //# sourceMappingURL=pull-attributes.js.map
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handlePullIntegrationsCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose: boolean): Promise<void>;
3
+ //# sourceMappingURL=pull-integrations.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Pull integrations command handler
3
+ * Downloads all integrations and connectors from NEWO platform
4
+ */
5
+ import path from 'path';
6
+ import { makeClient } from '../../api.js';
7
+ import { pullIntegrations } from '../../sync/integrations.js';
8
+ import { getValidAccessToken } from '../../auth.js';
9
+ import { requireSingleCustomer } from '../customer-selection.js';
10
+ export async function handlePullIntegrationsCommand(customerConfig, args, verbose) {
11
+ const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
12
+ const accessToken = await getValidAccessToken(selectedCustomer);
13
+ const client = await makeClient(verbose, accessToken);
14
+ const customerDir = path.join(process.cwd(), 'newo_customers', selectedCustomer.idn);
15
+ console.log(`📦 Fetching integrations for ${selectedCustomer.idn}...`);
16
+ await pullIntegrations(client, customerDir, verbose);
17
+ console.log(`✅ Integrations saved to newo_customers/${selectedCustomer.idn}/integrations/`);
18
+ }
19
+ //# sourceMappingURL=pull-integrations.js.map
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handlePushAkbCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose: boolean): Promise<void>;
3
+ //# sourceMappingURL=push-akb.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Push AKB command handler
3
+ * Uploads AKB (knowledge base) articles to NEWO platform
4
+ */
5
+ import path from 'path';
6
+ import { makeClient } from '../../api.js';
7
+ import { pushAkb } from '../../sync/akb.js';
8
+ import { getValidAccessToken } from '../../auth.js';
9
+ import { requireSingleCustomer } from '../customer-selection.js';
10
+ export async function handlePushAkbCommand(customerConfig, args, verbose) {
11
+ const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
12
+ const accessToken = await getValidAccessToken(selectedCustomer);
13
+ const client = await makeClient(verbose, accessToken);
14
+ const customerDir = path.join(process.cwd(), 'newo_customers', selectedCustomer.idn);
15
+ console.log(`📤 Pushing AKB articles for ${selectedCustomer.idn}...`);
16
+ await pushAkb(client, customerDir, verbose);
17
+ console.log(`✅ AKB articles pushed successfully`);
18
+ }
19
+ //# sourceMappingURL=push-akb.js.map
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handlePushIntegrationsCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose: boolean): Promise<void>;
3
+ //# sourceMappingURL=push-integrations.d.ts.map