@j-o-r/hello-dave 0.0.9 → 0.1.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 (82) hide show
  1. package/README.md +2 -0
  2. package/README.md.bak.1779452127 +240 -0
  3. package/TODO.md +31 -20
  4. package/agents/code_agent.js +6 -6
  5. package/agents/daisy_agent.js +10 -7
  6. package/agents/minimax.js +173 -0
  7. package/agents/spawn_agent.js +33 -10
  8. package/agents/stability.js +173 -0
  9. package/bin/codeDave +1 -1
  10. package/bin/dave.js +1 -1
  11. package/docs/dependencies.md +7 -0
  12. package/docs/music-toolsets.md +137 -0
  13. package/docs/plans/minimax-music-generation.md +80 -0
  14. package/docs/plans/unified-agent-architecture.md +146 -0
  15. package/docs/plans/websocket-streaming-plan.md.bak +317 -0
  16. package/docs/prompt/spawn_agent.md +46 -44
  17. package/docs/prompt/task_clarification_and_documentation.md +35 -0
  18. package/docs/todo-archive-infra-2026-04-21.md +15 -0
  19. package/docs/todo-archive-v0.1.0.md +32 -0
  20. package/lib/API/minimax/ImageToolset.js +169 -0
  21. package/lib/API/minimax/MusicToolset.js +290 -0
  22. package/lib/API/minimax/VideoToolset.js +296 -0
  23. package/lib/API/minimax/image.generation.md +239 -0
  24. package/lib/API/minimax/image.js +219 -0
  25. package/lib/API/minimax/image.to.image.md +257 -0
  26. package/lib/API/minimax/index.js +16 -0
  27. package/lib/API/minimax/music.cover.preprocess.md +206 -0
  28. package/lib/API/minimax/music.generation.md +346 -0
  29. package/lib/API/minimax/music.js +257 -0
  30. package/lib/API/minimax/music.lyrics.generation.md +205 -0
  31. package/lib/API/minimax/video.download.md +133 -0
  32. package/lib/API/minimax/video.first.last.image.md +186 -0
  33. package/lib/API/minimax/video.from.image.md +206 -0
  34. package/lib/API/minimax/video.from.subject.md +164 -0
  35. package/lib/API/minimax/video.generation.md +192 -0
  36. package/lib/API/minimax/video.js +339 -0
  37. package/lib/API/minimax/video.query.md +128 -0
  38. package/lib/API/stability.ai/ImageToolset.js +357 -0
  39. package/lib/API/stability.ai/MusicToolset.js +302 -0
  40. package/lib/API/stability.ai/audio-3.md +205 -0
  41. package/lib/API/stability.ai/audio.js +679 -0
  42. package/lib/API/stability.ai/image.js +911 -0
  43. package/lib/API/stability.ai/image.md +271 -0
  44. package/lib/API/stability.ai/index.js +11 -0
  45. package/lib/API/stability.ai/openapi.json +17118 -0
  46. package/lib/API/x.ai/ImageToolset.js +165 -0
  47. package/lib/API/x.ai/image.editing.md +86 -0
  48. package/lib/API/x.ai/image.js +393 -0
  49. package/lib/API/x.ai/image.md +213 -0
  50. package/lib/API/x.ai/image.to.generation.md +494 -0
  51. package/lib/API/x.ai/image.to.video.md +23 -0
  52. package/lib/API/x.ai/index.js +9 -0
  53. package/lib/AgentManager.js +1 -1
  54. package/lib/CdnToolset.js +191 -0
  55. package/lib/ToolSet.js +19 -1
  56. package/lib/cdn.js +373 -0
  57. package/lib/fafs.js +5 -3
  58. package/lib/genericToolset.js +75 -210
  59. package/lib/index.js +9 -1
  60. package/package.json +2 -2
  61. package/types/API/minimax/ImageToolset.d.ts +3 -0
  62. package/types/API/minimax/MusicToolset.d.ts +3 -0
  63. package/types/API/minimax/VideoToolset.d.ts +3 -0
  64. package/types/API/minimax/image.d.ts +109 -0
  65. package/types/API/minimax/index.d.ts +15 -0
  66. package/types/API/minimax/music.d.ts +46 -0
  67. package/types/API/minimax/video.d.ts +165 -0
  68. package/types/API/stability.ai/ImageToolset.d.ts +3 -0
  69. package/types/API/stability.ai/MusicToolset.d.ts +3 -0
  70. package/types/API/stability.ai/audio.d.ts +193 -0
  71. package/types/API/stability.ai/image.d.ts +274 -0
  72. package/types/API/stability.ai/index.d.ts +11 -0
  73. package/types/API/x.ai/ImageToolset.d.ts +3 -0
  74. package/types/API/x.ai/image.d.ts +82 -0
  75. package/types/API/x.ai/index.d.ts +9 -0
  76. package/types/AgentManager.d.ts +1 -1
  77. package/types/CdnToolset.d.ts +20 -0
  78. package/types/ToolSet.d.ts +8 -0
  79. package/types/cdn.d.ts +141 -0
  80. package/types/index.d.ts +8 -2
  81. package/utils/syntax_check.sh +59 -15
  82. package/docs/multi-agent-clusters.md.bak +0 -229
