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 +37 -10
- package/dist/board-hooks.d.ts +37 -27
- package/dist/board-hooks.d.ts.map +1 -1
- package/dist/board-hooks.js +50 -80
- package/dist/board-hooks.js.map +1 -1
- package/dist/cli.js +9001 -8996
- package/dist/cli.js.map +1 -1
- package/dist/install-hooks.d.ts +95 -0
- package/dist/install-hooks.d.ts.map +1 -0
- package/dist/install-hooks.js +352 -0
- package/dist/install-hooks.js.map +1 -0
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +1960 -924
- package/dist/mcp.js.map +1 -1
- package/dist/message-hook-core.d.ts +67 -0
- package/dist/message-hook-core.d.ts.map +1 -0
- package/dist/message-hook-core.js +77 -0
- package/dist/message-hook-core.js.map +1 -0
- package/dist/message-hook.d.ts +2 -0
- package/dist/message-hook.d.ts.map +1 -0
- package/dist/message-hook.js +423 -0
- package/dist/message-hook.js.map +1 -0
- package/dist/scan-worker.js +32 -24
- package/dist/service-installer.d.ts.map +1 -1
- package/dist/service-installer.js +7 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/watch.js +500 -483
- package/package.json +1 -1
- package/skills/chat-recall/SKILL.md +6 -1
- package/skills/chat-recall-sessions/SKILL.md +155 -0
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 **
|
|
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.**
|
|
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
|
-
|
|
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
|
|
223
|
-
chat-recall install-hooks --no-
|
|
224
|
-
chat-recall install-hooks --
|
|
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
|
|
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/
|
|
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` |
|
package/dist/board-hooks.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
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
|
|
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
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
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
|
|
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":"
|
|
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"}
|
package/dist/board-hooks.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
|
|
20
|
-
import {
|
|
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
|
|
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
|
|
47
|
-
if (
|
|
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
|
|
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
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
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
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
/**
|
|
82
|
-
export function
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
/**
|
|
98
|
-
function
|
|
99
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
package/dist/board-hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"board-hooks.js","sourceRoot":"","sources":["../src/board-hooks.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"board-hooks.js","sourceRoot":"","sources":["../src/board-hooks.ts"],"names":[],"mappings":"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"}
|