@juspay/neurolink 9.52.0 → 9.54.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 (151) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +19 -0
  3. package/dist/adapters/tts/cartesiaHandler.d.ts +12 -0
  4. package/dist/adapters/tts/cartesiaHandler.js +130 -0
  5. package/dist/agent/directTools.d.ts +2 -2
  6. package/dist/auth/errors.d.ts +1 -1
  7. package/dist/auth/middleware/AuthMiddleware.d.ts +1 -1
  8. package/dist/auth/providers/BaseAuthProvider.d.ts +1 -1
  9. package/dist/autoresearch/config.d.ts +11 -0
  10. package/dist/autoresearch/config.js +108 -0
  11. package/dist/autoresearch/errors.d.ts +40 -0
  12. package/dist/autoresearch/errors.js +20 -0
  13. package/dist/autoresearch/index.d.ts +23 -0
  14. package/dist/autoresearch/index.js +34 -0
  15. package/dist/autoresearch/phasePolicy.d.ts +9 -0
  16. package/dist/autoresearch/phasePolicy.js +69 -0
  17. package/dist/autoresearch/promptCompiler.d.ts +15 -0
  18. package/dist/autoresearch/promptCompiler.js +120 -0
  19. package/dist/autoresearch/repoPolicy.d.ts +32 -0
  20. package/dist/autoresearch/repoPolicy.js +128 -0
  21. package/dist/autoresearch/resultRecorder.d.ts +20 -0
  22. package/dist/autoresearch/resultRecorder.js +130 -0
  23. package/dist/autoresearch/runner.d.ts +10 -0
  24. package/dist/autoresearch/runner.js +102 -0
  25. package/dist/autoresearch/stateStore.d.ts +12 -0
  26. package/dist/autoresearch/stateStore.js +163 -0
  27. package/dist/autoresearch/summaryParser.d.ts +16 -0
  28. package/dist/autoresearch/summaryParser.js +94 -0
  29. package/dist/autoresearch/tools.d.ts +257 -0
  30. package/dist/autoresearch/tools.js +617 -0
  31. package/dist/autoresearch/worker.d.ts +71 -0
  32. package/dist/autoresearch/worker.js +417 -0
  33. package/dist/browser/neurolink.min.js +340 -326
  34. package/dist/cli/commands/autoresearch.d.ts +41 -0
  35. package/dist/cli/commands/autoresearch.js +487 -0
  36. package/dist/cli/commands/config.d.ts +1 -1
  37. package/dist/cli/commands/task.d.ts +2 -0
  38. package/dist/cli/commands/task.js +32 -3
  39. package/dist/cli/commands/voiceServer.d.ts +6 -0
  40. package/dist/cli/commands/voiceServer.js +17 -0
  41. package/dist/cli/parser.js +7 -1
  42. package/dist/core/baseProvider.js +18 -0
  43. package/dist/evaluation/errors/EvaluationError.d.ts +1 -1
  44. package/dist/lib/adapters/tts/cartesiaHandler.d.ts +12 -0
  45. package/dist/lib/adapters/tts/cartesiaHandler.js +131 -0
  46. package/dist/lib/agent/directTools.d.ts +2 -2
  47. package/dist/lib/auth/errors.d.ts +1 -1
  48. package/dist/lib/auth/middleware/AuthMiddleware.d.ts +1 -1
  49. package/dist/lib/auth/providers/BaseAuthProvider.d.ts +1 -1
  50. package/dist/lib/autoresearch/config.d.ts +11 -0
  51. package/dist/lib/autoresearch/config.js +109 -0
  52. package/dist/lib/autoresearch/errors.d.ts +40 -0
  53. package/dist/lib/autoresearch/errors.js +21 -0
  54. package/dist/lib/autoresearch/index.d.ts +23 -0
  55. package/dist/lib/autoresearch/index.js +35 -0
  56. package/dist/lib/autoresearch/phasePolicy.d.ts +9 -0
  57. package/dist/lib/autoresearch/phasePolicy.js +70 -0
  58. package/dist/lib/autoresearch/promptCompiler.d.ts +15 -0
  59. package/dist/lib/autoresearch/promptCompiler.js +121 -0
  60. package/dist/lib/autoresearch/repoPolicy.d.ts +32 -0
  61. package/dist/lib/autoresearch/repoPolicy.js +129 -0
  62. package/dist/lib/autoresearch/resultRecorder.d.ts +20 -0
  63. package/dist/lib/autoresearch/resultRecorder.js +131 -0
  64. package/dist/lib/autoresearch/runner.d.ts +10 -0
  65. package/dist/lib/autoresearch/runner.js +103 -0
  66. package/dist/lib/autoresearch/stateStore.d.ts +12 -0
  67. package/dist/lib/autoresearch/stateStore.js +164 -0
  68. package/dist/lib/autoresearch/summaryParser.d.ts +16 -0
  69. package/dist/lib/autoresearch/summaryParser.js +95 -0
  70. package/dist/lib/autoresearch/tools.d.ts +257 -0
  71. package/dist/lib/autoresearch/tools.js +618 -0
  72. package/dist/lib/autoresearch/worker.d.ts +71 -0
  73. package/dist/lib/autoresearch/worker.js +418 -0
  74. package/dist/lib/core/baseProvider.js +18 -0
  75. package/dist/lib/evaluation/errors/EvaluationError.d.ts +1 -1
  76. package/dist/lib/files/fileTools.d.ts +1 -1
  77. package/dist/lib/neurolink.js +22 -2
  78. package/dist/lib/providers/azureOpenai.d.ts +4 -1
  79. package/dist/lib/providers/azureOpenai.js +9 -3
  80. package/dist/lib/providers/litellm.js +2 -2
  81. package/dist/lib/providers/openRouter.js +2 -2
  82. package/dist/lib/providers/openaiCompatible.js +3 -1
  83. package/dist/lib/server/voice/frameBus.d.ts +8 -0
  84. package/dist/lib/server/voice/frameBus.js +25 -0
  85. package/dist/lib/server/voice/turnManager.d.ts +15 -0
  86. package/dist/lib/server/voice/turnManager.js +36 -0
  87. package/dist/lib/server/voice/types.d.ts +20 -0
  88. package/dist/lib/server/voice/types.js +2 -0
  89. package/dist/lib/server/voice/voiceServerApp.d.ts +1 -0
  90. package/dist/lib/server/voice/voiceServerApp.js +118 -0
  91. package/dist/lib/server/voice/voiceWebSocketHandler.d.ts +11 -0
  92. package/dist/lib/server/voice/voiceWebSocketHandler.js +536 -0
  93. package/dist/lib/tasks/autoresearchTaskExecutor.d.ts +32 -0
  94. package/dist/lib/tasks/autoresearchTaskExecutor.js +303 -0
  95. package/dist/lib/tasks/errors.d.ts +3 -1
  96. package/dist/lib/tasks/errors.js +1 -0
  97. package/dist/lib/tasks/taskExecutor.d.ts +4 -2
  98. package/dist/lib/tasks/taskExecutor.js +8 -1
  99. package/dist/lib/tasks/taskManager.js +27 -3
  100. package/dist/lib/tasks/tools/taskTools.d.ts +1 -1
  101. package/dist/lib/telemetry/attributes.d.ts +15 -0
  102. package/dist/lib/telemetry/attributes.js +16 -0
  103. package/dist/lib/telemetry/tracers.d.ts +1 -0
  104. package/dist/lib/telemetry/tracers.js +1 -0
  105. package/dist/lib/types/autoresearchTypes.d.ts +194 -0
  106. package/dist/lib/types/autoresearchTypes.js +18 -0
  107. package/dist/lib/types/common.d.ts +11 -0
  108. package/dist/lib/types/index.d.ts +16 -14
  109. package/dist/lib/types/index.js +21 -17
  110. package/dist/lib/types/taskTypes.d.ts +38 -0
  111. package/dist/lib/workflow/config.d.ts +3 -3
  112. package/dist/neurolink.js +22 -2
  113. package/dist/providers/azureOpenai.d.ts +4 -1
  114. package/dist/providers/azureOpenai.js +9 -3
  115. package/dist/providers/litellm.js +2 -2
  116. package/dist/providers/openRouter.js +2 -2
  117. package/dist/providers/openaiCompatible.js +3 -1
  118. package/dist/rag/errors/RAGError.d.ts +1 -1
  119. package/dist/server/voice/frameBus.d.ts +8 -0
  120. package/dist/server/voice/frameBus.js +24 -0
  121. package/dist/server/voice/public/app.js +275 -0
  122. package/dist/server/voice/public/index.html +18 -0
  123. package/dist/server/voice/public/pcm-worklet.js +67 -0
  124. package/dist/server/voice/public/styles.css +102 -0
  125. package/dist/server/voice/turnManager.d.ts +15 -0
  126. package/dist/server/voice/turnManager.js +35 -0
  127. package/dist/server/voice/types.d.ts +20 -0
  128. package/dist/server/voice/types.js +1 -0
  129. package/dist/server/voice/voiceServerApp.d.ts +1 -0
  130. package/dist/server/voice/voiceServerApp.js +117 -0
  131. package/dist/server/voice/voiceWebSocketHandler.d.ts +11 -0
  132. package/dist/server/voice/voiceWebSocketHandler.js +535 -0
  133. package/dist/tasks/autoresearchTaskExecutor.d.ts +32 -0
  134. package/dist/tasks/autoresearchTaskExecutor.js +302 -0
  135. package/dist/tasks/errors.d.ts +3 -1
  136. package/dist/tasks/errors.js +1 -0
  137. package/dist/tasks/taskExecutor.d.ts +4 -2
  138. package/dist/tasks/taskExecutor.js +8 -1
  139. package/dist/tasks/taskManager.js +27 -3
  140. package/dist/tasks/tools/taskTools.d.ts +1 -1
  141. package/dist/telemetry/attributes.d.ts +15 -0
  142. package/dist/telemetry/attributes.js +16 -0
  143. package/dist/telemetry/tracers.d.ts +1 -0
  144. package/dist/telemetry/tracers.js +1 -0
  145. package/dist/types/autoresearchTypes.d.ts +194 -0
  146. package/dist/types/autoresearchTypes.js +17 -0
  147. package/dist/types/common.d.ts +11 -0
  148. package/dist/types/index.d.ts +16 -14
  149. package/dist/types/index.js +21 -17
  150. package/dist/types/taskTypes.d.ts +38 -0
  151. package/package.json +2 -1
