chat-recall 0.7.20 → 0.7.21

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 CHANGED
@@ -19,7 +19,7 @@
19
19
  Every coding agent you run keeps a full transcript of its work: the decisions, the
20
20
  reasoning, the keys somebody pasted, the problems it found and never filed. Each one
21
21
  writes to its own directory in its own format, none can read another's, and nothing
22
- reads any of them. `chat-recall` does, through **63 MCP tools**.
22
+ reads any of them. `chat-recall` does, through **68 MCP tools**.
23
23
 
24
24
  | | What it does | Tools |
25
25
  |---|---|---|
@@ -131,7 +131,7 @@ Exclusions live on the machine that holds the data, so the CLI owns them; they a
131
131
  ## Four things it actually does
132
132
 
133
133
  1. **Cross-tool unified memory.** One index, one search, one UI over Claude Code (`~/.claude/projects/`), Codex (`~/.codex/`), OpenCode (`~/.local/share/opencode/`), Antigravity (`~/.gemini/antigravity-cli/`), Cursor (`~/.cursor/` for the CLI, `~/.config/Cursor/` for the IDE), Hermes Agent (`~/.hermes/`) and Pi (`~/.pi/agent/`). Sessions, plans, tasks, CLAUDE.md files, paste cache, shell history and agent diaries all share one pluggable `MemorySource` interface.
134
- 2. **The agent recalls itself.** 63 MCP tools, so Claude Code can `recall_smart_resume`, `recall_search` (with `like_session` to find similar work), `recall_edits_timeline`, `recall_subagent_search` and `recall_redundant_files` rather than asking you what happened last time. It writes back too, via `recall_decision_record`, `recall_kg_add` and `recall_set`.
134
+ 2. **The agent recalls itself.** 68 MCP tools, so Claude Code can `recall_smart_resume`, `recall_search` (with `like_session` to find similar work), `recall_edits_timeline`, `recall_subagent_search` and `recall_redundant_files` rather than asking you what happened last time. It writes back too, via `recall_decision_record`, `recall_kg_add` and `recall_set`.
135
135
  3. **Warns before you redo work.** A `UserPromptSubmit` hook searches for similar past sessions on every prompt and injects a short "you have done this before, in session X" note into the agent's context.
136
136
  4. **Temporal knowledge graph.** Decisions and tool mentions become entity-relationship triples with `valid_from`/`valid_to` windows, so you can ask what was decided in March and whether it still holds.
137
137
 
@@ -216,16 +216,20 @@ CHAT_RECALL_DAEMON_IDLE_SECS=0 # keep the daemon resident (default 900)
216
216
  If the daemon cannot be reached for any reason, the session loads the server
217
217
  itself and works exactly as it did before — slower, never broken.
218
218
 
