openvole 0.3.0 → 0.3.2

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/index.d.ts CHANGED
@@ -576,6 +576,8 @@ declare class TaskQueue {
576
576
  }): AgentTask;
577
577
  /** Cancel a task by ID */
578
578
  cancel(taskId: string): boolean;
579
+ /** Cancel all queued tasks (for shutdown) */
580
+ cancelAll(): void;
579
581
  /** Get all tasks (queued + running + completed) */
580
582
  list(): AgentTask[];
581
583
  /** Get a task by ID */
@@ -627,7 +629,7 @@ declare class SchedulerStore {
627
629
  nextRun?: string;
628
630
  createdAt: number;
629
631
  }>;
630
- /** Clear all schedules (for shutdown) */
632
+ /** Clear all schedules (for shutdown). Disables persistence so the file is never overwritten. */
631
633
  clearAll(): void;
632
634
  /** Save schedules to disk */
633
635
  private persist;
@@ -724,6 +726,7 @@ interface VoleEngine {
724
726
  declare function createEngine(projectRoot: string, options?: {
725
727
  io?: VoleIO;
726
728
  configPath?: string;
729
+ headless?: boolean;
727
730
  }): Promise<VoleEngine>;
728
731
 
729
732
  export { type ActionError, type ActionErrorCode, type ActionResult, type ActiveSkill, type AgentContext, type AgentMessage, type AgentPlan, type AgentTask, type BootstrapHook, type BusEvents, type CompactHook, type EffectivePermissions, type HeartbeatConfig, type LoopConfig, type LoopDependencies, type LoopPhase, type MessageBus, type ObserveHook, PHASE_ORDER, type PawConfig, type PawDefinition, type PawInstance, type PawManifest, PawRegistry, type PerceiveHook, type PlannedAction, RateLimiter, type RateLimits, type ScheduleHook, SchedulerStore, type SkillDefinition, type SkillInstance, SkillRegistry, TaskQueue, type TaskStatus, type ToolDefinition, ToolRegistry, type ToolRegistryEntry, type ToolSummary, type TransportType, Vault, type VaultEntry, type VoleConfig, type VoleEngine, type VoleIO, type VoleLock, addPawToLock, addSkillToLock, buildActiveSkills, computeEffectivePermissions, createActionError, createAgentContext, createEngine, createMessageBus, createTtyIO, defineConfig, failureResult, loadConfig, readLockFile, readPawManifest, removePawFromLock, removeSkillFromLock, resolvePawPath, resolveSkills, runAgentLoop, successResult, validatePermissions, writeLockFile };
package/dist/index.js CHANGED
@@ -737,6 +737,19 @@ var TaskQueue = class {
737
737
  }
738
738
  return false;
739
739
  }
740
+ /** Cancel all queued tasks (for shutdown) */
741
+ cancelAll() {
742
+ while (this.queue.length > 0) {
743
+ const task = this.queue.shift();
744
+ task.status = "cancelled";
745
+ task.completedAt = Date.now();
746
+ this.completed.push(task);
747
+ this.bus.emit("task:cancelled", { taskId: task.id });
748
+ }
749
+ for (const task of this.running.values()) {
750
+ task.status = "cancelled";
751
+ }
752
+ }
740
753
  /** Get all tasks (queued + running + completed) */
741
754
  list() {
742
755
  return [
@@ -853,7 +866,8 @@ var SchedulerStore = class {
853
866
  if (persisted.length > 0) {
854
867
  logger4.info(`Restored ${persisted.length} schedule(s) from disk`);
855
868
  }
856
- } catch {
869
+ } catch (err) {
870
+ logger4.warn(`Could not restore schedules: ${err}`);
857
871
  }
858
872
  }
859
873
  /** Create or replace a recurring schedule */
@@ -896,8 +910,9 @@ var SchedulerStore = class {
896
910
  createdAt
897
911
  }));
898
912
  }
