careervivid 1.12.14 → 1.12.16

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.
@@ -1 +1 @@
1
- {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../../src/commands/agent/repl.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAA4B,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAI7E,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,GAAE,MAAM,GAAG,IAAW,QAwBtF;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,WAAW,GAAG,sBAAsB,GAAG,IAAI,EACnD,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EAC9K,gBAAgB,EAAE,WAAW,EAC7B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,GAAG,EAAE,GACX,OAAO,CAAC,IAAI,CAAC,CAmVf"}
1
+ {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../../src/commands/agent/repl.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAA4B,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAI7E,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,GAAE,MAAM,GAAG,IAAW,QAwBtF;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,WAAW,GAAG,sBAAsB,GAAG,IAAI,EACnD,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EAC9K,gBAAgB,EAAE,WAAW,EAC7B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,GAAG,EAAE,GACX,OAAO,CAAC,IAAI,CAAC,CA4Yf"}
@@ -31,6 +31,29 @@ export async function askLoop(engine, options, selectedProvider, selectedModel,
31
31
  let currentModel = selectedModel;
32
32
  let pasteBuffer = [];
33
33
  let byoHistory = []; // Track history for BYO providers
34
+ // ── SIGINT handler: Ctrl+C cancels current operation and returns to prompt ──
35
+ let activeAbort = null;
36
+ const handleSigInt = () => {
37
+ const ab = activeAbort;
38
+ if (ab !== null && !ab.signal.aborted) {
39
+ ab.abort();
40
+ process.stdout.write("\n" + chalk.yellow("⚡ Interrupted. Press Ctrl+C again or type 'exit' to quit.\n"));
41
+ }
42
+ else {
43
+ // Second Ctrl+C exits
44
+ console.log(chalk.gray("\nGoodbye! 👋\n"));
45
+ process.exit(0);
46
+ }
47
+ };
48
+ process.on("SIGINT", handleSigInt);
49
+ /** Wraps a promise with a timeout. Rejects with a friendly timeout error. */
50
+ function withTimeout(p, ms, label) {
51
+ return new Promise((resolve, reject) => {
52
+ const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms / 1000}s. Press Ctrl+C if stuck.`)), ms);
53
+ p.then(v => { clearTimeout(timer); resolve(v); })
54
+ .catch(e => { clearTimeout(timer); reject(e); });
55
+ });
56
+ }
34
57
  const ask = async () => {
35
58
  try {
36
59
  const promptStartTime = Date.now();
@@ -41,8 +64,33 @@ export async function askLoop(engine, options, selectedProvider, selectedModel,
41
64
  });
42
65
  const duration = Date.now() - promptStartTime;
43
66
  let userInput = response.query;
44
- // Handle multiline copy & paste: prompt resolves extremely fast if stdin is buffered
45
- if (duration < 50) {
67
+ // ── Multi-line paste mode: user typed <<< (or <<<paste) ─────────────
68
+ // Allows pasting arbitrarily long content (e.g. full JD) without truncation.
69
+ if (userInput.trim() === "<<<" || userInput.trim().toLowerCase().startsWith("<<<")) {
70
+ const prefix = userInput.trim().slice(3).trim(); // text after <<<
71
+ console.log(chalk.dim(" 📋 Multi-line mode: paste your text, then press Enter twice to submit.\n"));
72
+ const lines = prefix ? [prefix] : [];
73
+ let emptyCount = 0;
74
+ while (emptyCount < 1) {
75
+ const lineResp = await prompt({
76
+ type: "input",
77
+ name: "line",
78
+ message: chalk.dim(" │"),
79
+ });
80
+ if (lineResp.line === "") {
81
+ emptyCount++;
82
+ }
83
+ else {
84
+ emptyCount = 0;
85
+ lines.push(lineResp.line);
86
+ }
87
+ }
88
+ userInput = lines.join("\n").trim();
89
+ pasteBuffer = [];
90
+ }
91
+ else if (duration < 150) {
92
+ // Handle multiline copy & paste: prompt resolves extremely fast if stdin is buffered.
93
+ // 150ms threshold gives enough headroom for large pastes (long JDs, cover letters).
46
94
  pasteBuffer.push(userInput);
47
95
  return ask();
48
96
  }
@@ -67,7 +115,10 @@ export async function askLoop(engine, options, selectedProvider, selectedModel,
67
115
  console.log(chalk.dim(" /model <name> — Switch to a different model mid-session"));
68
116
  console.log(chalk.dim(" /models — List all available CareerVivid models"));
69
117
  console.log(chalk.dim(" /help — Show this help message"));
70
- console.log(chalk.dim(" exit — End the session\n"));
118
+ console.log(chalk.dim(" exit — End the session"));
119
+ console.log(chalk.cyan("\n Paste long content (job descriptions, cover letters):"));
120
+ console.log(chalk.dim(" <<< — Open multi-line paste mode; press Enter twice when done"));
121
+ console.log(chalk.dim(" <<<your text — Start with text directly after <<<\n"));
71
122
  return ask();
72
123
  }
73
124
  if (cmd === "models") {
@@ -283,13 +334,7 @@ export async function askLoop(engine, options, selectedProvider, selectedModel,
283
334
  let userTurn = { role: "user", parts: [{ text: userInput }] };
284
335
  let round = 0;
285
336
  while (round < 10) {
286
- const result = await provider.generate({
287
- model: currentModel,
288
- history: byoHistory,
289
- userTurn,
290
- tools,
291
- systemInstruction,
292
- });
337
+ const result = await withTimeout(provider.generate({ model: currentModel, history: byoHistory, userTurn, tools, systemInstruction }), 45_000, "LLM generate()");
293
338
  if (round === 0) {
294
339
  process.stdout.write("\r\x1b[K"); // clear initial thinking spinner
295
340
  }
@@ -311,10 +356,17 @@ export async function askLoop(engine, options, selectedProvider, selectedModel,
311
356
  const tool = tools.find((t) => t.name === fc.name);
312
357
  let out;
313
358
  try {
314
- out = tool ? await tool.execute(fc.args) : { error: "Tool not found" };
359
+ out = tool
360
+ ? await withTimeout(tool.execute(fc.args), 45_000, `tool:${fc.name}`)
361
+ : { error: "Tool not found" };
315
362
  }
316
363
  catch (e) {
317
- out = { error: e.message };
364
+ if (e.message?.includes("No API key configured")) {
365
+ out = { error: "CareerVivid API key not found. Run 'cv login' to authenticate." };
366
+ }
367
+ else {
368
+ out = { error: e.message };
369
+ }
318
370
  }
319
371
  handleToolResult(fc.name, out);
320
372
  fnResponses.push({ functionResponse: { id: fc.id, name: fc.name, response: out } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "careervivid",
3
- "version": "1.12.14",
3
+ "version": "1.12.16",
4
4
  "description": "Official CLI for CareerVivid — publish articles, diagrams, and portfolio updates from your terminal or AI agent",
5
5
  "type": "module",
6
6
  "bin": {