awolve-myoffice-cli 1.1.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.
- package/README.md +205 -0
- package/dist/auth/cache-plugin.d.ts +20 -0
- package/dist/auth/cache-plugin.d.ts.map +1 -0
- package/dist/auth/cache-plugin.js +49 -0
- package/dist/auth/cache-plugin.js.map +1 -0
- package/dist/auth/config.d.ts +22 -0
- package/dist/auth/config.d.ts.map +1 -0
- package/dist/auth/config.js +64 -0
- package/dist/auth/config.js.map +1 -0
- package/dist/auth/device-code.d.ts +2 -0
- package/dist/auth/device-code.d.ts.map +1 -0
- package/dist/auth/device-code.js +38 -0
- package/dist/auth/device-code.js.map +1 -0
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +4 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/login.d.ts +7 -0
- package/dist/auth/login.d.ts.map +1 -0
- package/dist/auth/login.js +22 -0
- package/dist/auth/login.js.map +1 -0
- package/dist/auth/token-manager.d.ts +4 -0
- package/dist/auth/token-manager.d.ts.map +1 -0
- package/dist/auth/token-manager.js +78 -0
- package/dist/auth/token-manager.js.map +1 -0
- package/dist/cli/formatter.d.ts +5 -0
- package/dist/cli/formatter.d.ts.map +1 -0
- package/dist/cli/formatter.js +317 -0
- package/dist/cli/formatter.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +802 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/handler.d.ts +8 -0
- package/dist/core/handler.d.ts.map +1 -0
- package/dist/core/handler.js +289 -0
- package/dist/core/handler.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +819 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/calendar.d.ts +124 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +129 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/chats.d.ts +66 -0
- package/dist/tools/chats.d.ts.map +1 -0
- package/dist/tools/chats.js +102 -0
- package/dist/tools/chats.js.map +1 -0
- package/dist/tools/contacts.d.ts +119 -0
- package/dist/tools/contacts.d.ts.map +1 -0
- package/dist/tools/contacts.js +136 -0
- package/dist/tools/contacts.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +10 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/mail.d.ts +138 -0
- package/dist/tools/mail.d.ts.map +1 -0
- package/dist/tools/mail.js +187 -0
- package/dist/tools/mail.js.map +1 -0
- package/dist/tools/onedrive.d.ts +107 -0
- package/dist/tools/onedrive.d.ts.map +1 -0
- package/dist/tools/onedrive.js +136 -0
- package/dist/tools/onedrive.js.map +1 -0
- package/dist/tools/planner.d.ts +261 -0
- package/dist/tools/planner.d.ts.map +1 -0
- package/dist/tools/planner.js +401 -0
- package/dist/tools/planner.js.map +1 -0
- package/dist/tools/sharepoint.d.ts +138 -0
- package/dist/tools/sharepoint.d.ts.map +1 -0
- package/dist/tools/sharepoint.js +156 -0
- package/dist/tools/sharepoint.js.map +1 -0
- package/dist/tools/tasks.d.ts +107 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +131 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/teams.d.ts +66 -0
- package/dist/tools/teams.d.ts.map +1 -0
- package/dist/tools/teams.js +69 -0
- package/dist/tools/teams.js.map +1 -0
- package/dist/utils/graph-client.d.ts +10 -0
- package/dist/utils/graph-client.d.ts.map +1 -0
- package/dist/utils/graph-client.js +49 -0
- package/dist/utils/graph-client.js.map +1 -0
- package/dist/utils/signature.d.ts +2 -0
- package/dist/utils/signature.d.ts.map +1 -0
- package/dist/utils/signature.js +17 -0
- package/dist/utils/signature.js.map +1 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +20 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# MyOffice MCP
|
|
2
|
+
|
|
3
|
+
A lightweight MCP (Model Context Protocol) server for personal Microsoft 365 access, designed for AI assistants like Claude Code.
|
|
4
|
+
|
|
5
|
+
Unlike admin-focused M365 tools, this uses **delegated authentication** - users authenticate as themselves and can only access their own data.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Email** - List, read, search, send, delete
|
|
10
|
+
- **Calendar** - List, create, update, delete events (with Teams meetings)
|
|
11
|
+
- **Tasks** - Manage Microsoft To Do lists and tasks
|
|
12
|
+
- **OneDrive** - Browse, search, read files
|
|
13
|
+
- **Contacts** - List and search contacts
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- Node.js 18+
|
|
18
|
+
- An Azure AD app registration with delegated permissions (see setup below)
|
|
19
|
+
- Microsoft 365 account
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/awolve/ops-myoffice.git
|
|
25
|
+
cd ops-myoffice
|
|
26
|
+
npm install
|
|
27
|
+
npm run build
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Azure AD App Registration
|
|
31
|
+
|
|
32
|
+
1. Go to [Azure Portal](https://portal.azure.com) > Azure Active Directory > App registrations
|
|
33
|
+
2. Click **New registration**
|
|
34
|
+
- Name: `Personal M365 MCP` (or your choice)
|
|
35
|
+
- Supported account types: **Accounts in any organizational directory** (for multi-tenant)
|
|
36
|
+
- Redirect URI: Leave blank (we use device code flow)
|
|
37
|
+
3. After creation, note the **Application (client) ID**
|
|
38
|
+
4. Go to **Authentication** > Advanced settings
|
|
39
|
+
- Enable **Allow public client flows** = Yes
|
|
40
|
+
5. Go to **API permissions** > Add a permission > Microsoft Graph > Delegated permissions
|
|
41
|
+
- Add these permissions:
|
|
42
|
+
- `Mail.ReadWrite`
|
|
43
|
+
- `Mail.Send`
|
|
44
|
+
- `Calendars.ReadWrite`
|
|
45
|
+
- `Tasks.ReadWrite`
|
|
46
|
+
- `Files.ReadWrite`
|
|
47
|
+
- `Sites.Read.All`
|
|
48
|
+
- `Contacts.ReadWrite`
|
|
49
|
+
- `User.Read`
|
|
50
|
+
- `Team.ReadBasic.All`
|
|
51
|
+
- `Channel.ReadBasic.All`
|
|
52
|
+
- `ChannelMessage.Read.All`
|
|
53
|
+
- `ChannelMessage.Send`
|
|
54
|
+
- `Chat.Create`
|
|
55
|
+
- `Chat.ReadBasic`
|
|
56
|
+
- `Chat.Read`
|
|
57
|
+
- `ChatMessage.Send`
|
|
58
|
+
- `offline_access`
|
|
59
|
+
6. Click **Grant admin consent** (optional - users can consent themselves)
|
|
60
|
+
|
|
61
|
+
## Configuration
|
|
62
|
+
|
|
63
|
+
Set environment variables:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
export M365_CLIENT_ID="your-app-client-id"
|
|
67
|
+
export M365_TENANT_ID="common" # or your tenant ID for single-tenant
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or create a `.env` file:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
M365_CLIENT_ID=your-app-client-id
|
|
74
|
+
M365_TENANT_ID=common
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## First-Time Authentication
|
|
78
|
+
|
|
79
|
+
Run the login script to authenticate:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm run login
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
You'll see:
|
|
86
|
+
```
|
|
87
|
+
AUTHENTICATION REQUIRED
|
|
88
|
+
========================================
|
|
89
|
+
To sign in, use a web browser to open the page
|
|
90
|
+
https://microsoft.com/devicelogin and enter the code XXXXXXXX
|
|
91
|
+
========================================
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
After signing in, your token is cached at `~/.config/myoffice-mcp/token.json`
|
|
95
|
+
|
|
96
|
+
## Usage with Claude Code
|
|
97
|
+
|
|
98
|
+
Add to your Claude Code MCP settings:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"mcpServers": {
|
|
103
|
+
"myoffice-mcp": {
|
|
104
|
+
"command": "node",
|
|
105
|
+
"args": ["/path/to/ops-myoffice/dist/index.js"],
|
|
106
|
+
"env": {
|
|
107
|
+
"M365_CLIENT_ID": "your-client-id"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Available Tools
|
|
115
|
+
|
|
116
|
+
### Email
|
|
117
|
+
| Tool | Description |
|
|
118
|
+
|------|-------------|
|
|
119
|
+
| `mail_list` | List emails from a folder |
|
|
120
|
+
| `mail_read` | Read a specific email |
|
|
121
|
+
| `mail_search` | Search emails |
|
|
122
|
+
| `mail_send` | Send an email |
|
|
123
|
+
| `mail_delete` | Delete an email |
|
|
124
|
+
|
|
125
|
+
### Calendar
|
|
126
|
+
| Tool | Description |
|
|
127
|
+
|------|-------------|
|
|
128
|
+
| `calendar_list` | List events in date range |
|
|
129
|
+
| `calendar_get` | Get event details |
|
|
130
|
+
| `calendar_create` | Create an event |
|
|
131
|
+
| `calendar_update` | Update an event |
|
|
132
|
+
| `calendar_delete` | Delete an event |
|
|
133
|
+
|
|
134
|
+
### Tasks
|
|
135
|
+
| Tool | Description |
|
|
136
|
+
|------|-------------|
|
|
137
|
+
| `tasks_list_lists` | List all task lists |
|
|
138
|
+
| `tasks_list` | List tasks from a list |
|
|
139
|
+
| `tasks_create` | Create a task |
|
|
140
|
+
| `tasks_update` | Update a task |
|
|
141
|
+
| `tasks_complete` | Mark task complete |
|
|
142
|
+
| `tasks_delete` | Delete a task |
|
|
143
|
+
|
|
144
|
+
### OneDrive
|
|
145
|
+
| Tool | Description |
|
|
146
|
+
|------|-------------|
|
|
147
|
+
| `onedrive_list` | List files/folders |
|
|
148
|
+
| `onedrive_get` | Get file metadata |
|
|
149
|
+
| `onedrive_search` | Search files |
|
|
150
|
+
| `onedrive_read` | Read text file content |
|
|
151
|
+
| `onedrive_create_folder` | Create a folder |
|
|
152
|
+
|
|
153
|
+
### Contacts
|
|
154
|
+
| Tool | Description |
|
|
155
|
+
|------|-------------|
|
|
156
|
+
| `contacts_list` | List contacts |
|
|
157
|
+
| `contacts_search` | Search contacts |
|
|
158
|
+
| `contacts_get` | Get contact details |
|
|
159
|
+
| `contacts_create` | Create a new contact |
|
|
160
|
+
| `contacts_update` | Update an existing contact |
|
|
161
|
+
|
|
162
|
+
### Teams
|
|
163
|
+
| Tool | Description |
|
|
164
|
+
|------|-------------|
|
|
165
|
+
| `teams_list` | List Teams you're a member of |
|
|
166
|
+
| `teams_channels` | List channels in a Team |
|
|
167
|
+
| `teams_channel_messages` | Read messages from a channel |
|
|
168
|
+
| `teams_channel_post` | Post a message to a channel |
|
|
169
|
+
|
|
170
|
+
### Chats
|
|
171
|
+
| Tool | Description |
|
|
172
|
+
|------|-------------|
|
|
173
|
+
| `chats_list` | List 1:1 and group chats |
|
|
174
|
+
| `chats_messages` | Read messages from a chat |
|
|
175
|
+
| `chats_send` | Send a message in a chat |
|
|
176
|
+
| `chats_create` | Create a new 1:1 or group chat |
|
|
177
|
+
|
|
178
|
+
### Auth
|
|
179
|
+
| Tool | Description |
|
|
180
|
+
|------|-------------|
|
|
181
|
+
| `auth_status` | Check auth status |
|
|
182
|
+
|
|
183
|
+
## Security
|
|
184
|
+
|
|
185
|
+
- Uses delegated permissions only - users can only access their own data
|
|
186
|
+
- Tokens stored locally with restrictive permissions (0600)
|
|
187
|
+
- No client secrets required (public client)
|
|
188
|
+
- Destructive operations (send, delete) are clearly marked for AI confirmation
|
|
189
|
+
|
|
190
|
+
## Development
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Run in development mode
|
|
194
|
+
npm run dev
|
|
195
|
+
|
|
196
|
+
# Build
|
|
197
|
+
npm run build
|
|
198
|
+
|
|
199
|
+
# Run login flow
|
|
200
|
+
npm run login
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ICachePlugin, TokenCacheContext } from '@azure/msal-node';
|
|
2
|
+
/**
|
|
3
|
+
* MSAL Cache Plugin that persists the full token cache (including refresh tokens)
|
|
4
|
+
* to a file. This ensures tokens survive server restarts.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FileCachePlugin implements ICachePlugin {
|
|
7
|
+
private cachePath;
|
|
8
|
+
constructor(cachePath: string);
|
|
9
|
+
/**
|
|
10
|
+
* Called before MSAL accesses the cache.
|
|
11
|
+
* Load the cache from disk into MSAL's memory.
|
|
12
|
+
*/
|
|
13
|
+
beforeCacheAccess(cacheContext: TokenCacheContext): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Called after MSAL accesses the cache.
|
|
16
|
+
* If the cache changed, persist it to disk.
|
|
17
|
+
*/
|
|
18
|
+
afterCacheAccess(cacheContext: TokenCacheContext): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=cache-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-plugin.d.ts","sourceRoot":"","sources":["../../src/auth/cache-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAInE;;;GAGG;AACH,qBAAa,eAAgB,YAAW,YAAY;IAClD,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,EAAE,MAAM;IAI7B;;;OAGG;IACG,iBAAiB,CAAC,YAAY,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAavE;;;OAGG;IACG,gBAAgB,CAAC,YAAY,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;CAcvE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { dirname } from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* MSAL Cache Plugin that persists the full token cache (including refresh tokens)
|
|
5
|
+
* to a file. This ensures tokens survive server restarts.
|
|
6
|
+
*/
|
|
7
|
+
export class FileCachePlugin {
|
|
8
|
+
cachePath;
|
|
9
|
+
constructor(cachePath) {
|
|
10
|
+
this.cachePath = cachePath;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Called before MSAL accesses the cache.
|
|
14
|
+
* Load the cache from disk into MSAL's memory.
|
|
15
|
+
*/
|
|
16
|
+
async beforeCacheAccess(cacheContext) {
|
|
17
|
+
try {
|
|
18
|
+
if (existsSync(this.cachePath)) {
|
|
19
|
+
const cacheData = readFileSync(this.cachePath, 'utf-8');
|
|
20
|
+
if (cacheData && cacheData.trim()) {
|
|
21
|
+
cacheContext.tokenCache.deserialize(cacheData);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.error('[Cache] Failed to load cache:', error instanceof Error ? error.message : error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Called after MSAL accesses the cache.
|
|
31
|
+
* If the cache changed, persist it to disk.
|
|
32
|
+
*/
|
|
33
|
+
async afterCacheAccess(cacheContext) {
|
|
34
|
+
if (cacheContext.cacheHasChanged) {
|
|
35
|
+
try {
|
|
36
|
+
const dir = dirname(this.cachePath);
|
|
37
|
+
if (!existsSync(dir)) {
|
|
38
|
+
mkdirSync(dir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
const serialized = cacheContext.tokenCache.serialize();
|
|
41
|
+
writeFileSync(this.cachePath, serialized, { mode: 0o600 });
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error('[Cache] Failed to save cache:', error instanceof Error ? error.message : error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=cache-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-plugin.js","sourceRoot":"","sources":["../../src/auth/cache-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B;;;GAGG;AACH,MAAM,OAAO,eAAe;IAClB,SAAS,CAAS;IAE1B,YAAY,SAAiB;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB,CAAC,YAA+B;QACrD,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/B,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBACxD,IAAI,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;oBAClC,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,gBAAgB,CAAC,YAA+B;QACpD,IAAI,YAAY,CAAC,eAAe,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACpC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtC,CAAC;gBACD,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;gBACvD,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACjG,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface TokenCache {
|
|
2
|
+
accessToken: string;
|
|
3
|
+
refreshToken: string;
|
|
4
|
+
expiresAt: number;
|
|
5
|
+
account?: {
|
|
6
|
+
homeAccountId: string;
|
|
7
|
+
environment: string;
|
|
8
|
+
tenantId: string;
|
|
9
|
+
username: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface AuthConfig {
|
|
13
|
+
clientId: string;
|
|
14
|
+
tenantId: string;
|
|
15
|
+
scopes: string[];
|
|
16
|
+
}
|
|
17
|
+
export declare const DEFAULT_CONFIG: AuthConfig;
|
|
18
|
+
export declare const MSAL_CACHE_FILE: string;
|
|
19
|
+
export declare function getTokenCache(): TokenCache | null;
|
|
20
|
+
export declare function saveTokenCache(cache: TokenCache): void;
|
|
21
|
+
export declare function clearTokenCache(): void;
|
|
22
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAID,eAAO,MAAM,cAAc,EAAE,UA0B5B,CAAC;AAGF,eAAO,MAAM,eAAe,QAAgE,CAAC;AAE7F,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAUjD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAMtD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAQtC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
// Default Azure AD app for personal M365 access
|
|
5
|
+
// Users can override with their own app registration
|
|
6
|
+
export const DEFAULT_CONFIG = {
|
|
7
|
+
clientId: process.env.M365_CLIENT_ID || '',
|
|
8
|
+
tenantId: process.env.M365_TENANT_ID || 'common',
|
|
9
|
+
scopes: [
|
|
10
|
+
'https://graph.microsoft.com/Mail.ReadWrite',
|
|
11
|
+
'https://graph.microsoft.com/Mail.Send',
|
|
12
|
+
'https://graph.microsoft.com/Calendars.ReadWrite',
|
|
13
|
+
'https://graph.microsoft.com/Tasks.ReadWrite',
|
|
14
|
+
'https://graph.microsoft.com/Files.ReadWrite',
|
|
15
|
+
'https://graph.microsoft.com/Sites.Read.All',
|
|
16
|
+
'https://graph.microsoft.com/Contacts.ReadWrite',
|
|
17
|
+
'https://graph.microsoft.com/User.Read',
|
|
18
|
+
// Teams
|
|
19
|
+
'https://graph.microsoft.com/Team.ReadBasic.All',
|
|
20
|
+
'https://graph.microsoft.com/Channel.ReadBasic.All',
|
|
21
|
+
'https://graph.microsoft.com/ChannelMessage.Read.All',
|
|
22
|
+
'https://graph.microsoft.com/ChannelMessage.Send',
|
|
23
|
+
// Chats
|
|
24
|
+
'https://graph.microsoft.com/Chat.Create',
|
|
25
|
+
'https://graph.microsoft.com/Chat.ReadBasic',
|
|
26
|
+
'https://graph.microsoft.com/Chat.Read',
|
|
27
|
+
'https://graph.microsoft.com/ChatMessage.Send',
|
|
28
|
+
// Planner
|
|
29
|
+
'https://graph.microsoft.com/Group.Read.All',
|
|
30
|
+
'offline_access',
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
const TOKEN_FILE = join(homedir(), '.config', 'myoffice-mcp', 'token.json');
|
|
34
|
+
export const MSAL_CACHE_FILE = join(homedir(), '.config', 'myoffice-mcp', 'msal-cache.json');
|
|
35
|
+
export function getTokenCache() {
|
|
36
|
+
try {
|
|
37
|
+
if (existsSync(TOKEN_FILE)) {
|
|
38
|
+
const data = readFileSync(TOKEN_FILE, 'utf-8');
|
|
39
|
+
return JSON.parse(data);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Ignore errors, return null
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
export function saveTokenCache(cache) {
|
|
48
|
+
const dir = dirname(TOKEN_FILE);
|
|
49
|
+
if (!existsSync(dir)) {
|
|
50
|
+
mkdirSync(dir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
writeFileSync(TOKEN_FILE, JSON.stringify(cache, null, 2), { mode: 0o600 });
|
|
53
|
+
}
|
|
54
|
+
export function clearTokenCache() {
|
|
55
|
+
try {
|
|
56
|
+
if (existsSync(TOKEN_FILE)) {
|
|
57
|
+
writeFileSync(TOKEN_FILE, '', { mode: 0o600 });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Ignore errors
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAoBrC,gDAAgD;AAChD,qDAAqD;AACrD,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE;IAC1C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,QAAQ;IAChD,MAAM,EAAE;QACN,4CAA4C;QAC5C,uCAAuC;QACvC,iDAAiD;QACjD,6CAA6C;QAC7C,6CAA6C;QAC7C,4CAA4C;QAC5C,gDAAgD;QAChD,uCAAuC;QACvC,QAAQ;QACR,gDAAgD;QAChD,mDAAmD;QACnD,qDAAqD;QACrD,iDAAiD;QACjD,QAAQ;QACR,yCAAyC;QACzC,4CAA4C;QAC5C,uCAAuC;QACvC,8CAA8C;QAC9C,UAAU;QACV,4CAA4C;QAC5C,gBAAgB;KACjB;CACF,CAAC;AAEF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,CAAC,CAAC;AAE7F,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAiB;IAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,aAAa,CAAC,UAAU,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-code.d.ts","sourceRoot":"","sources":["../../src/auth/device-code.ts"],"names":[],"mappings":"AAMA,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAuChE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PublicClientApplication } from '@azure/msal-node';
|
|
2
|
+
import { DEFAULT_CONFIG, MSAL_CACHE_FILE } from './config.js';
|
|
3
|
+
import { FileCachePlugin } from './cache-plugin.js';
|
|
4
|
+
const cachePlugin = new FileCachePlugin(MSAL_CACHE_FILE);
|
|
5
|
+
export async function authenticateWithDeviceCode() {
|
|
6
|
+
if (!DEFAULT_CONFIG.clientId) {
|
|
7
|
+
throw new Error('M365_CLIENT_ID environment variable is required.\n' +
|
|
8
|
+
'Create an Azure AD app registration with delegated permissions and set M365_CLIENT_ID.');
|
|
9
|
+
}
|
|
10
|
+
const pca = new PublicClientApplication({
|
|
11
|
+
auth: {
|
|
12
|
+
clientId: DEFAULT_CONFIG.clientId,
|
|
13
|
+
authority: `https://login.microsoftonline.com/${DEFAULT_CONFIG.tenantId}`,
|
|
14
|
+
},
|
|
15
|
+
cache: {
|
|
16
|
+
cachePlugin,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
const deviceCodeRequest = {
|
|
20
|
+
scopes: DEFAULT_CONFIG.scopes,
|
|
21
|
+
deviceCodeCallback: (response) => {
|
|
22
|
+
console.log('\n' + '='.repeat(60));
|
|
23
|
+
console.log('AUTHENTICATION REQUIRED');
|
|
24
|
+
console.log('='.repeat(60));
|
|
25
|
+
console.log(`\n${response.message}\n`);
|
|
26
|
+
console.log('='.repeat(60) + '\n');
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const result = await pca.acquireTokenByDeviceCode(deviceCodeRequest);
|
|
30
|
+
if (!result || !result.accessToken) {
|
|
31
|
+
throw new Error('Failed to acquire access token');
|
|
32
|
+
}
|
|
33
|
+
// The cache plugin automatically persists the tokens via afterCacheAccess
|
|
34
|
+
console.log(`\nAuthenticated as: ${result.account?.username}`);
|
|
35
|
+
console.log('Token cached at:', MSAL_CACHE_FILE);
|
|
36
|
+
console.log('Refresh token is now properly persisted.\n');
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=device-code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-code.js","sourceRoot":"","sources":["../../src/auth/device-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAqB,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,eAAe,CAAC,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,oDAAoD;YACpD,wFAAwF,CACzF,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,uBAAuB,CAAC;QACtC,IAAI,EAAE;YACJ,QAAQ,EAAE,cAAc,CAAC,QAAQ;YACjC,SAAS,EAAE,qCAAqC,cAAc,CAAC,QAAQ,EAAE;SAC1E;QACD,KAAK,EAAE;YACL,WAAW;SACZ;KACF,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAsB;QAC3C,MAAM,EAAE,cAAc,CAAC,MAAM;QAC7B,kBAAkB,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACrC,CAAC;KACF,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,CAAC;IAErE,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,0EAA0E;IAC1E,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/auth/login.ts"],"names":[],"mappings":";AACA;;;GAGG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Standalone login script for initial authentication
|
|
4
|
+
* Run with: npm run login
|
|
5
|
+
*/
|
|
6
|
+
import { authenticateWithDeviceCode } from './device-code.js';
|
|
7
|
+
async function main() {
|
|
8
|
+
console.log('Personal M365 MCP - Authentication');
|
|
9
|
+
console.log('===================================\n');
|
|
10
|
+
try {
|
|
11
|
+
await authenticateWithDeviceCode();
|
|
12
|
+
console.log('Authentication successful!');
|
|
13
|
+
console.log('You can now use the M365 MCP with Claude Code.');
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error('Authentication failed:', error);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
main();
|
|
22
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/auth/login.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE9D,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,0BAA0B,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"AA0BA,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CA4CtD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAQxD;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ7D"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { PublicClientApplication } from '@azure/msal-node';
|
|
2
|
+
import { DEFAULT_CONFIG, MSAL_CACHE_FILE, getTokenCache } from './config.js';
|
|
3
|
+
import { FileCachePlugin } from './cache-plugin.js';
|
|
4
|
+
let msalInstance = null;
|
|
5
|
+
const cachePlugin = new FileCachePlugin(MSAL_CACHE_FILE);
|
|
6
|
+
function getMsalInstance() {
|
|
7
|
+
if (!msalInstance) {
|
|
8
|
+
if (!DEFAULT_CONFIG.clientId) {
|
|
9
|
+
throw new Error('M365_CLIENT_ID environment variable is required');
|
|
10
|
+
}
|
|
11
|
+
msalInstance = new PublicClientApplication({
|
|
12
|
+
auth: {
|
|
13
|
+
clientId: DEFAULT_CONFIG.clientId,
|
|
14
|
+
authority: `https://login.microsoftonline.com/${DEFAULT_CONFIG.tenantId}`,
|
|
15
|
+
},
|
|
16
|
+
cache: {
|
|
17
|
+
cachePlugin,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return msalInstance;
|
|
22
|
+
}
|
|
23
|
+
export async function getAccessToken() {
|
|
24
|
+
const pca = getMsalInstance();
|
|
25
|
+
// Get accounts from MSAL's persisted cache
|
|
26
|
+
const accounts = await pca.getTokenCache().getAllAccounts();
|
|
27
|
+
if (accounts.length === 0) {
|
|
28
|
+
// No accounts in MSAL cache - check legacy token.json for migration hint
|
|
29
|
+
const legacyCache = getTokenCache();
|
|
30
|
+
if (legacyCache?.account) {
|
|
31
|
+
console.error('[Auth] Found legacy token.json but no MSAL cache.');
|
|
32
|
+
console.error('[Auth] Please re-authenticate to migrate to new cache format.');
|
|
33
|
+
}
|
|
34
|
+
throw new Error('Not authenticated. Please run "npm run login" in the myoffice-mcp directory.');
|
|
35
|
+
}
|
|
36
|
+
// Use the first account (typically there's only one for personal use)
|
|
37
|
+
const account = accounts[0];
|
|
38
|
+
// Try silent token acquisition (MSAL handles refresh automatically)
|
|
39
|
+
console.error('[Auth] Acquiring token silently...');
|
|
40
|
+
try {
|
|
41
|
+
const silentRequest = {
|
|
42
|
+
scopes: DEFAULT_CONFIG.scopes,
|
|
43
|
+
account: account,
|
|
44
|
+
};
|
|
45
|
+
const result = await pca.acquireTokenSilent(silentRequest);
|
|
46
|
+
console.error('[Auth] Token acquired successfully');
|
|
47
|
+
return result.accessToken;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// Silent refresh failed - log the actual error
|
|
51
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
52
|
+
console.error('[Auth] Silent token acquisition FAILED:', errorMessage);
|
|
53
|
+
console.error('[Auth] Please re-authenticate by running: npm run login');
|
|
54
|
+
throw new Error(`Token acquisition failed: ${errorMessage}. ` +
|
|
55
|
+
`Please re-authenticate by running 'npm run login' in the myoffice-mcp directory.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function isAuthenticated() {
|
|
59
|
+
try {
|
|
60
|
+
const pca = getMsalInstance();
|
|
61
|
+
const accounts = await pca.getTokenCache().getAllAccounts();
|
|
62
|
+
return accounts.length > 0;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export async function getCurrentUser() {
|
|
69
|
+
try {
|
|
70
|
+
const pca = getMsalInstance();
|
|
71
|
+
const accounts = await pca.getTokenCache().getAllAccounts();
|
|
72
|
+
return accounts[0]?.username || null;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=token-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/cli/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoWH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAsErE"}
|