@@ -0,0 +1,41 @@
1
+ /**
2
+ * AutoResearch CLI Commands for NeuroLink
3
+ *
4
+ * - neurolink autoresearch init — Initialize autoresearch for a repo
5
+ * - neurolink autoresearch status — Show current research state
6
+ * - neurolink autoresearch results — Show experiment results
7
+ * - neurolink autoresearch run-once — Run one experiment cycle
8
+ * - neurolink autoresearch start — Start a scheduled autoresearch task
9
+ * - neurolink autoresearch pause — Pause a running autoresearch task
10
+ * - neurolink autoresearch resume — Resume a paused autoresearch task
11
+ * - neurolink autoresearch stop — Stop and cancel an autoresearch task
12
+ * - neurolink autoresearch reset — Reset autoresearch state for a repo
13
+ */
14
+ import type { CommandModule } from "yargs";
15
+ export declare class AutoresearchCommandFactory {
16
+ static createAutoresearchCommands(): CommandModule;
17
+ /**
18
+ * Get a direct TaskStore instance for store operations.
19
+ * Respects the same backend selection as TaskManager so both paths
20
+ * read/write the same store (Redis for bullmq, file for node-timeout).
21
+ */
22
+ private static getStore;
23
+ private static executeInit;
24
+ private static executeStatus;
25
+ private static executeResults;
26
+ private static executeRunOnce;
27
+ /**
28
+ * Start a scheduled autoresearch task via TaskManager.
29
+ * Reads config.json from .autoresearch/ and creates a TaskManager task.
30
+ */
31
+ private static executeStart;
32
+ /**
33
+ * Lifecycle operations: pause, resume, stop.
34
+ * Reads from the file task store and updates task status.
35
+ */
36
+ private static executeLifecycle;
37
+ /**
38
+ * Reset autoresearch state by removing the .autoresearch directory.
39
+ */
40
+ private static executeReset;
41
+ }
@@ -0,0 +1,487 @@
1
+ /**
2
+ * AutoResearch CLI Commands for NeuroLink
3
+ *
4
+ * - neurolink autoresearch init — Initialize autoresearch for a repo
5
+ * - neurolink autoresearch status — Show current research state
6
+ * - neurolink autoresearch results — Show experiment results
7
+ * - neurolink autoresearch run-once — Run one experiment cycle
8
+ * - neurolink autoresearch start — Start a scheduled autoresearch task
9
+ * - neurolink autoresearch pause — Pause a running autoresearch task
10
+ * - neurolink autoresearch resume — Resume a paused autoresearch task
11
+ * - neurolink autoresearch stop — Stop and cancel an autoresearch task
12
+ * - neurolink autoresearch reset — Reset autoresearch state for a repo
13
+ */
14
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
15
+ import { resolve } from "node:path";
16
+ import chalk from "chalk";
17
+ import ora from "ora";
18
+ import { TASK_DEFAULTS } from "../../lib/types/index.js";
19
+ export class AutoresearchCommandFactory {
20
+ static createAutoresearchCommands() {
21
+ return {
22
+ command: "autoresearch <subcommand>",
23
+ describe: "Run automated AI-driven research experiments",
24
+ builder: (yargs) => {
25
+ return yargs
26
+ .command("init <repoPath>", "Initialize autoresearch for a repository", (y) => y
27
+ .positional("repoPath", {
28
+ type: "string",
29
+ description: "Path to the repository",
30
+ demandOption: true,
31
+ })
32
+ .option("tag", {
33
+ type: "string",
34
+ alias: "t",
35
+ description: "Run tag (e.g. apr3)",
36
+ demandOption: true,
37
+ })
38
+ .option("target", {
39
+ type: "string",
40
+ default: "train.py",
41
+ description: "Mutable file(s), comma-separated",
42
+ })
43
+ .option("immutable", {
44
+ type: "string",
45
+ default: "",
46
+ description: "Immutable file(s), comma-separated",
47
+ })
48
+ .option("run-command", {
49
+ type: "string",
50
+ description: "Experiment command to execute",
51
+ demandOption: true,
52
+ })
53
+ .option("metric-name", {
54
+ type: "string",
55
+ default: "val_bpb",
56
+ })
57
+ .option("metric-pattern", {
58
+ type: "string",
59
+ default: "^val_bpb:\\s+([\\d.]+)",
60
+ })
61
+ .option("metric-direction", {
62
+ type: "string",
63
+ choices: ["lower", "higher"],
64
+ default: "lower",
65
+ })
66
+ .option("timeout", { type: "number", default: 600 })
67
+ .option("provider", { type: "string" })
68
+ .option("model", { type: "string" }), async (argv) => {
69
+ await AutoresearchCommandFactory.executeInit(argv);
70
+ })
71
+ .command("status [repoPath]", "Show current research state", (y) => y
72
+ .positional("repoPath", {
73
+ type: "string",
74
+ default: ".",
75
+ })
76
+ .option("format", {
77
+ type: "string",
78
+ choices: ["text", "json"],
79
+ default: "text",
80
+ }), async (argv) => {
81
+ await AutoresearchCommandFactory.executeStatus(argv);
82
+ })
83
+ .command("results [repoPath]", "Show experiment results", (y) => y
84
+ .positional("repoPath", {
85
+ type: "string",
86
+ default: ".",
87
+ })
88
+ .option("last", { type: "number", default: 20 })
89
+ .option("format", {
90
+ type: "string",
91
+ choices: ["text", "json", "table"],
92
+ default: "table",
93
+ }), async (argv) => {
94
+ await AutoresearchCommandFactory.executeResults(argv);
95
+ })
96
+ .command("run-once [repoPath]", "Run one experiment cycle", (y) => y
97
+ .positional("repoPath", {
98
+ type: "string",
99
+ default: ".",
100
+ })
101
+ .option("description", {
102
+ type: "string",
103
+ default: "manual run",
104
+ }), async (argv) => {
105
+ await AutoresearchCommandFactory.executeRunOnce(argv);
106
+ })
107
+ .command("start <repoPath>", "Start a scheduled autoresearch task via TaskManager", (y) => y
108
+ .positional("repoPath", {
109
+ type: "string",
110
+ description: "Path to the repository",
111
+ demandOption: true,
112
+ })
113
+ .option("interval", {
114
+ type: "number",
115
+ default: 300,
116
+ description: "Interval between ticks in seconds",
117
+ })
118
+ .option("max-runs", {
119
+ type: "number",
120
+ description: "Max experiment ticks (omit for unlimited)",
121
+ }), async (argv) => {
122
+ await AutoresearchCommandFactory.executeStart(argv);
123
+ })
124
+ .command("pause <taskId>", "Pause a running autoresearch task", (y) => y.positional("taskId", {
125
+ type: "string",
126
+ description: "Task ID to pause",
127
+ demandOption: true,
128
+ }), async (argv) => {
129
+ await AutoresearchCommandFactory.executeLifecycle(argv.taskId, "pause");
130
+ })
131
+ .command("resume <taskId>", "Resume a paused autoresearch task", (y) => y.positional("taskId", {
132
+ type: "string",
133
+ description: "Task ID to resume",
134
+ demandOption: true,
135
+ }), async (argv) => {
136
+ await AutoresearchCommandFactory.executeLifecycle(argv.taskId, "resume");
137
+ })
138
+ .command("stop <taskId>", "Stop and cancel an autoresearch task", (y) => y.positional("taskId", {
139
+ type: "string",
140
+ description: "Task ID to stop",
141
+ demandOption: true,
142
+ }), async (argv) => {
143
+ await AutoresearchCommandFactory.executeLifecycle(argv.taskId, "stop");
144
+ })
145
+ .command("reset [repoPath]", "Reset autoresearch state for a repository", (y) => y.positional("repoPath", {
146
+ type: "string",
147
+ default: ".",
148
+ }), async (argv) => {
149
+ await AutoresearchCommandFactory.executeReset(argv.repoPath);
150
+ })
151
+ .demandCommand(1, "Please specify an autoresearch subcommand");
152
+ },
153
+ handler: () => { },
154
+ };
155
+ }
156
+ /**
157
+ * Get a direct TaskStore instance for store operations.
158
+ * Respects the same backend selection as TaskManager so both paths
159
+ * read/write the same store (Redis for bullmq, file for node-timeout).
160
+ */
161
+ static async getStore(config) {
162
+ const backendName = config?.backend ?? TASK_DEFAULTS.backend;
163
+ if (backendName === "bullmq") {
164
+ const { RedisTaskStore } = await import("../../lib/tasks/store/redisTaskStore.js");
165
+ const store = new RedisTaskStore(config ?? {});
166
+ await store.initialize();
167
+ return store;
168
+ }
169
+ const { FileTaskStore } = await import("../../lib/tasks/store/fileTaskStore.js");
170
+ const store = new FileTaskStore(config ?? {});
171
+ await store.initialize();
172
+ return store;
173
+ }
174
+ static async executeInit(argv) {
175
+ const spinner = ora("Initializing autoresearch...").start();
176
+ try {
177
+ const repoPath = resolve(argv.repoPath);
178
+ if (!existsSync(repoPath)) {
179
+ spinner.fail(chalk.red(`Repository not found: ${repoPath}`));
180
+ process.exit(1);
181
+ }
182
+ const { ResearchWorker } = await import("../../lib/autoresearch/worker.js");
183
+ const mutablePaths = argv.target
184
+ .split(",")
185
+ .map((f) => f.trim())
186
+ .filter(Boolean);
187
+ const immutablePaths = argv.immutable
188
+ .split(",")
189
+ .map((f) => f.trim())
190
+ .filter(Boolean);
191
+ const worker = new ResearchWorker({
192
+ repoPath,
193
+ mutablePaths,
194
+ immutablePaths,
195
+ runCommand: argv.runCommand,
196
+ metric: {
197
+ name: argv.metricName,
198
+ direction: argv.metricDirection,
199
+ pattern: argv.metricPattern,
200
+ },
201
+ timeoutMs: argv.timeout * 1000,
202
+ provider: argv.provider,
203
+ model: argv.model,
204
+ });
205
+ const state = await worker.initialize(argv.tag);
206
+ // Persist config for run-once to read
207
+ const configDir = resolve(repoPath, ".autoresearch");
208
+ mkdirSync(configDir, { recursive: true });
209
+ writeFileSync(resolve(configDir, "config.json"), JSON.stringify({
210
+ tag: argv.tag,
211
+ mutablePaths,
212
+ immutablePaths,
213
+ runCommand: argv.runCommand,
214
+ metric: {
215
+ name: argv.metricName,
216
+ direction: argv.metricDirection,
217
+ pattern: argv.metricPattern,
218
+ },
219
+ timeoutMs: argv.timeout * 1000,
220
+ provider: argv.provider,
221
+ model: argv.model,
222
+ }, null, 2), "utf-8");
223
+ spinner.succeed(chalk.green("Autoresearch initialized"));
224
+ console.info(` Branch: ${state.branch} Tag: ${argv.tag} Target: ${mutablePaths.join(", ")}`);
225
+ }
226
+ catch (error) {
227
+ spinner.fail(chalk.red("Failed to initialize"));
228
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
229
+ process.exit(1);
230
+ }
231
+ }
232
+ static async executeStatus(argv) {
233
+ const repoPath = resolve(argv.repoPath);
234
+ const statePath = resolve(repoPath, ".autoresearch", "state.json");
235
+ if (!existsSync(statePath)) {
236
+ console.info(chalk.yellow("Not initialized. Run `neurolink autoresearch init` first."));
237
+ return;
238
+ }
239
+ let state;
240
+ try {
241
+ state = JSON.parse(readFileSync(statePath, "utf-8"));
242
+ }
243
+ catch (err) {
244
+ console.error(chalk.red(`Failed to parse state file: ${statePath}`));
245
+ console.error(chalk.dim(err instanceof Error ? err.message : String(err)));
246
+ return;
247
+ }
248
+ if (argv.format === "json") {
249
+ console.info(JSON.stringify(state, null, 2));
250
+ return;
251
+ }
252
+ console.info(` Tag: ${state.tag} Branch: ${state.branch} Phase: ${state.currentPhase}`);
253
+ console.info(` Runs: ${state.runCount} Keeps: ${state.keepCount} Best: ${state.bestMetric ?? "none"}`);
254
+ }
255
+ static async executeResults(argv) {
256
+ const repoPath = resolve(argv.repoPath);
257
+ const configPath = resolve(repoPath, ".autoresearch", "config.json");
258
+ let resultsPath = resolve(repoPath, "results.tsv");
259
+ if (existsSync(configPath)) {
260
+ try {
261
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
262
+ if (config.resultsPath) {
263
+ resultsPath = resolve(repoPath, config.resultsPath);
264
+ }
265
+ }
266
+ catch {
267
+ /* use default */
268
+ }
269
+ }
270
+ if (!existsSync(resultsPath)) {
271
+ console.info(chalk.yellow("No results file."));
272
+ return;
273
+ }
274
+ const lines = readFileSync(resultsPath, "utf-8").trim().split("\n");
275
+ if (lines.length < 2) {
276
+ console.info(chalk.yellow("No results yet."));
277
+ return;
278
+ }
279
+ const rows = lines.slice(1).slice(-argv.last);
280
+ if (argv.format === "json") {
281
+ console.info(JSON.stringify(rows.map((l) => l.split("\t")), null, 2));
282
+ return;
283
+ }
284
+ console.info(lines[0]);
285
+ for (const r of rows) {
286
+ console.info(r);
287
+ }
288
+ }
289
+ static async executeRunOnce(argv) {
290
+ const spinner = ora("Running experiment...").start();
291
+ try {
292
+ const repoPath = resolve(argv.repoPath);
293
+ const configPath = resolve(repoPath, ".autoresearch", "config.json");
294
+ if (!existsSync(configPath)) {
295
+ spinner.fail(chalk.red("No config. Run init first."));
296
+ process.exit(1);
297
+ }
298
+ let configRaw;
299
+ try {
300
+ configRaw = JSON.parse(readFileSync(configPath, "utf-8"));
301
+ }
302
+ catch (err) {
303
+ spinner.fail(chalk.red(`Failed to parse config: ${configPath}`));
304
+ console.error(chalk.dim(err instanceof Error ? err.message : String(err)));
305
+ process.exit(1);
306
+ }
307
+ const { ResearchWorker } = await import("../../lib/autoresearch/worker.js");
308
+ if (!configRaw.mutablePaths ||
309
+ !configRaw.runCommand ||
310
+ !configRaw.metric) {
311
+ spinner.fail(chalk.red("Config missing required fields (mutablePaths, runCommand, metric)"));
312
+ process.exit(1);
313
+ }
314
+ const worker = new ResearchWorker({
315
+ repoPath,
316
+ mutablePaths: configRaw.mutablePaths,
317
+ runCommand: configRaw.runCommand,
318
+ metric: configRaw.metric,
319
+ ...configRaw,
320
+ });
321
+ await worker.resume();
322
+ const record = await worker.runExperimentCycle(argv.description);
323
+ const c = record.status === "keep"
324
+ ? "green"
325
+ : record.status === "discard"
326
+ ? "yellow"
327
+ : "red";
328
+ spinner.succeed(chalk[c](`${record.status}: metric=${record.metric ?? "N/A"} commit=${record.commit}`));
329
+ }
330
+ catch (error) {
331
+ spinner.fail(chalk.red(error instanceof Error ? error.message : String(error)));
332
+ process.exit(1);
333
+ }
334
+ }
335
+ /**
336
+ * Start a scheduled autoresearch task via TaskManager.
337
+ * Reads config.json from .autoresearch/ and creates a TaskManager task.
338
+ */
339
+ static async executeStart(argv) {
340
+ const spinner = ora("Starting autoresearch task...").start();
341
+ try {
342
+ const repoPath = resolve(argv.repoPath);
343
+ const configPath = resolve(repoPath, ".autoresearch", "config.json");
344
+ if (!existsSync(configPath)) {
345
+ spinner.fail(chalk.red("No config. Run `neurolink autoresearch init` first."));
346
+ process.exit(1);
347
+ }
348
+ let configRaw;
349
+ try {
350
+ configRaw = JSON.parse(readFileSync(configPath, "utf-8"));
351
+ }
352
+ catch (err) {
353
+ spinner.fail(chalk.red(`Failed to parse config: ${configPath}`));
354
+ console.error(chalk.dim(err instanceof Error ? err.message : String(err)));
355
+ process.exit(1);
356
+ }
357
+ // Dynamic import to avoid pulling NeuroLink into CLI cold path
358
+ const { nanoid } = await import("nanoid");
359
+ if (!configRaw.mutablePaths ||
360
+ !configRaw.runCommand ||
361
+ !configRaw.metric) {
362
+ spinner.fail(chalk.red("Config missing required fields (mutablePaths, runCommand, metric)"));
363
+ process.exit(1);
364
+ }
365
+ const store = await AutoresearchCommandFactory.getStore();
366
+ const now = new Date().toISOString();
367
+ const task = {
368
+ id: `task_${nanoid(12)}`,
369
+ name: `autoresearch-${repoPath.split("/").pop()}`,
370
+ prompt: "Autonomous ML experiment loop",
371
+ schedule: { type: "interval", every: argv.interval * 1000 },
372
+ mode: "isolated",
373
+ type: "autoresearch",
374
+ status: "active",
375
+ tools: true,
376
+ timeout: configRaw.timeoutMs ?? 600_000,
377
+ retry: { maxAttempts: 1, backoffMs: [60_000] },
378
+ runCount: 0,
379
+ createdAt: now,
380
+ updatedAt: now,
381
+ autoresearch: {
382
+ repoPath,
383
+ mutablePaths: configRaw.mutablePaths,
384
+ runCommand: configRaw.runCommand,
385
+ metric: configRaw.metric,
386
+ ...(configRaw.immutablePaths?.length
387
+ ? { immutablePaths: configRaw.immutablePaths }
388
+ : {}),
389
+ ...(configRaw.programPath
390
+ ? { programPath: configRaw.programPath }
391
+ : {}),
392
+ ...(configRaw.resultsPath
393
+ ? { resultsPath: configRaw.resultsPath }
394
+ : {}),
395
+ ...(configRaw.statePath ? { statePath: configRaw.statePath } : {}),
396
+ ...(configRaw.logPath ? { logPath: configRaw.logPath } : {}),
397
+ ...(configRaw.branchPrefix
398
+ ? { branchPrefix: configRaw.branchPrefix }
399
+ : {}),
400
+ ...(configRaw.memoryMetric
401
+ ? { memoryMetric: configRaw.memoryMetric }
402
+ : {}),
403
+ ...(configRaw.timeoutMs ? { timeoutMs: configRaw.timeoutMs } : {}),
404
+ ...(configRaw.provider ? { provider: configRaw.provider } : {}),
405
+ ...(configRaw.model ? { model: configRaw.model } : {}),
406
+ ...(configRaw.thinkingLevel
407
+ ? { thinkingLevel: configRaw.thinkingLevel }
408
+ : {}),
409
+ ...(configRaw.maxExperiments
410
+ ? { maxExperiments: configRaw.maxExperiments }
411
+ : {}),
412
+ },
413
+ ...(argv.maxRuns ? { maxRuns: argv.maxRuns } : {}),
414
+ };
415
+ await store.save(task);
416
+ await store.shutdown();
417
+ spinner.succeed(chalk.green(`Autoresearch task created: ${task.id}`));
418
+ console.info(` Interval: ${argv.interval}s Max runs: ${argv.maxRuns ?? "unlimited"}`);
419
+ console.info(chalk.dim(" Note: Start the task worker with `neurolink task start` to begin execution."));
420
+ }
421
+ catch (error) {
422
+ spinner.fail(chalk.red(error instanceof Error ? error.message : String(error)));
423
+ process.exit(1);
424
+ }
425
+ }
426
+ /**
427
+ * Lifecycle operations: pause, resume, stop.
428
+ * Reads from the file task store and updates task status.
429
+ */
430
+ static async executeLifecycle(taskId, action) {
431
+ const spinner = ora(`${action}ing task ${taskId}...`).start();
432
+ try {
433
+ const store = await AutoresearchCommandFactory.getStore();
434
+ const task = await store.get(taskId);
435
+ if (!task) {
436
+ spinner.fail(chalk.red(`Task not found: ${taskId}`));
437
+ process.exit(1);
438
+ }
439
+ if (task.type !== "autoresearch") {
440
+ spinner.fail(chalk.red(`Task ${taskId} is not an autoresearch task (type: ${task.type})`));
441
+ process.exit(1);
442
+ }
443
+ let newStatus;
444
+ if (action === "pause") {
445
+ if (task.status !== "active") {
446
+ spinner.fail(chalk.red(`Cannot pause task with status: ${task.status}`));
447
+ process.exit(1);
448
+ }
449
+ newStatus = "paused";
450
+ }
451
+ else if (action === "resume") {
452
+ if (task.status !== "paused") {
453
+ spinner.fail(chalk.red(`Cannot resume task with status: ${task.status}`));
454
+ process.exit(1);
455
+ }
456
+ newStatus = "active";
457
+ }
458
+ else {
459
+ // stop
460
+ newStatus = "cancelled";
461
+ }
462
+ await store.update(taskId, {
463
+ status: newStatus,
464
+ });
465
+ await store.shutdown();
466
+ spinner.succeed(chalk.green(`Task ${taskId} → ${newStatus}`));
467
+ }
468
+ catch (error) {
469
+ spinner.fail(chalk.red(error instanceof Error ? error.message : String(error)));
470
+ process.exit(1);
471
+ }
472
+ }
473
+ /**
474
+ * Reset autoresearch state by removing the .autoresearch directory.
475
+ */
476
+ static async executeReset(repoPath) {
477
+ const resolved = resolve(repoPath);
478
+ const arDir = resolve(resolved, ".autoresearch");
479
+ if (!existsSync(arDir)) {
480
+ console.info(chalk.yellow("No .autoresearch directory found."));
481
+ return;
482
+ }
483
+ rmSync(arDir, { recursive: true, force: true });
484
+ console.info(chalk.green(`Reset autoresearch state for ${resolved}`));
485
+ }
486
+ }
487
+ //# sourceMappingURL=autoresearch.js.map
@@ -81,9 +81,9 @@ declare const ConfigSchema: z.ZodObject<{
81
81
  enableLogging: z.ZodDefault<z.ZodBoolean>;
82
82
  enableCaching: z.ZodDefault<z.ZodBoolean>;
83
83
  cacheStrategy: z.ZodDefault<z.ZodEnum<{
84
+ file: "file";
84
85
  memory: "memory";
85
86
  redis: "redis";
86
- file: "file";
87
87
  }>>;
88
88
  defaultEvaluationDomain: z.ZodOptional<z.ZodString>;
89
89
  enableAnalyticsByDefault: z.ZodDefault<z.ZodBoolean>;
@@ -32,6 +32,8 @@ export declare class TaskCommandFactory {
32
32
  * Used by all management commands: create, list, get, delete, logs, pause, resume, update.
33
33
  */
34
34
  private static getStore;
35
+ /** Attach autoresearch-specific event listeners for worker log output */
36
+ private static attachAutoresearchEventListeners;
35
37
  /** Attach event listeners and keep the process alive for scheduled task execution */
36
38
  private static enterWorkerMode;
37
39
  /**
@@ -16,14 +16,13 @@
16
16
  * - neurolink task status — Show worker status
17
17
  */
18
18
  import { spawn } from "node:child_process";
19
- import { openSync } from "node:fs";
19
+ import { mkdirSync, openSync } from "node:fs";
20
20
  import { join } from "node:path";
21
- import { mkdirSync } from "node:fs";
22
21
  import chalk from "chalk";
23
22
  import { nanoid } from "nanoid";
24
23
  import ora from "ora";
25
24
  import { TASK_DEFAULTS } from "../../lib/types/index.js";
26
- import { StateFileManager, isProcessRunning, formatUptime, getNeuroLinkDir, ensureStateDir, } from "../utils/serverUtils.js";
25
+ import { ensureStateDir, formatUptime, getNeuroLinkDir, isProcessRunning, StateFileManager, } from "../utils/serverUtils.js";
27
26
  const workerState = new StateFileManager("task-worker-state.json");
28
27
  /**
29
28
  * Parse human-readable duration to milliseconds.
@@ -284,6 +283,31 @@ export class TaskCommandFactory {
284
283
  await store.initialize();
285
284
  return store;
286
285
  }
286
+ /** Attach autoresearch-specific event listeners for worker log output */
287
+ static attachAutoresearchEventListeners(emitter) {
288
+ emitter.on("autoresearch:phase-changed", (event) => {
289
+ const e = event;
290
+ console.info(` ${chalk.magenta("⟳")} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.magenta("phase")} ${e.from} → ${chalk.bold(e.to ?? "?")}${e.tag ? ` [${e.tag}]` : ""}`);
291
+ });
292
+ emitter.on("autoresearch:experiment-completed", (event) => {
293
+ const e = event;
294
+ const icon = e.status === "keep"
295
+ ? chalk.green("✔")
296
+ : e.status === "discard"
297
+ ? chalk.yellow("↩")
298
+ : chalk.red("✘");
299
+ console.info(` ${icon} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.cyan("experiment")} ${e.status} metric=${e.metric ?? "N/A"} commit=${(e.commit ?? "").slice(0, 7)} ${e.durationMs ? `${e.durationMs}ms` : ""}`);
300
+ });
301
+ emitter.on("autoresearch:metric-improved", (event) => {
302
+ const e = event;
303
+ console.info(` ${chalk.green("★")} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.green("new best metric")} ${e.previousBest} → ${chalk.bold(String(e.newBest))} (${e.direction})`);
304
+ });
305
+ emitter.on("autoresearch:error", (event) => {
306
+ const e = event;
307
+ const errMsg = e.error ?? e.message ?? "unknown";
308
+ console.info(` ${chalk.red("⚠")} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.red("autoresearch error")} [${e.code}] ${errMsg.slice(0, 100)}${e.phase ? ` (phase: ${e.phase})` : ""}`);
309
+ });
310
+ }
287
311
  /** Attach event listeners and keep the process alive for scheduled task execution */
288
312
  static enterWorkerMode(neurolink, manager) {
289
313
  console.info(chalk.gray(" Worker running. Tasks will auto-execute on schedule."));
@@ -305,6 +329,8 @@ export class TaskCommandFactory {
305
329
  const r = result;
306
330
  console.info(` ${chalk.red("✘")} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.cyan(r.taskId)} — ${chalk.red(r.error?.slice(0, 100) || "unknown error")}`);
307
331
  });
332
+ // Autoresearch lifecycle events
333
+ TaskCommandFactory.attachAutoresearchEventListeners(emitter);
308
334
  }
309
335
  // Graceful shutdown on Ctrl+C
310
336
  const shutdown = async () => {
@@ -354,6 +380,7 @@ export class TaskCommandFactory {
354
380
  prompt: argv.prompt,
355
381
  schedule,
356
382
  mode,
383
+ type: "standard",
357
384
  status: "active",
358
385
  tools: TASK_DEFAULTS.tools,
359
386
  timeout: TASK_DEFAULTS.timeout,
@@ -796,6 +823,8 @@ export class TaskCommandFactory {
796
823
  const r = result;
797
824
  console.error(`[task-worker] ✘ ${new Date().toISOString()} ${r.taskId} — ${r.error?.slice(0, 200) || "unknown error"}`);
798
825
  });
826
+ // Autoresearch lifecycle events
827
+ TaskCommandFactory.attachAutoresearchEventListeners(emitter);
799
828
  }
800
829
  // Graceful shutdown
801
830
  const shutdown = async () => {
@@ -0,0 +1,6 @@
1
+ import type { CommandModule } from "yargs";
2
+ type VoiceServerArgs = {
3
+ port: number;
4
+ };
5
+ export declare const voiceServerCommand: CommandModule<object, VoiceServerArgs>;
6
+ export {};
@@ -0,0 +1,17 @@
1
+ import { startVoiceServer } from "../../lib/server/voice/voiceServerApp.js";
2
+ import { configureVoiceServerEnvironment } from "../../lib/server/voice/voiceWebSocketHandler.js";
3
+ export const voiceServerCommand = {
4
+ command: "voice-server",
5
+ describe: "Start the real-time voice assistant server (Soniox STT + Cartesia TTS + Cobra VAD)",
6
+ builder: (yargs) => yargs.option("port", {
7
+ alias: "p",
8
+ type: "number",
9
+ default: 3000,
10
+ describe: "Port to listen on",
11
+ }),
12
+ handler: async (argv) => {
13
+ configureVoiceServerEnvironment();
14
+ await startVoiceServer(argv.port);
15
+ },
16
+ };
17
+ //# sourceMappingURL=voiceServer.js.map
@@ -16,6 +16,8 @@ import { TelemetryCommandFactory } from "./commands/telemetry.js";
16
16
  import { proxyStartCommand, proxyStatusCommand, proxyTelemetryCommand, proxySetupCommand, proxyGuardCommand, proxyInstallCommand, proxyUninstallCommand, } from "./commands/proxy.js";
17
17
  import { EvaluateCommandFactory } from "./commands/evaluate.js";
18
18
  import { TaskCommandFactory } from "./commands/task.js";
19
+ import { AutoresearchCommandFactory } from "./commands/autoresearch.js";
20
+ import { voiceServerCommand } from "./commands/voiceServer.js";
19
21
  // Enhanced CLI with Professional UX
20
22
  export function initializeCliParser() {
21
23
  return (yargs(hideBin(process.argv))
@@ -203,6 +205,10 @@ export function initializeCliParser() {
203
205
  // Evaluate Command Group - Using EvaluateCommandFactory
204
206
  .command(EvaluateCommandFactory.createEvaluateCommand())
205
207
  // Task Command Group - Scheduled and self-running tasks
206
- .command(TaskCommandFactory.createTaskCommands())); // Close the main return statement
208
+ .command(TaskCommandFactory.createTaskCommands())
209
+ // AutoResearch Command Group - Automated AI-driven research experiments
210
+ .command(AutoresearchCommandFactory.createAutoresearchCommands())
211
+ // Real-time voice server (Soniox STT + Cartesia TTS + Cobra VAD)
212
+ .command(voiceServerCommand)); // Close the main return statement
207
213
  }
208
214
  //# sourceMappingURL=parser.js.map