219
- Then install the hooks (one command sets up auto-save, pre-compact backup, and the resume-hint that warns when you're about to redo work):
219
+ `chat-recall init` installs the Claude Code hooks in every profile's
220
+ `settings.json`. If you added only the MCP server, from a marketplace button or
221
+ by hand, the MCP server installs them when it starts. You run nothing else.
222
+
223
+ To choose which hooks run, or to remove them:
220
224
 
221
225
  ```bash
222
- chat-recall install-hooks # registers all five events, in every Claude profile
223
- chat-recall install-hooks --no-resume-hint # skip the resume warning
224
- chat-recall install-hooks --no-wakeup # skip the session-start wake-up bundle
225
- chat-recall install-hooks --no-escalate # skip the session-end escalation
226
- chat-recall install-hooks --uninstall # remove all of ours, leave third-party hooks alone
226
+ chat-recall install-hooks --no-resume-hint # without the resume warning
227
+ chat-recall install-hooks --no-messages # without messages between sessions
228
+ chat-recall install-hooks --uninstall # remove ours; third-party hooks stay
227
229
  ```
228
230
 
231
+ After `--uninstall` the MCP server does not put them back.
232
+
229
233
  | Hook | When it fires | What it does |
230
234
  |---|---|---|
231
235
  | `SessionStart` | New session (`startup` / `clear`) | Injects the project-scoped wake-up bundle |
@@ -233,6 +237,29 @@ chat-recall install-hooks --uninstall # remove all of ours, leave third-part
233
237
  | `Stop` | After every assistant turn | Auto-saves topics, decisions, and tools to `~/.chat-recall/memory/` |
234
238
  | `PreCompact` | Before Claude Code compacts context | Emergency save so nothing is lost to compaction |
235
239
  | `SessionEnd` | When the session closes | Escalates the session's learnings in the background, so nothing is delayed |
240
+ | `SessionStart`, `UserPromptSubmit`, `Stop`, `SessionEnd` | Each turn | Messages between sessions: tells the session its id, delivers what waits for it, reports its state |
241
+ | `SessionStart`, `UserPromptSubmit`, `Stop` (background) | Until a message arrives | Waits for a message from another session and wakes this one, also when it is idle |
242
+
243
+ ## Sessions that work together
244
+
245
+ One session can start others and direct them. In Claude Code, ask for it in
246
+ plain words: "start two workers, one on the API and one on the web form, and
247
+ tell me when both are done".
248
+
249
+ - `recall_session_spawn` starts a child as a Claude Code background session,
250
+ linked to its parent. `claude attach <id>` opens it.
251
+ - `recall_message_send` sends to a session by id or name, or to `parent`,
252
+ `children` or `group`. The message wakes the recipient within about a second,
253
+ also when it waits for input.
254
+ - `recall_session_status` lists the sessions: what each works on, its board
255
+ cards, and whether it is working, idle, waiting for a permission prompt, or
256
+ ended.
257
+ - Decisions, facts and shared state go in the memory every session reads:
258
+ `recall_decision_record`, `recall_kg_add`, `recall_set`.
259
+
260
+ A message from another session is not a message from you. A child acts on its
261
+ parent's messages because its parent started it with that instruction. Any
262
+ other session treats a message as information and checks with you first.
236
263
 
237
264
  ## The decision guard
238
265
 
@@ -256,13 +283,13 @@ guard uninstalled; a wrong warning costs a line of context. Set
256
283
  `CHAT_RECALL_GUARD_ENFORCE=1` to block instead, per machine. `CHAT_RECALL_GUARD=0`
257
284
  turns it off.
258
285
 
259
- `chat-recall install-hooks` registers it in all five tools. Each one keeps its
286
+ `chat-recall init` registers it in all five tools. Each one keeps its
260
287
  pre-execution hook in its own file, so the installer writes five shapes and
261
288
  skips any tool that is not on the machine (`--no-guard` to skip all of them):
262
289
 
263
290
  | Tool | Where | Event |
264
291
  |---|---|---|
265
- | Claude Code | `~/.claude/hooks.json`, every profile | `PreToolUse` |
292
+ | Claude Code | `~/.claude/settings.json`, every profile | `PreToolUse` |
266
293
  | Codex | `~/.codex/hooks.json` | `PreToolUse` |
267
294
  | Antigravity | `~/.gemini/antigravity-cli/hooks.json` | `PreToolUse` — the one tool with a real `ask` verdict, so it can prompt |
268
295
  | Cursor | `~/.cursor/hooks.json` | `beforeShellExecution` + `afterFileEdit` |
@@ -1,3 +1,10 @@
1
+ type HookEntry = {
2
+ matcher: string;
3
+ hooks: Array<{
4
+ type: string;
5
+ command: string;
6
+ }>;
7
+ };
1
8
  /** The two events the board loop needs, and the flag each one passes. */
2
9
  export declare const BOARD_HOOKS: ReadonlyArray<{
3
10
  event: string;
@@ -12,7 +19,7 @@ export declare const BOARD_HOOKS: ReadonlyArray<{
12
19
  */
13
20
  export declare function boardHookCommand(execPath: string, cliEntry: string, mode: 'claim' | 'close'): string;
14
21
  /**
15
- * True when this hooks.json entry is one of ours.
22
+ * True when this hook entry is one of ours.
16
23
  *
17
24
  * It answers for two shapes. The first is the CLI command above. The second is
18
25
  * `chat_recall_task_hook.sh`, a wrapper that shipped briefly and did nothing
@@ -21,36 +28,39 @@ export declare function boardHookCommand(execPath: string, cliEntry: string, mod
21
28
  * cleaned up.
22
29
  */
23
30
  export declare function isBoardHookEntry(entry: unknown): boolean;
24
- /** The `[event, entry]` pairs for a hooks.json. */
25
- export declare function boardHookEntries(execPath: string, cliEntry: string): Array<[string, {
26
- matcher: string;
27
- hooks: Array<{
28
- type: string;
29
- command: string;
30
- }>;
31
- }]>;
31
+ /** The `[event, entry]` pairs for a settings.json. */
32
+ export declare function boardHookEntries(execPath: string, cliEntry: string): Array<[string, HookEntry]>;
32
33
  /**
33
- * Merge the board hooks into one already-parsed hooks.json object.
34
- *
35
- * Every prior entry of ours is dropped first, so a reinstall after an upgrade
36
- * replaces a stale bundle path instead of stacking a second registration.
37
- * Entries that are not ours are untouched: a profile carries the resume hint on
38
- * the same event.
34
+ * The events of the message hook's turn runs. SessionStart tells the session
35
+ * its own id; the prompt and the turn end deliver what already waits;
36
+ * SessionEnd marks the session ended so a parent stops waiting for it.
39
37
  */
40
- export declare function mergeBoardHooks(config: {
41
- hooks?: Record<string, unknown[]>;
42
- }, execPath: string, cliEntry: string): void;
43
- /** Drop the board hooks from one already-parsed hooks.json object. */
44
- export declare function removeBoardHooks(config: {
45
- hooks?: Record<string, unknown[]>;
46
- }): number;
38
+ export declare const MESSAGE_HOOK_EVENTS: readonly string[];
47
39
  /**
48
- * Register the board hooks in every given hooks.json.
49
- *
50
- * Returns the files it wrote. A file it cannot parse is skipped rather than
51
- * overwritten: another tool's config is not ours to replace.
40
+ * The events that start the waiter. It runs in the background (asyncRewake)
41
+ * until a message arrives, then exits 2 and Claude Code wakes the session; the
42
+ * turn that follows ends in a Stop, which starts the next waiter.
52
43
  */
53
- export declare function registerBoardHooks(files: string[], execPath: string, cliEntry: string): string[];
44
+ export declare const MESSAGE_WAITER_EVENTS: readonly string[];
45
+ /** The command Claude Code runs for the message hook. Both paths quoted, as above. */
46
+ export declare function messageHookCommand(execPath: string, hookEntry: string, waiter?: boolean): string;
47
+ /** True when this hook entry is the message hook, its turn run or its waiter. */
48
+ export declare function isMessageHookEntry(entry: unknown): boolean;
49
+ /** True when this hook entry is the waiter. */
50
+ export declare function isMessageWaiterEntry(entry: unknown): boolean;
51
+ type HookCommand = {
52
+ type: string;
53
+ command: string;
54
+ asyncRewake?: boolean;
55
+ };
56
+ /** The `[event, entry]` pairs for the message hook: the turn runs, then the waiters. */
57
+ export declare function messageHookEntries(execPath: string, hookEntry: string): Array<[string, {
58
+ matcher: string;
59
+ hooks: HookCommand[];
60
+ }]>;
54
61
  /** Resolve the CLI entry that a hook should run. */
55
62
  export declare function resolveCliEntry(distDir: string): string;
63
+ /** Resolve the message hook bundle that sits beside the CLI. */
64
+ export declare function resolveMessageHookEntry(distDir: string): string;
65
+ export {};
56
66
  //# sourceMappingURL=board-hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"board-hooks.d.ts","sourceRoot":"","sources":["../src/board-hooks.ts"],"names":[],"mappings":"AAqBA,yEAAyE;AACzE,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;CAAE,CAGjF,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAEpG;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKxD;AAED,mDAAmD;AACnD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,KAAK,CAAC,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAAC,CAKvF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;CAAE,EAC7C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,IAAI,CASN;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;CAAE,GAAG,MAAM,CAWtF;AAYD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAehG;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvD"}
1
+ {"version":3,"file":"board-hooks.d.ts","sourceRoot":"","sources":["../src/board-hooks.ts"],"names":[],"mappings":"AA0BA,KAAK,SAAS,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC;AAQtF,yEAAyE;AACzE,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;CAAE,CAGjF,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAEpG;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKxD;AAED,sDAAsD;AACtD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAK/F;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAA+D,CAAC;AAEjH;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAiD,CAAC;AAErG,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,MAAM,CAE9F;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG1D;AAED,+CAA+C;AAC/C,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE5D;AAED,KAAK,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5E,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,EAAE,CAAA;CAAE,CAAC,CAAC,CAOlI;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,gEAAgE;AAChE,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG/D"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Registration for the two board hooks, on every platform.
2
+ * The commands for the two board hooks and the message hook, on every
3
+ * platform. install-hooks.ts writes them into each profile's settings.json.
3
4
  *
4
5
  * The other five hooks are POSIX shell scripts, and `install-hooks` refuses to
5
6
  * register any of them on Windows: Claude Code runs a hook command through
@@ -15,9 +16,18 @@
15
16
  * Registration is also the only reason the loop reaches anyone: `init` never
16
17
  * installed hooks, so until now the board moved for whoever had separately run
17
18
  * `chat-recall install-hooks`.
19
+ *
20
+ * The message hook is registered the same way, for the same reason. It is its
21
+ * own small bundle (`dist/message-hook.js`) because it runs on every tool call,
22
+ * and the full CLI takes about 0.4 s to start.
18
23
  */
19
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
20
- import { dirname, join } from 'node:path';
24
+ import { existsSync } from 'node:fs';
25
+ import { join } from 'node:path';
26
+ /** The command string of a hook entry, or null for a malformed one. */
27
+ function entryCommand(entry) {
28
+ const cmd = entry?.hooks?.[0]?.command;
29
+ return typeof cmd === 'string' ? cmd : null;
30
+ }
21
31
  /** The two events the board loop needs, and the flag each one passes. */
22
32
  export const BOARD_HOOKS = [
23
33
  { event: 'UserPromptSubmit', mode: 'claim' },
@@ -34,7 +44,7 @@ export function boardHookCommand(execPath, cliEntry, mode) {
34
44
  return `"${execPath}" "${cliEntry}" task-hook --${mode}`;
35
45
  }
36
46
  /**
37
- * True when this hooks.json entry is one of ours.
47
+ * True when this hook entry is one of ours.
38
48
  *
39
49
  * It answers for two shapes. The first is the CLI command above. The second is
40
50
  * `chat_recall_task_hook.sh`, a wrapper that shipped briefly and did nothing
@@ -43,14 +53,14 @@ export function boardHookCommand(execPath, cliEntry, mode) {
43
53
  * cleaned up.
44
54
  */
45
55
  export function isBoardHookEntry(entry) {
46
- const cmd = entry?.hooks?.[0]?.command;
47
- if (typeof cmd !== 'string')
56
+ const cmd = entryCommand(entry);
57
+ if (cmd === null)
48
58
  return false;
49
59
  if (cmd.includes('chat_recall_task_hook.sh'))
50
60
  return true;
51
61
  return cmd.includes('task-hook') && (cmd.includes('--claim') || cmd.includes('--close'));
52
62
  }
53
- /** The `[event, entry]` pairs for a hooks.json. */
63
+ /** The `[event, entry]` pairs for a settings.json. */
54
64
  export function boardHookEntries(execPath, cliEntry) {
55
65
  return BOARD_HOOKS.map(({ event, mode }) => [
56
66
  event,
@@ -58,87 +68,47 @@ export function boardHookEntries(execPath, cliEntry) {
58
68
  ]);
59
69
  }
60
70
  /**
61
- * Merge the board hooks into one already-parsed hooks.json object.
62
- *
63
- * Every prior entry of ours is dropped first, so a reinstall after an upgrade
64
- * replaces a stale bundle path instead of stacking a second registration.
65
- * Entries that are not ours are untouched: a profile carries the resume hint on
66
- * the same event.
71
+ * The events of the message hook's turn runs. SessionStart tells the session
72
+ * its own id; the prompt and the turn end deliver what already waits;
73
+ * SessionEnd marks the session ended so a parent stops waiting for it.
67
74
  */
68
- export function mergeBoardHooks(config, execPath, cliEntry) {
69
- if (!config.hooks || typeof config.hooks !== 'object')
70
- config.hooks = {};
71
- const entries = boardHookEntries(execPath, cliEntry);
72
- for (const { event } of BOARD_HOOKS) {
73
- const current = Array.isArray(config.hooks[event]) ? config.hooks[event] : [];
74
- const kept = current.filter((h) => !isBoardHookEntry(h));
75
- for (const [ev, entry] of entries)
76
- if (ev === event)
77
- kept.push(entry);
78
- config.hooks[event] = kept;
79
- }
75
+ export const MESSAGE_HOOK_EVENTS = ['SessionStart', 'UserPromptSubmit', 'Stop', 'SessionEnd'];
76
+ /**
77
+ * The events that start the waiter. It runs in the background (asyncRewake)
78
+ * until a message arrives, then exits 2 and Claude Code wakes the session; the
79
+ * turn that follows ends in a Stop, which starts the next waiter.
80
+ */
81
+ export const MESSAGE_WAITER_EVENTS = ['SessionStart', 'UserPromptSubmit', 'Stop'];
82
+ /** The command Claude Code runs for the message hook. Both paths quoted, as above. */
83
+ export function messageHookCommand(execPath, hookEntry, waiter = false) {
84
+ return `"${execPath}" "${hookEntry}"${waiter ? ' --wait' : ''}`;
80
85
  }
81
- /** Drop the board hooks from one already-parsed hooks.json object. */
82
- export function removeBoardHooks(config) {
83
- if (!config.hooks)
84
- return 0;
85
- let removed = 0;
86
- for (const { event } of BOARD_HOOKS) {
87
- const current = Array.isArray(config.hooks[event]) ? config.hooks[event] : [];
88
- const kept = current.filter((h) => !isBoardHookEntry(h));
89
- removed += current.length - kept.length;
90
- if (kept.length)
91
- config.hooks[event] = kept;
92
- else
93
- delete config.hooks[event];
94
- }
95
- return removed;
86
+ /** True when this hook entry is the message hook, its turn run or its waiter. */
87
+ export function isMessageHookEntry(entry) {
88
+ const cmd = entryCommand(entry);
89
+ return cmd !== null && /message-hook\.(js|ts)"?( --wait)?$/.test(cmd.trim());
96
90
  }
97
- /** Read a hooks.json, tolerating an absent or unreadable file. */
98
- function readConfig(file) {
99
- if (!existsSync(file))
100
- return { hooks: {} };
101
- try {
102
- const parsed = JSON.parse(readFileSync(file, 'utf-8'));
103
- if (!parsed.hooks || typeof parsed.hooks !== 'object')
104
- parsed.hooks = {};
105
- return parsed;
106
- }
107
- catch {
108
- return { hooks: {} };
109
- }
91
+ /** True when this hook entry is the waiter. */
92
+ export function isMessageWaiterEntry(entry) {
93
+ return isMessageHookEntry(entry) && /--wait$/.test(entryCommand(entry).trim());
110
94
  }
111
- /**
112
- * Register the board hooks in every given hooks.json.
113
- *
114
- * Returns the files it wrote. A file it cannot parse is skipped rather than
115
- * overwritten: another tool's config is not ours to replace.
116
- */
117
- export function registerBoardHooks(files, execPath, cliEntry) {
118
- const written = [];
119
- for (const file of files) {
120
- if (existsSync(file)) {
121
- try {
122
- JSON.parse(readFileSync(file, 'utf-8'));
123
- }
124
- catch {
125
- continue;
126
- }
127
- }
128
- const config = readConfig(file);
129
- mergeBoardHooks(config, execPath, cliEntry);
130
- try {
131
- mkdirSync(dirname(file), { recursive: true });
132
- writeFileSync(file, JSON.stringify(config, null, 2) + '\n');
133
- written.push(file);
134
- }
135
- catch { /* a read-only profile directory is not a reason to fail setup */ }
136
- }
137
- return written;
95
+ /** The `[event, entry]` pairs for the message hook: the turn runs, then the waiters. */
96
+ export function messageHookEntries(execPath, hookEntry) {
97
+ const turn = messageHookCommand(execPath, hookEntry);
98
+ const waiter = messageHookCommand(execPath, hookEntry, true);
99
+ return [
100
+ ...MESSAGE_HOOK_EVENTS.map((event) => [event, { matcher: '', hooks: [{ type: 'command', command: turn }] }]),
101
+ ...MESSAGE_WAITER_EVENTS.map((event) => [event, { matcher: '', hooks: [{ type: 'command', command: waiter, asyncRewake: true }] }]),
102
+ ];
138
103
  }
139
104
  /** Resolve the CLI entry that a hook should run. */
140
105
  export function resolveCliEntry(distDir) {
141
106
  const bundled = join(distDir, 'cli.js');
142
107
  return existsSync(bundled) ? bundled : join(distDir, 'cli.ts');
143
108
  }
109
+ /** Resolve the message hook bundle that sits beside the CLI. */
110
+ export function resolveMessageHookEntry(distDir) {
111
+ const bundled = join(distDir, 'message-hook.js');
112
+ return existsSync(bundled) ? bundled : join(distDir, 'message-hook.ts');
113
+ }
144
114
  //# sourceMappingURL=board-hooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"board-hooks.js","sourceRoot":"","sources":["../src/board-hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"board-hooks.js","sourceRoot":"","sources":["../src/board-hooks.ts"],"names":[],"mappings":"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"}