newo 3.3.2 → 3.4.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/CHANGELOG.md +37 -4
- package/README.md +8 -8
- package/dist/api.d.ts +4 -1
- package/dist/api.js +14 -0
- package/dist/cli/commands/add-project.d.ts +3 -0
- package/dist/cli/commands/add-project.js +136 -0
- package/dist/cli/commands/help.js +12 -1
- package/dist/cli/commands/list-registries.d.ts +3 -0
- package/dist/cli/commands/list-registries.js +39 -0
- package/dist/cli/commands/list-registry-items.d.ts +3 -0
- package/dist/cli/commands/list-registry-items.js +112 -0
- package/dist/cli.js +12 -0
- package/dist/types.d.ts +38 -0
- package/package.json +1 -1
- package/src/api.ts +25 -1
- package/src/cli/commands/add-project.ts +159 -0
- package/src/cli/commands/help.ts +12 -1
- package/src/cli/commands/list-registries.ts +53 -0
- package/src/cli/commands/list-registry-items.ts +149 -0
- package/src/cli.ts +15 -0
- package/src/types.ts +43 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.4.0] - 2025-12-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Project Registry**: Browse and install project templates from NEWO registries
|
|
15
|
+
- `newo list-registries` - List available registries (production, staging, development, etc.)
|
|
16
|
+
- `newo list-registry-items <registry-idn>` - Browse project templates in a registry with version info
|
|
17
|
+
- `newo add-project <idn> --item <template-idn>` - Install project from registry template
|
|
18
|
+
- Support for multiple registries: production, staging, development, testing, and custom registries
|
|
19
|
+
- Version selection with `--version` flag or automatic latest version detection
|
|
20
|
+
- Auto-update support with `--auto-update` flag for automatic updates when new versions are published
|
|
21
|
+
- Grouped display showing unique projects with version counts and active installations
|
|
22
|
+
- `--all` flag to show all versions of each project template
|
|
23
|
+
|
|
24
|
+
- **Registry Types** (`src/types.ts`):
|
|
25
|
+
- `Registry` - Registry metadata (id, idn, account_id, is_public)
|
|
26
|
+
- `RegistryItem` - Project template with versioning (id, idn, version, project_image, active_project_count)
|
|
27
|
+
- `RegistryItemProjectImage` - Project image metadata for templates
|
|
28
|
+
- `AddProjectFromRegistryRequest` - Request type for registry-based project installation
|
|
29
|
+
|
|
30
|
+
- **Registry API Functions** (`src/api.ts`):
|
|
31
|
+
- `listRegistries()` - Fetch available registries
|
|
32
|
+
- `listRegistryItems()` - Fetch project templates from a specific registry
|
|
33
|
+
- `addProjectFromRegistry()` - Create project from registry template
|
|
34
|
+
|
|
35
|
+
- **Registry Command Handlers** (`src/cli/commands/`):
|
|
36
|
+
- `list-registries.ts` - Display registries in formatted table
|
|
37
|
+
- `list-registry-items.ts` - Display projects with version grouping and sorting
|
|
38
|
+
- `add-project.ts` - Install templates with validation and progress feedback
|
|
39
|
+
|
|
40
|
+
### Enhanced
|
|
41
|
+
|
|
42
|
+
- **Help Command**: Added registry commands documentation and examples
|
|
43
|
+
- **CLAUDE.md**: Updated with registry feature documentation, API endpoints, and data flow
|
|
44
|
+
|
|
10
45
|
## [3.3.0] - 2025-10-20
|
|
11
46
|
|
|
12
47
|
### Added
|
|
@@ -78,15 +113,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
78
113
|
- 100% entity match validation (projects, agents, flows, skills)
|
|
79
114
|
- 100% file integrity verification (SHA256 checksums on attributes)
|
|
80
115
|
- 100% webhook creation success (all 5 webhooks verified)
|
|
81
|
-
-
|
|
116
|
+
- Significant time reduction compared to manual migration process
|
|
82
117
|
- **Entity Count Verification**: Automated comparison validates all entity types
|
|
83
118
|
- **Webhook Creation**: Batch webhook creation from YAML files tested and verified
|
|
84
119
|
|
|
85
120
|
### Performance
|
|
86
121
|
|
|
87
|
-
- **Migration
|
|
88
|
-
- Automated process: ~30 minutes
|
|
89
|
-
- Manual process: 8-10 hours
|
|
122
|
+
- **Migration Automation**: 100% automated with zero manual steps required
|
|
90
123
|
- **Reliability**: 100% success rate across multiple test migrations
|
|
91
124
|
- **Data Integrity**: Full SHA256 verification ensures zero data loss
|
|
92
125
|
|
package/README.md
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
**NEWO CLI** - Professional command-line tool for NEWO AI Agent development. Features **modular architecture**, **IDN-based file management**, and **comprehensive multi-customer support**.
|
|
9
9
|
|
|
10
10
|
Sync NEWO "Project → Agent → Flow → Skills" structure to local files with:
|
|
11
|
-
- 🚀 **Account migration** - Fully automated account copying with 100% accuracy
|
|
12
|
-
- 🏗️ **Complete entity management** - Create, edit, and delete agents, flows, skills, events, and states
|
|
11
|
+
- 🚀 **Account migration** - Fully automated account copying with 100% accuracy
|
|
12
|
+
- 🏗️ **Complete entity management** - Create, edit, and delete agents, flows, skills, events, and states
|
|
13
13
|
- 🔄 **Intelligent synchronization** - Pull projects, attributes, and conversations automatically
|
|
14
14
|
- 🎯 **IDN-based naming** - Skills named as `{skillIdn}.jinja/.guidance` for better organization
|
|
15
15
|
- 📊 **Real-time progress** - Live progress tracking during large operations (1,000+ skills)
|
|
@@ -19,11 +19,11 @@ Sync NEWO "Project → Agent → Flow → Skills" structure to local files with:
|
|
|
19
19
|
- ⚡ **Smart change detection** - SHA256-based efficient sync with hash consistency
|
|
20
20
|
- 🛡️ **File validation** - Multiple file detection with clear warnings and safe handling
|
|
21
21
|
- 🧠 **AI skill formats** - Support for `.guidance` (AI prompts) and `.jinja` (NSL templates)
|
|
22
|
-
- 📡 **Webhook automation** - Automatic webhook creation from YAML configuration
|
|
22
|
+
- 📡 **Webhook automation** - Automatic webhook creation from YAML configuration
|
|
23
23
|
- 📊 **Knowledge base import** - Bulk import AKB articles from structured text files
|
|
24
24
|
- 💬 **Conversation history** - Extract and sync user conversations and personas
|
|
25
|
-
- 🧪 **Sandbox testing** - Interactive agent testing with conversation continuation
|
|
26
|
-
- ✅ **Migration verification** - Automated validation of migration completeness
|
|
25
|
+
- 🧪 **Sandbox testing** - Interactive agent testing with conversation continuation
|
|
26
|
+
- ✅ **Migration verification** - Automated validation of migration completeness
|
|
27
27
|
- 🔧 **CI/CD ready** - GitHub Actions integration for automated deployments
|
|
28
28
|
|
|
29
29
|
---
|
|
@@ -152,7 +152,7 @@ NEWO_REFRESH_URL=custom_refresh_endpoint # Custom refresh endpoint
|
|
|
152
152
|
| `newo import-akb` | Import knowledge base articles | • Structured text parsing<br>• Bulk article import<br>• Validation and error reporting |
|
|
153
153
|
| `newo meta` | Get project metadata (debug) | • Project structure analysis<br>• Metadata validation |
|
|
154
154
|
|
|
155
|
-
### Account Migration Commands
|
|
155
|
+
### Account Migration Commands
|
|
156
156
|
|
|
157
157
|
**Enterprise-grade account migration with 100% automation:**
|
|
158
158
|
|
|
@@ -179,7 +179,7 @@ newo push --customer DEST_IDN
|
|
|
179
179
|
# 4. Verify success
|
|
180
180
|
newo verify --source SOURCE_IDN --dest DEST_IDN
|
|
181
181
|
|
|
182
|
-
# Complete! Account migrated
|
|
182
|
+
# Complete! Account fully migrated
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
**What Gets Migrated:**
|
|
@@ -191,7 +191,7 @@ newo verify --source SOURCE_IDN --dest DEST_IDN
|
|
|
191
191
|
- ✅ All metadata and configuration
|
|
192
192
|
|
|
193
193
|
**Benefits:**
|
|
194
|
-
- **
|
|
194
|
+
- **Automation**: 100% automated with zero manual steps
|
|
195
195
|
- **Accuracy**: 100% entity match verified
|
|
196
196
|
- **Reliability**: Tested with 1,084-skill account
|
|
197
197
|
- **Safety**: Source account read-only, never modified
|
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, Integration, Connector, CreateSandboxPersonaRequest, CreateSandboxPersonaResponse, CreateActorRequest, CreateActorResponse, SendChatMessageRequest, ConversationActsParams, ConversationActsResponse, ScriptAction, IntegrationSetting, CreateConnectorRequest, CreateConnectorResponse, UpdateConnectorRequest, OutgoingWebhook, IncomingWebhook, PersonaSearchResponse, AkbTopicsResponse } 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, Registry, RegistryItem, AddProjectFromRegistryRequest } 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[]>;
|
|
@@ -85,4 +85,7 @@ export declare function createIncomingWebhook(client: AxiosInstance, webhookData
|
|
|
85
85
|
id: string;
|
|
86
86
|
url: string;
|
|
87
87
|
}>;
|
|
88
|
+
export declare function listRegistries(client: AxiosInstance): Promise<Registry[]>;
|
|
89
|
+
export declare function listRegistryItems(client: AxiosInstance, registryId: string): Promise<RegistryItem[]>;
|
|
90
|
+
export declare function addProjectFromRegistry(client: AxiosInstance, projectData: AddProjectFromRegistryRequest): Promise<CreateProjectResponse>;
|
|
88
91
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.js
CHANGED
|
@@ -356,4 +356,18 @@ export async function createIncomingWebhook(client, webhookData) {
|
|
|
356
356
|
const response = await client.post('/api/v1/webhooks/incoming', webhookData);
|
|
357
357
|
return response.data;
|
|
358
358
|
}
|
|
359
|
+
// Registry API Functions
|
|
360
|
+
export async function listRegistries(client) {
|
|
361
|
+
const response = await client.get('/api/v1/designer/registries');
|
|
362
|
+
return response.data;
|
|
363
|
+
}
|
|
364
|
+
export async function listRegistryItems(client, registryId) {
|
|
365
|
+
const response = await client.get(`/api/v1/designer/registries/${registryId}/items`);
|
|
366
|
+
return response.data;
|
|
367
|
+
}
|
|
368
|
+
export async function addProjectFromRegistry(client, projectData) {
|
|
369
|
+
// Uses the same endpoint as createProject, but with registry fields populated
|
|
370
|
+
const response = await client.post('/api/v1/designer/projects', projectData);
|
|
371
|
+
return response.data;
|
|
372
|
+
}
|
|
359
373
|
//# sourceMappingURL=api.js.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
|
|
@@ -18,7 +18,10 @@ Core Commands:
|
|
|
18
18
|
newo import-akb <file> <persona_id> [--customer <idn>] # import AKB articles from structured text file
|
|
19
19
|
|
|
20
20
|
Project Management:
|
|
21
|
-
newo create-project <idn> [--title <title>] [--description <desc>] [--version <version>] [--auto-update] # create project on platform
|
|
21
|
+
newo create-project <idn> [--title <title>] [--description <desc>] [--version <version>] [--auto-update] # create empty project on platform
|
|
22
|
+
newo list-registries [--customer <idn>] # list available project registries (production, staging, etc.)
|
|
23
|
+
newo list-registry-items <registry-idn> [--all] # list available project templates in a registry
|
|
24
|
+
newo add-project <idn> --item <template-idn> [--registry <registry>] [--version <v>] [--auto-update] # install project from registry template
|
|
22
25
|
|
|
23
26
|
Entity Management (Full Lifecycle Support):
|
|
24
27
|
newo create-agent <idn> --project <project-idn> [--title <title>] [--description <desc>] # create agent → push to platform ✅
|
|
@@ -122,6 +125,14 @@ Usage Examples:
|
|
|
122
125
|
# Import AKB articles:
|
|
123
126
|
newo import-akb articles.txt da4550db-2b95-4500-91ff-fb4b60fe7be9
|
|
124
127
|
|
|
128
|
+
# Project Registry - Install templates from registry (NEW):
|
|
129
|
+
newo list-registries # See available registries
|
|
130
|
+
newo list-registry-items production # Browse production templates
|
|
131
|
+
newo list-registry-items production --all # See all versions
|
|
132
|
+
newo add-project my_calcom --item cal_com_integration # Install latest version
|
|
133
|
+
newo add-project my_zoho --item zoho_integration --version 1.0.2 # Install specific version
|
|
134
|
+
newo add-project my_weather --item weather_integration --auto-update # With auto-updates
|
|
135
|
+
|
|
125
136
|
# Sandbox testing (NEW v3.1.0):
|
|
126
137
|
newo sandbox "Hello, I want to order pizza" # Start new conversation
|
|
127
138
|
newo sandbox --actor abc123... "I want 2 large pizzas" # Continue conversation
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List Registries Command Handler - Lists available project registries
|
|
3
|
+
*/
|
|
4
|
+
import { makeClient, listRegistries } from '../../api.js';
|
|
5
|
+
import { getValidAccessToken } from '../../auth.js';
|
|
6
|
+
import { requireSingleCustomer } from '../customer-selection.js';
|
|
7
|
+
export async function handleListRegistriesCommand(customerConfig, args, verbose = false) {
|
|
8
|
+
try {
|
|
9
|
+
const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
|
|
10
|
+
if (verbose) {
|
|
11
|
+
console.log(`📋 Fetching registries for customer: ${selectedCustomer.idn}`);
|
|
12
|
+
}
|
|
13
|
+
// Get access token and create client
|
|
14
|
+
const accessToken = await getValidAccessToken(selectedCustomer);
|
|
15
|
+
const client = await makeClient(verbose, accessToken);
|
|
16
|
+
console.log('🔍 Fetching available project registries...\n');
|
|
17
|
+
const registries = await listRegistries(client);
|
|
18
|
+
if (registries.length === 0) {
|
|
19
|
+
console.log('No registries found.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
console.log(`✅ Found ${registries.length} registries:\n`);
|
|
23
|
+
// Display registries in a table-like format
|
|
24
|
+
console.log(' IDN │ Public │ ID');
|
|
25
|
+
console.log(' ────────────────────────┼────────┼────────────────────────────────────');
|
|
26
|
+
for (const registry of registries) {
|
|
27
|
+
const publicStatus = registry.is_public ? 'Yes' : 'No';
|
|
28
|
+
const idnPadded = registry.idn.padEnd(22);
|
|
29
|
+
const publicPadded = publicStatus.padEnd(6);
|
|
30
|
+
console.log(` ${idnPadded} │ ${publicPadded} │ ${registry.id}`);
|
|
31
|
+
}
|
|
32
|
+
console.log('\n💡 Use "newo list-registry-items <registry-idn>" to see available projects in a registry');
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error('❌ Failed to list registries:', error instanceof Error ? error.message : String(error));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=list-registries.js.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List Registry Items Command Handler - Lists available projects in a registry
|
|
3
|
+
*/
|
|
4
|
+
import { makeClient, listRegistries, listRegistryItems } from '../../api.js';
|
|
5
|
+
import { getValidAccessToken } from '../../auth.js';
|
|
6
|
+
import { requireSingleCustomer } from '../customer-selection.js';
|
|
7
|
+
function groupItemsByIdn(items) {
|
|
8
|
+
const groups = new Map();
|
|
9
|
+
for (const item of items) {
|
|
10
|
+
const existing = groups.get(item.idn) || [];
|
|
11
|
+
existing.push(item);
|
|
12
|
+
groups.set(item.idn, existing);
|
|
13
|
+
}
|
|
14
|
+
const result = [];
|
|
15
|
+
for (const [idn, versions] of groups) {
|
|
16
|
+
// Sort versions by published_at descending (newest first)
|
|
17
|
+
const sortedVersions = [...versions].sort((a, b) => new Date(b.published_at).getTime() - new Date(a.published_at).getTime());
|
|
18
|
+
const latestItem = sortedVersions[0];
|
|
19
|
+
if (!latestItem)
|
|
20
|
+
continue;
|
|
21
|
+
// Sum up active project counts across all versions
|
|
22
|
+
const totalActiveProjects = versions.reduce((sum, v) => sum + v.active_project_count, 0);
|
|
23
|
+
result.push({
|
|
24
|
+
idn,
|
|
25
|
+
versions: sortedVersions,
|
|
26
|
+
latestVersion: latestItem.version,
|
|
27
|
+
totalActiveProjects
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// Sort by IDN alphabetically
|
|
31
|
+
return result.sort((a, b) => a.idn.localeCompare(b.idn));
|
|
32
|
+
}
|
|
33
|
+
export async function handleListRegistryItemsCommand(customerConfig, args, verbose = false) {
|
|
34
|
+
try {
|
|
35
|
+
const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
|
|
36
|
+
// Parse arguments
|
|
37
|
+
const registryIdn = args._[1];
|
|
38
|
+
const showAllVersions = Boolean(args.all || args.a);
|
|
39
|
+
if (!registryIdn) {
|
|
40
|
+
console.error('Error: Registry IDN is required');
|
|
41
|
+
console.error('Usage: newo list-registry-items <registry-idn> [--all]');
|
|
42
|
+
console.error('');
|
|
43
|
+
console.error('Examples:');
|
|
44
|
+
console.error(' newo list-registry-items production');
|
|
45
|
+
console.error(' newo list-registry-items staging --all');
|
|
46
|
+
console.error('');
|
|
47
|
+
console.error('Run "newo list-registries" to see available registries');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
if (verbose) {
|
|
51
|
+
console.log(`📋 Fetching items from registry: ${registryIdn}`);
|
|
52
|
+
console.log(` Customer: ${selectedCustomer.idn}`);
|
|
53
|
+
console.log(` Show all versions: ${showAllVersions}`);
|
|
54
|
+
}
|
|
55
|
+
// Get access token and create client
|
|
56
|
+
const accessToken = await getValidAccessToken(selectedCustomer);
|
|
57
|
+
const client = await makeClient(verbose, accessToken);
|
|
58
|
+
// First, get registries to find the ID
|
|
59
|
+
console.log(`🔍 Fetching registry "${registryIdn}"...`);
|
|
60
|
+
const registries = await listRegistries(client);
|
|
61
|
+
const registry = registries.find((r) => r.idn === registryIdn);
|
|
62
|
+
if (!registry) {
|
|
63
|
+
console.error(`❌ Registry "${registryIdn}" not found`);
|
|
64
|
+
console.error('');
|
|
65
|
+
console.error('Available registries:');
|
|
66
|
+
for (const r of registries) {
|
|
67
|
+
console.error(` • ${r.idn}`);
|
|
68
|
+
}
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
console.log(`📦 Fetching projects from "${registryIdn}" registry (this may take a moment)...\n`);
|
|
72
|
+
const items = await listRegistryItems(client, registry.id);
|
|
73
|
+
if (items.length === 0) {
|
|
74
|
+
console.log(`No projects found in "${registryIdn}" registry.`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (showAllVersions) {
|
|
78
|
+
// Show all versions
|
|
79
|
+
console.log(`✅ Found ${items.length} project versions in "${registryIdn}" registry:\n`);
|
|
80
|
+
console.log(' Project IDN │ Version │ Active │ Published');
|
|
81
|
+
console.log(' ───────────────────────┼──────────┼────────┼────────────────────');
|
|
82
|
+
for (const item of items) {
|
|
83
|
+
const idnPadded = item.idn.substring(0, 21).padEnd(21);
|
|
84
|
+
const versionPadded = item.version.substring(0, 8).padEnd(8);
|
|
85
|
+
const activePadded = String(item.active_project_count).padEnd(6);
|
|
86
|
+
const published = new Date(item.published_at).toISOString().split('T')[0];
|
|
87
|
+
console.log(` ${idnPadded} │ ${versionPadded} │ ${activePadded} │ ${published}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Group by project IDN and show only latest version
|
|
92
|
+
const grouped = groupItemsByIdn(items);
|
|
93
|
+
console.log(`✅ Found ${grouped.length} unique projects in "${registryIdn}" registry:\n`);
|
|
94
|
+
console.log(' Project IDN │ Latest │ Active │ Versions');
|
|
95
|
+
console.log(' ───────────────────────┼──────────┼────────┼──────────');
|
|
96
|
+
for (const group of grouped) {
|
|
97
|
+
const idnPadded = group.idn.substring(0, 21).padEnd(21);
|
|
98
|
+
const versionPadded = group.latestVersion.substring(0, 8).padEnd(8);
|
|
99
|
+
const activePadded = String(group.totalActiveProjects).padEnd(6);
|
|
100
|
+
const versionCount = String(group.versions.length).padEnd(8);
|
|
101
|
+
console.log(` ${idnPadded} │ ${versionPadded} │ ${activePadded} │ ${versionCount}`);
|
|
102
|
+
}
|
|
103
|
+
console.log('\n💡 Use --all flag to see all versions');
|
|
104
|
+
}
|
|
105
|
+
console.log(`\n💡 Use "newo add-project <idn> --registry ${registryIdn} --item <project-idn>" to install a project`);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
console.error('❌ Failed to list registry items:', error instanceof Error ? error.message : String(error));
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=list-registry-items.js.map
|
package/dist/cli.js
CHANGED
|
@@ -38,6 +38,9 @@ import { handlePushAkbCommand } from './cli/commands/push-akb.js';
|
|
|
38
38
|
import { handleMigrateAccountCommand } from './cli/commands/migrate-account.js';
|
|
39
39
|
import { handleVerifyMigrationCommand } from './cli/commands/verify-migration.js';
|
|
40
40
|
import { handleCreateWebhooksCommand } from './cli/commands/create-webhooks.js';
|
|
41
|
+
import { handleListRegistriesCommand } from './cli/commands/list-registries.js';
|
|
42
|
+
import { handleListRegistryItemsCommand } from './cli/commands/list-registry-items.js';
|
|
43
|
+
import { handleAddProjectCommand } from './cli/commands/add-project.js';
|
|
41
44
|
dotenv.config();
|
|
42
45
|
async function main() {
|
|
43
46
|
try {
|
|
@@ -168,6 +171,15 @@ async function main() {
|
|
|
168
171
|
case 'create-webhooks':
|
|
169
172
|
await handleCreateWebhooksCommand(customerConfig, args, verbose);
|
|
170
173
|
break;
|
|
174
|
+
case 'list-registries':
|
|
175
|
+
await handleListRegistriesCommand(customerConfig, args, verbose);
|
|
176
|
+
break;
|
|
177
|
+
case 'list-registry-items':
|
|
178
|
+
await handleListRegistryItemsCommand(customerConfig, args, verbose);
|
|
179
|
+
break;
|
|
180
|
+
case 'add-project':
|
|
181
|
+
await handleAddProjectCommand(customerConfig, args, verbose);
|
|
182
|
+
break;
|
|
171
183
|
default:
|
|
172
184
|
console.error('Unknown command:', cmd);
|
|
173
185
|
console.error('Run "newo --help" for usage information');
|
package/dist/types.d.ts
CHANGED
|
@@ -703,4 +703,42 @@ export interface AkbYamlTopic {
|
|
|
703
703
|
labels: string[];
|
|
704
704
|
topic_summary: string;
|
|
705
705
|
}
|
|
706
|
+
export interface Registry {
|
|
707
|
+
readonly id: string;
|
|
708
|
+
readonly idn: string;
|
|
709
|
+
readonly account_id: string;
|
|
710
|
+
readonly is_public: boolean;
|
|
711
|
+
}
|
|
712
|
+
export interface RegistryItemProjectImage {
|
|
713
|
+
readonly id: string;
|
|
714
|
+
readonly idn: string;
|
|
715
|
+
readonly image_hash: string;
|
|
716
|
+
readonly storage_id: string;
|
|
717
|
+
readonly customer_idn: string;
|
|
718
|
+
readonly account_id: string;
|
|
719
|
+
readonly created_at: string;
|
|
720
|
+
}
|
|
721
|
+
export interface RegistryItem {
|
|
722
|
+
readonly id: string;
|
|
723
|
+
readonly idn: string;
|
|
724
|
+
readonly version: string;
|
|
725
|
+
readonly project_image: RegistryItemProjectImage;
|
|
726
|
+
readonly account_id: string;
|
|
727
|
+
readonly account_idn: string | null;
|
|
728
|
+
readonly account_email: string | null;
|
|
729
|
+
readonly is_public: boolean;
|
|
730
|
+
readonly active_project_count: number;
|
|
731
|
+
readonly created_at: string;
|
|
732
|
+
readonly published_at: string;
|
|
733
|
+
}
|
|
734
|
+
export interface AddProjectFromRegistryRequest {
|
|
735
|
+
idn: string;
|
|
736
|
+
title: string;
|
|
737
|
+
version?: string;
|
|
738
|
+
description?: string;
|
|
739
|
+
is_auto_update_enabled?: boolean;
|
|
740
|
+
registry_idn: string;
|
|
741
|
+
registry_item_idn: string;
|
|
742
|
+
registry_item_version: string | null;
|
|
743
|
+
}
|
|
706
744
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newo",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "NEWO CLI: Professional command-line tool with modular architecture for NEWO AI Agent development. Features account migration, integration management, webhook automation, AKB knowledge base, project attributes, sandbox testing, IDN-based file management, real-time progress tracking, intelligent sync operations, and comprehensive multi-customer support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/api.ts
CHANGED
|
@@ -52,7 +52,10 @@ import type {
|
|
|
52
52
|
OutgoingWebhook,
|
|
53
53
|
IncomingWebhook,
|
|
54
54
|
PersonaSearchResponse,
|
|
55
|
-
AkbTopicsResponse
|
|
55
|
+
AkbTopicsResponse,
|
|
56
|
+
Registry,
|
|
57
|
+
RegistryItem,
|
|
58
|
+
AddProjectFromRegistryRequest
|
|
56
59
|
} from './types.js';
|
|
57
60
|
|
|
58
61
|
// Per-request retry tracking to avoid shared state issues
|
|
@@ -552,4 +555,25 @@ export async function createIncomingWebhook(
|
|
|
552
555
|
): Promise<{ id: string; url: string }> {
|
|
553
556
|
const response = await client.post('/api/v1/webhooks/incoming', webhookData);
|
|
554
557
|
return response.data;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Registry API Functions
|
|
561
|
+
|
|
562
|
+
export async function listRegistries(client: AxiosInstance): Promise<Registry[]> {
|
|
563
|
+
const response = await client.get<Registry[]>('/api/v1/designer/registries');
|
|
564
|
+
return response.data;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export async function listRegistryItems(client: AxiosInstance, registryId: string): Promise<RegistryItem[]> {
|
|
568
|
+
const response = await client.get<RegistryItem[]>(`/api/v1/designer/registries/${registryId}/items`);
|
|
569
|
+
return response.data;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export async function addProjectFromRegistry(
|
|
573
|
+
client: AxiosInstance,
|
|
574
|
+
projectData: AddProjectFromRegistryRequest
|
|
575
|
+
): Promise<CreateProjectResponse> {
|
|
576
|
+
// Uses the same endpoint as createProject, but with registry fields populated
|
|
577
|
+
const response = await client.post<CreateProjectResponse>('/api/v1/designer/projects', projectData);
|
|
578
|
+
return response.data;
|
|
555
579
|
}
|
|
@@ -0,0 +1,159 @@
|
|
|
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
|
+
import type { MultiCustomerConfig, CliArgs, Registry, RegistryItem, AddProjectFromRegistryRequest } from '../../types.js';
|
|
8
|
+
|
|
9
|
+
export async function handleAddProjectCommand(
|
|
10
|
+
customerConfig: MultiCustomerConfig,
|
|
11
|
+
args: CliArgs,
|
|
12
|
+
verbose: boolean = false
|
|
13
|
+
): Promise<void> {
|
|
14
|
+
try {
|
|
15
|
+
const selectedCustomer = requireSingleCustomer(customerConfig, args.customer as string | undefined);
|
|
16
|
+
|
|
17
|
+
// Parse arguments
|
|
18
|
+
const projectIdn = args._[1] as string;
|
|
19
|
+
const registryIdn = args.registry as string || 'production';
|
|
20
|
+
const registryItemIdn = args.item as string;
|
|
21
|
+
const registryItemVersion = args.version as string | null || null;
|
|
22
|
+
const title = args.title as string || projectIdn || registryItemIdn;
|
|
23
|
+
const description = args.description as string || '';
|
|
24
|
+
const isAutoUpdateEnabled = Boolean(args['auto-update']);
|
|
25
|
+
|
|
26
|
+
// Validate required arguments
|
|
27
|
+
if (!registryItemIdn) {
|
|
28
|
+
console.error('Error: Registry item IDN is required');
|
|
29
|
+
console.error('');
|
|
30
|
+
console.error('Usage: newo add-project <project-idn> --item <registry-item-idn> [options]');
|
|
31
|
+
console.error('');
|
|
32
|
+
console.error('Options:');
|
|
33
|
+
console.error(' --item <idn> Registry item/template IDN (required)');
|
|
34
|
+
console.error(' --registry <idn> Registry to use (default: production)');
|
|
35
|
+
console.error(' --version <version> Specific version to install (default: latest)');
|
|
36
|
+
console.error(' --title <title> Project title (default: project IDN)');
|
|
37
|
+
console.error(' --description <desc> Project description');
|
|
38
|
+
console.error(' --auto-update Enable automatic updates from registry');
|
|
39
|
+
console.error('');
|
|
40
|
+
console.error('Examples:');
|
|
41
|
+
console.error(' newo add-project my_weather --item weather_integration');
|
|
42
|
+
console.error(' newo add-project my_calcom --item cal_com_integration --registry production');
|
|
43
|
+
console.error(' newo add-project my_zoho --item zoho_integration --version 1.0.2 --auto-update');
|
|
44
|
+
console.error('');
|
|
45
|
+
console.error('Run "newo list-registries" to see available registries');
|
|
46
|
+
console.error('Run "newo list-registry-items <registry-idn>" to see available project templates');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Use registry item IDN as project IDN if not specified
|
|
51
|
+
const finalProjectIdn = projectIdn || registryItemIdn;
|
|
52
|
+
|
|
53
|
+
if (verbose) {
|
|
54
|
+
console.log(`📦 Adding project from registry`);
|
|
55
|
+
console.log(` Project IDN: ${finalProjectIdn}`);
|
|
56
|
+
console.log(` Title: ${title}`);
|
|
57
|
+
console.log(` Registry: ${registryIdn}`);
|
|
58
|
+
console.log(` Item: ${registryItemIdn}`);
|
|
59
|
+
console.log(` Version: ${registryItemVersion || 'latest'}`);
|
|
60
|
+
console.log(` Auto-update: ${isAutoUpdateEnabled}`);
|
|
61
|
+
console.log(` Customer: ${selectedCustomer.idn}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Get access token and create client
|
|
65
|
+
const accessToken = await getValidAccessToken(selectedCustomer);
|
|
66
|
+
const client = await makeClient(verbose, accessToken);
|
|
67
|
+
|
|
68
|
+
// Validate registry exists
|
|
69
|
+
console.log(`🔍 Validating registry "${registryIdn}"...`);
|
|
70
|
+
const registries = await listRegistries(client);
|
|
71
|
+
const registry = registries.find((r: Registry) => r.idn === registryIdn);
|
|
72
|
+
|
|
73
|
+
if (!registry) {
|
|
74
|
+
console.error(`❌ Registry "${registryIdn}" not found`);
|
|
75
|
+
console.error('');
|
|
76
|
+
console.error('Available registries:');
|
|
77
|
+
for (const r of registries) {
|
|
78
|
+
console.error(` • ${r.idn}`);
|
|
79
|
+
}
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Validate registry item exists and find version
|
|
84
|
+
console.log(`🔍 Validating project template "${registryItemIdn}"...`);
|
|
85
|
+
const items = await listRegistryItems(client, registry.id);
|
|
86
|
+
const matchingItems = items.filter((item: RegistryItem) => item.idn === registryItemIdn);
|
|
87
|
+
|
|
88
|
+
if (matchingItems.length === 0) {
|
|
89
|
+
console.error(`❌ Project template "${registryItemIdn}" not found in "${registryIdn}" registry`);
|
|
90
|
+
console.error('');
|
|
91
|
+
console.error('Run "newo list-registry-items ' + registryIdn + '" to see available templates');
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Find the specific version or latest
|
|
96
|
+
let selectedItem: RegistryItem | undefined;
|
|
97
|
+
if (registryItemVersion) {
|
|
98
|
+
selectedItem = matchingItems.find((item: RegistryItem) => item.version === registryItemVersion);
|
|
99
|
+
if (!selectedItem) {
|
|
100
|
+
console.error(`❌ Version "${registryItemVersion}" not found for "${registryItemIdn}"`);
|
|
101
|
+
console.error('');
|
|
102
|
+
console.error('Available versions:');
|
|
103
|
+
const sortedItems = [...matchingItems].sort((a, b) =>
|
|
104
|
+
new Date(b.published_at).getTime() - new Date(a.published_at).getTime()
|
|
105
|
+
);
|
|
106
|
+
for (const item of sortedItems.slice(0, 10)) {
|
|
107
|
+
console.error(` • ${item.version} (published: ${new Date(item.published_at).toISOString().split('T')[0]})`);
|
|
108
|
+
}
|
|
109
|
+
if (sortedItems.length > 10) {
|
|
110
|
+
console.error(` ... and ${sortedItems.length - 10} more`);
|
|
111
|
+
}
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
// Get latest version (sorted by published_at desc)
|
|
116
|
+
const sortedItems = [...matchingItems].sort((a, b) =>
|
|
117
|
+
new Date(b.published_at).getTime() - new Date(a.published_at).getTime()
|
|
118
|
+
);
|
|
119
|
+
selectedItem = sortedItems[0];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!selectedItem) {
|
|
123
|
+
console.error(`❌ Could not determine version for "${registryItemIdn}"`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log(`📥 Installing "${registryItemIdn}" v${selectedItem.version} as "${finalProjectIdn}"...`);
|
|
128
|
+
|
|
129
|
+
// Create project from registry
|
|
130
|
+
const projectData: AddProjectFromRegistryRequest = {
|
|
131
|
+
idn: finalProjectIdn,
|
|
132
|
+
title,
|
|
133
|
+
version: '',
|
|
134
|
+
description,
|
|
135
|
+
is_auto_update_enabled: isAutoUpdateEnabled,
|
|
136
|
+
registry_idn: registryIdn,
|
|
137
|
+
registry_item_idn: registryItemIdn,
|
|
138
|
+
registry_item_version: registryItemVersion
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const response = await addProjectFromRegistry(client, projectData);
|
|
142
|
+
|
|
143
|
+
console.log('');
|
|
144
|
+
console.log(`✅ Project installed successfully!`);
|
|
145
|
+
console.log(` Project IDN: ${finalProjectIdn}`);
|
|
146
|
+
console.log(` Project ID: ${response.id}`);
|
|
147
|
+
console.log(` Source: ${registryItemIdn} v${selectedItem.version}`);
|
|
148
|
+
console.log(` Registry: ${registryIdn}`);
|
|
149
|
+
if (isAutoUpdateEnabled) {
|
|
150
|
+
console.log(` Auto-update: Enabled`);
|
|
151
|
+
}
|
|
152
|
+
console.log('');
|
|
153
|
+
console.log(`💡 Run "newo pull" to sync the project locally`);
|
|
154
|
+
|
|
155
|
+
} catch (error: unknown) {
|
|
156
|
+
console.error('❌ Failed to add project from registry:', error instanceof Error ? error.message : String(error));
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
}
|
package/src/cli/commands/help.ts
CHANGED
|
@@ -19,7 +19,10 @@ Core Commands:
|
|
|
19
19
|
newo import-akb <file> <persona_id> [--customer <idn>] # import AKB articles from structured text file
|
|
20
20
|
|
|
21
21
|
Project Management:
|
|
22
|
-
newo create-project <idn> [--title <title>] [--description <desc>] [--version <version>] [--auto-update] # create project on platform
|
|
22
|
+
newo create-project <idn> [--title <title>] [--description <desc>] [--version <version>] [--auto-update] # create empty project on platform
|
|
23
|
+
newo list-registries [--customer <idn>] # list available project registries (production, staging, etc.)
|
|
24
|
+
newo list-registry-items <registry-idn> [--all] # list available project templates in a registry
|
|
25
|
+
newo add-project <idn> --item <template-idn> [--registry <registry>] [--version <v>] [--auto-update] # install project from registry template
|
|
23
26
|
|
|
24
27
|
Entity Management (Full Lifecycle Support):
|
|
25
28
|
newo create-agent <idn> --project <project-idn> [--title <title>] [--description <desc>] # create agent → push to platform ✅
|
|
@@ -123,6 +126,14 @@ Usage Examples:
|
|
|
123
126
|
# Import AKB articles:
|
|
124
127
|
newo import-akb articles.txt da4550db-2b95-4500-91ff-fb4b60fe7be9
|
|
125
128
|
|
|
129
|
+
# Project Registry - Install templates from registry (NEW):
|
|
130
|
+
newo list-registries # See available registries
|
|
131
|
+
newo list-registry-items production # Browse production templates
|
|
132
|
+
newo list-registry-items production --all # See all versions
|
|
133
|
+
newo add-project my_calcom --item cal_com_integration # Install latest version
|
|
134
|
+
newo add-project my_zoho --item zoho_integration --version 1.0.2 # Install specific version
|
|
135
|
+
newo add-project my_weather --item weather_integration --auto-update # With auto-updates
|
|
136
|
+
|
|
126
137
|
# Sandbox testing (NEW v3.1.0):
|
|
127
138
|
newo sandbox "Hello, I want to order pizza" # Start new conversation
|
|
128
139
|
newo sandbox --actor abc123... "I want 2 large pizzas" # Continue conversation
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List Registries Command Handler - Lists available project registries
|
|
3
|
+
*/
|
|
4
|
+
import { makeClient, listRegistries } from '../../api.js';
|
|
5
|
+
import { getValidAccessToken } from '../../auth.js';
|
|
6
|
+
import { requireSingleCustomer } from '../customer-selection.js';
|
|
7
|
+
import type { MultiCustomerConfig, CliArgs } from '../../types.js';
|
|
8
|
+
|
|
9
|
+
export async function handleListRegistriesCommand(
|
|
10
|
+
customerConfig: MultiCustomerConfig,
|
|
11
|
+
args: CliArgs,
|
|
12
|
+
verbose: boolean = false
|
|
13
|
+
): Promise<void> {
|
|
14
|
+
try {
|
|
15
|
+
const selectedCustomer = requireSingleCustomer(customerConfig, args.customer as string | undefined);
|
|
16
|
+
|
|
17
|
+
if (verbose) {
|
|
18
|
+
console.log(`📋 Fetching registries for customer: ${selectedCustomer.idn}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Get access token and create client
|
|
22
|
+
const accessToken = await getValidAccessToken(selectedCustomer);
|
|
23
|
+
const client = await makeClient(verbose, accessToken);
|
|
24
|
+
|
|
25
|
+
console.log('🔍 Fetching available project registries...\n');
|
|
26
|
+
|
|
27
|
+
const registries = await listRegistries(client);
|
|
28
|
+
|
|
29
|
+
if (registries.length === 0) {
|
|
30
|
+
console.log('No registries found.');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log(`✅ Found ${registries.length} registries:\n`);
|
|
35
|
+
|
|
36
|
+
// Display registries in a table-like format
|
|
37
|
+
console.log(' IDN │ Public │ ID');
|
|
38
|
+
console.log(' ────────────────────────┼────────┼────────────────────────────────────');
|
|
39
|
+
|
|
40
|
+
for (const registry of registries) {
|
|
41
|
+
const publicStatus = registry.is_public ? 'Yes' : 'No';
|
|
42
|
+
const idnPadded = registry.idn.padEnd(22);
|
|
43
|
+
const publicPadded = publicStatus.padEnd(6);
|
|
44
|
+
console.log(` ${idnPadded} │ ${publicPadded} │ ${registry.id}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log('\n💡 Use "newo list-registry-items <registry-idn>" to see available projects in a registry');
|
|
48
|
+
|
|
49
|
+
} catch (error: unknown) {
|
|
50
|
+
console.error('❌ Failed to list registries:', error instanceof Error ? error.message : String(error));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List Registry Items Command Handler - Lists available projects in a registry
|
|
3
|
+
*/
|
|
4
|
+
import { makeClient, listRegistries, listRegistryItems } from '../../api.js';
|
|
5
|
+
import { getValidAccessToken } from '../../auth.js';
|
|
6
|
+
import { requireSingleCustomer } from '../customer-selection.js';
|
|
7
|
+
import type { MultiCustomerConfig, CliArgs, Registry, RegistryItem } from '../../types.js';
|
|
8
|
+
|
|
9
|
+
interface GroupedItem {
|
|
10
|
+
idn: string;
|
|
11
|
+
versions: RegistryItem[];
|
|
12
|
+
latestVersion: string;
|
|
13
|
+
totalActiveProjects: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function groupItemsByIdn(items: RegistryItem[]): GroupedItem[] {
|
|
17
|
+
const groups = new Map<string, RegistryItem[]>();
|
|
18
|
+
|
|
19
|
+
for (const item of items) {
|
|
20
|
+
const existing = groups.get(item.idn) || [];
|
|
21
|
+
existing.push(item);
|
|
22
|
+
groups.set(item.idn, existing);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const result: GroupedItem[] = [];
|
|
26
|
+
|
|
27
|
+
for (const [idn, versions] of groups) {
|
|
28
|
+
// Sort versions by published_at descending (newest first)
|
|
29
|
+
const sortedVersions = [...versions].sort((a, b) =>
|
|
30
|
+
new Date(b.published_at).getTime() - new Date(a.published_at).getTime()
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const latestItem = sortedVersions[0];
|
|
34
|
+
if (!latestItem) continue;
|
|
35
|
+
|
|
36
|
+
// Sum up active project counts across all versions
|
|
37
|
+
const totalActiveProjects = versions.reduce((sum, v) => sum + v.active_project_count, 0);
|
|
38
|
+
|
|
39
|
+
result.push({
|
|
40
|
+
idn,
|
|
41
|
+
versions: sortedVersions,
|
|
42
|
+
latestVersion: latestItem.version,
|
|
43
|
+
totalActiveProjects
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Sort by IDN alphabetically
|
|
48
|
+
return result.sort((a, b) => a.idn.localeCompare(b.idn));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function handleListRegistryItemsCommand(
|
|
52
|
+
customerConfig: MultiCustomerConfig,
|
|
53
|
+
args: CliArgs,
|
|
54
|
+
verbose: boolean = false
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
try {
|
|
57
|
+
const selectedCustomer = requireSingleCustomer(customerConfig, args.customer as string | undefined);
|
|
58
|
+
|
|
59
|
+
// Parse arguments
|
|
60
|
+
const registryIdn = args._[1] as string;
|
|
61
|
+
const showAllVersions = Boolean(args.all || args.a);
|
|
62
|
+
|
|
63
|
+
if (!registryIdn) {
|
|
64
|
+
console.error('Error: Registry IDN is required');
|
|
65
|
+
console.error('Usage: newo list-registry-items <registry-idn> [--all]');
|
|
66
|
+
console.error('');
|
|
67
|
+
console.error('Examples:');
|
|
68
|
+
console.error(' newo list-registry-items production');
|
|
69
|
+
console.error(' newo list-registry-items staging --all');
|
|
70
|
+
console.error('');
|
|
71
|
+
console.error('Run "newo list-registries" to see available registries');
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (verbose) {
|
|
76
|
+
console.log(`📋 Fetching items from registry: ${registryIdn}`);
|
|
77
|
+
console.log(` Customer: ${selectedCustomer.idn}`);
|
|
78
|
+
console.log(` Show all versions: ${showAllVersions}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Get access token and create client
|
|
82
|
+
const accessToken = await getValidAccessToken(selectedCustomer);
|
|
83
|
+
const client = await makeClient(verbose, accessToken);
|
|
84
|
+
|
|
85
|
+
// First, get registries to find the ID
|
|
86
|
+
console.log(`🔍 Fetching registry "${registryIdn}"...`);
|
|
87
|
+
const registries = await listRegistries(client);
|
|
88
|
+
const registry = registries.find((r: Registry) => r.idn === registryIdn);
|
|
89
|
+
|
|
90
|
+
if (!registry) {
|
|
91
|
+
console.error(`❌ Registry "${registryIdn}" not found`);
|
|
92
|
+
console.error('');
|
|
93
|
+
console.error('Available registries:');
|
|
94
|
+
for (const r of registries) {
|
|
95
|
+
console.error(` • ${r.idn}`);
|
|
96
|
+
}
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(`📦 Fetching projects from "${registryIdn}" registry (this may take a moment)...\n`);
|
|
101
|
+
|
|
102
|
+
const items = await listRegistryItems(client, registry.id);
|
|
103
|
+
|
|
104
|
+
if (items.length === 0) {
|
|
105
|
+
console.log(`No projects found in "${registryIdn}" registry.`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (showAllVersions) {
|
|
110
|
+
// Show all versions
|
|
111
|
+
console.log(`✅ Found ${items.length} project versions in "${registryIdn}" registry:\n`);
|
|
112
|
+
|
|
113
|
+
console.log(' Project IDN │ Version │ Active │ Published');
|
|
114
|
+
console.log(' ───────────────────────┼──────────┼────────┼────────────────────');
|
|
115
|
+
|
|
116
|
+
for (const item of items) {
|
|
117
|
+
const idnPadded = item.idn.substring(0, 21).padEnd(21);
|
|
118
|
+
const versionPadded = item.version.substring(0, 8).padEnd(8);
|
|
119
|
+
const activePadded = String(item.active_project_count).padEnd(6);
|
|
120
|
+
const published = new Date(item.published_at).toISOString().split('T')[0];
|
|
121
|
+
console.log(` ${idnPadded} │ ${versionPadded} │ ${activePadded} │ ${published}`);
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
// Group by project IDN and show only latest version
|
|
125
|
+
const grouped = groupItemsByIdn(items);
|
|
126
|
+
|
|
127
|
+
console.log(`✅ Found ${grouped.length} unique projects in "${registryIdn}" registry:\n`);
|
|
128
|
+
|
|
129
|
+
console.log(' Project IDN │ Latest │ Active │ Versions');
|
|
130
|
+
console.log(' ───────────────────────┼──────────┼────────┼──────────');
|
|
131
|
+
|
|
132
|
+
for (const group of grouped) {
|
|
133
|
+
const idnPadded = group.idn.substring(0, 21).padEnd(21);
|
|
134
|
+
const versionPadded = group.latestVersion.substring(0, 8).padEnd(8);
|
|
135
|
+
const activePadded = String(group.totalActiveProjects).padEnd(6);
|
|
136
|
+
const versionCount = String(group.versions.length).padEnd(8);
|
|
137
|
+
console.log(` ${idnPadded} │ ${versionPadded} │ ${activePadded} │ ${versionCount}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log('\n💡 Use --all flag to see all versions');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log(`\n💡 Use "newo add-project <idn> --registry ${registryIdn} --item <project-idn>" to install a project`);
|
|
144
|
+
|
|
145
|
+
} catch (error: unknown) {
|
|
146
|
+
console.error('❌ Failed to list registry items:', error instanceof Error ? error.message : String(error));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -38,6 +38,9 @@ import { handlePushAkbCommand } from './cli/commands/push-akb.js';
|
|
|
38
38
|
import { handleMigrateAccountCommand } from './cli/commands/migrate-account.js';
|
|
39
39
|
import { handleVerifyMigrationCommand } from './cli/commands/verify-migration.js';
|
|
40
40
|
import { handleCreateWebhooksCommand } from './cli/commands/create-webhooks.js';
|
|
41
|
+
import { handleListRegistriesCommand } from './cli/commands/list-registries.js';
|
|
42
|
+
import { handleListRegistryItemsCommand } from './cli/commands/list-registry-items.js';
|
|
43
|
+
import { handleAddProjectCommand } from './cli/commands/add-project.js';
|
|
41
44
|
import type { CliArgs, NewoApiError } from './types.js';
|
|
42
45
|
|
|
43
46
|
dotenv.config();
|
|
@@ -204,6 +207,18 @@ async function main(): Promise<void> {
|
|
|
204
207
|
await handleCreateWebhooksCommand(customerConfig, args, verbose);
|
|
205
208
|
break;
|
|
206
209
|
|
|
210
|
+
case 'list-registries':
|
|
211
|
+
await handleListRegistriesCommand(customerConfig, args, verbose);
|
|
212
|
+
break;
|
|
213
|
+
|
|
214
|
+
case 'list-registry-items':
|
|
215
|
+
await handleListRegistryItemsCommand(customerConfig, args, verbose);
|
|
216
|
+
break;
|
|
217
|
+
|
|
218
|
+
case 'add-project':
|
|
219
|
+
await handleAddProjectCommand(customerConfig, args, verbose);
|
|
220
|
+
break;
|
|
221
|
+
|
|
207
222
|
default:
|
|
208
223
|
console.error('Unknown command:', cmd);
|
|
209
224
|
console.error('Run "newo --help" for usage information');
|
package/src/types.ts
CHANGED
|
@@ -831,4 +831,47 @@ export interface AkbYamlTopic {
|
|
|
831
831
|
updated_at: string;
|
|
832
832
|
labels: string[];
|
|
833
833
|
topic_summary: string;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// Registry Types (for project marketplace/templates)
|
|
837
|
+
export interface Registry {
|
|
838
|
+
readonly id: string;
|
|
839
|
+
readonly idn: string;
|
|
840
|
+
readonly account_id: string;
|
|
841
|
+
readonly is_public: boolean;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
export interface RegistryItemProjectImage {
|
|
845
|
+
readonly id: string;
|
|
846
|
+
readonly idn: string;
|
|
847
|
+
readonly image_hash: string;
|
|
848
|
+
readonly storage_id: string;
|
|
849
|
+
readonly customer_idn: string;
|
|
850
|
+
readonly account_id: string;
|
|
851
|
+
readonly created_at: string;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
export interface RegistryItem {
|
|
855
|
+
readonly id: string;
|
|
856
|
+
readonly idn: string;
|
|
857
|
+
readonly version: string;
|
|
858
|
+
readonly project_image: RegistryItemProjectImage;
|
|
859
|
+
readonly account_id: string;
|
|
860
|
+
readonly account_idn: string | null;
|
|
861
|
+
readonly account_email: string | null;
|
|
862
|
+
readonly is_public: boolean;
|
|
863
|
+
readonly active_project_count: number;
|
|
864
|
+
readonly created_at: string;
|
|
865
|
+
readonly published_at: string;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
export interface AddProjectFromRegistryRequest {
|
|
869
|
+
idn: string;
|
|
870
|
+
title: string;
|
|
871
|
+
version?: string;
|
|
872
|
+
description?: string;
|
|
873
|
+
is_auto_update_enabled?: boolean;
|
|
874
|
+
registry_idn: string;
|
|
875
|
+
registry_item_idn: string;
|
|
876
|
+
registry_item_version: string | null;
|
|
834
877
|
}
|