newo 1.9.2 → 2.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 (66) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +68 -20
  3. package/dist/cli/commands/conversations.d.ts +3 -0
  4. package/dist/cli/commands/conversations.js +38 -0
  5. package/dist/cli/commands/help.d.ts +5 -0
  6. package/dist/cli/commands/help.js +50 -0
  7. package/dist/cli/commands/import-akb.d.ts +3 -0
  8. package/dist/cli/commands/import-akb.js +62 -0
  9. package/dist/cli/commands/list-customers.d.ts +3 -0
  10. package/dist/cli/commands/list-customers.js +13 -0
  11. package/dist/cli/commands/meta.d.ts +3 -0
  12. package/dist/cli/commands/meta.js +19 -0
  13. package/dist/cli/commands/pull-attributes.d.ts +3 -0
  14. package/dist/cli/commands/pull-attributes.js +16 -0
  15. package/dist/cli/commands/pull.d.ts +3 -0
  16. package/dist/cli/commands/pull.js +34 -0
  17. package/dist/cli/commands/push.d.ts +3 -0
  18. package/dist/cli/commands/push.js +39 -0
  19. package/dist/cli/commands/status.d.ts +3 -0
  20. package/dist/cli/commands/status.js +22 -0
  21. package/dist/cli/customer-selection.d.ts +23 -0
  22. package/dist/cli/customer-selection.js +110 -0
  23. package/dist/cli/errors.d.ts +9 -0
  24. package/dist/cli/errors.js +111 -0
  25. package/dist/cli.js +66 -463
  26. package/dist/fsutil.js +1 -1
  27. package/dist/sync/attributes.d.ts +7 -0
  28. package/dist/sync/attributes.js +90 -0
  29. package/dist/sync/conversations.d.ts +7 -0
  30. package/dist/sync/conversations.js +218 -0
  31. package/dist/sync/metadata.d.ts +8 -0
  32. package/dist/sync/metadata.js +124 -0
  33. package/dist/sync/projects.d.ts +13 -0
  34. package/dist/sync/projects.js +283 -0
  35. package/dist/sync/push.d.ts +7 -0
  36. package/dist/sync/push.js +171 -0
  37. package/dist/sync/skill-files.d.ts +42 -0
  38. package/dist/sync/skill-files.js +121 -0
  39. package/dist/sync/status.d.ts +6 -0
  40. package/dist/sync/status.js +247 -0
  41. package/dist/sync.d.ts +10 -8
  42. package/dist/sync.js +12 -1226
  43. package/dist/types.d.ts +0 -1
  44. package/package.json +2 -2
  45. package/src/cli/commands/conversations.ts +47 -0
  46. package/src/cli/commands/help.ts +50 -0
  47. package/src/cli/commands/import-akb.ts +71 -0
  48. package/src/cli/commands/list-customers.ts +14 -0
  49. package/src/cli/commands/meta.ts +26 -0
  50. package/src/cli/commands/pull-attributes.ts +23 -0
  51. package/src/cli/commands/pull.ts +43 -0
  52. package/src/cli/commands/push.ts +47 -0
  53. package/src/cli/commands/status.ts +30 -0
  54. package/src/cli/customer-selection.ts +135 -0
  55. package/src/cli/errors.ts +111 -0
  56. package/src/cli.ts +77 -471
  57. package/src/fsutil.ts +1 -1
  58. package/src/sync/attributes.ts +110 -0
  59. package/src/sync/conversations.ts +257 -0
  60. package/src/sync/metadata.ts +153 -0
  61. package/src/sync/projects.ts +359 -0
  62. package/src/sync/push.ts +200 -0
  63. package/src/sync/skill-files.ts +176 -0
  64. package/src/sync/status.ts +277 -0
  65. package/src/sync.ts +14 -1418
  66. package/src/types.ts +0 -1
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Customer attributes synchronization module
3
+ */
4
+ import { getCustomerAttributes } from '../api.js';
5
+ import { writeFileSafe, customerAttributesPath, customerAttributesMapPath, customerAttributesBackupPath } from '../fsutil.js';
6
+ import yaml from 'js-yaml';
7
+ /**
8
+ * Save customer attributes to YAML format and return content for hashing
9
+ */
10
+ export async function saveCustomerAttributes(client, customer, verbose = false) {
11
+ if (verbose)
12
+ console.log(`🔍 Fetching customer attributes for ${customer.idn}...`);
13
+ try {
14
+ const response = await getCustomerAttributes(client, true); // Include hidden attributes
15
+ // API returns { groups: [...], attributes: [...] }
16
+ // We only want the attributes array in the expected format
17
+ const attributes = response.attributes || response;
18
+ if (verbose)
19
+ console.log(`📦 Found ${Array.isArray(attributes) ? attributes.length : 'invalid'} attributes`);
20
+ // Create ID mapping for push operations (separate from YAML)
21
+ const idMapping = {};
22
+ // Transform attributes to match reference format exactly (no ID fields)
23
+ const cleanAttributes = Array.isArray(attributes) ? attributes.map(attr => {
24
+ // Store ID mapping for push operations
25
+ if (attr.id) {
26
+ idMapping[attr.idn] = attr.id;
27
+ }
28
+ // Special handling for complex JSON string values
29
+ let processedValue = attr.value;
30
+ if (typeof attr.value === 'string' && attr.value.startsWith('[{') && attr.value.endsWith('}]')) {
31
+ try {
32
+ // Parse and reformat JSON for better readability
33
+ const parsed = JSON.parse(attr.value);
34
+ processedValue = JSON.stringify(parsed, null, 0); // No extra spacing, but valid JSON
35
+ }
36
+ catch (e) {
37
+ // Keep original if parsing fails
38
+ processedValue = attr.value;
39
+ }
40
+ }
41
+ const cleanAttr = {
42
+ idn: attr.idn,
43
+ value: processedValue,
44
+ title: attr.title || "",
45
+ description: attr.description || "",
46
+ group: attr.group || "",
47
+ is_hidden: attr.is_hidden,
48
+ possible_values: attr.possible_values || [],
49
+ value_type: `__ENUM_PLACEHOLDER_${attr.value_type}__`
50
+ };
51
+ return cleanAttr;
52
+ }) : [];
53
+ const attributesYaml = {
54
+ attributes: cleanAttributes
55
+ };
56
+ // Configure YAML output to match reference format exactly
57
+ let yamlContent = yaml.dump(attributesYaml, {
58
+ indent: 2,
59
+ quotingType: '"',
60
+ forceQuotes: false,
61
+ lineWidth: 80, // Wrap long lines to match reference format
62
+ noRefs: true,
63
+ sortKeys: false,
64
+ flowLevel: -1, // Never use flow syntax
65
+ styles: {
66
+ '!!str': 'folded' // Use folded style for better line wrapping of long strings
67
+ }
68
+ });
69
+ // Post-process to fix enum format and improve JSON string formatting
70
+ yamlContent = yamlContent.replace(/__ENUM_PLACEHOLDER_(\w+)__/g, '!enum "AttributeValueTypes.$1"');
71
+ // Fix JSON string formatting to match reference (remove escape characters)
72
+ yamlContent = yamlContent.replace(/\\"/g, '"');
73
+ // Save all files: attributes.yaml, ID mapping, and backup for diff tracking
74
+ await writeFileSafe(customerAttributesPath(customer.idn), yamlContent);
75
+ await writeFileSafe(customerAttributesMapPath(customer.idn), JSON.stringify(idMapping, null, 2));
76
+ await writeFileSafe(customerAttributesBackupPath(customer.idn), yamlContent);
77
+ if (verbose) {
78
+ console.log(`✓ Saved customer attributes to ${customerAttributesPath(customer.idn)}`);
79
+ console.log(`✓ Saved attribute ID mapping to ${customerAttributesMapPath(customer.idn)}`);
80
+ console.log(`✓ Created attributes backup for diff tracking`);
81
+ }
82
+ // Return content for hash calculation
83
+ return yamlContent;
84
+ }
85
+ catch (error) {
86
+ console.error(`❌ Failed to save customer attributes for ${customer.idn}:`, error);
87
+ throw error;
88
+ }
89
+ }
90
+ //# sourceMappingURL=attributes.js.map
@@ -0,0 +1,7 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { CustomerConfig, ConversationOptions } from '../types.js';
3
+ /**
4
+ * Pull conversations for a customer and save to YAML
5
+ */
6
+ export declare function pullConversations(client: AxiosInstance, customer: CustomerConfig, options?: ConversationOptions, verbose?: boolean): Promise<void>;
7
+ //# sourceMappingURL=conversations.d.ts.map
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Conversations synchronization module
3
+ */
4
+ import { listUserPersonas, getChatHistory } from '../api.js';
5
+ import { writeFileSafe } from '../fsutil.js';
6
+ import yaml from 'js-yaml';
7
+ import pLimit from 'p-limit';
8
+ // Concurrency limit for API calls
9
+ const concurrencyLimit = pLimit(5);
10
+ /**
11
+ * Pull conversations for a customer and save to YAML
12
+ */
13
+ export async function pullConversations(client, customer, options = {}, verbose = false) {
14
+ if (verbose)
15
+ console.log(`💬 Fetching conversations for customer ${customer.idn}...`);
16
+ try {
17
+ // Get all user personas with pagination
18
+ const allPersonas = [];
19
+ let page = 1;
20
+ const perPage = 50;
21
+ let hasMore = true;
22
+ while (hasMore) {
23
+ const response = await listUserPersonas(client, page, perPage);
24
+ allPersonas.push(...response.items);
25
+ if (verbose)
26
+ console.log(`📋 Page ${page}: Found ${response.items.length} personas (${allPersonas.length}/${response.metadata.total} total)`);
27
+ hasMore = response.items.length === perPage && allPersonas.length < response.metadata.total;
28
+ page++;
29
+ }
30
+ if (options.maxPersonas && allPersonas.length > options.maxPersonas) {
31
+ allPersonas.splice(options.maxPersonas);
32
+ if (verbose)
33
+ console.log(`⚠️ Limited to ${options.maxPersonas} personas as requested`);
34
+ }
35
+ if (verbose)
36
+ console.log(`👥 Processing ${allPersonas.length} personas...`);
37
+ // Process personas concurrently with limited concurrency
38
+ const processedPersonas = [];
39
+ await Promise.all(allPersonas.map(persona => concurrencyLimit(async () => {
40
+ try {
41
+ // Extract phone number from actors
42
+ const phoneActor = persona.actors.find(actor => actor.integration_idn === 'newo_voice' &&
43
+ actor.connector_idn === 'newo_voice_connector' &&
44
+ actor.contact_information?.startsWith('+'));
45
+ const phone = phoneActor?.contact_information || null;
46
+ // Get acts for this persona
47
+ const allActs = [];
48
+ let actPage = 1;
49
+ const actsPerPage = 100; // Higher limit for acts
50
+ let hasMoreActs = true;
51
+ // Get user actor IDs from persona actors first
52
+ const userActors = persona.actors.filter(actor => actor.integration_idn === 'newo_voice' &&
53
+ actor.connector_idn === 'newo_voice_connector');
54
+ if (userActors.length === 0) {
55
+ if (verbose)
56
+ console.log(` 👤 ${persona.name}: No voice actors found, skipping`);
57
+ // No voice actors, can't get chat history - add persona with empty acts
58
+ processedPersonas.push({
59
+ id: persona.id,
60
+ name: persona.name,
61
+ phone,
62
+ act_count: persona.act_count,
63
+ acts: []
64
+ });
65
+ if (verbose)
66
+ console.log(` ✓ Processed ${persona.name}: 0 acts (no voice actors)`);
67
+ return; // Return from the concurrency function
68
+ }
69
+ // Safety mechanism to prevent infinite loops
70
+ const maxPages = 50; // Limit to 50 pages (5000 acts max per persona)
71
+ while (hasMoreActs && actPage <= maxPages) {
72
+ try {
73
+ const chatHistoryParams = {
74
+ user_actor_id: userActors[0].id,
75
+ page: actPage,
76
+ per: actsPerPage
77
+ };
78
+ if (verbose)
79
+ console.log(` 📄 ${persona.name}: Fetching page ${actPage}...`);
80
+ const chatResponse = await getChatHistory(client, chatHistoryParams);
81
+ if (chatResponse.items && chatResponse.items.length > 0) {
82
+ // Convert chat history format to acts format - create minimal ConversationAct objects
83
+ const convertedActs = chatResponse.items.map((item) => ({
84
+ id: item.id || `chat_${Math.random()}`,
85
+ command_act_id: null,
86
+ external_event_id: item.external_event_id || 'chat_history',
87
+ arguments: [],
88
+ reference_idn: (item.is_agent === true) ? 'agent_message' : 'user_message',
89
+ runtime_context_id: item.runtime_context_id || 'chat_history',
90
+ source_text: item.payload?.text || item.message || item.content || item.text || '',
91
+ original_text: item.payload?.text || item.message || item.content || item.text || '',
92
+ datetime: item.datetime || item.created_at || item.timestamp || new Date().toISOString(),
93
+ user_actor_id: userActors[0].id,
94
+ agent_actor_id: null,
95
+ user_persona_id: persona.id,
96
+ user_persona_name: persona.name,
97
+ agent_persona_id: item.agent_persona_id || 'unknown',
98
+ external_id: item.external_id || null,
99
+ integration_idn: 'newo_voice',
100
+ connector_idn: 'newo_voice_connector',
101
+ to_integration_idn: null,
102
+ to_connector_idn: null,
103
+ is_agent: Boolean(item.is_agent === true),
104
+ project_idn: null,
105
+ flow_idn: item.flow_idn || 'unknown',
106
+ skill_idn: item.skill_idn || 'unknown',
107
+ session_id: item.session_id || 'unknown',
108
+ recordings: item.recordings || [],
109
+ contact_information: item.contact_information || null
110
+ }));
111
+ allActs.push(...convertedActs);
112
+ if (verbose && convertedActs.length > 0) {
113
+ console.log(` 👤 ${persona.name}: Chat History - ${convertedActs.length} messages (${allActs.length} total)`);
114
+ }
115
+ // Check if we should continue paginating
116
+ const hasMetadata = chatResponse.metadata?.total !== undefined;
117
+ const currentTotal = chatResponse.metadata?.total || 0;
118
+ hasMoreActs = chatResponse.items.length === actsPerPage &&
119
+ hasMetadata &&
120
+ allActs.length < currentTotal;
121
+ actPage++;
122
+ if (verbose)
123
+ console.log(` 📊 ${persona.name}: Page ${actPage - 1} done, ${allActs.length}/${currentTotal} total acts`);
124
+ }
125
+ else {
126
+ // No more items
127
+ hasMoreActs = false;
128
+ if (verbose)
129
+ console.log(` 📊 ${persona.name}: No more chat history items`);
130
+ }
131
+ }
132
+ catch (chatError) {
133
+ if (verbose)
134
+ console.log(` ⚠️ Chat history failed for ${persona.name}: ${chatError instanceof Error ? chatError.message : String(chatError)}`);
135
+ hasMoreActs = false;
136
+ }
137
+ }
138
+ if (actPage > maxPages) {
139
+ if (verbose)
140
+ console.log(` ⚠️ ${persona.name}: Reached max pages limit (${maxPages}), stopping pagination`);
141
+ }
142
+ // Sort acts by datetime ascending (chronological order)
143
+ allActs.sort((a, b) => new Date(a.datetime).getTime() - new Date(b.datetime).getTime());
144
+ // Process acts into simplified format - exclude redundant fields
145
+ const processedActs = allActs.map(act => {
146
+ const processedAct = {
147
+ datetime: act.datetime,
148
+ type: act.reference_idn,
149
+ message: act.source_text
150
+ };
151
+ // Only include non-redundant fields
152
+ if (act.contact_information) {
153
+ processedAct.contact_information = act.contact_information;
154
+ }
155
+ if (act.flow_idn && act.flow_idn !== 'unknown') {
156
+ processedAct.flow_idn = act.flow_idn;
157
+ }
158
+ if (act.skill_idn && act.skill_idn !== 'unknown') {
159
+ processedAct.skill_idn = act.skill_idn;
160
+ }
161
+ if (act.session_id && act.session_id !== 'unknown') {
162
+ processedAct.session_id = act.session_id;
163
+ }
164
+ return processedAct;
165
+ });
166
+ processedPersonas.push({
167
+ id: persona.id,
168
+ name: persona.name,
169
+ phone,
170
+ act_count: persona.act_count,
171
+ acts: processedActs
172
+ });
173
+ if (verbose)
174
+ console.log(` ✓ Processed ${persona.name}: ${processedActs.length} acts`);
175
+ }
176
+ catch (error) {
177
+ console.error(`❌ Failed to process persona ${persona.name}:`, error);
178
+ // Continue with other personas
179
+ }
180
+ })));
181
+ // Sort personas by most recent act time (descending) - use latest act from acts array
182
+ processedPersonas.sort((a, b) => {
183
+ const aLatestTime = a.acts.length > 0 ? a.acts[a.acts.length - 1].datetime : '1970-01-01T00:00:00.000Z';
184
+ const bLatestTime = b.acts.length > 0 ? b.acts[b.acts.length - 1].datetime : '1970-01-01T00:00:00.000Z';
185
+ return new Date(bLatestTime).getTime() - new Date(aLatestTime).getTime();
186
+ });
187
+ // Calculate totals
188
+ const totalActs = processedPersonas.reduce((sum, persona) => sum + persona.acts.length, 0);
189
+ // Create final conversations data
190
+ const conversationsData = {
191
+ personas: processedPersonas,
192
+ total_personas: processedPersonas.length,
193
+ total_acts: totalActs,
194
+ generated_at: new Date().toISOString()
195
+ };
196
+ // Save to YAML file
197
+ const conversationsPath = `newo_customers/${customer.idn}/conversations.yaml`;
198
+ const yamlContent = yaml.dump(conversationsData, {
199
+ indent: 2,
200
+ quotingType: '"',
201
+ forceQuotes: false,
202
+ lineWidth: 120,
203
+ noRefs: true,
204
+ sortKeys: false,
205
+ flowLevel: -1
206
+ });
207
+ await writeFileSafe(conversationsPath, yamlContent);
208
+ if (verbose) {
209
+ console.log(`✓ Saved conversations to ${conversationsPath}`);
210
+ console.log(`📊 Summary: ${processedPersonas.length} personas, ${totalActs} total acts`);
211
+ }
212
+ }
213
+ catch (error) {
214
+ console.error(`❌ Failed to pull conversations for ${customer.idn}:`, error);
215
+ throw error;
216
+ }
217
+ }
218
+ //# sourceMappingURL=conversations.js.map
@@ -0,0 +1,8 @@
1
+ import type { ProjectData, ProjectMap } from '../types.js';
2
+ /**
3
+ * Generate flows.yaml file from project data
4
+ */
5
+ export declare function generateFlowsYaml(projectMap: ProjectMap | {
6
+ [key: string]: ProjectData;
7
+ }, customerIdn: string, verbose?: boolean): Promise<string>;
8
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Metadata and flows.yaml generation operations
3
+ */
4
+ import { writeFileSafe, flowMetadataPath, agentMetadataPath, flowsYamlPath } from '../fsutil.js';
5
+ import fs from 'fs-extra';
6
+ import yaml from 'js-yaml';
7
+ /**
8
+ * Generate flows.yaml file from project data
9
+ */
10
+ export async function generateFlowsYaml(projectMap, customerIdn, verbose = false) {
11
+ if (verbose)
12
+ console.log(`📊 Generating flows.yaml for customer ${customerIdn}...`);
13
+ const flowsData = {
14
+ flows: []
15
+ };
16
+ // Handle both formats
17
+ const projects = 'projects' in projectMap ? projectMap.projects : projectMap;
18
+ for (const [projectIdn, projectData] of Object.entries(projects)) {
19
+ if (verbose && projectIdn)
20
+ console.log(` 📁 Processing project: ${projectIdn}`);
21
+ for (const [agentIdn, agentData] of Object.entries(projectData.agents)) {
22
+ if (verbose)
23
+ console.log(` 📁 Processing agent: ${agentIdn}`);
24
+ const agentFlows = [];
25
+ for (const [flowIdn, flowData] of Object.entries(agentData.flows)) {
26
+ if (verbose)
27
+ console.log(` 📁 Processing flow: ${flowIdn}`);
28
+ // Load flow metadata to get comprehensive flow information
29
+ const flowMetaPath = flowMetadataPath(customerIdn, projectIdn, agentIdn, flowIdn);
30
+ let flowMeta = null;
31
+ try {
32
+ if (await fs.pathExists(flowMetaPath)) {
33
+ const flowMetaContent = await fs.readFile(flowMetaPath, 'utf8');
34
+ flowMeta = yaml.load(flowMetaContent);
35
+ }
36
+ }
37
+ catch (e) {
38
+ if (verbose)
39
+ console.log(` ⚠️ Could not load flow metadata: ${flowMetaPath}`);
40
+ }
41
+ const skills = [];
42
+ for (const [, skillMeta] of Object.entries(flowData.skills)) {
43
+ // Note: We don't need to load script content since prompt_script is excluded from flows.yaml
44
+ skills.push({
45
+ idn: skillMeta.idn,
46
+ title: skillMeta.title,
47
+ runner_type: skillMeta.runner_type,
48
+ model: skillMeta.model,
49
+ parameters: skillMeta.parameters.map((p) => ({
50
+ name: p.name,
51
+ default_value: p.default_value || ''
52
+ }))
53
+ });
54
+ }
55
+ // Use flow metadata if available, otherwise use basic info
56
+ const flowYaml = {
57
+ idn: flowIdn,
58
+ title: flowMeta?.title || 'Unknown Flow',
59
+ description: flowMeta?.description || null,
60
+ default_runner_type: flowMeta?.default_runner_type || 'guidance',
61
+ default_provider_idn: flowMeta?.default_model?.provider_idn || 'openai',
62
+ default_model_idn: flowMeta?.default_model?.model_idn || 'gpt-4',
63
+ skills,
64
+ events: flowMeta?.events?.map(event => ({
65
+ title: event.description,
66
+ idn: event.idn,
67
+ skill_selector: event.skill_selector,
68
+ skill_idn: event.skill_idn || null,
69
+ state_idn: event.state_idn || null,
70
+ integration_idn: event.integration_idn || null,
71
+ connector_idn: event.connector_idn || null,
72
+ interrupt_mode: event.interrupt_mode
73
+ })) || [],
74
+ state_fields: flowMeta?.state_fields?.map(state => ({
75
+ title: state.title,
76
+ idn: state.idn,
77
+ default_value: state.default_value || null,
78
+ scope: state.scope
79
+ })) || []
80
+ };
81
+ agentFlows.push(flowYaml);
82
+ }
83
+ if (agentFlows.length > 0) {
84
+ // Load agent metadata for description
85
+ const agentMetaPath = agentMetadataPath(customerIdn, projectIdn, agentIdn);
86
+ let agentDescription = null;
87
+ try {
88
+ if (await fs.pathExists(agentMetaPath)) {
89
+ const agentMetaContent = await fs.readFile(agentMetaPath, 'utf8');
90
+ const agentMeta = yaml.load(agentMetaContent);
91
+ agentDescription = agentMeta.description || null;
92
+ }
93
+ }
94
+ catch (e) {
95
+ if (verbose)
96
+ console.log(` ⚠️ Could not load agent metadata: ${agentMetaPath}`);
97
+ }
98
+ flowsData.flows.push({
99
+ agent_idn: agentIdn,
100
+ agent_description: agentDescription,
101
+ agent_flows: agentFlows
102
+ });
103
+ }
104
+ }
105
+ }
106
+ // Generate flows.yaml content
107
+ const flowsYamlContent = yaml.dump(flowsData, {
108
+ indent: 2,
109
+ quotingType: '"',
110
+ forceQuotes: false,
111
+ lineWidth: 120,
112
+ noRefs: true,
113
+ sortKeys: false,
114
+ flowLevel: -1
115
+ });
116
+ // Save flows.yaml
117
+ const flowsFilePath = flowsYamlPath(customerIdn);
118
+ await writeFileSafe(flowsFilePath, flowsYamlContent);
119
+ if (verbose)
120
+ console.log(`✓ Generated flows.yaml with ${flowsData.flows.length} agents`);
121
+ // Return content for hash calculation
122
+ return flowsYamlContent;
123
+ }
124
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1,13 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { ProjectMap, LegacyProjectMap, CustomerConfig } from '../types.js';
3
+ export declare function isProjectMap(x: unknown): x is ProjectMap;
4
+ export declare function isLegacyProjectMap(x: unknown): x is LegacyProjectMap;
5
+ /**
6
+ * Pull a single project and all its data
7
+ */
8
+ export declare function pullSingleProject(client: AxiosInstance, customer: CustomerConfig, projectId: string | null, verbose?: boolean, silentOverwrite?: boolean): Promise<void>;
9
+ /**
10
+ * Pull all projects for a customer
11
+ */
12
+ export declare function pullAll(client: AxiosInstance, customer: CustomerConfig, projectId?: string | null, verbose?: boolean, silentOverwrite?: boolean): Promise<void>;
13
+ //# sourceMappingURL=projects.d.ts.map