@agent-relay/hooks 0.1.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/dist/browser.d.ts +2 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +3 -0
- package/dist/browser.js.map +1 -0
- package/dist/emitter.d.ts +40 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +63 -0
- package/dist/emitter.js.map +1 -0
- package/dist/inbox-check/hook.d.ts +28 -0
- package/dist/inbox-check/hook.d.ts.map +1 -0
- package/dist/inbox-check/hook.js +97 -0
- package/dist/inbox-check/hook.js.map +1 -0
- package/dist/inbox-check/index.d.ts +8 -0
- package/dist/inbox-check/index.d.ts.map +1 -0
- package/dist/inbox-check/index.js +8 -0
- package/dist/inbox-check/index.js.map +1 -0
- package/dist/inbox-check/types.d.ts +31 -0
- package/dist/inbox-check/types.d.ts.map +1 -0
- package/dist/inbox-check/types.js +5 -0
- package/dist/inbox-check/types.js.map +1 -0
- package/dist/inbox-check/utils.d.ts +44 -0
- package/dist/inbox-check/utils.d.ts.map +1 -0
- package/dist/inbox-check/utils.js +107 -0
- package/dist/inbox-check/utils.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +173 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +476 -0
- package/dist/registry.js.map +1 -0
- package/dist/trajectory-hooks.d.ts +52 -0
- package/dist/trajectory-hooks.d.ts.map +1 -0
- package/dist/trajectory-hooks.js +183 -0
- package/dist/trajectory-hooks.js.map +1 -0
- package/dist/types.d.ts +285 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HookEmitter
|
|
3
|
+
*
|
|
4
|
+
* Lightweight async event emitter for hook handlers.
|
|
5
|
+
* - Supports async handlers
|
|
6
|
+
* - Allows stop-propagation via `{ stop: true }` return value
|
|
7
|
+
* - Can preload handlers from a config object
|
|
8
|
+
*/
|
|
9
|
+
export type EmitterHandlerResult = unknown | {
|
|
10
|
+
stop?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type EmitterHandler = (...args: unknown[]) => EmitterHandlerResult | Promise<EmitterHandlerResult>;
|
|
13
|
+
export interface EmitResult {
|
|
14
|
+
/** Raw results from each handler in order */
|
|
15
|
+
results: EmitterHandlerResult[];
|
|
16
|
+
/** Whether propagation was stopped by a handler */
|
|
17
|
+
stopped: boolean;
|
|
18
|
+
}
|
|
19
|
+
export type EmitterHandlerConfig = Record<string, EmitterHandler | EmitterHandler[]>;
|
|
20
|
+
export declare class HookEmitter {
|
|
21
|
+
private handlers;
|
|
22
|
+
constructor(config?: EmitterHandlerConfig);
|
|
23
|
+
/**
|
|
24
|
+
* Register a handler for an event.
|
|
25
|
+
* Returns an unsubscribe function to remove the handler.
|
|
26
|
+
*/
|
|
27
|
+
on(event: string, handler: EmitterHandler): () => void;
|
|
28
|
+
/**
|
|
29
|
+
* Emit an event and invoke handlers sequentially.
|
|
30
|
+
* If a handler returns `{ stop: true }`, propagation halts.
|
|
31
|
+
*/
|
|
32
|
+
emit(event: string, ...args: unknown[]): Promise<EmitResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Load handlers from a configuration object.
|
|
35
|
+
* Values can be a single handler or an array of handlers.
|
|
36
|
+
*/
|
|
37
|
+
load(config: EmitterHandlerConfig): void;
|
|
38
|
+
private shouldStop;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAChE,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAE1G,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,mDAAmD;IACnD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC,CAAC;AAErF,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAuC;gBAE3C,MAAM,CAAC,EAAE,oBAAoB;IAMzC;;;OAGG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,IAAI;IAWtD;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAkBlE;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IASxC,OAAO,CAAC,UAAU;CAGnB"}
|
package/dist/emitter.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HookEmitter
|
|
3
|
+
*
|
|
4
|
+
* Lightweight async event emitter for hook handlers.
|
|
5
|
+
* - Supports async handlers
|
|
6
|
+
* - Allows stop-propagation via `{ stop: true }` return value
|
|
7
|
+
* - Can preload handlers from a config object
|
|
8
|
+
*/
|
|
9
|
+
export class HookEmitter {
|
|
10
|
+
handlers = new Map();
|
|
11
|
+
constructor(config) {
|
|
12
|
+
if (config) {
|
|
13
|
+
this.load(config);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Register a handler for an event.
|
|
18
|
+
* Returns an unsubscribe function to remove the handler.
|
|
19
|
+
*/
|
|
20
|
+
on(event, handler) {
|
|
21
|
+
const list = this.handlers.get(event) ?? [];
|
|
22
|
+
list.push(handler);
|
|
23
|
+
this.handlers.set(event, list);
|
|
24
|
+
return () => {
|
|
25
|
+
const updated = this.handlers.get(event)?.filter((fn) => fn !== handler) ?? [];
|
|
26
|
+
this.handlers.set(event, updated);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Emit an event and invoke handlers sequentially.
|
|
31
|
+
* If a handler returns `{ stop: true }`, propagation halts.
|
|
32
|
+
*/
|
|
33
|
+
async emit(event, ...args) {
|
|
34
|
+
const results = [];
|
|
35
|
+
const handlers = this.handlers.get(event) ?? [];
|
|
36
|
+
let stopped = false;
|
|
37
|
+
for (const handler of handlers) {
|
|
38
|
+
const result = await handler(...args);
|
|
39
|
+
results.push(result);
|
|
40
|
+
if (this.shouldStop(result)) {
|
|
41
|
+
stopped = true;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { results, stopped };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Load handlers from a configuration object.
|
|
49
|
+
* Values can be a single handler or an array of handlers.
|
|
50
|
+
*/
|
|
51
|
+
load(config) {
|
|
52
|
+
for (const [event, handler] of Object.entries(config)) {
|
|
53
|
+
const handlers = Array.isArray(handler) ? handler : [handler];
|
|
54
|
+
for (const h of handlers) {
|
|
55
|
+
this.on(event, h);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
shouldStop(result) {
|
|
60
|
+
return typeof result === 'object' && result !== null && 'stop' in result && result.stop === true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.js","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH,MAAM,OAAO,WAAW;IACd,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAC;IAEvD,YAAY,MAA6B;QACvC,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,EAAE,CAAC,KAAa,EAAE,OAAuB;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAE/B,OAAO,GAAG,EAAE;YACV,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/E,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACpC,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,GAAG,IAAe;QAC1C,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;YACtC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAErB,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5B,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM;YACR,CAAC;QACH,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC9B,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,MAA4B;QAC/B,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC9D,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,MAA4B;QAC7C,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,IAAI,MAAM,IAAK,MAAc,CAAC,IAAI,KAAK,IAAI,CAAC;IAC5G,CAAC;CACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent Relay Inbox Check Hook
|
|
4
|
+
*
|
|
5
|
+
* A Claude Code Stop hook that checks for unread messages in the agent-relay inbox.
|
|
6
|
+
* When messages are present, it blocks Claude from stopping and instructs it to
|
|
7
|
+
* read and respond to the messages.
|
|
8
|
+
*
|
|
9
|
+
* This enables autonomous agent-to-agent communication without human intervention.
|
|
10
|
+
*
|
|
11
|
+
* Usage in .claude/settings.json:
|
|
12
|
+
* {
|
|
13
|
+
* "hooks": {
|
|
14
|
+
* "Stop": [{
|
|
15
|
+
* "hooks": [{
|
|
16
|
+
* "type": "command",
|
|
17
|
+
* "command": "node /path/to/agent-relay/dist/hooks/inbox-check/hook.js"
|
|
18
|
+
* }]
|
|
19
|
+
* }]
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* Environment Variables:
|
|
24
|
+
* - AGENT_RELAY_NAME: The agent's name (set by agent-relay wrapper)
|
|
25
|
+
* - AGENT_RELAY_INBOX_DIR: Custom inbox directory (default: /tmp/agent-relay)
|
|
26
|
+
*/
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/inbox-check/hook.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent Relay Inbox Check Hook
|
|
4
|
+
*
|
|
5
|
+
* A Claude Code Stop hook that checks for unread messages in the agent-relay inbox.
|
|
6
|
+
* When messages are present, it blocks Claude from stopping and instructs it to
|
|
7
|
+
* read and respond to the messages.
|
|
8
|
+
*
|
|
9
|
+
* This enables autonomous agent-to-agent communication without human intervention.
|
|
10
|
+
*
|
|
11
|
+
* Usage in .claude/settings.json:
|
|
12
|
+
* {
|
|
13
|
+
* "hooks": {
|
|
14
|
+
* "Stop": [{
|
|
15
|
+
* "hooks": [{
|
|
16
|
+
* "type": "command",
|
|
17
|
+
* "command": "node /path/to/agent-relay/dist/hooks/inbox-check/hook.js"
|
|
18
|
+
* }]
|
|
19
|
+
* }]
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* Environment Variables:
|
|
24
|
+
* - AGENT_RELAY_NAME: The agent's name (set by agent-relay wrapper)
|
|
25
|
+
* - AGENT_RELAY_INBOX_DIR: Custom inbox directory (default: /tmp/agent-relay)
|
|
26
|
+
*/
|
|
27
|
+
import { readFileSync } from 'node:fs';
|
|
28
|
+
import { DEFAULT_INBOX_DIR, getAgentName, getInboxPath, hasUnreadMessages, countMessages, buildBlockReason } from './utils.js';
|
|
29
|
+
/**
|
|
30
|
+
* Read hook input from stdin
|
|
31
|
+
*/
|
|
32
|
+
function readStdin() {
|
|
33
|
+
try {
|
|
34
|
+
const input = readFileSync(0, 'utf-8');
|
|
35
|
+
return JSON.parse(input);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Output hook result as JSON
|
|
43
|
+
*/
|
|
44
|
+
function outputResult(result) {
|
|
45
|
+
console.log(JSON.stringify(result));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Exit the hook process
|
|
49
|
+
*/
|
|
50
|
+
function exitHook(code) {
|
|
51
|
+
process.exit(code);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Main hook execution
|
|
55
|
+
*/
|
|
56
|
+
async function main() {
|
|
57
|
+
try {
|
|
58
|
+
// Read stdin (required by Claude Code hook protocol, but we only use env vars)
|
|
59
|
+
readStdin();
|
|
60
|
+
// Get agent name from env
|
|
61
|
+
const agentName = getAgentName();
|
|
62
|
+
// If no agent name configured, allow stop (not in relay mode)
|
|
63
|
+
if (!agentName) {
|
|
64
|
+
outputResult({ decision: 'approve' });
|
|
65
|
+
exitHook(0);
|
|
66
|
+
}
|
|
67
|
+
// Get inbox configuration
|
|
68
|
+
const inboxDir = process.env.AGENT_RELAY_INBOX_DIR || DEFAULT_INBOX_DIR;
|
|
69
|
+
const inboxPath = getInboxPath({ inboxDir, agentName });
|
|
70
|
+
// Check for unread messages
|
|
71
|
+
if (hasUnreadMessages(inboxPath)) {
|
|
72
|
+
const messageCount = countMessages(inboxPath);
|
|
73
|
+
const reason = buildBlockReason(inboxPath, messageCount);
|
|
74
|
+
// Log to stderr for visibility
|
|
75
|
+
console.error(`[agent-relay] Found ${messageCount} unread message(s), blocking stop`);
|
|
76
|
+
// Block stop and provide reason
|
|
77
|
+
outputResult({
|
|
78
|
+
decision: 'block',
|
|
79
|
+
reason
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// No messages, allow stop
|
|
84
|
+
outputResult({ decision: 'approve' });
|
|
85
|
+
}
|
|
86
|
+
exitHook(0);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
// On error, allow stop to avoid blocking user
|
|
90
|
+
console.error('[agent-relay] Hook error:', error);
|
|
91
|
+
outputResult({ decision: 'approve' });
|
|
92
|
+
exitHook(0);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Run the hook
|
|
96
|
+
main();
|
|
97
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/inbox-check/hook.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,SAAS,SAAS;IAChB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,MAAkB;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,+EAA+E;QAC/E,SAAS,EAAE,CAAC;QAEZ,0BAA0B;QAC1B,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;QAEjC,8DAA8D;QAC9D,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,YAAY,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YACtC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACd,CAAC;QAED,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,iBAAiB,CAAC;QACxE,MAAM,SAAS,GAAG,YAAY,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QAExD,4BAA4B;QAC5B,IAAI,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,MAAM,YAAY,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;YAEzD,+BAA+B;YAC/B,OAAO,CAAC,KAAK,CAAC,uBAAuB,YAAY,mCAAmC,CAAC,CAAC;YAEtF,gCAAgC;YAChC,YAAY,CAAC;gBACX,QAAQ,EAAE,OAAO;gBACjB,MAAM;aACP,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,0BAA0B;YAC1B,YAAY,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACxC,CAAC;QAED,QAAQ,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,8CAA8C;QAC9C,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAClD,YAAY,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACtC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;AACH,CAAC;AAED,eAAe;AACf,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inbox-check/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/inbox-check/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for Agent Relay Inbox Check Hook
|
|
3
|
+
*/
|
|
4
|
+
export interface HookInput {
|
|
5
|
+
/** The hook event type */
|
|
6
|
+
hook_event_name?: string;
|
|
7
|
+
/** Working directory */
|
|
8
|
+
workingDirectory?: string;
|
|
9
|
+
/** Session ID */
|
|
10
|
+
session_id?: string;
|
|
11
|
+
/** Stop reason from Claude */
|
|
12
|
+
stop_reason?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface HookOutput {
|
|
15
|
+
/** Decision: "approve" to allow stop, "block" to continue */
|
|
16
|
+
decision: 'approve' | 'block';
|
|
17
|
+
/** Reason for the decision (shown to Claude if blocked) */
|
|
18
|
+
reason?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface InboxMessage {
|
|
21
|
+
from: string;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
body: string;
|
|
24
|
+
}
|
|
25
|
+
export interface InboxConfig {
|
|
26
|
+
/** Base directory for inbox files */
|
|
27
|
+
inboxDir: string;
|
|
28
|
+
/** Agent name (from env var or config) */
|
|
29
|
+
agentName?: string;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/inbox-check/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,SAAS;IACxB,0BAA0B;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/inbox-check/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for Agent Relay Inbox Check Hook
|
|
3
|
+
*/
|
|
4
|
+
import type { InboxConfig, InboxMessage } from './types.js';
|
|
5
|
+
/** Default inbox directory */
|
|
6
|
+
export declare const DEFAULT_INBOX_DIR = "/tmp/agent-relay";
|
|
7
|
+
/**
|
|
8
|
+
* Get the agent name from environment or config
|
|
9
|
+
*/
|
|
10
|
+
export declare function getAgentName(): string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Get the inbox file path for an agent
|
|
13
|
+
*/
|
|
14
|
+
export declare function getInboxPath(config: InboxConfig): string;
|
|
15
|
+
/**
|
|
16
|
+
* Check if inbox file exists and has content
|
|
17
|
+
*/
|
|
18
|
+
export declare function inboxExists(inboxPath: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Read inbox file content
|
|
21
|
+
*/
|
|
22
|
+
export declare function readInbox(inboxPath: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Check if inbox has unread messages
|
|
25
|
+
* Messages are marked with "## Message from" header
|
|
26
|
+
*/
|
|
27
|
+
export declare function hasUnreadMessages(inboxPath: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Count unread messages in inbox
|
|
30
|
+
*/
|
|
31
|
+
export declare function countMessages(inboxPath: string): number;
|
|
32
|
+
/**
|
|
33
|
+
* Parse messages from inbox content
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseMessages(inboxPath: string): InboxMessage[];
|
|
36
|
+
/**
|
|
37
|
+
* Format a message for display
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatMessagePreview(msg: InboxMessage, maxLength?: number): string;
|
|
40
|
+
/**
|
|
41
|
+
* Build the block reason message
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildBlockReason(inboxPath: string, messageCount: number): string;
|
|
44
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/inbox-check/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,8BAA8B;AAC9B,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAEpD;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAGjD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAMxD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAO5D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAmB/D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,GAAE,MAAW,GAAG,MAAM,CAKtF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAehF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for Agent Relay Inbox Check Hook
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
/** Default inbox directory */
|
|
7
|
+
export const DEFAULT_INBOX_DIR = '/tmp/agent-relay';
|
|
8
|
+
/**
|
|
9
|
+
* Get the agent name from environment or config
|
|
10
|
+
*/
|
|
11
|
+
export function getAgentName() {
|
|
12
|
+
// Check environment variable set by agent-relay wrapper
|
|
13
|
+
return process.env.AGENT_RELAY_NAME;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the inbox file path for an agent
|
|
17
|
+
*/
|
|
18
|
+
export function getInboxPath(config) {
|
|
19
|
+
const agentName = config.agentName || getAgentName();
|
|
20
|
+
if (!agentName) {
|
|
21
|
+
throw new Error('Agent name not configured. Set AGENT_RELAY_NAME env var.');
|
|
22
|
+
}
|
|
23
|
+
return join(config.inboxDir, agentName, 'inbox.md');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if inbox file exists and has content
|
|
27
|
+
*/
|
|
28
|
+
export function inboxExists(inboxPath) {
|
|
29
|
+
return existsSync(inboxPath);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Read inbox file content
|
|
33
|
+
*/
|
|
34
|
+
export function readInbox(inboxPath) {
|
|
35
|
+
if (!inboxExists(inboxPath)) {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
return readFileSync(inboxPath, 'utf-8');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if inbox has unread messages
|
|
42
|
+
* Messages are marked with "## Message from" header
|
|
43
|
+
*/
|
|
44
|
+
export function hasUnreadMessages(inboxPath) {
|
|
45
|
+
const content = readInbox(inboxPath);
|
|
46
|
+
if (!content || !content.trim()) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
// Check for message headers
|
|
50
|
+
return content.includes('## Message from');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Count unread messages in inbox
|
|
54
|
+
*/
|
|
55
|
+
export function countMessages(inboxPath) {
|
|
56
|
+
const content = readInbox(inboxPath);
|
|
57
|
+
if (!content) {
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
const matches = content.match(/## Message from/g);
|
|
61
|
+
return matches ? matches.length : 0;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Parse messages from inbox content
|
|
65
|
+
*/
|
|
66
|
+
export function parseMessages(inboxPath) {
|
|
67
|
+
const content = readInbox(inboxPath);
|
|
68
|
+
if (!content) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
const messages = [];
|
|
72
|
+
const messageBlocks = content.split(/(?=## Message from)/);
|
|
73
|
+
for (const block of messageBlocks) {
|
|
74
|
+
const headerMatch = block.match(/## Message from (\S+) \| (.+)\n/);
|
|
75
|
+
if (headerMatch) {
|
|
76
|
+
const [, from, timestamp] = headerMatch;
|
|
77
|
+
const body = block.replace(/## Message from .+\n/, '').trim();
|
|
78
|
+
messages.push({ from, timestamp, body });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return messages;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Format a message for display
|
|
85
|
+
*/
|
|
86
|
+
export function formatMessagePreview(msg, maxLength = 50) {
|
|
87
|
+
const preview = msg.body.length > maxLength
|
|
88
|
+
? msg.body.substring(0, maxLength) + '...'
|
|
89
|
+
: msg.body;
|
|
90
|
+
return `[${msg.from}]: ${preview}`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Build the block reason message
|
|
94
|
+
*/
|
|
95
|
+
export function buildBlockReason(inboxPath, messageCount) {
|
|
96
|
+
const messages = parseMessages(inboxPath);
|
|
97
|
+
const previews = messages.slice(0, 3).map(m => formatMessagePreview(m));
|
|
98
|
+
let reason = `You have ${messageCount} unread relay message(s) in ${inboxPath}.\n\n`;
|
|
99
|
+
reason += 'Messages:\n';
|
|
100
|
+
reason += previews.map(p => ` - ${p}`).join('\n');
|
|
101
|
+
if (messages.length > 3) {
|
|
102
|
+
reason += `\n ... and ${messages.length - 3} more`;
|
|
103
|
+
}
|
|
104
|
+
reason += '\n\nPlease read the inbox file and respond to all messages before stopping.';
|
|
105
|
+
return reason;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/inbox-check/utils.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Relay Hooks
|
|
3
|
+
*
|
|
4
|
+
* Entry point for the hooks system types and utilities.
|
|
5
|
+
*/
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
export * from './registry.js';
|
|
8
|
+
export * from './trajectory-hooks.js';
|
|
9
|
+
export * from './emitter.js';
|
|
10
|
+
export * from './inbox-check/index.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Relay Hooks
|
|
3
|
+
*
|
|
4
|
+
* Entry point for the hooks system types and utilities.
|
|
5
|
+
*/
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
export * from './registry.js';
|
|
8
|
+
export * from './trajectory-hooks.js';
|
|
9
|
+
export * from './emitter.js';
|
|
10
|
+
export * from './inbox-check/index.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC"}
|