nothumanallowed 4.1.0 → 6.0.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/package.json +10 -3
- package/src/cli.mjs +181 -5
- package/src/commands/autostart.mjs +342 -0
- package/src/commands/chat.mjs +14 -8
- package/src/commands/microsoft-auth.mjs +29 -0
- package/src/commands/ops.mjs +37 -0
- package/src/commands/plugin.mjs +481 -0
- package/src/commands/ui.mjs +28 -7
- package/src/commands/voice.mjs +845 -0
- package/src/config.mjs +61 -0
- package/src/constants.mjs +9 -1
- package/src/services/llm.mjs +22 -1
- package/src/services/mail-router.mjs +298 -0
- package/src/services/memory.mjs +627 -0
- package/src/services/message-responder.mjs +778 -0
- package/src/services/microsoft-calendar.mjs +319 -0
- package/src/services/microsoft-mail.mjs +308 -0
- package/src/services/microsoft-oauth.mjs +345 -0
- package/src/services/ops-daemon.mjs +620 -11
- package/src/services/ops-pipeline.mjs +7 -8
- package/src/services/token-store.mjs +41 -14
- package/src/services/tool-executor.mjs +392 -0
- package/src/services/web-ui.mjs +187 -1
package/src/config.mjs
CHANGED
|
@@ -52,6 +52,11 @@ const DEFAULT_CONFIG = {
|
|
|
52
52
|
clientId: '',
|
|
53
53
|
clientSecret: '',
|
|
54
54
|
},
|
|
55
|
+
microsoft: {
|
|
56
|
+
clientId: '',
|
|
57
|
+
clientSecret: '',
|
|
58
|
+
tenantId: 'common',
|
|
59
|
+
},
|
|
55
60
|
ops: {
|
|
56
61
|
enabled: false,
|
|
57
62
|
planTime: '07:00',
|
|
@@ -67,6 +72,33 @@ const DEFAULT_CONFIG = {
|
|
|
67
72
|
desktop: true,
|
|
68
73
|
terminal: true,
|
|
69
74
|
},
|
|
75
|
+
proactive: {
|
|
76
|
+
enabled: true,
|
|
77
|
+
emailFollowUp: true,
|
|
78
|
+
meetingPrep: true,
|
|
79
|
+
patterns: true,
|
|
80
|
+
deadlines: true,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
responder: {
|
|
84
|
+
autoRoute: true,
|
|
85
|
+
telegram: {
|
|
86
|
+
token: '',
|
|
87
|
+
allowedChatIds: [],
|
|
88
|
+
},
|
|
89
|
+
discord: {
|
|
90
|
+
token: '',
|
|
91
|
+
allowedChannelIds: [],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
plugins: {
|
|
95
|
+
autoRun: true,
|
|
96
|
+
directory: '',
|
|
97
|
+
},
|
|
98
|
+
voice: {
|
|
99
|
+
preferWhisper: false,
|
|
100
|
+
speechSynthesis: true,
|
|
101
|
+
language: '',
|
|
70
102
|
},
|
|
71
103
|
};
|
|
72
104
|
|
|
@@ -174,11 +206,28 @@ export function setConfigValue(key, value) {
|
|
|
174
206
|
'knowledge': 'features.knowledgeEnabled',
|
|
175
207
|
'google-client-id': 'google.clientId',
|
|
176
208
|
'google-client-secret': 'google.clientSecret',
|
|
209
|
+
'microsoft-client-id': 'microsoft.clientId',
|
|
210
|
+
'microsoft-client-secret': 'microsoft.clientSecret',
|
|
211
|
+
'microsoft-tenant': 'microsoft.tenantId',
|
|
212
|
+
'microsoft-tenant-id': 'microsoft.tenantId',
|
|
177
213
|
'plan-time': 'ops.planTime',
|
|
178
214
|
'summary-time': 'ops.summaryTime',
|
|
179
215
|
'meeting-alert': 'ops.meetingAlertMinutes',
|
|
180
216
|
'telegram-webhook': 'ops.webhooks.telegram',
|
|
181
217
|
'discord-webhook': 'ops.webhooks.discord',
|
|
218
|
+
'plugin-autorun': 'plugins.autoRun',
|
|
219
|
+
'plugin-dir': 'plugins.directory',
|
|
220
|
+
'voice-whisper': 'voice.preferWhisper',
|
|
221
|
+
'voice-speech': 'voice.speechSynthesis',
|
|
222
|
+
'voice-language': 'voice.language',
|
|
223
|
+
'telegram-bot-token': 'responder.telegram.token',
|
|
224
|
+
'discord-bot-token': 'responder.discord.token',
|
|
225
|
+
'responder-auto-route': 'responder.autoRoute',
|
|
226
|
+
'proactive': 'ops.proactive.enabled',
|
|
227
|
+
'proactive-email': 'ops.proactive.emailFollowUp',
|
|
228
|
+
'proactive-meeting': 'ops.proactive.meetingPrep',
|
|
229
|
+
'proactive-patterns': 'ops.proactive.patterns',
|
|
230
|
+
'proactive-deadlines': 'ops.proactive.deadlines',
|
|
182
231
|
};
|
|
183
232
|
|
|
184
233
|
const resolved = aliases[key] || key;
|
|
@@ -199,6 +248,18 @@ export function setConfigValue(key, value) {
|
|
|
199
248
|
obj[lastKey] = value === 'true' || value === '1' || value === 'yes';
|
|
200
249
|
} else if (typeof existing === 'number') {
|
|
201
250
|
obj[lastKey] = Number(value);
|
|
251
|
+
} else if (Array.isArray(existing)) {
|
|
252
|
+
// Parse comma-separated values or JSON array
|
|
253
|
+
try {
|
|
254
|
+
const parsed = JSON.parse(value);
|
|
255
|
+
obj[lastKey] = Array.isArray(parsed) ? parsed : [parsed];
|
|
256
|
+
} catch {
|
|
257
|
+
obj[lastKey] = value.split(',').map(v => {
|
|
258
|
+
const trimmed = v.trim();
|
|
259
|
+
const num = Number(trimmed);
|
|
260
|
+
return !isNaN(num) && trimmed !== '' ? num : trimmed;
|
|
261
|
+
}).filter(Boolean);
|
|
262
|
+
}
|
|
202
263
|
} else {
|
|
203
264
|
obj[lastKey] = value;
|
|
204
265
|
}
|
package/src/constants.mjs
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import os from 'os';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
export const VERSION = '6.0.0';
|
|
5
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
6
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
7
11
|
|
|
@@ -9,6 +13,7 @@ export const NHA_DIR = path.join(os.homedir(), '.nha');
|
|
|
9
13
|
export const CORE_DIR = path.join(NHA_DIR, 'core');
|
|
10
14
|
export const AGENTS_DIR = path.join(NHA_DIR, 'agents');
|
|
11
15
|
export const EXTENSIONS_DIR = path.join(NHA_DIR, 'extensions');
|
|
16
|
+
export const PLUGINS_DIR = path.join(NHA_DIR, 'plugins');
|
|
12
17
|
export const SESSIONS_DIR = path.join(NHA_DIR, 'sessions');
|
|
13
18
|
export const MEMORY_DIR = path.join(NHA_DIR, 'memory');
|
|
14
19
|
export const CONFIG_FILE = path.join(NHA_DIR, 'config.json');
|
|
@@ -18,6 +23,9 @@ export const PIF_FILE = path.join(CORE_DIR, 'pif.mjs');
|
|
|
18
23
|
export const VERSIONS_FILE = path.join(CORE_DIR, 'versions.json');
|
|
19
24
|
export const LAST_UPDATE_CHECK = path.join(CORE_DIR, '.last-update-check');
|
|
20
25
|
|
|
26
|
+
/** Path to the daemon script within the installed npm package. */
|
|
27
|
+
export const DAEMON_SCRIPT = path.resolve(path.join(__dirname, 'services', 'ops-daemon.mjs'));
|
|
28
|
+
|
|
21
29
|
export const AGENTS = [
|
|
22
30
|
'ade', 'athena', 'atlas', 'babel', 'cartographer', 'cassandra', 'conductor',
|
|
23
31
|
'cron', 'echo', 'edi', 'epicure', 'flux', 'forge', 'glitch', 'heimdall',
|
package/src/services/llm.mjs
CHANGED
|
@@ -278,6 +278,9 @@ export async function callLLM(config, systemPrompt, userMessage, opts = {}) {
|
|
|
278
278
|
/**
|
|
279
279
|
* Call an agent by name — loads the agent file, calls LLM, returns response.
|
|
280
280
|
* No streaming. Used by PAO pipeline for batch agent calls.
|
|
281
|
+
*
|
|
282
|
+
* Automatically injects relevant episodic memories into the prompt
|
|
283
|
+
* and extracts key facts from the response for future retrieval.
|
|
281
284
|
*/
|
|
282
285
|
export async function callAgent(config, agentName, userMessage, opts = {}) {
|
|
283
286
|
const { AGENTS_DIR } = await import('../constants.mjs');
|
|
@@ -291,7 +294,25 @@ export async function callAgent(config, agentName, userMessage, opts = {}) {
|
|
|
291
294
|
const { systemPrompt } = parseAgentFile(source, agentName);
|
|
292
295
|
if (!systemPrompt) throw new Error(`Agent ${agentName} has no SYSTEM_PROMPT`);
|
|
293
296
|
|
|
294
|
-
|
|
297
|
+
// ── Episodic Memory: inject relevant past interactions ──────────────────
|
|
298
|
+
let enrichedSystemPrompt = systemPrompt;
|
|
299
|
+
try {
|
|
300
|
+
const { buildMemoryContext } = await import('./memory.mjs');
|
|
301
|
+
const memoryContext = buildMemoryContext(agentName, userMessage);
|
|
302
|
+
if (memoryContext) {
|
|
303
|
+
enrichedSystemPrompt = systemPrompt + memoryContext;
|
|
304
|
+
}
|
|
305
|
+
} catch { /* memory unavailable — proceed without it */ }
|
|
306
|
+
|
|
307
|
+
const response = await callLLM(config, enrichedSystemPrompt, userMessage, opts);
|
|
308
|
+
|
|
309
|
+
// ── Episodic Memory: extract key facts from the interaction ─────────────
|
|
310
|
+
try {
|
|
311
|
+
const { extractMemory } = await import('./memory.mjs');
|
|
312
|
+
extractMemory(agentName, userMessage, response);
|
|
313
|
+
} catch { /* memory extraction failed — non-critical */ }
|
|
314
|
+
|
|
315
|
+
return response;
|
|
295
316
|
}
|
|
296
317
|
|
|
297
318
|
// ── Agent File Parser (shared) ─────────────────────────────────────────────
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Mail + Calendar router — routes to Google or Microsoft based on auth state.
|
|
3
|
+
*
|
|
4
|
+
* Detects which provider is authenticated and routes all mail/calendar calls
|
|
5
|
+
* through the appropriate service. If both are authenticated, prefers the
|
|
6
|
+
* provider specified in config, falling back to the first authenticated one.
|
|
7
|
+
*
|
|
8
|
+
* All functions return the same unified data shapes defined by google-gmail.mjs
|
|
9
|
+
* and google-calendar.mjs parsers (Microsoft services normalize to the same shape).
|
|
10
|
+
*
|
|
11
|
+
* Zero dependencies — pure routing layer.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { getAuthenticatedProviders, loadTokens } from './token-store.mjs';
|
|
15
|
+
|
|
16
|
+
// Lazy imports to avoid loading both provider modules at startup
|
|
17
|
+
let _google = null;
|
|
18
|
+
let _microsoft = null;
|
|
19
|
+
let _googleCal = null;
|
|
20
|
+
let _microsoftCal = null;
|
|
21
|
+
|
|
22
|
+
async function getGoogleMail() {
|
|
23
|
+
if (!_google) _google = await import('./google-gmail.mjs');
|
|
24
|
+
return _google;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function getMicrosoftMail() {
|
|
28
|
+
if (!_microsoft) _microsoft = await import('./microsoft-mail.mjs');
|
|
29
|
+
return _microsoft;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function getGoogleCalendar() {
|
|
33
|
+
if (!_googleCal) _googleCal = await import('./google-calendar.mjs');
|
|
34
|
+
return _googleCal;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function getMicrosoftCalendar() {
|
|
38
|
+
if (!_microsoftCal) _microsoftCal = await import('./microsoft-calendar.mjs');
|
|
39
|
+
return _microsoftCal;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Determine which mail provider to use.
|
|
44
|
+
* @param {object} config — NHA config
|
|
45
|
+
* @returns {'google' | 'microsoft' | null}
|
|
46
|
+
*/
|
|
47
|
+
export function detectMailProvider(config) {
|
|
48
|
+
const providers = getAuthenticatedProviders();
|
|
49
|
+
|
|
50
|
+
// If a preferred provider is set in config and authenticated, use it
|
|
51
|
+
const preferred = config.ops?.mailProvider;
|
|
52
|
+
if (preferred && providers[preferred]) return preferred;
|
|
53
|
+
|
|
54
|
+
// Otherwise, use whichever is authenticated (Google first for backward compat)
|
|
55
|
+
if (providers.google) return 'google';
|
|
56
|
+
if (providers.microsoft) return 'microsoft';
|
|
57
|
+
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Check if any mail provider is authenticated.
|
|
63
|
+
*/
|
|
64
|
+
export function hasMailProvider() {
|
|
65
|
+
const providers = getAuthenticatedProviders();
|
|
66
|
+
return providers.google || providers.microsoft;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get authentication status for display purposes.
|
|
71
|
+
*/
|
|
72
|
+
export function getProviderStatus() {
|
|
73
|
+
const providers = getAuthenticatedProviders();
|
|
74
|
+
const result = [];
|
|
75
|
+
|
|
76
|
+
if (providers.google) {
|
|
77
|
+
const tokens = loadTokens('google');
|
|
78
|
+
result.push({ provider: 'google', email: tokens?.email || 'unknown', active: true });
|
|
79
|
+
}
|
|
80
|
+
if (providers.microsoft) {
|
|
81
|
+
const tokens = loadTokens('microsoft');
|
|
82
|
+
result.push({ provider: 'microsoft', email: tokens?.email || 'unknown', active: true });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ── Mail Functions ─────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* List messages matching a query.
|
|
92
|
+
*/
|
|
93
|
+
export async function listMessages(config, query = '', maxResults = 20) {
|
|
94
|
+
const provider = detectMailProvider(config);
|
|
95
|
+
if (!provider) throw new Error('No mail provider authenticated. Run: nha google auth OR nha microsoft auth');
|
|
96
|
+
|
|
97
|
+
if (provider === 'microsoft') {
|
|
98
|
+
const ms = await getMicrosoftMail();
|
|
99
|
+
return ms.listMessages(config, query, maxResults);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const gm = await getGoogleMail();
|
|
103
|
+
return gm.listMessages(config, query || 'is:unread', maxResults);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get a full message by ID.
|
|
108
|
+
*/
|
|
109
|
+
export async function getMessage(config, messageId) {
|
|
110
|
+
const provider = detectMailProvider(config);
|
|
111
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
112
|
+
|
|
113
|
+
if (provider === 'microsoft') {
|
|
114
|
+
const ms = await getMicrosoftMail();
|
|
115
|
+
return ms.getMessage(config, messageId);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const gm = await getGoogleMail();
|
|
119
|
+
return gm.getMessage(config, messageId);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get unread important emails (for daily planner).
|
|
124
|
+
*/
|
|
125
|
+
export async function getUnreadImportant(config, maxResults = 30) {
|
|
126
|
+
const provider = detectMailProvider(config);
|
|
127
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
128
|
+
|
|
129
|
+
if (provider === 'microsoft') {
|
|
130
|
+
const ms = await getMicrosoftMail();
|
|
131
|
+
return ms.getUnreadImportant(config, maxResults);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const gm = await getGoogleMail();
|
|
135
|
+
return gm.getUnreadImportant(config, maxResults);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get today's emails.
|
|
140
|
+
*/
|
|
141
|
+
export async function getTodayEmails(config, maxResults = 50) {
|
|
142
|
+
const provider = detectMailProvider(config);
|
|
143
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
144
|
+
|
|
145
|
+
if (provider === 'microsoft') {
|
|
146
|
+
const ms = await getMicrosoftMail();
|
|
147
|
+
return ms.getTodayEmails(config, maxResults);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const gm = await getGoogleMail();
|
|
151
|
+
return gm.getTodayEmails(config, maxResults);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Send an email.
|
|
156
|
+
*/
|
|
157
|
+
export async function sendEmail(config, to, subject, body, opts = {}) {
|
|
158
|
+
const provider = detectMailProvider(config);
|
|
159
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
160
|
+
|
|
161
|
+
if (provider === 'microsoft') {
|
|
162
|
+
const ms = await getMicrosoftMail();
|
|
163
|
+
return ms.sendEmail(config, to, subject, body, opts);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const gm = await getGoogleMail();
|
|
167
|
+
return gm.sendEmail(config, to, subject, body, opts);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Create a draft email.
|
|
172
|
+
*/
|
|
173
|
+
export async function createDraft(config, to, subject, body) {
|
|
174
|
+
const provider = detectMailProvider(config);
|
|
175
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
176
|
+
|
|
177
|
+
if (provider === 'microsoft') {
|
|
178
|
+
const ms = await getMicrosoftMail();
|
|
179
|
+
return ms.createDraft(config, to, subject, body);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const gm = await getGoogleMail();
|
|
183
|
+
return gm.createDraft(config, to, subject, body);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get user's email profile.
|
|
188
|
+
*/
|
|
189
|
+
export async function getProfile(config) {
|
|
190
|
+
const provider = detectMailProvider(config);
|
|
191
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
192
|
+
|
|
193
|
+
if (provider === 'microsoft') {
|
|
194
|
+
const ms = await getMicrosoftMail();
|
|
195
|
+
return ms.getProfile(config);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const gm = await getGoogleMail();
|
|
199
|
+
return gm.getProfile(config);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ── Calendar Functions ────────────────────────────────────────────────────
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get today's events from all calendars.
|
|
206
|
+
*/
|
|
207
|
+
export async function getTodayEvents(config) {
|
|
208
|
+
const provider = detectMailProvider(config);
|
|
209
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
210
|
+
|
|
211
|
+
if (provider === 'microsoft') {
|
|
212
|
+
const ms = await getMicrosoftCalendar();
|
|
213
|
+
return ms.getTodayEvents(config);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const gc = await getGoogleCalendar();
|
|
217
|
+
return gc.getTodayEvents(config);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get upcoming events (next N hours).
|
|
222
|
+
*/
|
|
223
|
+
export async function getUpcomingEvents(config, hours = 2) {
|
|
224
|
+
const provider = detectMailProvider(config);
|
|
225
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
226
|
+
|
|
227
|
+
if (provider === 'microsoft') {
|
|
228
|
+
const ms = await getMicrosoftCalendar();
|
|
229
|
+
return ms.getUpcomingEvents(config, hours);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const gc = await getGoogleCalendar();
|
|
233
|
+
return gc.getUpcomingEvents(config, hours);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get events for a specific date.
|
|
238
|
+
*/
|
|
239
|
+
export async function getEventsForDate(config, date) {
|
|
240
|
+
const provider = detectMailProvider(config);
|
|
241
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
242
|
+
|
|
243
|
+
if (provider === 'microsoft') {
|
|
244
|
+
const ms = await getMicrosoftCalendar();
|
|
245
|
+
return ms.getEventsForDate(config, date);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const gc = await getGoogleCalendar();
|
|
249
|
+
return gc.getEventsForDate(config, date);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Create a new calendar event.
|
|
254
|
+
*/
|
|
255
|
+
export async function createEvent(config, event, calendarId = 'primary') {
|
|
256
|
+
const provider = detectMailProvider(config);
|
|
257
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
258
|
+
|
|
259
|
+
if (provider === 'microsoft') {
|
|
260
|
+
const ms = await getMicrosoftCalendar();
|
|
261
|
+
return ms.createEvent(config, event, calendarId);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const gc = await getGoogleCalendar();
|
|
265
|
+
return gc.createEvent(config, event, calendarId);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Update an existing calendar event.
|
|
270
|
+
*/
|
|
271
|
+
export async function updateEvent(config, calendarId, eventId, patch) {
|
|
272
|
+
const provider = detectMailProvider(config);
|
|
273
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
274
|
+
|
|
275
|
+
if (provider === 'microsoft') {
|
|
276
|
+
const ms = await getMicrosoftCalendar();
|
|
277
|
+
return ms.updateEvent(config, calendarId, eventId, patch);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const gc = await getGoogleCalendar();
|
|
281
|
+
return gc.updateEvent(config, calendarId, eventId, patch);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* List events for a date range.
|
|
286
|
+
*/
|
|
287
|
+
export async function listEvents(config, calendarId = 'primary', timeMin, timeMax) {
|
|
288
|
+
const provider = detectMailProvider(config);
|
|
289
|
+
if (!provider) throw new Error('No mail provider authenticated.');
|
|
290
|
+
|
|
291
|
+
if (provider === 'microsoft') {
|
|
292
|
+
const ms = await getMicrosoftCalendar();
|
|
293
|
+
return ms.listEvents(config, calendarId, timeMin, timeMax);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const gc = await getGoogleCalendar();
|
|
297
|
+
return gc.listEvents(config, calendarId, timeMin, timeMax);
|
|
298
|
+
}
|