newo 2.0.5 → 3.0.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 +124 -0
- package/README.md +146 -0
- package/dist/api.d.ts +17 -1
- package/dist/api.js +78 -0
- package/dist/cli/commands/create-agent.d.ts +3 -0
- package/dist/cli/commands/create-agent.js +75 -0
- package/dist/cli/commands/create-attribute.d.ts +3 -0
- package/dist/cli/commands/create-attribute.js +63 -0
- package/dist/cli/commands/create-event.d.ts +3 -0
- package/dist/cli/commands/create-event.js +66 -0
- package/dist/cli/commands/create-flow.d.ts +3 -0
- package/dist/cli/commands/create-flow.js +100 -0
- package/dist/cli/commands/create-parameter.d.ts +3 -0
- package/dist/cli/commands/create-parameter.js +47 -0
- package/dist/cli/commands/create-persona.d.ts +3 -0
- package/dist/cli/commands/create-persona.js +43 -0
- package/dist/cli/commands/create-project.d.ts +3 -0
- package/dist/cli/commands/create-project.js +55 -0
- package/dist/cli/commands/create-skill.d.ts +3 -0
- package/dist/cli/commands/create-skill.js +115 -0
- package/dist/cli/commands/create-state.d.ts +3 -0
- package/dist/cli/commands/create-state.js +58 -0
- package/dist/cli/commands/delete-agent.d.ts +3 -0
- package/dist/cli/commands/delete-agent.js +70 -0
- package/dist/cli/commands/delete-flow.d.ts +3 -0
- package/dist/cli/commands/delete-flow.js +83 -0
- package/dist/cli/commands/delete-skill.d.ts +3 -0
- package/dist/cli/commands/delete-skill.js +87 -0
- package/dist/cli/commands/help.js +104 -22
- package/dist/cli/commands/push.js +4 -3
- package/dist/cli.js +48 -0
- package/dist/sync/diff-utils.d.ts +18 -0
- package/dist/sync/diff-utils.js +152 -0
- package/dist/sync/push.d.ts +1 -1
- package/dist/sync/push.js +372 -4
- package/dist/sync/skill-files.js +22 -49
- package/dist/sync/status.js +178 -1
- package/dist/types.d.ts +100 -1
- package/package.json +1 -1
- package/src/api.ts +118 -1
- package/src/cli/commands/create-agent.ts +96 -0
- package/src/cli/commands/create-attribute.ts +75 -0
- package/src/cli/commands/create-event.ts +79 -0
- package/src/cli/commands/create-flow.ts +124 -0
- package/src/cli/commands/create-parameter.ts +59 -0
- package/src/cli/commands/create-persona.ts +54 -0
- package/src/cli/commands/create-project.ts +66 -0
- package/src/cli/commands/create-skill.ts +144 -0
- package/src/cli/commands/create-state.ts +71 -0
- package/src/cli/commands/delete-agent.ts +90 -0
- package/src/cli/commands/delete-flow.ts +105 -0
- package/src/cli/commands/delete-skill.ts +110 -0
- package/src/cli/commands/help.ts +104 -22
- package/src/cli/commands/push.ts +5 -3
- package/src/cli.ts +60 -0
- package/src/sync/diff-utils.ts +168 -0
- package/src/sync/push.ts +413 -5
- package/src/sync/skill-files.ts +22 -57
- package/src/sync/status.ts +183 -1
- package/src/types.ts +122 -2
package/src/sync/status.ts
CHANGED
|
@@ -10,7 +10,10 @@ import {
|
|
|
10
10
|
skillMetadataPath,
|
|
11
11
|
customerAttributesPath,
|
|
12
12
|
customerAttributesBackupPath,
|
|
13
|
-
flowsYamlPath
|
|
13
|
+
flowsYamlPath,
|
|
14
|
+
projectDir,
|
|
15
|
+
agentMetadataPath,
|
|
16
|
+
flowMetadataPath
|
|
14
17
|
} from '../fsutil.js';
|
|
15
18
|
import {
|
|
16
19
|
validateSkillFolder,
|
|
@@ -32,6 +35,122 @@ function isLegacyProjectMap(x: unknown): x is LegacyProjectMap {
|
|
|
32
35
|
return typeof x === 'object' && x !== null && 'projectId' in x && 'agents' in x;
|
|
33
36
|
}
|
|
34
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Scan filesystem for local-only entities not in the project map yet
|
|
40
|
+
*/
|
|
41
|
+
async function scanForLocalOnlyEntities(customer: CustomerConfig, projects: Record<string, ProjectData>, verbose: boolean = false): Promise<{ agentCount: number; flowCount: number; skillCount: number; entities: Array<{ type: 'agent' | 'flow' | 'skill'; path: string; idn: string; projectIdn: string; agentIdn?: string; flowIdn?: string }> }> {
|
|
42
|
+
const localEntities: Array<{ type: 'agent' | 'flow' | 'skill'; path: string; idn: string; projectIdn: string; agentIdn?: string; flowIdn?: string }> = [];
|
|
43
|
+
let agentCount = 0;
|
|
44
|
+
let flowCount = 0;
|
|
45
|
+
let skillCount = 0;
|
|
46
|
+
|
|
47
|
+
// Scan each project directory
|
|
48
|
+
for (const [projectIdn] of Object.entries(projects)) {
|
|
49
|
+
const projDir = projectDir(customer.idn, projectIdn);
|
|
50
|
+
if (!(await fs.pathExists(projDir))) continue;
|
|
51
|
+
|
|
52
|
+
if (verbose) console.log(`🔍 Scanning project directory: ${projDir}`);
|
|
53
|
+
|
|
54
|
+
// Get all subdirectories in the project (these should be agents)
|
|
55
|
+
const agentDirs = await fs.readdir(projDir);
|
|
56
|
+
|
|
57
|
+
for (const agentIdn of agentDirs) {
|
|
58
|
+
const agentPath = `${projDir}/${agentIdn}`;
|
|
59
|
+
const agentStat = await fs.stat(agentPath);
|
|
60
|
+
|
|
61
|
+
// Skip files, only process directories
|
|
62
|
+
if (!agentStat.isDirectory()) continue;
|
|
63
|
+
|
|
64
|
+
// Skip if it's not really an agent directory (no metadata.yaml)
|
|
65
|
+
const agentMetaPath = agentMetadataPath(customer.idn, projectIdn, agentIdn);
|
|
66
|
+
if (!(await fs.pathExists(agentMetaPath))) continue;
|
|
67
|
+
|
|
68
|
+
// Check if this agent is already in the project map
|
|
69
|
+
const projectData = projects[projectIdn];
|
|
70
|
+
if (!projectData?.agents[agentIdn]) {
|
|
71
|
+
// This is a local-only agent!
|
|
72
|
+
localEntities.push({
|
|
73
|
+
type: 'agent',
|
|
74
|
+
path: agentMetaPath,
|
|
75
|
+
idn: agentIdn,
|
|
76
|
+
projectIdn
|
|
77
|
+
});
|
|
78
|
+
agentCount++;
|
|
79
|
+
if (verbose) console.log(` 🆕 Found local-only agent: ${agentIdn}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Now scan for flows within this agent (regardless of whether agent is local-only or not)
|
|
83
|
+
try {
|
|
84
|
+
const flowDirs = await fs.readdir(agentPath);
|
|
85
|
+
for (const flowIdn of flowDirs) {
|
|
86
|
+
const flowPath = `${agentPath}/${flowIdn}`;
|
|
87
|
+
const flowStat = await fs.stat(flowPath);
|
|
88
|
+
|
|
89
|
+
// Skip files, only process directories
|
|
90
|
+
if (!flowStat.isDirectory()) continue;
|
|
91
|
+
|
|
92
|
+
// Skip if it's not really a flow directory (no metadata.yaml)
|
|
93
|
+
const flowMetaPath = flowMetadataPath(customer.idn, projectIdn, agentIdn, flowIdn);
|
|
94
|
+
if (!(await fs.pathExists(flowMetaPath))) continue;
|
|
95
|
+
|
|
96
|
+
// Check if this flow exists in the project map
|
|
97
|
+
const agentData = projectData?.agents[agentIdn];
|
|
98
|
+
if (!agentData?.flows[flowIdn]) {
|
|
99
|
+
// This is a local-only flow!
|
|
100
|
+
localEntities.push({
|
|
101
|
+
type: 'flow',
|
|
102
|
+
path: flowMetaPath,
|
|
103
|
+
idn: flowIdn,
|
|
104
|
+
projectIdn,
|
|
105
|
+
agentIdn
|
|
106
|
+
});
|
|
107
|
+
flowCount++;
|
|
108
|
+
if (verbose) console.log(` 🆕 Found local-only flow: ${agentIdn}/${flowIdn}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Now scan for skills within this flow (regardless of whether flow is local-only or not)
|
|
112
|
+
try {
|
|
113
|
+
const skillDirs = await fs.readdir(flowPath);
|
|
114
|
+
for (const skillIdn of skillDirs) {
|
|
115
|
+
const skillPath = `${flowPath}/${skillIdn}`;
|
|
116
|
+
const skillStat = await fs.stat(skillPath);
|
|
117
|
+
|
|
118
|
+
// Skip files, only process directories
|
|
119
|
+
if (!skillStat.isDirectory()) continue;
|
|
120
|
+
|
|
121
|
+
// Skip if it's not really a skill directory (no metadata.yaml)
|
|
122
|
+
const skillMetaPath = skillMetadataPath(customer.idn, projectIdn, agentIdn, flowIdn, skillIdn);
|
|
123
|
+
if (!(await fs.pathExists(skillMetaPath))) continue;
|
|
124
|
+
|
|
125
|
+
// Check if this skill exists in the project map
|
|
126
|
+
const flowData = agentData?.flows[flowIdn];
|
|
127
|
+
if (!flowData?.skills[skillIdn]) {
|
|
128
|
+
// This is a local-only skill!
|
|
129
|
+
localEntities.push({
|
|
130
|
+
type: 'skill',
|
|
131
|
+
path: skillMetaPath,
|
|
132
|
+
idn: skillIdn,
|
|
133
|
+
projectIdn,
|
|
134
|
+
agentIdn,
|
|
135
|
+
flowIdn
|
|
136
|
+
});
|
|
137
|
+
skillCount++;
|
|
138
|
+
if (verbose) console.log(` 🆕 Found local-only skill: ${agentIdn}/${flowIdn}/${skillIdn}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// Ignore errors reading flow directory
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
// Ignore errors reading agent directory
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return { agentCount, flowCount, skillCount, entities: localEntities };
|
|
152
|
+
}
|
|
153
|
+
|
|
35
154
|
/**
|
|
36
155
|
* Check status of files for a customer
|
|
37
156
|
*/
|
|
@@ -54,6 +173,69 @@ export async function status(customer: CustomerConfig, verbose: boolean = false)
|
|
|
54
173
|
? { '': idMapData as ProjectData }
|
|
55
174
|
: (() => { throw new Error('Invalid project map format'); })();
|
|
56
175
|
|
|
176
|
+
// First, scan for any local-only entities (created locally but not yet pushed)
|
|
177
|
+
const localScan = await scanForLocalOnlyEntities(customer, projects, verbose);
|
|
178
|
+
const totalLocalEntities = localScan.agentCount + localScan.flowCount + localScan.skillCount;
|
|
179
|
+
|
|
180
|
+
if (totalLocalEntities > 0) {
|
|
181
|
+
dirty += totalLocalEntities;
|
|
182
|
+
|
|
183
|
+
for (const entity of localScan.entities) {
|
|
184
|
+
if (entity.type === 'agent') {
|
|
185
|
+
console.log(`A ${entity.projectIdn}/${entity.idn}/metadata.yaml (new agent)`);
|
|
186
|
+
if (verbose) {
|
|
187
|
+
try {
|
|
188
|
+
const metadataContent = await fs.readFile(entity.path, 'utf8');
|
|
189
|
+
const metadata = yaml.load(metadataContent) as any;
|
|
190
|
+
console.log(` 📊 New Agent: ${entity.idn}`);
|
|
191
|
+
if (metadata?.title && metadata.title !== entity.idn) {
|
|
192
|
+
console.log(` • Title: ${metadata.title}`);
|
|
193
|
+
}
|
|
194
|
+
if (metadata?.description) {
|
|
195
|
+
console.log(` • Description: ${metadata.description}`);
|
|
196
|
+
}
|
|
197
|
+
} catch (e) {
|
|
198
|
+
// Ignore parsing errors
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} else if (entity.type === 'flow') {
|
|
202
|
+
console.log(`A ${entity.projectIdn}/${entity.agentIdn}/${entity.idn}/metadata.yaml (new flow)`);
|
|
203
|
+
if (verbose) {
|
|
204
|
+
try {
|
|
205
|
+
const metadataContent = await fs.readFile(entity.path, 'utf8');
|
|
206
|
+
const metadata = yaml.load(metadataContent) as any;
|
|
207
|
+
console.log(` 📊 New Flow: ${entity.idn}`);
|
|
208
|
+
if (metadata?.title && metadata.title !== entity.idn) {
|
|
209
|
+
console.log(` • Title: ${metadata.title}`);
|
|
210
|
+
}
|
|
211
|
+
if (metadata?.default_runner_type) {
|
|
212
|
+
console.log(` • Runner: ${metadata.default_runner_type}`);
|
|
213
|
+
}
|
|
214
|
+
} catch (e) {
|
|
215
|
+
// Ignore parsing errors
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} else if (entity.type === 'skill') {
|
|
219
|
+
console.log(`A ${entity.projectIdn}/${entity.agentIdn}/${entity.flowIdn}/${entity.idn}/metadata.yaml (new skill)`);
|
|
220
|
+
if (verbose) {
|
|
221
|
+
try {
|
|
222
|
+
const metadataContent = await fs.readFile(entity.path, 'utf8');
|
|
223
|
+
const metadata = yaml.load(metadataContent) as any;
|
|
224
|
+
console.log(` 📊 New Skill: ${entity.idn}`);
|
|
225
|
+
if (metadata?.title && metadata.title !== entity.idn) {
|
|
226
|
+
console.log(` • Title: ${metadata.title}`);
|
|
227
|
+
}
|
|
228
|
+
if (metadata?.runner_type) {
|
|
229
|
+
console.log(` • Runner: ${metadata.runner_type}`);
|
|
230
|
+
}
|
|
231
|
+
} catch (e) {
|
|
232
|
+
// Ignore parsing errors
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
57
239
|
for (const [projectIdn, projectData] of Object.entries(projects)) {
|
|
58
240
|
if (verbose && projectIdn) console.log(`📁 Checking project: ${projectIdn}`);
|
|
59
241
|
|
package/src/types.ts
CHANGED
|
@@ -306,8 +306,7 @@ export interface AgentMetadata {
|
|
|
306
306
|
idn: string;
|
|
307
307
|
title?: string;
|
|
308
308
|
description?: string;
|
|
309
|
-
|
|
310
|
-
persona?: string;
|
|
309
|
+
persona_id?: string | null;
|
|
311
310
|
created_at?: string;
|
|
312
311
|
updated_at?: string;
|
|
313
312
|
}
|
|
@@ -449,4 +448,125 @@ export interface ConversationsData {
|
|
|
449
448
|
readonly total_personas: number;
|
|
450
449
|
readonly total_acts: number;
|
|
451
450
|
readonly generated_at: string;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Entity Creation/Deletion Types
|
|
454
|
+
|
|
455
|
+
export interface CreateAgentRequest {
|
|
456
|
+
idn: string;
|
|
457
|
+
title: string;
|
|
458
|
+
description?: string | null;
|
|
459
|
+
persona_id?: string | null;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export interface CreateAgentResponse {
|
|
463
|
+
id: string;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
export interface CreateFlowRequest {
|
|
467
|
+
idn: string;
|
|
468
|
+
title: string;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export interface CreateFlowResponse {
|
|
472
|
+
id: string;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export interface CreateSkillRequest {
|
|
476
|
+
idn: string;
|
|
477
|
+
title: string;
|
|
478
|
+
prompt_script?: string;
|
|
479
|
+
runner_type: RunnerType;
|
|
480
|
+
model: ModelConfig;
|
|
481
|
+
path?: string;
|
|
482
|
+
parameters?: SkillParameter[];
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export interface CreateSkillResponse {
|
|
486
|
+
id: string;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
export interface CreateFlowEventRequest {
|
|
490
|
+
idn: string;
|
|
491
|
+
description?: string;
|
|
492
|
+
skill_selector: string;
|
|
493
|
+
skill_idn?: string;
|
|
494
|
+
state_idn?: string | null;
|
|
495
|
+
interrupt_mode: string;
|
|
496
|
+
integration_idn: string;
|
|
497
|
+
connector_idn: string;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export interface CreateFlowEventResponse {
|
|
501
|
+
id: string;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export interface CreateFlowStateRequest {
|
|
505
|
+
title: string;
|
|
506
|
+
idn: string;
|
|
507
|
+
default_value?: string;
|
|
508
|
+
scope: string;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
export interface CreateFlowStateResponse {
|
|
512
|
+
id: string;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
export interface CreateSkillParameterRequest {
|
|
516
|
+
name: string;
|
|
517
|
+
default_value?: string;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export interface CreateSkillParameterResponse {
|
|
521
|
+
id: string;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
export interface CreateCustomerAttributeRequest {
|
|
525
|
+
idn: string;
|
|
526
|
+
value: string;
|
|
527
|
+
title: string;
|
|
528
|
+
description?: string;
|
|
529
|
+
group: string;
|
|
530
|
+
is_hidden: boolean;
|
|
531
|
+
possible_values: string[];
|
|
532
|
+
value_type: string;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
export interface CreateCustomerAttributeResponse {
|
|
536
|
+
id: string;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export interface CreatePersonaRequest {
|
|
540
|
+
name: string;
|
|
541
|
+
title: string;
|
|
542
|
+
description?: string;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
export interface CreatePersonaResponse {
|
|
546
|
+
id: string;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
export interface CreateProjectRequest {
|
|
550
|
+
idn: string;
|
|
551
|
+
title: string;
|
|
552
|
+
version?: string;
|
|
553
|
+
description?: string;
|
|
554
|
+
is_auto_update_enabled?: boolean;
|
|
555
|
+
registry_idn?: string;
|
|
556
|
+
registry_item_idn?: string | null;
|
|
557
|
+
registry_item_version?: string | null;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
export interface CreateProjectResponse {
|
|
561
|
+
id: string;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
export interface PublishFlowRequest {
|
|
565
|
+
version: string;
|
|
566
|
+
description: string;
|
|
567
|
+
type: string;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export interface PublishFlowResponse {
|
|
571
|
+
success: boolean;
|
|
452
572
|
}
|