@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.
Files changed (173) hide show
  1. package/CHANGELOG.md +42 -25
  2. package/README.md +81 -221
  3. package/TODO.md +173 -35
  4. package/agents/agent_creator.js +105 -0
  5. package/agents/agent_creator.prompt.md +371 -0
  6. package/agents/ask_agent.js +64 -127
  7. package/agents/claude_agent.js +68 -0
  8. package/agents/code_agent.js +55 -135
  9. package/agents/code_agent.prompt.md +50 -0
  10. package/agents/echo_agent.js +76 -0
  11. package/agents/financial_expert.js +75 -0
  12. package/agents/gpt_agent.js +52 -103
  13. package/agents/gpt_code.js +81 -0
  14. package/agents/grok_agent.js +58 -114
  15. package/agents/minimax_agent.js +92 -0
  16. package/agents/mureka_agent.js +77 -0
  17. package/agents/planner_agent.js +172 -0
  18. package/agents/stability_agent.js +87 -0
  19. package/agents/test_agent.js +75 -157
  20. package/agents/weather_agent.js +73 -0
  21. package/agents/workflow_agent.js +189 -0
  22. package/bin/dave.js +436 -184
  23. package/docs/bin-dave.md +85 -35
  24. package/docs/cdn-ssh.md +100 -0
  25. package/docs/creating-agents.md +301 -0
  26. package/docs/creating-toolsets.md +336 -0
  27. package/docs/docs-organization.md +48 -0
  28. package/docs/project-overview.md +86 -51
  29. package/lib/API/elevenlabs.io/music.compose.md +441 -0
  30. package/lib/API/elevenlabs.io/music.create-composition-plan.md +370 -0
  31. package/lib/API/elevenlabs.io/music.stream.md +425 -0
  32. package/lib/API/lalal.ai/lalal.js +445 -0
  33. package/lib/API/lalal.ai/openapi.json +2614 -0
  34. package/lib/API/minimax/ImageToolset.js +82 -37
  35. package/lib/API/minimax/MusicToolset.js +125 -79
  36. package/lib/API/minimax/VideoToolset.js +170 -167
  37. package/lib/API/minimax/image.js +5 -1
  38. package/lib/API/minimax/music.js +210 -23
  39. package/lib/API/minimax/video.js +242 -53
  40. package/lib/API/mureka/MusicToolset.js +646 -0
  41. package/lib/API/mureka/README.md +41 -0
  42. package/lib/API/mureka/index.js +7 -0
  43. package/lib/API/mureka/music.js +658 -0
  44. package/lib/API/openai.com/index.js +7 -0
  45. package/lib/API/openai.com/{reponses/text.js → responses.js} +64 -18
  46. package/lib/API/openai.com/video.create.character.md +40 -0
  47. package/lib/API/openai.com/video.create.md +219 -0
  48. package/lib/API/openai.com/video.delete.md +44 -0
  49. package/lib/API/openai.com/video.download.md +31 -0
  50. package/lib/API/openai.com/video.edit.md +155 -0
  51. package/lib/API/openai.com/video.extend.md +166 -0
  52. package/lib/API/openai.com/video.fetch.character.md +43 -0
  53. package/lib/API/openai.com/video.js +784 -0
  54. package/lib/API/openai.com/video.list.md +201 -0
  55. package/lib/API/openai.com/video.remix.md +175 -0
  56. package/lib/API/openai.com/video.retrieve.md +139 -0
  57. package/lib/API/openai.com/videoToolset.js +616 -0
  58. package/lib/API/stability.ai/ImageToolset.js +131 -40
  59. package/lib/API/stability.ai/MusicToolset.js +79 -47
  60. package/lib/API/stability.ai/audio.js +63 -131
  61. package/lib/API/x.ai/chat.responses.md +1040 -0
  62. package/lib/API/x.ai/image.js +229 -59
  63. package/lib/API/x.ai/imageToolset.js +376 -0
  64. package/lib/API/x.ai/index.js +1 -1
  65. package/lib/API/x.ai/responses.js +9 -18
  66. package/lib/Agent.js +271 -0
  67. package/lib/Agent.js.old +284 -0
  68. package/lib/AgentLauncher.js +593 -0
  69. package/lib/Cli.js +87 -13
  70. package/lib/Prompt.js +23 -1
  71. package/lib/Session.js +5 -4
  72. package/lib/ToolSet.js +102 -6
  73. package/lib/agentLoader.js +369 -0
  74. package/lib/cdn.js +67 -231
  75. package/lib/{CdnToolset.js → cdnToolset.js} +47 -64
  76. package/lib/defaultToolsets.js +43 -0
  77. package/lib/fafs.js +1 -1
  78. package/lib/genericToolset.js +442 -119
  79. package/lib/handOffToolset.js +179 -0
  80. package/lib/index.js +34 -27
  81. package/lib/toolsetLoader.js +248 -0
  82. package/package.json +10 -4
  83. package/types/API/lalal.ai/lalal.d.ts +116 -0
  84. package/types/API/minimax/image.d.ts +2 -1
  85. package/types/API/minimax/music.d.ts +189 -26
  86. package/types/API/minimax/video.d.ts +100 -31
  87. package/types/API/mureka/index.d.ts +7 -0
  88. package/types/API/mureka/music.d.ts +472 -0
  89. package/types/API/openai.com/index.d.ts +7 -0
  90. package/types/API/openai.com/{reponses/text.d.ts → responses.d.ts} +11 -11
  91. package/types/API/openai.com/video.d.ts +409 -0
  92. package/types/API/openai.com/videoToolset.d.ts +24 -0
  93. package/types/API/stability.ai/audio.d.ts +14 -103
  94. package/types/API/stability.ai/image.d.ts +2 -2
  95. package/types/API/x.ai/image.d.ts +138 -26
  96. package/types/API/x.ai/imageToolset.d.ts +3 -0
  97. package/types/API/x.ai/index.d.ts +1 -1
  98. package/types/API/x.ai/responses.d.ts +4 -4
  99. package/types/Agent.d.ts +123 -0
  100. package/types/AgentLauncher.d.ts +250 -0
  101. package/types/Cli.d.ts +28 -8
  102. package/types/Prompt.d.ts +23 -5
  103. package/types/Session.d.ts +1 -1
  104. package/types/ToolSet.d.ts +10 -0
  105. package/types/agentLoader.d.ts +78 -0
  106. package/types/cdn.d.ts +15 -90
  107. package/types/defaultToolsets.d.ts +9 -0
  108. package/types/fafs.d.ts +1 -1
  109. package/types/genericToolset.d.ts +1 -1
  110. package/types/handOffToolset.d.ts +28 -0
  111. package/types/index.d.ts +19 -17
  112. package/types/toolsetLoader.d.ts +114 -0
  113. package/utils/format_log.js +101 -23
  114. package/utils/launch_agent.js +18 -0
  115. package/utils/list_sessions.sh +13 -5
  116. package/utils/search_sessions.sh +65 -29
  117. package/utils/toolsets.js +33 -0
  118. package/README.md.bak.1779452127 +0 -240
  119. package/agents/codeserver.sh +0 -47
  120. package/agents/daisy_agent.js +0 -173
  121. package/agents/docs_agent.js +0 -148
  122. package/agents/memory_agent.js +0 -263
  123. package/agents/minimax.js +0 -173
  124. package/agents/npm_agent.js +0 -202
  125. package/agents/prompt_agent.js +0 -133
  126. package/agents/readme_agent.js +0 -148
  127. package/agents/spawn_agent.js +0 -160
  128. package/agents/stability.js +0 -173
  129. package/agents/todo_agent.js +0 -175
  130. package/bin/codeDave +0 -58
  131. package/docs/agent-dave-websocket-protocol.md +0 -180
  132. package/docs/agent-manager.md +0 -244
  133. package/docs/codeserver-pattern.md +0 -191
  134. package/docs/generic-toolset.md +0 -326
  135. package/docs/howtos/agent-networking.md +0 -253
  136. package/docs/howtos/spawn-agents.md.bak +0 -200
  137. package/docs/howtos/spawn-agents.md.bak_new +0 -200
  138. package/docs/multi-agent-clusters.md +0 -265
  139. package/docs/music-toolsets.md +0 -137
  140. package/docs/path-resolution-best-practices.md +0 -104
  141. package/docs/plans/minimax-music-generation.md +0 -80
  142. package/docs/plans/unified-agent-architecture.md +0 -146
  143. package/docs/plans/websocket-streaming-plan.md.bak +0 -317
  144. package/docs/prompt/spawn_agent.md +0 -175
  145. package/docs/prompt/spawn_agent.md.bak +0 -201
  146. package/docs/prompt/task_clarification_and_documentation.md +0 -35
  147. package/docs/prompt-class.md +0 -141
  148. package/docs/todo-archive-infra-2026-04-21.md +0 -15
  149. package/docs/todo-archive-v0.0.8.md +0 -1
  150. package/docs/todo-archive-v0.1.0.md +0 -32
  151. package/docs/todo-archive.md +0 -44
  152. package/docs/tools-syntax-validation.md +0 -121
  153. package/docs/toolset.md +0 -164
  154. package/docs/xai-responses.md +0 -111
  155. package/docs/xai_collections.md +0 -106
  156. package/lib/API/x.ai/ImageToolset.js +0 -165
  157. package/lib/API/x.ai/text.js +0 -415
  158. package/lib/AgentClient.js +0 -248
  159. package/lib/AgentManager.js +0 -245
  160. package/lib/AgentServer.js +0 -404
  161. package/lib/wsCli.js +0 -287
  162. package/lib/wsIO.js +0 -90
  163. package/types/API/x.ai/text.d.ts +0 -286
  164. package/types/AgentClient.d.ts +0 -109
  165. package/types/AgentManager.d.ts +0 -100
  166. package/types/AgentServer.d.ts +0 -89
  167. package/types/wsCli.d.ts +0 -17
  168. package/types/wsIO.d.ts +0 -30
  169. package/utils/test.sh +0 -46
  170. /package/docs/{suggestions.md → _notes/token-counts.md} +0 -0
  171. /package/lib/API/openai.com/{reponses/MESSAGES.md → MESSAGES.md} +0 -0
  172. /package/types/API/{x.ai/ImageToolset.d.ts → mureka/MusicToolset.d.ts} +0 -0
  173. /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
