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/README.md +63 -20
- package/dist/cli.js +63 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +54 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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(
|
|
918
|
-
await fs3.writeFile(
|
|
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
|
-
|
|
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
|
-
|
|
2684
|
-
|
|
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
|
-
|
|
2691
|
-
|
|
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
|
}
|