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.
Files changed (60) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +146 -0
  3. package/dist/api.d.ts +17 -1
  4. package/dist/api.js +78 -0
  5. package/dist/cli/commands/create-agent.d.ts +3 -0
  6. package/dist/cli/commands/create-agent.js +75 -0
  7. package/dist/cli/commands/create-attribute.d.ts +3 -0
  8. package/dist/cli/commands/create-attribute.js +63 -0
  9. package/dist/cli/commands/create-event.d.ts +3 -0
  10. package/dist/cli/commands/create-event.js +66 -0
  11. package/dist/cli/commands/create-flow.d.ts +3 -0
  12. package/dist/cli/commands/create-flow.js +100 -0
  13. package/dist/cli/commands/create-parameter.d.ts +3 -0
  14. package/dist/cli/commands/create-parameter.js +47 -0
  15. package/dist/cli/commands/create-persona.d.ts +3 -0
  16. package/dist/cli/commands/create-persona.js +43 -0
  17. package/dist/cli/commands/create-project.d.ts +3 -0
  18. package/dist/cli/commands/create-project.js +55 -0
  19. package/dist/cli/commands/create-skill.d.ts +3 -0
  20. package/dist/cli/commands/create-skill.js +115 -0
  21. package/dist/cli/commands/create-state.d.ts +3 -0
  22. package/dist/cli/commands/create-state.js +58 -0
  23. package/dist/cli/commands/delete-agent.d.ts +3 -0
  24. package/dist/cli/commands/delete-agent.js +70 -0
  25. package/dist/cli/commands/delete-flow.d.ts +3 -0
  26. package/dist/cli/commands/delete-flow.js +83 -0
  27. package/dist/cli/commands/delete-skill.d.ts +3 -0
  28. package/dist/cli/commands/delete-skill.js +87 -0
  29. package/dist/cli/commands/help.js +104 -22
  30. package/dist/cli/commands/push.js +4 -3
  31. package/dist/cli.js +48 -0
  32. package/dist/sync/diff-utils.d.ts +18 -0
  33. package/dist/sync/diff-utils.js +152 -0
  34. package/dist/sync/push.d.ts +1 -1
  35. package/dist/sync/push.js +372 -4
  36. package/dist/sync/skill-files.js +22 -49
  37. package/dist/sync/status.js +178 -1
  38. package/dist/types.d.ts +100 -1
  39. package/package.json +1 -1
  40. package/src/api.ts +118 -1
  41. package/src/cli/commands/create-agent.ts +96 -0
  42. package/src/cli/commands/create-attribute.ts +75 -0
  43. package/src/cli/commands/create-event.ts +79 -0
  44. package/src/cli/commands/create-flow.ts +124 -0
  45. package/src/cli/commands/create-parameter.ts +59 -0
  46. package/src/cli/commands/create-persona.ts +54 -0
  47. package/src/cli/commands/create-project.ts +66 -0
  48. package/src/cli/commands/create-skill.ts +144 -0
  49. package/src/cli/commands/create-state.ts +71 -0
  50. package/src/cli/commands/delete-agent.ts +90 -0
  51. package/src/cli/commands/delete-flow.ts +105 -0
  52. package/src/cli/commands/delete-skill.ts +110 -0
  53. package/src/cli/commands/help.ts +104 -22
  54. package/src/cli/commands/push.ts +5 -3
  55. package/src/cli.ts +60 -0
  56. package/src/sync/diff-utils.ts +168 -0
  57. package/src/sync/push.ts +413 -5
  58. package/src/sync/skill-files.ts +22 -57
  59. package/src/sync/status.ts +183 -1
  60. package/src/types.ts +122 -2
@@ -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
- // Additional agent settings from UI could be added here
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
  }