vole-agent 0.1.2 → 0.1.4

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/dist/app.js CHANGED
@@ -3,12 +3,14 @@ import {
3
3
  CliChatSession,
4
4
  loadConfig,
5
5
  renderToolResult
6
- } from "./chunk-DZLI6PBD.js";
6
+ } from "./chunk-ZGGSF3JK.js";
7
7
 
8
8
  // src/app.tsx
9
9
  import { useState, useEffect, useCallback, useMemo, useRef as useRef2 } from "react";
10
10
  import { render, Box, Text as Text2, useInput, useApp, useAnimation, useStdout, Static } from "ink";
11
11
  import TextInput from "ink-text-input";
12
+ import { readFile } from "fs/promises";
13
+ import { join } from "path";
12
14
 
13
15
  // src/Markdown.tsx
14
16
  import { marked as marked2 } from "marked";
@@ -452,6 +454,10 @@ function ChatApp({ config, cliOptions, sessionId }) {
452
454
  async (message) => {
453
455
  if (session === null || isSending || message.trim() === "") return;
454
456
  const trimmed = message.trim();
457
+ if (config.secrets.apiKey === void 0) {
458
+ setMessages((prev) => [...prev, { role: "user", content: trimmed }, { role: "error", content: 'No API key configured. Add one to ~/.vole/config.json (e.g. {"apiKey": "sk-..."}) or set VOLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY in your shell.' }]);
459
+ return;
460
+ }
455
461
  const controller = new AbortController();
456
462
  abortControllerRef.current = controller;
457
463
  setMessages((prev) => [...prev, { role: "user", content: trimmed }]);
@@ -660,10 +666,21 @@ function ChatApp({ config, cliOptions, sessionId }) {
660
666
  ] })
661
667
  ] });
662
668
  }
