agenthub-multiagent-mcp 1.76.0 → 1.77.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.
@@ -10,17 +10,17 @@ import * as path from "node:path";
10
10
  import * as os from "node:os";
11
11
  const BEGIN_MARKER = "# BEGIN agenthub — managed by agenthub-setup, do not edit inside markers";
12
12
  const END_MARKER = "# END agenthub";
13
- const SHELL_INIT_CONTENT = `# Auto-generated by \`agenthub-setup install-shell\`. Do not edit.
14
- # Routes \`claude\` through tmux session \`agenthub-<agent_id>\` so the
15
- # browser terminal (agenthub-tunneld) can attach. See:
16
- # docs/plans/2026-04-21-browser-terminal-design.md D8.
17
- claude() {
18
- if [ -n "$TMUX" ] || [ ! -t 0 ]; then command claude "$@"; return; fi
19
- local AGENT
20
- AGENT=$(jq -r .agent_id "$HOME/.agenthub/config.json" 2>/dev/null)
21
- if [ -z "$AGENT" ] || [ "$AGENT" = "null" ]; then command claude "$@"; return; fi
22
- exec tmux new -A -s "agenthub-$AGENT" command claude "$@"
23
- }
13
+ const SHELL_INIT_CONTENT = `# Auto-generated by \`agenthub-setup install-shell\`. Do not edit.
14
+ # Routes \`claude\` through tmux session \`agenthub-<agent_id>\` so the
15
+ # browser terminal (agenthub-tunneld) can attach. See:
16
+ # docs/plans/2026-04-21-browser-terminal-design.md D8.
17
+ claude() {
18
+ if [ -n "$TMUX" ] || [ ! -t 0 ]; then command claude "$@"; return; fi
19
+ local AGENT
20
+ AGENT=$(jq -r .agent_id "$HOME/.agenthub/config.json" 2>/dev/null)
21
+ if [ -z "$AGENT" ] || [ "$AGENT" = "null" ]; then command claude "$@"; return; fi
22
+ exec tmux new -A -s "agenthub-$AGENT" command claude "$@"
23
+ }
24
24
  `;
25
25
  export function detectShell() {
26
26
  const shellPath = process.env.SHELL;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Which coding session is this agent's work being captured into, if any
3
+ * (add-session-report-numbers).
4
+ *
5
+ * `session_close_report` attaches the answer when its caller did not pass a
6
+ * `session_id`, so a report from a captured session links to that session and
7
+ * shows its `s-YYYYMMDD-NNN` beside the report's own `h-` number. Before this,
8
+ * the `/close-session` skill never passed one, so no report ever linked.
9
+ *
10
+ * Two places can know, mirroring the two capture paths in session-capture.sh:
11
+ *
12
+ * 1. A daemon shift: the daemon opens the session and stamps
13
+ * `AGENTHUB_SESSION_ID` into the shift's environment, which this MCP
14
+ * process inherits.
15
+ * 2. An interactive session whose owner consented: the capture hook resolves
16
+ * a session per Claude Code session id and caches it beside the grant file
17
+ * (`<dir of grant>/agenthub-capture-state/<claude session id>.json`). The
18
+ * Claude session id is read from the activity marker the PostToolUse hook
19
+ * writes.
20
+ *
21
+ * Anything else — no capture, consent refused, a missing or unreadable file —
22
+ * answers `undefined`, and the report is filed without a session, exactly as
23
+ * before. This never throws and never calls the network.
24
+ */
25
+ export interface CurrentCaptureSessionOptions {
26
+ env?: NodeJS.ProcessEnv;
27
+ workingDir?: string | null;
28
+ homeDir?: string;
29
+ }
30
+ export declare function currentCaptureSessionId(opts?: CurrentCaptureSessionOptions): string | undefined;
31
+ //# sourceMappingURL=currentCaptureSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currentCaptureSession.d.ts","sourceRoot":"","sources":["../src/currentCaptureSession.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,MAAM,WAAW,4BAA4B;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,uBAAuB,CAAC,IAAI,GAAE,4BAAiC,GAAG,MAAM,GAAG,SAAS,CA8BnG"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Which coding session is this agent's work being captured into, if any
3
+ * (add-session-report-numbers).
4
+ *
5
+ * `session_close_report` attaches the answer when its caller did not pass a
6
+ * `session_id`, so a report from a captured session links to that session and
7
+ * shows its `s-YYYYMMDD-NNN` beside the report's own `h-` number. Before this,
8
+ * the `/close-session` skill never passed one, so no report ever linked.
9
+ *
10
+ * Two places can know, mirroring the two capture paths in session-capture.sh:
11
+ *
12
+ * 1. A daemon shift: the daemon opens the session and stamps
13
+ * `AGENTHUB_SESSION_ID` into the shift's environment, which this MCP
14
+ * process inherits.
15
+ * 2. An interactive session whose owner consented: the capture hook resolves
16
+ * a session per Claude Code session id and caches it beside the grant file
17
+ * (`<dir of grant>/agenthub-capture-state/<claude session id>.json`). The
18
+ * Claude session id is read from the activity marker the PostToolUse hook
19
+ * writes.
20
+ *
21
+ * Anything else — no capture, consent refused, a missing or unreadable file —
22
+ * answers `undefined`, and the report is filed without a session, exactly as
23
+ * before. This never throws and never calls the network.
24
+ */
25
+ import * as fs from "fs";
26
+ import * as os from "os";
27
+ import * as path from "path";
28
+ import { readActivityMarker } from "./activityMarker.js";
29
+ export function currentCaptureSessionId(opts = {}) {
30
+ const env = opts.env ?? process.env;
31
+ const fromEnv = (env.AGENTHUB_SESSION_ID || "").trim();
32
+ if (fromEnv)
33
+ return fromEnv;
34
+ if (!opts.workingDir)
35
+ return undefined;
36
+ const claudeSessionId = readActivityMarker(opts.workingDir)?.session_id;
37
+ if (!claudeSessionId)
38
+ return undefined;
39
+ const grantPath = (env.AGENTHUB_CAPTURE_GRANT || "").trim() ||
40
+ path.join(opts.homeDir ?? os.homedir(), ".claude", "agenthub-capture.json");
41
+ // Same file name rule as session-capture.sh: os.sep replaced by "_".
42
+ const stateFile = path.join(path.dirname(grantPath), "agenthub-capture-state", claudeSessionId.split(path.sep).join("_") + ".json");
43
+ try {
44
+ const state = JSON.parse(fs.readFileSync(stateFile, "utf8"));
45
+ if (state.denied)
46
+ return undefined;
47
+ const id = typeof state.session_id === "string" ? state.session_id.trim() : "";
48
+ return id || undefined;
49
+ }
50
+ catch {
51
+ return undefined;
52
+ }
53
+ }
54
+ //# sourceMappingURL=currentCaptureSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currentCaptureSession.js","sourceRoot":"","sources":["../src/currentCaptureSession.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAQzD,MAAM,UAAU,uBAAuB,CAAC,OAAqC,EAAE;IAC7E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAEpC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACvD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,IAAI,CAAC,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IACvC,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxE,IAAI,CAAC,eAAe;QAAE,OAAO,SAAS,CAAC;IAEvC,MAAM,SAAS,GACb,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QACzC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,uBAAuB,CAAC,CAAC;IAC9E,qEAAqE;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CACzB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EACvB,wBAAwB,EACxB,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CACpD,CAAC;IACF,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAG1D,CAAC;QACF,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QACnC,MAAM,EAAE,GAAG,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,OAAO,EAAE,IAAI,SAAS,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=currentCaptureSession.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currentCaptureSession.test.d.ts","sourceRoot":"","sources":["../src/currentCaptureSession.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import * as fs from "fs";
3
+ import * as os from "os";
4
+ import * as path from "path";
5
+ import { currentCaptureSessionId } from "./currentCaptureSession.js";
6
+ import { writeActivityMarker } from "./activityMarker.js";
7
+ let tmp;
8
+ let work;
9
+ let grant;
10
+ beforeEach(() => {
11
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), "agenthub-capsess-"));
12
+ work = path.join(tmp, "work");
13
+ fs.mkdirSync(work);
14
+ grant = path.join(tmp, "claude", "agenthub-capture.json");
15
+ });
16
+ afterEach(() => {
17
+ fs.rmSync(tmp, { recursive: true, force: true });
18
+ });
19
+ function writeState(claudeSid, state) {
20
+ const dir = path.join(path.dirname(grant), "agenthub-capture-state");
21
+ fs.mkdirSync(dir, { recursive: true });
22
+ fs.writeFileSync(path.join(dir, `${claudeSid}.json`), JSON.stringify(state));
23
+ }
24
+ describe("currentCaptureSessionId", () => {
25
+ it("prefers AGENTHUB_SESSION_ID (a daemon shift)", () => {
26
+ writeActivityMarker(work, "editing", { session_id: "claude-1", transcript_path: "/t" });
27
+ writeState("claude-1", { session_id: "from-state" });
28
+ const env = { AGENTHUB_SESSION_ID: " shift-sess ", AGENTHUB_CAPTURE_GRANT: grant };
29
+ expect(currentCaptureSessionId({ env, workingDir: work })).toBe("shift-sess");
30
+ });
31
+ it("reads the capture hook's cached session for the current Claude session", () => {
32
+ writeActivityMarker(work, "editing", { session_id: "claude-1", transcript_path: "/t" });
33
+ writeState("claude-1", { session_id: "cs-uuid-1", notice_text: "x" });
34
+ expect(currentCaptureSessionId({ env: { AGENTHUB_CAPTURE_GRANT: grant }, workingDir: work })).toBe("cs-uuid-1");
35
+ });
36
+ it("answers nothing when capture was refused", () => {
37
+ writeActivityMarker(work, "editing", { session_id: "claude-1", transcript_path: "/t" });
38
+ writeState("claude-1", { denied: true, session_id: "stale" });
39
+ expect(currentCaptureSessionId({ env: { AGENTHUB_CAPTURE_GRANT: grant }, workingDir: work })).toBeUndefined();
40
+ });
41
+ it("answers nothing with no marker, no state file, or no working dir", () => {
42
+ expect(currentCaptureSessionId({ env: { AGENTHUB_CAPTURE_GRANT: grant }, workingDir: work })).toBeUndefined();
43
+ writeActivityMarker(work, "editing", { session_id: "claude-2", transcript_path: "/t" });
44
+ expect(currentCaptureSessionId({ env: { AGENTHUB_CAPTURE_GRANT: grant }, workingDir: work })).toBeUndefined();
45
+ expect(currentCaptureSessionId({ env: {}, workingDir: null })).toBeUndefined();
46
+ });
47
+ it("uses ~/.claude/agenthub-capture.json when no grant path is set", () => {
48
+ const home = path.join(tmp, "home");
49
+ grant = path.join(home, ".claude", "agenthub-capture.json");
50
+ writeActivityMarker(work, "editing", { session_id: "claude-3", transcript_path: "/t" });
51
+ writeState("claude-3", { session_id: "cs-home" });
52
+ expect(currentCaptureSessionId({ env: {}, workingDir: work, homeDir: home })).toBe("cs-home");
53
+ });
54
+ });
55
+ //# sourceMappingURL=currentCaptureSession.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currentCaptureSession.test.js","sourceRoot":"","sources":["../src/currentCaptureSession.test.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,27 @@ CONNECT_TOKEN=""
36
36
  PY=$(command -v python || command -v python3)
37
37
  [ -z "$PY" ] && exit 0
38
38
 
39
+ # --- WhatsApp: a session that read WhatsApp is never captured again ----------
40
+ #
41
+ # The AgentHub MCP writes an empty marker named for the Claude Code session id
42
+ # before its first call to the local WhatsApp reader
43
+ # (add-whatsapp-personal-reader §3.5). From then on this hook uploads nothing
44
+ # for that session, on either path below, so the owner's messages cannot reach
45
+ # the server through session capture.
46
+ WA_READ=$(echo "$INPUT" | "$PY" -c "
47
+ import sys, json, os
48
+ try:
49
+ sid = json.load(sys.stdin).get('session_id') or ''
50
+ except Exception:
51
+ sid = ''
52
+ if sid:
53
+ name = sid.replace(os.sep, '_').replace('/', '_')
54
+ marker = os.path.join(os.path.expanduser('~'), '.claude', 'agenthub-whatsapp-sessions', name)
55
+ if os.path.exists(marker):
56
+ print('1')
57
+ " 2>/dev/null)
58
+ [ "$WA_READ" = "1" ] && exit 0
59
+
39
60
  # --- Interactive (human) path: resolve a session id, consent permitting -------
40
61
  #
41
62
  # Emits four lines: session id, api url, connect token, and the notice JSON to
@@ -49,11 +49,12 @@ describe("session-capture.sh", () => {
49
49
  // runs. A drift between them means one caller silently gets old behaviour.
50
50
  expect(read(PACKAGE_COPY)).toBe(read(REPO_COPY));
51
51
  });
52
- it("embeds exactly the two Python blocks the script is built around", () => {
53
- // The interactive bootstrap (§3.2) and the event builder (§1.5). A third
54
- // would mean someone added a block that these guards have not been reviewed
55
- // against.
56
- expect(pythonBlocks(read(PACKAGE_COPY))).toHaveLength(2);
52
+ it("embeds exactly the three Python blocks the script is built around", () => {
53
+ // The WhatsApp marker check (add-whatsapp-personal-reader §3.5), the
54
+ // interactive bootstrap (§3.2) and the event builder (§1.5). A fourth
55
+ // would mean someone added a block that these guards have not been
56
+ // reviewed against.
57
+ expect(pythonBlocks(read(PACKAGE_COPY))).toHaveLength(3);
57
58
  });
58
59
  it("contains no backtick inside an embedded Python block", () => {
59
60
  // Bash runs backticks inside a double-quoted string as a command, even in
@@ -1 +1 @@
1
- {"version":3,"file":"sessionCaptureScript.test.js","sourceRoot":"","sources":["../src/sessionCaptureScript.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessionCaptureScript.test.js","sourceRoot":"","sources":["../src/sessionCaptureScript.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAqD,MAAM,cAAc,CAAC;AAOrG,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAkH/D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,MAAM,MAAM,CAAC;IAChC,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;OAGG;IACH,cAAc,EAAE,MAAM,WAAW,CAAC;IAClC,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,WAAW,CAAC;IACpC,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAC7B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,KAAK,IAAI,CAAC;CACZ;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAyLD,wBAAgB,aAAa,IAAI,IAAI,EAAE,CAohGtC;AAqCD,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,OAAO,CAAC,CAwyFlB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAqD,MAAM,cAAc,CAAC;AAOrG,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAoH/D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,MAAM,MAAM,CAAC;IAChC,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;OAGG;IACH,cAAc,EAAE,MAAM,WAAW,CAAC;IAClC,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,WAAW,CAAC;IACpC,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAC7B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,KAAK,IAAI,CAAC;CACZ;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAyLD,wBAAgB,aAAa,IAAI,IAAI,EAAE,CAwhGtC;AAqCD,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,OAAO,CAAC,CAyzFlB"}
@@ -16,6 +16,7 @@ import { handleEmployeeTrainingToolCall, isEmployeeTrainingTool, registerEmploye
16
16
  import { registerSessionControlTools, handleSessionControlToolCall, isSessionControlTool, } from "./sessionControl.js";
17
17
  import { registerGoshtiReadTools, handleGoshtiReadToolCall, isGoshtiReadTool, } from "./goshtiRead.js";
18
18
  import { registerRunTools, handleRunToolCall, isRunTool } from "./runs.js";
19
+ import { isWhatsAppTool, runWhatsAppTool, whatsappToolDefinitions } from "./whatsapp.js";
19
20
  import { installPackFromArchive } from "../skillPackInstaller.js";
20
21
  import { getServerTime, useTimeInjection } from "../lib/server-time.js";
21
22
  import { getPendingItems } from "../lib/pending-items.js";
@@ -26,6 +27,7 @@ import * as path from "node:path";
26
27
  import { describeSendResult } from "../messageIdempotency.js";
27
28
  import { readZohoAttachments } from "../zohoAttachments.js";
28
29
  import { isUnknownSendOutcome, unknownSendOutcomeError } from "../zohoSendOutcome.js";
30
+ import { currentCaptureSessionId } from "../currentCaptureSession.js";
29
31
  // fix-message-send-idempotency — shared by the four message tools.
30
32
  const IDEMPOTENCY_KEY_DESCRIPTION = "Optional. Leave unset: a key derived from the message content is sent, so " +
31
33
  "re-issuing this exact call (e.g. after a timeout) never delivers it twice. " +
@@ -2221,6 +2223,9 @@ export function registerTools() {
2221
2223
  ...registerEmployeeTrainingTools(),
2222
2224
  // Reading Goshti as the agent's owner (add-agent-goshti-read §3.1)
2223
2225
  ...registerGoshtiReadTools(),
2226
+ // Reading the owner's WhatsApp through the local reader on this PC
2227
+ // (add-whatsapp-personal-reader §3). Never touches the AgentHub server.
2228
+ ...whatsappToolDefinitions(),
2224
2229
  // Orchestrated runs for the dashboard Run view (add-live-animated-views §1.8)
2225
2230
  ...registerRunTools(),
2226
2231
  // OpenSpec Visualizer tools
@@ -2461,13 +2466,13 @@ export function registerTools() {
2461
2466
  // Session handoff tools (add-session-handoff)
2462
2467
  {
2463
2468
  name: "session_close_report",
2464
- description: "Upload a session-close handoff report to AgentHub. Call this at the end of every session after running the close-session skill. Shares what shipped + what the next session should pick up, so /start-session on the next run (any machine) can resume cleanly.",
2469
+ description: "Upload a session-close handoff report to AgentHub. Call this at the end of every session after running the close-session skill. Shares what shipped + what the next session should pick up, so /start-session on the next run (any machine) can resume cleanly. The reply carries `display_number` (the report's own `h-YYYYMMDD-NNN`, always) and `session_display_number` (the captured coding session's `s-YYYYMMDD-NNN`, only when this session is captured).",
2465
2470
  inputSchema: {
2466
2471
  type: "object",
2467
2472
  properties: {
2468
2473
  summary: { type: "string", description: "Markdown summary of what shipped this session" },
2469
2474
  next_plan: { type: "string", description: "Markdown of what the next session should pick up" },
2470
- session_id: { type: "string", description: "Optional session UUID or display number `s-YYYYMMDD-NNN` for upsert keying. Server resolves either form to the canonical UUID before storing." },
2475
+ session_id: { type: "string", description: "Optional session UUID or display number `s-YYYYMMDD-NNN` for upsert keying. Server resolves either form to the canonical UUID before storing. Omit it normally: when this session is being captured, the tool attaches the capture session itself." },
2471
2476
  commits: {
2472
2477
  type: "array",
2473
2478
  description: "Commits pushed this session",
@@ -3251,6 +3256,17 @@ export async function handleToolCall(name, args, client, context) {
3251
3256
  if (isGoshtiReadTool(name)) {
3252
3257
  return handleGoshtiReadToolCall(name, args, client);
3253
3258
  }
3259
+ // WhatsApp reads (add-whatsapp-personal-reader §3). Local only: no agent
3260
+ // registration needed, no server call, refused unless the session is private.
3261
+ if (isWhatsAppTool(name)) {
3262
+ const out = await runWhatsAppTool(name, args, {
3263
+ env: process.env,
3264
+ homeDir: os.homedir(),
3265
+ workingDir: context.getWorkingDir(),
3266
+ fetch: (url, init) => fetch(url, init),
3267
+ });
3268
+ return { content: [{ type: "text", text: JSON.stringify(out, null, 2) }] };
3269
+ }
3254
3270
  // Orchestrated runs (add-live-animated-views §1.8). Same module pattern. The
3255
3271
  // run id run_open returns is kept in .agenthub/state, so the other run tools
3256
3272
  // (and sub-agents sharing the checkout's state) default to it.
@@ -5348,8 +5364,12 @@ export async function handleToolCall(name, args, client, context) {
5348
5364
  summary,
5349
5365
  next_plan: nextPlan,
5350
5366
  };
5351
- if (args.session_id)
5352
- body.session_id = args.session_id;
5367
+ // add-session-report-numbers: a caller's session_id wins; otherwise link
5368
+ // the session this work is being captured into, when there is one.
5369
+ const sessionId = args.session_id ||
5370
+ currentCaptureSessionId({ workingDir: context.getWorkingDir() });
5371
+ if (sessionId)
5372
+ body.session_id = sessionId;
5353
5373
  if (args.commits)
5354
5374
  body.commits = args.commits;
5355
5375
  if (args.open_threads)