@dolusoft/hirebase-mcp 1.1.9 → 1.1.11

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 (35) hide show
  1. package/README.md +30 -23
  2. package/dist/application/ports/calendar-service.d.ts +42 -0
  3. package/dist/application/ports/calendar-service.js +2 -0
  4. package/dist/application/ports/calendar-service.js.map +1 -0
  5. package/dist/infrastructure/ai/openai-embedding-service.js +1 -1
  6. package/dist/infrastructure/calendar/google-calendar.service.d.ts +24 -0
  7. package/dist/infrastructure/calendar/google-calendar.service.js +353 -0
  8. package/dist/infrastructure/calendar/google-calendar.service.js.map +1 -0
  9. package/dist/infrastructure/calendar/index.d.ts +1 -0
  10. package/dist/infrastructure/calendar/index.js +2 -0
  11. package/dist/infrastructure/calendar/index.js.map +1 -0
  12. package/dist/infrastructure/config/app-config.d.ts +2 -0
  13. package/dist/infrastructure/config/app-config.js +3 -1
  14. package/dist/infrastructure/config/app-config.js.map +1 -1
  15. package/dist/interface/dashboard/public/200.html +1 -1
  16. package/dist/interface/dashboard/public/404.html +1 -1
  17. package/dist/interface/dashboard/public/_nuxt/builds/latest.json +1 -1
  18. package/dist/interface/dashboard/public/_nuxt/builds/meta/32cf8bd4-f9b8-477d-bcff-75df710335e1.json +1 -0
  19. package/dist/interface/dashboard/public/_nuxt/builds/meta/4d9b8de6-1292-42ca-8f07-c47ba5f61768.json +1 -0
  20. package/dist/interface/dashboard/public/_nuxt/builds/meta/f4e23d88-bf4b-4110-976f-4e7a2c538e98.json +1 -0
  21. package/dist/interface/dashboard/public/_nuxt/builds/meta/fb00efc4-219c-4174-8827-fe876fe21945.json +1 -0
  22. package/dist/interface/dashboard/public/index.html +1 -1
  23. package/dist/interface/mcp/server.js +12 -0
  24. package/dist/interface/mcp/server.js.map +1 -1
  25. package/dist/interface/mcp/tools/add-contact.d.ts +3 -0
  26. package/dist/interface/mcp/tools/add-contact.js +43 -0
  27. package/dist/interface/mcp/tools/add-contact.js.map +1 -0
  28. package/dist/interface/mcp/tools/authorize-calendar.d.ts +3 -0
  29. package/dist/interface/mcp/tools/authorize-calendar.js +20 -0
  30. package/dist/interface/mcp/tools/authorize-calendar.js.map +1 -0
  31. package/dist/interface/mcp/tools/create-calendar-event.d.ts +3 -0
  32. package/dist/interface/mcp/tools/create-calendar-event.js +46 -0
  33. package/dist/interface/mcp/tools/create-calendar-event.js.map +1 -0
  34. package/dist/interface/mcp/types.d.ts +2 -0
  35. package/package.json +1 -1
package/README.md CHANGED
@@ -23,15 +23,16 @@ src/
23
23
  |---|---|
24
24
  | TypeScript 5.9 | Language |
25
25
  | LanceDB | Vector database (embedded, serverless) |
26
- | OpenAI `text-embedding-3-large` | 3072-dim embeddings |
26
+ | OpenAI `text-embedding-3-small` | 1536-dim embeddings |
27
27
  | OpenAI `gpt-5-mini` | Structured CV extraction (Responses API) |
28
28
  | MCP SDK | Model Context Protocol server |
29
29
  | Nuxt 4 + Nuxt UI | Real-time dashboard |
30
30
  | unpdf | PDF text extraction |
31
31
  | mammoth | DOCX text extraction |
32
32
  | Tesseract.js | OCR for image-based PDFs |
33
+ | Google Calendar + Contacts API | Interview scheduling & contact sync (OAuth2, zero dependencies) |
33
34
 
34
- ## MCP Tools (27)
35
+ ## MCP Tools (30)
35
36
 
36
37
  ### CV Management
37
38
 
@@ -79,6 +80,16 @@ src/
79
80
 
80
81
  **Pipeline statuses:** `new` → `contacted` → `unreachable` · `not_interested` · `interview_scheduled` → `no_show` · `interviewed` → `rejected` · `offer_sent` → `hired`
81
82
 
83
+ ### Google Integration
84
+
85
+ | Tool | Description |
86
+ |---|---|
87
+ | `authorize_google` | OAuth2 authorization flow — opens browser for Google consent (one-time, covers Calendar + Contacts) |
88
+ | `create_calendar_event` | Create events for interviews, meetings, and follow-ups |
89
+ | `add_contact` | Save candidate contact info to Google Contacts with optional group/label |
90
+
91
+ > Google tools only appear when `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` are configured. Enable **People API** and **Calendar API** in Google Cloud Console.
92
+
82
93
  ### System
83
94
 
84
95
  | Tool | Description |
@@ -104,7 +115,7 @@ CV File (PDF/DOCX/Scanned PDF)
104
115
  [3] Chunk into sections
105
116
  │ summary, each experience, education, skills, projects, certifications, full text
106
117
 
107
- [4] Generate embeddings (text-embedding-3-large, 3072d)
118
+ [4] Generate embeddings (text-embedding-3-small, 1536d)
108
119
 
109
120
 
110
121
  [5] Store in LanceDB (candidates + cv_chunks + cv_versions)
@@ -163,7 +174,7 @@ LanceDB tables:
163
174
  | Table | Purpose |
164
175
  |---|---|
165
176
  | `candidates` | Candidate profiles (name, email, skills, experience, loyalty score, tags) |
166
- | `cv_chunks` | Searchable CV sections with 3072-dim vector embeddings |
177
+ | `cv_chunks` | Searchable CV sections with 1536-dim vector embeddings |
167
178
  | `cv_versions` | Archived CV versions for update history |
