4 Commits

Author SHA1 Message Date
76993cf8b3 Merge pull request 'refine' (#9) from FEAT-refine into master
Reviewed-on: #9
2026-09-01 01:20:53 +00:00
KS Jannette
4d17c409be refine 2026-08-31 21:20:19 -04:00
KS Jannette
f96a8541c6 revisions 2026-08-31 16:52:48 -04:00
KS Jannette
8ad47f1d27 hotfix 2026-08-13 19:46:37 -04:00
22 changed files with 3515 additions and 3467 deletions

2
.gitignore vendored
View File

@@ -10,3 +10,5 @@ accountsAndCredentials/token.json.bak
# Runtime output # Runtime output
mailSummaries/ mailSummaries/
// revised Aug 31

View File

@@ -487,4 +487,5 @@ deClawed-Assity-Kitty/
├── vitest.config.ts ├── vitest.config.ts
├── .gitignore ├── .gitignore
└── README.md └── README.md
``` ```
// revised Aug 31

View File

@@ -1,12 +1,12 @@
{ {
"work": { "work": {
"label": "", "label": "",
"tokenFile": "token.json", "tokenFile": "token.json",
"spreadsheetId": "", "spreadsheetId": "",
"calendarId": "primary" "calendarId": "primary"
}, },
"secondary": { "secondary": {
"label": "", "label": "",
"tokenFile": "token-secondary.json" "tokenFile": "token-secondary.json"
} }
} }

View File

@@ -1,11 +1,13 @@
{ {
"installed": { "installed": {
"client_id": "", "client_id": "",
"project_id": "", "project_id": "",
"auth_uri": "https://accounts.google.com/o/oauth2/auth", "auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token", "token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "", "client_secret": "",
"redirect_uris": ["http://localhost"] "redirect_uris": [
} "http://localhost"
} ]
}
}

View File

@@ -1,7 +1,7 @@
{ {
"access_token": "", "access_token": "",
"refresh_token": "", "refresh_token": "",
"scope": "https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/gmail.modify https://www.googleapis.com/auth/calendar.events", "scope": "https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/gmail.modify https://www.googleapis.com/auth/calendar.events",
"token_type": "Bearer", "token_type": "Bearer",
"expiry_date": 0 "expiry_date": 0
} }

6744
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,31 @@
{ {
"name": "assistant", "name": "assistant",
"version": "1.0.0", "version": "1.0.0",
"description": "MCP server for Gmail job application management", "description": "MCP server for Gmail job application management",
"type": "module", "type": "module",
"bin": { "bin": {
"assistant": "./build/index.js" "assistant": "./build/index.js"
}, },
"scripts": { "scripts": {
"build": "tsc && chmod 755 build/index.js", "build": "tsc && chmod 755 build/index.js",
"auth": "npm run build && node build/auth.js", "auth": "npm run build && node build/auth.js",
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest" "test:watch": "vitest"
}, },
"files": [ "files": [
"build" "build"
], ],
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.30.0", "@modelcontextprotocol/sdk": "^1.30.0",
"googleapis": "^171.4.0", "googleapis": "^171.4.0",
"zod": "^3.25.76" "zod": "^3.25.76"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^25.2.3", "@types/node": "^25.2.3",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vitest": "^4.0.18" "vitest": "^4.0.18"
} }
} }

View File

@@ -4,3 +4,5 @@ export const server = new McpServer({
name: "assistant", name: "assistant",
version: "1.0.0", version: "1.0.0",
}); });
// revised Aug 31

View File

@@ -117,3 +117,5 @@ authorize().catch((err) => {
console.error("Authorization failed:", err); console.error("Authorization failed:", err);
process.exit(1); process.exit(1);
}); });
// revised Aug 31

View File

@@ -18,3 +18,5 @@ main().catch((error) => {
console.error("Fatal error in main():", error); console.error("Fatal error in main():", error);
process.exit(1); process.exit(1);
}); });
// revised Aug 31

View File

@@ -149,3 +149,5 @@ export const getSpreadsheetId = (account: string): string => {
export const getCalendarId = (account: string): string => export const getCalendarId = (account: string): string =>
accounts[account]?.calendarId ?? "primary"; accounts[account]?.calendarId ?? "primary";
// revised Aug 31

View File

@@ -54,3 +54,5 @@ server.registerPrompt(
}; };
} }
); );
// revised Aug 31

View File