- console.log(`
15
- FLAGS:
16
- --help : Show this help
17
- --clear : Removes the entire 'hello-dave' cache (chat history etc.)
18
- --search "[search_query_or_regex]" : Search in cache history
19
- --list : List all agent sessions in this folder
20
- --inspect "[path_to_ndjson_log]" : Inspect, Format and output a ndjson log file
21
- --connect [ws://url] [--secret "..."] : Connect to Agent websocket server
22
- Interactive: bin/dave.js --connect 'ws://localhost:8080' --secret '123'
23
- Piped actions:
24
- echo "predict the weather" | bin/dave.js --connect 'ws://...' --secret '123' # user_request
25
- echo "user_info" | bin/dave.js --connect 'ws://...' --secret '123' # user_info
26
- echo "user_reset" | bin/dave.js --connect 'ws://...' --secret '123' # user_reset
27
- --ask [--connect [ws://url]] [--secret "..."] [--model modelname] : Ask agent locally (XAIKEY req.) or remote
28
- Local: bin/dave.js --ask [--model grok-4-1-fast-reasoning]
29
- Remote: bin/dave.js --ask --connect 'ws://localhost:8080' --secret '123'
30
- Piped local: echo "predict the weather" | bin/dave.js --ask
31
- Piped remote: echo "predict the weather" | bin/dave.js --ask --connect 'ws://...' --secret '123'
32
- --code [port] [--secret "..."] : Launch CodeServer PM2 cluster via agents/codeserver.sh
33
- Usage: bin/dave.js --code 8080 --secret 123
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
- process.exit(exitCode)
36
- }
37
-
38
- // Make sure an action is defined
39
- const actions = ['help', 'clear', 'search', 'list', 'inspect', 'connect', 'code', 'ask'];
40
- if (!actions.some(key => args[key])) {
41
- printHelp(1);
42
- }
43
-
44
- if (args.help) {
45
- printHelp();
46
- }
47
-
48
- if (args.clear) {
49
- const clear_sessions = path.resolve(__dirname, '..', 'utils', 'clear_sessions.sh');
50
- const y = await cli.yesNo('Delete entire cache? (y/n) ');
51
- if (y) {
52
- console.log(clear_sessions);
53
- const res = await SH`${clear_sessions}`.run();
54
- console.log(res);
55
- }
56
- process.exit();
57
- } else if (args.search) {
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 ===================== */