newo 3.4.2 → 3.6.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 (64) hide show
  1. package/.env.example +5 -0
  2. package/CHANGELOG.md +21 -0
  3. package/dist/api.d.ts +18 -0
  4. package/dist/api.js +28 -0
  5. package/dist/cli/commands/export.d.ts +3 -0
  6. package/dist/cli/commands/export.js +62 -0
  7. package/dist/cli/commands/help.js +54 -42
  8. package/dist/cli/commands/pull.js +38 -14
  9. package/dist/cli/commands/push.js +32 -32
  10. package/dist/cli/commands/status.js +46 -7
  11. package/dist/cli-new/bootstrap.d.ts +7 -1
  12. package/dist/cli-new/bootstrap.js +11 -5
  13. package/dist/cli-new/di/tokens.d.ts +1 -0
  14. package/dist/cli-new/di/tokens.js +1 -0
  15. package/dist/cli.js +4 -0
  16. package/dist/domain/strategies/sync/ProjectSyncStrategy.d.ts +5 -0
  17. package/dist/domain/strategies/sync/ProjectSyncStrategy.js +97 -8
  18. package/dist/domain/strategies/sync/V2ProjectSyncStrategy.d.ts +80 -0
  19. package/dist/domain/strategies/sync/V2ProjectSyncStrategy.js +725 -0
  20. package/dist/env.d.ts +1 -0
  21. package/dist/env.js +1 -0
  22. package/dist/format/detect.d.ts +14 -0
  23. package/dist/format/detect.js +105 -0
  24. package/dist/format/extensions.d.ts +26 -0
  25. package/dist/format/extensions.js +45 -0
  26. package/dist/format/index.d.ts +11 -0
  27. package/dist/format/index.js +11 -0
  28. package/dist/format/paths-v2.d.ts +31 -0
  29. package/dist/format/paths-v2.js +104 -0
  30. package/dist/format/types.d.ts +28 -0
  31. package/dist/format/types.js +21 -0
  32. package/dist/format/v2-yaml.d.ts +143 -0
  33. package/dist/format/v2-yaml.js +222 -0
  34. package/dist/format/yaml-patch.d.ts +14 -0
  35. package/dist/format/yaml-patch.js +184 -0
  36. package/dist/fsutil.d.ts +10 -0
  37. package/dist/fsutil.js +25 -0
  38. package/dist/sync/attributes.js +3 -3
  39. package/dist/sync/skill-files.js +2 -2
  40. package/dist/types.d.ts +5 -0
  41. package/package.json +1 -1
  42. package/src/api.ts +64 -0
  43. package/src/cli/commands/export.ts +78 -0
  44. package/src/cli/commands/help.ts +54 -42
  45. package/src/cli/commands/pull.ts +46 -15
  46. package/src/cli/commands/push.ts +38 -31
  47. package/src/cli/commands/status.ts +59 -9
  48. package/src/cli-new/bootstrap.ts +19 -7
  49. package/src/cli-new/di/tokens.ts +1 -0
  50. package/src/cli.ts +5 -0
  51. package/src/domain/strategies/sync/ProjectSyncStrategy.ts +122 -8
  52. package/src/domain/strategies/sync/V2ProjectSyncStrategy.ts +1007 -0
  53. package/src/env.ts +2 -0
  54. package/src/format/detect.ts +123 -0
  55. package/src/format/extensions.ts +61 -0
  56. package/src/format/index.ts +66 -0
  57. package/src/format/paths-v2.ts +207 -0
  58. package/src/format/types.ts +40 -0
  59. package/src/format/v2-yaml.ts +345 -0
  60. package/src/format/yaml-patch.ts +208 -0
  61. package/src/fsutil.ts +37 -0
  62. package/src/sync/attributes.ts +3 -3
  63. package/src/sync/skill-files.ts +2 -2
  64. package/src/types.ts +6 -0
@@ -46,7 +46,9 @@ import {
46
46
  listFlowEvents,
47
47
  listFlowStates,
48
48
  updateSkill,
49
- publishFlow
49
+ publishFlow,
50
+ listLibraries,
51
+ updateLibrarySkill,
50
52
  } from '../../../api.js';
