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/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": "1.12.48",
4
- "description": "Official CLI for CareerVivid — publish articles, diagrams, and portfolio updates from your terminal or AI agent",
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",