168
179
  | `job_postings` | Job listings with required/preferred skills and status |
169
180
  | `applications` | Pipeline records linking candidates to jobs with status tracking |
@@ -190,29 +201,20 @@ pnpm build
190
201
 
191
202
  - Node.js >= 22
192
203
  - OpenAI API Key
204
+ - Google Cloud OAuth2 credentials (optional, for calendar integration)
193
205
 
194
206
  ## MCP Configuration
195
207
 
196
208
  ### Claude Code (npx)
197
209
 
198
210
  ```bash
199
- claude mcp add hirebase -- npx -y @dolusoft/hirebase-mcp
200
- ```
201
-
202
- Then set your OpenAI API key:
203
-
204
- ```json
205
- {
206
- "mcpServers": {
207
- "hirebase": {
208
- "command": "npx",
209
- "args": ["-y", "@dolusoft/hirebase-mcp"],
210
- "env": {
211
- "OPENAI_API_KEY": "sk-your-key"
212
- }
213
- }
214
- }
215
- }
211
+ claude mcp add hirebase -s user \
212
+ -e OPENAI_API_KEY=sk-your-key \
213
+ -e EMBEDDING_MODEL=text-embedding-3-small \
214
+ -e DASHBOARD_ENABLED=true \
215
+ -e GOOGLE_CLIENT_ID=your-client-id \
216
+ -e GOOGLE_CLIENT_SECRET=your-client-secret \
217
+ -- npx -y @dolusoft/hirebase-mcp
216
218
  ```
217
219
 
218
220
  ### Claude Desktop
@@ -227,7 +229,9 @@ Add to your Claude Desktop config (`claude_desktop_config.json`):
227
229
  "args": ["-y", "@dolusoft/hirebase-mcp"],
228
230
  "env": {
229
231
  "OPENAI_API_KEY": "sk-your-key",
230
- "LANCEDB_PATH": "./data/lancedb"
232
+ "LANCEDB_PATH": "./data/lancedb",
233
+ "GOOGLE_CLIENT_ID": "your-client-id",
234
+ "GOOGLE_CLIENT_SECRET": "your-client-secret"
231
235
  }
232
236
  }
233
237
  }
@@ -240,10 +244,12 @@ Add to your Claude Desktop config (`claude_desktop_config.json`):
240
244
  |---|---|---|
241
245
  | `OPENAI_API_KEY` | *required* | OpenAI API key |
242
246
  | `LANCEDB_PATH` | `./data/lancedb` | LanceDB storage path |
243
- | `EMBEDDING_MODEL` | `text-embedding-3-large` | Embedding model |
247
+ | `EMBEDDING_MODEL` | `text-embedding-3-small` | Embedding model |
244
248
  | `EXTRACTION_MODEL` | `gpt-5-mini` | CV extraction model |
245
249
  | `DASHBOARD_ENABLED` | `true` | Enable real-time dashboard |
246
250
  | `DASHBOARD_PORT` | `0` (random) | Dashboard server port |
251
+ | `GOOGLE_CLIENT_ID` | — | Google OAuth2 client ID (for calendar) |
252
+ | `GOOGLE_CLIENT_SECRET` | — | Google OAuth2 client secret (for calendar) |
247
253
 
248
254
  ## Key Design Decisions
249
255
 
@@ -255,6 +261,7 @@ Add to your Claude Desktop config (`claude_desktop_config.json`):
255
261
  - **Section-level chunking** — each work experience is a separate chunk for granular matching
256
262
  - **OCR fallback** — image-based PDFs automatically processed with Tesseract.js
257
263
  - **Composite scoring** — matching combines semantic, skill-based, and loyalty signals
264
+ - **Google Calendar** — zero-dependency OAuth2 + Calendar API using Node.js built-in `fetch`
258
265
 
259
266
  ## License
260
267
 