@@ -11,6 +11,7 @@ The employer confirms receipt of my application but requires no action from me.
Category B - Advancement to Next Step Category B - Advancement to Next Step
The employer wants to move forward. This includes: invitations to schedule a phone screen or interview, requests to complete an assessment or assignment, requests for additional information or documents, or any communication that requires a response or action from me. If an email both acknowledges receipt AND requests action, classify it as B. The employer wants to move forward. This includes: invitations to schedule a phone screen or interview, requests to complete an assessment or assignment, requests for additional information or documents, or any communication that requires a response or action from me. If an email both acknowledges receipt AND requests action, classify it as B.
This does *not* include Greenhouse "security code" emails, other "confirm identity codes" or "identity-confirmation" type emails, "verify candidate account" type emails,
Category C - Rejection Category C - Rejection
The employer declines to move forward. Typical language: "We have decided to pursue other candidates," "Unfortunately, you were not selected," "We will not be moving forward with your application." The employer declines to move forward. Typical language: "We have decided to pursue other candidates," "Unfortunately, you were not selected," "We will not be moving forward with your application."
@@ -19,14 +20,43 @@ Category D - Other
The email does not fit into categories A, B, or C. This includes non-job-application emails, newsletters, promotional content, or ambiguous messages that do not clearly match another category. The email does not fit into categories A, B, or C. This includes non-job-application emails, newsletters, promotional content, or ambiguous messages that do not clearly match another category.
STEP 3: STAR REVIEWED EMAILS STEP 3: STAR REVIEWED EMAILS
- For EVERY single email processed and reviewed in this run (Categories A, B, C, and D), apply the Gmail "STARRED" system label or use your email tool to add a star to the message. - For EVERY email processed and reviewed in this run that is in Category A, C, and D (NOT B), apply the Gmail "STARRED" system label or use your email tool to add a star to the message.
STEP 4: Confirm, via natural language output in the chat window, the total number of emails fetched for review and successfully starred. STEP 4: Confirm, via natural language output in the chat window, the total number of emails fetched for review and starred.
STEP 5: SUMMARIZE emails classified as Category B and Category D. STEP 5: SUMMARIZE emails classified as Category B and Category D, under separate headers, in the chat.
For each, state: For each, state:
1. Sender name and email address 1. Sender name and email address
2. Email subject line 2. Email subject line
3. Date and time received 3. Date and time received
4. Category (B or D) 4. Category (B or D)
5. Suggested action I should take 5. Suggested action I should take
STEP 6: **STRICT COMPLIANCE REQUIRED** **DO NOT FORGET***:
Summarize all "Category B" emails in the chat.
Star all reviewed email
Next, perform the following actions for each "Category B" email:
STEP 7: CREATE CALENDAR EVENTS
Immediately after logging to the spreadsheet, check whether ANY of these fields were populated or updated:
- Recruiter Call Scheduled
- Company First Interview
- Company Second Interview
For EACH of the above fields that contains a date/time, create a Google Calendar event using the create_calendar_event tool:
- Title format: "[<Recruiter Name> Call] Company - Role" or "[First Interview] Company - Role" or "[Second Interview] Company - Role"
- Start date/time: extracted from the email (convert to ISO 8601)
- Duration: 30 minutes unless otherwise specified in the email
- Location: the video meeting link, phone number, or platform name
- Description: include recruiter or company contact name/email/phone, and note whether they have your cell number
STRICT CONSTRAINTS:
- Do not make up phone numbers, links, dates, or anything at all. If it does not exist in text within a verifiable email, IT DOES NOT EXIST.
- PAST-DATE CHECK: Before creating a calendar event: 1) verify today's date from an external, reliable source; 2) compare the proposed meeting date/time against today's date; 3) if the meeting date has already passed, do NOT create a calendar event for it. Still log it to the spreadsheet, but skip the calendar step. The tool will also enforce this server-side.
- As described in more detail below, each new date/time value in a scheduling column = one new calendar event. Never skip this.
- Always use the same account for calendar events as was used for email fetching.
- Do not create duplicate calendar events for the same meeting (same company representative && same job description | same company && same date time)
- If information is not present in the email, leave that field empty (it's OK!) - do not guess or make up information.
// revised Aug 31

View File

@@ -1,20 +1,7 @@
PHASE 2: TAKE ACTION ON CATEGORY B EMAILS PHASE 2: TAKE ACTION ON CATEGORY B EMAILS
After completing classification (Phase 1), perform the following actions for each email classified as Category B (Advancement to Next Step). After completing classification (Phase 1), perform the following actions for each email classified as Category B (Advancement to Next Step).
STEP 1: LOG TO SPREADSHEET STEP 1: CREATE CALENDAR EVENTS
For each Category B email, extract as much of the following information as possible from the email contents and log it using the log_recruiter_contact tool:
A column exists for:
- Recruiter Name
- Recruiter Email
- Recruiter Phone/Tel
- Company/Role the recruiter seeks to fill
- First Contact: the date and time the email was received
- Subsequent Contacts: any follow-up communication with this recruiter about this role
- Recruiter Call Scheduled: if the email contains scheduling information, extract ALL details — date, time, platform (Zoom, MS Teams, Google Meet, etc.), meeting link, phone number to call — and note whether they confirm having your cell number or might not have it
If a row already exists for the same recruiter email + company/role combination (from a previous email), the tool will UPDATE the existing row. Provide all available fields and the tool handles merging.
STEP 2: CREATE CALENDAR EVENTS
Immediately after logging to the spreadsheet, check whether ANY of these fields were populated or updated: Immediately after logging to the spreadsheet, check whether ANY of these fields were populated or updated:
- Recruiter Call Scheduled - Recruiter Call Scheduled
- Company First Interview - Company First Interview
@@ -27,12 +14,6 @@ For EACH of the above fields that contains a date/time, create a Google Calendar
- Location: the video meeting link, phone number, or platform name - Location: the video meeting link, phone number, or platform name
- Description: include recruiter or company contact name/email/phone, and note whether they have your cell number - Description: include recruiter or company contact name/email/phone, and note whether they have your cell number
STEP 3: COMPANY INTERVIEW TRACKING
When an email indicates advancement beyond the recruiter screen to a company interview:
- Populate the Company First Interview or Company Second Interview field with details
- Those details should include company contact info (interviewer name, email, phone)
- Then immediately create a calendar event for the new interview date/time including interviewer name, email, phone
STRICT CONSTRAINTS: STRICT CONSTRAINTS:
- Do not make up phone numbers, links, dates, or anything at all. If it does not exist in text within a verifiable email, IT DOES NOT EXIST. - Do not make up phone numbers, links, dates, or anything at all. If it does not exist in text within a verifiable email, IT DOES NOT EXIST.
- PAST-DATE CHECK: Before creating a calendar event: 1) verify today's date from an external, reliable source; 2) compare the proposed meeting date/time against today's date; 3) if the meeting date has already passed, do NOT create a calendar event for it. Still log it to the spreadsheet, but skip the calendar step. The tool will also enforce this server-side. - PAST-DATE CHECK: Before creating a calendar event: 1) verify today's date from an external, reliable source; 2) compare the proposed meeting date/time against today's date; 3) if the meeting date has already passed, do NOT create a calendar event for it. Still log it to the spreadsheet, but skip the calendar step. The tool will also enforce this server-side.
@@ -40,3 +21,5 @@ STRICT CONSTRAINTS:
- Always use the same account for calendar events as was used for email fetching. - Always use the same account for calendar events as was used for email fetching.
- Do not create duplicate calendar events for the same meeting (same company representative && same job description | same company && same date time) - Do not create duplicate calendar events for the same meeting (same company representative && same job description | same company && same date time)
- If information is not present in the email, leave that field empty (it's OK!) - do not guess or make up information. - If information is not present in the email, leave that field empty (it's OK!) - do not guess or make up information.
// revised Aug 31

