@j-o-r/hello-dave 0.1.1 → 0.1.5
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/CHANGELOG.md +42 -25
- package/README.md +81 -221
- package/TODO.md +173 -35
- package/agents/agent_creator.js +105 -0
- package/agents/agent_creator.prompt.md +371 -0
- package/agents/ask_agent.js +64 -127
- package/agents/claude_agent.js +68 -0
- package/agents/code_agent.js +55 -135
- package/agents/code_agent.prompt.md +50 -0
- package/agents/echo_agent.js +76 -0
- package/agents/financial_expert.js +75 -0
- package/agents/gpt_agent.js +52 -103
- package/agents/gpt_code.js +81 -0
- package/agents/grok_agent.js +58 -114
- package/agents/minimax_agent.js +92 -0
- package/agents/mureka_agent.js +77 -0
- package/agents/planner_agent.js +172 -0
- package/agents/stability_agent.js +87 -0
- package/agents/test_agent.js +75 -157
- package/agents/weather_agent.js +73 -0
- package/agents/workflow_agent.js +189 -0
- package/bin/dave.js +436 -184
- package/docs/bin-dave.md +85 -35
- package/docs/cdn-ssh.md +100 -0
- package/docs/creating-agents.md +301 -0
- package/docs/creating-toolsets.md +336 -0
- package/docs/docs-organization.md +48 -0
- package/docs/project-overview.md +86 -51
- package/lib/API/elevenlabs.io/music.compose.md +441 -0
- package/lib/API/elevenlabs.io/music.create-composition-plan.md +370 -0
- package/lib/API/elevenlabs.io/music.stream.md +425 -0
- package/lib/API/lalal.ai/lalal.js +445 -0
- package/lib/API/lalal.ai/openapi.json +2614 -0
- package/lib/API/minimax/ImageToolset.js +82 -37
- package/lib/API/minimax/MusicToolset.js +125 -79
- package/lib/API/minimax/VideoToolset.js +170 -167
- package/lib/API/minimax/image.js +5 -1
- package/lib/API/minimax/music.js +210 -23
- package/lib/API/minimax/video.js +242 -53
- package/lib/API/mureka/MusicToolset.js +646 -0
- package/lib/API/mureka/README.md +41 -0
- package/lib/API/mureka/index.js +7 -0
- package/lib/API/mureka/music.js +658 -0
- package/lib/API/openai.com/index.js +7 -0
- package/lib/API/openai.com/{reponses/text.js → responses.js} +64 -18
- package/lib/API/openai.com/video.create.character.md +40 -0
- package/lib/API/openai.com/video.create.md +219 -0
- package/lib/API/openai.com/video.delete.md +44 -0
- package/lib/API/openai.com/video.download.md +31 -0
- package/lib/API/openai.com/video.edit.md +155 -0
- package/lib/API/openai.com/video.extend.md +166 -0
- package/lib/API/openai.com/video.fetch.character.md +43 -0
- package/lib/API/openai.com/video.js +784 -0
- package/lib/API/openai.com/video.list.md +201 -0
- package/lib/API/openai.com/video.remix.md +175 -0
- package/lib/API/openai.com/video.retrieve.md +139 -0
- package/lib/API/openai.com/videoToolset.js +616 -0
- package/lib/API/stability.ai/ImageToolset.js +131 -40
- package/lib/API/stability.ai/MusicToolset.js +79 -47
- package/lib/API/stability.ai/audio.js +63 -131
- package/lib/API/x.ai/chat.responses.md +1040 -0
- package/lib/API/x.ai/image.js +229 -59
- package/lib/API/x.ai/imageToolset.js +376 -0
- package/lib/API/x.ai/index.js +1 -1
- package/lib/API/x.ai/responses.js +9 -18
- package/lib/Agent.js +271 -0
- package/lib/Agent.js.old +284 -0
- package/lib/AgentLauncher.js +593 -0
- package/lib/Cli.js +87 -13
- package/lib/Prompt.js +23 -1
- package/lib/Session.js +5 -4
- package/lib/ToolSet.js +102 -6
- package/lib/agentLoader.js +369 -0
- package/lib/cdn.js +67 -231
- package/lib/{CdnToolset.js → cdnToolset.js} +47 -64
- package/lib/defaultToolsets.js +43 -0
- package/lib/fafs.js +1 -1
- package/lib/genericToolset.js +442 -119
- package/lib/handOffToolset.js +179 -0
- package/lib/index.js +34 -27
- package/lib/toolsetLoader.js +248 -0
- package/package.json +10 -4
- package/types/API/lalal.ai/lalal.d.ts +116 -0
- package/types/API/minimax/image.d.ts +2 -1
- package/types/API/minimax/music.d.ts +189 -26
- package/types/API/minimax/video.d.ts +100 -31
- package/types/API/mureka/index.d.ts +7 -0
- package/types/API/mureka/music.d.ts +472 -0
- package/types/API/openai.com/index.d.ts +7 -0
- package/types/API/openai.com/{reponses/text.d.ts → responses.d.ts} +11 -11
- package/types/API/openai.com/video.d.ts +409 -0
- package/types/API/openai.com/videoToolset.d.ts +24 -0
- package/types/API/stability.ai/audio.d.ts +14 -103
- package/types/API/stability.ai/image.d.ts +2 -2
- package/types/API/x.ai/image.d.ts +138 -26
- package/types/API/x.ai/imageToolset.d.ts +3 -0
- package/types/API/x.ai/index.d.ts +1 -1
- package/types/API/x.ai/responses.d.ts +4 -4
- package/types/Agent.d.ts +123 -0
- package/types/AgentLauncher.d.ts +250 -0
- package/types/Cli.d.ts +28 -8
- package/types/Prompt.d.ts +23 -5
- package/types/Session.d.ts +1 -1
- package/types/ToolSet.d.ts +10 -0
- package/types/agentLoader.d.ts +78 -0
- package/types/cdn.d.ts +15 -90
- package/types/defaultToolsets.d.ts +9 -0
- package/types/fafs.d.ts +1 -1
- package/types/genericToolset.d.ts +1 -1
- package/types/handOffToolset.d.ts +28 -0
- package/types/index.d.ts +19 -17
- package/types/toolsetLoader.d.ts +114 -0
- package/utils/format_log.js +101 -23
- package/utils/launch_agent.js +18 -0
- package/utils/list_sessions.sh +13 -5
- package/utils/search_sessions.sh +65 -29
- package/utils/toolsets.js +33 -0
- package/README.md.bak.1779452127 +0 -240
- package/agents/codeserver.sh +0 -47
- package/agents/daisy_agent.js +0 -173
- package/agents/docs_agent.js +0 -148
- package/agents/memory_agent.js +0 -263
- package/agents/minimax.js +0 -173
- package/agents/npm_agent.js +0 -202
- package/agents/prompt_agent.js +0 -133
- package/agents/readme_agent.js +0 -148
- package/agents/spawn_agent.js +0 -160
- package/agents/stability.js +0 -173
- package/agents/todo_agent.js +0 -175
- package/bin/codeDave +0 -58
- package/docs/agent-dave-websocket-protocol.md +0 -180
- package/docs/agent-manager.md +0 -244
- package/docs/codeserver-pattern.md +0 -191
- package/docs/generic-toolset.md +0 -326
- package/docs/howtos/agent-networking.md +0 -253
- package/docs/howtos/spawn-agents.md.bak +0 -200
- package/docs/howtos/spawn-agents.md.bak_new +0 -200
- package/docs/multi-agent-clusters.md +0 -265
- package/docs/music-toolsets.md +0 -137
- package/docs/path-resolution-best-practices.md +0 -104
- package/docs/plans/minimax-music-generation.md +0 -80
- package/docs/plans/unified-agent-architecture.md +0 -146
- package/docs/plans/websocket-streaming-plan.md.bak +0 -317
- package/docs/prompt/spawn_agent.md +0 -175
- package/docs/prompt/spawn_agent.md.bak +0 -201
- package/docs/prompt/task_clarification_and_documentation.md +0 -35
- package/docs/prompt-class.md +0 -141
- package/docs/todo-archive-infra-2026-04-21.md +0 -15
- package/docs/todo-archive-v0.0.8.md +0 -1
- package/docs/todo-archive-v0.1.0.md +0 -32
- package/docs/todo-archive.md +0 -44
- package/docs/tools-syntax-validation.md +0 -121
- package/docs/toolset.md +0 -164
- package/docs/xai-responses.md +0 -111
- package/docs/xai_collections.md +0 -106
- package/lib/API/x.ai/ImageToolset.js +0 -165
- package/lib/API/x.ai/text.js +0 -415
- package/lib/AgentClient.js +0 -248
- package/lib/AgentManager.js +0 -245
- package/lib/AgentServer.js +0 -404
- package/lib/wsCli.js +0 -287
- package/lib/wsIO.js +0 -90
- package/types/API/x.ai/text.d.ts +0 -286
- package/types/AgentClient.d.ts +0 -109
- package/types/AgentManager.d.ts +0 -100
- package/types/AgentServer.d.ts +0 -89
- package/types/wsCli.d.ts +0 -17
- package/types/wsIO.d.ts +0 -30
- package/utils/test.sh +0 -46
- /package/docs/{suggestions.md → _notes/token-counts.md} +0 -0
- /package/lib/API/openai.com/{reponses/MESSAGES.md → MESSAGES.md} +0 -0
- /package/types/API/{x.ai/ImageToolset.d.ts → mureka/MusicToolset.d.ts} +0 -0
- /package/types/{CdnToolset.d.ts → cdnToolset.d.ts} +0 -0
package/bin/dave.js
CHANGED
|
@@ -1,194 +1,446 @@
|
|
|
1
1
|
#!/usr/bin/env -S node
|
|
2
|
+
import fs from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
|
-
import cli from '@j-o-r/cli';
|
|
4
|
-
import { AgentManager, wsCli, wsIO } from '@j-o-r/hello-dave';
|
|
5
|
-
import { SH, parseArgs, readIn, bashEscape } from '@j-o-r/sh';
|
|
6
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import cli from '@j-o-r/cli';
|
|
6
|
+
import { SH, parseArgs, readIn } from '@j-o-r/sh';
|
|
7
|
+
import { AgentLauncher, listToolsets, renderToolsetList, renderToolsetsHelp } from '@j-o-r/hello-dave';
|
|
7
8
|
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = path.dirname(__filename);
|
|
10
|
-
const pipedInput = await readIn();
|
|
11
|
-
const args = parseArgs();
|
|
12
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Convert a command path to the public CLI command name.
|
|
14
|
+
*
|
|
15
|
+
* @param {string | undefined} commandPath Path used to invoke the command.
|
|
16
|
+
* @param {string} fallback Fallback command name.
|
|
17
|
+
* @returns {string} Extensionless command basename.
|
|
18
|
+
*/
|
|
19
|
+
function commandNameFromPath(commandPath, fallback) {
|
|
20
|
+
if (typeof commandPath !== 'string' || commandPath.trim().length === 0) return fallback;
|
|
21
|
+
const base = path.basename(commandPath);
|
|
22
|
+
return base.endsWith('.js') ? base.slice(0, -3) : base;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Find the nearest package.json by walking upward from a start directory.
|
|
27
|
+
*
|
|
28
|
+
* @param {string} startDir Directory where the search starts.
|
|
29
|
+
* @returns {string | null} Absolute package.json path, or null when not found.
|
|
30
|
+
*/
|
|
31
|
+
function findNearestPackageJson(startDir) {
|
|
32
|
+
let dir = path.resolve(startDir);
|
|
33
|
+
while (true) {
|
|
34
|
+
const candidate = path.join(dir, 'package.json');
|
|
35
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
36
|
+
const parent = path.dirname(dir);
|
|
37
|
+
if (parent === dir) return null;
|
|
38
|
+
dir = parent;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Read the npm package name for the package that owns this bin script.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} startDir Directory inside the owning package.
|
|
46
|
+
* @param {string} fallback Fallback package name.
|
|
47
|
+
* @returns {string} npm package name.
|
|
48
|
+
*/
|
|
49
|
+
function packageNameFromNearestPackageJson(startDir, fallback) {
|
|
50
|
+
const packageJsonPath = findNearestPackageJson(startDir);
|
|
51
|
+
if (!packageJsonPath) return fallback;
|
|
52
|
+
try {
|
|
53
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
54
|
+
return typeof pkg.name === 'string' && pkg.name.trim().length > 0 ? pkg.name.trim() : fallback;
|
|
55
|
+
} catch {
|
|
56
|
+
return fallback;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Resolve the absolute path to an installed module entry point.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} specifier Package import specifier.
|
|
64
|
+
* @returns {string | null} Absolute module entry path, or null when unavailable.
|
|
65
|
+
*/
|
|
66
|
+
function moduleEntryPath(specifier) {
|
|
67
|
+
try {
|
|
68
|
+
return fileURLToPath(import.meta.resolve(specifier));
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Resolve a utility script shipped by @j-o-r/hello-dave.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} scriptName Utility script basename, e.g. list_sessions.sh.
|
|
78
|
+
* @returns {string} Absolute utility script path.
|
|
79
|
+
*/
|
|
80
|
+
function helloDaveUtilityPath(scriptName) {
|
|
81
|
+
const moduleEntry = moduleEntryPath('@j-o-r/hello-dave');
|
|
82
|
+
const candidates = [
|
|
83
|
+
moduleEntry ? path.resolve(path.dirname(moduleEntry), '..', 'utils', scriptName) : null,
|
|
84
|
+
path.resolve(__dirname, '..', 'utils', scriptName)
|
|
85
|
+
].filter(Boolean);
|
|
86
|
+
|
|
87
|
+
for (const candidate of candidates) {
|
|
88
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
throw new Error(`Cannot find @j-o-r/hello-dave utility script: ${scriptName}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Capitalize a CLI command name for greeting text.
|
|
96
|
+
*
|
|
97
|
+
* @param {string} name CLI command name.
|
|
98
|
+
* @returns {string} Display name.
|
|
99
|
+
*/
|
|
100
|
+
function titleName(name) {
|
|
101
|
+
return name.length > 0 ? name[0].toUpperCase() + name.slice(1) : name;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Execute a utility script through @j-o-r/sh and return stdout/stderr.
|
|
106
|
+
*
|
|
107
|
+
* @param {string} file Absolute executable file path.
|
|
108
|
+
* @param {string[]} [args] Arguments passed safely as command arguments.
|
|
109
|
+
* @returns {Promise<string>} Process output.
|
|
110
|
+
*/
|
|
111
|
+
async function runExecutable(file, args = []) {
|
|
112
|
+
return await SH`${[file, ...args]} 2>&1`.options({ maxBuffer: 64 * 1024 * 1024 }).run();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Ask a yes/no question through @j-o-r/cli, but never block non-interactive stdin.
|
|
117
|
+
*
|
|
118
|
+
* @param {string} question Prompt text.
|
|
119
|
+
* @returns {Promise<boolean>} Whether the user answered yes.
|
|
120
|
+
*/
|
|
121
|
+
async function yesNo(question) {
|
|
122
|
+
if (!process.stdin.isTTY) return false;
|
|
123
|
+
return await cli.yesNo(question);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Print all discoverable agents in the standard CLI format.
|
|
128
|
+
*
|
|
129
|
+
* @param {Array<{name: string, path: string, desc?: string}>} agents Discoverable agents.
|
|
130
|
+
* @returns {void}
|
|
131
|
+
*/
|
|
132
|
+
function printAgentList(agents) {
|
|
133
|
+
if (agents.length === 0) {
|
|
134
|
+
console.log(' (no agents found)');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
for (const agent of agents) {
|
|
139
|
+
console.log(` ${agent.name}`);
|
|
140
|
+
console.log(` path: ${agent.path}`);
|
|
141
|
+
const desc = typeof agent.desc === 'string' && agent.desc.trim()
|
|
142
|
+
? agent.desc.trim().replace(/\s+/g, ' ')
|
|
143
|
+
: '[ERROR]';
|
|
144
|
+
console.log(` desc: ${desc.length > 140 ? desc.slice(0, 137) + '...' : desc}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Build a generic CLI help message.
|
|
150
|
+
*
|
|
151
|
+
* @param {string} cliName Public CLI command name.
|
|
152
|
+
* @param {string} npmPackageName Owning npm package name.
|
|
153
|
+
* @returns {string} Help text.
|
|
154
|
+
*/
|
|
155
|
+
function helpText(cliName, npmPackageName) {
|
|
156
|
+
return `
|
|
157
|
+
Hello, ${titleName(cliName)}.
|
|
158
|
+
|
|
159
|
+
${cliName} — a calm, reliable interface.
|
|
160
|
+
|
|
161
|
+
Usage:
|
|
162
|
+
${cliName} [agent] [message...] # global install: npm install -g ${npmPackageName}
|
|
163
|
+
# then just run: ${cliName} (or ${cliName} --help) — no npx, no long name
|
|
164
|
+
npx ${npmPackageName} [agent] [message...] # without global install
|
|
165
|
+
# (recommended: add a shell alias, e.g. in ~/.zshrc or ~/.bashrc)
|
|
166
|
+
# alias npx${cliName}='npx ${npmPackageName}'
|
|
167
|
+
# then use: npx${cliName} --help
|
|
168
|
+
${cliName} --parameter ...
|
|
169
|
+
|
|
170
|
+
Agent parameters (passed after the agent name):
|
|
171
|
+
Example: ${cliName} ask_agent --info
|
|
172
|
+
|
|
173
|
+
--info
|
|
174
|
+
Show information about the loaded agent (name, session, prompt, etc.).
|
|
175
|
+
|
|
176
|
+
--help
|
|
177
|
+
Show help specific to that agent.
|
|
178
|
+
|
|
179
|
+
[message...]
|
|
180
|
+
Send a one-shot message to the agent.
|
|
181
|
+
If no message is provided (and no piped input), starts the interactive CLI.
|
|
182
|
+
|
|
183
|
+
(no extra args)
|
|
184
|
+
Start the interactive CLI for the agent.
|
|
185
|
+
|
|
186
|
+
Built-in ${cliName} commands / flags:
|
|
187
|
+
--help
|
|
188
|
+
Show this help message.
|
|
189
|
+
|
|
190
|
+
--clear
|
|
191
|
+
Clear the entire session cache.
|
|
192
|
+
|
|
193
|
+
--search "[query]"
|
|
194
|
+
Search through saved session history.
|
|
195
|
+
|
|
196
|
+
--list
|
|
197
|
+
List recent sessions.
|
|
198
|
+
|
|
199
|
+
--inspect "[log.ndjson]" [--last 20|-n 20]
|
|
200
|
+
Pretty-print / inspect a session log file. Defaults to the last 20 events.
|
|
201
|
+
|
|
202
|
+
--list-agents
|
|
203
|
+
List all discoverable agents (via AgentLauncher).
|
|
204
|
+
|
|
205
|
+
--toolsets [filter...] [--json]
|
|
206
|
+
List toolsets exposed via API.toolset.
|
|
207
|
+
Filters match provider (e.g. minimax), type (e.g. image, music), or path.
|
|
208
|
+
Examples:
|
|
209
|
+
${cliName} --toolsets
|
|
210
|
+
${cliName} --toolsets image
|
|
211
|
+
${cliName} --toolsets minimax music
|
|
212
|
+
${cliName} --toolsets --json
|
|
213
|
+
|
|
214
|
+
Running agents:
|
|
215
|
+
Bare (non -flag) words are always treated as agent names.
|
|
216
|
+
Project-local agents in ./agents/ take precedence over built-in package agents.
|
|
217
|
+
|
|
218
|
+
Only bare names (as the first argument) are supported.
|
|
219
|
+
|
|
220
|
+
Two main modes:
|
|
221
|
+
|
|
222
|
+
Interactive CLI (no message):
|
|
223
|
+
${cliName} ask_agent
|
|
224
|
+
npx ${npmPackageName} ask_agent (or your npx${cliName} alias)
|
|
225
|
+
|
|
226
|
+
One-shot (message provided or piped input):
|
|
227
|
+
${cliName} code_agent "Refactor lib/Session.js"
|
|
228
|
+
npx ${npmPackageName} code_agent "Refactor lib/Session.js"
|
|
229
|
+
echo "hello" | ${cliName} some_agent
|
|
230
|
+
echo "hello" | npx ${npmPackageName} some_agent
|
|
231
|
+
|
|
232
|
+
Agents are loaded and executed via AgentLauncher (supports one-shot direct calls and interactive CLI).
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Print help and exit.
|
|
238
|
+
*
|
|
239
|
+
* @param {number} exitCode Process exit code.
|
|
240
|
+
* @returns {never}
|
|
241
|
+
*/
|
|
13
242
|
function printHelp(exitCode = 0) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
243
|
+
console.log(helpText(cliName, npmPackageName));
|
|
244
|
+
process.exit(exitCode);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Add piped input as the one-shot agent message when no message argument exists.
|
|
249
|
+
*
|
|
250
|
+
* @param {string} pipedInput Text read from stdin.
|
|
251
|
+
* @returns {void}
|
|
252
|
+
*/
|
|
253
|
+
function appendPipedAgentMessage(pipedInput) {
|
|
254
|
+
const currentArgs = process.argv.slice(2);
|
|
255
|
+
const positionals = currentArgs.filter((arg) => !arg.startsWith('--'));
|
|
256
|
+
const hasMessageInArgv = positionals.length > 1;
|
|
257
|
+
const message = pipedInput.replace(/\r?\n$/, '').replace(/\r$/, '').trim();
|
|
258
|
+
|
|
259
|
+
if (!hasMessageInArgv && message.length > 0) {
|
|
260
|
+
process.argv.push(message);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Run a named agent through AgentLauncher.
|
|
266
|
+
*
|
|
267
|
+
* @param {AgentLauncher} launcher Agent launcher instance.
|
|
268
|
+
* @param {string} agentName Agent name from argv.
|
|
269
|
+
* @param {string} pipedInput Text read from stdin.
|
|
270
|
+
* @returns {Promise<void>}
|
|
271
|
+
*/
|
|
272
|
+
async function runAgent(launcher, agentName, pipedInput) {
|
|
273
|
+
try {
|
|
274
|
+
await launcher.load(agentName);
|
|
275
|
+
} catch (err) {
|
|
276
|
+
console.error(`Failed to load agent "${agentName}": ${err.message}`);
|
|
277
|
+
try {
|
|
278
|
+
const agents = await launcher.list();
|
|
279
|
+
if (agents.length > 0) {
|
|
280
|
+
console.log('\nAvailable agents:');
|
|
281
|
+
printAgentList(agents);
|
|
282
|
+
}
|
|
283
|
+
} catch {}
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (process.argv.slice(2).includes('--help')) {
|
|
288
|
+
console.log(`
|
|
289
|
+
Usage: ${cliName} ${agentName} [message...]
|
|
290
|
+
npx ${npmPackageName} ${agentName} [message...]
|
|
291
|
+
${cliName} ${agentName} --info
|
|
292
|
+
${cliName} ${agentName} # starts interactive CLI
|
|
293
|
+
|
|
294
|
+
Loaded via AgentLauncher.
|
|
295
|
+
|
|
296
|
+
Modes:
|
|
297
|
+
${cliName} ${agentName} → interactive CLI session
|
|
298
|
+
${cliName} ${agentName} "your message" → one-shot response
|
|
299
|
+
echo "..." | ${cliName} ${agentName} → one-shot from piped input
|
|
300
|
+
|
|
301
|
+
${cliName} ${agentName} --info
|
|
302
|
+
${cliName} ${agentName} --help
|
|
34
303
|
`);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const history_search = path.resolve(__dirname, '..', 'utils', 'search_sessions.sh');
|
|
59
|
-
if (typeof args.search !== 'string') {
|
|
60
|
-
printHelp(1);
|
|
61
|
-
}
|
|
62
|
-
const res = await SH`${history_search} "${bashEscape(args.search)}"`.run();
|
|
63
|
-
console.log(res);
|
|
64
|
-
process.exit();
|
|
65
|
-
} else if (args.list) {
|
|
66
|
-
const list = path.resolve(__dirname, '..', 'utils', 'list_sessions.sh');
|
|
67
|
-
const res = await SH`${list}`.run();
|
|
68
|
-
console.log(res);
|
|
69
|
-
process.exit();
|
|
70
|
-
} else if (args.inspect) {
|
|
71
|
-
const format = path.resolve(__dirname, '..', 'utils', 'format_log.js');
|
|
72
|
-
if (typeof args.inspect !== 'string') {
|
|
73
|
-
printHelp(1);
|
|
74
|
-
}
|
|
75
|
-
try {
|
|
76
|
-
const res = await SH`${format} "${bashEscape(args.inspect)}"`.run();
|
|
77
|
-
console.log(res);
|
|
78
|
-
} catch (e) {
|
|
79
|
-
console.error(e);
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
} else if (args.ask) {
|
|
83
|
-
let secret = args.secret || '';
|
|
84
|
-
if (args.connect) {
|
|
85
|
-
// Remote mode: same as --connect
|
|
86
|
-
if (typeof pipedInput === 'string' && pipedInput.trim() !== '') {
|
|
87
|
-
// Piped input mode: use wsIO for one-shot actions
|
|
88
|
-
let action, input;
|
|
89
|
-
const trimmed = pipedInput.trim();
|
|
90
|
-
if (trimmed === 'user_info' || trimmed === 'user_reset') {
|
|
91
|
-
action = trimmed;
|
|
92
|
-
input = '';
|
|
93
|
-
} else {
|
|
94
|
-
action = 'user_request';
|
|
95
|
-
input = trimmed;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const response = await wsIO(args.connect, secret, action, input);
|
|
100
|
-
console.log(JSON.stringify(response.content, null, ' '));
|
|
101
|
-
} catch (e) {
|
|
102
|
-
console.error(`Error: ${e.message}`);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
// No piped input: interactive wsCli mode
|
|
107
|
-
wsCli(args.connect, secret);
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
// Local mode
|
|
111
|
-
const name = 'ask_dave';
|
|
112
|
-
const api = 'xai';
|
|
113
|
-
const contextWindow = 1900000;
|
|
114
|
-
const toolsetMode = 'auto';
|
|
115
|
-
/** @type {import('lib/API/x.ai/responses.js').XAIOptions} */
|
|
116
|
-
const options = {
|
|
117
|
-
tools: []
|
|
118
|
-
};
|
|
119
|
-
options.tools.push({ type: 'web_search' });
|
|
120
|
-
options.tools.push({ type: 'x_search' });
|
|
121
|
-
options.model = args.model || 'grok-4.20-reasoning';
|
|
122
|
-
options.temperature = 0.2;
|
|
123
|
-
// options.reasoning = { effort: 'medium', summary: 'auto' };
|
|
124
|
-
|
|
125
|
-
const prompt = `
|
|
126
|
-
Respond briefly and directly, using minimal words. Reason step-by-step first. Focus solely on core point; avoid elaboration or follow-ups. If unclear, ask clarifying questions before proceeding.
|
|
127
|
-
`.trim();
|
|
128
|
-
|
|
129
|
-
const agent = new AgentManager({ name });
|
|
130
|
-
agent.setup({
|
|
131
|
-
prompt,
|
|
132
|
-
api,
|
|
133
|
-
options,
|
|
134
|
-
toolsetMode,
|
|
135
|
-
contextWindow
|
|
136
|
-
});
|
|
137
|
-
agent.addGenericToolcall('open_link');
|
|
138
|
-
agent.addGenericToolcall('send_email');
|
|
139
|
-
agent.addGenericToolcall('history_search');
|
|
140
|
-
|
|
141
|
-
const cliIntro = `
|
|
142
|
-
${name} (${options.model}).
|
|
143
|
-
- context: ${contextWindow}
|
|
144
|
-
`.trim();
|
|
145
|
-
const description = `Ask dave, he knows.`.trim();
|
|
146
|
-
|
|
147
|
-
// Support piped one-shot (like --connect), else interactive CLI
|
|
148
|
-
if (typeof pipedInput === 'string' && pipedInput.trim() !== '') {
|
|
149
|
-
try {
|
|
150
|
-
const response = await agent.directCall(pipedInput.trim());
|
|
151
|
-
console.log(response);
|
|
152
|
-
} catch (e) {
|
|
153
|
-
console.error(`Error: ${e.message}`);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
await agent.start(undefined, undefined, cliIntro, name, description);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
} else if (args.connect) {
|
|
161
|
-
// Pure --connect (no --ask): same logic
|
|
162
|
-
let secret = args.secret || '';
|
|
163
|
-
|
|
164
|
-
if (typeof pipedInput === 'string' && pipedInput.trim() !== '') {
|
|
165
|
-
// Piped input mode: use wsIO for one-shot actions
|
|
166
|
-
let action, input;
|
|
167
|
-
const trimmed = pipedInput.trim();
|
|
168
|
-
if (trimmed === 'user_info' || trimmed === 'user_reset') {
|
|
169
|
-
action = trimmed;
|
|
170
|
-
input = '';
|
|
171
|
-
} else {
|
|
172
|
-
action = 'user_request';
|
|
173
|
-
input = trimmed;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
const response = await wsIO(args.connect, secret, action, input);
|
|
178
|
-
console.log(response.content);
|
|
179
|
-
} catch (e) {
|
|
180
|
-
console.error(`Error: ${e.message}`);
|
|
181
|
-
process.exit(1);
|
|
182
|
-
}
|
|
183
|
-
} else {
|
|
184
|
-
// No piped input: interactive wsCli mode
|
|
185
|
-
wsCli(args.connect, secret);
|
|
186
|
-
}
|
|
187
|
-
} else if (args.code) {
|
|
188
|
-
const port = parseInt(args.code || '8080');
|
|
189
|
-
const secret = (args.secret || '').trim() || '123';
|
|
190
|
-
const server = path.resolve(__dirname, '..', 'examples', 'codeserver.sh');
|
|
191
|
-
const RES = await SH`${server} ${port} ${bashEscape(secret)}`.run();
|
|
192
|
-
console.log(RES);
|
|
193
|
-
process.exit(0);
|
|
304
|
+
const active = launcher.getActiveAgent();
|
|
305
|
+
if (active && typeof active.info === 'function') {
|
|
306
|
+
try {
|
|
307
|
+
console.log(active.info());
|
|
308
|
+
} catch {}
|
|
309
|
+
}
|
|
310
|
+
process.exit(0);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
appendPipedAgentMessage(pipedInput);
|
|
314
|
+
await launcher.run();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Get the log path passed to --inspect.
|
|
319
|
+
*
|
|
320
|
+
* @param {{inspect?: boolean | string, _: string[]}} args Parsed CLI args.
|
|
321
|
+
* @returns {string} Log file path.
|
|
322
|
+
*/
|
|
323
|
+
function inspectFilePath(args) {
|
|
324
|
+
if (typeof args.inspect === 'string') return args.inspect;
|
|
325
|
+
if (Array.isArray(args._) && typeof args._[0] === 'string') return args._[0];
|
|
326
|
+
printHelp(1);
|
|
194
327
|
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Build optional --last arguments forwarded to format_log.js.
|
|
331
|
+
*
|
|
332
|
+
* @param {{last?: boolean | string, n?: boolean | string}} args Parsed CLI args.
|
|
333
|
+
* @returns {string[]} CLI arguments to forward.
|
|
334
|
+
*/
|
|
335
|
+
function inspectLastArgs(args) {
|
|
336
|
+
const value = args.last ?? args.n;
|
|
337
|
+
if (value === undefined) return [];
|
|
338
|
+
if (typeof value !== 'string' || !/^[1-9]\d*$/.test(value)) printHelp(1);
|
|
339
|
+
return ['--last', value];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Build toolset filters from parsed CLI arguments.
|
|
344
|
+
*
|
|
345
|
+
* @param {{toolsets?: boolean | string, _: string[]}} args Parsed CLI args.
|
|
346
|
+
* @returns {string[]} Toolset filters.
|
|
347
|
+
*/
|
|
348
|
+
function toolsetFilters(args) {
|
|
349
|
+
const filters = Array.isArray(args._) ? [...args._] : [];
|
|
350
|
+
return typeof args.toolsets === 'string' ? [args.toolsets, ...filters] : filters;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Run the built-in CLI commands.
|
|
355
|
+
*
|
|
356
|
+
* @param {AgentLauncher} launcher Agent launcher instance.
|
|
357
|
+
* @returns {Promise<void>}
|
|
358
|
+
*/
|
|
359
|
+
async function runBuiltins(launcher) {
|
|
360
|
+
const args = parseArgs(rawArgv);
|
|
361
|
+
const hasCliAction = Object.keys(args).some((key) => BUILTIN_COMMANDS.has(key));
|
|
362
|
+
|
|
363
|
+
if (!hasCliAction) printHelp(1);
|
|
364
|
+
if (args.help && args.toolsets === undefined) printHelp(0);
|
|
365
|
+
|
|
366
|
+
if (args.clear) {
|
|
367
|
+
const script = helloDaveUtilityPath('clear_sessions.sh');
|
|
368
|
+
if (await yesNo('Delete entire cache? (y/n) ')) {
|
|
369
|
+
console.log(script);
|
|
370
|
+
console.log(await runExecutable(script));
|
|
371
|
+
}
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (args.search) {
|
|
376
|
+
if (typeof args.search !== 'string') printHelp(1);
|
|
377
|
+
console.log(await runExecutable(helloDaveUtilityPath('search_sessions.sh'), [args.search]));
|
|
378
|
+
process.exit(0);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (args.list) {
|
|
382
|
+
console.log(await runExecutable(helloDaveUtilityPath('list_sessions.sh')));
|
|
383
|
+
process.exit(0);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (args.inspect) {
|
|
387
|
+
try {
|
|
388
|
+
console.log(await runExecutable(helloDaveUtilityPath('format_log.js'), [
|
|
389
|
+
...inspectLastArgs(args),
|
|
390
|
+
inspectFilePath(args)
|
|
391
|
+
]));
|
|
392
|
+
process.exit(0);
|
|
393
|
+
} catch (err) {
|
|
394
|
+
console.error(err);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (args.toolsets !== undefined) {
|
|
400
|
+
if (args.help) {
|
|
401
|
+
console.log(renderToolsetsHelp(`${cliName} --toolsets`));
|
|
402
|
+
process.exit(0);
|
|
403
|
+
}
|
|
404
|
+
const result = listToolsets({ filters: toolsetFilters(args) });
|
|
405
|
+
console.log(args.json ? JSON.stringify(result, null, 2) : renderToolsetList(result));
|
|
406
|
+
process.exit(0);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (args['list-agents']) {
|
|
410
|
+
try {
|
|
411
|
+
console.log('\nAvailable agents (via AgentLauncher):');
|
|
412
|
+
printAgentList(await launcher.list());
|
|
413
|
+
console.log(`\nUsage: ${cliName} <name> [message...] (or npx ${npmPackageName} <name> [message...])`);
|
|
414
|
+
} catch (err) {
|
|
415
|
+
console.error('Error listing agents via AgentLauncher:', err.message);
|
|
416
|
+
}
|
|
417
|
+
process.exit(0);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const cliName = commandNameFromPath(process.argv[1], 'dave');
|
|
422
|
+
const npmPackageName = packageNameFromNearestPackageJson(__dirname, '@j-o-r/hello-dave');
|
|
423
|
+
|
|
424
|
+
/** Flag names that trigger built-in CLI behavior. */
|
|
425
|
+
const BUILTIN_COMMANDS = new Set([
|
|
426
|
+
'help',
|
|
427
|
+
'clear',
|
|
428
|
+
'search',
|
|
429
|
+
'list',
|
|
430
|
+
'inspect',
|
|
431
|
+
'list-agents',
|
|
432
|
+
'toolsets'
|
|
433
|
+
]);
|
|
434
|
+
|
|
435
|
+
const rawArgv = process.argv.slice(2);
|
|
436
|
+
const agentName = rawArgv.length > 0 && !rawArgv[0].startsWith('-') ? rawArgv[0] : null;
|
|
437
|
+
const pipedInput = (await readIn()) ?? '';
|
|
438
|
+
const launcher = new AgentLauncher({ from: import.meta.url });
|
|
439
|
+
|
|
440
|
+
if (agentName) {
|
|
441
|
+
await runAgent(launcher, agentName, pipedInput);
|
|
442
|
+
} else {
|
|
443
|
+
await runBuiltins(launcher);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/* ===================== End of CLI entry ===================== */
|