@@ -7,12 +7,15 @@ import { fileURLToPath } from 'node:url';
7
7
  const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = path.dirname(__filename);
9
9
 
10
- // STANDARDIZED UTILS PATHS (hoisted constants for performance/consistency)
10
+ // STANDARDIZED UTILS PATHS
11
11
  const utilsDir = path.resolve(__dirname, '..', 'utils');
12
12
  const searchSessionsSh = path.join(utilsDir, 'search_sessions.sh');
13
13
  const listSessionsSh = path.join(utilsDir, 'list_sessions.sh');
14
14
  const syntaxCheckSh = path.join(utilsDir, 'syntax_check.sh');
15
15
 
16
+ // Do we have a SSH access point?
17
+ const SSH_EP = process.env.SSH_EP || '';
18
+
16
19
  const user = await env();
17
20
  const environment = `
18
21
  Name: ${user.name}
@@ -26,47 +29,7 @@ ExternalIp: ${user.external_ip}
26
29
  const tools = new ToolSet('auto');
27
30
 
28
31
  /**
29
- * Reduces verbose JavaScript evaluation error output to essential info (line number + core message).
30
- * @param {string} errorStr - Full Node.js error string.
31
- * @returns {string} Simplified error.
32
- * @private
33
- */
34
- const getJSError = (errorStr) => {
35
- let result = '';
36
- const linematch = errorStr.match(/\[eval\]:(\d+)/);
37
- const lineNumber = linematch ? linematch[1] : '';
38
- const match = errorStr.split(/\" \"\[eval\]:\d+/s);
39
- if (match.length > 1) {
40
- const res = match[1].split('\n').slice(0, -10).join('\n');
41
- result = `Error: line ${lineNumber}\n${res} `;
42
- } else {
43
- result = errorStr;
44
- }
45
- return result;
46
- };
47
- // /**
48
- // * Try to prevent double escaping by LLMS models
49
- // * When a string stays a string it is probably double escaped
50
- // * @parameter {string} s
51
- // * @returns {string}
52
- // */
53
- // const guessOverEscaping = (s) => {
54
- // let test;
55
- // if (typeof s === 'string') {
56
- // try {
57
- // test = JSON.parse(s);
58
- // } catch (_e) { }
59
- // if (typeof test === 'string') {
60
- // return test;
61
- // }
62
- // }
63
- // return s;
64
- // }
65
-
66
- /**
67
- * Try to prevent double escaping by LLMs.
68
- * Handles common patterns like \"path\", \\\"path\\\", JSON strings,
69
- * and multiple layers while being much safer on complex bash/JS scripts.
32
+ * Single source of truth for cleaning over-escaped strings from LLMs.
70
33
  */
71
34
  const guessOverEscaping = (s) => {
72
35
  if (typeof s !== 'string') return s;
@@ -74,13 +37,12 @@ const guessOverEscaping = (s) => {
74
37
  let current = s.trim();
75
38
  const seen = new Set();
76
39
  let iterations = 0;
77
- const MAX_ITER = 6; // safety limit
40
+ const MAX_ITER = 6;
78
41
 
79
42
  while (iterations < MAX_ITER && !seen.has(current)) {
80
43
  seen.add(current);
81
44
  iterations++;
82
45
 
83
- // 1. Most reliable: JSON.parse (undoes proper JSON string escaping)
84
46
  try {
85
47
  const parsed = JSON.parse(current);
86
48
  if (typeof parsed === 'string') {
@@ -89,24 +51,19 @@ const guessOverEscaping = (s) => {
89
51
  }
90
52
  } catch (e) { }
91
53
 
92
- // 2. Specifically strip the pattern you saw: \"...\" (including the backslashes)
93
54
  if (current.startsWith('\\"') && current.endsWith('\\"')) {
94
55
  current = current.slice(2, -2);
95
56
  continue;
96
57
  }
97
58
 
98
- // 3. Strip normal outer quotes, but protect JSON objects/arrays
99
59
  if (current.startsWith('"') && current.endsWith('"') && current.length > 2) {
100
- const inner = current.slice(1, -1);
101
- const trimmedInner = inner.trim();
102
- if (!trimmedInner.startsWith('{') && !trimmedInner.startsWith('[')) {
60
+ const inner = current.slice(1, -1).trim();
61
+ if (!inner.startsWith('{') && !inner.startsWith('[')) {
103
62
  current = inner;
104
63
  continue;
105
64
  }
106
65
  }
107
66
 
108
- // 4. Conservative global unescape of \" → "
109
- // Only applied to short strings without newlines (i.e. not full scripts)
110
67
  if (!current.includes('\n') && (current.match(/\\"/g) || []).length >= 1) {
111
68
  const lessEscaped = current.replace(/\\"/g, '"');
112
69
  if (lessEscaped !== current) {
@@ -115,20 +72,31 @@ const guessOverEscaping = (s) => {
115
72
  }
116
73
  }
117
74
 
118
- break; // no more productive changes
75
+ break;
119
76
  }
120
77
 
121
78
  return current;
122
- };/**
79
+ };
80
+
81
+ const getJSError = (errorStr) => {
82
+ let result = '';
83
+ const linematch = errorStr.match(/\[eval\]:(\d+)/);
84
+ const lineNumber = linematch ? linematch[1] : '';
85
+ const match = errorStr.split(/" "\[eval\]:\d+/s);
86
+ if (match.length > 1) {
87
+ const res = match[1].split('\n').slice(0, -10).join('\n');
88
+ result = `Error: line ${lineNumber}\n${res} `;
89
+ } else {
90
+ result = errorStr;
91
+ }
92
+ return result;
93
+ };
94
+
95
+ /**
123
96
  * @module lib/genericToolset
124
- * Secure utility tools for code execution, file I/O, system ops. Pre-populated ToolSet.
125
- *
126
- * @example
127
- * import tools from './lib/genericToolset.js';
128
- * await tools.call('get_user_env', {});
129
- *
130
- * @see {@link module:./index~ToolSet}
97
+ * Secure utility tools.
131
98
  */
99
+
132
100
  tools.add(
133
101
  'javascript_interpreter',
134
102
  'Execute ESM ES6 JavaScript on node.',
@@ -167,54 +135,45 @@ tools.add(
167
135
 
168
136
  tools.add(
169
137
  'execute_bash_script',
170
- 'Execute raw bash script or command (no escaping needed). Supports timeout to prevent hangs.',
138
+ 'Execute raw bash script or command (no escaping needed). Supports timeout.',
171
139
  {
172
140
  type: 'object',
173
141
  properties: {
174
142
  bash_script: {
175
143
  type: 'string',
176
- description: `Raw bash verbatim. Supports all syntax safely via stdin. System: ${user.system}`
144
+ description: `Write raw bash exactly...`
177
145
  },
178
- timeout: {
179
- type: 'number',
180
- default: 360,
181
- description: 'Max execution time in seconds (default 360 seconds, 0 is no timeout). Uses @j-o-r/sh timeout (ms) with SIGTERM on expiry to prevent hangs from interactive prompts or slow commands.'
182
- }
146
+ timeout: { type: 'number', default: 360 },
147
+ strict: { type: 'boolean', default: false }
183
148
  },
184
149
  required: ['bash_script']
185
150
  },
186
151
  async (params) => {
187
- const timeoutSec = Number(params.timeout ?? 300);
188
- const bash_script = guessOverEscaping(params.bash_script);
152
+ let bash_script = params.bash_script;
153
+ if (typeof bash_script !== 'string') bash_script = '';
154
+ // Check if the bash_script string has a shebang on the first line '#!'
155
+ // If not, add a bash shebang
156
+ const firstLine = bash_script.split('\n')[0] || '';
157
+ if (!firstLine.trim().startsWith('#!')) {
158
+ bash_script = '#!/bin/bash\n' + bash_script;
159
+ }
160
+ const timeoutSec = Number(params.timeout ?? 360);
161
+ const prams = params.strict ? '' : '-S error';
189
162
  if (isNaN(timeoutSec) || timeoutSec < 0) throw new Error('Invalid timeout');
190
163
  const timeout = timeoutSec * 1000;
191
- // return await SH`bash`.options({ timeout: timeoutMs }).run(params.bash_script);
192
- const delim = `END_SCRIPT_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
193
- return await SH`bash <<'${delim}'
194
- ${bash_script}
195
- ${delim}
196
- `.options({ timeout }).run();
197
-
164
+ const valid = SH`shellcheck ${prams} -`.runSync(bash_script).stdout.toString().trim();
165
+ if (valid !== '') throw new Error(valid);
166
+ return await SH`bash`.options({ timeout }).run(bash_script);
198
167
  }
