@tuturuuu/ai 0.0.10
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 +76 -0
- package/package.json +106 -0
- package/src/api-key-hash.ts +28 -0
- package/src/calendar/events.ts +34 -0
- package/src/calendar/route.ts +114 -0
- package/src/chat/credit-source.ts +1 -0
- package/src/chat/google/chat-request-schema.ts +150 -0
- package/src/chat/google/default-system-instruction.ts +198 -0
- package/src/chat/google/message-file-processing.ts +212 -0
- package/src/chat/google/mira-step-preparation.ts +221 -0
- package/src/chat/google/new/route.ts +368 -0
- package/src/chat/google/route-auth.ts +81 -0
- package/src/chat/google/route-chat-resolution.ts +98 -0
- package/src/chat/google/route-credits.ts +61 -0
- package/src/chat/google/route-message-preparation.ts +331 -0
- package/src/chat/google/route-mira-runtime.ts +206 -0
- package/src/chat/google/route.ts +632 -0
- package/src/chat/google/stream-finish-persistence.ts +722 -0
- package/src/chat/google/summary/route.ts +153 -0
- package/src/chat/mira-render-ui-policy.ts +540 -0
- package/src/chat/mira-system-instruction.ts +484 -0
- package/src/chat-sdk/adapters.ts +389 -0
- package/src/chat-sdk/registry.ts +197 -0
- package/src/chat-sdk.ts +33 -0
- package/src/core.ts +3 -0
- package/src/credits/cap-output-tokens.ts +90 -0
- package/src/credits/check-credits.ts +232 -0
- package/src/credits/constants.ts +30 -0
- package/src/credits/index.ts +46 -0
- package/src/credits/model-mapping.ts +92 -0
- package/src/credits/reservations.ts +514 -0
- package/src/credits/resolve-plan-model.ts +219 -0
- package/src/credits/sync-gateway-models.ts +351 -0
- package/src/credits/types.ts +109 -0
- package/src/credits/use-ai-credits.ts +3 -0
- package/src/embeddings/metered.ts +283 -0
- package/src/executions/route.ts +137 -0
- package/src/generate/route.ts +411 -0
- package/src/hooks.ts +7 -0
- package/src/meetings/summary/route.ts +7 -0
- package/src/meetings/transcription/route.ts +134 -0
- package/src/memory/client.ts +158 -0
- package/src/memory/config.ts +38 -0
- package/src/memory/index.ts +32 -0
- package/src/memory/ingest.ts +51 -0
- package/src/memory/middleware.ts +35 -0
- package/src/memory/operations.ts +480 -0
- package/src/memory/scope.ts +102 -0
- package/src/memory/settings.ts +121 -0
- package/src/memory/types.ts +101 -0
- package/src/memory/workspace.ts +36 -0
- package/src/memory.ts +1 -0
- package/src/mind/patch.ts +146 -0
- package/src/mind/route.ts +687 -0
- package/src/mind/tools.ts +1500 -0
- package/src/mind/types.ts +20 -0
- package/src/object/core.ts +3 -0
- package/src/object/flashcards/route.ts +140 -0
- package/src/object/quizzes/explanation/route.ts +145 -0
- package/src/object/quizzes/route.ts +142 -0
- package/src/object/types.ts +187 -0
- package/src/object/year-plan/route.ts +196 -0
- package/src/react.ts +1 -0
- package/src/scheduling/algorithm.ts +791 -0
- package/src/scheduling/default.ts +36 -0
- package/src/scheduling/duration-optimizer.ts +689 -0
- package/src/scheduling/index.ts +79 -0
- package/src/scheduling/priority-calculator.ts +187 -0
- package/src/scheduling/recurrence-calculator.ts +621 -0
- package/src/scheduling/templates.ts +892 -0
- package/src/scheduling/types.ts +136 -0
- package/src/scheduling/web-adapter.ts +308 -0
- package/src/scheduling.ts +6 -0
- package/src/supported-actions.ts +1 -0
- package/src/supported-providers.ts +6 -0
- package/src/tools/context-builder.ts +372 -0
- package/src/tools/core.ts +1 -0
- package/src/tools/definitions/calendar.ts +106 -0
- package/src/tools/definitions/finance.ts +197 -0
- package/src/tools/definitions/image.ts +74 -0
- package/src/tools/definitions/memory.ts +83 -0
- package/src/tools/definitions/meta.ts +154 -0
- package/src/tools/definitions/render-ui.ts +81 -0
- package/src/tools/definitions/tasks.ts +343 -0
- package/src/tools/definitions/time-tracking.ts +381 -0
- package/src/tools/definitions/workspace-context.ts +45 -0
- package/src/tools/definitions/workspace-user-chat.ts +111 -0
- package/src/tools/executors/calendar.ts +371 -0
- package/src/tools/executors/chat.ts +15 -0
- package/src/tools/executors/finance.ts +638 -0
- package/src/tools/executors/helpers/encryption.ts +107 -0
- package/src/tools/executors/image.ts +247 -0
- package/src/tools/executors/markitdown.ts +684 -0
- package/src/tools/executors/memory.ts +277 -0
- package/src/tools/executors/parallel-checks.ts +176 -0
- package/src/tools/executors/qr.ts +170 -0
- package/src/tools/executors/scope-helpers.ts +192 -0
- package/src/tools/executors/search.ts +149 -0
- package/src/tools/executors/settings.ts +40 -0
- package/src/tools/executors/tasks.ts +1087 -0
- package/src/tools/executors/theme.ts +23 -0
- package/src/tools/executors/timer/timer-categories-executor.ts +110 -0
- package/src/tools/executors/timer/timer-category-mutations.ts +240 -0
- package/src/tools/executors/timer/timer-goal-mutations.ts +323 -0
- package/src/tools/executors/timer/timer-goals-executor.ts +272 -0
- package/src/tools/executors/timer/timer-helpers.ts +372 -0
- package/src/tools/executors/timer/timer-mutation-schemas.ts +160 -0
- package/src/tools/executors/timer/timer-mutation-types.ts +212 -0
- package/src/tools/executors/timer/timer-mutations.ts +19 -0
- package/src/tools/executors/timer/timer-queries.ts +18 -0
- package/src/tools/executors/timer/timer-session-lifecycle.ts +299 -0
- package/src/tools/executors/timer/timer-session-mutations.ts +10 -0
- package/src/tools/executors/timer/timer-session-queries.ts +153 -0
- package/src/tools/executors/timer/timer-session-updates.ts +200 -0
- package/src/tools/executors/timer/timer-sessions-executor.ts +91 -0
- package/src/tools/executors/timer/timer-stats-executor.ts +157 -0
- package/src/tools/executors/timer.ts +22 -0
- package/src/tools/executors/user.ts +60 -0
- package/src/tools/executors/workspace.ts +135 -0
- package/src/tools/json-render-catalog.ts +875 -0
- package/src/tools/mira-tool-definitions.ts +55 -0
- package/src/tools/mira-tool-dispatcher.ts +265 -0
- package/src/tools/mira-tool-metadata.ts +164 -0
- package/src/tools/mira-tool-names.ts +95 -0
- package/src/tools/mira-tool-render-ui.ts +54 -0
- package/src/tools/mira-tool-types.ts +17 -0
- package/src/tools/mira-tools.ts +167 -0
- package/src/tools/normalize-render-ui-input.ts +321 -0
- package/src/tools/workspace-context.ts +233 -0
- package/src/types.ts +38 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import type { TablesUpdate } from '@tuturuuu/types';
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
import timezone from 'dayjs/plugin/timezone';
|
|
4
|
+
import utc from 'dayjs/plugin/utc';
|
|
5
|
+
import type { MiraToolContext } from '../mira-tools';
|
|
6
|
+
import { getWorkspaceContextWorkspaceId } from '../workspace-context';
|
|
7
|
+
import {
|
|
8
|
+
decryptEventsForTools,
|
|
9
|
+
encryptEventFieldsForTools,
|
|
10
|
+
getWorkspaceKeyForTools,
|
|
11
|
+
} from './helpers/encryption';
|
|
12
|
+
|
|
13
|
+
dayjs.extend(utc);
|
|
14
|
+
dayjs.extend(timezone);
|
|
15
|
+
|
|
16
|
+
export async function executeGetUpcomingEvents(
|
|
17
|
+
args: Record<string, unknown>,
|
|
18
|
+
ctx: MiraToolContext
|
|
19
|
+
) {
|
|
20
|
+
const days = (args.num_days as number) || (args.days as number) || 7;
|
|
21
|
+
const tz = ctx.timezone;
|
|
22
|
+
const workspaceId = getWorkspaceContextWorkspaceId(ctx);
|
|
23
|
+
|
|
24
|
+
// Build the query window in the user's timezone so "today" means their
|
|
25
|
+
// full calendar day, not "from this UTC instant forward".
|
|
26
|
+
let rangeStart: dayjs.Dayjs;
|
|
27
|
+
let rangeEnd: dayjs.Dayjs;
|
|
28
|
+
|
|
29
|
+
if (tz) {
|
|
30
|
+
try {
|
|
31
|
+
rangeStart = dayjs().tz(tz).startOf('day');
|
|
32
|
+
rangeEnd = rangeStart.add(days, 'day').endOf('day');
|
|
33
|
+
} catch (_) {
|
|
34
|
+
console.warn(`Invalid timezone ${tz}, falling back to UTC`);
|
|
35
|
+
rangeStart = dayjs.utc().startOf('day');
|
|
36
|
+
rangeEnd = rangeStart.add(days, 'day').endOf('day');
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
rangeStart = dayjs.utc().startOf('day');
|
|
40
|
+
rangeEnd = rangeStart.add(days, 'day').endOf('day');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { data: events, error } = await ctx.supabase
|
|
44
|
+
.from('workspace_calendar_events')
|
|
45
|
+
.select('id, title, description, start_at, end_at, location, is_encrypted')
|
|
46
|
+
.eq('ws_id', workspaceId)
|
|
47
|
+
.gte('start_at', rangeStart.toISOString())
|
|
48
|
+
.lte('start_at', rangeEnd.toISOString())
|
|
49
|
+
.order('start_at', { ascending: true })
|
|
50
|
+
.limit(50);
|
|
51
|
+
|
|
52
|
+
if (error) return { error: error.message };
|
|
53
|
+
if (!events?.length) return { count: 0, events: [] };
|
|
54
|
+
|
|
55
|
+
const decrypted = await decryptEventsForTools(events, workspaceId);
|
|
56
|
+
|
|
57
|
+
// Format dates in the user's timezone so the model presents local times
|
|
58
|
+
const formatInTz = (iso: string) => {
|
|
59
|
+
if (!tz) return iso;
|
|
60
|
+
try {
|
|
61
|
+
return dayjs(iso).tz(tz).format('YYYY-MM-DDTHH:mm:ssZ');
|
|
62
|
+
} catch {
|
|
63
|
+
return iso;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
count: decrypted.length,
|
|
69
|
+
timezone: tz ?? 'UTC',
|
|
70
|
+
events: decrypted.map(
|
|
71
|
+
(e: {
|
|
72
|
+
id: string;
|
|
73
|
+
title: string;
|
|
74
|
+
description?: string;
|
|
75
|
+
start_at: string;
|
|
76
|
+
end_at: string;
|
|
77
|
+
location: string | null;
|
|
78
|
+
}) => ({
|
|
79
|
+
id: e.id,
|
|
80
|
+
title: e.title,
|
|
81
|
+
description: e.description || null,
|
|
82
|
+
start: formatInTz(e.start_at),
|
|
83
|
+
end: formatInTz(e.end_at),
|
|
84
|
+
location: e.location,
|
|
85
|
+
})
|
|
86
|
+
),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function executeCreateEvent(
|
|
91
|
+
args: Record<string, unknown>,
|
|
92
|
+
ctx: MiraToolContext
|
|
93
|
+
) {
|
|
94
|
+
const workspaceId = getWorkspaceContextWorkspaceId(ctx);
|
|
95
|
+
const title = args.title as string;
|
|
96
|
+
const description = (args.description as string) ?? '';
|
|
97
|
+
const location = (args.location as string) ?? null;
|
|
98
|
+
|
|
99
|
+
// Convert standard ISO strings or casual strings into proper UTC timestamps
|
|
100
|
+
// based on the provided timezone, assuming the LLM provides dates in the local timezone context.
|
|
101
|
+
let startAt = args.startAt as string;
|
|
102
|
+
let endAt = args.endAt as string;
|
|
103
|
+
|
|
104
|
+
if (ctx.timezone) {
|
|
105
|
+
try {
|
|
106
|
+
// If the model gave an ISO string without Z, treat it as local to the timezone
|
|
107
|
+
const startDayjs = startAt.includes('Z')
|
|
108
|
+
? dayjs(startAt)
|
|
109
|
+
: dayjs.tz(startAt, ctx.timezone);
|
|
110
|
+
const endDayjs = endAt.includes('Z')
|
|
111
|
+
? dayjs(endAt)
|
|
112
|
+
: dayjs.tz(endAt, ctx.timezone);
|
|
113
|
+
|
|
114
|
+
startAt = startDayjs.toISOString();
|
|
115
|
+
endAt = endDayjs.toISOString();
|
|
116
|
+
} catch (err) {
|
|
117
|
+
console.warn(
|
|
118
|
+
'Failed to parse timezone dates, falling back to basic parsing',
|
|
119
|
+
err
|
|
120
|
+
);
|
|
121
|
+
// Fallback to basic Date parsing if timezone plugin fails
|
|
122
|
+
startAt = new Date(args.startAt as string).toISOString();
|
|
123
|
+
endAt = new Date(args.endAt as string).toISOString();
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
startAt = new Date(args.startAt as string).toISOString();
|
|
127
|
+
endAt = new Date(args.endAt as string).toISOString();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const encrypted = await encryptEventFieldsForTools(
|
|
131
|
+
{ title, description, location },
|
|
132
|
+
workspaceId
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const { data: event, error } = await ctx.supabase
|
|
136
|
+
.from('workspace_calendar_events')
|
|
137
|
+
.insert({
|
|
138
|
+
title: encrypted.title,
|
|
139
|
+
start_at: startAt,
|
|
140
|
+
end_at: endAt,
|
|
141
|
+
description: encrypted.description,
|
|
142
|
+
location: encrypted.location,
|
|
143
|
+
ws_id: workspaceId,
|
|
144
|
+
is_encrypted: encrypted.is_encrypted,
|
|
145
|
+
})
|
|
146
|
+
.select('id, title, start_at, end_at')
|
|
147
|
+
.single();
|
|
148
|
+
|
|
149
|
+
if (error) return { error: error.message };
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
success: true,
|
|
153
|
+
message: `Event "${title}" created`,
|
|
154
|
+
event: encrypted.is_encrypted
|
|
155
|
+
? { ...event, title, description, location }
|
|
156
|
+
: event,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export async function executeUpdateEvent(
|
|
161
|
+
args: Record<string, unknown>,
|
|
162
|
+
ctx: MiraToolContext
|
|
163
|
+
) {
|
|
164
|
+
const workspaceId = getWorkspaceContextWorkspaceId(ctx);
|
|
165
|
+
const eventId = args.eventId as string;
|
|
166
|
+
const title = args.title as string | undefined;
|
|
167
|
+
const description = args.description as string | undefined;
|
|
168
|
+
const location = args.location as string | undefined;
|
|
169
|
+
let startAt = args.startAt as string | undefined;
|
|
170
|
+
let endAt = args.endAt as string | undefined;
|
|
171
|
+
|
|
172
|
+
// Convert dates if provided
|
|
173
|
+
if (startAt || endAt) {
|
|
174
|
+
if (ctx.timezone) {
|
|
175
|
+
try {
|
|
176
|
+
if (startAt) {
|
|
177
|
+
const startDayjs = startAt.includes('Z')
|
|
178
|
+
? dayjs(startAt)
|
|
179
|
+
: dayjs.tz(startAt, ctx.timezone);
|
|
180
|
+
startAt = startDayjs.toISOString();
|
|
181
|
+
}
|
|
182
|
+
if (endAt) {
|
|
183
|
+
const endDayjs = endAt.includes('Z')
|
|
184
|
+
? dayjs(endAt)
|
|
185
|
+
: dayjs.tz(endAt, ctx.timezone);
|
|
186
|
+
endAt = endDayjs.toISOString();
|
|
187
|
+
}
|
|
188
|
+
} catch (err) {
|
|
189
|
+
console.warn(
|
|
190
|
+
'Failed to parse timezone dates for update, falling back',
|
|
191
|
+
err
|
|
192
|
+
);
|
|
193
|
+
if (startAt) startAt = new Date(startAt).toISOString();
|
|
194
|
+
if (endAt) endAt = new Date(endAt).toISOString();
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
if (startAt) startAt = new Date(startAt).toISOString();
|
|
198
|
+
if (endAt) endAt = new Date(endAt).toISOString();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Get existing event to check encryption status
|
|
203
|
+
const { data: existingEvent, error: fetchError } = await ctx.supabase
|
|
204
|
+
.from('workspace_calendar_events')
|
|
205
|
+
.select('is_encrypted')
|
|
206
|
+
.eq('id', eventId)
|
|
207
|
+
.eq('ws_id', workspaceId)
|
|
208
|
+
.single();
|
|
209
|
+
|
|
210
|
+
if (fetchError || !existingEvent) {
|
|
211
|
+
return { error: fetchError?.message || 'Event not found' };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const updates: TablesUpdate<'workspace_calendar_events'> = {};
|
|
215
|
+
if (startAt) updates.start_at = startAt;
|
|
216
|
+
if (endAt) updates.end_at = endAt;
|
|
217
|
+
|
|
218
|
+
if (
|
|
219
|
+
title !== undefined ||
|
|
220
|
+
description !== undefined ||
|
|
221
|
+
location !== undefined
|
|
222
|
+
) {
|
|
223
|
+
const fieldsToEncrypt = {
|
|
224
|
+
title: title ?? '', // Ensure fallback if undefined but we need to encrypt
|
|
225
|
+
description: description ?? '',
|
|
226
|
+
location: location ?? null,
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// We only encrypt the fields that were actually provided to be updated,
|
|
230
|
+
// but the helper expects the full object. We will merge carefully.
|
|
231
|
+
const encrypted = await encryptEventFieldsForTools(
|
|
232
|
+
fieldsToEncrypt,
|
|
233
|
+
workspaceId
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
if (title !== undefined) updates.title = encrypted.title;
|
|
237
|
+
if (description !== undefined) updates.description = encrypted.description;
|
|
238
|
+
if (location !== undefined) updates.location = encrypted.location;
|
|
239
|
+
updates.is_encrypted = encrypted.is_encrypted;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const { error } = await ctx.supabase
|
|
243
|
+
.from('workspace_calendar_events')
|
|
244
|
+
.update(updates)
|
|
245
|
+
.eq('id', eventId)
|
|
246
|
+
.eq('ws_id', workspaceId);
|
|
247
|
+
|
|
248
|
+
if (error) return { error: error.message };
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
success: true,
|
|
252
|
+
message: `Event updated successfully`,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export async function executeDeleteEvent(
|
|
257
|
+
args: Record<string, unknown>,
|
|
258
|
+
ctx: MiraToolContext
|
|
259
|
+
) {
|
|
260
|
+
const workspaceId = getWorkspaceContextWorkspaceId(ctx);
|
|
261
|
+
const eventId = args.eventId as string;
|
|
262
|
+
|
|
263
|
+
const { error } = await ctx.supabase
|
|
264
|
+
.from('workspace_calendar_events')
|
|
265
|
+
.delete()
|
|
266
|
+
.eq('id', eventId)
|
|
267
|
+
.eq('ws_id', workspaceId);
|
|
268
|
+
|
|
269
|
+
if (error) return { error: error.message };
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
success: true,
|
|
273
|
+
message: `Event deleted successfully`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ── E2EE Management ──
|
|
278
|
+
|
|
279
|
+
export async function executeCheckE2EEStatus(
|
|
280
|
+
_args: Record<string, unknown>,
|
|
281
|
+
ctx: MiraToolContext
|
|
282
|
+
) {
|
|
283
|
+
const workspaceId = getWorkspaceContextWorkspaceId(ctx);
|
|
284
|
+
const key = await getWorkspaceKeyForTools(workspaceId);
|
|
285
|
+
const hasKey = key !== null;
|
|
286
|
+
|
|
287
|
+
if (!hasKey) {
|
|
288
|
+
return {
|
|
289
|
+
enabled: false,
|
|
290
|
+
hasKey: false,
|
|
291
|
+
message:
|
|
292
|
+
'End-to-end encryption is not enabled for this workspace. Calendar events are stored in plaintext.',
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const { count, error } = await ctx.supabase
|
|
297
|
+
.from('workspace_calendar_events')
|
|
298
|
+
.select('id', { count: 'exact', head: true })
|
|
299
|
+
.eq('ws_id', workspaceId)
|
|
300
|
+
.eq('is_encrypted', false);
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
enabled: true,
|
|
304
|
+
hasKey: true,
|
|
305
|
+
unencryptedCount: error ? -1 : (count ?? 0),
|
|
306
|
+
message:
|
|
307
|
+
count && count > 0
|
|
308
|
+
? `E2EE is enabled but ${count} event(s) are still unencrypted.`
|
|
309
|
+
: 'E2EE is enabled. All calendar events are encrypted.',
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export async function executeEnableE2EE(
|
|
314
|
+
_args: Record<string, unknown>,
|
|
315
|
+
ctx: MiraToolContext
|
|
316
|
+
) {
|
|
317
|
+
const workspaceId = getWorkspaceContextWorkspaceId(ctx);
|
|
318
|
+
try {
|
|
319
|
+
const {
|
|
320
|
+
isEncryptionEnabled,
|
|
321
|
+
getMasterKey,
|
|
322
|
+
encryptWorkspaceKey,
|
|
323
|
+
generateWorkspaceKey,
|
|
324
|
+
} = await import('@tuturuuu/utils/encryption');
|
|
325
|
+
|
|
326
|
+
if (!isEncryptionEnabled()) {
|
|
327
|
+
return {
|
|
328
|
+
success: false,
|
|
329
|
+
error:
|
|
330
|
+
'Encryption is not configured on this server. Please contact an administrator.',
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Check if key already exists
|
|
335
|
+
const existingKey = await getWorkspaceKeyForTools(workspaceId);
|
|
336
|
+
if (existingKey) {
|
|
337
|
+
return {
|
|
338
|
+
success: true,
|
|
339
|
+
message: 'E2EE is already enabled for this workspace.',
|
|
340
|
+
alreadyEnabled: true,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const masterKey = getMasterKey();
|
|
345
|
+
const newKey = generateWorkspaceKey();
|
|
346
|
+
const encryptedKey = await encryptWorkspaceKey(newKey, masterKey);
|
|
347
|
+
|
|
348
|
+
const { createAdminClient } = await import(
|
|
349
|
+
'@tuturuuu/supabase/next/server'
|
|
350
|
+
);
|
|
351
|
+
const sbAdmin = await createAdminClient();
|
|
352
|
+
|
|
353
|
+
const { error } = await sbAdmin.from('workspace_encryption_keys').insert({
|
|
354
|
+
ws_id: workspaceId,
|
|
355
|
+
encrypted_key: encryptedKey,
|
|
356
|
+
} as never);
|
|
357
|
+
|
|
358
|
+
if (error) return { success: false, error: error.message };
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
success: true,
|
|
362
|
+
message:
|
|
363
|
+
'E2EE has been enabled. New calendar events will be encrypted automatically.',
|
|
364
|
+
};
|
|
365
|
+
} catch (err) {
|
|
366
|
+
return {
|
|
367
|
+
success: false,
|
|
368
|
+
error: `Failed to enable E2EE: ${err instanceof Error ? err.message : 'Unknown error'}`,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MiraToolContext } from '../mira-tools';
|
|
2
|
+
|
|
3
|
+
export async function executeSetImmersiveMode(
|
|
4
|
+
args: Record<string, unknown>,
|
|
5
|
+
_ctx: MiraToolContext
|
|
6
|
+
) {
|
|
7
|
+
const enabled = args.enabled as boolean;
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
success: true,
|
|
11
|
+
action: 'set_immersive_mode',
|
|
12
|
+
enabled,
|
|
13
|
+
message: `Immersive mode ${enabled ? 'enabled' : 'disabled'}`,
|
|
14
|
+
};
|
|
15
|
+
}
|