@redpop/apple-mail-mcp 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +247 -2
- package/SECURITY.md +102 -0
- package/bin/Mail MCP Helper.app/Contents/CodeResources +0 -0
- package/bin/Mail MCP Helper.app/Contents/Info.plist +26 -0
- package/bin/Mail MCP Helper.app/Contents/MacOS/mail-helper +0 -0
- package/bin/Mail MCP Helper.app/Contents/Resources/AppIcon.icns +0 -0
- package/bin/Mail MCP Helper.app/Contents/_CodeSignature/CodeResources +128 -0
- package/dist/bodyScan.js +259 -0
- package/dist/bodyScan.js.map +1 -0
- package/dist/cli/doctor.js +242 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/main.js +59 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/setup.js +107 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/context.js +43 -0
- package/dist/context.js.map +1 -0
- package/dist/cursor.js +39 -0
- package/dist/cursor.js.map +1 -0
- package/dist/dates.js +44 -0
- package/dist/dates.js.map +1 -0
- package/dist/errors.js +56 -0
- package/dist/errors.js.map +1 -0
- package/dist/fdaPrompt.js +29 -0
- package/dist/fdaPrompt.js.map +1 -0
- package/dist/fold.js +8 -0
- package/dist/fold.js.map +1 -0
- package/dist/helper.js +45 -0
- package/dist/helper.js.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/links.js +9 -0
- package/dist/links.js.map +1 -0
- package/dist/mailboxes.js +124 -0
- package/dist/mailboxes.js.map +1 -0
- package/dist/mime.js +151 -0
- package/dist/mime.js.map +1 -0
- package/dist/mimeTrim.js +222 -0
- package/dist/mimeTrim.js.map +1 -0
- package/dist/policy.js +84 -0
- package/dist/policy.js.map +1 -0
- package/dist/quickHtml.js +238 -0
- package/dist/quickHtml.js.map +1 -0
- package/dist/quotes.js +72 -0
- package/dist/quotes.js.map +1 -0
- package/dist/schemas.js +57 -0
- package/dist/schemas.js.map +1 -0
- package/dist/securityMail.data.js +34 -0
- package/dist/securityMail.data.js.map +1 -0
- package/dist/securityMail.js +82 -0
- package/dist/securityMail.js.map +1 -0
- package/dist/server.js +19 -0
- package/dist/server.js.map +1 -0
- package/dist/signing.js +64 -0
- package/dist/signing.js.map +1 -0
- package/dist/state.js +46 -0
- package/dist/state.js.map +1 -0
- package/dist/stdioRunner.js +206 -0
- package/dist/stdioRunner.js.map +1 -0
- package/dist/summary.js +57 -0
- package/dist/summary.js.map +1 -0
- package/dist/tools/getMessage.js +112 -0
- package/dist/tools/getMessage.js.map +1 -0
- package/dist/tools/getThread.js +52 -0
- package/dist/tools/getThread.js.map +1 -0
- package/dist/tools/index.js +11 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/listMailboxes.js +50 -0
- package/dist/tools/listMailboxes.js.map +1 -0
- package/dist/tools/respond.js +34 -0
- package/dist/tools/respond.js.map +1 -0
- package/dist/tools/searchMessages.js +159 -0
- package/dist/tools/searchMessages.js.map +1 -0
- package/package.json +60 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"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"}
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { formatLocal } from './dates.js';
|
|
5
|
+
export function defaultStateDir() {
|
|
6
|
+
return join(homedir(), 'Library', 'Application Support', 'apple-mail-mcp');
|
|
7
|
+
}
|
|
8
|
+
const MIN_INTERVAL_MS = 60_000;
|
|
9
|
+
// Letzter Schreibzeitpunkt je Verzeichnis, damit pro Minute hoechstens einmal geschrieben wird.
|
|
10
|
+
const lastWrite = new Map();
|
|
11
|
+
export function readState(dir = defaultStateDir()) {
|
|
12
|
+
try {
|
|
13
|
+
const o = JSON.parse(readFileSync(join(dir, 'state.json'), 'utf8'));
|
|
14
|
+
if (typeof o.lastAccessOk !== 'string')
|
|
15
|
+
return null;
|
|
16
|
+
return {
|
|
17
|
+
lastAccessOk: o.lastAccessOk,
|
|
18
|
+
helperSha256: typeof o.helperSha256 === 'string' ? o.helperSha256 : null,
|
|
19
|
+
helperVersion: typeof o.helperVersion === 'string' ? o.helperVersion : null,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Haelt fest, dass der Zugriff geklappt hat (Spec 12.3). Wirft nie; enthaelt keine Mail-Daten. */
|
|
27
|
+
export function recordAccessOk(info, dir = defaultStateDir(), now = Date.now) {
|
|
28
|
+
const t = now();
|
|
29
|
+
const prev = lastWrite.get(dir);
|
|
30
|
+
if (prev !== undefined && t - prev < MIN_INTERVAL_MS)
|
|
31
|
+
return;
|
|
32
|
+
lastWrite.set(dir, t);
|
|
33
|
+
try {
|
|
34
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
35
|
+
const file = join(dir, 'state.json');
|
|
36
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
37
|
+
const body = { lastAccessOk: formatLocal(Math.floor(t / 1000)), helperSha256: info.helperSha256, helperVersion: info.helperVersion };
|
|
38
|
+
writeFileSync(tmp, JSON.stringify(body), { mode: 0o600 });
|
|
39
|
+
chmodSync(tmp, 0o600);
|
|
40
|
+
renameSync(tmp, file);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Zustandsdatei ist nur eine Hilfe; ein Schreibfehler darf keinen Tool-Aufruf stoeren.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACvF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAWxC,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,gBAAgB,CAAC,CAAA;AAC5E,CAAC;AAED,MAAM,eAAe,GAAG,MAAM,CAAA;AAC9B,gGAAgG;AAChG,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAA;AAE3C,MAAM,UAAU,SAAS,CAAC,GAAG,GAAW,eAAe,EAAE;IACvD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAA;QAC9F,IAAI,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAA;QACnD,OAAO;YACL,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,YAAY,EAAE,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI;YACxE,aAAa,EAAE,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI;SAC5E,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,cAAc,CAAC,IAAgB,EAAE,GAAG,GAAW,eAAe,EAAE,EAAE,GAAG,GAAiB,IAAI,CAAC,GAAG;IAC5G,MAAM,CAAC,GAAG,GAAG,EAAE,CAAA;IACf,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC/B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,GAAG,IAAI,GAAG,eAAe;QAAE,OAAM;IAC5D,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IACrB,IAAI,CAAC;QACH,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;QACpC,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAA;QACxC,MAAM,IAAI,GAAU,EAAE,YAAY,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAA;QAC3I,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QACzD,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACrB,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,uFAAuF;IACzF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { HelperError } from './errors.js';
|
|
4
|
+
import { helloResult } from './schemas.js';
|
|
5
|
+
/** Protokollversion, die dieser Node-Teil spricht (Spec 7.3 hello). */
|
|
6
|
+
export const PROTOCOL_VERSION = 1;
|
|
7
|
+
/** Laengste erlaubte Antwortzeile (Spec 7.1). */
|
|
8
|
+
export const MAX_LINE_BYTES = 32 * 1024 * 1024;
|
|
9
|
+
export const DEFAULT_TIMEOUTS = { firstRequestMs: 15_000, requestMs: 10_000 };
|
|
10
|
+
/**
|
|
11
|
+
* Haelt `mail-helper serve` als langlebigen Kindprozess und spricht NDJSON ueber
|
|
12
|
+
* stdin/stdout. Nach jedem Start geht zuerst `hello` raus; passt die Protokollversion
|
|
13
|
+
* nicht, wird der Prozess verworfen und alles Offene mit HELPER_VERSION_MISMATCH abgelehnt.
|
|
14
|
+
* Der Helper arbeitet sequenziell; die id macht eine Desynchronisation laut statt still.
|
|
15
|
+
*/
|
|
16
|
+
export function createStdioRunner(executable, timeouts = DEFAULT_TIMEOUTS, options = {}) {
|
|
17
|
+
const log = options.log ?? ((line) => void process.stderr.write(line + '\n'));
|
|
18
|
+
let live;
|
|
19
|
+
/** Teile der noch unvollstaendigen Antwortzeile; gesucht wird nur im jeweils neuen Teil (linear statt quadratisch). */
|
|
20
|
+
let chunks = [];
|
|
21
|
+
let chunkChars = 0;
|
|
22
|
+
let nextId = 1;
|
|
23
|
+
let helperVersion = null;
|
|
24
|
+
/** Hat der aktuelle Prozess schon eine echte Anfrage beantwortet (hello zaehlt nicht)? Steuert die Frist. */
|
|
25
|
+
let isWarm = false;
|
|
26
|
+
/**
|
|
27
|
+
* Timeouts in Folge auf echten Anfragen (nach erfolgreichem hello), unabhaengig von isWarm; zwei davon
|
|
28
|
+
* heissen: haengt, neu starten. Sonst bliebe ein Helper, der hello beantwortet und danach haengt, fuer immer.
|
|
29
|
+
*/
|
|
30
|
+
let consecutiveTimeouts = 0;
|
|
31
|
+
const MAX_CONSECUTIVE_TIMEOUTS = 2;
|
|
32
|
+
const pending = [];
|
|
33
|
+
function rejectAllPending(error) {
|
|
34
|
+
while (pending.length > 0) {
|
|
35
|
+
const entry = pending.shift();
|
|
36
|
+
if (entry === undefined)
|
|
37
|
+
continue;
|
|
38
|
+
clearTimeout(entry.timer);
|
|
39
|
+
entry.reject(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Verwirft den Prozess; der naechste Aufruf startet von selbst einen frischen. */
|
|
43
|
+
function discardChild(error) {
|
|
44
|
+
const previous = live?.proc;
|
|
45
|
+
live = undefined;
|
|
46
|
+
chunks = [];
|
|
47
|
+
chunkChars = 0;
|
|
48
|
+
isWarm = false;
|
|
49
|
+
consecutiveTimeouts = 0;
|
|
50
|
+
rejectAllPending(error);
|
|
51
|
+
if (previous !== undefined) {
|
|
52
|
+
previous.removeAllListeners();
|
|
53
|
+
previous.stdout?.removeAllListeners();
|
|
54
|
+
previous.stdin?.end();
|
|
55
|
+
previous.kill();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function handleLine(line) {
|
|
59
|
+
let parsed;
|
|
60
|
+
try {
|
|
61
|
+
parsed = JSON.parse(line);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Unlesbare Zeile: die Leitung ist nicht mehr vertrauenswuerdig, also alles ablehnen und neu anfangen.
|
|
65
|
+
discardChild(new HelperError('HELPER_CRASHED', 'Unreadable response from the helper.'));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Ohne numerische id laesst sich die Antwort keiner Anfrage sicher zuordnen (der Helper hat eine
|
|
69
|
+
// Anfrage nicht lesen koennen). Kein Raten: die Leitung gilt als verloren, alles Offene scheitert laut.
|
|
70
|
+
if (typeof parsed.id !== 'number') {
|
|
71
|
+
discardChild(new HelperError('HELPER_CRASHED', 'The helper sent a response without a request id.'));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const index = pending.findIndex((entry) => entry.id === parsed.id);
|
|
75
|
+
if (index === -1)
|
|
76
|
+
return; // Antwort auf etwas, das nicht mehr offen ist (z. B. nach Timeout).
|
|
77
|
+
const entry = pending.splice(index, 1)[0];
|
|
78
|
+
if (entry === undefined)
|
|
79
|
+
return;
|
|
80
|
+
clearTimeout(entry.timer);
|
|
81
|
+
// Nur eine echte Anfrage macht den Helper warm; hello oeffnet die Datenbank nie (Spec 7.2).
|
|
82
|
+
if (!entry.isHello)
|
|
83
|
+
isWarm = true;
|
|
84
|
+
consecutiveTimeouts = 0;
|
|
85
|
+
if (parsed.ok === true) {
|
|
86
|
+
entry.resolve(parsed.result);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
entry.reject(new HelperError(parsed.error?.code ?? 'HELPER_CRASHED', parsed.error?.message ?? 'Unknown error'));
|
|
90
|
+
}
|
|
91
|
+
function onData(chunk) {
|
|
92
|
+
let rest = chunk;
|
|
93
|
+
let newlineIndex = rest.indexOf('\n');
|
|
94
|
+
while (newlineIndex !== -1) {
|
|
95
|
+
chunks.push(rest.slice(0, newlineIndex));
|
|
96
|
+
const line = chunks.join('');
|
|
97
|
+
chunks = [];
|
|
98
|
+
chunkChars = 0;
|
|
99
|
+
rest = rest.slice(newlineIndex + 1);
|
|
100
|
+
if (Buffer.byteLength(line, 'utf8') > MAX_LINE_BYTES) {
|
|
101
|
+
discardChild(new HelperError('HELPER_CRASHED', 'response too large'));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const trimmed = line.trim();
|
|
105
|
+
if (trimmed.length > 0) {
|
|
106
|
+
const before = live;
|
|
107
|
+
handleLine(trimmed);
|
|
108
|
+
if (live !== before)
|
|
109
|
+
return; // handleLine hat den Prozess verworfen.
|
|
110
|
+
}
|
|
111
|
+
newlineIndex = rest.indexOf('\n');
|
|
112
|
+
}
|
|
113
|
+
if (rest.length > 0) {
|
|
114
|
+
chunks.push(rest);
|
|
115
|
+
chunkChars += rest.length;
|
|
116
|
+
}
|
|
117
|
+
// Zeichen sind hoechstens so gross wie Bytes: diese Schranke greift sicher, nie zu frueh.
|
|
118
|
+
if (chunkChars > MAX_LINE_BYTES)
|
|
119
|
+
discardChild(new HelperError('HELPER_CRASHED', 'response too large'));
|
|
120
|
+
}
|
|
121
|
+
/** Schickt eine Anfrage an den aktuellen Prozess und setzt die Frist. */
|
|
122
|
+
function send(proc, command, payload, timeoutMs, isHello) {
|
|
123
|
+
const request = new Promise((resolve, reject) => {
|
|
124
|
+
const id = nextId++;
|
|
125
|
+
const entry = {
|
|
126
|
+
id,
|
|
127
|
+
isHello,
|
|
128
|
+
resolve,
|
|
129
|
+
reject,
|
|
130
|
+
timer: setTimeout(() => {
|
|
131
|
+
const index = pending.findIndex((candidate) => candidate.id === id);
|
|
132
|
+
if (index !== -1)
|
|
133
|
+
pending.splice(index, 1);
|
|
134
|
+
const timeout = new HelperError('HELPER_TIMEOUT', `No response from the helper within ${String(timeoutMs)}ms.`);
|
|
135
|
+
if (isHello) {
|
|
136
|
+
discardChild(timeout);
|
|
137
|
+
reject(timeout); // Der Eintrag ist schon aus pending entfernt; ohne dies bliebe ready offen.
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
consecutiveTimeouts += 1;
|
|
141
|
+
if (consecutiveTimeouts >= MAX_CONSECUTIVE_TIMEOUTS) {
|
|
142
|
+
discardChild(new HelperError('HELPER_TIMEOUT', 'The helper stopped responding and was restarted.'));
|
|
143
|
+
}
|
|
144
|
+
reject(timeout);
|
|
145
|
+
}, timeoutMs),
|
|
146
|
+
};
|
|
147
|
+
pending.push(entry);
|
|
148
|
+
proc.stdin?.write(`${JSON.stringify({ id, command, payload })}\n`);
|
|
149
|
+
});
|
|
150
|
+
if (!options.debug)
|
|
151
|
+
return request;
|
|
152
|
+
// Diagnose (APPLE_MAIL_MCP_DEBUG): nur Kommando, Dauer und Code, nie Payload oder Ergebnis.
|
|
153
|
+
const started = performance.now();
|
|
154
|
+
const done = (outcome) => log(`apple-mail-mcp: ${command} ${Math.round(performance.now() - started)} ms ${outcome}`);
|
|
155
|
+
request.then(() => done('ok'), (error) => done(error instanceof HelperError ? error.code : 'error'));
|
|
156
|
+
return request;
|
|
157
|
+
}
|
|
158
|
+
function ensureChild() {
|
|
159
|
+
if (live !== undefined)
|
|
160
|
+
return live;
|
|
161
|
+
// stderr geht unveraendert an den Elternprozess (Diagnose des Helpers).
|
|
162
|
+
const proc = spawn(executable, ['serve'], { stdio: ['pipe', 'pipe', 'inherit'] });
|
|
163
|
+
isWarm = false;
|
|
164
|
+
chunks = [];
|
|
165
|
+
chunkChars = 0;
|
|
166
|
+
proc.stdout?.setEncoding('utf8');
|
|
167
|
+
proc.stdout?.on('data', onData);
|
|
168
|
+
// EPIPE auf stdin darf den Server nicht mitreissen; 'exit' entscheidet ueber Offenes.
|
|
169
|
+
proc.stdin?.on('error', () => { });
|
|
170
|
+
proc.on('error', (error) => {
|
|
171
|
+
discardChild(new HelperError(error.code === 'ENOENT' ? 'HELPER_MISSING' : 'HELPER_CRASHED', error.message));
|
|
172
|
+
});
|
|
173
|
+
proc.on('exit', (code, signal) => {
|
|
174
|
+
const reason = signal !== null ? `signal ${signal}` : `exit code ${String(code)}`;
|
|
175
|
+
discardChild(new HelperError('HELPER_CRASHED', `The helper exited (${reason}).`));
|
|
176
|
+
});
|
|
177
|
+
const ready = send(proc, 'hello', {}, timeouts.firstRequestMs, true).then((result) => {
|
|
178
|
+
const hello = helloResult.safeParse(result);
|
|
179
|
+
if (!hello.success || hello.data.protocolVersion !== PROTOCOL_VERSION) {
|
|
180
|
+
const error = new HelperError('HELPER_VERSION_MISMATCH', 'The helper speaks a different protocol version.');
|
|
181
|
+
discardChild(error);
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
helperVersion = hello.data.helperVersion;
|
|
185
|
+
});
|
|
186
|
+
ready.catch(() => { }); // Fehler erreichen den Aufrufer ueber run(); hier nur unbehandelte Rejection vermeiden.
|
|
187
|
+
live = { proc, ready };
|
|
188
|
+
return live;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
async run(command, payload) {
|
|
192
|
+
if (!existsSync(executable))
|
|
193
|
+
throw new HelperError('HELPER_MISSING', executable);
|
|
194
|
+
const current = ensureChild();
|
|
195
|
+
await current.ready;
|
|
196
|
+
if (live !== current)
|
|
197
|
+
throw new HelperError('HELPER_CRASHED', 'The helper stopped before the request could be sent.');
|
|
198
|
+
return send(current.proc, command, payload, isWarm ? timeouts.requestMs : timeouts.firstRequestMs, false);
|
|
199
|
+
},
|
|
200
|
+
stop() {
|
|
201
|
+
discardChild(new HelperError('HELPER_CRASHED', 'The helper was shut down.'));
|
|
202
|
+
},
|
|
203
|
+
helperVersion: () => helperVersion,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=stdioRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdioRunner.js","sourceRoot":"","sources":["../src/stdioRunner.ts"],"names":[],"mappings":"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"}
|
package/dist/summary.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { formatLocal } from './dates.js';
|
|
3
|
+
import { messageLink } from './links.js';
|
|
4
|
+
import { classify, redactSubject } from './securityMail.js';
|
|
5
|
+
const Address = z.object({ address: z.string(), name: z.string().nullable() });
|
|
6
|
+
const MailboxRef = z.object({ id: z.string(), name: z.string(), account: z.string() });
|
|
7
|
+
export const MessageSummary = z.object({
|
|
8
|
+
id: z.string(),
|
|
9
|
+
link: z.string().nullable(),
|
|
10
|
+
subject: z.string(),
|
|
11
|
+
subjectRedacted: z.boolean().optional(),
|
|
12
|
+
from: Address.nullable(),
|
|
13
|
+
to: z.array(Address),
|
|
14
|
+
cc: z.array(Address),
|
|
15
|
+
recipientCount: z.number().int(),
|
|
16
|
+
date: z.string(),
|
|
17
|
+
mailboxes: z.array(MailboxRef),
|
|
18
|
+
unread: z.boolean(),
|
|
19
|
+
flagged: z.boolean(),
|
|
20
|
+
attachmentNames: z.array(z.string()),
|
|
21
|
+
attachmentCount: z.number().int(),
|
|
22
|
+
threadId: z.string().nullable(),
|
|
23
|
+
bodyLocal: z.enum(['full', 'partial', 'none']),
|
|
24
|
+
matchContext: z.string().optional(),
|
|
25
|
+
});
|
|
26
|
+
/** Standard fuer die Empfaengerzahl je Feld (entspricht dem Helper-Payload, Spec 7.3). */
|
|
27
|
+
export const DEFAULT_MAX_RECIPIENTS = 5;
|
|
28
|
+
export function toSummary(row, policy, config, maxRecipients = DEFAULT_MAX_RECIPIENTS) {
|
|
29
|
+
const from = row.sender === null || row.sender.address === '' ? null : { address: row.sender.address, name: row.sender.name };
|
|
30
|
+
const verdict = classify({ subject: row.subject, fromAddress: from?.address ?? null });
|
|
31
|
+
const redact = verdict.security && !config.showSecurityMails;
|
|
32
|
+
const pick = (type) => row.recipients.filter((r) => r.type === type).slice(0, maxRecipients).map((r) => ({ address: r.address, name: r.name }));
|
|
33
|
+
const accountName = new Map(policy.accounts.map((a) => [a.id, a.name]));
|
|
34
|
+
const mailboxes = row.mailboxIds.flatMap((id) => {
|
|
35
|
+
const mb = policy.mailboxes.get(id);
|
|
36
|
+
return mb ? [{ id: String(id), name: mb.name, account: accountName.get(mb.accountId) ?? mb.accountId }] : [];
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
id: String(row.gid),
|
|
40
|
+
link: messageLink(row.messageIdHeader),
|
|
41
|
+
subject: redact ? redactSubject(row.subject) : row.subject,
|
|
42
|
+
...(redact ? { subjectRedacted: true } : {}),
|
|
43
|
+
from,
|
|
44
|
+
to: pick('to'),
|
|
45
|
+
cc: pick('cc'),
|
|
46
|
+
recipientCount: row.recipientCount,
|
|
47
|
+
date: formatLocal(row.dateReceived),
|
|
48
|
+
mailboxes,
|
|
49
|
+
unread: !row.read,
|
|
50
|
+
flagged: row.flagged,
|
|
51
|
+
attachmentNames: row.attachmentNames,
|
|
52
|
+
attachmentCount: row.attachmentCount ?? row.attachmentNames.length,
|
|
53
|
+
threadId: row.conversationId ? String(row.conversationId) : null,
|
|
54
|
+
bodyLocal: row.file,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { HelperError } from '../errors.js';
|
|
3
|
+
import { formatLocal } from '../dates.js';
|
|
4
|
+
import { parseMessage, truncateText } from '../mime.js';
|
|
5
|
+
import { stripQuotes } from '../quotes.js';
|
|
6
|
+
import { getMessagesResult } from '../schemas.js';
|
|
7
|
+
import { classify, redactSubject } from '../securityMail.js';
|
|
8
|
+
import { MessageSummary, toSummary } from '../summary.js';
|
|
9
|
+
import { respond } from './respond.js';
|
|
10
|
+
const MAX_RECIPIENTS = 100;
|
|
11
|
+
const Input = z
|
|
12
|
+
.object({
|
|
13
|
+
id: z.string().regex(/^\d+$/),
|
|
14
|
+
maxChars: z.number().int().min(500).max(100_000).default(20_000),
|
|
15
|
+
stripQuoted: z.boolean().default(false),
|
|
16
|
+
})
|
|
17
|
+
.strict();
|
|
18
|
+
const Address = z.object({ address: z.string(), name: z.string().nullable() });
|
|
19
|
+
const Output = MessageSummary.omit({ matchContext: true }).extend({
|
|
20
|
+
replyTo: z.array(Address),
|
|
21
|
+
dateSent: z.string().nullable(),
|
|
22
|
+
body: z
|
|
23
|
+
.object({
|
|
24
|
+
text: z.string(),
|
|
25
|
+
format: z.enum(['plain', 'html']),
|
|
26
|
+
truncated: z.boolean(),
|
|
27
|
+
totalChars: z.number().int(),
|
|
28
|
+
quotedRemoved: z.boolean(),
|
|
29
|
+
})
|
|
30
|
+
.nullable(),
|
|
31
|
+
bodyAvailable: z.boolean(),
|
|
32
|
+
bodyUnavailableReason: z.enum(['not_downloaded', 'file_not_found', 'withheld_security', 'parse_failed']).nullable(),
|
|
33
|
+
attachments: z.array(z.object({ name: z.string(), downloaded: z.boolean() })),
|
|
34
|
+
note: z.string().optional(),
|
|
35
|
+
});
|
|
36
|
+
export function registerGetMessage(server, ctx) {
|
|
37
|
+
server.registerTool('get_message', {
|
|
38
|
+
description: 'Returns one message with its headers, attachment names and body text, as plain text with quoted replies optionally removed. Changes nothing.',
|
|
39
|
+
inputSchema: Input,
|
|
40
|
+
outputSchema: Output,
|
|
41
|
+
annotations: { title: 'Get message', readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
42
|
+
}, async (input) => respond(async () => {
|
|
43
|
+
const config = ctx.config();
|
|
44
|
+
const policy = await ctx.policy();
|
|
45
|
+
if (policy.allowedMailboxIds.length === 0)
|
|
46
|
+
throw new HelperError('MESSAGE_NOT_FOUND', '');
|
|
47
|
+
const gid = Number(input.id);
|
|
48
|
+
// Jenseits von 2^53 waere die Zahl gerundet und traefe womoeglich eine andere Mail: nie an den Helper.
|
|
49
|
+
if (!Number.isSafeInteger(gid))
|
|
50
|
+
throw new HelperError('MESSAGE_NOT_FOUND', '');
|
|
51
|
+
const raw = getMessagesResult.parse(await ctx.runner.run('get-messages', {
|
|
52
|
+
allowedMailboxIds: policy.allowedMailboxIds,
|
|
53
|
+
gids: [gid],
|
|
54
|
+
maxBytesPerMessage: 8 * 1024 * 1024,
|
|
55
|
+
maxBytesTotal: 16 * 1024 * 1024,
|
|
56
|
+
}));
|
|
57
|
+
const row = raw.messages.find((m) => m.gid === gid);
|
|
58
|
+
if (!row || raw.missing.includes(gid))
|
|
59
|
+
throw new HelperError('MESSAGE_NOT_FOUND', '');
|
|
60
|
+
const summary = toSummary(row, policy, config, MAX_RECIPIENTS);
|
|
61
|
+
const { matchContext: _m, ...base } = summary;
|
|
62
|
+
const exchange = row.mailboxIds.some((id) => policy.mailboxes.get(id)?.type === 'exchange');
|
|
63
|
+
const attachments = row.attachmentNames.map((name) => ({ name, downloaded: row.file === 'full' }));
|
|
64
|
+
const result = {
|
|
65
|
+
...base,
|
|
66
|
+
replyTo: [],
|
|
67
|
+
dateSent: row.dateSent === null ? null : formatLocal(row.dateSent),
|
|
68
|
+
body: null,
|
|
69
|
+
bodyAvailable: false,
|
|
70
|
+
bodyUnavailableReason: null,
|
|
71
|
+
attachments,
|
|
72
|
+
};
|
|
73
|
+
const unavailable = (reason, extra = {}) => ({ structured: Output.parse({ ...result, bodyUnavailableReason: reason, ...extra }) });
|
|
74
|
+
if (row.raw === null && exchange)
|
|
75
|
+
return unavailable('file_not_found');
|
|
76
|
+
if (row.file === 'none')
|
|
77
|
+
return unavailable('not_downloaded');
|
|
78
|
+
if (row.raw === null)
|
|
79
|
+
return unavailable('file_not_found');
|
|
80
|
+
const parsed = await parseMessage(Buffer.from(row.raw, 'base64'));
|
|
81
|
+
if (!parsed.ok)
|
|
82
|
+
return unavailable('parse_failed');
|
|
83
|
+
result.to = parsed.headers.to.slice(0, MAX_RECIPIENTS);
|
|
84
|
+
result.cc = parsed.headers.cc.slice(0, MAX_RECIPIENTS);
|
|
85
|
+
result.replyTo = parsed.headers.replyTo.slice(0, MAX_RECIPIENTS);
|
|
86
|
+
const verdict = classify({ subject: row.subject, fromAddress: summary.from?.address ?? null, text: parsed.text });
|
|
87
|
+
if (verdict.security && !config.showSecurityMails) {
|
|
88
|
+
return unavailable('withheld_security', {
|
|
89
|
+
subject: redactSubject(row.subject),
|
|
90
|
+
subjectRedacted: true,
|
|
91
|
+
note: 'The body of this message was withheld because it looks like a security message (code, password reset or sign-in). The configuration decides this; tool parameters cannot change it.',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
let text = parsed.text;
|
|
95
|
+
let quotedRemoved = false;
|
|
96
|
+
if (input.stripQuoted) {
|
|
97
|
+
const s = stripQuotes(text);
|
|
98
|
+
text = s.text;
|
|
99
|
+
quotedRemoved = s.removed;
|
|
100
|
+
}
|
|
101
|
+
const cut = truncateText(text, Math.min(input.maxChars, config.maxBodyChars));
|
|
102
|
+
return {
|
|
103
|
+
structured: Output.parse({
|
|
104
|
+
...result,
|
|
105
|
+
body: { text: cut.text, format: parsed.format, truncated: cut.truncated, totalChars: cut.totalChars, quotedRemoved },
|
|
106
|
+
bodyAvailable: true,
|
|
107
|
+
...(row.rawTruncated ? { note: 'The message file is larger than the read limit, so the body may end early.' } : {}),
|
|
108
|
+
}),
|
|
109
|
+
};
|
|
110
|
+
}, ctx));
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=getMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getMessage.js","sourceRoot":"","sources":["../../src/tools/getMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAA;AAE1B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,cAAc,GAAG,GAAG,CAAA;AAE1B,MAAM,KAAK,GAAG,CAAC;KACZ,MAAM,CAAC;IACN,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;IAC7B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAChE,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACxC,CAAC;KACD,MAAM,EAAE,CAAA;AAEX,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;AAE9E,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAChE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IACzB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,IAAI,EAAE,CAAC;SACJ,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;QACtB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;QAC5B,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;KAC3B,CAAC;SACD,QAAQ,EAAE;IACb,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;IAC1B,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE;IACnH,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC7E,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAA;AAEF,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,GAAgB;IACpE,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,WAAW,EAAE,8IAA8I;QAC3J,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;KACtG,EACD,KAAK,EAAE,KAAK,EAAE,EAAE,CACd,OAAO,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAA;QAC3B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAA;QACjC,IAAI,MAAM,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,WAAW,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;QACzF,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC5B,uGAAuG;QACvG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,WAAW,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;QAC9E,MAAM,GAAG,GAAG,iBAAiB,CAAC,KAAK,CACjC,MAAM,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE;YACnC,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;YAC3C,IAAI,EAAE,CAAC,GAAG,CAAC;YACX,kBAAkB,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;YACnC,aAAa,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;SAChC,CAAC,CACH,CAAA;QACD,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAA;QACnD,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,WAAW,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;QAErF,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,CAAA;QAC9D,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;QAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,KAAK,UAAU,CAAC,CAAA;QAC3F,MAAM,WAAW,GAAG,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAA;QAGlG,MAAM,MAAM,GAA4B;YACtC,GAAG,IAAI;YACP,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClE,IAAI,EAAE,IAAI;YACV,aAAa,EAAE,KAAK;YACpB,qBAAqB,EAAE,IAAI;YAC3B,WAAW;SACZ,CAAA;QACD,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,KAAK,GAA4B,EAAE,EAAE,EAAE,CAC1E,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,EAAE,qBAAqB,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;QAExF,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,IAAI,QAAQ;YAAE,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAA;QACtE,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAA;QAC7D,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI;YAAE,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAA;QAE1D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;QACjE,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,cAAc,CAAC,CAAA;QAElD,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAA;QACtD,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAA;QACtD,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAA;QAEhE,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;QACjH,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;YAClD,OAAO,WAAW,CAAC,mBAAmB,EAAE;gBACtC,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC;gBACnC,eAAe,EAAE,IAAI;gBACrB,IAAI,EAAE,qLAAqL;aAC5L,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;QACtB,IAAI,aAAa,GAAG,KAAK,CAAA;QACzB,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;YAC3B,IAAI,GAAG,CAAC,CAAC,IAAI,CAAA;YACb,aAAa,GAAG,CAAC,CAAC,OAAO,CAAA;QAC3B,CAAC;QACD,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;QAC7E,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC;gBACvB,GAAG,MAAM;gBACT,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,aAAa,EAAE;gBACpH,aAAa,EAAE,IAAI;gBACnB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,4EAA4E,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACpH,CAAC;SACH,CAAA;IACH,CAAC,EAAE,GAAG,CAAC,CACV,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { HelperError } from '../errors.js';
|
|
3
|
+
import { threadResult } from '../schemas.js';
|
|
4
|
+
import { MessageSummary, toSummary } from '../summary.js';
|
|
5
|
+
import { respond } from './respond.js';
|
|
6
|
+
const Input = z
|
|
7
|
+
.object({
|
|
8
|
+
id: z.string().regex(/^\d+$/),
|
|
9
|
+
limit: z.number().int().min(1).max(100).default(50),
|
|
10
|
+
})
|
|
11
|
+
.strict();
|
|
12
|
+
const Output = z.object({
|
|
13
|
+
threadId: z.string().nullable(),
|
|
14
|
+
messages: z.array(MessageSummary),
|
|
15
|
+
hasMore: z.boolean(),
|
|
16
|
+
note: z.string().optional(),
|
|
17
|
+
});
|
|
18
|
+
export function registerGetThread(server, ctx) {
|
|
19
|
+
server.registerTool('get_thread', {
|
|
20
|
+
description: 'Returns summaries of the messages in the conversation that contains the given message (up to the limit, oldest first), without bodies. Changes nothing.',
|
|
21
|
+
inputSchema: Input,
|
|
22
|
+
outputSchema: Output,
|
|
23
|
+
annotations: { title: 'Get thread', readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
24
|
+
}, async (input) => respond(async () => {
|
|
25
|
+
const config = ctx.config();
|
|
26
|
+
const policy = await ctx.policy();
|
|
27
|
+
if (policy.allowedMailboxIds.length === 0)
|
|
28
|
+
throw new HelperError('MESSAGE_NOT_FOUND', '');
|
|
29
|
+
const gid = Number(input.id);
|
|
30
|
+
// Jenseits von 2^53 waere die Zahl gerundet und traefe womoeglich eine andere Mail: nie an den Helper.
|
|
31
|
+
if (!Number.isSafeInteger(gid))
|
|
32
|
+
throw new HelperError('MESSAGE_NOT_FOUND', '');
|
|
33
|
+
const raw = threadResult.parse(await ctx.runner.run('thread', {
|
|
34
|
+
allowedMailboxIds: policy.allowedMailboxIds,
|
|
35
|
+
gid,
|
|
36
|
+
limit: input.limit,
|
|
37
|
+
maxRecipients: 5,
|
|
38
|
+
}));
|
|
39
|
+
const note = raw.hasMore
|
|
40
|
+
? `This thread has more messages than the limit. The oldest ${input.limit} messages are shown; use get_message on a listed id for details.`
|
|
41
|
+
: undefined;
|
|
42
|
+
return {
|
|
43
|
+
structured: Output.parse({
|
|
44
|
+
threadId: raw.conversationId ? String(raw.conversationId) : null,
|
|
45
|
+
messages: raw.messages.map((r) => toSummary(r, policy, config, 5)),
|
|
46
|
+
hasMore: raw.hasMore,
|
|
47
|
+
...(note ? { note } : {}),
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
}, ctx));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=getThread.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getThread.js","sourceRoot":"","sources":["../../src/tools/getThread.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { registerGetMessage } from './getMessage.js';
|
|
2
|
+
import { registerGetThread } from './getThread.js';
|
|
3
|
+
import { registerListMailboxes } from './listMailboxes.js';
|
|
4
|
+
import { registerSearchMessages } from './searchMessages.js';
|
|
5
|
+
export function registerTools(server, ctx) {
|
|
6
|
+
registerListMailboxes(server, ctx);
|
|
7
|
+
registerSearchMessages(server, ctx);
|
|
8
|
+
registerGetMessage(server, ctx);
|
|
9
|
+
registerGetThread(server, ctx);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,MAAM,UAAU,aAAa,CAAC,MAAiB,EAAE,GAAgB;IAC/D,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAClC,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/B,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAChC,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { respond } from './respond.js';
|
|
3
|
+
const Input = z.object({}).strict();
|
|
4
|
+
const Output = z.object({
|
|
5
|
+
accounts: z.array(z.object({
|
|
6
|
+
id: z.string(),
|
|
7
|
+
name: z.string(),
|
|
8
|
+
address: z.string().nullable(),
|
|
9
|
+
type: z.enum(['imap', 'local', 'exchange', 'other']),
|
|
10
|
+
mailboxes: z.array(z.object({
|
|
11
|
+
id: z.string(),
|
|
12
|
+
name: z.string(),
|
|
13
|
+
path: z.string(),
|
|
14
|
+
role: z.enum(['inbox', 'sent', 'drafts', 'archive', 'junk', 'trash', 'allmail', 'other']),
|
|
15
|
+
total: z.number().int(),
|
|
16
|
+
unread: z.number().int(),
|
|
17
|
+
})),
|
|
18
|
+
})),
|
|
19
|
+
note: z.string().optional(),
|
|
20
|
+
});
|
|
21
|
+
export function registerListMailboxes(server, ctx) {
|
|
22
|
+
server.registerTool('list_mailboxes', {
|
|
23
|
+
description: 'Lists the mail accounts and mailboxes that are visible under the current settings, with message counts. Changes nothing.',
|
|
24
|
+
inputSchema: Input,
|
|
25
|
+
outputSchema: Output,
|
|
26
|
+
annotations: { title: 'List mailboxes', readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
27
|
+
}, async () => respond(async () => {
|
|
28
|
+
const policy = await ctx.policy(true);
|
|
29
|
+
const accounts = policy.accounts.map((a) => ({
|
|
30
|
+
id: a.id,
|
|
31
|
+
name: a.name,
|
|
32
|
+
address: a.address,
|
|
33
|
+
type: a.type,
|
|
34
|
+
mailboxes: [...policy.mailboxes.values()]
|
|
35
|
+
.filter((m) => m.accountId === a.id)
|
|
36
|
+
.map((m) => ({
|
|
37
|
+
id: String(m.id),
|
|
38
|
+
name: m.name,
|
|
39
|
+
path: m.path.join('/'),
|
|
40
|
+
role: m.role,
|
|
41
|
+
total: m.total,
|
|
42
|
+
unread: m.unread,
|
|
43
|
+
})),
|
|
44
|
+
}));
|
|
45
|
+
const n = policy.unmatchedAllowlistEntries;
|
|
46
|
+
const note = n > 0 ? `${n} configured account${n === 1 ? '' : 's'} did not match any mail account.` : undefined;
|
|
47
|
+
return { structured: Output.parse({ accounts, ...(note ? { note } : {}) }) };
|
|
48
|
+
}, ctx));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=listMailboxes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listMailboxes.js","sourceRoot":"","sources":["../../src/tools/listMailboxes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { HelperError, describeError, fdaMessage } from '../errors.js';
|
|
2
|
+
// Freigabe pro Code, nicht pro Herkunft: nur diese Codes geben ihren Text als Detail an das Modell weiter.
|
|
3
|
+
// Node verfasst sie selbst (dates.ts, cursor.ts, context.ts); INVALID_INPUT kommt auch vom Helper, dort aber
|
|
4
|
+
// nur mit festen Texten ohne Pfade oder Mail-Daten ("Invalid value for <feld>."). Ein neuer Helper-Text unter
|
|
5
|
+
// einem dieser Codes darf deshalb nie Pfade oder Nutzerdaten enthalten. Alle anderen Codes geben nur den festen Text.
|
|
6
|
+
const DETAIL_CODES = new Set(['INVALID_INPUT', 'INVALID_CURSOR', 'CONFIG_INVALID']);
|
|
7
|
+
/**
|
|
8
|
+
* Einzige Stelle, an der Fehler zu Antworten werden. Das Modell bekommt Klartext,
|
|
9
|
+
* niemals einen Stacktrace.
|
|
10
|
+
*
|
|
11
|
+
* Bewusst ohne `: Promise<ToolResult>`-Rueckgabetyp-Annotation: `ToolResult` hat keine
|
|
12
|
+
* Indexsignatur, das SDK-eigene `CallToolResult` aber schon; eine explizite Annotation
|
|
13
|
+
* macht die Rueckgabe nominell inkompatibel und laesst `registerTool` auf die veraltete
|
|
14
|
+
* Raw-Shape-Ueberladung zurueckfallen. `satisfies` prueft dieselbe Form ohne Festnageln.
|
|
15
|
+
*/
|
|
16
|
+
export async function respond(produce, ctx) {
|
|
17
|
+
try {
|
|
18
|
+
const { structured } = await produce();
|
|
19
|
+
return { content: [{ type: 'text', text: JSON.stringify(structured, null, 2) }], structuredContent: structured };
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
const openedNow = ctx.onHelperError(error);
|
|
23
|
+
let text;
|
|
24
|
+
if (error instanceof HelperError) {
|
|
25
|
+
text = error.code === 'FULL_DISK_ACCESS_REQUIRED' ? fdaMessage(ctx.bundlePath, openedNow, ctx.helperName) : describeError(error.code, DETAIL_CODES.has(error.code) ? error.message : undefined);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Keine Nutzerdaten und kein Stacktrace an das Modell.
|
|
29
|
+
text = describeError('UNKNOWN');
|
|
30
|
+
}
|
|
31
|
+
return { content: [{ type: 'text', text }], isError: true };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=respond.js.map
|