newo 2.0.0 ā 2.0.2
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/projects.js +27 -12
- package/dist/sync/skill-files.d.ts +3 -2
- package/dist/sync/skill-files.js +34 -10
- package/package.json +1 -1
- package/src/sync/projects.ts +27 -13
- package/src/sync/skill-files.ts +41 -10
package/dist/sync/projects.js
CHANGED
|
@@ -48,9 +48,10 @@ export async function pullSingleProject(client, customer, projectId, verbose = f
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
const newHashes = {};
|
|
51
|
-
// Progress tracking
|
|
51
|
+
// Progress tracking and overwrite control
|
|
52
52
|
let totalSkills = 0;
|
|
53
53
|
let processedSkills = 0;
|
|
54
|
+
let globalOverwriteAll = silentOverwrite;
|
|
54
55
|
// Count total skills for progress tracking
|
|
55
56
|
for (const project of projects) {
|
|
56
57
|
const agents = await listAgents(client, project.id);
|
|
@@ -182,7 +183,7 @@ export async function pullSingleProject(client, customer, projectId, verbose = f
|
|
|
182
183
|
// Check if any existing file has the same content
|
|
183
184
|
hasContentMatch = existingFiles.some(file => !isContentDifferent(file.content, scriptContent));
|
|
184
185
|
if (hasContentMatch) {
|
|
185
|
-
// Content is the same -
|
|
186
|
+
// Content is the same - handle file naming
|
|
186
187
|
const matchingFile = existingFiles.find(file => !isContentDifferent(file.content, scriptContent));
|
|
187
188
|
const correctName = `${skill.idn}.${getExtensionForRunner(skill.runner_type)}`;
|
|
188
189
|
if (matchingFile && matchingFile.fileName !== correctName) {
|
|
@@ -192,30 +193,44 @@ export async function pullSingleProject(client, customer, projectId, verbose = f
|
|
|
192
193
|
console.log(` š Renamed ${matchingFile.fileName} ā ${correctName}`);
|
|
193
194
|
}
|
|
194
195
|
else if (matchingFile && matchingFile.fileName === correctName) {
|
|
195
|
-
// Already has correct name and content
|
|
196
|
+
// Already has correct name and content - skip completely
|
|
196
197
|
shouldWrite = false;
|
|
197
198
|
newHashes[matchingFile.filePath] = sha256(scriptContent);
|
|
198
199
|
if (verbose)
|
|
199
200
|
console.log(` ā Content unchanged for ${skill.idn}, keeping existing file`);
|
|
200
201
|
}
|
|
201
202
|
}
|
|
202
|
-
else if (!
|
|
203
|
-
// Content is different, ask for overwrite
|
|
203
|
+
else if (!globalOverwriteAll) {
|
|
204
|
+
// Content is different, ask for overwrite unless global override is set
|
|
204
205
|
const existingFile = existingFiles[0];
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
console.log(` ā ļø Skipped overwrite for ${skill.idn}`);
|
|
206
|
+
const overwriteChoice = await askForOverwrite(skill.idn, existingFile.content, scriptContent, existingFile.fileName);
|
|
207
|
+
if (overwriteChoice === 'quit') {
|
|
208
|
+
console.log('ā Pull operation cancelled by user');
|
|
209
|
+
process.exit(0);
|
|
210
210
|
}
|
|
211
|
-
else {
|
|
212
|
-
|
|
211
|
+
else if (overwriteChoice === 'all') {
|
|
212
|
+
globalOverwriteAll = true;
|
|
213
|
+
// Continue with overwrite
|
|
213
214
|
for (const file of existingFiles) {
|
|
214
215
|
await fs.remove(file.filePath);
|
|
215
216
|
if (verbose)
|
|
216
217
|
console.log(` šļø Removed ${file.fileName}`);
|
|
217
218
|
}
|
|
218
219
|
}
|
|
220
|
+
else if (overwriteChoice === 'yes') {
|
|
221
|
+
// Single overwrite
|
|
222
|
+
for (const file of existingFiles) {
|
|
223
|
+
await fs.remove(file.filePath);
|
|
224
|
+
if (verbose)
|
|
225
|
+
console.log(` šļø Removed ${file.fileName}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// User said no
|
|
230
|
+
shouldWrite = false;
|
|
231
|
+
if (verbose)
|
|
232
|
+
console.log(` ā ļø Skipped overwrite for ${skill.idn}`);
|
|
233
|
+
}
|
|
219
234
|
}
|
|
220
235
|
else {
|
|
221
236
|
// Silent overwrite mode - remove existing files
|
|
@@ -35,8 +35,9 @@ export declare function getSingleSkillFile(customerIdn: string, projectIdn: stri
|
|
|
35
35
|
* Check if skill script content is different from target content
|
|
36
36
|
*/
|
|
37
37
|
export declare function isContentDifferent(existingContent: string, newContent: string): boolean;
|
|
38
|
+
export type OverwriteChoice = 'yes' | 'no' | 'all' | 'quit';
|
|
38
39
|
/**
|
|
39
|
-
* Interactive overwrite confirmation
|
|
40
|
+
* Interactive overwrite confirmation with content diff
|
|
40
41
|
*/
|
|
41
|
-
export declare function askForOverwrite(skillIdn: string,
|
|
42
|
+
export declare function askForOverwrite(skillIdn: string, existingContent: string, newContent: string, fileName: string): Promise<OverwriteChoice>;
|
|
42
43
|
//# sourceMappingURL=skill-files.d.ts.map
|
package/dist/sync/skill-files.js
CHANGED
|
@@ -93,29 +93,53 @@ export function isContentDifferent(existingContent, newContent) {
|
|
|
93
93
|
return sha256(existingContent.trim()) !== sha256(newContent.trim());
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
|
-
* Interactive overwrite confirmation
|
|
96
|
+
* Interactive overwrite confirmation with content diff
|
|
97
97
|
*/
|
|
98
|
-
export async function askForOverwrite(skillIdn,
|
|
98
|
+
export async function askForOverwrite(skillIdn, existingContent, newContent, fileName) {
|
|
99
99
|
const readline = await import('readline');
|
|
100
100
|
const rl = readline.createInterface({
|
|
101
101
|
input: process.stdin,
|
|
102
102
|
output: process.stdout
|
|
103
103
|
});
|
|
104
|
-
console.log(`\nā ļø
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
console.log(`\nā ļø Content differs for skill ${skillIdn} (${fileName}):`);
|
|
105
|
+
// ANSI color codes
|
|
106
|
+
const red = '\x1b[31m';
|
|
107
|
+
const green = '\x1b[32m';
|
|
108
|
+
const reset = '\x1b[0m';
|
|
109
|
+
// Show a GitHub-style colored diff
|
|
110
|
+
const existingLines = existingContent.trim().split('\n');
|
|
111
|
+
const newLines = newContent.trim().split('\n');
|
|
112
|
+
// Show first few different lines with colors
|
|
113
|
+
let diffShown = 0;
|
|
114
|
+
const maxDiffLines = 5;
|
|
115
|
+
for (let i = 0; i < Math.max(existingLines.length, newLines.length) && diffShown < maxDiffLines; i++) {
|
|
116
|
+
const existingLine = existingLines[i] || '';
|
|
117
|
+
const newLine = newLines[i] || '';
|
|
118
|
+
if (existingLine !== newLine) {
|
|
119
|
+
if (existingLine)
|
|
120
|
+
console.log(`${red}-${existingLine}${reset}`);
|
|
121
|
+
if (newLine)
|
|
122
|
+
console.log(`${green}+${newLine}${reset}`);
|
|
123
|
+
diffShown++;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (diffShown === maxDiffLines) {
|
|
127
|
+
console.log(' ... (more differences)');
|
|
128
|
+
}
|
|
107
129
|
const answer = await new Promise((resolve) => {
|
|
108
|
-
rl.question(
|
|
130
|
+
rl.question(`\nReplace local with remote? (y)es/(n)o/(a)ll/(q)uit: `, resolve);
|
|
109
131
|
});
|
|
110
132
|
rl.close();
|
|
111
133
|
const choice = answer.toLowerCase().trim();
|
|
112
134
|
if (choice === 'q' || choice === 'quit') {
|
|
113
|
-
|
|
114
|
-
process.exit(0);
|
|
135
|
+
return 'quit';
|
|
115
136
|
}
|
|
116
137
|
if (choice === 'a' || choice === 'all') {
|
|
117
|
-
return
|
|
138
|
+
return 'all';
|
|
139
|
+
}
|
|
140
|
+
if (choice === 'y' || choice === 'yes') {
|
|
141
|
+
return 'yes';
|
|
118
142
|
}
|
|
119
|
-
return
|
|
143
|
+
return 'no';
|
|
120
144
|
}
|
|
121
145
|
//# sourceMappingURL=skill-files.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newo",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "NEWO CLI: Professional command-line tool with modular architecture for NEWO AI Agent development. Features IDN-based file management, real-time progress tracking, intelligent sync operations, and comprehensive multi-customer support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/sync/projects.ts
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
askForOverwrite,
|
|
28
28
|
getExtensionForRunner
|
|
29
29
|
} from './skill-files.js';
|
|
30
|
+
import type { OverwriteChoice } from './skill-files.js';
|
|
30
31
|
import fs from 'fs-extra';
|
|
31
32
|
import { sha256, saveHashes } from '../hash.js';
|
|
32
33
|
import yaml from 'js-yaml';
|
|
@@ -96,9 +97,10 @@ export async function pullSingleProject(
|
|
|
96
97
|
|
|
97
98
|
const newHashes: HashStore = {};
|
|
98
99
|
|
|
99
|
-
// Progress tracking
|
|
100
|
+
// Progress tracking and overwrite control
|
|
100
101
|
let totalSkills = 0;
|
|
101
102
|
let processedSkills = 0;
|
|
103
|
+
let globalOverwriteAll = silentOverwrite;
|
|
102
104
|
|
|
103
105
|
// Count total skills for progress tracking
|
|
104
106
|
for (const project of projects) {
|
|
@@ -249,7 +251,7 @@ export async function pullSingleProject(
|
|
|
249
251
|
hasContentMatch = existingFiles.some(file => !isContentDifferent(file.content, scriptContent));
|
|
250
252
|
|
|
251
253
|
if (hasContentMatch) {
|
|
252
|
-
// Content is the same -
|
|
254
|
+
// Content is the same - handle file naming
|
|
253
255
|
const matchingFile = existingFiles.find(file => !isContentDifferent(file.content, scriptContent));
|
|
254
256
|
const correctName = `${skill.idn}.${getExtensionForRunner(skill.runner_type)}`;
|
|
255
257
|
|
|
@@ -258,29 +260,41 @@ export async function pullSingleProject(
|
|
|
258
260
|
await fs.remove(matchingFile.filePath);
|
|
259
261
|
if (verbose) console.log(` š Renamed ${matchingFile.fileName} ā ${correctName}`);
|
|
260
262
|
} else if (matchingFile && matchingFile.fileName === correctName) {
|
|
261
|
-
// Already has correct name and content
|
|
263
|
+
// Already has correct name and content - skip completely
|
|
262
264
|
shouldWrite = false;
|
|
263
265
|
newHashes[matchingFile.filePath] = sha256(scriptContent);
|
|
264
266
|
if (verbose) console.log(` ā Content unchanged for ${skill.idn}, keeping existing file`);
|
|
265
267
|
}
|
|
266
|
-
} else if (!
|
|
267
|
-
// Content is different, ask for overwrite
|
|
268
|
+
} else if (!globalOverwriteAll) {
|
|
269
|
+
// Content is different, ask for overwrite unless global override is set
|
|
268
270
|
const existingFile = existingFiles[0]!;
|
|
269
|
-
const
|
|
271
|
+
const overwriteChoice: OverwriteChoice = await askForOverwrite(
|
|
270
272
|
skill.idn,
|
|
271
|
-
existingFile.
|
|
272
|
-
|
|
273
|
+
existingFile.content,
|
|
274
|
+
scriptContent,
|
|
275
|
+
existingFile.fileName
|
|
273
276
|
);
|
|
274
277
|
|
|
275
|
-
if (
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
} else {
|
|
279
|
-
|
|
278
|
+
if (overwriteChoice === 'quit') {
|
|
279
|
+
console.log('ā Pull operation cancelled by user');
|
|
280
|
+
process.exit(0);
|
|
281
|
+
} else if (overwriteChoice === 'all') {
|
|
282
|
+
globalOverwriteAll = true;
|
|
283
|
+
// Continue with overwrite
|
|
284
|
+
for (const file of existingFiles) {
|
|
285
|
+
await fs.remove(file.filePath);
|
|
286
|
+
if (verbose) console.log(` šļø Removed ${file.fileName}`);
|
|
287
|
+
}
|
|
288
|
+
} else if (overwriteChoice === 'yes') {
|
|
289
|
+
// Single overwrite
|
|
280
290
|
for (const file of existingFiles) {
|
|
281
291
|
await fs.remove(file.filePath);
|
|
282
292
|
if (verbose) console.log(` šļø Removed ${file.fileName}`);
|
|
283
293
|
}
|
|
294
|
+
} else {
|
|
295
|
+
// User said no
|
|
296
|
+
shouldWrite = false;
|
|
297
|
+
if (verbose) console.log(` ā ļø Skipped overwrite for ${skill.idn}`);
|
|
284
298
|
}
|
|
285
299
|
} else {
|
|
286
300
|
// Silent overwrite mode - remove existing files
|
package/src/sync/skill-files.ts
CHANGED
|
@@ -142,35 +142,66 @@ export function isContentDifferent(existingContent: string, newContent: string):
|
|
|
142
142
|
return sha256(existingContent.trim()) !== sha256(newContent.trim());
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
export type OverwriteChoice = 'yes' | 'no' | 'all' | 'quit';
|
|
146
|
+
|
|
145
147
|
/**
|
|
146
|
-
* Interactive overwrite confirmation
|
|
148
|
+
* Interactive overwrite confirmation with content diff
|
|
147
149
|
*/
|
|
148
|
-
export async function askForOverwrite(skillIdn: string,
|
|
150
|
+
export async function askForOverwrite(skillIdn: string, existingContent: string, newContent: string, fileName: string): Promise<OverwriteChoice> {
|
|
149
151
|
const readline = await import('readline');
|
|
150
152
|
const rl = readline.createInterface({
|
|
151
153
|
input: process.stdin,
|
|
152
154
|
output: process.stdout
|
|
153
155
|
});
|
|
154
156
|
|
|
155
|
-
console.log(`\nā ļø
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
console.log(`\nā ļø Content differs for skill ${skillIdn} (${fileName}):`);
|
|
158
|
+
|
|
159
|
+
// ANSI color codes
|
|
160
|
+
const red = '\x1b[31m';
|
|
161
|
+
const green = '\x1b[32m';
|
|
162
|
+
const reset = '\x1b[0m';
|
|
163
|
+
|
|
164
|
+
// Show a GitHub-style colored diff
|
|
165
|
+
const existingLines = existingContent.trim().split('\n');
|
|
166
|
+
const newLines = newContent.trim().split('\n');
|
|
167
|
+
|
|
168
|
+
// Show first few different lines with colors
|
|
169
|
+
let diffShown = 0;
|
|
170
|
+
const maxDiffLines = 5;
|
|
171
|
+
|
|
172
|
+
for (let i = 0; i < Math.max(existingLines.length, newLines.length) && diffShown < maxDiffLines; i++) {
|
|
173
|
+
const existingLine = existingLines[i] || '';
|
|
174
|
+
const newLine = newLines[i] || '';
|
|
175
|
+
|
|
176
|
+
if (existingLine !== newLine) {
|
|
177
|
+
if (existingLine) console.log(`${red}-${existingLine}${reset}`);
|
|
178
|
+
if (newLine) console.log(`${green}+${newLine}${reset}`);
|
|
179
|
+
diffShown++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (diffShown === maxDiffLines) {
|
|
184
|
+
console.log(' ... (more differences)');
|
|
185
|
+
}
|
|
158
186
|
|
|
159
187
|
const answer = await new Promise<string>((resolve) => {
|
|
160
|
-
rl.question(
|
|
188
|
+
rl.question(`\nReplace local with remote? (y)es/(n)o/(a)ll/(q)uit: `, resolve);
|
|
161
189
|
});
|
|
162
190
|
rl.close();
|
|
163
191
|
|
|
164
192
|
const choice = answer.toLowerCase().trim();
|
|
165
193
|
|
|
166
194
|
if (choice === 'q' || choice === 'quit') {
|
|
167
|
-
|
|
168
|
-
process.exit(0);
|
|
195
|
+
return 'quit';
|
|
169
196
|
}
|
|
170
197
|
|
|
171
198
|
if (choice === 'a' || choice === 'all') {
|
|
172
|
-
return
|
|
199
|
+
return 'all';
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (choice === 'y' || choice === 'yes') {
|
|
203
|
+
return 'yes';
|
|
173
204
|
}
|
|
174
205
|
|
|
175
|
-
return
|
|
206
|
+
return 'no';
|
|
176
207
|
}
|