View File

@@ -109,3 +109,5 @@ server.registerTool(
} }
} }
); );
// revised Aug 31

View File

@@ -358,3 +358,5 @@ server.registerTool(
} }
} }
); );
// revised Aug 31

View File

@@ -177,3 +177,5 @@ server.registerTool(
} }
} }
); );
// revised Aug 31

View File

@@ -165,3 +165,5 @@ export const RAW_BODIES = {
"msg-cat-c-001": catCBody, "msg-cat-c-001": catCBody,
"msg-cat-d-001": catDBody, "msg-cat-d-001": catDBody,
}; };
// revised Aug 31

View File

@@ -285,3 +285,5 @@ describe("Phase 1: Email Review Workflow", () => {
}); });
}); });
}); });
// revised Aug 31

View File

@@ -84,3 +84,5 @@ describe("decodeBody", () => {
expect(decodeBody(msg)).toBe(htmlContent); expect(decodeBody(msg)).toBe(htmlContent);
}); });
}); });
// revised Aug 31

View File

@@ -1,15 +1,21 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2022", "target": "ES2022",
"module": "Node16", "module": "Node16",
"moduleResolution": "Node16", "moduleResolution": "Node16",
"outDir": "./build", "outDir": "./build",
"rootDir": "./src", "rootDir": "./src",
"strict": true, "strict": true,
"esModuleInterop": true, "esModuleInterop": true,
"skipLibCheck": true, "skipLibCheck": true,
"forceConsistentCasingInFileNames": true "forceConsistentCasingInFileNames": true
}, },
"include": ["src/**/*"], "include": [
"exclude": ["node_modules", "test", "vitest.config.ts"] "src/**/*"
} ],
"exclude": [
"node_modules",
"test",
"vitest.config.ts"
]
}

View File

@@ -6,3 +6,5 @@ export default defineConfig({
globals: true, globals: true,
}, },
}); });
// revised Aug 31