@zhijiewang/openharness 0.9.3 → 0.11.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/README.md +87 -24
- package/dist/Tool.d.ts.map +1 -1
- package/dist/Tool.js +7 -1
- package/dist/Tool.js.map +1 -1
- package/dist/Tool.test.js +8 -2
- package/dist/Tool.test.js.map +1 -1
- package/dist/agents/roles.d.ts +25 -0
- package/dist/agents/roles.d.ts.map +1 -0
- package/dist/agents/roles.js +116 -0
- package/dist/agents/roles.js.map +1 -0
- package/dist/agents/roles.test.d.ts +2 -0
- package/dist/agents/roles.test.d.ts.map +1 -0
- package/dist/agents/roles.test.js +38 -0
- package/dist/agents/roles.test.js.map +1 -0
- package/dist/commands/commands-new.test.d.ts +5 -0
- package/dist/commands/commands-new.test.d.ts.map +1 -0
- package/dist/commands/commands-new.test.js +132 -0
- package/dist/commands/commands-new.test.js.map +1 -0
- package/dist/commands/commands.test.js +31 -0
- package/dist/commands/commands.test.js.map +1 -1
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +199 -6
- package/dist/commands/index.js.map +1 -1
- package/dist/components/REPL.js +1 -1
- package/dist/components/REPL.js.map +1 -1
- package/dist/git/git.test.js +33 -1
- package/dist/git/git.test.js.map +1 -1
- package/dist/git/index.d.ts +12 -0
- package/dist/git/index.d.ts.map +1 -1
- package/dist/git/index.js +47 -2
- package/dist/git/index.js.map +1 -1
- package/dist/harness/checkpoints.d.ts +36 -0
- package/dist/harness/checkpoints.d.ts.map +1 -0
- package/dist/harness/checkpoints.js +156 -0
- package/dist/harness/checkpoints.js.map +1 -0
- package/dist/harness/config.d.ts +3 -0
- package/dist/harness/config.d.ts.map +1 -1
- package/dist/harness/config.js +35 -2
- package/dist/harness/config.js.map +1 -1
- package/dist/harness/config.test.js +21 -1
- package/dist/harness/config.test.js.map +1 -1
- package/dist/harness/hooks-env.test.d.ts +5 -0
- package/dist/harness/hooks-env.test.d.ts.map +1 -0
- package/dist/harness/hooks-env.test.js +41 -0
- package/dist/harness/hooks-env.test.js.map +1 -0
- package/dist/harness/hooks.d.ts +7 -0
- package/dist/harness/hooks.d.ts.map +1 -1
- package/dist/harness/hooks.js +14 -0
- package/dist/harness/hooks.js.map +1 -1
- package/dist/harness/keybindings.d.ts.map +1 -1
- package/dist/harness/keybindings.js +4 -0
- package/dist/harness/keybindings.js.map +1 -1
- package/dist/harness/memory.d.ts +19 -0
- package/dist/harness/memory.d.ts.map +1 -1
- package/dist/harness/memory.js +85 -0
- package/dist/harness/memory.js.map +1 -1
- package/dist/harness/onboarding.d.ts +1 -1
- package/dist/harness/onboarding.d.ts.map +1 -1
- package/dist/harness/onboarding.js +59 -4
- package/dist/harness/onboarding.js.map +1 -1
- package/dist/harness/onboarding.test.d.ts +5 -0
- package/dist/harness/onboarding.test.d.ts.map +1 -0
- package/dist/harness/onboarding.test.js +93 -0
- package/dist/harness/onboarding.test.js.map +1 -0
- package/dist/harness/rules.d.ts +6 -1
- package/dist/harness/rules.d.ts.map +1 -1
- package/dist/harness/rules.js +52 -5
- package/dist/harness/rules.js.map +1 -1
- package/dist/harness/rules.test.js +30 -1
- package/dist/harness/rules.test.js.map +1 -1
- package/dist/harness/session.d.ts +8 -1
- package/dist/harness/session.d.ts.map +1 -1
- package/dist/harness/session.js +13 -5
- package/dist/harness/session.js.map +1 -1
- package/dist/harness/store.d.ts +46 -0
- package/dist/harness/store.d.ts.map +1 -0
- package/dist/harness/store.js +56 -0
- package/dist/harness/store.js.map +1 -0
- package/dist/harness/store.test.d.ts +2 -0
- package/dist/harness/store.test.d.ts.map +1 -0
- package/dist/harness/store.test.js +71 -0
- package/dist/harness/store.test.js.map +1 -0
- package/dist/harness/submit-handler.d.ts +2 -0
- package/dist/harness/submit-handler.d.ts.map +1 -1
- package/dist/harness/submit-handler.js +3 -0
- package/dist/harness/submit-handler.js.map +1 -1
- package/dist/main.js +153 -26
- package/dist/main.js.map +1 -1
- package/dist/mcp/client.d.ts +2 -0
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +10 -2
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/loader.d.ts +2 -0
- package/dist/mcp/loader.d.ts.map +1 -1
- package/dist/mcp/loader.js +34 -18
- package/dist/mcp/loader.js.map +1 -1
- package/dist/mcp/loader.test.d.ts +7 -0
- package/dist/mcp/loader.test.d.ts.map +1 -0
- package/dist/mcp/loader.test.js +25 -0
- package/dist/mcp/loader.test.js.map +1 -0
- package/dist/providers/anthropic-convert.test.d.ts +5 -0
- package/dist/providers/anthropic-convert.test.d.ts.map +1 -0
- package/dist/providers/anthropic-convert.test.js +98 -0
- package/dist/providers/anthropic-convert.test.js.map +1 -0
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +23 -4
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/stream-parsing.test.d.ts +6 -0
- package/dist/providers/stream-parsing.test.d.ts.map +1 -0
- package/dist/providers/stream-parsing.test.js +174 -0
- package/dist/providers/stream-parsing.test.js.map +1 -0
- package/dist/query/compress.d.ts +17 -0
- package/dist/query/compress.d.ts.map +1 -0
- package/dist/query/compress.js +115 -0
- package/dist/query/compress.js.map +1 -0
- package/dist/query/errors.d.ts +10 -0
- package/dist/query/errors.d.ts.map +1 -0
- package/dist/query/errors.js +22 -0
- package/dist/query/errors.js.map +1 -0
- package/dist/query/index.d.ts +15 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +199 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/tools.d.ts +17 -0
- package/dist/query/tools.d.ts.map +1 -0
- package/dist/query/tools.js +129 -0
- package/dist/query/tools.js.map +1 -0
- package/dist/query/types.d.ts +31 -0
- package/dist/query/types.d.ts.map +1 -0
- package/dist/query/types.js +5 -0
- package/dist/query/types.js.map +1 -0
- package/dist/query.d.ts +8 -38
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +7 -444
- package/dist/query.js.map +1 -1
- package/dist/query.test.js +1 -1
- package/dist/query.test.js.map +1 -1
- package/dist/renderer/cells.d.ts.map +1 -1
- package/dist/renderer/cells.js +15 -2
- package/dist/renderer/cells.js.map +1 -1
- package/dist/renderer/colors.d.ts +8 -0
- package/dist/renderer/colors.d.ts.map +1 -0
- package/dist/renderer/colors.js +18 -0
- package/dist/renderer/colors.js.map +1 -0
- package/dist/renderer/diff.test.d.ts +5 -0
- package/dist/renderer/diff.test.d.ts.map +1 -0
- package/dist/renderer/diff.test.js +140 -0
- package/dist/renderer/diff.test.js.map +1 -0
- package/dist/renderer/differ.d.ts +1 -5
- package/dist/renderer/differ.d.ts.map +1 -1
- package/dist/renderer/differ.js +3 -20
- package/dist/renderer/differ.js.map +1 -1
- package/dist/renderer/e2e.test.js +136 -53
- package/dist/renderer/e2e.test.js.map +1 -1
- package/dist/renderer/image.test.d.ts +5 -0
- package/dist/renderer/image.test.d.ts.map +1 -0
- package/dist/renderer/image.test.js +66 -0
- package/dist/renderer/image.test.js.map +1 -0
- package/dist/renderer/index.d.ts +28 -16
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +289 -222
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/layout.d.ts +14 -5
- package/dist/renderer/layout.d.ts.map +1 -1
- package/dist/renderer/layout.js +522 -388
- package/dist/renderer/layout.js.map +1 -1
- package/dist/renderer/markdown.d.ts.map +1 -1
- package/dist/renderer/markdown.js +42 -36
- package/dist/renderer/markdown.js.map +1 -1
- package/dist/renderer/perf.test.js +1 -4
- package/dist/renderer/perf.test.js.map +1 -1
- package/dist/renderer/session-browser.test.d.ts +6 -0
- package/dist/renderer/session-browser.test.d.ts.map +1 -0
- package/dist/renderer/session-browser.test.js +95 -0
- package/dist/renderer/session-browser.test.js.map +1 -0
- package/dist/renderer/ui-ux.test.d.ts +15 -0
- package/dist/renderer/ui-ux.test.d.ts.map +1 -0
- package/dist/renderer/ui-ux.test.js +470 -0
- package/dist/renderer/ui-ux.test.js.map +1 -0
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +192 -67
- package/dist/repl.js.map +1 -1
- package/dist/services/StreamingToolExecutor.d.ts.map +1 -1
- package/dist/services/StreamingToolExecutor.js +4 -2
- package/dist/services/StreamingToolExecutor.js.map +1 -1
- package/dist/services/agent-messaging.d.ts +68 -0
- package/dist/services/agent-messaging.d.ts.map +1 -0
- package/dist/services/agent-messaging.js +121 -0
- package/dist/services/agent-messaging.js.map +1 -0
- package/dist/services/agent-messaging.test.d.ts +2 -0
- package/dist/services/agent-messaging.test.d.ts.map +1 -0
- package/dist/services/agent-messaging.test.js +88 -0
- package/dist/services/agent-messaging.test.js.map +1 -0
- package/dist/services/cron.d.ts +40 -0
- package/dist/services/cron.d.ts.map +1 -0
- package/dist/services/cron.js +90 -0
- package/dist/services/cron.js.map +1 -0
- package/dist/services/cron.test.d.ts +2 -0
- package/dist/services/cron.test.d.ts.map +1 -0
- package/dist/services/cron.test.js +49 -0
- package/dist/services/cron.test.js.map +1 -0
- package/dist/tools/AgentTool/index.d.ts +9 -0
- package/dist/tools/AgentTool/index.d.ts.map +1 -1
- package/dist/tools/AgentTool/index.js +89 -6
- package/dist/tools/AgentTool/index.js.map +1 -1
- package/dist/tools/BashTool/index.d.ts +6 -0
- package/dist/tools/BashTool/index.d.ts.map +1 -1
- package/dist/tools/BashTool/index.js +39 -1
- package/dist/tools/BashTool/index.js.map +1 -1
- package/dist/tools/FileEditTool/index.js +4 -4
- package/dist/tools/FileEditTool/index.js.map +1 -1
- package/dist/tools/FileReadTool/index.d.ts +3 -0
- package/dist/tools/FileReadTool/index.d.ts.map +1 -1
- package/dist/tools/FileReadTool/index.js +102 -4
- package/dist/tools/FileReadTool/index.js.map +1 -1
- package/dist/tools/FileWriteTool/index.d.ts.map +1 -1
- package/dist/tools/FileWriteTool/index.js +20 -5
- package/dist/tools/FileWriteTool/index.js.map +1 -1
- package/dist/tools/GlobTool/index.d.ts.map +1 -1
- package/dist/tools/GlobTool/index.js +4 -61
- package/dist/tools/GlobTool/index.js.map +1 -1
- package/dist/tools/GrepTool/index.d.ts +30 -0
- package/dist/tools/GrepTool/index.d.ts.map +1 -1
- package/dist/tools/GrepTool/index.js +153 -72
- package/dist/tools/GrepTool/index.js.map +1 -1
- package/dist/tools/LSTool/index.d.ts +3 -0
- package/dist/tools/LSTool/index.d.ts.map +1 -1
- package/dist/tools/LSTool/index.js +44 -29
- package/dist/tools/LSTool/index.js.map +1 -1
- package/dist/tools/TaskCreateTool/index.d.ts +6 -0
- package/dist/tools/TaskCreateTool/index.d.ts.map +1 -1
- package/dist/tools/TaskCreateTool/index.js +8 -2
- package/dist/tools/TaskCreateTool/index.js.map +1 -1
- package/dist/tools/TaskGetTool/index.d.ts +12 -0
- package/dist/tools/TaskGetTool/index.d.ts.map +1 -0
- package/dist/tools/TaskGetTool/index.js +50 -0
- package/dist/tools/TaskGetTool/index.js.map +1 -0
- package/dist/tools/TaskOutputTool/index.d.ts +15 -0
- package/dist/tools/TaskOutputTool/index.d.ts.map +1 -0
- package/dist/tools/TaskOutputTool/index.js +45 -0
- package/dist/tools/TaskOutputTool/index.js.map +1 -0
- package/dist/tools/TaskStopTool/index.d.ts +15 -0
- package/dist/tools/TaskStopTool/index.d.ts.map +1 -0
- package/dist/tools/TaskStopTool/index.js +51 -0
- package/dist/tools/TaskStopTool/index.js.map +1 -0
- package/dist/tools/TaskUpdateTool/index.d.ts +21 -3
- package/dist/tools/TaskUpdateTool/index.d.ts.map +1 -1
- package/dist/tools/TaskUpdateTool/index.js +48 -3
- package/dist/tools/TaskUpdateTool/index.js.map +1 -1
- package/dist/tools/tools-basic.test.js +191 -2
- package/dist/tools/tools-basic.test.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +6 -0
- package/dist/tools.js.map +1 -1
- package/dist/types/permissions.d.ts +2 -2
- package/dist/types/permissions.d.ts.map +1 -1
- package/dist/types/permissions.js +59 -13
- package/dist/types/permissions.js.map +1 -1
- package/dist/types/permissions.test.js +57 -0
- package/dist/types/permissions.test.js.map +1 -1
- package/dist/utils/bash-safety.d.ts +18 -0
- package/dist/utils/bash-safety.d.ts.map +1 -0
- package/dist/utils/bash-safety.js +227 -0
- package/dist/utils/bash-safety.js.map +1 -0
- package/dist/utils/bash-safety.test.d.ts +2 -0
- package/dist/utils/bash-safety.test.d.ts.map +1 -0
- package/dist/utils/bash-safety.test.js +112 -0
- package/dist/utils/bash-safety.test.js.map +1 -0
- package/dist/utils/fs.d.ts +15 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +64 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/fs.test.d.ts +5 -0
- package/dist/utils/fs.test.d.ts.map +1 -0
- package/dist/utils/fs.test.js +82 -0
- package/dist/utils/fs.test.js.map +1 -0
- package/dist/utils/safe-env.d.ts +10 -0
- package/dist/utils/safe-env.d.ts.map +1 -0
- package/dist/utils/safe-env.js +40 -0
- package/dist/utils/safe-env.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent messaging — peer-to-peer communication between sub-agents.
|
|
3
|
+
*
|
|
4
|
+
* Provides a message bus for agents to send/receive messages, share state,
|
|
5
|
+
* and coordinate work. Uses file-based locking for concurrent file access.
|
|
6
|
+
*
|
|
7
|
+
* Architecture (inspired by Claude Code Agent Teams):
|
|
8
|
+
* - Each agent has a unique ID
|
|
9
|
+
* - Messages are stored in a shared inbox (in-memory for same-process agents)
|
|
10
|
+
* - File locking prevents concurrent edits to the same file
|
|
11
|
+
*/
|
|
12
|
+
export type AgentMessage = {
|
|
13
|
+
from: string;
|
|
14
|
+
to: string;
|
|
15
|
+
type: 'request' | 'response' | 'status' | 'error';
|
|
16
|
+
content: string;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
metadata?: Record<string, unknown>;
|
|
19
|
+
};
|
|
20
|
+
export type AgentInfo = {
|
|
21
|
+
id: string;
|
|
22
|
+
role: string;
|
|
23
|
+
status: 'idle' | 'working' | 'done' | 'error';
|
|
24
|
+
currentTask?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Message bus for agent-to-agent communication.
|
|
28
|
+
*/
|
|
29
|
+
export declare class AgentMessageBus {
|
|
30
|
+
private inboxes;
|
|
31
|
+
private agents;
|
|
32
|
+
private fileLocks;
|
|
33
|
+
/** Register an agent with the bus */
|
|
34
|
+
registerAgent(id: string, role: string): void;
|
|
35
|
+
/** Unregister an agent */
|
|
36
|
+
unregisterAgent(id: string): void;
|
|
37
|
+
/** Send a message to a specific agent or broadcast */
|
|
38
|
+
send(message: Omit<AgentMessage, 'timestamp'>): void;
|
|
39
|
+
/** Receive pending messages for an agent (drains inbox) */
|
|
40
|
+
receive(agentId: string): AgentMessage[];
|
|
41
|
+
/** Peek at inbox without draining */
|
|
42
|
+
peek(agentId: string): AgentMessage[];
|
|
43
|
+
/** Update agent status */
|
|
44
|
+
updateStatus(agentId: string, status: AgentInfo['status'], currentTask?: string): void;
|
|
45
|
+
/** Get all registered agents */
|
|
46
|
+
getAgents(): AgentInfo[];
|
|
47
|
+
/** Get a specific agent's info */
|
|
48
|
+
getAgent(id: string): AgentInfo | undefined;
|
|
49
|
+
/** Acquire a lock on a file path. Returns true if acquired, false if already locked. */
|
|
50
|
+
acquireLock(agentId: string, filePath: string): boolean;
|
|
51
|
+
/** Release a lock on a file path */
|
|
52
|
+
releaseLock(agentId: string, filePath: string): void;
|
|
53
|
+
/** Release all locks held by an agent */
|
|
54
|
+
releaseAllLocks(agentId: string): void;
|
|
55
|
+
/** Check if a file is locked (and by whom) */
|
|
56
|
+
isLocked(filePath: string): {
|
|
57
|
+
locked: boolean;
|
|
58
|
+
holder?: string;
|
|
59
|
+
};
|
|
60
|
+
/** Get all current locks */
|
|
61
|
+
getLocks(): Array<{
|
|
62
|
+
filePath: string;
|
|
63
|
+
holder: string;
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
export declare function getMessageBus(): AgentMessageBus;
|
|
67
|
+
export declare function resetMessageBus(): void;
|
|
68
|
+
//# sourceMappingURL=agent-messaging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-messaging.d.ts","sourceRoot":"","sources":["../../src/services/agent-messaging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,SAAS,CAA6B;IAE9C,qCAAqC;IACrC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAK7C,0BAA0B;IAC1B,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IASjC,sDAAsD;IACtD,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,GAAG,IAAI;IAcpD,2DAA2D;IAC3D,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE;IAQxC,qCAAqC;IACrC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE;IAIrC,0BAA0B;IAC1B,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAQtF,gCAAgC;IAChC,SAAS,IAAI,SAAS,EAAE;IAIxB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAM3C,wFAAwF;IACxF,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAOvD,oCAAoC;IACpC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpD,yCAAyC;IACzC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAMtC,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAKhE,4BAA4B;IAC5B,QAAQ,IAAI,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAGxD;AAKD,wBAAgB,aAAa,IAAI,eAAe,CAG/C;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent messaging — peer-to-peer communication between sub-agents.
|
|
3
|
+
*
|
|
4
|
+
* Provides a message bus for agents to send/receive messages, share state,
|
|
5
|
+
* and coordinate work. Uses file-based locking for concurrent file access.
|
|
6
|
+
*
|
|
7
|
+
* Architecture (inspired by Claude Code Agent Teams):
|
|
8
|
+
* - Each agent has a unique ID
|
|
9
|
+
* - Messages are stored in a shared inbox (in-memory for same-process agents)
|
|
10
|
+
* - File locking prevents concurrent edits to the same file
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Message bus for agent-to-agent communication.
|
|
14
|
+
*/
|
|
15
|
+
export class AgentMessageBus {
|
|
16
|
+
inboxes = new Map();
|
|
17
|
+
agents = new Map();
|
|
18
|
+
fileLocks = new Map(); // filePath → agentId
|
|
19
|
+
/** Register an agent with the bus */
|
|
20
|
+
registerAgent(id, role) {
|
|
21
|
+
this.agents.set(id, { id, role, status: 'idle' });
|
|
22
|
+
this.inboxes.set(id, []);
|
|
23
|
+
}
|
|
24
|
+
/** Unregister an agent */
|
|
25
|
+
unregisterAgent(id) {
|
|
26
|
+
this.agents.delete(id);
|
|
27
|
+
this.inboxes.delete(id);
|
|
28
|
+
// Release all locks held by this agent
|
|
29
|
+
for (const [file, holder] of this.fileLocks) {
|
|
30
|
+
if (holder === id)
|
|
31
|
+
this.fileLocks.delete(file);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Send a message to a specific agent or broadcast */
|
|
35
|
+
send(message) {
|
|
36
|
+
const msg = { ...message, timestamp: Date.now() };
|
|
37
|
+
if (msg.to === '*') {
|
|
38
|
+
// Broadcast to all agents except sender
|
|
39
|
+
for (const [id, inbox] of this.inboxes) {
|
|
40
|
+
if (id !== msg.from)
|
|
41
|
+
inbox.push(msg);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const inbox = this.inboxes.get(msg.to);
|
|
46
|
+
if (inbox)
|
|
47
|
+
inbox.push(msg);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Receive pending messages for an agent (drains inbox) */
|
|
51
|
+
receive(agentId) {
|
|
52
|
+
const inbox = this.inboxes.get(agentId);
|
|
53
|
+
if (!inbox || inbox.length === 0)
|
|
54
|
+
return [];
|
|
55
|
+
const messages = [...inbox];
|
|
56
|
+
inbox.length = 0;
|
|
57
|
+
return messages;
|
|
58
|
+
}
|
|
59
|
+
/** Peek at inbox without draining */
|
|
60
|
+
peek(agentId) {
|
|
61
|
+
return [...(this.inboxes.get(agentId) ?? [])];
|
|
62
|
+
}
|
|
63
|
+
/** Update agent status */
|
|
64
|
+
updateStatus(agentId, status, currentTask) {
|
|
65
|
+
const agent = this.agents.get(agentId);
|
|
66
|
+
if (agent) {
|
|
67
|
+
agent.status = status;
|
|
68
|
+
agent.currentTask = currentTask;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Get all registered agents */
|
|
72
|
+
getAgents() {
|
|
73
|
+
return [...this.agents.values()];
|
|
74
|
+
}
|
|
75
|
+
/** Get a specific agent's info */
|
|
76
|
+
getAgent(id) {
|
|
77
|
+
return this.agents.get(id);
|
|
78
|
+
}
|
|
79
|
+
// ── File Locking ──
|
|
80
|
+
/** Acquire a lock on a file path. Returns true if acquired, false if already locked. */
|
|
81
|
+
acquireLock(agentId, filePath) {
|
|
82
|
+
const holder = this.fileLocks.get(filePath);
|
|
83
|
+
if (holder && holder !== agentId)
|
|
84
|
+
return false;
|
|
85
|
+
this.fileLocks.set(filePath, agentId);
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
/** Release a lock on a file path */
|
|
89
|
+
releaseLock(agentId, filePath) {
|
|
90
|
+
const holder = this.fileLocks.get(filePath);
|
|
91
|
+
if (holder === agentId)
|
|
92
|
+
this.fileLocks.delete(filePath);
|
|
93
|
+
}
|
|
94
|
+
/** Release all locks held by an agent */
|
|
95
|
+
releaseAllLocks(agentId) {
|
|
96
|
+
for (const [file, holder] of this.fileLocks) {
|
|
97
|
+
if (holder === agentId)
|
|
98
|
+
this.fileLocks.delete(file);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Check if a file is locked (and by whom) */
|
|
102
|
+
isLocked(filePath) {
|
|
103
|
+
const holder = this.fileLocks.get(filePath);
|
|
104
|
+
return holder ? { locked: true, holder } : { locked: false };
|
|
105
|
+
}
|
|
106
|
+
/** Get all current locks */
|
|
107
|
+
getLocks() {
|
|
108
|
+
return [...this.fileLocks.entries()].map(([filePath, holder]) => ({ filePath, holder }));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Singleton message bus for the current process */
|
|
112
|
+
let globalBus = null;
|
|
113
|
+
export function getMessageBus() {
|
|
114
|
+
if (!globalBus)
|
|
115
|
+
globalBus = new AgentMessageBus();
|
|
116
|
+
return globalBus;
|
|
117
|
+
}
|
|
118
|
+
export function resetMessageBus() {
|
|
119
|
+
globalBus = null;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=agent-messaging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-messaging.js","sourceRoot":"","sources":["../../src/services/agent-messaging.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-messaging.test.d.ts","sourceRoot":"","sources":["../../src/services/agent-messaging.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, it, beforeEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { AgentMessageBus } from './agent-messaging.js';
|
|
4
|
+
describe('AgentMessageBus', () => {
|
|
5
|
+
let bus;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
bus = new AgentMessageBus();
|
|
8
|
+
bus.registerAgent('agent-1', 'code-reviewer');
|
|
9
|
+
bus.registerAgent('agent-2', 'test-writer');
|
|
10
|
+
});
|
|
11
|
+
describe('messaging', () => {
|
|
12
|
+
it('sends and receives messages', () => {
|
|
13
|
+
bus.send({ from: 'agent-1', to: 'agent-2', type: 'request', content: 'review file.ts' });
|
|
14
|
+
const msgs = bus.receive('agent-2');
|
|
15
|
+
assert.strictEqual(msgs.length, 1);
|
|
16
|
+
assert.strictEqual(msgs[0].content, 'review file.ts');
|
|
17
|
+
assert.strictEqual(msgs[0].from, 'agent-1');
|
|
18
|
+
});
|
|
19
|
+
it('drains inbox on receive', () => {
|
|
20
|
+
bus.send({ from: 'agent-1', to: 'agent-2', type: 'request', content: 'hello' });
|
|
21
|
+
bus.receive('agent-2');
|
|
22
|
+
const msgs = bus.receive('agent-2');
|
|
23
|
+
assert.strictEqual(msgs.length, 0);
|
|
24
|
+
});
|
|
25
|
+
it('peek does not drain', () => {
|
|
26
|
+
bus.send({ from: 'agent-1', to: 'agent-2', type: 'request', content: 'hello' });
|
|
27
|
+
const peeked = bus.peek('agent-2');
|
|
28
|
+
assert.strictEqual(peeked.length, 1);
|
|
29
|
+
const received = bus.receive('agent-2');
|
|
30
|
+
assert.strictEqual(received.length, 1);
|
|
31
|
+
});
|
|
32
|
+
it('broadcasts to all except sender', () => {
|
|
33
|
+
bus.registerAgent('agent-3', 'debugger');
|
|
34
|
+
bus.send({ from: 'agent-1', to: '*', type: 'status', content: 'done with task A' });
|
|
35
|
+
assert.strictEqual(bus.receive('agent-2').length, 1);
|
|
36
|
+
assert.strictEqual(bus.receive('agent-3').length, 1);
|
|
37
|
+
assert.strictEqual(bus.receive('agent-1').length, 0); // sender doesn't get it
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('agent registry', () => {
|
|
41
|
+
it('lists registered agents', () => {
|
|
42
|
+
const agents = bus.getAgents();
|
|
43
|
+
assert.strictEqual(agents.length, 2);
|
|
44
|
+
assert.ok(agents.find(a => a.id === 'agent-1'));
|
|
45
|
+
});
|
|
46
|
+
it('updates agent status', () => {
|
|
47
|
+
bus.updateStatus('agent-1', 'working', 'task-42');
|
|
48
|
+
const agent = bus.getAgent('agent-1');
|
|
49
|
+
assert.strictEqual(agent?.status, 'working');
|
|
50
|
+
assert.strictEqual(agent?.currentTask, 'task-42');
|
|
51
|
+
});
|
|
52
|
+
it('unregisters agent and cleans up', () => {
|
|
53
|
+
bus.send({ from: 'agent-1', to: 'agent-2', type: 'request', content: 'hello' });
|
|
54
|
+
bus.unregisterAgent('agent-2');
|
|
55
|
+
assert.strictEqual(bus.getAgent('agent-2'), undefined);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('file locking', () => {
|
|
59
|
+
it('acquires and releases locks', () => {
|
|
60
|
+
assert.strictEqual(bus.acquireLock('agent-1', 'src/file.ts'), true);
|
|
61
|
+
assert.strictEqual(bus.isLocked('src/file.ts').locked, true);
|
|
62
|
+
assert.strictEqual(bus.isLocked('src/file.ts').holder, 'agent-1');
|
|
63
|
+
bus.releaseLock('agent-1', 'src/file.ts');
|
|
64
|
+
assert.strictEqual(bus.isLocked('src/file.ts').locked, false);
|
|
65
|
+
});
|
|
66
|
+
it('prevents double-locking by different agent', () => {
|
|
67
|
+
bus.acquireLock('agent-1', 'src/file.ts');
|
|
68
|
+
assert.strictEqual(bus.acquireLock('agent-2', 'src/file.ts'), false);
|
|
69
|
+
});
|
|
70
|
+
it('allows same agent to re-lock', () => {
|
|
71
|
+
bus.acquireLock('agent-1', 'src/file.ts');
|
|
72
|
+
assert.strictEqual(bus.acquireLock('agent-1', 'src/file.ts'), true);
|
|
73
|
+
});
|
|
74
|
+
it('releaseAllLocks clears agent locks', () => {
|
|
75
|
+
bus.acquireLock('agent-1', 'a.ts');
|
|
76
|
+
bus.acquireLock('agent-1', 'b.ts');
|
|
77
|
+
bus.releaseAllLocks('agent-1');
|
|
78
|
+
assert.strictEqual(bus.isLocked('a.ts').locked, false);
|
|
79
|
+
assert.strictEqual(bus.isLocked('b.ts').locked, false);
|
|
80
|
+
});
|
|
81
|
+
it('unregister releases locks', () => {
|
|
82
|
+
bus.acquireLock('agent-1', 'src/file.ts');
|
|
83
|
+
bus.unregisterAgent('agent-1');
|
|
84
|
+
assert.strictEqual(bus.isLocked('src/file.ts').locked, false);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=agent-messaging.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-messaging.test.js","sourceRoot":"","sources":["../../src/services/agent-messaging.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron scheduler — run prompts on recurring schedules.
|
|
3
|
+
*
|
|
4
|
+
* Cron definitions are stored in ~/.oh/crons/ as JSON files.
|
|
5
|
+
* Each cron has an id, schedule (cron expression), prompt, and metadata.
|
|
6
|
+
*
|
|
7
|
+
* This is a simple implementation using setInterval for minute-level granularity.
|
|
8
|
+
* For production use, consider node-cron or similar.
|
|
9
|
+
*/
|
|
10
|
+
export type CronDefinition = {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
schedule: string;
|
|
14
|
+
prompt: string;
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
createdAt: number;
|
|
17
|
+
lastRun?: number;
|
|
18
|
+
runCount: number;
|
|
19
|
+
};
|
|
20
|
+
export type CronResult = {
|
|
21
|
+
cronId: string;
|
|
22
|
+
timestamp: number;
|
|
23
|
+
output: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
};
|
|
26
|
+
/** List all cron definitions */
|
|
27
|
+
export declare function listCrons(): CronDefinition[];
|
|
28
|
+
/** Create a new cron definition */
|
|
29
|
+
export declare function createCron(name: string, schedule: string, prompt: string): CronDefinition;
|
|
30
|
+
/** Delete a cron definition */
|
|
31
|
+
export declare function deleteCron(id: string): boolean;
|
|
32
|
+
/** Update a cron definition (e.g., after a run) */
|
|
33
|
+
export declare function updateCron(cron: CronDefinition): void;
|
|
34
|
+
/** Parse a simplified schedule string into milliseconds interval */
|
|
35
|
+
export declare function parseScheduleMs(schedule: string): number | null;
|
|
36
|
+
/**
|
|
37
|
+
* Check which crons are due to run based on their schedule and lastRun.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getDueCrons(crons: CronDefinition[]): CronDefinition[];
|
|
40
|
+
//# sourceMappingURL=cron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../../src/services/cron.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,gCAAgC;AAChC,wBAAgB,SAAS,IAAI,cAAc,EAAE,CAU5C;AAED,mCAAmC;AACnC,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAgBzF;AAED,+BAA+B;AAC/B,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAK9C;AAED,mDAAmD;AACnD,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAGrD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc/D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CASrE"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron scheduler — run prompts on recurring schedules.
|
|
3
|
+
*
|
|
4
|
+
* Cron definitions are stored in ~/.oh/crons/ as JSON files.
|
|
5
|
+
* Each cron has an id, schedule (cron expression), prompt, and metadata.
|
|
6
|
+
*
|
|
7
|
+
* This is a simple implementation using setInterval for minute-level granularity.
|
|
8
|
+
* For production use, consider node-cron or similar.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync, writeFileSync, mkdirSync, readdirSync, existsSync, unlinkSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
const CRON_DIR = join(homedir(), '.oh', 'crons');
|
|
14
|
+
/** List all cron definitions */
|
|
15
|
+
export function listCrons() {
|
|
16
|
+
if (!existsSync(CRON_DIR))
|
|
17
|
+
return [];
|
|
18
|
+
return readdirSync(CRON_DIR)
|
|
19
|
+
.filter(f => f.endsWith('.json'))
|
|
20
|
+
.map(f => {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(readFileSync(join(CRON_DIR, f), 'utf-8'));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
.filter((c) => c !== null);
|
|
29
|
+
}
|
|
30
|
+
/** Create a new cron definition */
|
|
31
|
+
export function createCron(name, schedule, prompt) {
|
|
32
|
+
mkdirSync(CRON_DIR, { recursive: true });
|
|
33
|
+
const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
|
|
34
|
+
const cron = {
|
|
35
|
+
id,
|
|
36
|
+
name,
|
|
37
|
+
schedule,
|
|
38
|
+
prompt,
|
|
39
|
+
enabled: true,
|
|
40
|
+
createdAt: Date.now(),
|
|
41
|
+
runCount: 0,
|
|
42
|
+
};
|
|
43
|
+
writeFileSync(join(CRON_DIR, `${id}.json`), JSON.stringify(cron, null, 2));
|
|
44
|
+
return cron;
|
|
45
|
+
}
|
|
46
|
+
/** Delete a cron definition */
|
|
47
|
+
export function deleteCron(id) {
|
|
48
|
+
const path = join(CRON_DIR, `${id}.json`);
|
|
49
|
+
if (!existsSync(path))
|
|
50
|
+
return false;
|
|
51
|
+
unlinkSync(path);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/** Update a cron definition (e.g., after a run) */
|
|
55
|
+
export function updateCron(cron) {
|
|
56
|
+
mkdirSync(CRON_DIR, { recursive: true });
|
|
57
|
+
writeFileSync(join(CRON_DIR, `${cron.id}.json`), JSON.stringify(cron, null, 2));
|
|
58
|
+
}
|
|
59
|
+
/** Parse a simplified schedule string into milliseconds interval */
|
|
60
|
+
export function parseScheduleMs(schedule) {
|
|
61
|
+
// "every 5m" → 5 minutes
|
|
62
|
+
const minMatch = schedule.match(/^every\s+(\d+)\s*m(?:in(?:ute)?s?)?$/i);
|
|
63
|
+
if (minMatch)
|
|
64
|
+
return parseInt(minMatch[1]) * 60 * 1000;
|
|
65
|
+
// "every 2h" → 2 hours
|
|
66
|
+
const hourMatch = schedule.match(/^every\s+(\d+)\s*h(?:ours?)?$/i);
|
|
67
|
+
if (hourMatch)
|
|
68
|
+
return parseInt(hourMatch[1]) * 60 * 60 * 1000;
|
|
69
|
+
// "every 1d" → 1 day
|
|
70
|
+
const dayMatch = schedule.match(/^every\s+(\d+)\s*d(?:ays?)?$/i);
|
|
71
|
+
if (dayMatch)
|
|
72
|
+
return parseInt(dayMatch[1]) * 24 * 60 * 60 * 1000;
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Check which crons are due to run based on their schedule and lastRun.
|
|
77
|
+
*/
|
|
78
|
+
export function getDueCrons(crons) {
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
return crons.filter(c => {
|
|
81
|
+
if (!c.enabled)
|
|
82
|
+
return false;
|
|
83
|
+
const intervalMs = parseScheduleMs(c.schedule);
|
|
84
|
+
if (!intervalMs)
|
|
85
|
+
return false;
|
|
86
|
+
const lastRun = c.lastRun ?? c.createdAt;
|
|
87
|
+
return (now - lastRun) >= intervalMs;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=cron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.js","sourceRoot":"","sources":["../../src/services/cron.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.test.d.ts","sourceRoot":"","sources":["../../src/services/cron.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { parseScheduleMs, getDueCrons } from './cron.js';
|
|
4
|
+
describe('parseScheduleMs', () => {
|
|
5
|
+
it('parses minutes', () => {
|
|
6
|
+
assert.strictEqual(parseScheduleMs('every 5m'), 5 * 60 * 1000);
|
|
7
|
+
assert.strictEqual(parseScheduleMs('every 10 minutes'), 10 * 60 * 1000);
|
|
8
|
+
assert.strictEqual(parseScheduleMs('every 1 min'), 1 * 60 * 1000);
|
|
9
|
+
});
|
|
10
|
+
it('parses hours', () => {
|
|
11
|
+
assert.strictEqual(parseScheduleMs('every 2h'), 2 * 60 * 60 * 1000);
|
|
12
|
+
assert.strictEqual(parseScheduleMs('every 1 hour'), 1 * 60 * 60 * 1000);
|
|
13
|
+
});
|
|
14
|
+
it('parses days', () => {
|
|
15
|
+
assert.strictEqual(parseScheduleMs('every 1d'), 24 * 60 * 60 * 1000);
|
|
16
|
+
assert.strictEqual(parseScheduleMs('every 7 days'), 7 * 24 * 60 * 60 * 1000);
|
|
17
|
+
});
|
|
18
|
+
it('returns null for invalid', () => {
|
|
19
|
+
assert.strictEqual(parseScheduleMs('invalid'), null);
|
|
20
|
+
assert.strictEqual(parseScheduleMs('* * * * *'), null);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('getDueCrons', () => {
|
|
24
|
+
it('returns crons past their interval', () => {
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
const crons = [
|
|
27
|
+
{ id: '1', name: 'test', schedule: 'every 5m', prompt: 'hi', enabled: true, createdAt: now - 10 * 60 * 1000, lastRun: now - 10 * 60 * 1000, runCount: 0 },
|
|
28
|
+
];
|
|
29
|
+
const due = getDueCrons(crons);
|
|
30
|
+
assert.strictEqual(due.length, 1);
|
|
31
|
+
});
|
|
32
|
+
it('skips crons not yet due', () => {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
const crons = [
|
|
35
|
+
{ id: '1', name: 'test', schedule: 'every 5m', prompt: 'hi', enabled: true, createdAt: now, lastRun: now, runCount: 0 },
|
|
36
|
+
];
|
|
37
|
+
const due = getDueCrons(crons);
|
|
38
|
+
assert.strictEqual(due.length, 0);
|
|
39
|
+
});
|
|
40
|
+
it('skips disabled crons', () => {
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const crons = [
|
|
43
|
+
{ id: '1', name: 'test', schedule: 'every 5m', prompt: 'hi', enabled: false, createdAt: now - 10 * 60 * 1000, runCount: 0 },
|
|
44
|
+
];
|
|
45
|
+
const due = getDueCrons(crons);
|
|
46
|
+
assert.strictEqual(due.length, 0);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=cron.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.test.js","sourceRoot":"","sources":["../../src/services/cron.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,14 +4,23 @@ declare const inputSchema: z.ZodObject<{
|
|
|
4
4
|
prompt: z.ZodString;
|
|
5
5
|
description: z.ZodOptional<z.ZodString>;
|
|
6
6
|
isolated: z.ZodOptional<z.ZodBoolean>;
|
|
7
|
+
run_in_background: z.ZodOptional<z.ZodBoolean>;
|
|
8
|
+
model: z.ZodOptional<z.ZodString>;
|
|
9
|
+
subagent_type: z.ZodOptional<z.ZodString>;
|
|
7
10
|
}, "strip", z.ZodTypeAny, {
|
|
8
11
|
prompt: string;
|
|
12
|
+
model?: string | undefined;
|
|
9
13
|
description?: string | undefined;
|
|
14
|
+
run_in_background?: boolean | undefined;
|
|
10
15
|
isolated?: boolean | undefined;
|
|
16
|
+
subagent_type?: string | undefined;
|
|
11
17
|
}, {
|
|
12
18
|
prompt: string;
|
|
19
|
+
model?: string | undefined;
|
|
13
20
|
description?: string | undefined;
|
|
21
|
+
run_in_background?: boolean | undefined;
|
|
14
22
|
isolated?: boolean | undefined;
|
|
23
|
+
subagent_type?: string | undefined;
|
|
15
24
|
}>;
|
|
16
25
|
export declare const AgentTool: Tool<typeof inputSchema>;
|
|
17
26
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/AgentTool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,eAAe,CAAC;AAGnE,QAAA,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/AgentTool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,eAAe,CAAC;AAGnE,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;EAOf,CAAC;AAEH,eAAO,MAAM,SAAS,EAAE,IAAI,CAAC,OAAO,WAAW,CA6K9C,CAAC"}
|