@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.
- package/README.md +30 -23
- package/dist/application/ports/calendar-service.d.ts +42 -0
- package/dist/application/ports/calendar-service.js +2 -0
- package/dist/application/ports/calendar-service.js.map +1 -0
- package/dist/infrastructure/ai/openai-embedding-service.js +1 -1
- package/dist/infrastructure/calendar/google-calendar.service.d.ts +24 -0
- package/dist/infrastructure/calendar/google-calendar.service.js +353 -0
- package/dist/infrastructure/calendar/google-calendar.service.js.map +1 -0
- package/dist/infrastructure/calendar/index.d.ts +1 -0
- package/dist/infrastructure/calendar/index.js +2 -0
- package/dist/infrastructure/calendar/index.js.map +1 -0
- package/dist/infrastructure/config/app-config.d.ts +2 -0
- package/dist/infrastructure/config/app-config.js +3 -1
- package/dist/infrastructure/config/app-config.js.map +1 -1
- package/dist/interface/dashboard/public/200.html +1 -1
- package/dist/interface/dashboard/public/404.html +1 -1
- package/dist/interface/dashboard/public/_nuxt/builds/latest.json +1 -1
- package/dist/interface/dashboard/public/_nuxt/builds/meta/32cf8bd4-f9b8-477d-bcff-75df710335e1.json +1 -0
- package/dist/interface/dashboard/public/_nuxt/builds/meta/4d9b8de6-1292-42ca-8f07-c47ba5f61768.json +1 -0
- package/dist/interface/dashboard/public/_nuxt/builds/meta/f4e23d88-bf4b-4110-976f-4e7a2c538e98.json +1 -0
- package/dist/interface/dashboard/public/_nuxt/builds/meta/fb00efc4-219c-4174-8827-fe876fe21945.json +1 -0
- package/dist/interface/dashboard/public/index.html +1 -1
- package/dist/interface/mcp/server.js +12 -0
- package/dist/interface/mcp/server.js.map +1 -1
- package/dist/interface/mcp/tools/add-contact.d.ts +3 -0
- package/dist/interface/mcp/tools/add-contact.js +43 -0
- package/dist/interface/mcp/tools/add-contact.js.map +1 -0
- package/dist/interface/mcp/tools/authorize-calendar.d.ts +3 -0
- package/dist/interface/mcp/tools/authorize-calendar.js +20 -0
- package/dist/interface/mcp/tools/authorize-calendar.js.map +1 -0
- package/dist/interface/mcp/tools/create-calendar-event.d.ts +3 -0
- package/dist/interface/mcp/tools/create-calendar-event.js +46 -0
- package/dist/interface/mcp/tools/create-calendar-event.js.map +1 -0
- package/dist/interface/mcp/types.d.ts +2 -0
- 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-
|
|
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 (
|
|
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-
|
|
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
|
|
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
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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-
|
|
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 @@
|
|
|
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-
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infrastructure/calendar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -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":"
|
|
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:"
|
|
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:"
|
|
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":"
|
|
1
|
+
{"id":"fb00efc4-219c-4174-8827-fe876fe21945","timestamp":1771936236824}
|
package/dist/interface/dashboard/public/_nuxt/builds/meta/32cf8bd4-f9b8-477d-bcff-75df710335e1.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"32cf8bd4-f9b8-477d-bcff-75df710335e1","timestamp":1771936203708,"prerendered":[]}
|
package/dist/interface/dashboard/public/_nuxt/builds/meta/4d9b8de6-1292-42ca-8f07-c47ba5f61768.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"4d9b8de6-1292-42ca-8f07-c47ba5f61768","timestamp":1771932381046,"prerendered":[]}
|
package/dist/interface/dashboard/public/_nuxt/builds/meta/f4e23d88-bf4b-4110-976f-4e7a2c538e98.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"f4e23d88-bf4b-4110-976f-4e7a2c538e98","timestamp":1771932335753,"prerendered":[]}
|
package/dist/interface/dashboard/public/_nuxt/builds/meta/fb00efc4-219c-4174-8827-fe876fe21945.json
ADDED
|
@@ -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:"
|
|
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;
|
|
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;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0DAA0D,CAAC;AAEjG,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;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,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,IAAI,eAAkD,CAAC;IACvD,IAAI,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,kBAAkB,EAAE,CAAC;QACvD,eAAe,GAAG,IAAI,qBAAqB,CACzC,MAAM,CAAC,cAAc,EACrB,MAAM,CAAC,kBAAkB,EACzB,MAAM,CAAC,WAAW,CACnB,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAiB;QACzB,aAAa;QACb,SAAS;QACT,WAAW;QACX,cAAc;QACd,eAAe;QACf,oBAAoB;QACpB,OAAO;QACP,gBAAgB;QAChB,SAAS;QACT,aAAa;QACb,eAAe;KAChB,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;IAC5C,6BAA6B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5C,+BAA+B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC9C,sBAAsB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAErC,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"}
|
|
@@ -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,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,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 {};
|