newo 1.6.0 → 1.7.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/src/api.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  import axios, { type AxiosInstance, type InternalAxiosRequestConfig, type AxiosResponse, type AxiosError } from 'axios';
2
2
  import { getValidAccessToken, forceReauth } from './auth.js';
3
3
  import { ENV } from './env.js';
4
- import type {
5
- ProjectMeta,
6
- Agent,
7
- Skill,
8
- FlowEvent,
4
+ import type {
5
+ ProjectMeta,
6
+ Agent,
7
+ Skill,
8
+ FlowEvent,
9
9
  FlowState,
10
10
  AkbImportArticle,
11
- CustomerProfile
11
+ CustomerProfile,
12
+ CustomerAttribute,
13
+ CustomerAttributesResponse
12
14
  } from './types.js';
13
15
 
14
16
  // Per-request retry tracking to avoid shared state issues
@@ -127,4 +129,27 @@ export async function importAkbArticle(client: AxiosInstance, articleData: AkbIm
127
129
  export async function getCustomerProfile(client: AxiosInstance): Promise<CustomerProfile> {
128
130
  const response = await client.get<CustomerProfile>('/api/v1/customer/profile');
129
131
  return response.data;
132
+ }
133
+
134
+ export async function getCustomerAttributes(client: AxiosInstance, includeHidden: boolean = true): Promise<CustomerAttributesResponse> {
135
+ const response = await client.get<CustomerAttributesResponse>('/api/v1/bff/customer/attributes', {
136
+ params: { include_hidden: includeHidden }
137
+ });
138
+ return response.data;
139
+ }
140
+
141
+ export async function updateCustomerAttribute(client: AxiosInstance, attribute: CustomerAttribute): Promise<void> {
142
+ if (!attribute.id) {
143
+ throw new Error(`Attribute ${attribute.idn} is missing ID - cannot update`);
144
+ }
145
+ await client.put(`/api/v1/customer/attributes/${attribute.id}`, {
146
+ idn: attribute.idn,
147
+ value: attribute.value,
148
+ title: attribute.title,
149
+ description: attribute.description,
150
+ group: attribute.group,
151
+ is_hidden: attribute.is_hidden,
152
+ possible_values: attribute.possible_values,
153
+ value_type: attribute.value_type
154
+ });
130
155
  }
package/src/cli.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import minimist from 'minimist';
3
3
  import dotenv from 'dotenv';
4
4
  import { makeClient, getProjectMeta, importAkbArticle } from './api.js';
5
- import { pullAll, pushChanged, status } from './sync.js';
5
+ import { pullAll, pushChanged, status, saveCustomerAttributes } from './sync.js';
6
6
  import { parseAkbFile, prepareArticlesForImport } from './akb.js';
7
7
  import { initializeEnvironment, ENV, EnvValidationError } from './env.js';
8
8
  import { parseCustomerConfigAsync, listCustomers, getCustomer, getDefaultCustomer, tryGetDefaultCustomer, getAllCustomers, validateCustomerConfig } from './customerAsync.js';
@@ -281,6 +281,10 @@ File Structure:
281
281
  }
282
282
  const meta = await getProjectMeta(client, selectedCustomer.projectId);
283
283
  console.log(JSON.stringify(meta, null, 2));
284
+ } else if (cmd === 'pull-attributes') {
285
+ console.log(`🔍 Fetching customer attributes for ${selectedCustomer.idn}...`);
286
+ await saveCustomerAttributes(client, selectedCustomer, verbose);
287
+ console.log(`✅ Customer attributes saved to newo_customers/${selectedCustomer.idn}/attributes.yaml`);
284
288
  } else if (cmd === 'import-akb') {
285
289
  const akbFile = args._[1];
286
290
  const personaId = args._[2];
package/src/fsutil.ts CHANGED
@@ -39,18 +39,74 @@ export function flowsYamlPath(customerIdn: string): string {
39
39
  return path.posix.join(customerProjectsDir(customerIdn), 'flows.yaml');
40
40
  }
41
41
 
42
+ export function customerAttributesPath(customerIdn: string): string {
43
+ return path.posix.join(customerDir(customerIdn), 'attributes.yaml');
44
+ }
45
+
46
+ export function customerAttributesMapPath(customerIdn: string): string {
47
+ return path.join(customerStateDir(customerIdn), 'attributes-map.json');
48
+ }
49
+
50
+ // Legacy skill path - direct file
42
51
  export function skillPath(
43
52
  customerIdn: string,
44
- projectIdn: string,
45
- agentIdn: string,
46
- flowIdn: string,
47
- skillIdn: string,
53
+ projectIdn: string,
54
+ agentIdn: string,
55
+ flowIdn: string,
56
+ skillIdn: string,
48
57
  runnerType: RunnerType = 'guidance'
49
58
  ): string {
50
59
  const extension = runnerType === 'nsl' ? '.jinja' : '.guidance';
51
60
  return path.posix.join(customerProjectsDir(customerIdn), projectIdn, agentIdn, flowIdn, `${skillIdn}${extension}`);
52
61
  }
53
62
 
63
+ // New hierarchical structure paths
64
+ export function skillFolderPath(
65
+ customerIdn: string,
66
+ projectIdn: string,
67
+ agentIdn: string,
68
+ flowIdn: string,
69
+ skillIdn: string
70
+ ): string {
71
+ return path.posix.join(customerProjectsDir(customerIdn), projectIdn, agentIdn, flowIdn, skillIdn);
72
+ }
73
+
74
+ export function skillScriptPath(
75
+ customerIdn: string,
76
+ projectIdn: string,
77
+ agentIdn: string,
78
+ flowIdn: string,
79
+ skillIdn: string,
80
+ runnerType: RunnerType = 'guidance'
81
+ ): string {
82
+ const extension = runnerType === 'nsl' ? '.jinja' : '.guidance';
83
+ return path.posix.join(skillFolderPath(customerIdn, projectIdn, agentIdn, flowIdn, skillIdn), `skill${extension}`);
84
+ }
85
+
86
+ // Metadata paths for hierarchical structure
87
+ export function projectMetadataPath(customerIdn: string, projectIdn: string): string {
88
+ return path.posix.join(customerProjectsDir(customerIdn), projectIdn, 'metadata.yaml');
89
+ }
90
+
91
+ export function agentMetadataPath(customerIdn: string, projectIdn: string, agentIdn: string): string {
92
+ return path.posix.join(customerProjectsDir(customerIdn), projectIdn, agentIdn, 'metadata.yaml');
93
+ }
94
+
95
+ export function flowMetadataPath(customerIdn: string, projectIdn: string, agentIdn: string, flowIdn: string): string {
96
+ return path.posix.join(customerProjectsDir(customerIdn), projectIdn, agentIdn, flowIdn, 'metadata.yaml');
97
+ }
98
+
99
+ export function skillMetadataPath(
100
+ customerIdn: string,
101
+ projectIdn: string,
102
+ agentIdn: string,
103
+ flowIdn: string,
104
+ skillIdn: string
105
+ ): string {
106
+ return path.posix.join(skillFolderPath(customerIdn, projectIdn, agentIdn, flowIdn, skillIdn), 'metadata.yaml');
107
+ }
108
+
109
+ // Legacy metadata path - keep for backwards compatibility
54
110
  export function metadataPath(customerIdn: string, projectIdn: string): string {
55
111
  return path.posix.join(customerProjectsDir(customerIdn), projectIdn, 'metadata.json');
56
112
  }