51
53
  import {
52
54
  ensureState,
@@ -60,7 +62,10 @@ import {
60
62
  skillFolderPath,
61
63
  flowsYamlPath,
62
64
  customerProjectsDir,
63
- projectDir
65
+ projectDir,
66
+ libraryMetadataPath,
67
+ librarySkillMetadataPath,
68
+ librarySkillScriptPath,
64
69
  } from '../../../fsutil.js';
65
70
  import { sha256, saveHashes, loadHashes } from '../../../hash.js';
66
71
  import { generateFlowsYaml } from '../../../sync/metadata.js';
@@ -241,6 +246,52 @@ export class ProjectSyncStrategy implements ISyncStrategy<ProjectMeta, LocalProj
241
246
  }
242
247
  }
243
248
 
249
+ // Pull libraries for this project
250
+ try {
251
+ const libraries = await listLibraries(client, project.id);
252
+ if (libraries.length > 0) {
253
+ this.logger.verbose(` Found ${libraries.length} libraries in project ${project.idn}`);
254
+ projectData.libraries = {};
255
+
256
+ for (const lib of libraries) {
257
+ projectData.libraries[lib.idn] = {
258
+ id: lib.id,
259
+ skills: {}
260
+ };
261
+
262
+ // Save library metadata
263
+ const libMetaPath = libraryMetadataPath(customer.idn, project.idn, lib.idn);
264
+ const libMeta = { id: lib.id, idn: lib.idn };
265
+ const libMetaYaml = yaml.dump(libMeta, { indent: 2, quotingType: '"', forceQuotes: false });
266
+ await writeFileSafe(libMetaPath, libMetaYaml);
267
+ hashes[libMetaPath] = sha256(libMetaYaml);
268
+
269
+ for (const skill of lib.skills) {
270
+ // Save skill metadata
271
+ const skillMetaPath = librarySkillMetadataPath(customer.idn, project.idn, lib.idn, skill.idn);
272
+ const skillMeta: SkillMetadata = {
273
+ id: skill.id, idn: skill.idn, title: skill.title,
274
+ runner_type: skill.runner_type, model: skill.model,
275
+ parameters: [...skill.parameters], path: skill.path
276
+ };
277
+ const skillMetaYaml = yaml.dump(skillMeta, { indent: 2, quotingType: '"', forceQuotes: false });
278
+ await writeFileSafe(skillMetaPath, skillMetaYaml);
279
+ hashes[skillMetaPath] = sha256(skillMetaYaml);
280
+
281
+ // Save skill script
282
+ const scriptContent = skill.prompt_script || '';
283
+ const scriptPath = librarySkillScriptPath(customer.idn, project.idn, lib.idn, skill.idn, skill.runner_type);
284
+ await writeFileSafe(scriptPath, scriptContent);
285
+ hashes[scriptPath] = sha256(scriptContent);
286
+
287
+ projectData.libraries[lib.idn]!.skills[skill.idn] = skillMeta;
288
+ }
289
+ }
290
+ }
291
+ } catch (error) {
292
+ this.logger.verbose(` Could not pull libraries for project ${project.idn}: ${error instanceof Error ? error.message : String(error)}`);
293
+ }
294
+
244
295
  existingMap.projects[project.idn] = projectData;
245
296
  projects.push(localProject);
246
297
  }
