opencode-swarm-plugin 0.11.2 → 0.12.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.
- package/.beads/issues.jsonl +6 -0
- package/README.md +8 -8
- package/bin/swarm.ts +200 -14
- package/dist/index.js +52 -1
- package/dist/plugin.js +51 -1
- package/examples/plugin-wrapper-template.ts +723 -0
- package/package.json +1 -1
- package/src/agent-mail.ts +106 -3
- package/src/index.ts +22 -0
package/package.json
CHANGED
package/src/agent-mail.ts
CHANGED
|
@@ -62,9 +62,83 @@ export interface AgentMailState {
|
|
|
62
62
|
// Module-level state (keyed by sessionID)
|
|
63
63
|
// ============================================================================
|
|
64
64
|
|
|
65
|
+
import {
|
|
66
|
+
existsSync,
|
|
67
|
+
mkdirSync,
|
|
68
|
+
readFileSync,
|
|
69
|
+
writeFileSync,
|
|
70
|
+
unlinkSync,
|
|
71
|
+
} from "fs";
|
|
72
|
+
import { join } from "path";
|
|
73
|
+
import { tmpdir } from "os";
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Directory for persisting session state across CLI invocations
|
|
77
|
+
* This allows `swarm tool` commands to share state
|
|
78
|
+
*/
|
|
79
|
+
const SESSION_STATE_DIR =
|
|
80
|
+
process.env.SWARM_STATE_DIR || join(tmpdir(), "swarm-sessions");
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get the file path for a session's state
|
|
84
|
+
*/
|
|
85
|
+
function getSessionStatePath(sessionID: string): string {
|
|
86
|
+
// Sanitize sessionID to be filesystem-safe
|
|
87
|
+
const safeID = sessionID.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
88
|
+
return join(SESSION_STATE_DIR, `${safeID}.json`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Load session state from disk
|
|
93
|
+
*/
|
|
94
|
+
function loadSessionState(sessionID: string): AgentMailState | null {
|
|
95
|
+
const path = getSessionStatePath(sessionID);
|
|
96
|
+
try {
|
|
97
|
+
if (existsSync(path)) {
|
|
98
|
+
const data = readFileSync(path, "utf-8");
|
|
99
|
+
return JSON.parse(data) as AgentMailState;
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
// File might be corrupted or inaccessible - ignore and return null
|
|
103
|
+
console.warn(`[agent-mail] Could not load session state: ${error}`);
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Save session state to disk
|
|
110
|
+
*/
|
|
111
|
+
function saveSessionState(sessionID: string, state: AgentMailState): void {
|
|
112
|
+
try {
|
|
113
|
+
// Ensure directory exists
|
|
114
|
+
if (!existsSync(SESSION_STATE_DIR)) {
|
|
115
|
+
mkdirSync(SESSION_STATE_DIR, { recursive: true });
|
|
116
|
+
}
|
|
117
|
+
const path = getSessionStatePath(sessionID);
|
|
118
|
+
writeFileSync(path, JSON.stringify(state, null, 2));
|
|
119
|
+
} catch (error) {
|
|
120
|
+
// Non-fatal - state just won't persist
|
|
121
|
+
console.warn(`[agent-mail] Could not save session state: ${error}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Delete session state from disk
|
|
127
|
+
*/
|
|
128
|
+
function deleteSessionState(sessionID: string): void {
|
|
129
|
+
const path = getSessionStatePath(sessionID);
|
|
130
|
+
try {
|
|
131
|
+
if (existsSync(path)) {
|
|
132
|
+
unlinkSync(path);
|
|
133
|
+
}
|
|
134
|
+
} catch {
|
|
135
|
+
// Ignore errors on cleanup
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
65
139
|
/**
|
|
66
140
|
* State storage keyed by sessionID.
|
|
67
|
-
*
|
|
141
|
+
* In-memory cache that also persists to disk for CLI usage.
|
|
68
142
|
*/
|
|
69
143
|
const sessionStates = new Map<string, AgentMailState>();
|
|
70
144
|
|
|
@@ -691,9 +765,23 @@ export async function mcpCall<T>(
|
|
|
691
765
|
|
|
692
766
|
/**
|
|
693
767
|
* Get Agent Mail state for a session, or throw if not initialized
|
|
768
|
+
*
|
|
769
|
+
* Checks in-memory cache first, then falls back to disk storage.
|
|
770
|
+
* This allows CLI invocations to share state across calls.
|
|
694
771
|
*/
|
|
695
772
|
function requireState(sessionID: string): AgentMailState {
|
|
696
|
-
|
|
773
|
+
// Check in-memory cache first
|
|
774
|
+
let state = sessionStates.get(sessionID);
|
|
775
|
+
|
|
776
|
+
// If not in memory, try loading from disk
|
|
777
|
+
if (!state) {
|
|
778
|
+
state = loadSessionState(sessionID) ?? undefined;
|
|
779
|
+
if (state) {
|
|
780
|
+
// Cache in memory for subsequent calls in same process
|
|
781
|
+
sessionStates.set(sessionID, state);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
697
785
|
if (!state) {
|
|
698
786
|
throw new AgentMailNotInitializedError();
|
|
699
787
|
}
|
|
@@ -702,23 +790,38 @@ function requireState(sessionID: string): AgentMailState {
|
|
|
702
790
|
|
|
703
791
|
/**
|
|
704
792
|
* Store Agent Mail state for a session
|
|
793
|
+
*
|
|
794
|
+
* Saves to both in-memory cache and disk for CLI persistence.
|
|
705
795
|
*/
|
|
706
796
|
function setState(sessionID: string, state: AgentMailState): void {
|
|
707
797
|
sessionStates.set(sessionID, state);
|
|
798
|
+
saveSessionState(sessionID, state);
|
|
708
799
|
}
|
|
709
800
|
|
|
710
801
|
/**
|
|
711
802
|
* Get state if exists (for cleanup hooks)
|
|
803
|
+
*
|
|
804
|
+
* Checks in-memory cache first, then falls back to disk storage.
|
|
712
805
|
*/
|
|
713
806
|
function getState(sessionID: string): AgentMailState | undefined {
|
|
714
|
-
|
|
807
|
+
let state = sessionStates.get(sessionID);
|
|
808
|
+
if (!state) {
|
|
809
|
+
state = loadSessionState(sessionID) ?? undefined;
|
|
810
|
+
if (state) {
|
|
811
|
+
sessionStates.set(sessionID, state);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
return state;
|
|
715
815
|
}
|
|
716
816
|
|
|
717
817
|
/**
|
|
718
818
|
* Clear state for a session
|
|
819
|
+
*
|
|
820
|
+
* Removes from both in-memory cache and disk.
|
|
719
821
|
*/
|
|
720
822
|
function clearState(sessionID: string): void {
|
|
721
823
|
sessionStates.delete(sessionID);
|
|
824
|
+
deleteSessionState(sessionID);
|
|
722
825
|
}
|
|
723
826
|
|
|
724
827
|
// ============================================================================
|
package/src/index.ts
CHANGED
|
@@ -280,6 +280,28 @@ export {
|
|
|
280
280
|
type StrategyDefinition,
|
|
281
281
|
} from "./swarm";
|
|
282
282
|
|
|
283
|
+
// =============================================================================
|
|
284
|
+
// Unified Tool Registry for CLI
|
|
285
|
+
// =============================================================================
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* All tools in a single registry for CLI tool execution
|
|
289
|
+
*
|
|
290
|
+
* This is used by `swarm tool <name>` command to dynamically execute tools.
|
|
291
|
+
* Each tool has an `execute` function that takes (args, ctx) and returns a string.
|
|
292
|
+
*/
|
|
293
|
+
export const allTools = {
|
|
294
|
+
...beadsTools,
|
|
295
|
+
...agentMailTools,
|
|
296
|
+
...structuredTools,
|
|
297
|
+
...swarmTools,
|
|
298
|
+
} as const;
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Type for CLI tool names (all available tools)
|
|
302
|
+
*/
|
|
303
|
+
export type CLIToolName = keyof typeof allTools;
|
|
304
|
+
|
|
283
305
|
/**
|
|
284
306
|
* Re-export storage module
|
|
285
307
|
*
|