m365-agent-cli 1.2.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.
Files changed (92) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +916 -0
  3. package/package.json +50 -0
  4. package/src/cli.ts +100 -0
  5. package/src/commands/auto-reply.ts +182 -0
  6. package/src/commands/calendar.ts +576 -0
  7. package/src/commands/counter.ts +87 -0
  8. package/src/commands/create-event.ts +544 -0
  9. package/src/commands/delegates.ts +286 -0
  10. package/src/commands/delete-event.ts +321 -0
  11. package/src/commands/drafts.ts +502 -0
  12. package/src/commands/files.ts +532 -0
  13. package/src/commands/find.ts +195 -0
  14. package/src/commands/findtime.ts +270 -0
  15. package/src/commands/folders.ts +177 -0
  16. package/src/commands/forward-event.ts +49 -0
  17. package/src/commands/graph-calendar.ts +217 -0
  18. package/src/commands/login.ts +195 -0
  19. package/src/commands/mail.ts +950 -0
  20. package/src/commands/oof.ts +263 -0
  21. package/src/commands/outlook-categories.ts +173 -0
  22. package/src/commands/outlook-graph.ts +880 -0
  23. package/src/commands/planner.ts +1678 -0
  24. package/src/commands/respond.ts +291 -0
  25. package/src/commands/rooms.ts +210 -0
  26. package/src/commands/rules.ts +511 -0
  27. package/src/commands/schedule.ts +109 -0
  28. package/src/commands/send.ts +204 -0
  29. package/src/commands/serve.ts +14 -0
  30. package/src/commands/sharepoint.ts +179 -0
  31. package/src/commands/site-pages.ts +163 -0
  32. package/src/commands/subscribe.ts +103 -0
  33. package/src/commands/subscriptions.ts +29 -0
  34. package/src/commands/suggest.ts +155 -0
  35. package/src/commands/todo.ts +2092 -0
  36. package/src/commands/update-event.ts +608 -0
  37. package/src/commands/update.ts +88 -0
  38. package/src/commands/verify-token.ts +62 -0
  39. package/src/commands/whoami.ts +74 -0
  40. package/src/index.ts +190 -0
  41. package/src/lib/atomic-write.ts +20 -0
  42. package/src/lib/attach-link-spec.test.ts +24 -0
  43. package/src/lib/attach-link-spec.ts +70 -0
  44. package/src/lib/attachments.ts +79 -0
  45. package/src/lib/auth.ts +192 -0
  46. package/src/lib/calendar-range.test.ts +41 -0
  47. package/src/lib/calendar-range.ts +103 -0
  48. package/src/lib/dates.test.ts +74 -0
  49. package/src/lib/dates.ts +137 -0
  50. package/src/lib/delegate-client.test.ts +74 -0
  51. package/src/lib/delegate-client.ts +322 -0
  52. package/src/lib/ews-client.ts +3418 -0
  53. package/src/lib/git-commit.ts +4 -0
  54. package/src/lib/glitchtip-eligibility.ts +220 -0
  55. package/src/lib/glitchtip.ts +253 -0
  56. package/src/lib/global-env.ts +3 -0
  57. package/src/lib/graph-auth.ts +223 -0
  58. package/src/lib/graph-calendar-client.test.ts +118 -0
  59. package/src/lib/graph-calendar-client.ts +112 -0
  60. package/src/lib/graph-client.test.ts +107 -0
  61. package/src/lib/graph-client.ts +1058 -0
  62. package/src/lib/graph-constants.ts +12 -0
  63. package/src/lib/graph-directory.ts +116 -0
  64. package/src/lib/graph-event.ts +134 -0
  65. package/src/lib/graph-schedule.ts +173 -0
  66. package/src/lib/graph-subscriptions.ts +94 -0
  67. package/src/lib/graph-user-path.ts +13 -0
  68. package/src/lib/jwt-utils.ts +34 -0
  69. package/src/lib/markdown.test.ts +21 -0
  70. package/src/lib/markdown.ts +174 -0
  71. package/src/lib/mime-type.ts +106 -0
  72. package/src/lib/oof-client.test.ts +59 -0
  73. package/src/lib/oof-client.ts +122 -0
  74. package/src/lib/outlook-graph-client.test.ts +146 -0
  75. package/src/lib/outlook-graph-client.ts +649 -0
  76. package/src/lib/outlook-master-categories.ts +145 -0
  77. package/src/lib/package-info.ts +59 -0
  78. package/src/lib/places-client.ts +144 -0
  79. package/src/lib/planner-client.ts +1226 -0
  80. package/src/lib/rules-client.ts +178 -0
  81. package/src/lib/sharepoint-client.ts +101 -0
  82. package/src/lib/site-pages-client.ts +73 -0
  83. package/src/lib/todo-client.test.ts +298 -0
  84. package/src/lib/todo-client.ts +1309 -0
  85. package/src/lib/url-validation.ts +40 -0
  86. package/src/lib/utils.ts +45 -0
  87. package/src/lib/webhook-server.ts +51 -0
  88. package/src/test/auth.test.ts +104 -0
  89. package/src/test/cli.integration.test.ts +1083 -0
  90. package/src/test/ews-client.test.ts +268 -0
  91. package/src/test/mocks/index.ts +375 -0
  92. package/src/test/mocks/responses.ts +861 -0