@@ -489,11 +540,15 @@ export class ProjectSyncStrategy implements ISyncStrategy<ProjectMeta, LocalProj
489
540
  for (const change of changes) {
490
541
  try {
491
542
  if (change.operation === 'modified') {
492
- // Update existing skill
493
- const updateResult = await this.pushSkillUpdate(client, customer, change, mapData, newHashes);
494
- result.updated += updateResult;
543
+ const isLibrary = change.path.includes('/libraries/');
544
+ if (isLibrary) {
545
+ const updateResult = await this.pushLibrarySkillUpdate(client, change, mapData, newHashes);
546
+ result.updated += updateResult;
547
+ } else {
548
+ const updateResult = await this.pushSkillUpdate(client, customer, change, mapData, newHashes);
549
+ result.updated += updateResult;
550
+ }
495
551
  } else if (change.operation === 'created') {
496
- // Create new entity
497
552
  const createResult = await this.pushNewEntity(client, customer, change, mapData, newHashes);
498
553
  result.created += createResult;
499
554
  }
@@ -563,6 +618,40 @@ export class ProjectSyncStrategy implements ISyncStrategy<ProjectMeta, LocalProj
563
618
  return 1;
564
619
  }
565
620
 
621
+ /**
622
+ * Push a library skill update
623
+ * Path: newo_customers/{customer}/projects/{project}/libraries/{lib}/{skill}/{skill}.jinja
624
+ */
625
+ private async pushLibrarySkillUpdate(
626
+ client: AxiosInstance,
627
+ change: ChangeItem<LocalProjectData>,
628
+ mapData: ProjectMap,
629
+ newHashes: HashStore
630
+ ): Promise<number> {
631
+ const pathParts = change.path.split('/');
632
+ const skillIdn = pathParts[pathParts.length - 2] || '';
633
+ const libIdn = pathParts[pathParts.length - 3] || '';
634
+ const projectIdn = pathParts[pathParts.length - 5] || '';
635
+
636
+ const projectData = mapData.projects[projectIdn];
637
+ const libData = projectData?.libraries?.[libIdn];
638
+ const skillData = libData?.skills[skillIdn];
639
+
640
+ if (!skillData || !libData) {
641
+ throw new Error(`Library skill ${skillIdn} not found in project map`);
642
+ }
643
+
644
+ const content = await fs.readFile(change.path, 'utf8');
645
+
646
+ await updateLibrarySkill(client, libData.id, skillData.id, {
647
+ prompt_script: content,
648
+ });
649
+
650
+ newHashes[change.path] = sha256(content);
651
+ this.logger.info(`Pushed library skill: ${libIdn}/${skillIdn}`);
652
+ return 1;
653
+ }
654
+
566
655
  /**
567
656
  * Push a new entity
568
657
  */
@@ -616,7 +705,7 @@ export class ProjectSyncStrategy implements ISyncStrategy<ProjectMeta, LocalProj
616
705
  const hashes = await loadHashes(customer.idn);
617
706
  const mapData = await fs.readJson(mapFile) as ProjectMap;
618
707
 
619
- // Scan for changed skill scripts
708
+ // Scan for changed flow skill scripts
620
709
  for (const [projectIdn, projectData] of Object.entries(mapData.projects)) {
621
710
  for (const [agentIdn, agentData] of Object.entries(projectData.agents)) {
622
711
  for (const [flowIdn, flowData] of Object.entries(agentData.flows)) {
@@ -629,7 +718,7 @@ export class ProjectSyncStrategy implements ISyncStrategy<ProjectMeta, LocalProj
629
718
 
630
719
  if (storedHash !== currentHash) {
631
720
  changes.push({
632
- item: {} as LocalProjectData, // Simplified for now
721
+ item: {} as LocalProjectData,
633
722
  operation: 'modified',
634
723
  path: skillFile.filePath
635
724
  });
@@ -638,6 +727,31 @@ export class ProjectSyncStrategy implements ISyncStrategy<ProjectMeta, LocalProj
638
727
  }
639
728
  }
640
729
  }
730
+
731
+ // Scan for changed library skill scripts
732
+ if (projectData.libraries) {
733
+ for (const [libIdn, libData] of Object.entries(projectData.libraries)) {
734
+ for (const [skillIdn, skillMeta] of Object.entries(libData.skills)) {
735
+ const scriptPath = librarySkillScriptPath(
736
+ customer.idn, projectIdn, libIdn, skillIdn, skillMeta.runner_type
737
+ );
738
+
739
+ if (await fs.pathExists(scriptPath)) {
740
+ const content = await fs.readFile(scriptPath, 'utf8');
741
+ const currentHash = sha256(content);
742
+ const storedHash = hashes[scriptPath];
743
+
744
+ if (storedHash !== currentHash) {
745
+ changes.push({
746
+ item: {} as LocalProjectData,
747
+ operation: 'modified',
748
+ path: scriptPath
749
+ });
750
+ }
751
+ }
752
+ }
753
+ }
754
+ }
641
755
  }
642
756
 
643
757
  return changes;