899
- /** Clear all schedules (for shutdown) */
913
+ /** Clear all schedules (for shutdown). Disables persistence so the file is never overwritten. */
900
914
  clearAll() {
915
+ this.savePath = void 0;
901
916
  for (const entry of this.schedules.values()) {
902
917
  entry.job.stop();
903
918
  }
@@ -906,16 +921,29 @@ var SchedulerStore = class {
906
921
  }
907
922
  /** Save schedules to disk */
908
923
  async persist() {
909
- if (!this.savePath) return;
924
+ const targetPath = this.savePath;
925
+ if (!targetPath) return;
910
926
  const toSave = Array.from(this.schedules.values()).filter((s) => s.id !== "__heartbeat__").map(({ id, input, cron, createdAt }) => ({
911
927
  id,
912
928
  input,
913
929
  cron,
914
930
  createdAt
915
931
  }));
932
+ if (toSave.length === 0) {
933
+ try {
934
+ const existing = await fs3.readFile(targetPath, "utf-8");
935
+ const parsed = JSON.parse(existing);
936
+ if (parsed.length > 0) {
937
+ logger4.warn(`Refusing to overwrite ${parsed.length} persisted schedule(s) with empty list`);
938
+ return;
939
+ }
940
+ } catch {
941
+ }
942
+ }
916
943
  try {
917
- await fs3.mkdir(path3.dirname(this.savePath), { recursive: true });
918
- await fs3.writeFile(this.savePath, JSON.stringify(toSave, null, 2) + "\n", "utf-8");
944
+ await fs3.mkdir(path3.dirname(targetPath), { recursive: true });
945
+ await fs3.writeFile(targetPath, JSON.stringify(toSave, null, 2) + "\n", "utf-8");
946
+ logger4.debug(`Persisted ${toSave.length} schedule(s) to disk`);
919
947
  } catch (err) {
920
948
  logger4.error(`Failed to persist schedules: ${err}`);
921
949
  }
@@ -1287,8 +1315,14 @@ var IpcTransport = class {
1287
1315
  this.handlers.clear();
1288
1316
  }
1289
1317
  send(message) {
1318
+ if (this.disposed) return;
1290
1319
  if (this.type === "ipc") {
1291
- this.childProcess.send?.(message);
1320
+ try {
1321
+ if (this.childProcess.connected) {
1322
+ this.childProcess.send?.(message);
1323
+ }
1324
+ } catch {
1325
+ }
1292
1326
  } else {
1293
1327
  const json = JSON.stringify(message);
1294
1328
  const header = `Content-Length: ${Buffer.byteLength(json)}\r
@@ -2649,6 +2683,7 @@ async function createEngine(projectRoot, options) {
2649
2683
  rateLimiter
2650
2684
  });
2651
2685
  });
2686
+ let shuttingDown = false;
2652
2687
  const engine = {
2653
2688
  bus,
2654
2689
  toolRegistry,
@@ -2659,10 +2694,12 @@ async function createEngine(projectRoot, options) {
2659
2694
  config,
2660
2695
  async start() {
2661
2696
  engineLogger.info("Starting OpenVole...");
2697
+ const headless = options?.headless ?? false;
2662
2698
  if (config.brain) {
2663
2699
  } else {
2664
2700
  engineLogger.info("No Brain Paw configured \u2014 Think step will be a no-op");
2665
2701
  }
2702
+ const headlessSkipPatterns = ["paw-dashboard", "paw-telegram", "paw-slack", "paw-discord", "paw-whatsapp"];
2666
2703
  const pawConfigs = config.paws.map(normalizePawConfig);
2667
2704
  const brainConfig = pawConfigs.find((p) => p.name === config.brain);
2668
2705
  const subprocessPaws = pawConfigs.filter(
@@ -2680,15 +2717,18 @@ async function createEngine(projectRoot, options) {
2680
2717
  pawRegistry.setBrain("");
2681
2718
  }
2682
2719
  }
2683
- for (const pawConfig of subprocessPaws) {
2684
- await pawRegistry.load(pawConfig);
2685
- }
2720
+ const pawsToLoad = headless ? subprocessPaws.filter((p) => !headlessSkipPatterns.some((pat) => p.name.includes(pat))) : subprocessPaws;
2721
+ await Promise.all(pawsToLoad.map((pawConfig) => pawRegistry.load(pawConfig)));
2686
2722
  for (const skillName of config.skills) {
2687
2723
  await skillRegistry.load(skillName);
2688
2724
  }
2689
2725
  skillRegistry.resolve();
2690
- await scheduler.restore();
2691
- if (config.heartbeat.enabled) {
2726
+ if (!headless) {
2727
+ await scheduler.restore();
2728
+ } else {
2729
+ await scheduler.loadFromDisk();
2730
+ }
2731
+ if (config.heartbeat.enabled && !headless) {
2692
2732
  const heartbeatMdPath = path10.resolve(projectRoot, ".openvole", "HEARTBEAT.md");
2693
2733
  const heartbeatCron = `*/${config.heartbeat.intervalMinutes} * * * *`;
2694
2734
  scheduler.add(
@@ -2719,8 +2759,11 @@ ${heartbeatContent}` : "Heartbeat wake-up. Check active skills and decide if any
2719
2759
  taskQueue.enqueue(input, source, sessionId ? { sessionId } : void 0);
2720
2760
  },
2721
2761
  async shutdown() {
2762
+ if (shuttingDown) return;
2763
+ shuttingDown = true;
2722
2764
  engineLogger.info("Shutting down...");
2723
2765
  scheduler.clearAll();
2766
+ taskQueue.cancelAll();
2724
2767
  for (const paw of pawRegistry.list()) {
2725
2768
  await pawRegistry.unload(paw.name);
2726
2769
  }