m365-cli 0.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 ADDED
@@ -0,0 +1,683 @@
1
+ # M365 CLI
2
+
3
+ Modern command-line interface for Microsoft 365 personal accounts (Mail, Calendar, OneDrive, SharePoint).
4
+
5
+ ## Features
6
+
7
+ - 📧 **Mail**: List, read, send, search emails (with attachments)
8
+ - 📅 **Calendar**: Manage events (list, create, update, delete)
9
+ - 📁 **OneDrive**: File management (upload, download, search, share)
10
+ - 🌐 **SharePoint**: Site and document management
11
+ - 🔐 **Secure**: OAuth 2.0 Device Code Flow authentication
12
+ - 🚀 **Fast**: Minimal dependencies, uses native Node.js fetch
13
+ - 🤖 **AI-friendly**: Clean text output + JSON option
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install -g m365-cli
19
+ ```
20
+
21
+ If you prefer to install from source:
22
+ ```bash
23
+ git clone <repo>
24
+ cd m365-cli
25
+ npm install
26
+ npm link
27
+ ```
28
+
29
+ After linking, the `m365` command will be available globally.
30
+
31
+ ## Quick Start
32
+
33
+ ### 1. Login
34
+
35
+ ```bash
36
+ m365 login
37
+ ```
38
+
39
+ Follow the prompts to authenticate with your Microsoft 365 account using Device Code Flow.
40
+
41
+ ### 2. List Emails
42
+
43
+ ```bash
44
+ m365 mail list --top 5
45
+ ```
46
+
47
+ ### 3. View Calendar
48
+
49
+ ```bash
50
+ m365 calendar list --days 7
51
+ ```
52
+
53
+ ### 4. Browse OneDrive
54
+
55
+ ```bash
56
+ m365 onedrive ls
57
+ ```
58
+
59
+ ## Commands Reference
60
+
61
+ ### Authentication
62
+
63
+ ```bash
64
+ m365 login # Login with Device Code Flow
65
+ m365 logout # Clear stored credentials
66
+ ```
67
+
68
+ ### Mail Commands
69
+
70
+ ```bash
71
+ # List emails
72
+ m365 mail list [options]
73
+ --top <n> # Number of emails (default: 10)
74
+ --folder <name> # Folder to list (default: inbox)
75
+ --json # Output as JSON
76
+
77
+ # Supported folders:
78
+ # inbox - Inbox (default)
79
+ # sent - Sent Items
80
+ # drafts - Drafts
81
+ # deleted - Deleted Items
82
+ # junk - Junk Email
83
+ # Or use a folder ID directly
84
+
85
+ # Read email
86
+ m365 mail read <id> [options]
87
+ --force # Skip whitelist check
88
+ --json # Output as JSON
89
+
90
+ # Send email
91
+ m365 mail send <to> <subject> <body> [options]
92
+ --attach <file1> <file2> ... # Attach files
93
+ --json # Output as JSON
94
+
95
+ # Search emails
96
+ m365 mail search <query> [options]
97
+ --top <n> # Number of results (default: 10)
98
+ --json # Output as JSON
99
+
100
+ # Manage trusted senders whitelist
101
+ m365 mail trust <email> # Add to whitelist
102
+ m365 mail untrust <email> # Remove from whitelist
103
+ m365 mail trusted [options] # List whitelist
104
+ --json # Output as JSON
105
+
106
+ # List attachments
107
+ m365 mail attachments <id> [options]
108
+ --json # Output as JSON
109
+
110
+ # Download attachment
111
+ m365 mail download-attachment <message-id> <attachment-id> [local-path] [options]
112
+ --json # Output as JSON
113
+ ```
114
+
115
+ **Examples:**
116
+ ```bash
117
+ m365 mail list --top 5
118
+ m365 mail list --folder sent --top 10 # List sent emails
119
+ m365 mail list --folder drafts # List draft emails
120
+ m365 mail read AAMkADA5ZDE2Njk2...
121
+ m365 mail read AAMkADA5ZDE2Njk2... --force # Skip whitelist check
122
+ m365 mail send "user@example.com" "Meeting" "Let's meet tomorrow" --attach report.pdf
123
+ m365 mail search "project update" --top 20
124
+
125
+ # Whitelist management
126
+ m365 mail trusted # List trusted senders
127
+ m365 mail trust user@example.com # Trust specific sender
128
+ m365 mail trust @example.com # Trust entire domain
129
+ m365 mail untrust user@example.com # Remove from whitelist
130
+
131
+ # Attachment examples
132
+ m365 mail attachments AAMkADA5ZDE2Njk2... # List all attachments in an email
133
+ m365 mail download-attachment AAMkADA5... AAMkAGQ... # Download using attachment's original filename
134
+ m365 mail download-attachment AAMkADA5... AAMkAGQ... ~/Downloads/file.pdf # Specify output path
135
+ ```
136
+
137
+ ### Security: Trusted Senders Whitelist
138
+
139
+ The CLI includes a **phishing protection feature** that filters email content from untrusted senders.
140
+
141
+ **How it works:**
142
+ - When reading emails with `m365 mail read`, the sender is checked against a whitelist
143
+ - If the sender is not trusted, only metadata (sender, subject, date) is shown
144
+ - Email body is replaced with: `[Content filtered - sender not in trusted senders list]`
145
+ - Use `--force` to bypass the check when needed
146
+
147
+ 1. `~/.m365-cli/trusted-senders.txt`
148
+
149
+ **Whitelist format:**
150
+ ```
151
+ # Trust specific email addresses
152
+ user@example.com
153
+ other@example.com
154
+ user@example.com
155
+
156
+ # Trust entire domains (prefix with @)
157
+ @example.com
158
+ @microsoft.com
159
+ ```
160
+
161
+ **Management commands:**
162
+ ```bash
163
+ m365 mail trusted # View current whitelist
164
+ m365 mail trust user@example.com # Add to whitelist
165
+ m365 mail trust @example.com # Trust entire domain
166
+ m365 mail untrust user@example.com # Remove from whitelist
167
+ ```
168
+
169
+ **Special handling:**
170
+ - Internal organization emails (Exchange DN format) are automatically trusted
171
+ - Marked emails in lists show a ⚠️ warning indicator for untrusted senders
172
+
173
+ ### Calendar Commands
174
+
175
+ ```bash
176
+ # List events
177
+ m365 calendar list [options]
178
+ m365 cal list [options] # Alias
179
+ --days <n> # Look ahead N days (default: 7)
180
+ --top <n> # Maximum events (default: 50)
181
+ --json # Output as JSON
182
+
183
+ # Get event details
184
+ m365 calendar get <id> [options]
185
+ --json # Output as JSON
186
+
187
+ # Create event
188
+ m365 calendar create <title> [options]
189
+ --start <datetime> # Start time (required)
190
+ --end <datetime> # End time (required)
191
+ --location <location> # Event location
192
+ --body <description> # Event description
193
+ --attendees <email1,email2> # Attendee emails (comma-separated)
194
+ --allday # All-day event
195
+ --json # Output as JSON
196
+
197
+ # Update event
198
+ m365 calendar update <id> [options]
199
+ --title <title> # New title
200
+ --start <datetime> # New start time
201
+ --end <datetime> # New end time
202
+ --location <location> # New location
203
+ --body <description> # New description
204
+ --json # Output as JSON
205
+
206
+ # Delete event
207
+ m365 calendar delete <id> [options]
208
+ --json # Output as JSON
209
+ ```
210
+
211
+ **Datetime formats:**
212
+ - Full datetime: `2026-02-17T14:00:00`
213
+ - Date only (for all-day events): `2026-02-17`
214
+
215
+ **Examples:**
216
+ ```bash
217
+ m365 cal list --days 5
218
+ m365 cal get AAMkADA5ZDE2Njk2...
219
+ m365 cal create "Team Meeting" --start "2026-02-17T14:00:00" --end "2026-02-17T15:00:00" --location "Room A"
220
+ m365 cal create "Holiday" --start "2026-02-20" --end "2026-02-21" --allday
221
+ m365 cal update AAMkADA5... --location "Room B"
222
+ m365 cal delete AAMkADA5...
223
+ ```
224
+
225
+ ### OneDrive Commands
226
+
227
+ ```bash
228
+ # List files
229
+ m365 onedrive ls [path] [options]
230
+ m365 od ls [path] [options] # Alias
231
+ --top <n> # Maximum items (default: 100)
232
+ --json # Output as JSON
233
+
234
+ # Get file/folder metadata
235
+ m365 onedrive get <path> [options]
236
+ --json # Output as JSON
237
+
238
+ # Download file
239
+ m365 onedrive download <remote-path> [local-path] [options]
240
+ --json # Output as JSON
241
+
242
+ # Upload file
243
+ m365 onedrive upload <local-path> [remote-path] [options]
244
+ --json # Output as JSON
245
+
246
+ # Search files
247
+ m365 onedrive search <query> [options]
248
+ --top <n> # Maximum results (default: 50)
249
+ --json # Output as JSON
250
+
251
+ # Create sharing link
252
+ m365 onedrive share <path> [options]
253
+ --type <view|edit> # Link type (default: view)
254
+ --json # Output as JSON
255
+
256
+ # Create folder
257
+ m365 onedrive mkdir <path> [options]
258
+ --json # Output as JSON
259
+
260
+ # Delete file/folder
261
+ m365 onedrive rm <path> [options]
262
+ --force # Skip confirmation
263
+ --json # Output as JSON
264
+ ```
265
+
266
+ **Examples:**
267
+ ```bash
268
+ m365 od ls
269
+ m365 od ls Documents
270
+ m365 od get "Documents/report.pdf"
271
+ m365 od download "Documents/report.pdf" ~/Downloads/
272
+ m365 od upload ~/Desktop/photo.jpg "Photos/vacation.jpg"
273
+ m365 od search "budget" --top 20
274
+ m365 od share "Documents/report.pdf" --type edit
275
+ m365 od mkdir "Projects/New Project"
276
+ m365 od rm "old-file.txt" --force
277
+ ```
278
+
279
+ **Features:**
280
+ - 🚀 Large file upload support (automatic chunking for files ≥4MB)
281
+ - 📊 Progress display for downloads and uploads
282
+ - 💾 Human-readable file sizes (B/KB/MB/GB/TB)
283
+ - ⚠️ Confirmation prompt before deletion (unless `--force`)
284
+
285
+ ### SharePoint Commands
286
+
287
+ ```bash
288
+ # List sites
289
+ m365 sharepoint sites [options]
290
+ m365 sp sites [options] # Alias
291
+ --search <query> # Search for sites
292
+ --top <n> # Maximum sites (default: 50)
293
+ --json # Output as JSON
294
+
295
+ # List site lists
296
+ m365 sharepoint lists <site> [options]
297
+ --top <n> # Maximum lists (default: 100)
298
+ --json # Output as JSON
299
+
300
+ # List list items
301
+ m365 sharepoint items <site> <list> [options]
302
+ --top <n> # Maximum items (default: 100)
303
+ --json # Output as JSON
304
+
305
+ # List files in document library
306
+ m365 sharepoint files <site> [path] [options]
307
+ --top <n> # Maximum files (default: 100)
308
+ --json # Output as JSON
309
+
310
+ # Download file
311
+ m365 sharepoint download <site> <file-path> [local-path] [options]
312
+ --json # Output as JSON
313
+
314
+ # Upload file
315
+ m365 sharepoint upload <site> <local-path> [remote-path] [options]
316
+ --json # Output as JSON
317
+
318
+ # Search content
319
+ m365 sharepoint search <query> [options]
320
+ --top <n> # Maximum results (default: 50)
321
+ --json # Output as JSON
322
+ ```
323
+
324
+ **Site identifier formats:**
325
+
326
+ SharePoint commands accept sites in multiple formats:
327
+
328
+ 1. **Path format** (recommended):
329
+ ```
330
+ hostname:/sites/sitename
331
+ # Example: contoso.sharepoint.com:/sites/team
332
+ ```
333
+
334
+ 2. **Site ID format** (from `m365 sp sites` output):
335
+ ```
336
+ hostname,siteId,webId
337
+ # Example: contoso.sharepoint.com,8bfb5166-...,ea772c4f-...
338
+ ```
339
+
340
+ 3. **URL format** (for some commands):
341
+ ```
342
+ https://hostname/sites/sitename
343
+ # Example: https://contoso.sharepoint.com/sites/team
344
+ ```
345
+
346
+ **Tip:** Run `m365 sp sites --json` to get the exact site ID for any site.
347
+
348
+ **Examples:**
349
+ ```bash
350
+ m365 sp sites
351
+ m365 sp sites --search "marketing"
352
+
353
+ # Using path format (recommended)
354
+ m365 sp lists "contoso.sharepoint.com:/sites/team"
355
+
356
+ # Using site ID from sites list output
357
+ m365 sp lists "contoso.sharepoint.com,8bfb5166-7dff-4f15-8d44-3417d68f519a,ea772c4f-..."
358
+
359
+ m365 sp files "contoso.sharepoint.com:/sites/team" "Documents"
360
+ m365 sp download "contoso.sharepoint.com:/sites/team" "Documents/file.pdf"
361
+ m365 sp upload "contoso.sharepoint.com:/sites/team" ~/report.pdf "Documents/report.pdf"
362
+ m365 sp search "quarterly report" --top 20
363
+ ```
364
+
365
+ **Note:** SharePoint commands require `Sites.ReadWrite.All` permission. If you encounter permission errors, run `m365 logout` then `m365 login` to re-authenticate with updated permissions.
366
+
367
+ ## Configuration
368
+
369
+ ### Credentials Location
370
+
371
+ Credentials are stored at: `~/.m365-cli/credentials.json`
372
+
373
+ **Security:** File permissions are set to `600` (owner read/write only). Do not share this file.
374
+
375
+ ### Azure AD Application
376
+
377
+ #### Option 1: Use Existing Application (Quick Start)
378
+
379
+ This tool comes pre-configured with a shared Azure AD application:
380
+ - **Tenant ID**: `5b4c4b46-4279-4f19-9e5d-84ea285f9b9c`
381
+ - **Client ID**: `091b3d7b-e217-4410-868c-01c3ee6189b6`
382
+
383
+ No additional setup required — just run `m365 login` and you're ready to go.
384
+
385
+ #### Option 2: Create Your Own Azure AD Application
386
+
387
+ For production use or organizational requirements, you can register your own Azure AD application.
388
+
389
+ ##### Prerequisites
390
+
391
+ - Access to **Azure Portal** or **Azure CLI**
392
+ - Azure AD / Microsoft Entra ID tenant
393
+ - **Permissions**: Global Administrator or Application Administrator role
394
+
395
+ ##### Method 1: Azure Portal (Recommended for First-Time Setup)
396
+
397
+ **Step 1: Create the Application**
398
+
399
+ 1. Sign in to [Azure Portal](https://portal.azure.com)
400
+ 2. Navigate to: **Microsoft Entra ID** > **App registrations** > **New registration**
401
+ 3. Configure the application:
402
+ - **Name**: `M365 CLI` (or your preferred name)
403
+ - **Supported account types**: Select **"Accounts in this organizational directory only (Single tenant)"**
404
+ - **Redirect URI**: Leave empty (not needed for Device Code Flow)
405
+ 4. Click **Register**
406
+
407
+ **Step 2: Enable Public Client Flow**
408
+
409
+ 1. In your app's page, go to **Authentication** (left sidebar)
410
+ 2. Scroll down to **Advanced settings** > **Allow public client flows**
411
+ 3. Set **"Enable the following mobile and desktop flows"** to **Yes**
412
+ 4. Click **Save** at the top
413
+
414
+ > ⚠️ **Important**: This setting is required for Device Code Flow authentication.
415
+
416
+ **Step 3: Configure API Permissions**
417
+
418
+ 1. Go to **API permissions** (left sidebar)
419
+ 2. Click **Add a permission** > **Microsoft Graph** > **Delegated permissions**
420
+ 3. Add the following permissions:
421
+ - `Mail.ReadWrite` - Read and write mail
422
+ - `Mail.Send` - Send mail as the user
423
+ - `Calendars.ReadWrite` - Read and write calendar events
424
+ - `Files.ReadWrite.All` - Read and write all files the user can access
425
+ - `Sites.ReadWrite.All` - Read and write SharePoint sites
426
+ - `User.Read` - Sign in and read user profile (added by default)
427
+ 4. Click **Add permissions**
428
+ 5. Click **Grant admin consent for [Your Organization]** (admin approval required)
429
+ 6. Confirm by clicking **Yes**
430
+
431
+ > 💡 **Tip**: Admin consent allows all users in your organization to use the app without individual approval.
432
+
433
+ **Step 4: Get Configuration Values**
434
+
435
+ 1. Go to **Overview** page
436
+ 2. Copy the following values:
437
+ - **Application (client) ID** → This is your `CLIENT_ID`
438
+ - **Directory (tenant) ID** → This is your `TENANT_ID`
439
+
440
+ **Step 5: Configure the CLI**
441
+
442
+ Choose one of these methods:
443
+
444
+ **Option A: Environment Variables (Recommended)**
445
+ ```bash
446
+ export M365_TENANT_ID="your-tenant-id"
447
+ export M365_CLIENT_ID="your-client-id"
448
+ ```
449
+
450
+ Add these to your `~/.bashrc` or `~/.zshrc` to make them permanent.
451
+
452
+ **Option B: Configuration File**
453
+
454
+ Edit `config/default.json`:
455
+ ```json
456
+ {
457
+ "tenantId": "your-tenant-id",
458
+ "clientId": "your-client-id"
459
+ }
460
+ ```
461
+
462
+ ##### Method 2: Azure CLI (One-Command Setup)
463
+
464
+ If you have [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) installed:
465
+
466
+ ```bash
467
+ # Login to Azure
468
+ az login
469
+
470
+ # Create the application
471
+ APP_ID=$(az ad app create \
472
+ --display-name "M365 CLI" \
473
+ --sign-in-audience AzureADMyOrg \
474
+ --enable-access-token-issuance true \
475
+ --query appId -o tsv)
476
+
477
+ echo "Created app with ID: $APP_ID"
478
+
479
+ # Enable public client flow
480
+ az ad app update --id $APP_ID --is-fallback-public-client true
481
+
482
+ # Add Microsoft Graph permissions
483
+ # Permission IDs for Microsoft Graph (00000003-0000-0000-c000-000000000000):
484
+ # User.Read: e1fe6dd8-ba31-4d61-89e7-88639da4683d
485
+ # Mail.ReadWrite: e2a3a72e-5f79-4c64-b1b1-878b674786c9
486
+ # Mail.Send: e383f46e-2787-4529-855e-0e479a3ffac0
487
+ # Calendars.ReadWrite: 1ec239c2-d7c9-4623-a91a-a9775856bb36
488
+ # Files.ReadWrite.All: 5c28f0bf-8a70-41f1-8ab2-9032436ddb65
489
+ # Sites.ReadWrite.All: 89fe6a52-be36-487e-b7d8-d061c450a026
490
+
491
+ az ad app permission add --id $APP_ID \
492
+ --api 00000003-0000-0000-c000-000000000000 \
493
+ --api-permissions \
494
+ e1fe6dd8-ba31-4d61-89e7-88639da4683d=Scope \
495
+ e2a3a72e-5f79-4c64-b1b1-878b674786c9=Scope \
496
+ e383f46e-2787-4529-855e-0e479a3ffac0=Scope \
497
+ 1ec239c2-d7c9-4623-a91a-a9775856bb36=Scope \
498
+ 5c28f0bf-8a70-41f1-8ab2-9032436ddb65=Scope \
499
+ 89fe6a52-be36-487e-b7d8-d061c450a026=Scope
500
+
501
+ # Grant admin consent
502
+ az ad app permission admin-consent --id $APP_ID
503
+
504
+ # Get tenant ID
505
+ TENANT_ID=$(az account show --query tenantId -o tsv)
506
+
507
+ # Display configuration
508
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
509
+ echo "✅ Azure AD Application Created Successfully"
510
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
511
+ echo "Tenant ID: $TENANT_ID"
512
+ echo "Client ID: $APP_ID"
513
+ echo ""
514
+ echo "Configure the CLI with:"
515
+ echo "export M365_TENANT_ID=\"$TENANT_ID\""
516
+ echo "export M365_CLIENT_ID=\"$APP_ID\""
517
+ ```
518
+
519
+ Copy the output values and configure them as shown in Step 5 above.
520
+
521
+ ##### Verification
522
+
523
+ After configuration, test the setup:
524
+
525
+ ```bash
526
+ # Login with your custom app
527
+ m365 login
528
+
529
+ # Test basic functionality
530
+ m365 mail list --top 3
531
+ ```
532
+
533
+ You should see the Device Code Flow prompt. Follow the authentication steps in your browser.
534
+
535
+ ### Permissions
536
+
537
+ The application requests the following Microsoft Graph permissions:
538
+ - `Mail.ReadWrite` - Read and write mail
539
+ - `Mail.Send` - Send mail
540
+ - `Calendars.ReadWrite` - Read and write calendar events
541
+ - `Files.ReadWrite.All` - Read and write files in OneDrive
542
+ - `Sites.ReadWrite.All` - Read and write SharePoint sites
543
+
544
+ ## Output Formats
545
+
546
+ ### Default (Text)
547
+
548
+ Clean, human-readable output with emoji icons:
549
+
550
+ ```
551
+ 📧 Mail List (top 3)
552
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
553
+ [1] 📩 Meeting Reminder
554
+ From: alice@example.com
555
+ Date: 2026-02-16 09:30
556
+ ID: AAMkAG...
557
+ ```
558
+
559
+ ### JSON (--json)
560
+
561
+ Structured output for scripting and AI consumption:
562
+
563
+ ```json
564
+ [
565
+ {
566
+ "id": "AAMkAG...",
567
+ "subject": "Meeting Reminder",
568
+ "from": {
569
+ "emailAddress": {
570
+ "name": "Alice",
571
+ "address": "alice@example.com"
572
+ }
573
+ },
574
+ "receivedDateTime": "2026-02-16T09:30:00Z",
575
+ "isRead": false
576
+ }
577
+ ]
578
+ ```
579
+
580
+ ## Project Structure
581
+
582
+ ```
583
+ m365-cli/
584
+ ├── bin/
585
+ │ └── m365.js # CLI entry point
586
+ ├── src/
587
+ │ ├── auth/ # Authentication
588
+ │ │ ├── token-manager.js # Token storage & refresh
589
+ │ │ └── device-flow.js # Device Code Flow
590
+ │ ├── graph/ # Graph API client
591
+ │ │ └── client.js # HTTP client with auto-refresh
592
+ │ ├── commands/ # Command implementations
593
+ │ │ ├── mail.js # Mail commands
594
+ │ │ ├── calendar.js # Calendar commands
595
+ │ │ ├── onedrive.js # OneDrive commands
596
+ │ │ └── sharepoint.js # SharePoint commands
597
+ │ └── utils/ # Utilities
598
+ │ ├── config.js # Config management
599
+ │ ├── output.js # Output formatting
600
+ │ └── error.js # Error handling
601
+ ├── config/
602
+ │ └── default.json # Default configuration
603
+ ├── package.json # Project metadata
604
+ ├── README.md # This file
605
+ └── PLAN.md # Development roadmap
606
+ ```
607
+
608
+ ## Development
609
+
610
+ ### Tech Stack
611
+
612
+ - **Node.js 18+** - ESM modules, native fetch API
613
+ - **commander.js** - CLI framework
614
+ - **Microsoft Graph API** - M365 services
615
+
616
+ ### Local Testing
617
+
618
+ ```bash
619
+ # Link for local development
620
+ npm link
621
+
622
+ # Test commands
623
+ m365 --help
624
+ m365 mail --help
625
+ m365 mail list --top 3
626
+ ```
627
+
628
+ ## Troubleshooting
629
+
630
+ ### "Not authenticated" error
631
+
632
+ Run `m365 login` to authenticate.
633
+
634
+ ### Token expired
635
+
636
+ Tokens refresh automatically. If refresh fails, run `m365 login` again.
637
+
638
+ ### Permission denied (SharePoint)
639
+
640
+ SharePoint requires additional permissions. Run:
641
+ ```bash
642
+ m365 logout
643
+ m365 login
644
+ ```
645
+
646
+ ### Network errors
647
+
648
+ - Check internet connection
649
+ - Verify firewall settings
650
+ - Ensure Microsoft Graph API is accessible
651
+
652
+ ## Roadmap
653
+
654
+ - [x] **Phase 1**: Framework + Mail ✅
655
+ - [x] **Phase 2**: Calendar ✅
656
+ - [x] **Phase 3**: OneDrive ✅
657
+ - [x] **Phase 3.5**: SharePoint ✅
658
+ - [ ] **Phase 4**: Contacts & Advanced Features
659
+ - [ ] **Phase 5**: Optimization & Release
660
+
661
+ See [PLAN.md](./PLAN.md) for detailed roadmap and implementation notes.
662
+
663
+ ## Security
664
+
665
+ - ✅ Credentials stored with `600` permissions
666
+ - ✅ OAuth 2.0 Device Code Flow
667
+ - ✅ Automatic token refresh
668
+ - ✅ No sensitive data in logs
669
+ - ✅ HTTPS-only communication
670
+
671
+ ## License
672
+
673
+ MIT License - see LICENSE file for details.
674
+
675
+ ## Contributing
676
+
677
+ Contributions welcome! Please open an issue or PR.
678
+
679
+ ---
680
+
681
+ **Current Version**: 0.1.0
682
+ **Status**: Phases 1-3 Complete ✅
683
+ **Updated**: 2026-02-16