newo 1.3.0 → 1.5.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/.env.example +2 -2
- package/CHANGELOG.md +99 -2
- package/README.md +59 -10
- package/dist/akb.d.ts +10 -0
- package/dist/akb.js +84 -0
- package/dist/api.d.ts +13 -0
- package/dist/api.js +100 -0
- package/dist/auth.d.ts +6 -0
- package/dist/auth.js +104 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +111 -0
- package/dist/fsutil.d.ts +12 -0
- package/dist/fsutil.js +28 -0
- package/dist/hash.d.ts +5 -0
- package/dist/hash.js +17 -0
- package/dist/sync.d.ts +7 -0
- package/dist/sync.js +337 -0
- package/dist/types.d.ts +206 -0
- package/dist/types.js +5 -0
- package/package.json +32 -9
- package/src/{akb.js → akb.ts} +16 -25
- package/src/api.ts +127 -0
- package/src/auth.ts +142 -0
- package/src/{cli.js → cli.ts} +29 -15
- package/src/fsutil.ts +41 -0
- package/src/hash.ts +20 -0
- package/src/sync.ts +396 -0
- package/src/types.ts +248 -0
- package/src/api.js +0 -98
- package/src/auth.js +0 -92
- package/src/fsutil.js +0 -26
- package/src/hash.js +0 -17
- package/src/sync.js +0 -284
package/src/sync.js
DELETED
|
@@ -1,284 +0,0 @@
|
|
|
1
|
-
import { listAgents, listFlowSkills, updateSkill, listFlowEvents, listFlowStates } from './api.js';
|
|
2
|
-
import { ensureState, skillPath, writeFileAtomic, readIfExists, MAP_PATH } 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 path from 'path';
|
|
7
|
-
|
|
8
|
-
export async function pullAll(client, projectId, verbose = false) {
|
|
9
|
-
await ensureState();
|
|
10
|
-
if (verbose) console.log(`🔍 Fetching agents for project ${projectId}...`);
|
|
11
|
-
const agents = await listAgents(client, projectId);
|
|
12
|
-
if (verbose) console.log(`📦 Found ${agents.length} agents`);
|
|
13
|
-
|
|
14
|
-
const idMap = { projectId, agents: {} };
|
|
15
|
-
|
|
16
|
-
for (const agent of agents) {
|
|
17
|
-
const aKey = agent.idn;
|
|
18
|
-
idMap.agents[aKey] = { id: agent.id, flows: {} };
|
|
19
|
-
|
|
20
|
-
for (const flow of agent.flows ?? []) {
|
|
21
|
-
idMap.agents[aKey].flows[flow.idn] = { id: flow.id, skills: {} };
|
|
22
|
-
|
|
23
|
-
const skills = await listFlowSkills(client, flow.id);
|
|
24
|
-
for (const s of skills) {
|
|
25
|
-
const file = skillPath(agent.idn, flow.idn, s.idn, s.runner_type);
|
|
26
|
-
await writeFileAtomic(file, s.prompt_script || '');
|
|
27
|
-
// Store complete skill metadata for push operations
|
|
28
|
-
idMap.agents[aKey].flows[flow.idn].skills[s.idn] = {
|
|
29
|
-
id: s.id,
|
|
30
|
-
title: s.title,
|
|
31
|
-
idn: s.idn,
|
|
32
|
-
runner_type: s.runner_type,
|
|
33
|
-
model: s.model,
|
|
34
|
-
parameters: s.parameters,
|
|
35
|
-
path: s.path
|
|
36
|
-
};
|
|
37
|
-
console.log(`✓ Pulled ${file}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
await fs.writeJson(MAP_PATH, idMap, { spaces: 2 });
|
|
43
|
-
|
|
44
|
-
// Generate flows.yaml
|
|
45
|
-
if (verbose) console.log('📄 Generating flows.yaml...');
|
|
46
|
-
await generateFlowsYaml(client, agents, verbose);
|
|
47
|
-
|
|
48
|
-
const hashes = {};
|
|
49
|
-
for (const [agentIdn, agentObj] of Object.entries(idMap.agents)) {
|
|
50
|
-
for (const [flowIdn, flowObj] of Object.entries(agentObj.flows)) {
|
|
51
|
-
for (const [skillIdn, skillMeta] of Object.entries(flowObj.skills)) {
|
|
52
|
-
const p = skillPath(agentIdn, flowIdn, skillIdn, skillMeta.runner_type);
|
|
53
|
-
const content = await fs.readFile(p, 'utf8');
|
|
54
|
-
hashes[p] = sha256(content);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
await saveHashes(hashes);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function pushChanged(client, verbose = false) {
|
|
62
|
-
await ensureState();
|
|
63
|
-
if (!(await fs.pathExists(MAP_PATH))) {
|
|
64
|
-
throw new Error('Missing .newo/map.json. Run `newo pull` first.');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (verbose) console.log('📋 Loading project mapping...');
|
|
68
|
-
const idMap = await fs.readJson(MAP_PATH);
|
|
69
|
-
if (verbose) console.log('🔍 Loading file hashes...');
|
|
70
|
-
const oldHashes = await loadHashes();
|
|
71
|
-
const newHashes = { ...oldHashes };
|
|
72
|
-
|
|
73
|
-
if (verbose) console.log('🔄 Scanning for changes...');
|
|
74
|
-
let pushed = 0;
|
|
75
|
-
let scanned = 0;
|
|
76
|
-
|
|
77
|
-
for (const [agentIdn, agentObj] of Object.entries(idMap.agents)) {
|
|
78
|
-
if (verbose) console.log(` 📁 Scanning agent: ${agentIdn}`);
|
|
79
|
-
for (const [flowIdn, flowObj] of Object.entries(agentObj.flows)) {
|
|
80
|
-
if (verbose) console.log(` 📁 Scanning flow: ${flowIdn}`);
|
|
81
|
-
for (const [skillIdn, skillMeta] of Object.entries(flowObj.skills)) {
|
|
82
|
-
const p = skillPath(agentIdn, flowIdn, skillIdn, skillMeta.runner_type);
|
|
83
|
-
scanned++;
|
|
84
|
-
if (verbose) console.log(` 📄 Checking: ${p}`);
|
|
85
|
-
|
|
86
|
-
const content = await readIfExists(p);
|
|
87
|
-
if (content === null) {
|
|
88
|
-
if (verbose) console.log(` ⚠️ File not found: ${p}`);
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const h = sha256(content);
|
|
93
|
-
const oldHash = oldHashes[p];
|
|
94
|
-
if (verbose) {
|
|
95
|
-
console.log(` 🔍 Hash comparison:`);
|
|
96
|
-
console.log(` Old: ${oldHash || 'none'}`);
|
|
97
|
-
console.log(` New: ${h}`);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (oldHash !== h) {
|
|
101
|
-
if (verbose) console.log(` 🔄 File changed, preparing to push...`);
|
|
102
|
-
|
|
103
|
-
// Create complete skill object with updated prompt_script
|
|
104
|
-
const skillObject = {
|
|
105
|
-
id: skillMeta.id,
|
|
106
|
-
title: skillMeta.title,
|
|
107
|
-
idn: skillMeta.idn,
|
|
108
|
-
prompt_script: content,
|
|
109
|
-
runner_type: skillMeta.runner_type,
|
|
110
|
-
model: skillMeta.model,
|
|
111
|
-
parameters: skillMeta.parameters,
|
|
112
|
-
path: skillMeta.path
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
if (verbose) {
|
|
116
|
-
console.log(` 📤 Pushing skill object:`);
|
|
117
|
-
console.log(` ID: ${skillObject.id}`);
|
|
118
|
-
console.log(` Title: ${skillObject.title}`);
|
|
119
|
-
console.log(` IDN: ${skillObject.idn}`);
|
|
120
|
-
console.log(` Content length: ${content.length} chars`);
|
|
121
|
-
console.log(` Content preview: ${content.substring(0, 100).replace(/\n/g, '\\n')}...`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
await updateSkill(client, skillObject);
|
|
125
|
-
console.log(`↑ Pushed ${p}`);
|
|
126
|
-
newHashes[p] = h;
|
|
127
|
-
pushed++;
|
|
128
|
-
} else if (verbose) {
|
|
129
|
-
console.log(` ✓ No changes`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (verbose) console.log(`🔄 Scanned ${scanned} files, found ${pushed} changes`);
|
|
136
|
-
await saveHashes(newHashes);
|
|
137
|
-
console.log(pushed ? `✅ Push complete. ${pushed} file(s) updated.` : '✅ Nothing to push.');
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export async function status(verbose = false) {
|
|
141
|
-
await ensureState();
|
|
142
|
-
if (!(await fs.pathExists(MAP_PATH))) {
|
|
143
|
-
console.log('No map. Run `newo pull` first.');
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (verbose) console.log('📋 Loading project mapping and hashes...');
|
|
148
|
-
const idMap = await fs.readJson(MAP_PATH);
|
|
149
|
-
const hashes = await loadHashes();
|
|
150
|
-
let dirty = 0;
|
|
151
|
-
|
|
152
|
-
for (const [agentIdn, agentObj] of Object.entries(idMap.agents)) {
|
|
153
|
-
if (verbose) console.log(` 📁 Checking agent: ${agentIdn}`);
|
|
154
|
-
for (const [flowIdn, flowObj] of Object.entries(agentObj.flows)) {
|
|
155
|
-
if (verbose) console.log(` 📁 Checking flow: ${flowIdn}`);
|
|
156
|
-
for (const [skillIdn, skillMeta] of Object.entries(flowObj.skills)) {
|
|
157
|
-
const p = skillPath(agentIdn, flowIdn, skillIdn, skillMeta.runner_type);
|
|
158
|
-
const exists = await fs.pathExists(p);
|
|
159
|
-
if (!exists) {
|
|
160
|
-
console.log(`D ${p}`);
|
|
161
|
-
dirty++;
|
|
162
|
-
if (verbose) console.log(` ❌ Deleted: ${p}`);
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
const content = await fs.readFile(p, 'utf8');
|
|
166
|
-
const h = sha256(content);
|
|
167
|
-
const oldHash = hashes[p];
|
|
168
|
-
if (verbose) {
|
|
169
|
-
console.log(` 📄 ${p}`);
|
|
170
|
-
console.log(` Old hash: ${oldHash || 'none'}`);
|
|
171
|
-
console.log(` New hash: ${h}`);
|
|
172
|
-
}
|
|
173
|
-
if (oldHash !== h) {
|
|
174
|
-
console.log(`M ${p}`);
|
|
175
|
-
dirty++;
|
|
176
|
-
if (verbose) console.log(` 🔄 Modified: ${p}`);
|
|
177
|
-
} else if (verbose) {
|
|
178
|
-
console.log(` ✓ Unchanged: ${p}`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
console.log(dirty ? `${dirty} changed file(s).` : 'Clean.');
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async function generateFlowsYaml(client, agents, verbose = false) {
|
|
187
|
-
const flowsData = { flows: [] };
|
|
188
|
-
|
|
189
|
-
for (const agent of agents) {
|
|
190
|
-
if (verbose) console.log(` 📁 Processing agent: ${agent.idn}`);
|
|
191
|
-
|
|
192
|
-
const agentFlows = [];
|
|
193
|
-
|
|
194
|
-
for (const flow of agent.flows ?? []) {
|
|
195
|
-
if (verbose) console.log(` 📄 Processing flow: ${flow.idn}`);
|
|
196
|
-
|
|
197
|
-
// Get skills for this flow
|
|
198
|
-
const skills = await listFlowSkills(client, flow.id);
|
|
199
|
-
const skillsData = skills.map(skill => ({
|
|
200
|
-
idn: skill.idn,
|
|
201
|
-
title: skill.title || "",
|
|
202
|
-
prompt_script: `flows/${flow.idn}/${skill.idn}.${skill.runner_type === 'nsl' ? 'jinja' : 'nsl'}`,
|
|
203
|
-
runner_type: `!enum "RunnerType.${skill.runner_type}"`,
|
|
204
|
-
model: {
|
|
205
|
-
model_idn: skill.model.model_idn,
|
|
206
|
-
provider_idn: skill.model.provider_idn
|
|
207
|
-
},
|
|
208
|
-
parameters: skill.parameters.map(param => ({
|
|
209
|
-
name: param.name,
|
|
210
|
-
default_value: param.default_value || " "
|
|
211
|
-
}))
|
|
212
|
-
}));
|
|
213
|
-
|
|
214
|
-
// Get events for this flow
|
|
215
|
-
let eventsData = [];
|
|
216
|
-
try {
|
|
217
|
-
const events = await listFlowEvents(client, flow.id);
|
|
218
|
-
eventsData = events.map(event => ({
|
|
219
|
-
title: event.description,
|
|
220
|
-
idn: event.idn,
|
|
221
|
-
skill_selector: `!enum "SkillSelector.${event.skill_selector}"`,
|
|
222
|
-
skill_idn: event.skill_idn,
|
|
223
|
-
state_idn: event.state_idn,
|
|
224
|
-
integration_idn: event.integration_idn,
|
|
225
|
-
connector_idn: event.connector_idn,
|
|
226
|
-
interrupt_mode: `!enum "InterruptMode.${event.interrupt_mode}"`
|
|
227
|
-
}));
|
|
228
|
-
if (verbose) console.log(` 📋 Found ${events.length} events`);
|
|
229
|
-
} catch (error) {
|
|
230
|
-
if (verbose) console.log(` ⚠️ No events found for flow ${flow.idn}`);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Get state fields for this flow
|
|
234
|
-
let stateFieldsData = [];
|
|
235
|
-
try {
|
|
236
|
-
const states = await listFlowStates(client, flow.id);
|
|
237
|
-
stateFieldsData = states.map(state => ({
|
|
238
|
-
title: state.title,
|
|
239
|
-
idn: state.idn,
|
|
240
|
-
default_value: state.default_value,
|
|
241
|
-
scope: `!enum "StateFieldScope.${state.scope}"`
|
|
242
|
-
}));
|
|
243
|
-
if (verbose) console.log(` 📊 Found ${states.length} state fields`);
|
|
244
|
-
} catch (error) {
|
|
245
|
-
if (verbose) console.log(` ⚠️ No state fields found for flow ${flow.idn}`);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
agentFlows.push({
|
|
249
|
-
idn: flow.idn,
|
|
250
|
-
title: flow.title,
|
|
251
|
-
description: flow.description || null,
|
|
252
|
-
default_runner_type: `!enum "RunnerType.${flow.default_runner_type}"`,
|
|
253
|
-
default_provider_idn: flow.default_model.provider_idn,
|
|
254
|
-
default_model_idn: flow.default_model.model_idn,
|
|
255
|
-
skills: skillsData,
|
|
256
|
-
events: eventsData,
|
|
257
|
-
state_fields: stateFieldsData
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
flowsData.flows.push({
|
|
262
|
-
agent_idn: agent.idn,
|
|
263
|
-
agent_description: agent.description,
|
|
264
|
-
agent_flows: agentFlows
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Convert to YAML and write to file with custom enum handling
|
|
269
|
-
let yamlContent = yaml.dump(flowsData, {
|
|
270
|
-
indent: 2,
|
|
271
|
-
lineWidth: -1,
|
|
272
|
-
noRefs: true,
|
|
273
|
-
sortKeys: false,
|
|
274
|
-
quotingType: '"',
|
|
275
|
-
forceQuotes: false
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
// Post-process to fix enum formatting
|
|
279
|
-
yamlContent = yamlContent.replace(/"(!enum "[^"]+")"/g, '$1');
|
|
280
|
-
|
|
281
|
-
const yamlPath = path.join('flows.yaml');
|
|
282
|
-
await fs.writeFile(yamlPath, yamlContent, 'utf8');
|
|
283
|
-
console.log(`✓ Generated flows.yaml`);
|
|
284
|
-
}
|