669
+ async function readJsonFile(path) {
670
+ try {
671
+ return JSON.parse(await readFile(path, "utf8"));
672
+ } catch {
673
+ return void 0;
674
+ }
675
+ }
663
676
  async function runInkChat({ args, env, sessionsDirectory }) {
664
677
  let config;
665
678
  try {
666
- config = loadConfig({ env });
679
+ const home = env.HOME ?? process.env.HOME;
680
+ const input = { env };
681
+ if (home !== void 0) input.userConfig = await readJsonFile(join(home, ".vole", "config.json"));
682
+ input.projectConfig = await readJsonFile("vole.config.json");
683
+ config = loadConfig(input);
667
684
  } catch (err) {
668
685
  process.stderr.write(
669
686
  `Configuration error: ${err instanceof Error ? err.message : String(err)}
@@ -672,13 +689,6 @@ async function runInkChat({ args, env, sessionsDirectory }) {
672
689
  process.exitCode = 1;
673
690
  return;
674
691
  }
675
- if (config.secrets.apiKey === void 0) {
676
- process.stderr.write(
677
- "Missing VOLE_API_KEY or OPENROUTER_API_KEY. Set one to start `vole chat`, or use `vole chat --fake-interactive` for local learning.\n"
678
- );
679
- process.exitCode = 1;
680
- return;
681
- }
682
692
  const sessionIndex = args.indexOf("--session");
683
693
  const sessionId = sessionIndex !== -1 && args[sessionIndex + 1] !== void 0 ? args[sessionIndex + 1] : void 0;
684
694
  const cliOptions = {
@@ -3301,6 +3301,23 @@ function isNodeError4(error) {
3301
3301
 
3302
3302
  // src/index.ts
3303
3303
  var cliPackageName = "@vole/cli";
3304
+ async function readJsonFile(path) {
3305
+ try {
3306
+ return JSON.parse(await readFile6(path, "utf8"));
3307
+ } catch {
3308
+ return void 0;
3309
+ }
3310
+ }
3311
+ async function loadCliConfig(options = {}) {
3312
+ const env = options.env ?? process.env;
3313
+ const home = env.HOME ?? process.env.HOME;
3314
+ const input = { env };
3315
+ if (home !== void 0) {
3316
+ input.userConfig = await readJsonFile(join7(home, ".vole", "config.json"));
3317
+ }
3318
+ input.projectConfig = await readJsonFile(join7("vole.config.json"));
3319
+ return loadConfig(input);
3320
+ }
3304
3321
  var AGENT_SYSTEM_INSTRUCTION = `You are Vole, a capable coding and general-purpose agent.
3305
3322
 
3306
3323
  ## Tool Call Style
@@ -3446,7 +3463,7 @@ async function runFakeChatTurn(input, options) {
3446
3463
  stderr: "Missing message for `chat --fake`.\n"
3447
3464
  };
3448
3465
  }
3449
- const session = CliChatSession.createFake(`Fake response to: ${message}`, options);
3466
+ const session = await CliChatSession.createFake(`Fake response to: ${message}`, options);
3450
3467
  const turn = await session.sendMessage(message);
3451
3468
  const commandOutput = await renderSlashCommands(session, slashCommands);
3452
3469
  const assistantText = turn.assistantText;
@@ -3463,18 +3480,18 @@ ${commandOutput}`,
3463
3480
  };
3464
3481
  }
3465
3482
  async function runInteractiveFakeChat(options, args) {
3466
- const session = CliChatSession.createFake((message) => `Fake response to: ${message}`, options, {
3483
+ const session = await CliChatSession.createFake((message) => `Fake response to: ${message}`, options, {
3467
3484
  ...args.sessionId === void 0 ? {} : { sessionId: args.sessionId }
3468
3485
  });
3469
3486
  return runInteractiveLoop(session, "Vole chat (fake provider)", options);
3470
3487
  }
3471
3488
  async function runInteractiveConfiguredChat(options, args) {
3472
- const config = loadConfig(options.env ? { env: options.env } : {});
3489
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3473
3490
  if (config.secrets.apiKey === void 0) {
3474
3491
  return {
3475
3492
  exitCode: 1,
3476
3493
  stdout: "",
3477
- stderr: "Missing VOLE_API_KEY or OPENROUTER_API_KEY. Set one to start `vole chat`, or use `vole chat --fake-interactive` for local learning.\n"
3494
+ stderr: "No API key configured. Add one to ~/.vole/config.json or set VOLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY in your shell.\n"
3478
3495
  };
3479
3496
  }
3480
3497
  if (args.resume && args.sessionId !== void 0) {
@@ -3503,7 +3520,7 @@ Resumed session: ${resumedSessionId}`,
3503
3520
  );
3504
3521
  }