199
168
  );
200
169
 
201
170
  tools.add(
202
- 'send_email',
203
- 'Send email via msmtp.',
204
- {
205
- type: 'object',
206
- properties: {
207
- to: { type: 'string', description: 'Recipient' },
208
- subject: { type: 'string', description: 'Subject' },
209
- body: { type: 'string', description: 'Body' }
210
- },
211
- required: ['to', 'subject', 'body']
212
- },
171
+ 'send_email', 'Send email via msmtp.', { type: 'object', properties: { to: { type: 'string' }, subject: { type: 'string' }, body: { type: 'string' } }, required: ['to', 'subject', 'body'] },
213
172
  async (params) => {
214
173
  const to = guessOverEscaping(params.to);
215
174
  const subject = guessOverEscaping(params.subject);
216
175
  const body = guessOverEscaping(params.body);
217
- const delim = `END_EMAIL_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
176
+ const delim = `END_EMAIL_${Date.now().toString(36)}`;
218
177
  return await SH`msmtp ${params.to} <<'${delim}'
219
178
  To: ${to}
220
179
  Subject: ${subject}
@@ -226,174 +185,80 @@ ${delim}
226
185
  );
227
186
 
228
187
  tools.add(
229
- 'open_link',
230
- 'Open URL/file with xdg-open.',
231
- {
232
- type: 'object',
233
- properties: {
234
- url: { type: 'string', description: 'URL or file path' }
235
- },
236
- required: ['url']
237
- },
238
- async (params) => {
239
- let url = guessOverEscaping(params.url?.trim());
240
- return await SH`xdg-open ${[url]}`.run();
241
- }
188
+ 'open_link', 'Open URL/file with xdg-open.', { type: 'object', properties: { url: { type: 'string' } }, required: ['url'] },
189
+ async (params) => await SH`xdg-open ${[guessOverEscaping(params.url)]}`.run()
242
190
  );
243
191
 
244
192
  tools.add(
245
- 'execute_remote_script',
246
- 'Run bash on remote via SSH. Supports timeout to prevent hangs.',
193
+ 'execute_remote_script', `Run bash on remote via SSH. ${SSH_EP}`,
247
194
  {
248
195
  type: 'object',
249
196
  properties: {
250
- url: { type: 'string', description: 'ssh://user@host[:port]' },
251
- script: { type: 'string', description: 'Raw script' },
252
- timeout: {
253
- type: 'number',
254
- default: 30,
255
- description: 'Max execution time in seconds (default 30). Uses @j-o-r/sh timeout (ms) with SIGTERM on SSH process expiry.'
256
- }
197
+ url: { type: 'string', description: `ssh://user@host[:port] default: ${SSH_EP}` },
198
+ script: { type: 'string' },
199
+ timeout: { type: 'number', default: 30 }
257
200
  },
258
201
  required: ['url', 'script']
259
202
  },
260
203
  async (params) => {
261
204
  let { url, script } = params;
205
+ if (!url || url === '') url = SSH_EP;
262
206
  url = guessOverEscaping(url);
263
207
  script = guessOverEscaping(script);
264
-
265
- const timeoutSec = Number(params.timeout ?? 30);
266
- if (isNaN(timeoutSec) || timeoutSec <= 0) throw new Error('Invalid timeout');
267
- const timeoutMs = timeoutSec * 1000;
208
+ const timeoutMs = (Number(params.timeout ?? 30)) * 1000;
268
209
  if (!url.startsWith('ssh://')) throw new Error('ssh://user@host[:port]');
269
210
  const withoutProto = url.slice(6);
270
211
  const parts = withoutProto.split(':');
271
212
  let port = 22, userHost = withoutProto;
272
213
  if (parts.length > 1) { userHost = parts[0]; port = parseInt(parts[1]); }
273
214
  const [user, host] = userHost.split('@');
274
- if (!user || !host) throw new Error('Invalid SSH URL');
275
215
  return await SH`ssh -p ${port} ${user}@${host} bash`.options({ timeout: timeoutMs }).run(script);
276
216
  }
277
217
  );
278
218
 
279
219
  tools.add(
280
- 'history_search',
281
- 'Search/list chat sessions in .cache/.',
282
- {
283
- type: 'object',
284
- properties: {
285
- query: { type: 'string', description: 'Query/regex or empty to list' }
286
- },
287
- required: []
288
- },
220
+ 'history_search', 'Search/list chat sessions in .cache/.',
221
+ { type: 'object', properties: { query: { type: 'string' } } },
289
222
  async (params) => {
290
223
  if (typeof params.query === 'string' && params.query.trim()) {
291
- const q = guessOverEscaping(params.query);
292
- return await SH`${searchSessionsSh} "${bashEscape(q)}"`.run();
224
+ return await SH`${searchSessionsSh} "${bashEscape(guessOverEscaping(params.query))}"`.run();
293
225
  }
294
226
  return await SH`${listSessionsSh}`.run();
295
227
  }
296
228
  );
297
229
 
298
230
  tools.add(
299
- 'read_file',
300
- 'Read file from CWD (relative path only).',
301
- {
302
- type: 'object',
303
- properties: {
304
- file: { type: 'string', description: `Relative path. cwd: ${user.cwd}` }
305
- },
306
- required: ['file']
307
- },
231
+ 'read_file', 'Read file from CWD (relative path only).',
232
+ { type: 'object', properties: { file: { type: 'string' } }, required: ['file'] },
308
233
  async (params) => {
309
234
  let file = guessOverEscaping(params.file?.trim());
310
- if (typeof file !== 'string' || !file || file.startsWith('/') || file.includes('..') || file.includes('\\\\')) {
311
- throw new Error('Relative CWD path only (no /, .., \\\\).');
312
- }
313
- const resolved = path.resolve(process.cwd(), file);
314
- if (!resolved.startsWith(process.cwd())) throw new Error('Escapes CWD.');
315
- return await fs.readFile(resolved, 'utf8');
235
+ if (!file || file.startsWith('/') || file.includes('..')) throw new Error('Relative CWD path only');
236
+ return await fs.readFile(path.resolve(process.cwd(), file), 'utf8');
316
237
  }
317
238
  );
318
239
 
319
240
  tools.add(
320
- 'write_file',
321
- 'Write/validate file in CWD. Auto-syntax check + JS fix + chmod.',
322
- {
323
- type: 'object',
324
- properties: {
325
- file: { type: 'string', description: `Relative path. cwd: ${user.cwd}` },
326
- content: { type: 'string', description: 'Raw content verbatim (no escaping).' }
327
- },
328
- required: ['file', 'content']
329
- },
241
+ 'write_file', 'Write/validate file in CWD.',
242
+ { type: 'object', properties: { file: { type: 'string' }, content: { type: 'string' } }, required: ['file', 'content'] },
330
243
  async (params) => {
331
- let file = guessOverEscaping(params.file?.trim());
332
- let content = guessOverEscaping(params.content ?? '');
333
- if (typeof file !== 'string' || !file || file.startsWith('/') || file.includes('..') || file.includes('\\\\')) {
334
- throw new Error('Relative CWD path only.');
335
- }
336
- const resolved = path.resolve(process.cwd(), file);
337
- if (!resolved.startsWith(process.cwd())) throw new Error('Escapes CWD.');
338
- const dir = path.dirname(resolved);
339
- const ext = path.extname(file);
340
- let finalContent = content, validationMsg = '';
341
-
342
- const temp1 = path.join(dir, `temp_${Date.now()}_${Math.random().toString(36).slice(2, 6)}${ext || '.tmp'}`);
343
- await fs.writeFile(temp1, content, 'utf8');
344
-
345
- try {
346
- await SH`${syntaxCheckSh} ${[temp1]}`.run();
347
- validationMsg = ' ✓ Syntax OK';
348
- } catch (e) {
349
- if (!['.js', '.mjs'].includes(ext)) {
350
- await fs.unlink(temp1).catch(() => { });
351
- throw new Error(`Syntax error: ${e.message}`);
352
- }
353
- let fixed = content.replace(/\\\\`/g, '\\`').replace(/\\\`/g, '`').replace(/\\`/g, '`').replace(/\\\$/g, '$').replace(/\\\${/g, '${');
354
- const temp2 = path.join(dir, `temp_fix_${Date.now()}_${Math.random().toString(36).slice(2, 6)}.js`);
355
- await fs.writeFile(temp2, fixed, 'utf8');
356
- try {
357
- await SH`${syntaxCheckSh} ${[temp2]}`.run();
358
- finalContent = fixed;
359
- await fs.rename(temp2, resolved);
360
- await fs.unlink(temp1).catch(() => { });
361
- validationMsg = ' ✓ Fixed JS';
362
- } catch {
363
- await fs.unlink(temp1).catch(() => { });
364
- await fs.unlink(temp2).catch(() => { });
365
- throw new Error(`Syntax error (fix failed): ${e.message}`);
366
- }
367
- }
368
-
369
- if (validationMsg === ' ✓ Syntax OK') await fs.rename(temp1, resolved);
370
-
371
- if (finalContent.startsWith('#!')) {
372
- await SH`chmod +x ${[resolved]}`.run();
373
- validationMsg += ' ✓ +x';
374
- }
375
-
376
- return `Wrote ${file} (${Buffer.byteLength(finalContent, 'utf8')} bytes).${validationMsg}`;
244
+ let fileParam = guessOverEscaping(params.file?.trim());
245
+ let content = guessOverEscaping(params.content || '');
246
+ if (!fileParam || fileParam.startsWith('/') || fileParam.includes('..')) throw new Error('Relative CWD path only');
247
+ const resolved = path.resolve(process.cwd(), fileParam);
248
+ await fs.mkdir(path.dirname(resolved), { recursive: true });
249
+ await fs.writeFile(resolved, content, 'utf8');
250
+ return `Wrote ${fileParam} (${Buffer.byteLength(content, 'utf8')} bytes).`;
377
251
  }
378
252
  );
379
253
 
380
254
  tools.add(
381
- 'syntax_check',
382
- 'Syntax validate file via utils/syntax_check.sh.',
383
- {
384
- type: 'object',
385
- properties: {
386
- file: { type: 'string', description: 'Relative CWD path' }
387
- },
388
- required: ['file']
389
- },
255
+ 'syntax_check', 'Syntax validate file via utils/syntax_check.sh.',
256
+ { type: 'object', properties: { file: { type: 'string' } }, required: ['file'] },
390
257
  async (params) => {
391
258
  const file = guessOverEscaping(params.file?.trim());
392
- if (typeof file !== 'string' || !file) throw new Error('Relative path required.');
393
259
  const resolved = path.resolve(process.cwd(), file);
394
- if (!resolved.startsWith(process.cwd())) throw new Error('Escapes CWD.');
395
- return await SH`${syntaxCheckSh} ${[resolved]}`.run();
260
+ return await SH`${syntaxCheckSh} ${resolved}`.run() || 'Syntax OK';
396
261
  }
397
262
  );
398
263
 
399
- export default tools;
264
+ export default tools;
package/lib/index.js CHANGED
@@ -2,7 +2,9 @@ import {request as gpt} from './API/openai.com/reponses/text.js';
2
2
  import {request as xai} from './API/x.ai/responses.js';
3
3
  import {request as claude} from './API/anthropic.com/text.js';
4
4
  import {request as brave} from './API/brave.com/search.js';
5
-
5
+ import minimax from './API/minimax/index.js';
6
+ import stability from './API/stability.ai/index.js';
7
+ import xai from './API/x.ai/index.js';
6
8
  import { env, GLOBAL } from './fafs.js';
7
9
  import ToolSet from './ToolSet.js';
8
10
  import AgentServer from './AgentServer.js';
@@ -23,6 +25,9 @@ const API = {
23
25
  search: {
24
26
  brave
25
27
  },
28
+ minimax,
29
+ stability,
30
+ xai
26
31
  }
27
32
  export {
28
33
  AgentManager,
@@ -38,3 +43,6 @@ export {
38
43
  wsCli,
39
44
  wsIO
40
45
  };
46
+
47
+ // Export the dedicated CDN toolset
48
+ export { default as CdnToolset } from './CdnToolset.js';
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@j-o-r/hello-dave",
3
3
  "type": "module",
4
- "version": "0.0.9",
5
- "description": "ESM toolkit for building AI agents with unified access to Grok (XAI), OpenAI, and Anthropic endpoints",
4
+ "version": "0.1.0",
5
+ "description": "ESM toolkit for building AI agents, CLI xai coding agent and unified access to Grok (XAI), OpenAI, and Anthropic endpoints, music, image and video creation toolsets from minimax, stability and x.ai.",
6
6
  "main": "./lib/index.js",
7
7
  "types": "./types/index.d.ts",
8
8
  "typesVersions": {
@@ -0,0 +1,3 @@
1
+ export default tools;
2
+ declare const tools: ToolSet;
3
+ import ToolSet from '../../ToolSet.js';
@@ -0,0 +1,3 @@
1
+ export default tools;
2
+ declare const tools: ToolSet;
3
+ import ToolSet from '../../ToolSet.js';
@@ -0,0 +1,3 @@
1
+ export default tools;
2
+ declare const tools: ToolSet;
3
+ import ToolSet from '../../ToolSet.js';
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Get authentication headers for Minimax API.
3
+ *
4
+ * @returns {Object} Headers object with Authorization Bearer token.
5
+ * @throws {Error} If MINIMAX_API_KEY environment variable is not set.
6
+ */
7
+ export function getHeaders(): Object;
8
+ /**
9
+ * Saves image data (either URL or base64) to a local temporary file.
10
+ * Handles both `response_format: 'url'` and `response_format: 'base64'`.
11
+ * Supports data URL prefix for base64.
12
+ *
13
+ * @param {string} imageData - Either a URL or a base64-encoded string (with or without data: prefix).
14
+ * @param {string} [filenamePrefix='minimax-image'] - Prefix for the local filename.
15
+ * @param {number} [index=0] - Index for multiple images to avoid filename collisions.
16
+ * @returns {Promise<string>} Absolute path to the saved local file.
17
+ */
18
+ export function saveImageToLocal(imageData: string, filenamePrefix?: string, index?: number): Promise<string>;
19
+ /**
20
+ * Core image generation request (supports both Text-to-Image and Image-to-Image).
21
+ *
22
+ * Fully implements the official Minimax Image Generation API
23
+ * as documented in `lib/API/minimax/image.generation.md` and `image.to.image.md`.
24
+ *
25
+ * Uses the single endpoint `/v1/image_generation`.
26
+ *
27
+ * Supports all models, parameters, and response formats.
28
+ *
29
+ * @param {string} prompt - Text description of the image, max 1500 characters.
30
+ * @param {Object} [options] - All available options from the official spec.
31
+ *
32
+ * @param {string} [options.model='image-01'] - Model to use.
33
+ * Supported values:
34
+ * - 'image-01' (default, text-to-image and img2img)
35
+ * - 'image-01-live' (for image-to-image)
36
+ *
37
+ * @param {string} [options.aspect_ratio='1:1'] - Image aspect ratio.
38
+ * Options: '1:1', '16:9', '4:3', '3:2', '2:3', '3:4', '9:16', '21:9'
39
+ *
40
+ * @param {number} [options.width] - Image width in px (512-2048, divisible by 8).
41
+ * Only effective for model 'image-01'. aspect_ratio takes priority if both provided.
42
+ *
43
+ * @param {number} [options.height] - Image height in px (same rules as width).
44
+ *
45
+ * @param {string} [options.response_format='url'] - 'url' or 'base64'.
46
+ * Default is `'url'` (user preference).
47
+ * ⚠️ `url` links expire after 24 hours.
48
+ *
49
+ * @param {number} [options.seed] - Random seed for reproducibility.
50
+ *
51
+ * @param {number} [options.n=1] - Number of images to generate (1-9).
52
+ *
53
+ * @param {boolean} [options.prompt_optimizer=false] - Enable automatic prompt optimization.
54
+ *
55
+ * @param {Array<Object>} [options.subject_reference] - For Image-to-Image.
56
+ * Array of subject references. Currently supports:
57
+ * - { type: 'character', image_file: 'https://...' or 'data:image/...;base64,...' }
58
+ *
59
+ * @param {Object} [options.extra] - Any additional parameters not yet documented.
60
+ *
61
+ * @returns {Promise<{
62
+ * image_urls: string[], // Array from data.image_urls (if url format)
63
+ * image_base64: string[], // Array from data.image_base64 (if base64 format)
64
+ * local_paths: string[], // Absolute paths to saved files
65
+ * metadata: Object, // { success_count, failed_count }
66
+ * id: string, // Trace ID
67
+ * duration: number, // API call duration in milliseconds
68
+ * raw: object // Full raw response
69
+ * }>}
70
+ *
71
+ * @example
72
+ * // Text-to-Image (basic)
73
+ * const result = await requestImage("A serene mountain landscape at sunset", {
74
+ * model: "image-01",
75
+ * aspect_ratio: "16:9",
76
+ * n: 2
77
+ * });
78
+ *
79
+ * @example
80
+ * // Image-to-Image
81
+ * const result = await requestImage("A girl looking into the distance", {
82
+ * model: "image-01",
83
+ * subject_reference: [{
84
+ * type: "character",
85
+ * image_file: "https://example.com/portrait.jpg"
86
+ * }],
87
+ * n: 1
88
+ * });
89
+ */
90
+ export function requestImage(prompt: string, options?: {
91
+ model?: string | undefined;
92
+ aspect_ratio?: string | undefined;
93
+ width?: number | undefined;
94
+ height?: number | undefined;
95
+ response_format?: string | undefined;
96
+ seed?: number | undefined;
97
+ n?: number | undefined;
98
+ prompt_optimizer?: boolean | undefined;
99
+ subject_reference?: Object[] | undefined;
100
+ extra?: Object | undefined;
101
+ }): Promise<{
102
+ image_urls: string[];
103
+ image_base64: string[];
104
+ local_paths: string[];
105
+ metadata: Object;
106
+ id: string;
107
+ duration: number;
108
+ raw: object;
109
+ }>;
@@ -0,0 +1,15 @@
1
+ declare namespace _default {
2
+ export { music };
3
+ export { musicToolset };
4
+ export { video };
5
+ export { videoToolset };
6
+ export { image };
7
+ export { imageToolset };
8
+ }
9
+ export default _default;
10
+ import * as music from './music.js';
11
+ import musicToolset from './MusicToolset.js';
12
+ import * as video from './video.js';
13
+ import videoToolset from './VideoToolset.js';
14
+ import * as image from './image.js';
15
+ import imageToolset from './ImageToolset.js';
@@ -0,0 +1,46 @@
1
+ export function getHeaders(): {
2
+ 'Content-Type': string;
3
+ Authorization: string;
4
+ };
5
+ export function saveAudioToLocal(audioData: any, filenamePrefix?: string): Promise<any>;
6
+ export function createMusic(prompt: any, options?: {}): Promise<{
7
+ audio_url: any;
8
+ local_path: any;
9
+ duration: number;
10
+ raw: any;
11
+ }>;
12
+ export function changeMusic(prompt: any, options?: {}): Promise<{
13
+ audio_url: any;
14
+ local_path: any;
15
+ duration: number;
16
+ raw: any;
17
+ }>;
18
+ export function analyzeMusic(audioUrl: any, options?: {}): Promise<{
19
+ cover_feature_id: any;
20
+ formatted_lyrics: any;
21
+ structure_result: any;
22
+ audio_duration: any;
23
+ trace_id: any;
24
+ raw: any;
25
+ }>;
26
+ /**
27
+ * Generate complete song lyrics or edit/continue existing lyrics.
28
+ *
29
+ * @param {string} prompt - Theme, style, or editing instruction.
30
+ * @param {Object} [options]
31
+ * @param {'write_full_song'|'edit'} [options.mode='write_full_song']
32
+ * @param {string} [options.lyrics] - Existing lyrics (required for edit mode)
33
+ * @param {string} [options.title]
34
+ *
35
+ * @returns {Promise<{song_title: string, style_tags: string, lyrics: string, raw: object}>}
36
+ */
37
+ export function generateLyrics(prompt: string, options?: {
38
+ mode?: "write_full_song" | "edit" | undefined;
39
+ lyrics?: string | undefined;
40
+ title?: string | undefined;
41
+ }): Promise<{
42
+ song_title: string;
43
+ style_tags: string;
44
+ lyrics: string;
45
+ raw: object;
46
+ }>;