careervivid 1.12.48 → 2.0.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 +85 -19
- package/dist/agent/instructions.d.ts.map +1 -1
- package/dist/agent/instructions.js +10 -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 +106 -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/toolRegistry.d.ts.map +1 -1
- package/dist/commands/agent/toolRegistry.js +6 -1
- package/dist/commands/interview.d.ts +21 -0
- package/dist/commands/interview.d.ts.map +1 -0
- package/dist/commands/interview.js +738 -0
- 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/dist/index.js
CHANGED
|
@@ -53,6 +53,8 @@ import { registerJobsCommand } from "./commands/jobs.js";
|
|
|
53
53
|
import { registerResumesCommand } from "./commands/resumes.js";
|
|
54
54
|
import { registerReferralCommand } from "./commands/referral.js";
|
|
55
55
|
import { registerEvalCommand } from "./commands/eval.js";
|
|
56
|
+
import { registerInterviewCommand } from "./commands/interview.js";
|
|
57
|
+
import { registerAdminCommand } from "./commands/admin.js";
|
|
56
58
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
57
59
|
const pkg = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
|
|
58
60
|
const program = new Command();
|
|
@@ -77,6 +79,8 @@ registerJobsCommand(program);
|
|
|
77
79
|
registerResumesCommand(program);
|
|
78
80
|
registerReferralCommand(program);
|
|
79
81
|
registerEvalCommand(program);
|
|
82
|
+
registerInterviewCommand(program);
|
|
83
|
+
registerAdminCommand(program);
|
|
80
84
|
// Shortcuts for whiteboard creation
|
|
81
85
|
registerNewCommand(program);
|
|
82
86
|
registerListTemplatesCommand(program);
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CVLogger — Generic structured logging module for the CareerVivid CLI.
|
|
3
|
+
*
|
|
4
|
+
* Design goals:
|
|
5
|
+
* - Zero-friction: never throws, never blocks the user — fire-and-forget
|
|
6
|
+
* - Extensible: one logger per command/feature, sessionId for event correlation
|
|
7
|
+
* - Dual-sink: (1) remote POST to cliLog Cloud Function, (2) local JSONL fallback
|
|
8
|
+
* - Buffered: batched remote flushes to minimize network calls
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* import { createLogger } from "../lib/logger.js";
|
|
12
|
+
* const log = createLogger("interview", { sessionId, apiKey, version: pkg.version });
|
|
13
|
+
* log.info("session_start", { role, numQuestions });
|
|
14
|
+
* log.error("connection_error", err, { phase: "websocket_open" });
|
|
15
|
+
* await log.dispose(); // flush before process exit
|
|
16
|
+
*
|
|
17
|
+
* Extending to new features — no changes to this file needed:
|
|
18
|
+
* const agentLog = createLogger("agent", { apiKey, version });
|
|
19
|
+
* const resumeLog = createLogger("resume", { sessionId: resumeId, apiKey, version });
|
|
20
|
+
*/
|
|
21
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
22
|
+
export interface LogEvent {
|
|
23
|
+
/** Severity level */
|
|
24
|
+
level: LogLevel;
|
|
25
|
+
/** Feature area: "interview" | "agent" | "resume" | ... */
|
|
26
|
+
feature: string;
|
|
27
|
+
/** Machine-readable event name: "session_start" | "billing_complete" | ... */
|
|
28
|
+
event: string;
|
|
29
|
+
/** Optional session/entity correlation ID */
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
/** Arbitrary serializable metadata */
|
|
32
|
+
metadata?: Record<string, unknown>;
|
|
33
|
+
/** Error message (when level === "error") */
|
|
34
|
+
errorMessage?: string;
|
|
35
|
+
/** Error stack trace (when level === "error") */
|
|
36
|
+
errorStack?: string;
|
|
37
|
+
/** ISO 8601 timestamp from the client */
|
|
38
|
+
clientTime: string;
|
|
39
|
+
/** CLI package.json version */
|
|
40
|
+
cliVersion: string;
|
|
41
|
+
}
|
|
42
|
+
export declare class CVLogger {
|
|
43
|
+
private readonly _feature;
|
|
44
|
+
private _sessionId;
|
|
45
|
+
private readonly _flushUrl;
|
|
46
|
+
private readonly _apiKey;
|
|
47
|
+
private readonly _cliVersion;
|
|
48
|
+
private readonly _localLogDir;
|
|
49
|
+
private _buffer;
|
|
50
|
+
private _flushing;
|
|
51
|
+
private _disposed;
|
|
52
|
+
private _flushTimer;
|
|
53
|
+
private static readonly FLUSH_INTERVAL_MS;
|
|
54
|
+
private static readonly FLUSH_BUFFER_SIZE;
|
|
55
|
+
constructor(opts: {
|
|
56
|
+
feature: string;
|
|
57
|
+
sessionId?: string;
|
|
58
|
+
flushUrl: string;
|
|
59
|
+
apiKey?: string;
|
|
60
|
+
cliVersion: string;
|
|
61
|
+
localLogDir?: string;
|
|
62
|
+
});
|
|
63
|
+
/** Informational event. */
|
|
64
|
+
info(event: string, metadata?: Record<string, unknown>): void;
|
|
65
|
+
/** Warning event. */
|
|
66
|
+
warn(event: string, metadata?: Record<string, unknown>): void;
|
|
67
|
+
/**
|
|
68
|
+
* Error event. Accepts Error objects or any thrown value.
|
|
69
|
+
* Serializes the error — never rethrows.
|
|
70
|
+
*/
|
|
71
|
+
error(event: string, err?: unknown, metadata?: Record<string, unknown>): void;
|
|
72
|
+
/**
|
|
73
|
+
* Record a numeric metric (latency, token count, credit charge, etc.)
|
|
74
|
+
* Stored as an "info" event with metricName + metricValue in metadata.
|
|
75
|
+
*/
|
|
76
|
+
metric(name: string, value: number, metadata?: Record<string, unknown>): void;
|
|
77
|
+
/**
|
|
78
|
+
* Update the sessionId after construction.
|
|
79
|
+
* Use when the sessionId isn't available until after an async call.
|
|
80
|
+
*/
|
|
81
|
+
setSessionId(sessionId: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Flush buffered events to the remote endpoint.
|
|
84
|
+
* Safe to call multiple times — idempotent. Never throws.
|
|
85
|
+
*/
|
|
86
|
+
flush(): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Dispose: stop auto-flush timer + flush remaining events.
|
|
89
|
+
* Always call before the command exits (use try/finally).
|
|
90
|
+
*/
|
|
91
|
+
dispose(): Promise<void>;
|
|
92
|
+
private _push;
|
|
93
|
+
private _writeLocal;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a feature-scoped logger. Pass this around; call dispose() at the end.
|
|
97
|
+
*
|
|
98
|
+
* @param feature "interview" | "agent" | "resume" | "jobs" | etc.
|
|
99
|
+
* @param opts.sessionId Correlation ID (interview sessionId, resumeId, …)
|
|
100
|
+
* @param opts.apiKey CareerVivid cv_live_ key (for remote attribution)
|
|
101
|
+
* @param opts.version CLI version from package.json
|
|
102
|
+
*/
|
|
103
|
+
export declare function createLogger(feature: string, opts?: {
|
|
104
|
+
sessionId?: string;
|
|
105
|
+
apiKey?: string;
|
|
106
|
+
version?: string;
|
|
107
|
+
}): CVLogger;
|
|
108
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAQH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,QAAQ;IACrB,qBAAqB;IACrB,KAAK,EAAE,QAAQ,CAAC;IAChB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;CACtB;AAID,qBAAa,QAAQ;IACjB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAEtC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAA+C;IAElE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAU;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAM;gBAEnC,IAAI,EAAE;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;KACxB;IAwBD,2BAA2B;IAC3B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI7D,qBAAqB;IACrB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI7D;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAc7E;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI7E;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIrC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5B;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,OAAO,CAAC,KAAK;IA+Bb,OAAO,CAAC,WAAW;CAOtB;AAWD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACrE,QAAQ,CAQV"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CVLogger — Generic structured logging module for the CareerVivid CLI.
|
|
3
|
+
*
|
|
4
|
+
* Design goals:
|
|
5
|
+
* - Zero-friction: never throws, never blocks the user — fire-and-forget
|
|
6
|
+
* - Extensible: one logger per command/feature, sessionId for event correlation
|
|
7
|
+
* - Dual-sink: (1) remote POST to cliLog Cloud Function, (2) local JSONL fallback
|
|
8
|
+
* - Buffered: batched remote flushes to minimize network calls
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* import { createLogger } from "../lib/logger.js";
|
|
12
|
+
* const log = createLogger("interview", { sessionId, apiKey, version: pkg.version });
|
|
13
|
+
* log.info("session_start", { role, numQuestions });
|
|
14
|
+
* log.error("connection_error", err, { phase: "websocket_open" });
|
|
15
|
+
* await log.dispose(); // flush before process exit
|
|
16
|
+
*
|
|
17
|
+
* Extending to new features — no changes to this file needed:
|
|
18
|
+
* const agentLog = createLogger("agent", { apiKey, version });
|
|
19
|
+
* const resumeLog = createLogger("resume", { sessionId: resumeId, apiKey, version });
|
|
20
|
+
*/
|
|
21
|
+
import { appendFileSync, mkdirSync, existsSync } from "fs";
|
|
22
|
+
import { join } from "path";
|
|
23
|
+
import { homedir } from "os";
|
|
24
|
+
// ─── Logger class ─────────────────────────────────────────────────────────────
|
|
25
|
+
export class CVLogger {
|
|
26
|
+
_feature;
|
|
27
|
+
_sessionId;
|
|
28
|
+
_flushUrl;
|
|
29
|
+
_apiKey;
|
|
30
|
+
_cliVersion;
|
|
31
|
+
_localLogDir;
|
|
32
|
+
_buffer = [];
|
|
33
|
+
_flushing = false;
|
|
34
|
+
_disposed = false;
|
|
35
|
+
_flushTimer = null;
|
|
36
|
+
static FLUSH_INTERVAL_MS = 60_000;
|
|
37
|
+
static FLUSH_BUFFER_SIZE = 25;
|
|
38
|
+
constructor(opts) {
|
|
39
|
+
this._feature = opts.feature;
|
|
40
|
+
this._sessionId = opts.sessionId;
|
|
41
|
+
this._flushUrl = opts.flushUrl;
|
|
42
|
+
this._apiKey = opts.apiKey;
|
|
43
|
+
this._cliVersion = opts.cliVersion;
|
|
44
|
+
this._localLogDir = opts.localLogDir ?? join(homedir(), ".cv", "logs");
|
|
45
|
+
// Ensure local log directory exists
|
|
46
|
+
try {
|
|
47
|
+
if (!existsSync(this._localLogDir)) {
|
|
48
|
+
mkdirSync(this._localLogDir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch { /* non-fatal */ }
|
|
52
|
+
// Auto-flush timer — unref() so it doesn't prevent clean process exit
|
|
53
|
+
this._flushTimer = setInterval(() => {
|
|
54
|
+
if (this._buffer.length > 0)
|
|
55
|
+
this.flush().catch(() => { });
|
|
56
|
+
}, CVLogger.FLUSH_INTERVAL_MS);
|
|
57
|
+
this._flushTimer.unref?.();
|
|
58
|
+
}
|
|
59
|
+
// ── Public API ────────────────────────────────────────────────────────────
|
|
60
|
+
/** Informational event. */
|
|
61
|
+
info(event, metadata) {
|
|
62
|
+
this._push("info", event, metadata);
|
|
63
|
+
}
|
|
64
|
+
/** Warning event. */
|
|
65
|
+
warn(event, metadata) {
|
|
66
|
+
this._push("warn", event, metadata);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Error event. Accepts Error objects or any thrown value.
|
|
70
|
+
* Serializes the error — never rethrows.
|
|
71
|
+
*/
|
|
72
|
+
error(event, err, metadata) {
|
|
73
|
+
let errorMessage;
|
|
74
|
+
let errorStack;
|
|
75
|
+
if (err instanceof Error) {
|
|
76
|
+
errorMessage = err.message;
|
|
77
|
+
errorStack = err.stack;
|
|
78
|
+
}
|
|
79
|
+
else if (typeof err === "string") {
|
|
80
|
+
errorMessage = err;
|
|
81
|
+
}
|
|
82
|
+
else if (err != null) {
|
|
83
|
+
try {
|
|
84
|
+
errorMessage = JSON.stringify(err);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
errorMessage = String(err);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this._push("error", event, metadata, errorMessage, errorStack);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Record a numeric metric (latency, token count, credit charge, etc.)
|
|
94
|
+
* Stored as an "info" event with metricName + metricValue in metadata.
|
|
95
|
+
*/
|
|
96
|
+
metric(name, value, metadata) {
|
|
97
|
+
this._push("info", `metric:${name}`, { ...metadata, metricName: name, metricValue: value });
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Update the sessionId after construction.
|
|
101
|
+
* Use when the sessionId isn't available until after an async call.
|
|
102
|
+
*/
|
|
103
|
+
setSessionId(sessionId) {
|
|
104
|
+
this._sessionId = sessionId;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Flush buffered events to the remote endpoint.
|
|
108
|
+
* Safe to call multiple times — idempotent. Never throws.
|
|
109
|
+
*/
|
|
110
|
+
async flush() {
|
|
111
|
+
if (this._flushing || this._buffer.length === 0 || !this._apiKey)
|
|
112
|
+
return;
|
|
113
|
+
this._flushing = true;
|
|
114
|
+
const batch = this._buffer.splice(0); // atomic drain
|
|
115
|
+
try {
|
|
116
|
+
await fetch(this._flushUrl, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: { "Content-Type": "application/json" },
|
|
119
|
+
body: JSON.stringify({ apiKey: this._apiKey, events: batch }),
|
|
120
|
+
signal: AbortSignal.timeout(8_000),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Remote flush failed: events are already in local JSONL file.
|
|
125
|
+
// Don't re-buffer — avoids memory growth on persistent failures.
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
this._flushing = false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Dispose: stop auto-flush timer + flush remaining events.
|
|
133
|
+
* Always call before the command exits (use try/finally).
|
|
134
|
+
*/
|
|
135
|
+
async dispose() {
|
|
136
|
+
if (this._disposed)
|
|
137
|
+
return;
|
|
138
|
+
this._disposed = true;
|
|
139
|
+
if (this._flushTimer) {
|
|
140
|
+
clearInterval(this._flushTimer);
|
|
141
|
+
this._flushTimer = null;
|
|
142
|
+
}
|
|
143
|
+
await this.flush();
|
|
144
|
+
}
|
|
145
|
+
// ── Internal ──────────────────────────────────────────────────────────────
|
|
146
|
+
_push(level, event, metadata, errorMessage, errorStack) {
|
|
147
|
+
if (this._disposed)
|
|
148
|
+
return;
|
|
149
|
+
const entry = {
|
|
150
|
+
level,
|
|
151
|
+
feature: this._feature,
|
|
152
|
+
event,
|
|
153
|
+
sessionId: this._sessionId,
|
|
154
|
+
metadata,
|
|
155
|
+
errorMessage,
|
|
156
|
+
errorStack,
|
|
157
|
+
clientTime: new Date().toISOString(),
|
|
158
|
+
cliVersion: this._cliVersion,
|
|
159
|
+
};
|
|
160
|
+
// Write to local JSONL immediately (synchronous, best-effort)
|
|
161
|
+
this._writeLocal(entry);
|
|
162
|
+
this._buffer.push(entry);
|
|
163
|
+
// Trigger remote flush if buffer is large enough
|
|
164
|
+
if (this._buffer.length >= CVLogger.FLUSH_BUFFER_SIZE) {
|
|
165
|
+
this.flush().catch(() => { });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
_writeLocal(entry) {
|
|
169
|
+
try {
|
|
170
|
+
const date = entry.clientTime.slice(0, 10); // YYYY-MM-DD
|
|
171
|
+
const logFile = join(this._localLogDir, `${this._feature}-${date}.jsonl`);
|
|
172
|
+
appendFileSync(logFile, JSON.stringify(entry) + "\n");
|
|
173
|
+
}
|
|
174
|
+
catch { /* local write failure is non-fatal */ }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
178
|
+
const CLI_LOG_URL = process.env.CV_FUNCTIONS_URL
|
|
179
|
+
? `${process.env.CV_FUNCTIONS_URL}/cliLog`
|
|
180
|
+
: "https://us-west1-jastalk-firebase.cloudfunctions.net/cliLog";
|
|
181
|
+
// ─── Factory ──────────────────────────────────────────────────────────────────
|
|
182
|
+
/**
|
|
183
|
+
* Create a feature-scoped logger. Pass this around; call dispose() at the end.
|
|
184
|
+
*
|
|
185
|
+
* @param feature "interview" | "agent" | "resume" | "jobs" | etc.
|
|
186
|
+
* @param opts.sessionId Correlation ID (interview sessionId, resumeId, …)
|
|
187
|
+
* @param opts.apiKey CareerVivid cv_live_ key (for remote attribution)
|
|
188
|
+
* @param opts.version CLI version from package.json
|
|
189
|
+
*/
|
|
190
|
+
export function createLogger(feature, opts = {}) {
|
|
191
|
+
return new CVLogger({
|
|
192
|
+
feature,
|
|
193
|
+
sessionId: opts.sessionId,
|
|
194
|
+
flushUrl: CLI_LOG_URL,
|
|
195
|
+
apiKey: opts.apiKey,
|
|
196
|
+
cliVersion: opts.version ?? "unknown",
|
|
197
|
+
});
|
|
198
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "careervivid",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Official CLI for CareerVivid —
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Official CLI for CareerVivid — AI voice interviews, autonomous job applications, resume editing, and portfolio publishing from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cv": "dist/index.js",
|
|
@@ -57,10 +57,15 @@
|
|
|
57
57
|
"keywords": [
|
|
58
58
|
"careervivid",
|
|
59
59
|
"cli",
|
|
60
|
+
"ai-interview",
|
|
61
|
+
"voice-interview",
|
|
62
|
+
"mock-interview",
|
|
63
|
+
"job-search",
|
|
60
64
|
"developer-tools",
|
|
61
65
|
"publish",
|
|
62
66
|
"portfolio",
|
|
63
67
|
"ai-agent",
|
|
68
|
+
"resume",
|
|
64
69
|
"mcp"
|
|
65
70
|
],
|
|
66
71
|
"author": "CareerVivid",
|