newo 1.4.0 → 1.5.1

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/dist/sync.js ADDED
@@ -0,0 +1,376 @@
1
+ import { listProjects, listAgents, listFlowSkills, updateSkill, listFlowEvents, listFlowStates, getProjectMeta } from './api.js';
2
+ import { ensureState, skillPath, writeFileSafe, readIfExists, mapPath, metadataPath, flowsYamlPath } from './fsutil.js';
3
+ import fs from 'fs-extra';
4
+ import { sha256, loadHashes, saveHashes } from './hash.js';
5
+ import yaml from 'js-yaml';
6
+ import pLimit from 'p-limit';
7
+ // Concurrency limits for API operations
8
+ const concurrencyLimit = pLimit(5);
9
+ // Type guards for better type safety
10
+ function isProjectMap(x) {
11
+ return !!x && typeof x === 'object' && 'projects' in x;
12
+ }
13
+ function isLegacyProjectMap(x) {
14
+ return !!x && typeof x === 'object' && 'agents' in x;
15
+ }
16
+ export async function pullSingleProject(client, customer, projectId, projectIdn, verbose = false) {
17
+ if (verbose)
18
+ console.log(`🔍 Fetching agents for project ${projectId} (${projectIdn}) for customer ${customer.idn}...`);
19
+ const agents = await listAgents(client, projectId);
20
+ if (verbose)
21
+ console.log(`📦 Found ${agents.length} agents`);
22
+ // Get and save project metadata
23
+ const projectMeta = await getProjectMeta(client, projectId);
24
+ await writeFileSafe(metadataPath(customer.idn, projectIdn), JSON.stringify(projectMeta, null, 2));
25
+ if (verbose)
26
+ console.log(`✓ Saved metadata for ${projectIdn}`);
27
+ const projectMap = { projectId, projectIdn, agents: {} };
28
+ for (const agent of agents) {
29
+ const aKey = agent.idn;
30
+ projectMap.agents[aKey] = { id: agent.id, flows: {} };
31
+ for (const flow of agent.flows ?? []) {
32
+ projectMap.agents[aKey].flows[flow.idn] = { id: flow.id, skills: {} };
33
+ const skills = await listFlowSkills(client, flow.id);
34
+ // Process skills concurrently with limited concurrency
35
+ await Promise.all(skills.map(skill => concurrencyLimit(async () => {
36
+ const file = skillPath(customer.idn, projectIdn, agent.idn, flow.idn, skill.idn, skill.runner_type);
37
+ await writeFileSafe(file, skill.prompt_script || '');
38
+ // Store complete skill metadata for push operations
39
+ projectMap.agents[aKey].flows[flow.idn].skills[skill.idn] = {
40
+ id: skill.id,
41
+ title: skill.title,
42
+ idn: skill.idn,
43
+ runner_type: skill.runner_type,
44
+ model: skill.model,
45
+ parameters: [...skill.parameters],
46
+ path: skill.path || undefined
47
+ };
48
+ console.log(`✓ Pulled ${file}`);
49
+ })));
50
+ }
51
+ }
52
+ // Generate flows.yaml for this project
53
+ if (verbose)
54
+ console.log(`📄 Generating flows.yaml...`);
55
+ await generateFlowsYaml(client, customer, agents, verbose);
56
+ return projectMap;
57
+ }
58
+ export async function pullAll(client, customer, projectId = null, verbose = false) {
59
+ await ensureState(customer.idn);
60
+ if (projectId) {
61
+ // Single project mode
62
+ const projectMeta = await getProjectMeta(client, projectId);
63
+ const projectMap = await pullSingleProject(client, customer, projectId, projectMeta.idn, verbose);
64
+ const idMap = { projects: { [projectMeta.idn]: projectMap } };
65
+ await fs.writeJson(mapPath(customer.idn), idMap, { spaces: 2 });
66
+ // Generate hash tracking for this project
67
+ const hashes = {};
68
+ for (const [agentIdn, agentObj] of Object.entries(projectMap.agents)) {
69
+ for (const [flowIdn, flowObj] of Object.entries(agentObj.flows)) {
70
+ for (const [skillIdn, skillMeta] of Object.entries(flowObj.skills)) {
71
+ const p = skillPath(customer.idn, projectMeta.idn, agentIdn, flowIdn, skillIdn, skillMeta.runner_type);
72
+ const content = await fs.readFile(p, 'utf8');
73
+ hashes[p] = sha256(content);
74
+ }
75
+ }
76
+ }
77
+ await saveHashes(hashes, customer.idn);
78
+ return;
79
+ }
80
+ // Multi-project mode
81
+ if (verbose)
82
+ console.log(`🔍 Fetching all projects for customer ${customer.idn}...`);
83
+ const projects = await listProjects(client);
84
+ if (verbose)
85
+ console.log(`📦 Found ${projects.length} projects`);
86
+ const idMap = { projects: {} };
87
+ const allHashes = {};
88
+ for (const project of projects) {
89
+ if (verbose)
90
+ console.log(`\n📁 Processing project: ${project.idn} (${project.title})`);
91
+ const projectMap = await pullSingleProject(client, customer, project.id, project.idn, verbose);
92
+ idMap.projects[project.idn] = projectMap;
93
+ // Collect hashes for this project
94
+ for (const [agentIdn, agentObj] of Object.entries(projectMap.agents)) {
95
+ for (const [flowIdn, flowObj] of Object.entries(agentObj.flows)) {
96
+ for (const [skillIdn, skillMeta] of Object.entries(flowObj.skills)) {
97
+ const p = skillPath(customer.idn, project.idn, agentIdn, flowIdn, skillIdn, skillMeta.runner_type);
98
+ const content = await fs.readFile(p, 'utf8');
99
+ allHashes[p] = sha256(content);
100
+ }
101
+ }
102
+ }
103
+ }
104
+ await fs.writeJson(mapPath(customer.idn), idMap, { spaces: 2 });
105
+ await saveHashes(allHashes, customer.idn);
106
+ }
107
+ export async function pushChanged(client, customer, verbose = false) {
108
+ await ensureState(customer.idn);
109
+ if (!(await fs.pathExists(mapPath(customer.idn)))) {
110
+ throw new Error(`Missing .newo/${customer.idn}/map.json. Run \`newo pull --customer ${customer.idn}\` first.`);
111
+ }
112
+ if (verbose)
113
+ console.log(`📋 Loading project mapping for customer ${customer.idn}...`);
114
+ const idMapData = await fs.readJson(mapPath(customer.idn));
115
+ if (verbose)
116
+ console.log('🔍 Loading file hashes...');
117
+ const oldHashes = await loadHashes(customer.idn);
118
+ const newHashes = { ...oldHashes };
119
+ if (verbose)
120
+ console.log('🔄 Scanning for changes...');
121
+ let pushed = 0;
122
+ let scanned = 0;
123
+ // Handle both old single-project format and new multi-project format with type guards
124
+ const projects = isProjectMap(idMapData) && idMapData.projects
125
+ ? idMapData.projects
126
+ : isLegacyProjectMap(idMapData)
127
+ ? { '': idMapData }
128
+ : (() => { throw new Error('Invalid project map format'); })();
129
+ for (const [projectIdn, projectData] of Object.entries(projects)) {
130
+ if (verbose && projectIdn)
131
+ console.log(`📁 Scanning project: ${projectIdn}`);
132
+ for (const [agentIdn, agentObj] of Object.entries(projectData.agents)) {
133
+ if (verbose)
134
+ console.log(` 📁 Scanning agent: ${agentIdn}`);
135
+ for (const [flowIdn, flowObj] of Object.entries(agentObj.flows)) {
136
+ if (verbose)
137
+ console.log(` 📁 Scanning flow: ${flowIdn}`);
138
+ for (const [skillIdn, skillMeta] of Object.entries(flowObj.skills)) {
139
+ const p = projectIdn ?
140
+ skillPath(customer.idn, projectIdn, agentIdn, flowIdn, skillIdn, skillMeta.runner_type) :
141
+ skillPath(customer.idn, '', agentIdn, flowIdn, skillIdn, skillMeta.runner_type);
142
+ scanned++;
143
+ if (verbose)
144
+ console.log(` 📄 Checking: ${p}`);
145
+ const content = await readIfExists(p);
146
+ if (content === null) {
147
+ if (verbose)
148
+ console.log(` ⚠️ File not found: ${p}`);
149
+ continue;
150
+ }
151
+ const h = sha256(content);
152
+ const oldHash = oldHashes[p];
153
+ if (verbose) {
154
+ console.log(` 🔍 Hash comparison:`);
155
+ console.log(` Old: ${oldHash || 'none'}`);
156
+ console.log(` New: ${h}`);
157
+ }
158
+ if (oldHash !== h) {
159
+ if (verbose)
160
+ console.log(` 🔄 File changed, preparing to push...`);
161
+ // Create complete skill object with updated prompt_script
162
+ const skillObject = {
163
+ id: skillMeta.id,
164
+ title: skillMeta.title,
165
+ idn: skillMeta.idn,
166
+ prompt_script: content,
167
+ runner_type: skillMeta.runner_type,
168
+ model: skillMeta.model,
169
+ parameters: skillMeta.parameters,
170
+ path: skillMeta.path || undefined
171
+ };
172
+ if (verbose) {
173
+ console.log(` 📤 Pushing skill object:`);
174
+ console.log(` ID: ${skillObject.id}`);
175
+ console.log(` Title: ${skillObject.title}`);
176
+ console.log(` IDN: ${skillObject.idn}`);
177
+ console.log(` Content length: ${content.length} chars`);
178
+ console.log(` Content preview: ${content.substring(0, 100).replace(/\n/g, '\\n')}...`);
179
+ }
180
+ await updateSkill(client, skillObject);
181
+ console.log(`↑ Pushed ${p}`);
182
+ newHashes[p] = h;
183
+ pushed++;
184
+ }
185
+ else if (verbose) {
186
+ console.log(` ✓ No changes`);
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+ if (verbose)
193
+ console.log(`🔄 Scanned ${scanned} files, found ${pushed} changes`);
194
+ await saveHashes(newHashes, customer.idn);
195
+ console.log(pushed ? `✅ Push complete. ${pushed} file(s) updated.` : '✅ Nothing to push.');
196
+ }
197
+ export async function status(customer, verbose = false) {
198
+ await ensureState(customer.idn);
199
+ if (!(await fs.pathExists(mapPath(customer.idn)))) {
200
+ console.log(`No map for customer ${customer.idn}. Run \`newo pull --customer ${customer.idn}\` first.`);
201
+ return;
202
+ }
203
+ if (verbose)
204
+ console.log(`📋 Loading project mapping and hashes for customer ${customer.idn}...`);
205
+ const idMapData = await fs.readJson(mapPath(customer.idn));
206
+ const hashes = await loadHashes(customer.idn);
207
+ let dirty = 0;
208
+ // Handle both old single-project format and new multi-project format with type guards
209
+ const projects = isProjectMap(idMapData) && idMapData.projects
210
+ ? idMapData.projects
211
+ : isLegacyProjectMap(idMapData)
212
+ ? { '': idMapData }
213
+ : (() => { throw new Error('Invalid project map format'); })();
214
+ for (const [projectIdn, projectData] of Object.entries(projects)) {
215
+ if (verbose && projectIdn)
216
+ console.log(`📁 Checking project: ${projectIdn}`);
217
+ for (const [agentIdn, agentObj] of Object.entries(projectData.agents)) {
218
+ if (verbose)
219
+ console.log(` 📁 Checking agent: ${agentIdn}`);
220
+ for (const [flowIdn, flowObj] of Object.entries(agentObj.flows)) {
221
+ if (verbose)
222
+ console.log(` 📁 Checking flow: ${flowIdn}`);
223
+ for (const [skillIdn, skillMeta] of Object.entries(flowObj.skills)) {
224
+ const p = projectIdn ?
225
+ skillPath(customer.idn, projectIdn, agentIdn, flowIdn, skillIdn, skillMeta.runner_type) :
226
+ skillPath(customer.idn, '', agentIdn, flowIdn, skillIdn, skillMeta.runner_type);
227
+ const exists = await fs.pathExists(p);
228
+ if (!exists) {
229
+ console.log(`D ${p}`);
230
+ dirty++;
231
+ if (verbose)
232
+ console.log(` ❌ Deleted: ${p}`);
233
+ continue;
234
+ }
235
+ const content = await fs.readFile(p, 'utf8');
236
+ const h = sha256(content);
237
+ const oldHash = hashes[p];
238
+ if (verbose) {
239
+ console.log(` 📄 ${p}`);
240
+ console.log(` Old hash: ${oldHash || 'none'}`);
241
+ console.log(` New hash: ${h}`);
242
+ }
243
+ if (oldHash !== h) {
244
+ console.log(`M ${p}`);
245
+ dirty++;
246
+ if (verbose)
247
+ console.log(` 🔄 Modified: ${p}`);
248
+ }
249
+ else if (verbose) {
250
+ console.log(` ✓ Unchanged: ${p}`);
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ console.log(dirty ? `${dirty} changed file(s).` : 'Clean.');
257
+ }
258
+ async function generateFlowsYaml(client, customer, agents, verbose = false) {
259
+ const flowsData = { flows: [] };
260
+ // Calculate total flows for progress tracking
261
+ const totalFlows = agents.reduce((sum, agent) => sum + (agent.flows?.length || 0), 0);
262
+ let processedFlows = 0;
263
+ if (!verbose && totalFlows > 0) {
264
+ console.log(`📄 Generating flows.yaml (${totalFlows} flows)...`);
265
+ }
266
+ for (const agent of agents) {
267
+ if (verbose)
268
+ console.log(` 📁 Processing agent: ${agent.idn}`);
269
+ const agentFlows = [];
270
+ for (const flow of agent.flows ?? []) {
271
+ processedFlows++;
272
+ if (verbose) {
273
+ console.log(` 📄 Processing flow: ${flow.idn}`);
274
+ }
275
+ else {
276
+ // Simple progress indicator without verbose mode
277
+ const percent = Math.round((processedFlows / totalFlows) * 100);
278
+ const progressBar = '█'.repeat(Math.floor(percent / 5)) + '░'.repeat(20 - Math.floor(percent / 5));
279
+ const progressText = ` [${progressBar}] ${percent}% (${processedFlows}/${totalFlows}) ${flow.idn}`;
280
+ // Pad the line to clear any leftover text from longer previous lines
281
+ const padding = ' '.repeat(Math.max(0, 80 - progressText.length));
282
+ process.stdout.write(`\r${progressText}${padding}`);
283
+ }
284
+ // Get skills for this flow
285
+ const skills = await listFlowSkills(client, flow.id);
286
+ const skillsData = skills.map(skill => ({
287
+ idn: skill.idn,
288
+ title: skill.title || "",
289
+ prompt_script: `flows/${flow.idn}/${skill.idn}.${skill.runner_type === 'nsl' ? 'jinja' : 'guidance'}`,
290
+ runner_type: `!enum "RunnerType.${skill.runner_type}"`,
291
+ model: {
292
+ model_idn: skill.model.model_idn,
293
+ provider_idn: skill.model.provider_idn
294
+ },
295
+ parameters: skill.parameters.map(param => ({
296
+ name: param.name,
297
+ default_value: param.default_value || " "
298
+ }))
299
+ }));
300
+ // Get events for this flow
301
+ let eventsData = [];
302
+ try {
303
+ const events = await listFlowEvents(client, flow.id);
304
+ eventsData = events.map(event => ({
305
+ title: event.description,
306
+ idn: event.idn,
307
+ skill_selector: `!enum "SkillSelector.${event.skill_selector}"`,
308
+ skill_idn: event.skill_idn || undefined,
309
+ state_idn: event.state_idn || undefined,
310
+ integration_idn: event.integration_idn || undefined,
311
+ connector_idn: event.connector_idn || undefined,
312
+ interrupt_mode: `!enum "InterruptMode.${event.interrupt_mode}"`
313
+ }));
314
+ if (verbose)
315
+ console.log(` 📋 Found ${events.length} events`);
316
+ }
317
+ catch (error) {
318
+ if (verbose)
319
+ console.log(` ⚠️ No events found for flow ${flow.idn}`);
320
+ }
321
+ // Get state fields for this flow
322
+ let stateFieldsData = [];
323
+ try {
324
+ const states = await listFlowStates(client, flow.id);
325
+ stateFieldsData = states.map(state => ({
326
+ title: state.title,
327
+ idn: state.idn,
328
+ default_value: state.default_value || undefined,
329
+ scope: `!enum "StateFieldScope.${state.scope}"`
330
+ }));
331
+ if (verbose)
332
+ console.log(` 📊 Found ${states.length} state fields`);
333
+ }
334
+ catch (error) {
335
+ if (verbose)
336
+ console.log(` ⚠️ No state fields found for flow ${flow.idn}`);
337
+ }
338
+ agentFlows.push({
339
+ idn: flow.idn,
340
+ title: flow.title,
341
+ description: flow.description || null,
342
+ default_runner_type: `!enum "RunnerType.${flow.default_runner_type}"`,
343
+ default_provider_idn: flow.default_model.provider_idn,
344
+ default_model_idn: flow.default_model.model_idn,
345
+ skills: skillsData,
346
+ events: eventsData,
347
+ state_fields: stateFieldsData
348
+ });
349
+ }
350
+ const agentData = {
351
+ agent_idn: agent.idn,
352
+ agent_description: agent.description || undefined,
353
+ agent_flows: agentFlows
354
+ };
355
+ flowsData.flows.push(agentData);
356
+ }
357
+ // Clear progress bar and move to new line
358
+ if (!verbose && totalFlows > 0) {
359
+ process.stdout.write('\n');
360
+ }
361
+ // Convert to YAML and write to file with custom enum handling
362
+ let yamlContent = yaml.dump(flowsData, {
363
+ indent: 2,
364
+ lineWidth: -1,
365
+ noRefs: true,
366
+ sortKeys: false,
367
+ quotingType: '"',
368
+ forceQuotes: false
369
+ });
370
+ // Post-process to fix enum formatting
371
+ yamlContent = yamlContent.replace(/"(!enum "[^"]+")"/g, '$1');
372
+ const yamlPath = flowsYamlPath(customer.idn);
373
+ await writeFileSafe(yamlPath, yamlContent);
374
+ console.log(`✓ Generated flows.yaml`);
375
+ }
376
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Comprehensive type definitions for NEWO CLI
3
+ */
4
+ export interface NewoEnvironment {
5
+ NEWO_BASE_URL?: string;
6
+ NEWO_PROJECT_ID?: string;
7
+ NEWO_API_KEY?: string;
8
+ NEWO_API_KEYS?: string;
9
+ NEWO_ACCESS_TOKEN?: string;
10
+ NEWO_REFRESH_TOKEN?: string;
11
+ NEWO_REFRESH_URL?: string;
12
+ NEWO_DEFAULT_CUSTOMER?: string;
13
+ [key: string]: string | undefined;
14
+ }
15
+ export interface ApiKeyConfig {
16
+ key: string;
17
+ project_id?: string;
18
+ }
19
+ export interface CustomerConfig {
20
+ idn: string;
21
+ apiKey: string;
22
+ projectId?: string | undefined;
23
+ }
24
+ export interface CustomerProfile {
25
+ id: string;
26
+ idn: string;
27
+ organization_name: string;
28
+ email: string;
29
+ [key: string]: any;
30
+ }
31
+ export interface MultiCustomerConfig {
32
+ customers: Record<string, CustomerConfig>;
33
+ defaultCustomer?: string | undefined;
34
+ }
35
+ export interface TokenResponse {
36
+ access_token?: string;
37
+ token?: string;
38
+ accessToken?: string;
39
+ refresh_token?: string;
40
+ refreshToken?: string;
41
+ expires_in?: number;
42
+ expiresIn?: number;
43
+ }
44
+ export interface StoredTokens {
45
+ access_token: string;
46
+ refresh_token: string;
47
+ expires_at: number;
48
+ }
49
+ export interface ProjectMeta {
50
+ readonly id: string;
51
+ readonly idn: string;
52
+ readonly title: string;
53
+ readonly description?: string;
54
+ readonly created_at?: string;
55
+ readonly updated_at?: string;
56
+ }
57
+ export interface Agent {
58
+ readonly id: string;
59
+ readonly idn: string;
60
+ readonly title?: string;
61
+ readonly description?: string;
62
+ readonly flows?: readonly Flow[];
63
+ }
64
+ export interface Flow {
65
+ readonly id: string;
66
+ readonly idn: string;
67
+ readonly title: string;
68
+ readonly description?: string;
69
+ readonly default_runner_type: RunnerType;
70
+ readonly default_model: ModelConfig;
71
+ }
72
+ export interface ModelConfig {
73
+ readonly model_idn: string;
74
+ readonly provider_idn: string;
75
+ }
76
+ export interface SkillParameter {
77
+ readonly name: string;
78
+ readonly default_value?: string;
79
+ }
80
+ export interface Skill {
81
+ readonly id: string;
82
+ readonly idn: string;
83
+ readonly title: string;
84
+ prompt_script?: string;
85
+ readonly runner_type: RunnerType;
86
+ readonly model: ModelConfig;
87
+ readonly parameters: readonly SkillParameter[];
88
+ readonly path?: string | undefined;
89
+ }
90
+ export interface FlowEvent {
91
+ readonly id: string;
92
+ readonly idn: string;
93
+ readonly description: string;
94
+ readonly skill_selector: SkillSelector;
95
+ readonly skill_idn?: string;
96
+ readonly state_idn?: string;
97
+ readonly integration_idn?: string;
98
+ readonly connector_idn?: string;
99
+ readonly interrupt_mode: InterruptMode;
100
+ }
101
+ export interface FlowState {
102
+ readonly id: string;
103
+ readonly idn: string;
104
+ readonly title: string;
105
+ readonly default_value?: string;
106
+ readonly scope: StateFieldScope;
107
+ }
108
+ export type RunnerType = 'guidance' | 'nsl';
109
+ export type SkillSelector = 'first' | 'last' | 'random' | 'all';
110
+ export type InterruptMode = 'allow' | 'deny' | 'queue';
111
+ export type StateFieldScope = 'flow' | 'agent' | 'project' | 'global';
112
+ export interface SkillMetadata {
113
+ id: string;
114
+ title: string;
115
+ idn: string;
116
+ runner_type: RunnerType;
117
+ model: ModelConfig;
118
+ parameters: SkillParameter[];
119
+ path?: string | undefined;
120
+ }
121
+ export interface FlowData {
122
+ id: string;
123
+ skills: Record<string, SkillMetadata>;
124
+ }
125
+ export interface AgentData {
126
+ id: string;
127
+ flows: Record<string, FlowData>;
128
+ }
129
+ export interface ProjectData {
130
+ projectId: string;
131
+ projectIdn: string;
132
+ agents: Record<string, AgentData>;
133
+ }
134
+ export interface ProjectMap {
135
+ projects: Record<string, ProjectData>;
136
+ }
137
+ export interface LegacyProjectMap extends ProjectData {
138
+ projects?: Record<string, ProjectData>;
139
+ }
140
+ export interface HashStore {
141
+ [filePath: string]: string;
142
+ }
143
+ export interface ParsedArticle {
144
+ readonly topic_name: string;
145
+ readonly persona_id: string | null;
146
+ readonly topic_summary: string;
147
+ readonly topic_facts: readonly string[];
148
+ readonly confidence: number;
149
+ readonly source: string;
150
+ readonly labels: readonly string[];
151
+ }
152
+ export interface AkbImportArticle extends Omit<ParsedArticle, 'persona_id'> {
153
+ persona_id: string;
154
+ }
155
+ export interface CliArgs {
156
+ readonly _: readonly string[];
157
+ readonly verbose?: boolean;
158
+ readonly v?: boolean;
159
+ readonly [key: string]: unknown;
160
+ }
161
+ export interface FlowsYamlSkill {
162
+ idn: string;
163
+ title: string;
164
+ prompt_script: string;
165
+ runner_type: string;
166
+ model: ModelConfig;
167
+ parameters: Array<{
168
+ name: string;
169
+ default_value: string;
170
+ }>;
171
+ }
172
+ export interface FlowsYamlEvent {
173
+ title: string;
174
+ idn: string;
175
+ skill_selector: string;
176
+ skill_idn?: string | undefined;
177
+ state_idn?: string | undefined;
178
+ integration_idn?: string | undefined;
179
+ connector_idn?: string | undefined;
180
+ interrupt_mode: string;
181
+ }
182
+ export interface FlowsYamlState {
183
+ title: string;
184
+ idn: string;
185
+ default_value?: string | undefined;
186
+ scope: string;
187
+ }
188
+ export interface FlowsYamlFlow {
189
+ idn: string;
190
+ title: string;
191
+ description: string | null;
192
+ default_runner_type: string;
193
+ default_provider_idn: string;
194
+ default_model_idn: string;
195
+ skills: FlowsYamlSkill[];
196
+ events: FlowsYamlEvent[];
197
+ state_fields: FlowsYamlState[];
198
+ }
199
+ export interface FlowsYamlAgent {
200
+ agent_idn: string;
201
+ agent_description?: string | undefined;
202
+ agent_flows: FlowsYamlFlow[];
203
+ }
204
+ export interface FlowsYamlData {
205
+ flows: FlowsYamlAgent[];
206
+ }
207
+ export interface AxiosClientConfig {
208
+ baseURL?: string;
209
+ headers?: Record<string, string>;
210
+ }
211
+ export interface NewoApiError extends Error {
212
+ response?: {
213
+ status: number;
214
+ data: unknown;
215
+ };
216
+ config?: {
217
+ method?: string;
218
+ url?: string;
219
+ headers?: Record<string, string>;
220
+ };
221
+ }
222
+ export type FileStatus = 'M' | 'D' | 'clean';
223
+ export interface StatusResult {
224
+ filePath: string;
225
+ status: FileStatus;
226
+ oldHash?: string;
227
+ newHash?: string;
228
+ }
229
+ //# sourceMappingURL=types.d.ts.map
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Comprehensive type definitions for NEWO CLI
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "newo",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "NEWO CLI: sync flows/skills between NEWO and local files, multi-project support, import AKB articles",
5
- "type": "module",
6
5
  "bin": {
7
- "newo": "src/cli.js"
6
+ "newo": "dist/cli.js"
8
7
  },
9
8
  "files": [
10
- "src/**/*.js",
9
+ "dist/**/*.js",
10
+ "dist/**/*.d.ts",
11
+ "src/**/*.ts",
11
12
  "README.md",
12
13
  "CHANGELOG.md",
13
14
  ".env.example"
@@ -44,19 +45,39 @@
44
45
  "dotenv": "^16.4.5",
45
46
  "fs-extra": "^11.2.0",
46
47
  "js-yaml": "^4.1.0",
47
- "minimist": "^1.2.8"
48
+ "minimist": "^1.2.8",
49
+ "p-limit": "^5.0.0"
48
50
  },
49
51
  "devDependencies": {
50
- "mocha": "^10.2.0"
52
+ "@types/chai": "^4.3.11",
53
+ "@types/fs-extra": "^11.0.4",
54
+ "@types/js-yaml": "^4.0.9",
55
+ "@types/minimist": "^1.2.5",
56
+ "@types/node": "^22.5.4",
57
+ "@types/sinon": "^17.0.3",
58
+ "c8": "^9.1.0",
59
+ "chai": "^5.0.2",
60
+ "mocha": "^10.2.0",
61
+ "sinon": "^18.0.1",
62
+ "tsx": "^4.20.5",
63
+ "typescript": "^5.6.2"
51
64
  },
52
65
  "scripts": {
53
- "dev": "node ./src/cli.js",
54
- "pull": "node ./src/cli.js pull",
55
- "push": "node ./src/cli.js push",
56
- "status": "node ./src/cli.js status",
57
- "test": "mocha test/*.test.js --timeout 60000",
58
- "test:api": "mocha test/api.test.js --timeout 30000",
59
- "test:sync": "mocha test/sync.test.js --timeout 60000",
60
- "test:integration": "mocha test/integration.test.js --timeout 120000"
66
+ "build": "tsc",
67
+ "build:watch": "tsc --watch",
68
+ "dev": "npm run build && node ./dist/cli.js",
69
+ "dev:watch": "tsc --watch & nodemon --watch dist dist/cli.js",
70
+ "pull": "npm run build && node ./dist/cli.js pull",
71
+ "push": "npm run build && node ./dist/cli.js push",
72
+ "status": "npm run build && node ./dist/cli.js status",
73
+ "clean": "rm -rf dist coverage",
74
+ "typecheck": "tsc --noEmit",
75
+ "lint": "tsc --noEmit --strict",
76
+ "test": "npm run build && node --test test/*.test.js",
77
+ "test:unit": "npm run build && node --test test/{api,sync,auth,hash,fsutil,akb}.test.js",
78
+ "test:integration": "npm run build && node --test test/integration.test.js",
79
+ "test:coverage": "npm run build && c8 --reporter=html --reporter=text node --test test/*.test.js",
80
+ "test:mocha": "npm run build && c8 mocha test/*.test.js --timeout 60000",
81
+ "prepublishOnly": "npm run clean && npm run build"
61
82
  }
62
83
  }