junecoder 1.0.9 → 1.0.11

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tui.mjs +25 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "junecoder",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Zero Npm Dependencies Agent Framework",
5
5
  "main": "agent.mjs",
6
6
  "type": "module",
package/tui.mjs CHANGED
@@ -229,6 +229,7 @@ export async function startTUI(agent, opts = {}) {
229
229
  if (state.question) { borderColor = C.tool; title = " " + sliceByWidth(state.question.text, W - 6) + " "; }
230
230
  else if (state.permission) { borderColor = C.warn; title = state.permission.name === "continue" ? " Continue? (y/n) " : " Allow " + state.permission.name + "? (y/n/a) "; }
231
231
  else if (state.processing) title = " Processing... ";
232
+ else if (setupMode) title = " API Key ";
232
233
  else title = " Input ";
233
234
  const topBorder = "\u256d\u2500" + title + "\u2500".repeat(Math.max(0, W - 3 - stringWidth(title))) + "\u256e";
234
235
  out.push(`${borderColor}${topBorder}${ansi.reset}${ansi.clearLine}`);
@@ -331,12 +332,14 @@ export async function startTUI(agent, opts = {}) {
331
332
  // ─── First-run setup: capture API key from input box ──────────────────────────
332
333
  let setupMode = opts.needsSetup;
333
334
  if (setupMode) {
335
+ pushLine("", C.dim);
336
+ pushLine("", C.dim);
334
337
  pushLine("", C.dim);
335
338
  pushLine("Welcome to JuneCoder!", ansi.bold + C.assistant);
336
339
  pushLine("Before you start, you need a DeepSeek API key.", C.text);
337
340
  pushLine("Get one at: https://platform.deepseek.com/api_keys", C.dim);
338
341
  pushLine("", C.dim);
339
- state.status = "Paste your DeepSeek API key and press Enter (https://platform.deepseek.com/api_keys)";
342
+ state.status = "Paste your DeepSeek API key and press Enter";
340
343
  }
341
344
 
342
345
  async function submit() {
@@ -345,11 +348,26 @@ export async function startTUI(agent, opts = {}) {
345
348
 
346
349
  // ─── Setup mode: first input is the API key ──────────────────────────────
347
350
  if (setupMode) {
348
- setupMode = false;
349
351
  state.input = []; state.cursor = 0;
350
352
  const trimmed = text.trim();
351
353
 
354
+ // Allow slash commands to pass through during setup (e.g. /key cancel)
355
+ if (trimmed.startsWith("/")) {
356
+ setupMode = false;
357
+ await handleSlash(trimmed);
358
+ return;
359
+ }
360
+
361
+ // Empty input: exit on first-run, cancel on re-key
352
362
  if (!trimmed) {
363
+ if (agent.provider.apiKey) {
364
+ // Already have a key — user is just changing their mind
365
+ setupMode = false;
366
+ pushLine("Key unchanged.", C.dim);
367
+ state.status = "Ready";
368
+ render();
369
+ return;
370
+ }
353
371
  pushLine("No API key provided. Exiting.", C.error);
354
372
  render();
355
373
  await new Promise(r => setTimeout(r, 1500));
@@ -360,8 +378,8 @@ export async function startTUI(agent, opts = {}) {
360
378
  if (!trimmed.startsWith("sk-")) {
361
379
  pushLine("Invalid key — DeepSeek API keys must start with 'sk-'. Try again:", C.error);
362
380
  pushLine("", C.dim);
363
- setupMode = true; // stay in setup mode
364
- state.status = "Paste your DeepSeek API key and press Enter (https://platform.deepseek.com/api_keys)";
381
+ setupMode = true;
382
+ state.status = "Paste your DeepSeek API key and press Enter";
365
383
  render();
366
384
  return;
367
385
  }
@@ -374,6 +392,7 @@ export async function startTUI(agent, opts = {}) {
374
392
 
375
393
  pushLine("API key saved to ~/.junecoder/.env", C.tool);
376
394
  pushLine("", C.dim);
395
+ setupMode = false;
377
396
  state.status = "Ready";
378
397
  render();
379
398
  return;
@@ -425,9 +444,9 @@ export async function startTUI(agent, opts = {}) {
425
444
  case "model": pushLine(" Model: " + agent.provider.model + " | Provider: " + (agent.provider.type || "?"), C.dim); break;
426
445
  case "key": {
427
446
  pushLine(" Current key: " + (agent.provider.apiKey ? agent.provider.apiKey.slice(0, 8) + "..." : "(none)"), C.dim);
428
- pushLine(" To change, paste your new API key and press Enter.", C.tool);
447
+ pushLine(" Paste a new key, /cmd to cancel, or Enter to keep current.", C.tool);
429
448
  setupMode = true;
430
- state.status = "Paste your DeepSeek API key and press Enter (https://platform.deepseek.com/api_keys)";
449
+ state.status = "Paste your DeepSeek API key and press Enter";
431
450
  break;
432
451
  }
433
452
  case "session": { const slots = listSlots(agent.cwd); pushLine("Sessions:", C.tool); if (slots.length === 0) pushLine(" (none)", C.dim); else for (const s of slots) pushLine(" " + s.label, C.dim); break; }