@vibetasks/core 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.
@@ -0,0 +1,179 @@
1
+ import { SupabaseClient } from '@supabase/supabase-js';
2
+
3
+ interface TaskFlowConfig {
4
+ supabase_url?: string;
5
+ supabase_key?: string;
6
+ default_priority?: 'none' | 'low' | 'medium' | 'high';
7
+ list_limit?: number;
8
+ [key: string]: any;
9
+ }
10
+ /**
11
+ * Manages TaskFlow configuration stored in ~/.config/taskflow/config.json
12
+ */
13
+ declare class ConfigManager {
14
+ private configDir;
15
+ private configPath;
16
+ constructor();
17
+ /**
18
+ * Ensure the config directory exists
19
+ */
20
+ ensureConfigDir(): Promise<void>;
21
+ /**
22
+ * Get the full configuration object
23
+ */
24
+ getConfig(): Promise<TaskFlowConfig>;
25
+ /**
26
+ * Set a configuration value
27
+ */
28
+ setConfig(key: string, value: any): Promise<void>;
29
+ /**
30
+ * Get a single configuration value
31
+ */
32
+ get(key: string): Promise<any>;
33
+ /**
34
+ * Delete a configuration value
35
+ */
36
+ delete(key: string): Promise<void>;
37
+ /**
38
+ * Clear all configuration
39
+ */
40
+ clear(): Promise<void>;
41
+ /**
42
+ * Get the config file path (useful for debugging)
43
+ */
44
+ getConfigPath(): string;
45
+ }
46
+
47
+ /**
48
+ * Manages authentication tokens with secure storage
49
+ * Uses system keychain (keytar) when available, falls back to config file
50
+ */
51
+ declare class AuthManager {
52
+ private configManager;
53
+ private keytar;
54
+ private useKeytar;
55
+ constructor();
56
+ /**
57
+ * Initialize keytar (system keychain) if available
58
+ */
59
+ private initKeytar;
60
+ /**
61
+ * Get the access token
62
+ */
63
+ getAccessToken(): Promise<string | null>;
64
+ /**
65
+ * Set the access token
66
+ */
67
+ setAccessToken(token: string): Promise<void>;
68
+ /**
69
+ * Get the refresh token
70
+ */
71
+ getRefreshToken(): Promise<string | null>;
72
+ /**
73
+ * Set the refresh token
74
+ */
75
+ setRefreshToken(token: string): Promise<void>;
76
+ /**
77
+ * Delete all stored tokens
78
+ */
79
+ clearTokens(): Promise<void>;
80
+ /**
81
+ * Get a config value (pass-through to ConfigManager)
82
+ */
83
+ getConfig(key: string): Promise<any>;
84
+ /**
85
+ * Set a config value (pass-through to ConfigManager)
86
+ */
87
+ setConfig(key: string, value: any): Promise<void>;
88
+ /**
89
+ * Check if user is authenticated (has access token)
90
+ */
91
+ isAuthenticated(): Promise<boolean>;
92
+ /**
93
+ * Get storage method being used
94
+ */
95
+ getStorageMethod(): 'keychain' | 'config-file';
96
+ }
97
+
98
+ interface SupabaseConfig {
99
+ supabaseUrl: string;
100
+ supabaseKey: string;
101
+ accessToken?: string;
102
+ }
103
+ /**
104
+ * Create a Supabase client with the provided configuration
105
+ *
106
+ * @param config - Supabase configuration including URL, key, and optional access token
107
+ * @returns Configured Supabase client
108
+ */
109
+ declare function createSupabaseClient(config: SupabaseConfig): SupabaseClient;
110
+ /**
111
+ * Create a Supabase client from environment variables
112
+ *
113
+ * @returns Configured Supabase client
114
+ * @throws Error if environment variables are not set
115
+ */
116
+ declare function createSupabaseClientFromEnv(): SupabaseClient;
117
+
118
+ type TaskFilter = 'all' | 'today' | 'upcoming' | 'completed';
119
+ type TaskPriority = 'none' | 'low' | 'medium' | 'high';
120
+ interface Tag {
121
+ id: string;
122
+ user_id?: string;
123
+ name: string;
124
+ color: string;
125
+ created_at?: string;
126
+ }
127
+ interface Task {
128
+ id: string;
129
+ user_id?: string;
130
+ title: string;
131
+ notes?: string;
132
+ notes_format?: 'html' | 'markdown';
133
+ completed?: boolean;
134
+ completed_at?: string;
135
+ due_date?: string;
136
+ start_date?: string;
137
+ duration_minutes?: number;
138
+ scheduled_time?: string;
139
+ recurrence_rule?: string;
140
+ recurrence_end?: string;
141
+ priority?: TaskPriority;
142
+ parent_task_id?: string;
143
+ position?: number;
144
+ created_at?: string;
145
+ updated_at?: string;
146
+ tags?: Tag[];
147
+ attachments?: any[];
148
+ subtasks?: Task[];
149
+ }
150
+ /**
151
+ * TaskOperations class provides a high-level API for task management
152
+ * Wraps the existing task-service.ts functionality with authentication and configuration
153
+ */
154
+ declare class TaskOperations {
155
+ private supabase;
156
+ constructor(supabase: SupabaseClient);
157
+ /**
158
+ * Create TaskOperations from AuthManager
159
+ */
160
+ static fromAuthManager(authManager: AuthManager): Promise<TaskOperations>;
161
+ getTasks(filter?: TaskFilter): Promise<Task[]>;
162
+ getTask(taskId: string): Promise<Task>;
163
+ createTask(task: Partial<Task>): Promise<Task>;
164
+ updateTask(taskId: string, updates: Partial<Task>): Promise<Task>;
165
+ deleteTask(taskId: string): Promise<void>;
166
+ completeTask(taskId: string): Promise<Task>;
167
+ uncompleteTask(taskId: string): Promise<Task>;
168
+ getTags(): Promise<Tag[]>;
169
+ createTag(name: string, color?: string): Promise<Tag>;
170
+ linkTaskTags(taskId: string, tagIds: string[]): Promise<void>;
171
+ unlinkAllTaskTags(taskId: string): Promise<void>;
172
+ searchTasks(query: string, limit?: number): Promise<Task[]>;
173
+ /**
174
+ * Find tag by name (case-insensitive), create if doesn't exist
175
+ */
176
+ findOrCreateTag(name: string, color?: string): Promise<Tag>;
177
+ }
178
+
179
+ export { AuthManager, ConfigManager, type SupabaseConfig, type Tag, type Task, type TaskFilter, type TaskFlowConfig, TaskOperations, type TaskPriority, createSupabaseClient, createSupabaseClientFromEnv };
package/dist/index.js ADDED
@@ -0,0 +1,456 @@
1
+ // src/config-manager.ts
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import os from "os";
5
+ var ConfigManager = class {
6
+ configDir;
7
+ configPath;
8
+ constructor() {
9
+ const configHome = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
10
+ this.configDir = path.join(configHome, "taskflow");
11
+ this.configPath = path.join(this.configDir, "config.json");
12
+ }
13
+ /**
14
+ * Ensure the config directory exists
15
+ */
16
+ async ensureConfigDir() {
17
+ try {
18
+ await fs.mkdir(this.configDir, { recursive: true });
19
+ } catch (error) {
20
+ throw new Error(`Failed to create config directory: ${error.message}`);
21
+ }
22
+ }
23
+ /**
24
+ * Get the full configuration object
25
+ */
26
+ async getConfig() {
27
+ try {
28
+ const data = await fs.readFile(this.configPath, "utf-8");
29
+ return JSON.parse(data);
30
+ } catch (error) {
31
+ if (error.code === "ENOENT") {
32
+ return {};
33
+ }
34
+ throw new Error(`Failed to read config: ${error.message}`);
35
+ }
36
+ }
37
+ /**
38
+ * Set a configuration value
39
+ */
40
+ async setConfig(key, value) {
41
+ await this.ensureConfigDir();
42
+ const config = await this.getConfig();
43
+ config[key] = value;
44
+ try {
45
+ await fs.writeFile(this.configPath, JSON.stringify(config, null, 2), "utf-8");
46
+ } catch (error) {
47
+ throw new Error(`Failed to write config: ${error.message}`);
48
+ }
49
+ }
50
+ /**
51
+ * Get a single configuration value
52
+ */
53
+ async get(key) {
54
+ const config = await this.getConfig();
55
+ return config[key];
56
+ }
57
+ /**
58
+ * Delete a configuration value
59
+ */
60
+ async delete(key) {
61
+ await this.ensureConfigDir();
62
+ const config = await this.getConfig();
63
+ delete config[key];
64
+ try {
65
+ await fs.writeFile(this.configPath, JSON.stringify(config, null, 2), "utf-8");
66
+ } catch (error) {
67
+ throw new Error(`Failed to write config: ${error.message}`);
68
+ }
69
+ }
70
+ /**
71
+ * Clear all configuration
72
+ */
73
+ async clear() {
74
+ try {
75
+ await fs.unlink(this.configPath);
76
+ } catch (error) {
77
+ if (error.code !== "ENOENT") {
78
+ throw new Error(`Failed to clear config: ${error.message}`);
79
+ }
80
+ }
81
+ }
82
+ /**
83
+ * Get the config file path (useful for debugging)
84
+ */
85
+ getConfigPath() {
86
+ return this.configPath;
87
+ }
88
+ };
89
+
90
+ // src/auth-manager.ts
91
+ var SERVICE_NAME = "taskflow-cli";
92
+ var ACCESS_TOKEN_ACCOUNT = "access-token";
93
+ var REFRESH_TOKEN_ACCOUNT = "refresh-token";
94
+ var AuthManager = class {
95
+ configManager;
96
+ keytar = null;
97
+ useKeytar = false;
98
+ constructor() {
99
+ this.configManager = new ConfigManager();
100
+ this.initKeytar();
101
+ }
102
+ /**
103
+ * Initialize keytar (system keychain) if available
104
+ */
105
+ async initKeytar() {
106
+ try {
107
+ this.keytar = await import("keytar");
108
+ this.useKeytar = true;
109
+ } catch (error) {
110
+ this.useKeytar = false;
111
+ }
112
+ }
113
+ /**
114
+ * Get the access token
115
+ */
116
+ async getAccessToken() {
117
+ if (this.keytar === null && process.platform !== "linux") {
118
+ await this.initKeytar();
119
+ }
120
+ if (this.useKeytar && this.keytar) {
121
+ try {
122
+ const token = await this.keytar.getPassword(SERVICE_NAME, ACCESS_TOKEN_ACCOUNT);
123
+ if (token) return token;
124
+ } catch (error) {
125
+ }
126
+ }
127
+ return await this.configManager.get("access_token");
128
+ }
129
+ /**
130
+ * Set the access token
131
+ */
132
+ async setAccessToken(token) {
133
+ if (this.keytar === null && process.platform !== "linux") {
134
+ await this.initKeytar();
135
+ }
136
+ if (this.useKeytar && this.keytar) {
137
+ try {
138
+ await this.keytar.setPassword(SERVICE_NAME, ACCESS_TOKEN_ACCOUNT, token);
139
+ return;
140
+ } catch (error) {
141
+ }
142
+ }
143
+ await this.configManager.setConfig("access_token", token);
144
+ }
145
+ /**
146
+ * Get the refresh token
147
+ */
148
+ async getRefreshToken() {
149
+ if (this.keytar === null && process.platform !== "linux") {
150
+ await this.initKeytar();
151
+ }
152
+ if (this.useKeytar && this.keytar) {
153
+ try {
154
+ const token = await this.keytar.getPassword(SERVICE_NAME, REFRESH_TOKEN_ACCOUNT);
155
+ if (token) return token;
156
+ } catch (error) {
157
+ }
158
+ }
159
+ return await this.configManager.get("refresh_token");
160
+ }
161
+ /**
162
+ * Set the refresh token
163
+ */
164
+ async setRefreshToken(token) {
165
+ if (this.keytar === null && process.platform !== "linux") {
166
+ await this.initKeytar();
167
+ }
168
+ if (this.useKeytar && this.keytar) {
169
+ try {
170
+ await this.keytar.setPassword(SERVICE_NAME, REFRESH_TOKEN_ACCOUNT, token);
171
+ return;
172
+ } catch (error) {
173
+ }
174
+ }
175
+ await this.configManager.setConfig("refresh_token", token);
176
+ }
177
+ /**
178
+ * Delete all stored tokens
179
+ */
180
+ async clearTokens() {
181
+ if (this.keytar === null && process.platform !== "linux") {
182
+ await this.initKeytar();
183
+ }
184
+ if (this.useKeytar && this.keytar) {
185
+ try {
186
+ await this.keytar.deletePassword(SERVICE_NAME, ACCESS_TOKEN_ACCOUNT);
187
+ await this.keytar.deletePassword(SERVICE_NAME, REFRESH_TOKEN_ACCOUNT);
188
+ } catch (error) {
189
+ }
190
+ }
191
+ await this.configManager.delete("access_token");
192
+ await this.configManager.delete("refresh_token");
193
+ }
194
+ /**
195
+ * Get a config value (pass-through to ConfigManager)
196
+ */
197
+ async getConfig(key) {
198
+ return await this.configManager.get(key);
199
+ }
200
+ /**
201
+ * Set a config value (pass-through to ConfigManager)
202
+ */
203
+ async setConfig(key, value) {
204
+ await this.configManager.setConfig(key, value);
205
+ }
206
+ /**
207
+ * Check if user is authenticated (has access token)
208
+ */
209
+ async isAuthenticated() {
210
+ const token = await this.getAccessToken();
211
+ return token !== null && token !== void 0 && token.length > 0;
212
+ }
213
+ /**
214
+ * Get storage method being used
215
+ */
216
+ getStorageMethod() {
217
+ return this.useKeytar ? "keychain" : "config-file";
218
+ }
219
+ };
220
+
221
+ // src/supabase-client.ts
222
+ import { createClient } from "@supabase/supabase-js";
223
+ function createSupabaseClient(config) {
224
+ const { supabaseUrl, supabaseKey, accessToken } = config;
225
+ if (!supabaseUrl || !supabaseKey) {
226
+ throw new Error("Supabase URL and key are required");
227
+ }
228
+ const client = createClient(supabaseUrl, supabaseKey, {
229
+ auth: {
230
+ persistSession: false,
231
+ // CLI/MCP don't need session persistence
232
+ autoRefreshToken: false
233
+ // We'll handle refresh manually if needed
234
+ },
235
+ global: accessToken ? {
236
+ headers: {
237
+ Authorization: `Bearer ${accessToken}`
238
+ }
239
+ } : void 0
240
+ });
241
+ return client;
242
+ }
243
+ function createSupabaseClientFromEnv() {
244
+ const supabaseUrl = process.env.TASKFLOW_SUPABASE_URL || process.env.SUPABASE_URL;
245
+ const supabaseKey = process.env.TASKFLOW_SUPABASE_KEY || process.env.SUPABASE_KEY || process.env.SUPABASE_ANON_KEY;
246
+ const accessToken = process.env.TASKFLOW_ACCESS_TOKEN;
247
+ if (!supabaseUrl || !supabaseKey) {
248
+ throw new Error(
249
+ "Supabase configuration not found in environment variables. Set TASKFLOW_SUPABASE_URL and TASKFLOW_SUPABASE_KEY, or run: taskflow login"
250
+ );
251
+ }
252
+ return createSupabaseClient({
253
+ supabaseUrl,
254
+ supabaseKey,
255
+ accessToken
256
+ });
257
+ }
258
+
259
+ // src/task-operations.ts
260
+ var TaskOperations = class _TaskOperations {
261
+ supabase;
262
+ constructor(supabase) {
263
+ this.supabase = supabase;
264
+ }
265
+ /**
266
+ * Create TaskOperations from AuthManager
267
+ */
268
+ static async fromAuthManager(authManager) {
269
+ const supabaseUrl = await authManager.getConfig("supabase_url");
270
+ const supabaseKey = await authManager.getConfig("supabase_key");
271
+ const accessToken = await authManager.getAccessToken();
272
+ if (!supabaseUrl || !supabaseKey) {
273
+ throw new Error(
274
+ "Supabase configuration not found. Run: taskflow login"
275
+ );
276
+ }
277
+ if (!accessToken) {
278
+ throw new Error("Not authenticated. Run: taskflow login");
279
+ }
280
+ const supabase = createSupabaseClient({
281
+ supabaseUrl,
282
+ supabaseKey,
283
+ accessToken
284
+ });
285
+ return new _TaskOperations(supabase);
286
+ }
287
+ // ============================================
288
+ // TASK CRUD OPERATIONS
289
+ // ============================================
290
+ async getTasks(filter = "all") {
291
+ let query = this.supabase.from("tasks").select(`
292
+ *,
293
+ tags:task_tags(tag:tags(*))
294
+ `).is("parent_task_id", null).order("position", { ascending: true });
295
+ if (filter === "today") {
296
+ const today = /* @__PURE__ */ new Date();
297
+ today.setHours(0, 0, 0, 0);
298
+ const tomorrow = new Date(today);
299
+ tomorrow.setDate(tomorrow.getDate() + 1);
300
+ query = query.gte("due_date", today.toISOString()).lt("due_date", tomorrow.toISOString()).eq("completed", false);
301
+ } else if (filter === "upcoming") {
302
+ const tomorrow = /* @__PURE__ */ new Date();
303
+ tomorrow.setDate(tomorrow.getDate() + 1);
304
+ tomorrow.setHours(0, 0, 0, 0);
305
+ query = query.gte("due_date", tomorrow.toISOString()).eq("completed", false);
306
+ } else if (filter === "completed") {
307
+ query = query.eq("completed", true).order("completed_at", { ascending: false });
308
+ } else {
309
+ query = query.eq("completed", false);
310
+ }
311
+ const { data, error } = await query;
312
+ if (error) throw error;
313
+ return (data || []).map((task) => ({
314
+ ...task,
315
+ tags: task.tags?.map((t) => t.tag).filter(Boolean) || []
316
+ }));
317
+ }
318
+ async getTask(taskId) {
319
+ const { data, error } = await this.supabase.from("tasks").select(`
320
+ *,
321
+ tags:task_tags(tag:tags(*))
322
+ `).eq("id", taskId).single();
323
+ if (error) throw error;
324
+ return {
325
+ ...data,
326
+ tags: data.tags?.map((t) => t.tag).filter(Boolean) || []
327
+ };
328
+ }
329
+ async createTask(task) {
330
+ const { data: { user } } = await this.supabase.auth.getUser();
331
+ if (!user) throw new Error("Not authenticated");
332
+ const { data, error } = await this.supabase.from("tasks").insert({
333
+ user_id: user.id,
334
+ title: task.title,
335
+ notes: task.notes,
336
+ notes_format: task.notes_format || "markdown",
337
+ due_date: task.due_date,
338
+ start_date: task.start_date,
339
+ duration_minutes: task.duration_minutes,
340
+ scheduled_time: task.scheduled_time,
341
+ recurrence_rule: task.recurrence_rule,
342
+ recurrence_end: task.recurrence_end,
343
+ priority: task.priority || "none",
344
+ parent_task_id: task.parent_task_id,
345
+ position: task.position || 0
346
+ }).select().single();
347
+ if (error) throw error;
348
+ if (task.tags && task.tags.length > 0) {
349
+ await this.linkTaskTags(data.id, task.tags.map((t) => t.id));
350
+ }
351
+ return data;
352
+ }
353
+ async updateTask(taskId, updates) {
354
+ const updateData = {};
355
+ if (updates.title !== void 0) updateData.title = updates.title;
356
+ if (updates.notes !== void 0) updateData.notes = updates.notes;
357
+ if (updates.notes_format !== void 0) updateData.notes_format = updates.notes_format;
358
+ if (updates.completed !== void 0) {
359
+ updateData.completed = updates.completed;
360
+ updateData.completed_at = updates.completed ? (/* @__PURE__ */ new Date()).toISOString() : null;
361
+ }
362
+ if (updates.due_date !== void 0) updateData.due_date = updates.due_date;
363
+ if (updates.start_date !== void 0) updateData.start_date = updates.start_date;
364
+ if (updates.duration_minutes !== void 0) updateData.duration_minutes = updates.duration_minutes;
365
+ if (updates.scheduled_time !== void 0) updateData.scheduled_time = updates.scheduled_time;
366
+ if (updates.recurrence_rule !== void 0) updateData.recurrence_rule = updates.recurrence_rule;
367
+ if (updates.recurrence_end !== void 0) updateData.recurrence_end = updates.recurrence_end;
368
+ if (updates.priority !== void 0) updateData.priority = updates.priority;
369
+ if (updates.position !== void 0) updateData.position = updates.position;
370
+ const { data, error } = await this.supabase.from("tasks").update(updateData).eq("id", taskId).select().single();
371
+ if (error) throw error;
372
+ if (updates.tags !== void 0) {
373
+ await this.unlinkAllTaskTags(taskId);
374
+ if (updates.tags.length > 0) {
375
+ await this.linkTaskTags(taskId, updates.tags.map((t) => t.id));
376
+ }
377
+ }
378
+ return data;
379
+ }
380
+ async deleteTask(taskId) {
381
+ const { error } = await this.supabase.from("tasks").delete().eq("id", taskId);
382
+ if (error) throw error;
383
+ }
384
+ async completeTask(taskId) {
385
+ const { data, error } = await this.supabase.from("tasks").update({
386
+ completed: true,
387
+ completed_at: (/* @__PURE__ */ new Date()).toISOString()
388
+ }).eq("id", taskId).select().single();
389
+ if (error) throw error;
390
+ return data;
391
+ }
392
+ async uncompleteTask(taskId) {
393
+ const { data, error } = await this.supabase.from("tasks").update({
394
+ completed: false,
395
+ completed_at: null
396
+ }).eq("id", taskId).select().single();
397
+ if (error) throw error;
398
+ return data;
399
+ }
400
+ // ============================================
401
+ // TAG OPERATIONS
402
+ // ============================================
403
+ async getTags() {
404
+ const { data, error } = await this.supabase.from("tags").select("*").order("name", { ascending: true });
405
+ if (error) throw error;
406
+ return data;
407
+ }
408
+ async createTag(name, color = "#8B5CF6") {
409
+ const { data: { user } } = await this.supabase.auth.getUser();
410
+ if (!user) throw new Error("Not authenticated");
411
+ const { data, error } = await this.supabase.from("tags").insert({ user_id: user.id, name, color }).select().single();
412
+ if (error) throw error;
413
+ return data;
414
+ }
415
+ async linkTaskTags(taskId, tagIds) {
416
+ if (tagIds.length === 0) return;
417
+ const { error } = await this.supabase.from("task_tags").insert(tagIds.map((tagId) => ({ task_id: taskId, tag_id: tagId })));
418
+ if (error) throw error;
419
+ }
420
+ async unlinkAllTaskTags(taskId) {
421
+ const { error } = await this.supabase.from("task_tags").delete().eq("task_id", taskId);
422
+ if (error) throw error;
423
+ }
424
+ // ============================================
425
+ // SEARCH & UTILITY
426
+ // ============================================
427
+ async searchTasks(query, limit = 20) {
428
+ const { data, error } = await this.supabase.from("tasks").select(`
429
+ *,
430
+ tags:task_tags(tag:tags(*))
431
+ `).ilike("title", `%${query}%`).is("parent_task_id", null).eq("completed", false).order("position", { ascending: true }).limit(limit);
432
+ if (error) throw error;
433
+ return (data || []).map((task) => ({
434
+ ...task,
435
+ tags: task.tags?.map((t) => t.tag).filter(Boolean) || []
436
+ }));
437
+ }
438
+ /**
439
+ * Find tag by name (case-insensitive), create if doesn't exist
440
+ */
441
+ async findOrCreateTag(name, color) {
442
+ const tags = await this.getTags();
443
+ const existing = tags.find((t) => t.name.toLowerCase() === name.toLowerCase());
444
+ if (existing) {
445
+ return existing;
446
+ }
447
+ return await this.createTag(name, color);
448
+ }
449
+ };
450
+ export {
451
+ AuthManager,
452
+ ConfigManager,
453
+ TaskOperations,
454
+ createSupabaseClient,
455
+ createSupabaseClientFromEnv
456
+ };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@vibetasks/core",
3
+ "version": "0.1.0",
4
+ "description": "Shared core logic for VibeTasks MCP server and CLI - authentication, task operations, and config management",
5
+ "author": "Vyas",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "type": "module",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "keywords": [
14
+ "vibetasks",
15
+ "vibe",
16
+ "vibecoding",
17
+ "mcp",
18
+ "task-management",
19
+ "supabase",
20
+ "authentication",
21
+ "productivity"
22
+ ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/vyassathya/vibetasks.git",
26
+ "directory": "packages/mcp-core"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "dev": "tsx src/index.ts",
33
+ "build": "tsup src/index.ts --format esm --clean --dts",
34
+ "typecheck": "tsc --noEmit"
35
+ },
36
+ "dependencies": {
37
+ "@supabase/supabase-js": "^2.39.0",
38
+ "keytar": "^7.9.0",
39
+ "zod": "^3.22.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^20.0.0",
43
+ "tsx": "^4.7.0",
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.3.3"
46
+ }
47
+ }