@rubytech/create-maxy 1.0.763 → 1.0.765

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.
Files changed (88) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/package-lock.json +56 -1
  3. package/payload/platform/package.json +1 -0
  4. package/payload/platform/plugins/docs/references/outlook-guide.md +69 -0
  5. package/payload/platform/plugins/docs/references/platform.md +1 -1
  6. package/payload/platform/plugins/outlook/PLUGIN.md +48 -0
  7. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.d.ts +2 -0
  8. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.d.ts.map +1 -0
  9. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js +94 -0
  10. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js.map +1 -0
  11. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.d.ts +2 -0
  12. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.d.ts.map +1 -0
  13. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.js +31 -0
  14. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.js.map +1 -0
  15. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.d.ts +2 -0
  16. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.d.ts.map +1 -0
  17. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js +213 -0
  18. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js.map +1 -0
  19. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.d.ts +2 -0
  20. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.d.ts.map +1 -0
  21. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js +130 -0
  22. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js.map +1 -0
  23. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts +65 -0
  24. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts.map +1 -0
  25. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js +261 -0
  26. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js.map +1 -0
  27. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts +61 -0
  28. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts.map +1 -0
  29. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js +170 -0
  30. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js.map +1 -0
  31. package/payload/platform/plugins/outlook/mcp/dist/index.d.ts +18 -0
  32. package/payload/platform/plugins/outlook/mcp/dist/index.d.ts.map +1 -0
  33. package/payload/platform/plugins/outlook/mcp/dist/index.js +152 -0
  34. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -0
  35. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +60 -0
  36. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -0
  37. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +189 -0
  38. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -0
  39. package/payload/platform/plugins/outlook/mcp/dist/lib/log.d.ts +23 -0
  40. package/payload/platform/plugins/outlook/mcp/dist/lib/log.d.ts.map +1 -0
  41. package/payload/platform/plugins/outlook/mcp/dist/lib/log.js +53 -0
  42. package/payload/platform/plugins/outlook/mcp/dist/lib/log.js.map +1 -0
  43. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +26 -0
  44. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts.map +1 -0
  45. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js +50 -0
  46. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -0
  47. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.d.ts +12 -0
  48. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.d.ts.map +1 -0
  49. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.js +32 -0
  50. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.js.map +1 -0
  51. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.d.ts +59 -0
  52. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.d.ts.map +1 -0
  53. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.js +54 -0
  54. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.js.map +1 -0
  55. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.d.ts +14 -0
  56. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.d.ts.map +1 -0
  57. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.js +45 -0
  58. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.js.map +1 -0
  59. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +15 -0
  60. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts.map +1 -0
  61. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js +48 -0
  62. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -0
  63. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts +8 -0
  64. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts.map +1 -0
  65. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js +49 -0
  66. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js.map +1 -0
  67. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts +19 -0
  68. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts.map +1 -0
  69. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js +58 -0
  70. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js.map +1 -0
  71. package/payload/platform/plugins/outlook/mcp/package.json +20 -0
  72. package/payload/platform/plugins/outlook/mcp/scripts/verify-doc-impl.sh +109 -0
  73. package/payload/platform/plugins/outlook/references/auth.md +118 -0
  74. package/payload/platform/plugins/outlook/references/graph-surfaces.md +114 -0
  75. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +65 -0
  76. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  77. package/payload/server/chunk-EIQT6QDH.js +9562 -0
  78. package/payload/server/chunk-IO2WQEY4.js +9562 -0
  79. package/payload/server/chunk-TKYZ7AEB.js +3142 -0
  80. package/payload/server/client-pool-CX2MFW75.js +28 -0
  81. package/payload/server/maxy-edge.js +2 -2
  82. package/payload/server/public/assets/{admin-V6NDkEoR.js → admin-g-Fjko8R.js} +5 -5
  83. package/payload/server/public/assets/{graph-BHcUKzXh.js → graph-DHBGJFDX.js} +1 -1
  84. package/payload/server/public/assets/page-BscgOyqp.js +50 -0
  85. package/payload/server/public/graph.html +2 -2
  86. package/payload/server/public/index.html +2 -2
  87. package/payload/server/server.js +146 -39
  88. package/payload/server/public/assets/page-DxH_Opxt.js +0 -50
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@maxy/outlook",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "start": "node dist/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@microsoft/microsoft-graph-client": "^3.0.7",
13
+ "@modelcontextprotocol/sdk": "^1.12.1",
14
+ "zod": "^3.24.0"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^22.0.0",
18
+ "typescript": "^5.7.0"
19
+ }
20
+ }
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env bash
2
+ # verify-doc-impl.sh
3
+ #
4
+ # Doc-impl alignment grep, promoted from Task 811's manual verification step
5
+ # to a permanent gate. Run from anywhere; resolves to the plugin tree itself.
6
+ #
7
+ # Verifies:
8
+ # 1. Every `outlook-*` tool name in `platform/plugins/docs/references/outlook-guide.md`
9
+ # resolves to a `server.tool("outlook-...", ...)` registration in mcp/src/index.ts.
10
+ # 2. Every `[outlook-mcp]` log-line shape in outlook-guide.md matches a
11
+ # log({event:"..."}) literal in mcp/src/.
12
+ # 3. Every tool name in `PLUGIN.md` frontmatter matches a registration in mcp/src/index.ts.
13
+ # 4. Public-agent isolation: `outlook` does not appear in public-agent assembly files.
14
+ # 5. Bearer-token redaction: log.ts contains the redaction regex pair.
15
+ #
16
+ # Exit non-zero on any mismatch. Print the first diverging item.
17
+
18
+ set -euo pipefail
19
+
20
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ PLUGIN_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
22
+ REPO_ROOT="$(cd "$PLUGIN_DIR/../../../.." && pwd)"
23
+ GUIDE="$REPO_ROOT/platform/plugins/docs/references/outlook-guide.md"
24
+ PLUGIN_MD="$REPO_ROOT/platform/plugins/outlook/PLUGIN.md"
25
+ INDEX_TS="$PLUGIN_DIR/src/index.ts"
26
+ SRC_DIR="$PLUGIN_DIR/src"
27
+
28
+ fail() {
29
+ echo "[verify-doc-impl] FAIL: $1" >&2
30
+ exit 1
31
+ }
32
+
33
+ [ -f "$GUIDE" ] || fail "operator guide missing: $GUIDE"
34
+ [ -f "$PLUGIN_MD" ] || fail "PLUGIN.md missing: $PLUGIN_MD"
35
+ [ -f "$INDEX_TS" ] || fail "index.ts missing: $INDEX_TS"
36
+
37
+ # Tool names registered in src/index.ts. The MCP-SDK call shape is:
38
+ # server.tool(
39
+ # "outlook-XYZ",
40
+ # ...
41
+ # so the tool name appears on its own line as ` "outlook-XYZ",`.
42
+ TOOLS_REGISTERED=$(grep -oE '"outlook-[a-z\-]+",' "$INDEX_TS" \
43
+ | sed -E 's/^"|",$//g' | sort -u)
44
+
45
+ # Tool names referenced in outlook-guide.md (backtick-wrapped)
46
+ TOOLS_IN_GUIDE=$(grep -oE '`outlook-[a-z\-]+`' "$GUIDE" | tr -d '`' | sort -u)
47
+
48
+ # Tool names in PLUGIN.md frontmatter (lines starting with " - outlook-")
49
+ TOOLS_IN_PLUGIN_MD=$(grep -E '^\s+- outlook-' "$PLUGIN_MD" | sed -E 's/^[[:space:]]*-[[:space:]]+//' | sort -u)
50
+
51
+ # Set 1: every tool in guide must be registered
52
+ while IFS= read -r tool; do
53
+ [ -z "$tool" ] && continue
54
+ if ! echo "$TOOLS_REGISTERED" | grep -qx "$tool"; then
55
+ fail "tool '$tool' referenced in outlook-guide.md but not registered in mcp/src/index.ts"
56
+ fi
57
+ done <<< "$TOOLS_IN_GUIDE"
58
+
59
+ # Set 2: every tool in PLUGIN.md frontmatter must be registered
60
+ while IFS= read -r tool; do
61
+ [ -z "$tool" ] && continue
62
+ if ! echo "$TOOLS_REGISTERED" | grep -qx "$tool"; then
63
+ fail "tool '$tool' declared in PLUGIN.md frontmatter but not registered in mcp/src/index.ts"
64
+ fi
65
+ done <<< "$TOOLS_IN_PLUGIN_MD"
66
+
67
+ # Set 3: every registered tool must appear in PLUGIN.md frontmatter
68
+ while IFS= read -r tool; do
69
+ [ -z "$tool" ] && continue
70
+ if ! echo "$TOOLS_IN_PLUGIN_MD" | grep -qx "$tool"; then
71
+ fail "tool '$tool' registered in mcp/src/index.ts but missing from PLUGIN.md frontmatter"
72
+ fi
73
+ done <<< "$TOOLS_REGISTERED"
74
+
75
+ # Log-shape alignment: every event tag in outlook-guide.md must have a matching
76
+ # log({ event: "..." }) literal in mcp/src/. Event tags appear in the table as:
77
+ # | Auth init | `auth-init account=<id> codeChallenge=...` |
78
+ # We pull the first word inside backticks on each table row that contains "account=".
79
+ EVENTS_IN_GUIDE=$(grep -E '`[a-z\-]+ account=' "$GUIDE" \
80
+ | sed -E 's/.*`([a-z\-]+) account=.*/\1/' | sort -u)
81
+ EVENTS_IN_SRC=$(grep -rh -oE 'event:[[:space:]]*"[a-z\-]+"' "$SRC_DIR" \
82
+ | sed -E 's/^event:[[:space:]]*"|"$//g' | sort -u)
83
+
84
+ while IFS= read -r ev; do
85
+ [ -z "$ev" ] && continue
86
+ if ! echo "$EVENTS_IN_SRC" | grep -qx "$ev"; then
87
+ fail "log event '$ev' documented in outlook-guide.md but no log({event:\"$ev\"}) literal in mcp/src/"
88
+ fi
89
+ done <<< "$EVENTS_IN_GUIDE"
90
+
91
+ # Public-agent isolation: outlook must not appear in public-agent assembly files.
92
+ ISOLATION_HITS=$( (cd "$REPO_ROOT" && grep -rE 'outlook' \
93
+ platform/ui/app/lib/claude-agent/public-agent.ts \
94
+ platform/ui/app/lib/claude-agent/system-prompt-assembly.ts \
95
+ platform/templates/agents/public/ 2>/dev/null) || true)
96
+ if [ -n "$ISOLATION_HITS" ]; then
97
+ echo "$ISOLATION_HITS" >&2
98
+ fail "isolation breach: 'outlook' string appears in public-agent assembly path"
99
+ fi
100
+
101
+ # Bearer redaction guard: lib/log.ts must contain both regex literals.
102
+ if ! grep -q 'Bearer\\s+\[A-Za-z0-9' "$SRC_DIR/lib/log.ts"; then
103
+ fail "Bearer redaction regex missing in lib/log.ts"
104
+ fi
105
+ if ! grep -q 'access_token=\[A-Za-z0-9' "$SRC_DIR/lib/log.ts"; then
106
+ fail "access_token redaction regex missing in lib/log.ts"
107
+ fi
108
+
109
+ echo "[verify-doc-impl] OK — $(echo "$TOOLS_REGISTERED" | wc -l | tr -d ' ') tools, $(echo "$EVENTS_IN_GUIDE" | wc -l | tr -d ' ') events, isolation, redaction all aligned"
@@ -0,0 +1,118 @@
1
+ # Outlook Auth Reference
2
+
3
+ ## Vendored upstream
4
+
5
+ The PKCE flow and encrypted token store are adapted from:
6
+
7
+ - **Repo:** [`nsakki55/outlook-mcp`](https://github.com/nsakki55/outlook-mcp)
8
+ - **Pinned commit:** `e49d8e68ac8d69db653c25803127dc3b98626cda`
9
+ - **License:** MIT
10
+
11
+ Adaptations:
12
+
13
+ - Per-account paths (`{ACCOUNTS_DIR}/{accountId}/secrets/outlook/`) instead of upstream's single-user `~/.outlook-mcp/`
14
+ - `keytar` fallback removed (Pi runs headless; no Secret Service)
15
+ - `node-persist` removed; single JSON blob written atomically (temp + rename)
16
+ - Loopback callback port is **ephemeral** via `server.listen(0)` (upstream uses fixed `49152`)
17
+ - No `xdg-open` browser auto-launch; auth URL is logged + returned to the operator for the VNC browser
18
+ - `outlook-account-register` awaits the full PKCE flow synchronously (5-min timeout)
19
+
20
+ To re-vendor at a newer SHA:
21
+
22
+ 1. Fetch `tokenManager.ts` and `authManager.ts` from the new SHA.
23
+ 2. Apply the adaptations above.
24
+ 3. Update the **Pinned commit** line above.
25
+ 4. Bump `@maxy/outlook` version.
26
+ 5. Run the test suite.
27
+
28
+ ## Entra app registration (one-time per Maxy install)
29
+
30
+ The plugin requires an Azure AD ("Entra ID") app the operator owns. Steps:
31
+
32
+ 1. Sign in to the [Azure portal](https://portal.azure.com) with a Microsoft account.
33
+ 2. Go to **Microsoft Entra ID → App registrations → New registration**.
34
+ 3. **Name:** `Maxy Outlook` (or any name the operator prefers).
35
+ 4. **Supported account types:** *Accounts in any organizational directory and personal Microsoft accounts*.
36
+ 5. **Redirect URI** (Platform: *Mobile and desktop applications*): `http://localhost`
37
+ - **Note:** no port is specified. Microsoft Identity Platform treats native-app loopback redirects with port-flexible matching, allowing the plugin to use an ephemeral port.
38
+ 6. Click **Register**. Copy the **Application (client) ID** — this is `OUTLOOK_CLIENT_ID`.
39
+ 7. Go to **API permissions → Add a permission → Microsoft Graph → Delegated permissions**, add:
40
+ - `offline_access`
41
+ - `User.Read`
42
+ - `Mail.Read`
43
+ - `Calendars.Read`
44
+ - `Contacts.Read`
45
+ 8. Click **Grant admin consent for <tenant>** if applicable. Personal accounts auto-consent at first sign-in.
46
+ 9. Set the env var on the Pi:
47
+ ```
48
+ OUTLOOK_CLIENT_ID=<the Application (client) ID copied above>
49
+ OUTLOOK_TENANT_ID=common # or your tenant GUID for single-tenant
50
+ ```
51
+
52
+ ## PKCE flow (per-account)
53
+
54
+ Triggered by `outlook-account-register`. Sequence:
55
+
56
+ ```
57
+ operator plugin Microsoft
58
+ | | |
59
+ | outlook-account-register | |
60
+ |--------------------------------------------->| |
61
+ | | bind 127.0.0.1:<ephemeral-port> |
62
+ | | generate code_verifier (32 bytes) |
63
+ | | code_challenge = SHA256(verifier) |
64
+ | | state = randomBytes(16) |
65
+ | | |
66
+ | { authUrl, status: "pending" } | |
67
+ |<---------------------------------------------| |
68
+ | | |
69
+ | open authUrl in VNC browser | |
70
+ |---------------------------------------------------------------------------------> |
71
+ | | |
72
+ | consent ←--------------------------------------- |
73
+ | | |
74
+ | | GET /callback?code=...&state=... |
75
+ | | <----------------------------------|
76
+ | | |
77
+ | | verify state |
78
+ | | POST /token (code + verifier) |
79
+ | | -----------------------------------> |
80
+ | | < tokens |
81
+ | | <----------------------------------- |
82
+ | | encrypt → write {tokens.enc} |
83
+ | | GET /me (record graphUserId) |
84
+ | | -----------------------------------> |
85
+ | | |
86
+ | { status: "registered", graphUserId, ... } | |
87
+ |<---------------------------------------------| |
88
+ ```
89
+
90
+ ## Token store layout
91
+
92
+ Per-account, mode 0700 directory + mode 0600 files:
93
+
94
+ ```
95
+ data/accounts/<accountId>/secrets/outlook/
96
+ ├── .key # 32 random bytes, base64-encoded — the AES-256-CBC key
97
+ └── tokens.enc # AES-256-CBC ciphertext: "<iv-hex>:<cipher-hex>" of JSON blob
98
+ ```
99
+
100
+ The JSON blob shape:
101
+
102
+ ```typescript
103
+ {
104
+ accessToken: string;
105
+ refreshToken: string | null;
106
+ accessTokenExpiry: number; // unix ms
107
+ refreshTokenExpiry: number; // unix ms; ~90 days from issue
108
+ lastRefresh: number; // unix ms
109
+ graphUserId: string | null; // from /me.id
110
+ scopes: string[]; // granted scopes from token response
111
+ }
112
+ ```
113
+
114
+ Atomic write: temp + rename. Either old or new tokens, never partial.
115
+
116
+ ## Refresh
117
+
118
+ Triggered automatically when the access token is within `5 minutes` of expiry (`refreshThresholdMs`). Failure → terminal `token-refresh-failed`, tokens cleared, operator must re-register. Refresh tokens last 90 days.
@@ -0,0 +1,114 @@
1
+ # Graph Surfaces
2
+
3
+ Microsoft Graph endpoints used by each tool, with the response shape and the fields selected.
4
+
5
+ ## outlook-mail-list
6
+
7
+ **Endpoint (Inbox):** `GET /me/mailFolders/Inbox/messages?$top={N}&$orderby=receivedDateTime DESC&$select=id,subject,from,receivedDateTime,bodyPreview,isRead`
8
+
9
+ **Endpoint (other folder):** `GET /me/mailFolders/{folderId-or-displayName}/messages?...`
10
+
11
+ **Returned shape:**
12
+ ```typescript
13
+ Array<{
14
+ id: string;
15
+ subject: string | null;
16
+ from: string | null; // emailAddress.address
17
+ receivedDateTime: string; // ISO 8601
18
+ bodyPreview: string; // truncated to 1024 chars
19
+ isRead: boolean;
20
+ }>
21
+ ```
22
+
23
+ ## outlook-mail-search
24
+
25
+ **Endpoint:** `GET /me/messages?$search="{query}"&$top={N}&$select=id,subject,from,receivedDateTime,bodyPreview,isRead`
26
+
27
+ **Required header:** `ConsistencyLevel: eventual` (Graph requirement for `$search`).
28
+
29
+ **Returned shape:** identical to `outlook-mail-list`.
30
+
31
+ ## outlook-calendar-list
32
+
33
+ **Endpoint:** `GET /me/calendarView?startDateTime={now}&endDateTime={now+rangeDays}&$top={N}&$orderby=start/dateTime ASC&$select=id,subject,start,end,location,attendees,isAllDay,organizer`
34
+
35
+ **Returned shape:**
36
+ ```typescript
37
+ Array<{
38
+ id: string;
39
+ subject: string | null;
40
+ start: { dateTime: string; timeZone: string };
41
+ end: { dateTime: string; timeZone: string };
42
+ location: string | null;
43
+ attendees: Array<{ email: string; name: string | null; response: string }>;
44
+ isAllDay: boolean;
45
+ organizer: string | null;
46
+ }>
47
+ ```
48
+
49
+ ## outlook-calendar-event
50
+
51
+ **Endpoint:** `GET /me/events/{eventId}?$select=id,subject,start,end,location,attendees,isAllDay,organizer,bodyPreview,body,webLink`
52
+
53
+ **Returned shape:** as `outlook-calendar-list` plus:
54
+ ```typescript
55
+ {
56
+ bodyPreview: string; // 1024 chars
57
+ body: string; // up to 16384 chars (HTML or text per content type)
58
+ webLink: string | null;
59
+ }
60
+ ```
61
+
62
+ ## outlook-contacts-list
63
+
64
+ **Endpoint:** `GET /me/contacts?$top={N}&$select=id,displayName,emailAddresses,businessPhones,homePhones,mobilePhone,jobTitle,companyName`
65
+
66
+ **Returned shape:**
67
+ ```typescript
68
+ Array<{
69
+ id: string;
70
+ displayName: string | null;
71
+ emailAddresses: string[]; // .address values flattened
72
+ phones: string[]; // business + home + mobile concatenated
73
+ jobTitle: string | null;
74
+ companyName: string | null;
75
+ }>
76
+ ```
77
+
78
+ ## outlook-mailbox-info
79
+
80
+ **Endpoint:** `GET /me/mailFolders?$top=50&$select=id` (best-effort — folder count is null if Graph is unreachable)
81
+
82
+ **Returned shape:**
83
+ ```typescript
84
+ {
85
+ registered: boolean;
86
+ graphUserId: string | null;
87
+ scopes: string[];
88
+ tokenExpSec: number | null;
89
+ refreshTokenExpSec: number | null;
90
+ tokenWithinRefreshWindow: boolean;
91
+ folderCount: number | null;
92
+ }
93
+ ```
94
+
95
+ ## outlook-account-register
96
+
97
+ No Graph endpoint of its own. The flow exchanges an authorization code at:
98
+
99
+ - `POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token`
100
+
101
+ After the token exchange, the tool fetches `GET /me?$select=id,mail,userPrincipalName` to record `graphUserId`.
102
+
103
+ ## Error classification
104
+
105
+ All tool failures route through `lib/graph-client.ts:classifyGraphError`. Decisions key off **status code + Graph `error.code` field + headers**, never the error `message` body.
106
+
107
+ | HTTP status | Graph `error.code` | Class | Action |
108
+ |---|---|---|---|
109
+ | 401 | (any) | `auth` | Refresh once, retry; if still 401 → terminal `auth-required` |
110
+ | 429 | (any) — header `Retry-After` present | `rate-limit-recoverable` | Backoff per header, retry once |
111
+ | 429 | (any) — header `Retry-After` absent | `rate-limit-terminal` | Terminal abort |
112
+ | 503 | `MailboxNotEnabledForRESTAPI` | `on-prem` | Terminal: route operator to IMAP plugin |
113
+ | 5xx | (any) | `5xx` | Retry once with 500 ms; then terminal |
114
+ | any | (any) | `other` | Re-throw |
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: outlook
3
+ description: "Microsoft 365 / Outlook.com via Microsoft Graph (read-only). Use when the user asks about their Outlook mail, calendar, or contacts — listing, searching, or checking events. First-time use requires outlook-account-register; subsequent use is transparent. Tools — outlook-mail-list / outlook-mail-search (inbox), outlook-calendar-list / outlook-calendar-event (calendar), outlook-contacts-list (contacts), outlook-mailbox-info (health), outlook-account-register (PKCE register)."
4
+ ---
5
+
6
+ # Outlook (Microsoft Graph)
7
+
8
+ Read-only access to the user's Outlook.com or Microsoft 365 mailbox via Microsoft Graph. Per-account OAuth, encrypted token storage, refresh handled automatically.
9
+
10
+ ## When to activate
11
+
12
+ Activate when the user asks about:
13
+
14
+ - Their Outlook / Office 365 / Hotmail mail (recent messages, search by keyword/sender)
15
+ - Their Outlook calendar (upcoming events, specific event details, free/busy windows)
16
+ - Their Outlook contacts
17
+
18
+ Do **not** activate for:
19
+
20
+ - IMAP-only providers (Gmail, iCloud, custom domains not on Microsoft 365) — use the `email` plugin instead.
21
+ - On-premises Exchange — Microsoft Graph deprecated hybrid REST 2023-07. The plugin detects on-prem mailboxes and emits a clear error pointing to the IMAP path.
22
+ - Sending / drafting / modifying messages or events — out of scope. Read-only.
23
+
24
+ ## First-time setup (one-time per account)
25
+
26
+ The Outlook plugin needs an **Entra app registration** in the operator's Microsoft tenant. This is a one-time-per-install step (not per-account), documented at [`references/auth.md`](references/auth.md).
27
+
28
+ Once the Entra app exists and `OUTLOOK_CLIENT_ID` is set in the Maxy installation, run:
29
+
30
+ 1. **`outlook-account-register`** — the tool returns an `authUrl`. The operator opens this URL in the VNC browser, signs in with the Microsoft account they want to connect, and consents to the requested scopes (`offline_access`, `User.Read`, `Mail.Read`, `Calendars.Read`, `Contacts.Read`).
31
+ 2. Tool returns `{ status: "registered", graphUserId, scopes, tokenExpSec }` once consent completes.
32
+
33
+ Subsequent tool calls use the persisted refresh token to mint access tokens transparently. Re-register is only needed if the refresh token expires (90 days) or the user revokes consent.
34
+
35
+ ## Reading mail
36
+
37
+ - `outlook-mail-list` — recent mail, default top=25, folder=Inbox.
38
+ - `outlook-mail-search query=<keyword>` — Microsoft Graph `$search` over the mailbox.
39
+
40
+ ## Reading calendar
41
+
42
+ - `outlook-calendar-list rangeDays=<N>` — events in the next N days (default 7, max 365).
43
+ - `outlook-calendar-event eventId=<id>` — single event with full body and attendees.
44
+
45
+ ## Reading contacts
46
+
47
+ - `outlook-contacts-list` — top contacts, default top=50.
48
+
49
+ ## Health check
50
+
51
+ - `outlook-mailbox-info` — quick state probe: is the account registered? Are tokens within the refresh window? How many folders are visible? Useful when troubleshooting a tool that returned `auth-required`.
52
+
53
+ ## What can go wrong
54
+
55
+ | Error | Meaning | Operator action |
56
+ |---|---|---|
57
+ | `auth-required` | Account not registered, or refresh token expired | Run `outlook-account-register` |
58
+ | `Outlook token refresh failed` | Network down or refresh token invalidated | Verify connectivity; re-run register if persistent |
59
+ | `Microsoft Graph does not support on-premises Exchange` | Mailbox is on hybrid Exchange | Use the `email` plugin (IMAP) |
60
+ | `Outlook rate-limited without Retry-After hint` | Graph 429 with no backoff guidance | Retry later; if persistent, file a bug |
61
+
62
+ ## Reference files
63
+
64
+ - [`references/auth.md`](references/auth.md) — Entra app registration + PKCE flow + re-vendor procedure
65
+ - [`references/graph-surfaces.md`](references/graph-surfaces.md) — Graph endpoint and response shape per tool
@@ -3,7 +3,7 @@ name: personal-assistant
3
3
  description: "Your personal assistant — scheduling, platform administration, messaging channels, system health, and browser automation. Delegate when a task involves managing your calendar, configuring the platform, operating messaging channels, or completing interactive browser tasks."
4
4
  summary: "Handles the operational tasks you'd give a personal assistant — scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf. For example, when you want to schedule a weekly check-in, set up Telegram, or fill out an online form."
5
5
  model: claude-sonnet-4-6
6
- tools: mcp__admin__system-status, mcp__admin__brand-settings, mcp__admin__account-manage, mcp__admin__account-update, mcp__admin__logs-read, mcp__admin__plugin-read, mcp__admin__api-key-store, mcp__admin__api-key-verify, mcp__admin__render-component, mcp__admin__file-attach, mcp__admin__wifi, mcp__contacts__contact-create, mcp__contacts__contact-lookup, mcp__contacts__contact-update, mcp__contacts__contact-delete, mcp__contacts__contact-list, mcp__contacts__contact-export, mcp__contacts__contact-erase, mcp__contacts__group-create, mcp__contacts__group-manage, mcp__telegram__message, mcp__telegram__message-history, mcp__telegram__telegram-webhook-register, mcp__whatsapp__whatsapp-login-start, mcp__whatsapp__whatsapp-login-wait, mcp__whatsapp__whatsapp-status, mcp__whatsapp__whatsapp-disconnect, mcp__whatsapp__whatsapp-send, mcp__whatsapp__whatsapp-send-document, mcp__whatsapp__whatsapp-config, mcp__whatsapp__whatsapp-activity, mcp__whatsapp__whatsapp-conversations, mcp__whatsapp__whatsapp-messages, mcp__whatsapp__whatsapp-group-info, mcp__email__email-setup, mcp__email__email-read, mcp__email__email-send, mcp__email__email-reply, mcp__email__email-search, mcp__email__email-graph-query, mcp__email__email-otp-extract, mcp__email__email-status, mcp__email__email-auto-respond-config, mcp__scheduling__schedule-event, mcp__scheduling__schedule-list, mcp__scheduling__schedule-get, mcp__scheduling__schedule-update, mcp__scheduling__schedule-cancel, mcp__scheduling__schedule-export-ics, mcp__scheduling__schedule-import-ics, mcp__scheduling__time-resolve, mcp__memory__memory-search, mcp__memory__profile-update, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_navigate_back, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_click, mcp__plugin_playwright_playwright__browser_fill, mcp__plugin_playwright_playwright__browser_fill_form, mcp__plugin_playwright_playwright__browser_type, mcp__plugin_playwright_playwright__browser_press_key, mcp__plugin_playwright_playwright__browser_hover, mcp__plugin_playwright_playwright__browser_select_option, mcp__plugin_playwright_playwright__browser_wait_for, mcp__plugin_playwright_playwright__browser_handle_dialog, mcp__plugin_playwright_playwright__browser_evaluate, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_tabs, mcp__plugin_playwright_playwright__browser_close
6
+ tools: mcp__admin__system-status, mcp__admin__brand-settings, mcp__admin__account-manage, mcp__admin__account-update, mcp__admin__logs-read, mcp__admin__plugin-read, mcp__admin__api-key-store, mcp__admin__api-key-verify, mcp__admin__render-component, mcp__admin__file-attach, mcp__admin__wifi, mcp__contacts__contact-create, mcp__contacts__contact-lookup, mcp__contacts__contact-update, mcp__contacts__contact-delete, mcp__contacts__contact-list, mcp__contacts__contact-export, mcp__contacts__contact-erase, mcp__contacts__group-create, mcp__contacts__group-manage, mcp__telegram__message, mcp__telegram__message-history, mcp__telegram__telegram-webhook-register, mcp__whatsapp__whatsapp-login-start, mcp__whatsapp__whatsapp-login-wait, mcp__whatsapp__whatsapp-status, mcp__whatsapp__whatsapp-disconnect, mcp__whatsapp__whatsapp-send, mcp__whatsapp__whatsapp-send-document, mcp__whatsapp__whatsapp-config, mcp__whatsapp__whatsapp-activity, mcp__whatsapp__whatsapp-conversations, mcp__whatsapp__whatsapp-messages, mcp__whatsapp__whatsapp-group-info, mcp__email__email-setup, mcp__email__email-read, mcp__email__email-send, mcp__email__email-reply, mcp__email__email-search, mcp__email__email-graph-query, mcp__email__email-otp-extract, mcp__email__email-status, mcp__email__email-auto-respond-config, mcp__outlook__outlook-account-register, mcp__outlook__outlook-mail-list, mcp__outlook__outlook-mail-search, mcp__outlook__outlook-calendar-list, mcp__outlook__outlook-calendar-event, mcp__outlook__outlook-contacts-list, mcp__outlook__outlook-mailbox-info, mcp__scheduling__schedule-event, mcp__scheduling__schedule-list, mcp__scheduling__schedule-get, mcp__scheduling__schedule-update, mcp__scheduling__schedule-cancel, mcp__scheduling__schedule-export-ics, mcp__scheduling__schedule-import-ics, mcp__scheduling__time-resolve, mcp__memory__memory-search, mcp__memory__profile-update, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_navigate_back, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_click, mcp__plugin_playwright_playwright__browser_fill, mcp__plugin_playwright_playwright__browser_fill_form, mcp__plugin_playwright_playwright__browser_type, mcp__plugin_playwright_playwright__browser_press_key, mcp__plugin_playwright_playwright__browser_hover, mcp__plugin_playwright_playwright__browser_select_option, mcp__plugin_playwright_playwright__browser_wait_for, mcp__plugin_playwright_playwright__browser_handle_dialog, mcp__plugin_playwright_playwright__browser_evaluate, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_tabs, mcp__plugin_playwright_playwright__browser_close
7
7
  ---
8
8
 
9
9
  # Personal Assistant