agenthub-multiagent-mcp 1.7.1 → 1.7.3
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/hooks/index.d.ts +93 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +134 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/onConnect.d.ts +20 -0
- package/dist/hooks/onConnect.d.ts.map +1 -0
- package/dist/hooks/onConnect.js +85 -0
- package/dist/hooks/onConnect.js.map +1 -0
- package/dist/hooks/onDisconnect.d.ts +40 -0
- package/dist/hooks/onDisconnect.d.ts.map +1 -0
- package/dist/hooks/onDisconnect.js +106 -0
- package/dist/hooks/onDisconnect.js.map +1 -0
- package/dist/hooks/onTaskComplete.d.ts +21 -0
- package/dist/hooks/onTaskComplete.d.ts.map +1 -0
- package/dist/hooks/onTaskComplete.js +112 -0
- package/dist/hooks/onTaskComplete.js.map +1 -0
- package/dist/hooks/onTaskStart.d.ts +20 -0
- package/dist/hooks/onTaskStart.d.ts.map +1 -0
- package/dist/hooks/onTaskStart.js +78 -0
- package/dist/hooks/onTaskStart.js.map +1 -0
- package/dist/hooks/periodicReminder.d.ts +34 -0
- package/dist/hooks/periodicReminder.d.ts.map +1 -0
- package/dist/hooks/periodicReminder.js +97 -0
- package/dist/hooks/periodicReminder.js.map +1 -0
- package/dist/hooks/sessionState.d.ts +66 -0
- package/dist/hooks/sessionState.d.ts.map +1 -0
- package/dist/hooks/sessionState.js +188 -0
- package/dist/hooks/sessionState.js.map +1 -0
- package/dist/hooks/types.d.ts +82 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +5 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +3 -2
- package/dist/state.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +173 -6
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/tools.test.js +4 -3
- package/dist/tools/tools.test.js.map +1 -1
- package/package.json +1 -1
- package/src/hooks/index.ts +184 -0
- package/src/hooks/onConnect.ts +115 -0
- package/src/hooks/onDisconnect.ts +138 -0
- package/src/hooks/onTaskComplete.ts +134 -0
- package/src/hooks/onTaskStart.ts +101 -0
- package/src/hooks/periodicReminder.ts +116 -0
- package/src/hooks/sessionState.ts +219 -0
- package/src/hooks/types.ts +95 -0
- package/src/index.ts +14 -1
- package/src/state.ts +3 -2
- package/src/tools/index.ts +202 -7
- package/src/tools/tools.test.ts +4 -3
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Hooks Enforcement System
|
|
3
|
+
*
|
|
4
|
+
* Entry point for all hook functionality.
|
|
5
|
+
* Provides a unified API for the tool handlers.
|
|
6
|
+
*/
|
|
7
|
+
export * from "./types.js";
|
|
8
|
+
import { HookResult, AvailableTask, OnConnectBriefing, TaskCompleteValidation, SessionState, HookConfig } from "./types.js";
|
|
9
|
+
import * as onConnect from "./onConnect.js";
|
|
10
|
+
import * as onTaskStart from "./onTaskStart.js";
|
|
11
|
+
import * as onTaskComplete from "./onTaskComplete.js";
|
|
12
|
+
import * as onDisconnect from "./onDisconnect.js";
|
|
13
|
+
import * as periodicReminder from "./periodicReminder.js";
|
|
14
|
+
export { onConnect, onTaskStart, onTaskComplete, onDisconnect, periodicReminder };
|
|
15
|
+
/**
|
|
16
|
+
* Hook Manager - Central orchestration for all hooks.
|
|
17
|
+
*/
|
|
18
|
+
export declare class HookManager {
|
|
19
|
+
/**
|
|
20
|
+
* Check if hooks are enabled.
|
|
21
|
+
*/
|
|
22
|
+
isEnabled(): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Handle agent connection (register or reconnect).
|
|
25
|
+
*/
|
|
26
|
+
handleConnect(agentId: string, agentName: string, agentType: string | undefined, briefing: OnConnectBriefing, isReconnect: boolean): HookResult;
|
|
27
|
+
/**
|
|
28
|
+
* Handle task start.
|
|
29
|
+
* Returns blocked: true if ticket is required but not provided.
|
|
30
|
+
*/
|
|
31
|
+
handleTaskStart(agentId: string, taskId: string | undefined, taskDescription: string, availableTasks: AvailableTask[]): HookResult;
|
|
32
|
+
/**
|
|
33
|
+
* Handle task completion.
|
|
34
|
+
* Returns blocked: true if context requirements are not met.
|
|
35
|
+
*/
|
|
36
|
+
handleTaskComplete(agentId: string, validation: TaskCompleteValidation): HookResult;
|
|
37
|
+
/**
|
|
38
|
+
* Handle agent disconnect.
|
|
39
|
+
* Non-blocking - returns session summary.
|
|
40
|
+
*/
|
|
41
|
+
handleDisconnect(agentId: string): {
|
|
42
|
+
summary: ReturnType<typeof onDisconnect.generateSessionSummary>;
|
|
43
|
+
slackMessage: string | null;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Check if a periodic reminder should be shown.
|
|
47
|
+
* Call after each tool call.
|
|
48
|
+
*/
|
|
49
|
+
checkReminder(agentId: string): HookResult;
|
|
50
|
+
/**
|
|
51
|
+
* Record a context save operation.
|
|
52
|
+
*/
|
|
53
|
+
recordContextSave(agentId: string, type: "decision" | "note" | "blocker" | "insight"): void;
|
|
54
|
+
/**
|
|
55
|
+
* Check if a tool is a context-saving operation.
|
|
56
|
+
*/
|
|
57
|
+
isContextSaveOperation(toolName: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Check if a tool is a task lifecycle operation.
|
|
60
|
+
*/
|
|
61
|
+
isTaskLifecycleOperation(toolName: string): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Get context counts for the current task.
|
|
64
|
+
*/
|
|
65
|
+
getContextCounts(agentId: string): SessionState["context_counts"];
|
|
66
|
+
/**
|
|
67
|
+
* Check if task has incomplete work.
|
|
68
|
+
*/
|
|
69
|
+
hasIncompleteWork(agentId: string): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Build partial completion data if there's incomplete work.
|
|
72
|
+
*/
|
|
73
|
+
buildPartialCompletion(agentId: string): {
|
|
74
|
+
task_id: string;
|
|
75
|
+
summary: string;
|
|
76
|
+
outcome: "partial";
|
|
77
|
+
context_counts: SessionState["context_counts"];
|
|
78
|
+
} | null;
|
|
79
|
+
/**
|
|
80
|
+
* Build briefing data from API responses.
|
|
81
|
+
*/
|
|
82
|
+
buildBriefing(availableTasks: AvailableTask[], pendingMessagesCount: number, unfinishedTask?: OnConnectBriefing["unfinished_task"], activeBlockers?: number): OnConnectBriefing;
|
|
83
|
+
/**
|
|
84
|
+
* Update hook configuration.
|
|
85
|
+
*/
|
|
86
|
+
configure(config: Partial<HookConfig>): void;
|
|
87
|
+
/**
|
|
88
|
+
* Get current configuration.
|
|
89
|
+
*/
|
|
90
|
+
getConfig(): HookConfig;
|
|
91
|
+
}
|
|
92
|
+
export declare const hookManager: HookManager;
|
|
93
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,YAAY,CAAC;AAG3B,OAAO,EACL,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,sBAAsB,EACtB,YAAY,EACZ,UAAU,EACX,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAC;AAG1D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAElF;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,aAAa,CACX,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,iBAAiB,EAC3B,WAAW,EAAE,OAAO,GACnB,UAAU;IAQb;;;OAGG;IACH,eAAe,CACb,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,aAAa,EAAE,GAC9B,UAAU;IAYb;;;OAGG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,sBAAsB,GAAG,UAAU;IASnF;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;QACjC,OAAO,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,sBAAsB,CAAC,CAAC;QAChE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B;IAID;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU;IAQ1C;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI;IAI3F;;OAEG;IACH,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIjD;;OAEG;IACH,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAInD;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAAC,gBAAgB,CAAC;IAIjE;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI3C;;OAEG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM;;;;;;IAItC;;OAEG;IACH,aAAa,CACX,cAAc,EAAE,aAAa,EAAE,EAC/B,oBAAoB,EAAE,MAAM,EAC5B,cAAc,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,EACrD,cAAc,CAAC,EAAE,MAAM,GACtB,iBAAiB;IAIpB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI;IAI5C;;OAEG;IACH,SAAS,IAAI,UAAU;CAGxB;AAGD,eAAO,MAAM,WAAW,aAAoB,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Hooks Enforcement System
|
|
3
|
+
*
|
|
4
|
+
* Entry point for all hook functionality.
|
|
5
|
+
* Provides a unified API for the tool handlers.
|
|
6
|
+
*/
|
|
7
|
+
export * from "./types.js";
|
|
8
|
+
import * as sessionState from "./sessionState.js";
|
|
9
|
+
import * as onConnect from "./onConnect.js";
|
|
10
|
+
import * as onTaskStart from "./onTaskStart.js";
|
|
11
|
+
import * as onTaskComplete from "./onTaskComplete.js";
|
|
12
|
+
import * as onDisconnect from "./onDisconnect.js";
|
|
13
|
+
import * as periodicReminder from "./periodicReminder.js";
|
|
14
|
+
// Re-export individual hook modules for direct access
|
|
15
|
+
export { onConnect, onTaskStart, onTaskComplete, onDisconnect, periodicReminder };
|
|
16
|
+
/**
|
|
17
|
+
* Hook Manager - Central orchestration for all hooks.
|
|
18
|
+
*/
|
|
19
|
+
export class HookManager {
|
|
20
|
+
/**
|
|
21
|
+
* Check if hooks are enabled.
|
|
22
|
+
*/
|
|
23
|
+
isEnabled() {
|
|
24
|
+
return sessionState.isEnabled();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Handle agent connection (register or reconnect).
|
|
28
|
+
*/
|
|
29
|
+
handleConnect(agentId, agentName, agentType, briefing, isReconnect) {
|
|
30
|
+
if (!this.isEnabled()) {
|
|
31
|
+
return { blocked: false };
|
|
32
|
+
}
|
|
33
|
+
return onConnect.executeOnConnect(agentId, agentName, agentType, briefing, isReconnect);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Handle task start.
|
|
37
|
+
* Returns blocked: true if ticket is required but not provided.
|
|
38
|
+
*/
|
|
39
|
+
handleTaskStart(agentId, taskId, taskDescription, availableTasks) {
|
|
40
|
+
if (!this.isEnabled()) {
|
|
41
|
+
// Still track the task even if enforcement is disabled
|
|
42
|
+
if (taskId) {
|
|
43
|
+
sessionState.startTask(agentId, taskId);
|
|
44
|
+
}
|
|
45
|
+
return { blocked: false };
|
|
46
|
+
}
|
|
47
|
+
return onTaskStart.executeOnTaskStart(agentId, taskId, taskDescription, availableTasks);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Handle task completion.
|
|
51
|
+
* Returns blocked: true if context requirements are not met.
|
|
52
|
+
*/
|
|
53
|
+
handleTaskComplete(agentId, validation) {
|
|
54
|
+
if (!this.isEnabled()) {
|
|
55
|
+
sessionState.completeTask(agentId);
|
|
56
|
+
return { blocked: false };
|
|
57
|
+
}
|
|
58
|
+
return onTaskComplete.executeOnTaskComplete(agentId, validation);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Handle agent disconnect.
|
|
62
|
+
* Non-blocking - returns session summary.
|
|
63
|
+
*/
|
|
64
|
+
handleDisconnect(agentId) {
|
|
65
|
+
return onDisconnect.executeOnDisconnect(agentId);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if a periodic reminder should be shown.
|
|
69
|
+
* Call after each tool call.
|
|
70
|
+
*/
|
|
71
|
+
checkReminder(agentId) {
|
|
72
|
+
if (!this.isEnabled()) {
|
|
73
|
+
return { blocked: false };
|
|
74
|
+
}
|
|
75
|
+
return periodicReminder.checkReminder(agentId);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Record a context save operation.
|
|
79
|
+
*/
|
|
80
|
+
recordContextSave(agentId, type) {
|
|
81
|
+
sessionState.recordContextSave(agentId, type);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if a tool is a context-saving operation.
|
|
85
|
+
*/
|
|
86
|
+
isContextSaveOperation(toolName) {
|
|
87
|
+
return periodicReminder.isContextSaveOperation(toolName);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if a tool is a task lifecycle operation.
|
|
91
|
+
*/
|
|
92
|
+
isTaskLifecycleOperation(toolName) {
|
|
93
|
+
return periodicReminder.isTaskLifecycleOperation(toolName);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get context counts for the current task.
|
|
97
|
+
*/
|
|
98
|
+
getContextCounts(agentId) {
|
|
99
|
+
return sessionState.getContextCounts(agentId);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if task has incomplete work.
|
|
103
|
+
*/
|
|
104
|
+
hasIncompleteWork(agentId) {
|
|
105
|
+
return onDisconnect.hasIncompleteWork(agentId);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Build partial completion data if there's incomplete work.
|
|
109
|
+
*/
|
|
110
|
+
buildPartialCompletion(agentId) {
|
|
111
|
+
return onDisconnect.buildPartialCompletion(agentId);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Build briefing data from API responses.
|
|
115
|
+
*/
|
|
116
|
+
buildBriefing(availableTasks, pendingMessagesCount, unfinishedTask, activeBlockers) {
|
|
117
|
+
return onConnect.buildBriefing(availableTasks, pendingMessagesCount, unfinishedTask, activeBlockers);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Update hook configuration.
|
|
121
|
+
*/
|
|
122
|
+
configure(config) {
|
|
123
|
+
sessionState.setConfig(config);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get current configuration.
|
|
127
|
+
*/
|
|
128
|
+
getConfig() {
|
|
129
|
+
return sessionState.getConfig();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Singleton instance
|
|
133
|
+
export const hookManager = new HookManager();
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OnConnect Hook
|
|
3
|
+
* Triggered on agent_register or agent_reconnect.
|
|
4
|
+
* Provides a briefing with available tasks and any unfinished work.
|
|
5
|
+
*/
|
|
6
|
+
import { HookResult, OnConnectBriefing, AvailableTask } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Format the connection briefing message.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatBriefing(agentName: string, agentType: string | undefined, briefing: OnConnectBriefing, isReconnect: boolean): string;
|
|
11
|
+
/**
|
|
12
|
+
* Execute the OnConnect hook.
|
|
13
|
+
* Returns a briefing message to append to the registration response.
|
|
14
|
+
*/
|
|
15
|
+
export declare function executeOnConnect(agentId: string, agentName: string, agentType: string | undefined, briefing: OnConnectBriefing, isReconnect: boolean): HookResult;
|
|
16
|
+
/**
|
|
17
|
+
* Build briefing data from API responses.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildBriefing(availableTasks: AvailableTask[], pendingMessagesCount: number, unfinishedTask?: OnConnectBriefing["unfinished_task"], activeBlockers?: number): OnConnectBriefing;
|
|
20
|
+
//# sourceMappingURL=onConnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onConnect.d.ts","sourceRoot":"","sources":["../../src/hooks/onConnect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1E;;GAEG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,iBAAiB,EAC3B,WAAW,EAAE,OAAO,GACnB,MAAM,CAyDR;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,iBAAiB,EAC3B,WAAW,EAAE,OAAO,GACnB,UAAU,CAWZ;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,aAAa,EAAE,EAC/B,oBAAoB,EAAE,MAAM,EAC5B,cAAc,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,EACrD,cAAc,CAAC,EAAE,MAAM,GACtB,iBAAiB,CAOnB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OnConnect Hook
|
|
3
|
+
* Triggered on agent_register or agent_reconnect.
|
|
4
|
+
* Provides a briefing with available tasks and any unfinished work.
|
|
5
|
+
*/
|
|
6
|
+
import * as sessionState from "./sessionState.js";
|
|
7
|
+
/**
|
|
8
|
+
* Format the connection briefing message.
|
|
9
|
+
*/
|
|
10
|
+
export function formatBriefing(agentName, agentType, briefing, isReconnect) {
|
|
11
|
+
const lines = [];
|
|
12
|
+
// Header
|
|
13
|
+
const action = isReconnect ? "Reconnected" : "Registered";
|
|
14
|
+
lines.push(`✅ ${action} as "${agentName}"`);
|
|
15
|
+
lines.push("");
|
|
16
|
+
// Available tasks
|
|
17
|
+
if (briefing.available_tasks.length > 0) {
|
|
18
|
+
const typeNote = agentType ? ` (matching your type: ${agentType})` : "";
|
|
19
|
+
lines.push(`📋 AVAILABLE TASKS${typeNote}:`);
|
|
20
|
+
for (const task of briefing.available_tasks.slice(0, 5)) {
|
|
21
|
+
const priority = task.priority.toUpperCase();
|
|
22
|
+
lines.push(` • [${task.key}] ${task.title} - ${priority} priority`);
|
|
23
|
+
}
|
|
24
|
+
if (briefing.available_tasks.length > 5) {
|
|
25
|
+
lines.push(` ... and ${briefing.available_tasks.length - 5} more`);
|
|
26
|
+
}
|
|
27
|
+
lines.push("");
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
lines.push("📋 No tasks currently available matching your type.");
|
|
31
|
+
lines.push("");
|
|
32
|
+
}
|
|
33
|
+
// Unfinished work (for reconnects)
|
|
34
|
+
if (briefing.unfinished_task) {
|
|
35
|
+
lines.push("⚠️ UNFINISHED WORK:");
|
|
36
|
+
const task = briefing.unfinished_task;
|
|
37
|
+
const keyPart = task.key ? `[${task.key}] ` : "";
|
|
38
|
+
lines.push(` • Previous task: ${keyPart}${task.title} (${task.last_status})`);
|
|
39
|
+
if (briefing.active_blockers > 0) {
|
|
40
|
+
lines.push(` • Active blockers: ${briefing.active_blockers}`);
|
|
41
|
+
}
|
|
42
|
+
lines.push("");
|
|
43
|
+
}
|
|
44
|
+
// Pending messages
|
|
45
|
+
if (briefing.pending_messages_count > 0) {
|
|
46
|
+
lines.push(`📬 You have ${briefing.pending_messages_count} unread message(s).`);
|
|
47
|
+
lines.push("");
|
|
48
|
+
}
|
|
49
|
+
// Action guidance
|
|
50
|
+
lines.push("👉 ACTION REQUIRED:");
|
|
51
|
+
if (briefing.unfinished_task) {
|
|
52
|
+
lines.push(" • Resume previous task, OR");
|
|
53
|
+
}
|
|
54
|
+
if (briefing.available_tasks.length > 0) {
|
|
55
|
+
lines.push(" • Call `claim_ticket_task` to claim a task, OR");
|
|
56
|
+
}
|
|
57
|
+
lines.push(" • Call `agent_start_work` with a task_id to start work");
|
|
58
|
+
return lines.join("\n");
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Execute the OnConnect hook.
|
|
62
|
+
* Returns a briefing message to append to the registration response.
|
|
63
|
+
*/
|
|
64
|
+
export function executeOnConnect(agentId, agentName, agentType, briefing, isReconnect) {
|
|
65
|
+
// Initialize session state
|
|
66
|
+
sessionState.getSession(agentId);
|
|
67
|
+
// Format the briefing
|
|
68
|
+
const message = formatBriefing(agentName, agentType, briefing, isReconnect);
|
|
69
|
+
return {
|
|
70
|
+
blocked: false,
|
|
71
|
+
append_to_response: message,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build briefing data from API responses.
|
|
76
|
+
*/
|
|
77
|
+
export function buildBriefing(availableTasks, pendingMessagesCount, unfinishedTask, activeBlockers) {
|
|
78
|
+
return {
|
|
79
|
+
available_tasks: availableTasks,
|
|
80
|
+
pending_messages_count: pendingMessagesCount,
|
|
81
|
+
unfinished_task: unfinishedTask,
|
|
82
|
+
active_blockers: activeBlockers || 0,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=onConnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onConnect.js","sourceRoot":"","sources":["../../src/hooks/onConnect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OnDisconnect Hook
|
|
3
|
+
* Triggered on agent_disconnect or connection lost.
|
|
4
|
+
* Handles session cleanup, summary generation, and sync.
|
|
5
|
+
*/
|
|
6
|
+
import { SessionSummary, SessionState } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Generate a session summary from the session state.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateSessionSummary(agentId: string): SessionSummary | null;
|
|
11
|
+
/**
|
|
12
|
+
* Format the session summary for Slack notification.
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatSlackSummary(summary: SessionSummary): string;
|
|
15
|
+
/**
|
|
16
|
+
* Execute the OnDisconnect hook.
|
|
17
|
+
* Non-blocking - handles cleanup and returns summary.
|
|
18
|
+
*/
|
|
19
|
+
export declare function executeOnDisconnect(agentId: string): {
|
|
20
|
+
summary: SessionSummary | null;
|
|
21
|
+
slackMessage: string | null;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Check if the session has incomplete work.
|
|
25
|
+
*/
|
|
26
|
+
export declare function hasIncompleteWork(agentId: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Get the current task ID if there's incomplete work.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getIncompleteTaskId(agentId: string): string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Build partial completion data for incomplete tasks.
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildPartialCompletion(agentId: string): {
|
|
35
|
+
task_id: string;
|
|
36
|
+
summary: string;
|
|
37
|
+
outcome: "partial";
|
|
38
|
+
context_counts: SessionState["context_counts"];
|
|
39
|
+
} | null;
|
|
40
|
+
//# sourceMappingURL=onDisconnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onDisconnect.d.ts","sourceRoot":"","sources":["../../src/hooks/onDisconnect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAc,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGtE;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAmC7E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAkBlE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG;IACpD,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAcA;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,CAAC;IACnB,cAAc,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;CAChD,GAAG,IAAI,CAkBP"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OnDisconnect Hook
|
|
3
|
+
* Triggered on agent_disconnect or connection lost.
|
|
4
|
+
* Handles session cleanup, summary generation, and sync.
|
|
5
|
+
*/
|
|
6
|
+
import * as sessionState from "./sessionState.js";
|
|
7
|
+
/**
|
|
8
|
+
* Generate a session summary from the session state.
|
|
9
|
+
*/
|
|
10
|
+
export function generateSessionSummary(agentId) {
|
|
11
|
+
const session = sessionState.getSession(agentId);
|
|
12
|
+
if (!session) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const now = new Date();
|
|
16
|
+
const durationMs = now.getTime() - session.connected_at.getTime();
|
|
17
|
+
const durationMinutes = Math.floor(durationMs / (60 * 1000));
|
|
18
|
+
const summary = {
|
|
19
|
+
agent_id: session.agent_id,
|
|
20
|
+
started_at: session.connected_at,
|
|
21
|
+
ended_at: now,
|
|
22
|
+
duration_minutes: durationMinutes,
|
|
23
|
+
tasks_worked: session.task_id ? [session.task_id] : [],
|
|
24
|
+
context_summary: {
|
|
25
|
+
decisions: session.context_counts.decisions,
|
|
26
|
+
notes: session.context_counts.notes,
|
|
27
|
+
blockers_resolved: 0, // Would need to track separately
|
|
28
|
+
insights: session.context_counts.insights,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
// Check for incomplete task
|
|
32
|
+
if (session.task_id) {
|
|
33
|
+
summary.incomplete_task = {
|
|
34
|
+
task_id: session.task_id,
|
|
35
|
+
last_status: "partial",
|
|
36
|
+
auto_summary: `Session ended while working on task. Duration: ${durationMinutes} minutes. Context saved: ${session.context_counts.decisions} decisions, ${session.context_counts.notes} notes.`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return summary;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Format the session summary for Slack notification.
|
|
43
|
+
*/
|
|
44
|
+
export function formatSlackSummary(summary) {
|
|
45
|
+
const lines = [];
|
|
46
|
+
lines.push(`🔌 Agent disconnected: ${summary.agent_id}`);
|
|
47
|
+
lines.push(`⏱️ Session duration: ${summary.duration_minutes} minutes`);
|
|
48
|
+
const ctx = summary.context_summary;
|
|
49
|
+
if (ctx.decisions > 0 || ctx.notes > 0 || ctx.insights > 0) {
|
|
50
|
+
lines.push(`📝 Context: ${ctx.decisions} decisions, ${ctx.notes} notes, ${ctx.insights} insights`);
|
|
51
|
+
}
|
|
52
|
+
if (summary.incomplete_task) {
|
|
53
|
+
lines.push(`⚠️ Incomplete task: ${summary.incomplete_task.task_id}`);
|
|
54
|
+
}
|
|
55
|
+
return lines.join("\n");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Execute the OnDisconnect hook.
|
|
59
|
+
* Non-blocking - handles cleanup and returns summary.
|
|
60
|
+
*/
|
|
61
|
+
export function executeOnDisconnect(agentId) {
|
|
62
|
+
// Generate summary before clearing session
|
|
63
|
+
const summary = generateSessionSummary(agentId);
|
|
64
|
+
// Clear the session
|
|
65
|
+
sessionState.clearSession(agentId);
|
|
66
|
+
// Format Slack message if we have a summary
|
|
67
|
+
const slackMessage = summary ? formatSlackSummary(summary) : null;
|
|
68
|
+
return {
|
|
69
|
+
summary,
|
|
70
|
+
slackMessage,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if the session has incomplete work.
|
|
75
|
+
*/
|
|
76
|
+
export function hasIncompleteWork(agentId) {
|
|
77
|
+
const session = sessionState.getSession(agentId);
|
|
78
|
+
return session?.task_id !== null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get the current task ID if there's incomplete work.
|
|
82
|
+
*/
|
|
83
|
+
export function getIncompleteTaskId(agentId) {
|
|
84
|
+
const session = sessionState.getSession(agentId);
|
|
85
|
+
return session?.task_id || null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Build partial completion data for incomplete tasks.
|
|
89
|
+
*/
|
|
90
|
+
export function buildPartialCompletion(agentId) {
|
|
91
|
+
const session = sessionState.getSession(agentId);
|
|
92
|
+
if (!session?.task_id) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const durationMs = session.task_started_at
|
|
96
|
+
? new Date().getTime() - session.task_started_at.getTime()
|
|
97
|
+
: 0;
|
|
98
|
+
const durationMinutes = Math.floor(durationMs / (60 * 1000));
|
|
99
|
+
return {
|
|
100
|
+
task_id: session.task_id,
|
|
101
|
+
summary: `Session ended while working on task. Duration: ${durationMinutes} minutes.`,
|
|
102
|
+
outcome: "partial",
|
|
103
|
+
context_counts: session.context_counts,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=onDisconnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onDisconnect.js","sourceRoot":"","sources":["../../src/hooks/onDisconnect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OnTaskComplete Hook
|
|
3
|
+
* Triggered on agent_complete_task.
|
|
4
|
+
* Enforces context requirements before allowing task completion.
|
|
5
|
+
*/
|
|
6
|
+
import { HookResult, TaskCompleteValidation } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Execute the OnTaskComplete hook.
|
|
9
|
+
* Validates that context has been saved and summary is adequate.
|
|
10
|
+
*/
|
|
11
|
+
export declare function executeOnTaskComplete(agentId: string, validation: TaskCompleteValidation): HookResult;
|
|
12
|
+
/**
|
|
13
|
+
* Check if task completion should be allowed (for soft mode).
|
|
14
|
+
* Returns true even without context if enforcement is disabled.
|
|
15
|
+
*/
|
|
16
|
+
export declare function shouldAllowCompletion(agentId: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Get a summary of context saved during the task.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getTaskContextSummary(agentId: string): string;
|
|
21
|
+
//# sourceMappingURL=onTaskComplete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onTaskComplete.d.ts","sourceRoot":"","sources":["../../src/hooks/onTaskComplete.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAgB,MAAM,YAAY,CAAC;AAoD9E;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,sBAAsB,GACjC,UAAU,CAiCZ;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAU9D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAc7D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OnTaskComplete Hook
|
|
3
|
+
* Triggered on agent_complete_task.
|
|
4
|
+
* Enforces context requirements before allowing task completion.
|
|
5
|
+
*/
|
|
6
|
+
import * as sessionState from "./sessionState.js";
|
|
7
|
+
/**
|
|
8
|
+
* Format the block message when context is missing.
|
|
9
|
+
*/
|
|
10
|
+
function formatBlockMessage(counts) {
|
|
11
|
+
const lines = [];
|
|
12
|
+
lines.push("🚫 CANNOT COMPLETE TASK - MISSING CONTEXT");
|
|
13
|
+
lines.push("");
|
|
14
|
+
lines.push("You haven't recorded any decisions or notes.");
|
|
15
|
+
lines.push("Before completing, you MUST document:");
|
|
16
|
+
lines.push("");
|
|
17
|
+
lines.push("REQUIRED (at least one):");
|
|
18
|
+
const decisionStatus = counts.decisions > 0 ? "✅" : "❌";
|
|
19
|
+
const noteStatus = counts.notes > 0 ? "✅" : "❌";
|
|
20
|
+
lines.push(` ${decisionStatus} Decisions: ${counts.decisions} → save_decision(description, reasoning)`);
|
|
21
|
+
lines.push(` ${noteStatus} Notes: ${counts.notes} → save_note(content)`);
|
|
22
|
+
lines.push("");
|
|
23
|
+
lines.push("OPTIONAL:");
|
|
24
|
+
lines.push(` • Blockers: ${counts.blockers} → save_blocker(description)`);
|
|
25
|
+
lines.push(` • Insights: ${counts.insights} → save_codebase_insight(area, insight)`);
|
|
26
|
+
lines.push("");
|
|
27
|
+
lines.push("📝 After saving context, call agent_complete_task again.");
|
|
28
|
+
return lines.join("\n");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validate that the summary meets minimum requirements.
|
|
32
|
+
*/
|
|
33
|
+
function validateSummary(summary, minLength) {
|
|
34
|
+
if (!summary || summary.trim().length === 0) {
|
|
35
|
+
return {
|
|
36
|
+
valid: false,
|
|
37
|
+
message: "Summary cannot be empty. Describe what was accomplished.",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (summary.trim().length < minLength) {
|
|
41
|
+
return {
|
|
42
|
+
valid: false,
|
|
43
|
+
message: `Summary is too short (${summary.trim().length} chars). Minimum: ${minLength} chars.`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return { valid: true };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Execute the OnTaskComplete hook.
|
|
50
|
+
* Validates that context has been saved and summary is adequate.
|
|
51
|
+
*/
|
|
52
|
+
export function executeOnTaskComplete(agentId, validation) {
|
|
53
|
+
const config = sessionState.getConfig();
|
|
54
|
+
// Get context counts from session
|
|
55
|
+
const sessionCounts = sessionState.getContextCounts(agentId);
|
|
56
|
+
// Validate summary
|
|
57
|
+
const summaryValidation = validateSummary(validation.summary, config.min_summary_length);
|
|
58
|
+
if (!summaryValidation.valid) {
|
|
59
|
+
return {
|
|
60
|
+
blocked: true,
|
|
61
|
+
message: `🚫 INVALID SUMMARY\n\n${summaryValidation.message}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Check if context has been saved
|
|
65
|
+
if (!sessionState.hasContextSaved(agentId)) {
|
|
66
|
+
return {
|
|
67
|
+
blocked: true,
|
|
68
|
+
message: formatBlockMessage(sessionCounts),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Validation passed - record completion
|
|
72
|
+
sessionState.completeTask(agentId);
|
|
73
|
+
// Return success with context summary
|
|
74
|
+
const contextNote = `✅ Task completed with ${sessionCounts.decisions} decision(s), ${sessionCounts.notes} note(s), ${sessionCounts.blockers} blocker(s), ${sessionCounts.insights} insight(s).`;
|
|
75
|
+
return {
|
|
76
|
+
blocked: false,
|
|
77
|
+
append_to_response: contextNote,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Check if task completion should be allowed (for soft mode).
|
|
82
|
+
* Returns true even without context if enforcement is disabled.
|
|
83
|
+
*/
|
|
84
|
+
export function shouldAllowCompletion(agentId) {
|
|
85
|
+
const config = sessionState.getConfig();
|
|
86
|
+
// If strict mode is off, always allow
|
|
87
|
+
if (!config.enabled) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
// Check if context has been saved
|
|
91
|
+
return sessionState.hasContextSaved(agentId);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get a summary of context saved during the task.
|
|
95
|
+
*/
|
|
96
|
+
export function getTaskContextSummary(agentId) {
|
|
97
|
+
const counts = sessionState.getContextCounts(agentId);
|
|
98
|
+
const parts = [];
|
|
99
|
+
if (counts.decisions > 0)
|
|
100
|
+
parts.push(`${counts.decisions} decision(s)`);
|
|
101
|
+
if (counts.notes > 0)
|
|
102
|
+
parts.push(`${counts.notes} note(s)`);
|
|
103
|
+
if (counts.blockers > 0)
|
|
104
|
+
parts.push(`${counts.blockers} blocker(s)`);
|
|
105
|
+
if (counts.insights > 0)
|
|
106
|
+
parts.push(`${counts.insights} insight(s)`);
|
|
107
|
+
if (parts.length === 0) {
|
|
108
|
+
return "No context saved during this task.";
|
|
109
|
+
}
|
|
110
|
+
return `Context saved: ${parts.join(", ")}.`;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=onTaskComplete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onTaskComplete.js","sourceRoot":"","sources":["../../src/hooks/onTaskComplete.ts"],"names":[],"mappings":"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"}
|