@@ -0,0 +1,42 @@
1
+ export interface CalendarEventInput {
2
+ title: string;
3
+ description?: string;
4
+ location?: string;
5
+ startTime: string;
6
+ endTime: string;
7
+ attendees?: string[];
8
+ }
9
+ export interface CalendarEventResult {
10
+ id: string;
11
+ title: string;
12
+ htmlLink: string;
13
+ startTime: string;
14
+ endTime: string;
15
+ }
16
+ export interface ContactInput {
17
+ firstName: string;
18
+ lastName?: string;
19
+ phone?: string;
20
+ email?: string;
21
+ company?: string;
22
+ title?: string;
23
+ notes?: string;
24
+ groupName?: string;
25
+ }
26
+ export interface ContactResult {
27
+ resourceName: string;
28
+ name: string;
29
+ phone?: string;
30
+ email?: string;
31
+ groupName?: string;
32
+ }
33
+ export interface ICalendarService {
34
+ isAuthorized(): Promise<boolean>;
35
+ authorize(): Promise<{
36
+ success: boolean;
37
+ message: string;
38
+ }>;
39
+ createEvent(event: CalendarEventInput): Promise<CalendarEventResult>;
40
+ deleteEvent(eventId: string): Promise<void>;
41
+ createContact(contact: ContactInput): Promise<ContactResult>;
42
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=calendar-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar-service.js","sourceRoot":"","sources":["../../../src/application/ports/calendar-service.ts"],"names":[],"mappings":""}
@@ -3,7 +3,7 @@ import { EmbeddingError } from '../../shared/errors/index.js';
3
3
  export class OpenAiEmbeddingService {
4
4
  client;
5
5
  model;
6
- constructor(apiKey, model = 'text-embedding-3-large') {
6
+ constructor(apiKey, model = 'text-embedding-3-small') {
7
7
  this.client = new OpenAI({ apiKey });
8
8
  this.model = model;
9
9
  }
@@ -0,0 +1,24 @@
1
+ import type { ICalendarService, CalendarEventInput, CalendarEventResult, ContactInput, ContactResult } from '../../application/ports/calendar-service.js';
2
+ export declare class GoogleCalendarService implements ICalendarService {
3
+ private clientId;
4
+ private clientSecret;
5
+ private tokenPath;
6
+ private tokens;
7
+ private tokensLoaded;
8
+ constructor(clientId: string, clientSecret: string, dataPath: string);
9
+ isAuthorized(): Promise<boolean>;
10
+ authorize(): Promise<{
11
+ success: boolean;
12
+ message: string;
13
+ }>;
14
+ createEvent(event: CalendarEventInput): Promise<CalendarEventResult>;
15
+ deleteEvent(eventId: string): Promise<void>;
16
+ createContact(contact: ContactInput): Promise<ContactResult>;
17
+ private hasRequiredScopes;
18
+ private clearTokens;
19
+ private ensureTokensLoaded;
20
+ private saveTokens;
21
+ private getAccessToken;
22
+ private exchangeCodeForTokens;
23
+ private findOrCreateContactGroup;
24
+ }
@@ -0,0 +1,353 @@
1
+ import { createServer as createHttpServer } from 'node:http';
2
+ import { exec } from 'node:child_process';
3
+ import { readFile, writeFile, mkdir, unlink } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ import { join, dirname } from 'node:path';
6
+ const AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
7
+ const TOKEN_URL = 'https://oauth2.googleapis.com/token';
8
+ const CALENDAR_API = 'https://www.googleapis.com/calendar/v3';
9
+ const PEOPLE_API = 'https://people.googleapis.com/v1';
10
+ const SCOPES = [
11
+ 'https://www.googleapis.com/auth/calendar.events',
12
+ 'https://www.googleapis.com/auth/contacts',
13
+ ];
14
+ const AUTH_TIMEOUT_MS = 120_000;
15
+ const TOKEN_BUFFER_MS = 300_000; // Refresh 5 min before expiry
16
+ export class GoogleCalendarService {
17
+ clientId;
18
+ clientSecret;
19
+ tokenPath;
20
+ tokens = null;
21
+ tokensLoaded = false;
22
+ constructor(clientId, clientSecret, dataPath) {
23
+ this.clientId = clientId;
24
+ this.clientSecret = clientSecret;
25
+ this.tokenPath = join(dirname(dataPath), 'google-token.json');
26
+ }
27
+ async isAuthorized() {
28
+ await this.ensureTokensLoaded();
29
+ return this.tokens !== null && !!this.tokens.refresh_token && this.hasRequiredScopes();
30
+ }
31
+ async authorize() {
32
+ await this.ensureTokensLoaded();
33
+ // If already authorized with all required scopes, skip
34
+ if (this.tokens?.refresh_token && this.hasRequiredScopes()) {
35
+ return { success: true, message: 'Already authorized with Google (Calendar + Contacts).' };
36
+ }
37
+ // If scopes changed, clear old token to force re-auth
38
+ if (this.tokens?.refresh_token && !this.hasRequiredScopes()) {
39
+ await this.clearTokens();
40
+ }
41
+ return new Promise((resolve) => {
42
+ let resolved = false;
43
+ const httpServer = createHttpServer(async (req, res) => {
44
+ if (resolved)
45
+ return;
46
+ const url = new URL(req.url, 'http://localhost');
47
+ const code = url.searchParams.get('code');
48
+ const error = url.searchParams.get('error');
49
+ if (error) {
50
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
51
+ res.end(htmlPage('Yetkilendirme Başarısız', 'Erişim reddedildi. Bu pencereyi kapatabilirsiniz.'));
52
+ resolved = true;
53
+ httpServer.close();
54
+ resolve({ success: false, message: `Authorization denied: ${error}` });
55
+ return;
56
+ }
57
+ if (code) {
58
+ const port = httpServer.address().port;
59
+ try {
60
+ await this.exchangeCodeForTokens(code, `http://localhost:${port}`);
61
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
62
+ res.end(htmlPage('HireBase Yetkilendirildi!', 'Google Calendar + Contacts bağlantısı başarılı. Bu pencereyi kapatabilirsiniz.'));
63
+ resolved = true;
64
+ httpServer.close();
65
+ resolve({ success: true, message: 'Google (Calendar + Contacts) successfully authorized. Token saved.' });
66
+ }
67
+ catch (err) {
68
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
69
+ res.end(htmlPage('Hata', 'Token alınamadı. Lütfen tekrar deneyin.'));
70
+ resolved = true;
71
+ httpServer.close();
72
+ resolve({ success: false, message: `Token exchange failed: ${err.message}` });
73
+ }
74
+ return;
75
+ }
76
+ res.writeHead(404);
77
+ res.end();
78
+ });
79
+ httpServer.listen(0, () => {
80
+ const port = httpServer.address().port;
81
+ const redirectUri = `http://localhost:${port}`;
82
+ const authUrl = new URL(AUTH_URL);
83
+ authUrl.searchParams.set('client_id', this.clientId);
84
+ authUrl.searchParams.set('redirect_uri', redirectUri);
85
+ authUrl.searchParams.set('response_type', 'code');
86
+ authUrl.searchParams.set('scope', SCOPES.join(' '));
87
+ authUrl.searchParams.set('access_type', 'offline');
88
+ authUrl.searchParams.set('prompt', 'consent');
89
+ openBrowser(authUrl.toString());
90
+ setTimeout(() => {
91
+ if (!resolved) {
92
+ resolved = true;
93
+ httpServer.close();
94
+ resolve({ success: false, message: 'Authorization timed out after 120 seconds.' });
95
+ }
96
+ }, AUTH_TIMEOUT_MS);
97
+ });
98
+ });
99
+ }
100
+ // ── Calendar ─────────────────────────────────────────────────────
101
+ async createEvent(event) {
102
+ const accessToken = await this.getAccessToken();
103
+ const body = {
104
+ summary: event.title,
105
+ description: event.description,
106
+ location: event.location,
107
+ start: {
108
+ dateTime: event.startTime,
109
+ timeZone: 'Europe/Istanbul',
110
+ },
111
+ end: {
112
+ dateTime: event.endTime,
113
+ timeZone: 'Europe/Istanbul',
114
+ },
115
+ attendees: event.attendees?.map((email) => ({ email })),
116
+ reminders: {
117
+ useDefault: false,
118
+ overrides: [
119
+ { method: 'popup', minutes: 30 },
120
+ { method: 'popup', minutes: 10 },
121
+ ],
122
+ },
123
+ };
124
+ const response = await fetch(`${CALENDAR_API}/calendars/primary/events`, {
125
+ method: 'POST',
126
+ headers: {
127
+ Authorization: `Bearer ${accessToken}`,
128
+ 'Content-Type': 'application/json',
129
+ },
130
+ body: JSON.stringify(body),
131
+ });
132
+ if (!response.ok) {
133
+ const error = await response.text();
134
+ throw new Error(`Failed to create calendar event: ${error}`);
135
+ }
136
+ const data = (await response.json());
137
+ return {
138
+ id: data.id,
139
+ title: data.summary,
140
+ htmlLink: data.htmlLink,
141
+ startTime: data.start.dateTime,
142
+ endTime: data.end.dateTime,
143
+ };
144
+ }
145
+ async deleteEvent(eventId) {
146
+ const accessToken = await this.getAccessToken();
147
+ const response = await fetch(`${CALENDAR_API}/calendars/primary/events/${eventId}`, {
148
+ method: 'DELETE',
149
+ headers: { Authorization: `Bearer ${accessToken}` },
150
+ });
151
+ if (!response.ok && response.status !== 404) {
152
+ const error = await response.text();
153
+ throw new Error(`Failed to delete calendar event: ${error}`);
154
+ }
155
+ }
156
+ // ── Contacts ─────────────────────────────────────────────────────
157
+ async createContact(contact) {
158
+ const accessToken = await this.getAccessToken();
159
+ // Build People API person resource
160
+ const person = {
161
+ names: [{ givenName: contact.firstName, familyName: contact.lastName ?? '' }],
162
+ };
163
+ if (contact.phone) {
164
+ person.phoneNumbers = [{ value: contact.phone, type: 'mobile' }];
165
+ }
166
+ if (contact.email) {
167
+ person.emailAddresses = [{ value: contact.email, type: 'work' }];
168
+ }
169
+ if (contact.company || contact.title) {
170
+ person.organizations = [{ name: contact.company ?? '', title: contact.title ?? '' }];
171
+ }
172
+ if (contact.notes) {
173
+ person.biographies = [{ value: contact.notes, contentType: 'TEXT_PLAIN' }];
174
+ }
175
+ // If group requested, find or create it
176
+ let groupResourceName;
177
+ if (contact.groupName) {
178
+ groupResourceName = await this.findOrCreateContactGroup(accessToken, contact.groupName);
179
+ if (groupResourceName) {
180
+ person.memberships = [
181
+ { contactGroupMembership: { contactGroupResourceName: groupResourceName } },
182
+ ];
183
+ }
184
+ }
185
+ const response = await fetch(`${PEOPLE_API}/people:createContact`, {
186
+ method: 'POST',
187
+ headers: {
188
+ Authorization: `Bearer ${accessToken}`,
189
+ 'Content-Type': 'application/json',
190
+ },
191
+ body: JSON.stringify(person),
192
+ });
193
+ if (!response.ok) {
194
+ const error = await response.text();
195
+ throw new Error(`Failed to create contact: ${error}`);
196
+ }
197
+ const data = (await response.json());
198
+ return {
199
+ resourceName: data.resourceName,
200
+ name: data.names?.[0]?.displayName ?? `${contact.firstName} ${contact.lastName ?? ''}`.trim(),
201
+ phone: data.phoneNumbers?.[0]?.value,
202
+ email: data.emailAddresses?.[0]?.value,
203
+ groupName: contact.groupName,
204
+ };
205
+ }
206
+ // ── Private helpers ──────────────────────────────────────────────
207
+ hasRequiredScopes() {
208
+ if (!this.tokens?.scopes)
209
+ return false;
210
+ return SCOPES.every((s) => this.tokens.scopes.includes(s));
211
+ }
212
+ async clearTokens() {
213
+ this.tokens = null;
214
+ this.tokensLoaded = true;
215
+ if (existsSync(this.tokenPath)) {
216
+ await unlink(this.tokenPath);
217
+ }
218
+ // Also clean up old token file name
219
+ const oldPath = join(dirname(this.tokenPath), 'google-calendar-token.json');
220
+ if (existsSync(oldPath)) {
221
+ await unlink(oldPath);
222
+ }
223
+ }
224
+ async ensureTokensLoaded() {
225
+ if (this.tokensLoaded)
226
+ return;
227
+ try {
228
+ if (existsSync(this.tokenPath)) {
229
+ const data = await readFile(this.tokenPath, 'utf-8');
230
+ this.tokens = JSON.parse(data);
231
+ }
232
+ else {
233
+ // Migrate from old token file name
234
+ const oldPath = join(dirname(this.tokenPath), 'google-calendar-token.json');
235
+ if (existsSync(oldPath)) {
236
+ const data = await readFile(oldPath, 'utf-8');
237
+ this.tokens = JSON.parse(data);
238
+ }
239
+ }
240
+ }
241
+ catch {
242
+ this.tokens = null;
243
+ }
244
+ this.tokensLoaded = true;
245
+ }
246
+ async saveTokens(tokens) {
247
+ this.tokens = tokens;
248
+ const dir = dirname(this.tokenPath);
249
+ if (!existsSync(dir)) {
250
+ await mkdir(dir, { recursive: true });
251
+ }
252
+ await writeFile(this.tokenPath, JSON.stringify(tokens, null, 2));
253
+ }
254
+ async getAccessToken() {
255
+ await this.ensureTokensLoaded();
256
+ if (!this.tokens?.refresh_token) {
257
+ throw new Error('Not authorized. Call authorize_google first.');
258
+ }
259
+ // Return current token if still valid
260
+ if (this.tokens.expires_at && Date.now() < this.tokens.expires_at - TOKEN_BUFFER_MS) {
261
+ return this.tokens.access_token;
262
+ }
263
+ // Refresh the token
264
+ const response = await fetch(TOKEN_URL, {
265
+ method: 'POST',
266
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
267
+ body: new URLSearchParams({
268
+ client_id: this.clientId,
269
+ client_secret: this.clientSecret,
270
+ refresh_token: this.tokens.refresh_token,
271
+ grant_type: 'refresh_token',
272
+ }),
273
+ });
274
+ if (!response.ok) {
275
+ const error = await response.text();
276
+ throw new Error(`Token refresh failed: ${error}`);
277
+ }
278
+ const data = (await response.json());
279
+ this.tokens.access_token = data.access_token;
280
+ this.tokens.expires_at = Date.now() + data.expires_in * 1000;
281
+ await this.saveTokens(this.tokens);
282
+ return data.access_token;
283
+ }
284
+ async exchangeCodeForTokens(code, redirectUri) {
285
+ const response = await fetch(TOKEN_URL, {
286
+ method: 'POST',
287
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
288
+ body: new URLSearchParams({
289
+ code,
290
+ client_id: this.clientId,
291
+ client_secret: this.clientSecret,
292
+ redirect_uri: redirectUri,
293
+ grant_type: 'authorization_code',
294
+ }),
295
+ });
296
+ if (!response.ok) {
297
+ const error = await response.text();
298
+ throw new Error(error);
299
+ }
300
+ const data = (await response.json());
301
+ await this.saveTokens({
302
+ access_token: data.access_token,
303
+ refresh_token: data.refresh_token,
304
+ token_type: data.token_type,
305
+ expires_at: Date.now() + data.expires_in * 1000,
306
+ scopes: data.scope.split(' '),
307
+ });
308
+ }
309
+ async findOrCreateContactGroup(accessToken, groupName) {
310
+ // List existing groups
311
+ const listResponse = await fetch(`${PEOPLE_API}/contactGroups`, {
312
+ headers: { Authorization: `Bearer ${accessToken}` },
313
+ });
314
+ if (listResponse.ok) {
315
+ const groups = (await listResponse.json());
316
+ const existing = groups.contactGroups?.find((g) => g.name === groupName && g.groupType === 'USER_CONTACT_GROUP');
317
+ if (existing)
318
+ return existing.resourceName;
319
+ }
320
+ // Create new group
321
+ const createResponse = await fetch(`${PEOPLE_API}/contactGroups`, {
322
+ method: 'POST',
323
+ headers: {
324
+ Authorization: `Bearer ${accessToken}`,
325
+ 'Content-Type': 'application/json',
326
+ },
327
+ body: JSON.stringify({ contactGroup: { name: groupName } }),
328
+ });
329
+ if (createResponse.ok) {
330
+ const created = (await createResponse.json());
331
+ return created.resourceName;
332
+ }
333
+ return undefined;
334
+ }
335
+ }
336
+ // ── Utilities ──────────────────────────────────────────────────────
337
+ function openBrowser(url) {
338
+ const cmd = process.platform === 'win32'
339
+ ? `start "" "${url}"`
340
+ : process.platform === 'darwin'
341
+ ? `open "${url}"`
342
+ : `xdg-open "${url}"`;
343
+ exec(cmd);
344
+ }
345
+ function htmlPage(title, message) {
346
+ return `<!DOCTYPE html>
347
+ <html><head><meta charset="utf-8"><title>HireBase</title>
348
+ <style>body{font-family:system-ui;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#f8fafc}
349
+ .card{text-align:center;padding:3rem;border-radius:1rem;background:white;box-shadow:0 4px 24px rgba(0,0,0,.08)}
350
+ h1{color:#0f172a;margin-bottom:.5rem}p{color:#64748b}</style>
351
+ </head><body><div class="card"><h1>${title}</h1><p>${message}</p></div></body></html>`;
352
+ }
353
+ //# sourceMappingURL=google-calendar.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-calendar.service.js","sourceRoot":"","sources":["../../../src/infrastructure/calendar/google-calendar.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { GoogleCalendarService } from './google-calendar.service.js';
@@ -0,0 +1,2 @@
1
+ export { GoogleCalendarService } from './google-calendar.service.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infrastructure/calendar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -5,5 +5,7 @@ export interface AppConfig {
5
5
  extractionModel: string;
6
6
  dashboardEnabled: boolean;
7
7
  dashboardPort: number;
8
+ googleClientId?: string;
9
+ googleClientSecret?: string;
8
10
  }
9
11
  export declare function loadConfig(): AppConfig;
@@ -6,10 +6,12 @@ export function loadConfig() {
6
6
  return {
7
7
  openaiApiKey,
8
8
  lancedbPath: process.env.LANCEDB_PATH ?? './data/lancedb',
9
- embeddingModel: process.env.EMBEDDING_MODEL ?? 'text-embedding-3-small',
9
+ embeddingModel: process.env.EMBEDDING_MODEL ?? 'text-embedding-3-small', // Production uses small (1536d)
10
10
  extractionModel: process.env.EXTRACTION_MODEL ?? 'gpt-5-mini',
11
11
  dashboardEnabled: process.env.DASHBOARD_ENABLED !== 'false',
12
12
  dashboardPort: parseInt(process.env.DASHBOARD_PORT ?? '0', 10),
13
+ googleClientId: process.env.GOOGLE_CLIENT_ID,
14
+ googleClientSecret: process.env.GOOGLE_CLIENT_SECRET,
13
15
  };
14
16
  }
15
17
  //# sourceMappingURL=app-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-config.js","sourceRoot":"","sources":["../../../src/infrastructure/config/app-config.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,UAAU;IACxB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAChD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,OAAO;QACL,YAAY;QACZ,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,gBAAgB;QACzD,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,wBAAwB;QACvE,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,YAAY;QAC7D,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,OAAO;QAC3D,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,EAAE,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"app-config.js","sourceRoot":"","sources":["../../../src/infrastructure/config/app-config.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,UAAU;IACxB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAChD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,OAAO;QACL,YAAY;QACZ,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,gBAAgB;QACzD,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,wBAAwB,EAAE,gCAAgC;QACzG,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,YAAY;QAC7D,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,OAAO;QAC3D,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,EAAE,EAAE,CAAC;QAC9D,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5C,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;KACrD,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/_nuxt/entry.Bl31cpjT.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CdJZeyak.js"><script type="module" src="/_nuxt/CdJZeyak.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"ec2a9f02-6137-4473-bc4f-0e48df1e085b",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771927507070,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/_nuxt/entry.Bl31cpjT.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CdJZeyak.js"><script type="module" src="/_nuxt/CdJZeyak.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"fb00efc4-219c-4174-8827-fe876fe21945",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771936240884,false]</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/_nuxt/entry.Bl31cpjT.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CdJZeyak.js"><script type="module" src="/_nuxt/CdJZeyak.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"ec2a9f02-6137-4473-bc4f-0e48df1e085b",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771927507070,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/_nuxt/entry.Bl31cpjT.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CdJZeyak.js"><script type="module" src="/_nuxt/CdJZeyak.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"fb00efc4-219c-4174-8827-fe876fe21945",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771936240884,false]</script></body></html>
@@ -1 +1 @@
1
- {"id":"ec2a9f02-6137-4473-bc4f-0e48df1e085b","timestamp":1771927503106}
1
+ {"id":"fb00efc4-219c-4174-8827-fe876fe21945","timestamp":1771936236824}
@@ -0,0 +1 @@
1
+ {"id":"32cf8bd4-f9b8-477d-bcff-75df710335e1","timestamp":1771936203708,"prerendered":[]}
@@ -0,0 +1 @@
1
+ {"id":"4d9b8de6-1292-42ca-8f07-c47ba5f61768","timestamp":1771932381046,"prerendered":[]}
@@ -0,0 +1 @@
1
+ {"id":"f4e23d88-bf4b-4110-976f-4e7a2c538e98","timestamp":1771932335753,"prerendered":[]}
@@ -0,0 +1 @@
1
+ {"id":"fb00efc4-219c-4174-8827-fe876fe21945","timestamp":1771936236824,"prerendered":[]}
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/_nuxt/entry.Bl31cpjT.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CdJZeyak.js"><script type="module" src="/_nuxt/CdJZeyak.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"ec2a9f02-6137-4473-bc4f-0e48df1e085b",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771927507070,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/_nuxt/entry.Bl31cpjT.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CdJZeyak.js"><script type="module" src="/_nuxt/CdJZeyak.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"fb00efc4-219c-4174-8827-fe876fe21945",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771936240884,false]</script></body></html>
@@ -12,6 +12,7 @@ import { DocxParser } from '../../infrastructure/parsers/docx-parser.js';
12
12
  import { OpenAiEmbeddingService } from '../../infrastructure/ai/openai-embedding-service.js';
13
13
  import { OpenAiStructuredExtractor } from '../../infrastructure/ai/openai-structured-extractor.js';
14
14
  import { CsvExportService } from '../../infrastructure/export/csv-export-service.js';
15
+ import { GoogleCalendarService } from '../../infrastructure/calendar/google-calendar.service.js';
15
16
  import { DashboardEventBus } from '../dashboard/event-bus.js';
16
17
  import { wrapAllRegisteredTools } from '../dashboard/tool-wrapper.js';
17
18
  import { startDashboardServer } from '../dashboard/server.js';
@@ -42,6 +43,9 @@ import { registerSetPendingActionTool } from './tools/set-pending-action.js';
42
43
  import { registerGetPipelineTool } from './tools/get-pipeline.js';
43
44
  import { registerGetCandidateHistoryTool } from './tools/get-candidate-history.js';
44
45
  import { registerGetPendingActionsTool } from './tools/get-pending-actions.js';
46
+ import { registerAuthorizeCalendarTool } from './tools/authorize-calendar.js';
47
+ import { registerCreateCalendarEventTool } from './tools/create-calendar-event.js';
48
+ import { registerAddContactTool } from './tools/add-contact.js';
45
49
  export async function createServer() {
46
50
  const config = loadConfig();
47
51
  configureVectorDimension(config.embeddingModel);
@@ -56,6 +60,10 @@ export async function createServer() {
56
60
  const embeddingService = new OpenAiEmbeddingService(config.openaiApiKey, config.embeddingModel);
57
61
  const extractor = new OpenAiStructuredExtractor(config.openaiApiKey, config.extractionModel);
58
62
  const exportService = new CsvExportService();
63
+ let calendarService;
64
+ if (config.googleClientId && config.googleClientSecret) {
65
+ calendarService = new GoogleCalendarService(config.googleClientId, config.googleClientSecret, config.lancedbPath);
66
+ }
59
67
  const deps = {
60
68
  candidateRepo,
61
69
  chunkRepo,
@@ -67,6 +75,7 @@ export async function createServer() {
67
75
  embeddingService,
68
76
  extractor,
69
77
  exportService,
78
+ calendarService,
70
79
  };
71
80
  const server = new McpServer({
72
81
  name: 'hirebase',
@@ -99,6 +108,9 @@ export async function createServer() {
99
108
  registerGetPipelineTool(server, deps);
100
109
  registerGetCandidateHistoryTool(server, deps);
101
110
  registerGetPendingActionsTool(server, deps);
111
+ registerAuthorizeCalendarTool(server, deps);
112
+ registerCreateCalendarEventTool(server, deps);
113
+ registerAddContactTool(server, deps);
102
114
  if (config.dashboardEnabled) {
103
115
  const eventBus = new DashboardEventBus();
104
116
  wrapAllRegisteredTools(server, eventBus, deps);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/interface/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,2CAA2C,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,8CAA8C,CAAC;AACrG,OAAO,EAAE,0BAA0B,EAAE,MAAM,kEAAkE,CAAC;AAC9G,OAAO,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAC;AACtG,OAAO,EAAE,wBAAwB,EAAE,MAAM,gEAAgE,CAAC;AAC1G,OAAO,EAAE,2BAA2B,EAAE,MAAM,oEAAoE,CAAC;AACjH,OAAO,EAAE,4BAA4B,EAAE,MAAM,oEAAoE,CAAC;AAClH,OAAO,EAAE,iCAAiC,EAAE,MAAM,0EAA0E,CAAC;AAC7H,OAAO,EAAE,SAAS,EAAE,MAAM,4CAA4C,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,6CAA6C,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qDAAqD,CAAC;AAC7F,OAAO,EAAE,yBAAyB,EAAE,MAAM,wDAAwD,CAAC;AACnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,mDAAmD,CAAC;AAErF,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,mCAAmC,CAAC;AACrF,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAE/E,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,wBAAwB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAChD,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAEjD,MAAM,aAAa,GAAG,IAAI,0BAA0B,CAAC,EAAE,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,IAAI,wBAAwB,CAAC,EAAE,CAAC,CAAC;IACrD,MAAM,cAAc,GAAG,IAAI,2BAA2B,CAAC,EAAE,CAAC,CAAC;IAC3D,MAAM,eAAe,GAAG,IAAI,4BAA4B,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,oBAAoB,GAAG,IAAI,iCAAiC,CAAC,EAAE,CAAC,CAAC;IAEvE,MAAM,OAAO,GAAG,CAAC,IAAI,SAAS,EAAE,EAAE,IAAI,UAAU,EAAE,CAAC,CAAC;IACpD,MAAM,gBAAgB,GAAG,IAAI,sBAAsB,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;IAChG,MAAM,SAAS,GAAG,IAAI,yBAAyB,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IAC7F,MAAM,aAAa,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAE7C,MAAM,IAAI,GAAiB;QACzB,aAAa;QACb,SAAS;QACT,WAAW;QACX,cAAc;QACd,eAAe;QACf,oBAAoB;QACpB,OAAO;QACP,gBAAgB;QAChB,SAAS;QACT,aAAa;KACd,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAChC,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnC,0BAA0B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzC,4BAA4B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC3C,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAClC,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnC,sBAAsB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrC,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxC,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnC,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxC,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxC,2BAA2B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxC,2BAA2B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxC,2BAA2B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,4BAA4B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC3C,4BAA4B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC3C,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxC,gCAAgC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC/C,2BAA2B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,4BAA4B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC3C,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,+BAA+B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC9C,6BAA6B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE5C,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACzC,sBAAsB,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,oBAAoB,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/interface/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { Dependencies } from '../types.js';
3
+ export declare function registerAddContactTool(server: McpServer, deps: Dependencies): void;
@@ -0,0 +1,43 @@
1
+ import { z } from 'zod/v4';
2
+ export function registerAddContactTool(server, deps) {
3
+ if (!deps.calendarService)
4
+ return;
5
+ server.tool('add_contact', 'Add a contact to Google Contacts. Useful for saving candidate phone numbers and details for easy access from your phone.', {
6
+ first_name: z.string().describe('First name'),
7
+ last_name: z.string().optional().describe('Last name'),
8
+ phone: z.string().optional().describe('Phone number (e.g., "+90 543 157 17 55")'),
9
+ email: z.string().optional().describe('Email address'),
10
+ company: z.string().optional().describe('Company / organization name'),
11
+ title: z.string().optional().describe('Job title (e.g., "Senior Frontend Developer")'),
12
+ notes: z.string().optional().describe('Additional notes about the contact'),
13
+ group_name: z
14
+ .string()
15
+ .optional()
16
+ .describe('Contact group/label name (e.g., "HireBase - Senior Frontend Developer"). Auto-created if not exists.'),
17
+ }, async ({ first_name, last_name, phone, email, company, title, notes, group_name }) => {
18
+ try {
19
+ const result = await deps.calendarService.createContact({
20
+ firstName: first_name,
21
+ lastName: last_name,
22
+ phone,
23
+ email,
24
+ company,
25
+ title,
26
+ notes,
27
+ groupName: group_name,
28
+ });
29
+ return {
30
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
31
+ };
32
+ }
33
+ catch (error) {
34
+ return {
35
+ content: [
36
+ { type: 'text', text: JSON.stringify({ error: error.message }) },
37
+ ],
38
+ isError: true,
39
+ };
40
+ }
41
+ });
42
+ }
43
+ //# sourceMappingURL=add-contact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-contact.js","sourceRoot":"","sources":["../../../../src/interface/mcp/tools/add-contact.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAG3B,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,IAAkB;IAC1E,IAAI,CAAC,IAAI,CAAC,eAAe;QAAE,OAAO;IAElC,MAAM,CAAC,IAAI,CACT,aAAa,EACb,0HAA0H,EAC1H;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC7C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;QACjF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;QACtD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QACtE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QACtF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;QAC3E,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,sGAAsG,CAAC;KACpH,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE;QACnF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAgB,CAAC,aAAa,CAAC;gBACvD,SAAS,EAAE,UAAU;gBACrB,QAAQ,EAAE,SAAS;gBACnB,KAAK;gBACL,KAAK;gBACL,OAAO;gBACP,KAAK;gBACL,KAAK;gBACL,SAAS,EAAE,UAAU;aACtB,CAAC,CAAC;YACH,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,EAAE;iBACrF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { Dependencies } from '../types.js';
3
+ export declare function registerAuthorizeCalendarTool(server: McpServer, deps: Dependencies): void;
@@ -0,0 +1,20 @@
1
+ export function registerAuthorizeCalendarTool(server, deps) {
2
+ if (!deps.calendarService)
3
+ return;
4
+ server.tool('authorize_google', 'Authorize HireBase to access Google Calendar and Contacts. Opens browser for Google OAuth consent. Required once before creating calendar events or contacts.', {}, async () => {
5
+ try {
6
+ const result = await deps.calendarService.authorize();
7
+ return {
8
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
9
+ isError: !result.success,
10
+ };
11
+ }
12
+ catch (error) {
13
+ return {
14
+ content: [{ type: 'text', text: JSON.stringify({ error: error.message }) }],
15
+ isError: true,
16
+ };
17
+ }
18
+ });
19
+ }
20
+ //# sourceMappingURL=authorize-calendar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorize-calendar.js","sourceRoot":"","sources":["../../../../src/interface/mcp/tools/authorize-calendar.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,6BAA6B,CAAC,MAAiB,EAAE,IAAkB;IACjF,IAAI,CAAC,IAAI,CAAC,eAAe;QAAE,OAAO;IAElC,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,+JAA+J,EAC/J,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAgB,CAAC,SAAS,EAAE,CAAC;YACvD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC3E,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO;aACzB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBAC/F,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { Dependencies } from '../types.js';
3
+ export declare function registerCreateCalendarEventTool(server: McpServer, deps: Dependencies): void;
@@ -0,0 +1,46 @@
1
+ import { z } from 'zod/v4';
2
+ export function registerCreateCalendarEventTool(server, deps) {
3
+ if (!deps.calendarService)
4
+ return;
5
+ server.tool('create_calendar_event', 'Create an event in Google Calendar. Use for scheduling interviews, meetings, and follow-ups.', {
6
+ title: z.string().describe('Event title (e.g., "Görüşme - Cemre Özer")'),
7
+ start_time: z
8
+ .string()
9
+ .describe('Start time in ISO 8601 format (e.g., "2026-02-26T11:30:00+03:00")'),
10
+ end_time: z
11
+ .string()
12
+ .describe('End time in ISO 8601 format (e.g., "2026-02-26T12:30:00+03:00")'),
13
+ description: z.string().optional().describe('Event description with details'),
14
+ location: z
15
+ .string()
16
+ .optional()
17
+ .describe('Event location (e.g., "WhatsApp Online", "Dolusoft Ofis")'),
18
+ attendees: z
19
+ .array(z.string())
20
+ .optional()
21
+ .describe('List of attendee email addresses'),
22
+ }, async ({ title, start_time, end_time, description, location, attendees }) => {
23
+ try {
24
+ const result = await deps.calendarService.createEvent({
25
+ title,
26
+ startTime: start_time,
27
+ endTime: end_time,
28
+ description,
29
+ location,
30
+ attendees,
31
+ });
32
+ return {
33
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
34
+ };
35
+ }
36
+ catch (error) {
37
+ return {
38
+ content: [
39
+ { type: 'text', text: JSON.stringify({ error: error.message }) },
40
+ ],
41
+ isError: true,
42
+ };
43
+ }
44
+ });
45
+ }
46
+ //# sourceMappingURL=create-calendar-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-calendar-event.js","sourceRoot":"","sources":["../../../../src/interface/mcp/tools/create-calendar-event.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAG3B,MAAM,UAAU,+BAA+B,CAAC,MAAiB,EAAE,IAAkB;IACnF,IAAI,CAAC,IAAI,CAAC,eAAe;QAAE,OAAO;IAElC,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,8FAA8F,EAC9F;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACxE,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,CAAC,mEAAmE,CAAC;QAChF,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,CAAC,iEAAiE,CAAC;QAC9E,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;QAC7E,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,2DAA2D,CAAC;QACxE,SAAS,EAAE,CAAC;aACT,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,QAAQ,EAAE;aACV,QAAQ,CAAC,kCAAkC,CAAC;KAChD,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE;QAC1E,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAgB,CAAC,WAAW,CAAC;gBACrD,KAAK;gBACL,SAAS,EAAE,UAAU;gBACrB,OAAO,EAAE,QAAQ;gBACjB,WAAW;gBACX,QAAQ;gBACR,SAAS;aACV,CAAC,CAAC;YACH,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,EAAE;iBACrF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -5,6 +5,7 @@ import type { IDocumentParser } from '../../application/ports/document-parser.js
5
5
  import type { IEmbeddingService } from '../../application/ports/embedding-service.js';
6
6
  import type { IStructuredExtractor } from '../../application/ports/structured-extractor.js';
7
7
  import type { IExportService } from '../../application/ports/export-service.js';
8
+ import type { ICalendarService } from '../../application/ports/calendar-service.js';
8
9
  import type { IJobPostingRepository } from '../../domain/repositories/job-posting-repository.js';
9
10
  import type { IApplicationRepository } from '../../domain/repositories/application-repository.js';
10
11
  import type { IApplicationEventRepository } from '../../domain/repositories/application-event-repository.js';
@@ -22,5 +23,6 @@ export interface Dependencies {
22
23
  embeddingService: IEmbeddingService;
23
24
  extractor: IStructuredExtractor;
24
25
  exportService: IExportService;
26
+ calendarService?: ICalendarService;
25
27
  }
26
28
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dolusoft/hirebase-mcp",
3
- "version": "1.1.9",
3
+ "version": "1.1.11",
4
4
  "description": "HireBase - AI-powered CV search engine with LanceDB and MCP",
5
5
  "type": "module",
6
6
  "main": "dist/interface/cli/index.js",