@@ -0,0 +1,155 @@
1
+ import { Command } from 'commander';
2
+ import { resolveGraphAuth } from '../lib/graph-auth.js';
3
+ import { type AttendeeBase, type FindMeetingTimesRequest, findMeetingTimes } from '../lib/graph-schedule.js';
4
+
5
+ export const suggestCommand = new Command('suggest')
6
+ .description('AI meeting time suggestions')
7
+ .option('--attendees <emails>', 'Comma-separated email addresses to invite')
8
+ .option('--duration <duration>', 'Duration (e.g., 30m, 1h)', '30m')
9
+ .option('--days <days>', 'Number of days to check from now', '5')
10
+ .option('--json', 'Output as JSON')
11
+ .option('--token <token>', 'Graph access token (bypass interactive auth)')
12
+ .option('--identity <name>', 'Graph token cache identity (default: default)')
13
+ .option('--user <email>', 'Mailbox whose calendar is used for findMeetingTimes (delegation)')
14
+ .action(
15
+ async (options: {
16
+ attendees?: string;
17
+ duration: string;
18
+ days: string;
19
+ json?: boolean;
20
+ token?: string;
21
+ identity?: string;
22
+ user?: string;
23
+ }) => {
24
+ const authResult = await resolveGraphAuth({ token: options.token, identity: options.identity });
25
+ if (!authResult.success || !authResult.token) {
26
+ if (options.json) {
27
+ console.log(JSON.stringify({ error: authResult.error }, null, 2));
28
+ } else {
29
+ console.error(`Error: ${authResult.error}`);
30
+ }
31
+ process.exit(1);
32
+ }
33
+
34
+ const durationMapping: Record<string, string> = {
35
+ '15m': 'PT15M',
36
+ '30m': 'PT30M',
37
+ '45m': 'PT45M',
38
+ '1h': 'PT1H',
39
+ '2h': 'PT2H'
40
+ };
41
+
42
+ const durationKey = options.duration.trim().toLowerCase();
43
+ if (!Object.hasOwn(durationMapping, durationKey)) {
44
+ const message = `Invalid duration "${options.duration}". Supported values are: ${Object.keys(durationMapping).join(', ')}.`;
45
+ if (options.json) {
46
+ console.log(JSON.stringify({ error: message }, null, 2));
47
+ } else {
48
+ console.error(`Error: ${message}`);
49
+ }
50
+ process.exit(1);
51
+ }
52
+
53
+ const durationStr = durationMapping[durationKey];
54
+ const days = parseInt(options.days, 10) || 5;
55
+
56
+ const startDateTime = new Date();
57
+ const endDateTime = new Date(startDateTime);
58
+ endDateTime.setDate(startDateTime.getDate() + days);
59
+
60
+ // dateTime should not include Z/offset - keep dateTime and timeZone separate
61
+ const startDateTimeISO = startDateTime.toISOString().replace('Z', '');
62
+ const endDateTimeISO = endDateTime.toISOString().replace('Z', '');
63
+
64
+ const attendeesList: AttendeeBase[] = options.attendees
65
+ ? options.attendees.split(',').map((email) => ({
66
+ type: 'required' as const,
67
+ emailAddress: {
68
+ address: email.trim()
69
+ }
70
+ }))
71
+ : [];
72
+
73
+ const request: FindMeetingTimesRequest = {
74
+ attendees: attendeesList.length > 0 ? attendeesList : undefined,
75
+ meetingDuration: durationStr,
76
+ timeConstraint: {
77
+ activityDomain: 'work',
78
+ timeSlots: [
79
+ {
80
+ start: {
81
+ dateTime: startDateTimeISO,
82
+ timeZone: 'UTC'
83
+ },
84
+ end: {
85
+ dateTime: endDateTimeISO,
86
+ timeZone: 'UTC'
87
+ }
88
+ }
89
+ ]
90
+ },
91
+ isOrganizerOptional: false,
92
+ returnSuggestionReasons: true,
93
+ minimumAttendeePercentage: 100
94
+ };
95
+
96
+ const result = await findMeetingTimes(authResult.token, request, options.user);
97
+
98
+ if (!result.ok || !result.data) {
99
+ if (options.json) {
100
+ console.log(JSON.stringify({ error: result.error }, null, 2));
101
+ } else {
102
+ console.error('Error finding meeting times:', result.error?.message || 'Unknown error');
103
+ }
104
+ process.exit(1);
105
+ }
106
+
107
+ if (options.json) {
108
+ console.log(JSON.stringify(result.data, null, 2));
109
+ return;
110
+ }
111
+
112
+ const { emptySuggestionsReason, meetingTimeSuggestions } = result.data;
113
+
114
+ console.log('\nAI Meeting Time Suggestions:\n');
115
+
116
+ if (emptySuggestionsReason) {
117
+ console.log('No suitable meeting times found for the following reason:');
118
+ console.log(` - ${emptySuggestionsReason}`);
119
+ return;
120
+ }
121
+
122
+ if (!meetingTimeSuggestions || meetingTimeSuggestions.length === 0) {
123
+ console.log('No suggestions found.');
124
+ return;
125
+ }
126
+
127
+ for (const suggestion of meetingTimeSuggestions) {
128
+ const start = suggestion.meetingTimeSlot?.start?.dateTime
129
+ ? new Date(`${suggestion.meetingTimeSlot.start.dateTime}Z`).toLocaleString()
130
+ : 'Unknown';
131
+ const end = suggestion.meetingTimeSlot?.end?.dateTime
132
+ ? new Date(`${suggestion.meetingTimeSlot.end.dateTime}Z`).toLocaleString()
133
+ : 'Unknown';
134
+
135
+ const confidence = suggestion.confidence !== undefined ? `${suggestion.confidence}%` : 'Unknown';
136
+
137
+ console.log(`Suggestion: ${start} - ${end}`);
138
+ console.log(` Confidence: ${confidence}`);
139
+
140
+ if (suggestion.suggestionReason) {
141
+ console.log(` Reason: ${suggestion.suggestionReason}`);
142
+ }
143
+
144
+ if (suggestion.attendeeAvailability && suggestion.attendeeAvailability.length > 0) {
145
+ console.log(' Attendee Availability:');
146
+ for (const attendee of suggestion.attendeeAvailability) {
147
+ const email = attendee.attendee?.emailAddress?.address || 'Unknown';
148
+ const status = attendee.availability || 'Unknown';
149
+ console.log(` - ${email}: ${status}`);
150
+ }
151
+ }
152
+ console.log();
153
+ }
154
+ }
155
+ );