careervivid 1.12.50 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -19
- package/dist/agent/instructions.d.ts.map +1 -1
- package/dist/agent/instructions.js +21 -0
- package/dist/agent/tools/fetchInterviewContext.d.ts +14 -0
- package/dist/agent/tools/fetchInterviewContext.d.ts.map +1 -0
- package/dist/agent/tools/fetchInterviewContext.js +114 -0
- package/dist/agent/tools/interview.d.ts +13 -0
- package/dist/agent/tools/interview.d.ts.map +1 -0
- package/dist/agent/tools/interview.js +141 -0
- package/dist/commands/admin.d.ts +18 -0
- package/dist/commands/admin.d.ts.map +1 -0
- package/dist/commands/admin.js +187 -0
- package/dist/commands/agent/repl.d.ts.map +1 -1
- package/dist/commands/agent/repl.js +15 -1
- package/dist/commands/agent/toolRegistry.d.ts.map +1 -1
- package/dist/commands/agent/toolRegistry.js +10 -1
- package/dist/commands/interview.d.ts.map +1 -1
- package/dist/commands/interview.js +109 -20
- package/dist/index.js +4 -0
- package/dist/lib/logger.d.ts +108 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +198 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# careervivid · CLI
|
|
2
2
|
|
|
3
|
-
> **Your AI-powered career terminal — autonomous job applications, resume editing, job pipeline tracking, and portfolio publishing from the command line.**
|
|
3
|
+
> **Your AI-powered career terminal — voice mock interviews, autonomous job applications, resume editing, job pipeline tracking, and portfolio publishing from the command line.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/careervivid)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://nodejs.org)
|
|
8
|
+
[](https://www.npmjs.com/package/careervivid)
|
|
8
9
|
|
|
9
10
|
---
|
|
10
11
|
|
|
@@ -12,6 +13,7 @@
|
|
|
12
13
|
|
|
13
14
|
- [Quick Start](#quick-start)
|
|
14
15
|
- [Commands](#commands)
|
|
16
|
+
- [cv interview](#cv-interview) 🎙 **AI Voice Interview**
|
|
15
17
|
- [cv agent](#cv-agent) ⭐ **AI Agent**
|
|
16
18
|
- [cv agent --jobs](#cv-agent---jobs) 🤖 **Autonomous Job Applications**
|
|
17
19
|
- [cv agent --resume](#cv-agent---resume) 📄 **Resume CRUD**
|
|
@@ -40,18 +42,20 @@ npm install -g careervivid
|
|
|
40
42
|
|
|
41
43
|
# 2. Log in and get your free API key
|
|
42
44
|
cv login
|
|
43
|
-
# → opens careervivid.app
|
|
44
|
-
# →
|
|
45
|
-
|
|
45
|
+
# → opens careervivid.app in your browser
|
|
46
|
+
# → authenticate once, API key is saved automatically
|
|
47
|
+
|
|
48
|
+
# 3. Practice an interview with voice AI
|
|
49
|
+
cv interview
|
|
46
50
|
|
|
47
|
-
#
|
|
51
|
+
# 4. Start the AI agent
|
|
48
52
|
cv agent
|
|
49
53
|
|
|
50
|
-
#
|
|
54
|
+
# 5. Or jump straight into job-hunting mode
|
|
51
55
|
cv agent --jobs
|
|
52
56
|
```
|
|
53
57
|
|
|
54
|
-
> **Free tier includes
|
|
58
|
+
> **Free tier includes 10 AI credits/month** — no credit card required.
|
|
55
59
|
|
|
56
60
|
---
|
|
57
61
|
|
|
@@ -59,6 +63,59 @@ cv agent --jobs
|
|
|
59
63
|
|
|
60
64
|
---
|
|
61
65
|
|
|
66
|
+
### `cv interview`
|
|
67
|
+
|
|
68
|
+
**AI-powered voice mock interview** using the Gemini Live API. Vivid, your AI interviewer, conducts a real-time spoken interview tailored to the role you specify. After the session, you receive an auto-generated feedback report with scores and actionable improvement tips.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
cv interview # interactive role prompt, voice mode
|
|
72
|
+
cv interview --role "Senior Software Engineer"
|
|
73
|
+
cv interview --role "Product Manager" --text # text-only fallback (no mic needed)
|
|
74
|
+
cv interview --role "SDE" --resume <id> # load your resume for context
|
|
75
|
+
cv interview --questions 7 # custom question count (default 5)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Requirements (voice mode):**
|
|
79
|
+
- `sox` for audio I/O — install once:
|
|
80
|
+
```bash
|
|
81
|
+
# macOS
|
|
82
|
+
brew install sox
|
|
83
|
+
# Ubuntu / Debian
|
|
84
|
+
sudo apt install sox
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**How it works:**
|
|
88
|
+
|
|
89
|
+
1. Vivid generates tailored interview questions using your role (and resume, if provided)
|
|
90
|
+
2. A real-time voice session opens — speak your answers naturally
|
|
91
|
+
3. Vivid asks follow-up questions and adapts to your responses
|
|
92
|
+
4. Press **Ctrl+C** at any time to end
|
|
93
|
+
5. A structured feedback report is generated covering:
|
|
94
|
+
- Overall, communication, confidence, and relevance scores (0–100)
|
|
95
|
+
- Specific strengths and areas for improvement
|
|
96
|
+
|
|
97
|
+
**Interview History & Coaching:**
|
|
98
|
+
|
|
99
|
+
Every session (transcript + report) is automatically persisted to your CareerVivid account. This enables the **AI Agent** to provide post-interview coaching:
|
|
100
|
+
|
|
101
|
+
1. Complete an interview via `cv interview`.
|
|
102
|
+
2. Start the agent: `cv agent`.
|
|
103
|
+
3. Ask: *"How can I improve my answers from my last interview?"*
|
|
104
|
+
4. The agent retrieves your actual transcript and suggests **STAR-method** improvements for your specific responses.
|
|
105
|
+
|
|
106
|
+
**Credit cost:** **2 credits/minute** (minimum 2, maximum 60 per session)
|
|
107
|
+
|
|
108
|
+
| Session length | Credits |
|
|
109
|
+
|---|---|
|
|
110
|
+
| < 1 min | 2 |
|
|
111
|
+
| 5 min | 10 |
|
|
112
|
+
| 10 min | 20 |
|
|
113
|
+
| 30 min+ | 60 (cap) |
|
|
114
|
+
|
|
115
|
+
> Credits are only charged after the session ends — never upfront.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
62
119
|
### `cv agent`
|
|
63
120
|
|
|
64
121
|
An **autonomous AI agent** that runs interactively in your terminal. Choose from CareerVivid Cloud (credits deducted from your account) or Bring Your Own API Key.
|
|
@@ -294,7 +351,7 @@ CV_API_KEY=cv_live_YOUR_KEY_HERE cv publish article.md
|
|
|
294
351
|
|
|
295
352
|
### `cv login`
|
|
296
353
|
|
|
297
|
-
Open the CareerVivid sign-in page and
|
|
354
|
+
Open the CareerVivid sign-in page and automatically save your API key.
|
|
298
355
|
|
|
299
356
|
```bash
|
|
300
357
|
cv login
|
|
@@ -336,17 +393,20 @@ cv config set llmModel gpt-4o
|
|
|
336
393
|
|
|
337
394
|
| Plan | Credits / Month | Price |
|
|
338
395
|
|---|---|---|
|
|
339
|
-
| **Free** |
|
|
396
|
+
| **Free** | 10 credits | $0 |
|
|
340
397
|
| **Pro** | 1,000 credits | Paid |
|
|
341
398
|
| **Max** | 10,000 credits | Paid |
|
|
342
399
|
|
|
343
|
-
**Credit costs
|
|
400
|
+
**Credit costs by feature:**
|
|
344
401
|
|
|
345
|
-
|
|
|
402
|
+
| Feature | Credits |
|
|
346
403
|
|---|---|
|
|
347
|
-
| `
|
|
348
|
-
| `gemini-
|
|
404
|
+
| `cv interview` (voice) | 2 credits/min (min 2, max 60) |
|
|
405
|
+
| `gemini-3.1-flash-lite-preview` agent turn | 0.5 cr |
|
|
406
|
+
| `gemini-2.5-flash` agent turn | 1 cr |
|
|
349
407
|
| `gemini-3.1-pro-preview` (`--pro`) | 2 cr |
|
|
408
|
+
| Resume tailor | 2 cr |
|
|
409
|
+
| Job evaluation | 3 cr |
|
|
350
410
|
|
|
351
411
|
> **Bring Your Own Key:** Using `--provider openai` (or any non-CareerVivid provider) deducts **zero credits** — you pay your provider directly.
|
|
352
412
|
|
|
@@ -462,12 +522,13 @@ echo "# My Architecture\n\nExplains the new service..." \
|
|
|
462
522
|
You have access to the `cv` CLI tool.
|
|
463
523
|
|
|
464
524
|
Available commands:
|
|
465
|
-
- cv
|
|
466
|
-
- cv
|
|
467
|
-
- cv agent --
|
|
468
|
-
- cv jobs
|
|
469
|
-
- cv jobs
|
|
470
|
-
- cv jobs
|
|
525
|
+
- cv interview AI voice interview (requires sox)
|
|
526
|
+
- cv publish <file> Publish an article (private by default, use --public to share)
|
|
527
|
+
- cv agent --resume Resume CRUD: read, update fields, tailor
|
|
528
|
+
- cv agent --jobs Job hunting + autonomous apply
|
|
529
|
+
- cv jobs hunt --role "..." AI job search
|
|
530
|
+
- cv jobs apply <url> Autonomous form filling (stops before submit)
|
|
531
|
+
- cv jobs list View job tracker
|
|
471
532
|
|
|
472
533
|
Rules:
|
|
473
534
|
1. Never include real API keys in published content.
|
|
@@ -500,6 +561,20 @@ cv auth check
|
|
|
500
561
|
CV_API_KEY=cv_live_YOUR_KEY cv publish article.md
|
|
501
562
|
```
|
|
502
563
|
|
|
564
|
+
**`cv interview` — no audio / can't hear Vivid**
|
|
565
|
+
```bash
|
|
566
|
+
# Install sox first:
|
|
567
|
+
brew install sox # macOS
|
|
568
|
+
sudo apt install sox # Ubuntu/Debian
|
|
569
|
+
|
|
570
|
+
# Then retry:
|
|
571
|
+
cv interview
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
**`cv interview` — hearing echo / Vivid repeating itself**
|
|
575
|
+
|
|
576
|
+
This can occur if your microphone picks up the speaker output. The CLI uses half-duplex mute suppression (mic is muted while Vivid is speaking). Use headphones for the best experience.
|
|
577
|
+
|
|
503
578
|
**`browser_sidecar.py not found`**
|
|
504
579
|
```bash
|
|
505
580
|
# browser-use is not set up. Follow the browser-use Setup section above.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../src/agent/instructions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,eAAO,MAAM,aAAa,QAalB,CAAC;AAMT,eAAO,MAAM,cAAc,QAcnB,CAAC;AAMT,eAAO,MAAM,cAAc,QAqCnB,CAAC;AAMT,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../src/agent/instructions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,eAAO,MAAM,aAAa,QAalB,CAAC;AAMT,eAAO,MAAM,cAAc,QAcnB,CAAC;AAMT,eAAO,MAAM,cAAc,QAqCnB,CAAC;AAMT,eAAO,MAAM,kBAAkB,QA0DvB,CAAC;AAMT,eAAO,MAAM,YAAY,QA6CjB,CAAC;AAMT,eAAO,MAAM,iBAAiB,QAkBtB,CAAC;AAOT;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,MAAM,CAkCT"}
|
|
@@ -127,6 +127,24 @@ These tools read/write the Firebase Kanban board at careervivid.app/job-tracker.
|
|
|
127
127
|
- **verify_url** — Verify a single link is alive before sharing it.
|
|
128
128
|
- **verify_job_urls** — Verify all URLs from a search_jobs result batch.
|
|
129
129
|
NEVER share a link without verifying it first.
|
|
130
|
+
|
|
131
|
+
### 🎙 AI Voice Interview
|
|
132
|
+
- **start_interview** ⭐ — Launch a live AI mock interview session directly in the terminal.
|
|
133
|
+
- Vivid (the AI interviewer) asks tailored questions based on the role and user's resume.
|
|
134
|
+
- User speaks answers (voice mode, requires sox) or types them (text mode).
|
|
135
|
+
- Feedback report auto-generated at the end with scores and improvement tips.
|
|
136
|
+
- **Credit cost:** 2 credits/minute (min 2, max 60). Text mode ~1 credit flat.
|
|
137
|
+
- Use when user says: "practice interview", "mock interview", "interview me for [role]", "I have an interview at [company]", etc.
|
|
138
|
+
- ⚠️ **PRE-FLIGHT REQUIRED:** Before calling this tool, ALWAYS ask the user:
|
|
139
|
+
1. What role (if not already stated)
|
|
140
|
+
2. Voice or Text mode? — Never assume. Ask every time unless user already specified.
|
|
141
|
+
- **fetch_interview_context** — Retrieve the user's recent mock interview sessions (transcript + scores) for coaching.
|
|
142
|
+
- Use when user says: "improve my answers", "review my interview", "how did I do?",
|
|
143
|
+
"coach me on my [company] interview", "what did I say", "help me with STAR stories",
|
|
144
|
+
or any post-interview coaching request.
|
|
145
|
+
- Returns: scores, strengths, areasForImprovement, and the full Q&A transcript.
|
|
146
|
+
- After fetching, provide specific STAR-method rewrites for weak answers.
|
|
147
|
+
- ⭐ After start_interview completes, ALWAYS offer: "Would you like me to review your answers and give coaching tips?"
|
|
130
148
|
`.trim();
|
|
131
149
|
// ---------------------------------------------------------------------------
|
|
132
150
|
// §5 — Autonomous execution harness (appended in --jobs mode)
|
|
@@ -174,6 +192,8 @@ If it does, call tracker_update_job instead — never create a duplicate row.
|
|
|
174
192
|
| view saved openings | openings_list |
|
|
175
193
|
| applied to a specific opening | openings_apply |
|
|
176
194
|
| find NEW companies/roles not yet in tracker | get_resume → search_jobs |
|
|
195
|
+
| practice interview, mock interview, interview me | ask role + voice/text → start_interview |
|
|
196
|
+
| review interview, improve answers, how did I do | fetch_interview_context → STAR coaching |
|
|
177
197
|
`.trim();
|
|
178
198
|
// ---------------------------------------------------------------------------
|
|
179
199
|
// §6 — Greeting protocol (shared across modes)
|
|
@@ -189,6 +209,7 @@ When the user sends a generic greeting ("hey", "hi", "hello", "start"), respond
|
|
|
189
209
|
• 🔍 Search for job opportunities
|
|
190
210
|
• 📊 Check my job pipeline / tracker
|
|
191
211
|
• ✉️ Draft a cover letter or tailor my resume
|
|
212
|
+
• 🎙 Start an AI mock interview (voice or text)
|
|
192
213
|
• 📈 Get an overview of my job search progress
|
|
193
214
|
• 🗓️ Pick up where we left off
|
|
194
215
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fetch_interview_context tool — retrieves the user's recent CLI interview
|
|
3
|
+
* sessions (transcript + feedback report) from Firestore via the
|
|
4
|
+
* cliGetInterviewContext Cloud Function.
|
|
5
|
+
*
|
|
6
|
+
* This allows the agent to:
|
|
7
|
+
* - Review what the user actually said during a mock interview
|
|
8
|
+
* - Identify weak answers by score
|
|
9
|
+
* - Suggest STAR-method improvements for specific questions
|
|
10
|
+
* - Pick up post-interview coaching without requiring copy-paste
|
|
11
|
+
*/
|
|
12
|
+
import { Tool } from "../Tool.js";
|
|
13
|
+
export declare const FetchInterviewContextTool: Tool;
|
|
14
|
+
//# sourceMappingURL=fetchInterviewContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchInterviewContext.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/fetchInterviewContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAqFlC,eAAO,MAAM,yBAAyB,EAAE,IAkCvC,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fetch_interview_context tool — retrieves the user's recent CLI interview
|
|
3
|
+
* sessions (transcript + feedback report) from Firestore via the
|
|
4
|
+
* cliGetInterviewContext Cloud Function.
|
|
5
|
+
*
|
|
6
|
+
* This allows the agent to:
|
|
7
|
+
* - Review what the user actually said during a mock interview
|
|
8
|
+
* - Identify weak answers by score
|
|
9
|
+
* - Suggest STAR-method improvements for specific questions
|
|
10
|
+
* - Pick up post-interview coaching without requiring copy-paste
|
|
11
|
+
*/
|
|
12
|
+
import { Type } from "@google/genai";
|
|
13
|
+
import { getApiKey } from "../../config.js";
|
|
14
|
+
const CLI_CONTEXT_URL = process.env.CV_FUNCTIONS_URL
|
|
15
|
+
? `${process.env.CV_FUNCTIONS_URL}/cliGetInterviewContext`
|
|
16
|
+
: "https://us-west1-jastalk-firebase.cloudfunctions.net/cliGetInterviewContext";
|
|
17
|
+
/** Cap per session to avoid bloating the agent's context window */
|
|
18
|
+
const MAX_TRANSCRIPT_ENTRIES = 40;
|
|
19
|
+
async function fetchInterviewContext(args) {
|
|
20
|
+
const apiKey = getApiKey();
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
return "❌ Not logged in. Run `cv login` first to access your interview history.";
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const res = await fetch(CLI_CONTEXT_URL, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: { "Content-Type": "application/json" },
|
|
28
|
+
body: JSON.stringify({ apiKey, limit: args.limit ?? 3 }),
|
|
29
|
+
});
|
|
30
|
+
if (res.status === 401) {
|
|
31
|
+
return "❌ API key invalid or expired. Run `cv login` to re-authenticate.";
|
|
32
|
+
}
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
return `⚠️ Could not retrieve interview history (HTTP ${res.status}). Try again shortly.`;
|
|
35
|
+
}
|
|
36
|
+
const data = await res.json();
|
|
37
|
+
const sessions = data.sessions ?? [];
|
|
38
|
+
if (sessions.length === 0) {
|
|
39
|
+
return "No recent interview sessions found. Run `cv interview` or start one via `cv agent` to build your history.";
|
|
40
|
+
}
|
|
41
|
+
// Build a compact, agent-readable context string
|
|
42
|
+
const parts = [];
|
|
43
|
+
parts.push(`📋 Found ${sessions.length} recent interview session(s):\n`);
|
|
44
|
+
for (let i = 0; i < sessions.length; i++) {
|
|
45
|
+
const s = sessions[i];
|
|
46
|
+
const date = s.startedAt ? new Date(s.startedAt).toLocaleString() : "Unknown date";
|
|
47
|
+
const duration = s.durationMinutes != null ? `${s.durationMinutes} min` : "N/A";
|
|
48
|
+
parts.push(`─── Session ${i + 1}: ${s.role} (${date}, ${duration}) ───`);
|
|
49
|
+
// Feedback scores
|
|
50
|
+
if (s.feedbackReport) {
|
|
51
|
+
const r = s.feedbackReport;
|
|
52
|
+
parts.push(`Scores: Overall ${r.overallScore}/100 · Communication ${r.communicationScore}/100 · Confidence ${r.confidenceScore}/100 · Relevance ${r.relevanceScore}/100`);
|
|
53
|
+
parts.push(`Strengths: ${r.strengths}`);
|
|
54
|
+
parts.push(`Areas for improvement: ${r.areasForImprovement}`);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
parts.push("(No feedback report available for this session)");
|
|
58
|
+
}
|
|
59
|
+
// Transcript (capped)
|
|
60
|
+
const entries = s.transcript ?? [];
|
|
61
|
+
if (entries.length > 0) {
|
|
62
|
+
parts.push("\nTranscript:");
|
|
63
|
+
const capped = entries.slice(0, MAX_TRANSCRIPT_ENTRIES);
|
|
64
|
+
for (const e of capped) {
|
|
65
|
+
const speaker = e.speaker === "ai" ? "Interviewer" : "Candidate";
|
|
66
|
+
parts.push(` ${speaker}: ${e.text}`);
|
|
67
|
+
}
|
|
68
|
+
if (entries.length > MAX_TRANSCRIPT_ENTRIES) {
|
|
69
|
+
parts.push(` ... (${entries.length - MAX_TRANSCRIPT_ENTRIES} more turns not shown)`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
parts.push("(Transcript not yet available for this session — it may still be saving)");
|
|
74
|
+
}
|
|
75
|
+
parts.push("");
|
|
76
|
+
}
|
|
77
|
+
return parts.join("\n");
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
return `⚠️ Error fetching interview context: ${err.message}`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export const FetchInterviewContextTool = {
|
|
84
|
+
name: "fetch_interview_context",
|
|
85
|
+
description: `Retrieves the user's recent mock interview sessions from the database, including the full transcript and AI feedback scores.
|
|
86
|
+
|
|
87
|
+
Use this tool when the user:
|
|
88
|
+
- Asks to "improve my answers", "review my interview", "how did I do?"
|
|
89
|
+
- Says anything about their last/recent interview performance
|
|
90
|
+
- Wants coaching, STAR-method help, or answer refinement after an interview
|
|
91
|
+
- Asks what specific questions they were asked or what they said
|
|
92
|
+
|
|
93
|
+
RETURNS:
|
|
94
|
+
- Scores (overall, communication, confidence, relevance) for each session
|
|
95
|
+
- Strengths and areas for improvement
|
|
96
|
+
- Full transcript of interviewer questions and candidate answers (capped to 40 turns)
|
|
97
|
+
|
|
98
|
+
After fetching context, provide targeted, STAR-method coaching based on the actual answers given.
|
|
99
|
+
Default: retrieves the 3 most recent sessions.`,
|
|
100
|
+
parameters: {
|
|
101
|
+
type: Type.OBJECT,
|
|
102
|
+
properties: {
|
|
103
|
+
limit: {
|
|
104
|
+
type: Type.INTEGER,
|
|
105
|
+
description: "Number of recent sessions to fetch (1–10). Default: 3.",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
required: [],
|
|
109
|
+
},
|
|
110
|
+
requiresConfirmation: false,
|
|
111
|
+
execute: async (args) => {
|
|
112
|
+
return fetchInterviewContext(args);
|
|
113
|
+
},
|
|
114
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* start_interview tool — launches a live `cv interview` session
|
|
3
|
+
* from within the agent REPL.
|
|
4
|
+
*
|
|
5
|
+
* The tool spawns the interview subprocess with the terminal attached
|
|
6
|
+
* (stdio: "inherit") so the user gets the full interactive voice/text
|
|
7
|
+
* experience without leaving the agent session. When the interview ends
|
|
8
|
+
* the agent picks up again and can discuss results, next steps, etc.
|
|
9
|
+
*/
|
|
10
|
+
import { Tool } from "../Tool.js";
|
|
11
|
+
export declare const StartInterviewTool: Tool;
|
|
12
|
+
export declare const ALL_INTERVIEW_TOOLS: Tool[];
|
|
13
|
+
//# sourceMappingURL=interview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interview.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/interview.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAoFlC,eAAO,MAAM,kBAAkB,EAAE,IAqEhC,CAAC;AAIF,eAAO,MAAM,mBAAmB,EAAE,IAAI,EAAoD,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* start_interview tool — launches a live `cv interview` session
|
|
3
|
+
* from within the agent REPL.
|
|
4
|
+
*
|
|
5
|
+
* The tool spawns the interview subprocess with the terminal attached
|
|
6
|
+
* (stdio: "inherit") so the user gets the full interactive voice/text
|
|
7
|
+
* experience without leaving the agent session. When the interview ends
|
|
8
|
+
* the agent picks up again and can discuss results, next steps, etc.
|
|
9
|
+
*/
|
|
10
|
+
import { spawn } from "child_process";
|
|
11
|
+
import { Type } from "@google/genai";
|
|
12
|
+
/** Resolve the `cv` binary that is currently running this process. */
|
|
13
|
+
function getCvBin() {
|
|
14
|
+
// process.argv[1] is the entry-point JS file.
|
|
15
|
+
// When installed globally via npm, `cv` is a shell wrapper that calls
|
|
16
|
+
// the same binary — we can just re-use process.argv[0] (node) + argv[1].
|
|
17
|
+
// But the cleanest approach is to call the same node + script directly.
|
|
18
|
+
return process.argv[1]; // absolute path to dist/index.js
|
|
19
|
+
}
|
|
20
|
+
async function runInterview(args) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const argv = [
|
|
23
|
+
getCvBin(),
|
|
24
|
+
"interview",
|
|
25
|
+
"--role", args.role,
|
|
26
|
+
];
|
|
27
|
+
if (args.mode === "text")
|
|
28
|
+
argv.push("--text");
|
|
29
|
+
if (args.questions && args.questions > 0) {
|
|
30
|
+
argv.push("--questions", String(args.questions));
|
|
31
|
+
}
|
|
32
|
+
if (args.resume_id)
|
|
33
|
+
argv.push("--resume", args.resume_id);
|
|
34
|
+
// Clear current line + move to fresh line before the interview TUI takes over.
|
|
35
|
+
// This prevents any leftover cursor text from flashing during the session.
|
|
36
|
+
process.stdout.write("\r\x1b[K\n");
|
|
37
|
+
// ── SIGINT isolation ─────────────────────────────────────────────────
|
|
38
|
+
// When the user presses Ctrl+C during the interview:
|
|
39
|
+
// - SIGINT is sent to the whole process group (parent agent + child)
|
|
40
|
+
// - The child (cv interview) handles it: billing → feedback report → exit 0
|
|
41
|
+
// - The parent MUST ignore it, otherwise it terminates and kills the child
|
|
42
|
+
// before the report is generated and shown.
|
|
43
|
+
// We suppress SIGINT on the agent for the lifetime of the subprocess and
|
|
44
|
+
// restore a default handler once the child exits cleanly.
|
|
45
|
+
const noop = () => { };
|
|
46
|
+
process.on("SIGINT", noop); // suppress — child handles it
|
|
47
|
+
// Inherit the terminal so the full interactive TUI works.
|
|
48
|
+
const child = spawn(process.execPath, argv, {
|
|
49
|
+
stdio: "inherit",
|
|
50
|
+
env: process.env,
|
|
51
|
+
});
|
|
52
|
+
const cleanup = () => {
|
|
53
|
+
// Remove our suppressor so future Ctrl+C in the agent REPL works normally.
|
|
54
|
+
process.removeListener("SIGINT", noop);
|
|
55
|
+
};
|
|
56
|
+
child.on("close", (code) => {
|
|
57
|
+
cleanup();
|
|
58
|
+
// code === null means killed by signal (e.g. SIGINT handled by child itself).
|
|
59
|
+
// The child always does billing + report before exiting, so treat as completed.
|
|
60
|
+
if (code === 0 || code === null) {
|
|
61
|
+
resolve(`✅ Interview session for "${args.role}" completed.\n` +
|
|
62
|
+
`The user has received their feedback report above.\n` +
|
|
63
|
+
`You may now discuss their performance, suggest areas for improvement, ` +
|
|
64
|
+
`help them prep specific STAR stories, or start another session.`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
resolve(`⚠️ Interview session ended with exit code ${code}.\n` +
|
|
68
|
+
`This may mean the session was cut short before the report was generated. ` +
|
|
69
|
+
`Ask if they'd like to start another session or discuss their responses.`);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
child.on("error", (err) => {
|
|
73
|
+
cleanup();
|
|
74
|
+
resolve(`❌ Failed to launch interview session: ${err.message}`);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
export const StartInterviewTool = {
|
|
79
|
+
name: "start_interview",
|
|
80
|
+
description: `Launch a live AI mock interview session for the user.
|
|
81
|
+
|
|
82
|
+
Use this tool when the user says ANYTHING like:
|
|
83
|
+
- "Start an interview", "practice interview", "mock interview"
|
|
84
|
+
- "Interview me for [role]", "prep me for [company] interview"
|
|
85
|
+
- "I have an interview at [company], let's practice"
|
|
86
|
+
- "Start a voice interview", "text interview"
|
|
87
|
+
|
|
88
|
+
⚠️ MANDATORY PRE-FLIGHT — before calling this tool, you MUST know:
|
|
89
|
+
1. **role** — which job role to interview for (ask if not mentioned)
|
|
90
|
+
2. **mode** — ALWAYS ask the user: "Voice (real-time speech, requires sox) or Text?"
|
|
91
|
+
Never assume voice. Some users are on servers, don't have a mic, or prefer text.
|
|
92
|
+
Only skip asking if the user already said 'voice' or 'text' in their message.
|
|
93
|
+
3. **questions** — optional, default 5 (no need to ask unless user wants to customize)
|
|
94
|
+
|
|
95
|
+
Example pre-flight:
|
|
96
|
+
User: "Can I take an interview?"
|
|
97
|
+
You: "Sure! What role are you interviewing for, and would you prefer Voice or Text mode?"
|
|
98
|
+
User: "Senior SWE, voice please."
|
|
99
|
+
You: → call start_interview(role="Senior Software Engineer", mode="voice")
|
|
100
|
+
|
|
101
|
+
HOW IT WORKS:
|
|
102
|
+
- Launches the full interactive \`cv interview\` session directly in the terminal.
|
|
103
|
+
- The user speaks (voice mode) or types (text mode) their answers to Vivid, the AI interviewer.
|
|
104
|
+
- At the end, a feedback report with scores and improvement tips is displayed automatically.
|
|
105
|
+
- You (the agent) can then discuss results, coach on weak areas, help build STAR stories, etc.
|
|
106
|
+
|
|
107
|
+
CREDIT COST: 2 credits/minute (minimum 2, capped at 60). Text mode uses ~1 credit flat.
|
|
108
|
+
|
|
109
|
+
DEFAULTS:
|
|
110
|
+
- mode defaults to "voice" (requires sox). Suggest "text" if user is on a server / no mic.
|
|
111
|
+
- questions defaults to 5.`,
|
|
112
|
+
parameters: {
|
|
113
|
+
type: Type.OBJECT,
|
|
114
|
+
properties: {
|
|
115
|
+
role: {
|
|
116
|
+
type: Type.STRING,
|
|
117
|
+
description: "The job role to interview for, e.g. 'Senior Software Engineer', 'Product Manager', 'Data Scientist'.",
|
|
118
|
+
},
|
|
119
|
+
mode: {
|
|
120
|
+
type: Type.STRING,
|
|
121
|
+
enum: ["voice", "text"],
|
|
122
|
+
description: "Interview mode. 'voice' = real-time speech (default, requires sox). 'text' = text-only fallback.",
|
|
123
|
+
},
|
|
124
|
+
questions: {
|
|
125
|
+
type: Type.INTEGER,
|
|
126
|
+
description: "Number of interview questions to generate (1–10). Default: 5.",
|
|
127
|
+
},
|
|
128
|
+
resume_id: {
|
|
129
|
+
type: Type.STRING,
|
|
130
|
+
description: "Optional. CareerVivid resume ID to load as context. The AI will tailor questions to the user's actual background.",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
required: ["role"],
|
|
134
|
+
},
|
|
135
|
+
requiresConfirmation: false,
|
|
136
|
+
execute: async (args) => {
|
|
137
|
+
return runInterview(args);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
import { FetchInterviewContextTool } from "./fetchInterviewContext.js";
|
|
141
|
+
export const ALL_INTERVIEW_TOOLS = [StartInterviewTool, FetchInterviewContextTool];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cv admin — Admin-only commands: log inspection, audit, diagnostics.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* cv admin logs Last 100 events across all features
|
|
6
|
+
* cv admin logs --feature interview Interview events only
|
|
7
|
+
* cv admin logs --feature interview --level error Errors only
|
|
8
|
+
* cv admin logs --uid <userId> Events for a specific user
|
|
9
|
+
* cv admin logs --since 2025-01-01 Events since a date
|
|
10
|
+
* cv admin logs --limit 50 Custom limit (max 500)
|
|
11
|
+
* cv admin logs --json Raw JSON output (pipe-friendly)
|
|
12
|
+
*
|
|
13
|
+
* Access: requires `role: "admin"` on the caller's Firestore user document.
|
|
14
|
+
* Feature logs are written by cli/src/lib/logger.ts and stored in Firestore cliLogs.
|
|
15
|
+
*/
|
|
16
|
+
import { Command } from "commander";
|
|
17
|
+
export declare function registerAdminCommand(program: Command): void;
|
|
18
|
+
//# sourceMappingURL=admin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/commands/admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6FpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoH3D"}
|