3505
3522
  async function runListSessions(options) {
3506
- const config = loadConfig(options.env ? { env: options.env } : {});
3523
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3507
3524
  const store = createConfiguredSessionStore(config, options, createSessionId());
3508
3525
  const sessions = await store.listSessions();
3509
3526
  if (sessions.length === 0) {
@@ -3520,12 +3537,12 @@ async function runListSessions(options) {
3520
3537
  };
3521
3538
  }
3522
3539
  async function runMemoryDreaming(options) {
3523
- const config = loadConfig(options.env ? { env: options.env } : {});
3540
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3524
3541
  if (config.secrets.apiKey === void 0) {
3525
3542
  return {
3526
3543
  exitCode: 1,
3527
3544
  stdout: "",
3528
- stderr: "Missing VOLE_API_KEY or OPENROUTER_API_KEY. Set one to run memory dreaming.\n"
3545
+ stderr: "No API key configured. Add one to ~/.vole/config.json or set VOLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY in your shell.\n"
3529
3546
  };
3530
3547
  }
3531
3548
  if (config.memory.longTermFiles !== "write") {
@@ -3543,12 +3560,12 @@ Be concise and factual. Do not duplicate what is already in MEMORY.md.`;
3543
3560
  return runBackgroundTask(dreamGoal, "auto", options);
3544
3561
  }
3545
3562
  async function runBackgroundTask(goal, mode, options) {
3546
- const config = loadConfig(options.env ? { env: options.env } : {});
3563
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3547
3564
  if (config.secrets.apiKey === void 0) {
3548
3565
  return {
3549
3566
  exitCode: 1,
3550
3567
  stdout: "",
3551
- stderr: "Missing VOLE_API_KEY or OPENROUTER_API_KEY. Set one to run background tasks.\n"
3568
+ stderr: "No API key configured. Add one to ~/.vole/config.json or set VOLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY in your shell.\n"
3552
3569
  };
3553
3570
  }
3554
3571
  const effectiveConfig = options.sessionsDirectory ? { ...config, sessions: { directory: options.sessionsDirectory } } : config;
@@ -3626,7 +3643,7 @@ ${resultLine}
3626
3643
  };
3627
3644
  }
3628
3645
  async function runListTasks(options, limit) {
3629
- const config = loadConfig(options.env ? { env: options.env } : {});
3646
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3630
3647
  const effectiveConfig = options.sessionsDirectory ? { ...config, sessions: { directory: options.sessionsDirectory } } : config;
3631
3648
  const sessionsDir = resolveSessionsDirectory(effectiveConfig, options.env);
3632
3649
  const taskStore = new JsonlTaskStore(join7(sessionsDir, "task-runs.jsonl"));
@@ -3733,12 +3750,12 @@ async function runDaemonTask(task, config, options, taskStore) {
3733
3750
  await writeHeartbeat(heartbeatPath, endHeartbeat);
3734
3751
  }
3735
3752
  async function runDaemon(options, once) {
3736
- const config = loadConfig(options.env ? { env: options.env } : {});
3753
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3737
3754
  if (config.secrets.apiKey === void 0) {
3738
3755
  return {
3739
3756
  exitCode: 1,
3740
3757
  stdout: "",
3741
- stderr: "Missing VOLE_API_KEY or OPENROUTER_API_KEY. Set one to run the daemon.\n"
3758
+ stderr: "No API key configured. Add one to ~/.vole/config.json or set VOLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY in your shell.\n"
3742
3759
  };
3743
3760
  }
3744
3761
  const effectiveConfig = options.sessionsDirectory ? { ...config, sessions: { directory: options.sessionsDirectory } } : config;
@@ -3787,14 +3804,14 @@ async function runDaemon(options, once) {
3787
3804
  process.once("SIGINT", shutdown);
3788
3805
  });
3789
3806
  }
3790
- function resolveTaskflowFilePath(options) {
3791
- const config = loadConfig(options.env ? { env: options.env } : {});
3807
+ async function resolveTaskflowFilePath(options) {
3808
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3792
3809
  const effectiveConfig = options.sessionsDirectory ? { ...config, sessions: { directory: options.sessionsDirectory } } : config;
3793
3810
  const sessionsDir = resolveSessionsDirectory(effectiveConfig, options.env);
3794
3811
  return join7(dirname4(sessionsDir), "taskflow.jsonl");
3795
3812
  }
3796
3813
  async function runTaskflowList(options, limit) {
3797
- const filePath = resolveTaskflowFilePath(options);
3814
+ const filePath = await resolveTaskflowFilePath(options);
3798
3815
  const store = new JsonlTaskFlowStore(filePath);
3799
3816
  const records = await store.list(limit !== void 0 ? { limit } : {});
3800
3817
  if (records.length === 0) {
@@ -3815,7 +3832,7 @@ async function runTaskflowList(options, limit) {
3815
3832
  };
3816
3833
  }
3817
3834
  async function runTaskflowShow(id, options) {
3818
- const filePath = resolveTaskflowFilePath(options);
3835
+ const filePath = await resolveTaskflowFilePath(options);
3819
3836
  const store = new JsonlTaskFlowStore(filePath);
3820
3837
  const record = await store.get(id);
3821
3838
  if (record === void 0) {
@@ -3845,7 +3862,7 @@ async function runTaskflowShow(id, options) {
3845
3862
  };
3846
3863
  }
3847
3864
  async function runTaskflowCancel(id, options) {
3848
- const filePath = resolveTaskflowFilePath(options);
3865
+ const filePath = await resolveTaskflowFilePath(options);
3849
3866
  const store = new JsonlTaskFlowStore(filePath);
3850
3867
  const updated = await store.update(id, { status: "cancelled" });
3851
3868
  if (updated === void 0) {
@@ -3869,7 +3886,7 @@ function resolveSkillsDirectory(config, options) {
3869
3886
  return join7(dirname4(sessionsDir), "skills");
3870
3887
  }
3871
3888
  async function runSkillsList(options) {
3872
- const config = loadConfig(options.env ? { env: options.env } : {});
3889
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3873
3890
  const skillsDir = resolveSkillsDirectory(config, options);
3874
3891
  const loader = new SkillLoader();
3875
3892
  const skills = await loader.load({
@@ -3884,7 +3901,7 @@ async function runSkillsList(options) {
3884
3901
  };
3885
3902
  }
3886
3903
  async function runSkillsInstall(sourcePath, options) {
3887
- const config = loadConfig(options.env ? { env: options.env } : {});
3904
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3888
3905
  const skillsDir = resolveSkillsDirectory(config, options);
3889
3906
  const manager = new SkillManager(skillsDir);
3890
3907
  try {
@@ -3905,7 +3922,7 @@ async function runSkillsInstall(sourcePath, options) {
3905
3922
  }
3906
3923
  }
3907
3924
  async function runSkillsLifecycle(action, name, options) {
3908
- const config = loadConfig(options.env ? { env: options.env } : {});
3925
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3909
3926
  const skillsDir = resolveSkillsDirectory(config, options);
3910
3927
  const manager = new SkillManager(skillsDir);
3911
3928
  try {
@@ -3932,7 +3949,7 @@ async function runSkillsLifecycle(action, name, options) {
3932
3949
  }
3933
3950
  }
3934
3951
  async function runSkillsReview(name, options) {
3935
- const config = loadConfig(options.env ? { env: options.env } : {});
3952
+ const config = await loadCliConfig(options.env ? { env: options.env } : {});
3936
3953
  const skillsDir = resolveSkillsDirectory(config, options);
3937
3954
  const manager = new SkillManager(skillsDir);
3938
3955
  const def = await manager.review(name);
@@ -4090,8 +4107,8 @@ var CliChatSession = class _CliChatSession {
4090
4107
  close() {
4091
4108
  this.#gateway?.unregister(this.#sessionId);
4092
4109
  }
4093
- static createFake(responseContent = "Fake response to: Hello trace", options = {}, sessionOptions = {}) {
4094
- const config = redactedConfig(loadConfig(options.env ? { env: options.env } : {}));
4110
+ static async createFake(responseContent = "Fake response to: Hello trace", options = {}, sessionOptions = {}) {
4111
+ const config = redactedConfig(await loadCliConfig(options.env ? { env: options.env } : {}));
4095
4112
  const approvalPromptLog = [];
4096
4113
  const provider = options.fakeModelOutputs ? new FakeModelProvider(options.fakeModelOutputs) : typeof responseContent === "function" ? new MessageMappedFakeModelProvider(responseContent) : new FakeModelProvider([
4097
4114
  {
@@ -4123,9 +4140,6 @@ var CliChatSession = class _CliChatSession {
4123
4140
  );
4124
4141
  }
4125
4142
  static async createConfigured(config, options = {}, sessionOptions = {}) {
4126
- if (config.secrets.apiKey === void 0) {
4127
- throw new Error("Configured chat requires an API key.");
4128
- }
4129
4143
  const sessionId = sessionOptions.sessionId ?? createSessionId();
4130
4144
  const currentDate = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4131
4145
  const approvalPromptLog = [];
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  renderTodosProgress,
9
9
  renderToolResult,
10
10
  runCli
11
- } from "./chunk-DZLI6PBD.js";
11
+ } from "./chunk-ZGGSF3JK.js";
12
12
  export {
13
13
  CliChatSession,
14
14
  cliPackageName,