lazyclaw 3.99.4 → 3.99.5

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/cli.mjs CHANGED
@@ -1457,10 +1457,10 @@ async function _pickProviderInteractive() {
1457
1457
  });
1458
1458
  return { provider: ans || providers[0], model: null };
1459
1459
  }
1460
- // Default cursor: prefer claude-cli (subscription, no key) so first-
1461
- // time users with Claude Code already installed don't have to scroll.
1462
- let idx = items.findIndex(it => it.provider === 'claude-cli');
1463
- if (idx < 0) idx = 0;
1460
+ // Default cursor: lands on item 0 (= the first row from PROVIDERS
1461
+ // insertion order, which registry.mjs deliberately curates as the
1462
+ // most user-familiar vendor gemini at the time of writing).
1463
+ let idx = 0;
1464
1464
 
1465
1465
  const readline = await import('node:readline');
1466
1466
  readline.emitKeypressEvents(process.stdin);
@@ -3082,10 +3082,69 @@ function parseArgs(argv) {
3082
3082
  // so chat / agent / etc. behave bit-identically to typing them
3083
3083
  // directly. Non-TTY (piped, scripted) callers still see the
3084
3084
  // classic "Usage: …" line so automation isn't surprised.
3085
+ // First-run welcome panel + delegated onboard. Drawn once before the
3086
+ // main launcher menu when the config has no provider yet. Walks the
3087
+ // user through the same arrow-key picker that `lazyclaw onboard`
3088
+ // uses; on success the launcher continues, on cancel the launcher
3089
+ // exits politely instead of dropping into a menu where every option
3090
+ // would error.
3091
+ async function _runFirstTimeOnboard() {
3092
+ const accent = (s) => `\x1b[38;5;208m${s}\x1b[0m`;
3093
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
3094
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`;
3095
+ process.stdout.write('\x1b[2J\x1b[H');
3096
+ const banner = [
3097
+ accent(' ╭──────────────────────────────╮'),
3098
+ accent(' │ _ │'),
3099
+ accent(' │ | |__ _ _____ _ _ │'),
3100
+ accent(' │ | / _` |_ / || | \'_| │'),
3101
+ accent(' │ |_\\__,_/__\\_, |_| │'),
3102
+ accent(' │ LazyClaw |__/ ' + (readVersionFromRepo() || '').padEnd(10) + ' │'),
3103
+ accent(' ╰──────────────────────────────╯'),
3104
+ ];
3105
+ banner.forEach((l) => process.stdout.write(l + '\n'));
3106
+ process.stdout.write('\n');
3107
+ process.stdout.write(` ${bold('👋 Welcome — first-time setup')}\n\n`);
3108
+ process.stdout.write(` ${dim('No provider configured yet at')} ${configPath()}\n`);
3109
+ process.stdout.write(` ${dim('Pick a provider + model below; LazyClaw stores it in ~/.lazyclaw/config.json.')}\n\n`);
3110
+ process.stdout.write(` ${dim('Quick rule of thumb:')}\n`);
3111
+ process.stdout.write(` ${dim(' · gemini / openai / anthropic — need an API key (sk-... / paste during setup)')}\n`);
3112
+ process.stdout.write(` ${dim(' · claude-cli / ollama — keyless (use your existing Claude Code login or local Ollama)')}\n`);
3113
+ process.stdout.write(` ${dim(' · mock — offline echo, only useful for testing')}\n\n`);
3114
+ process.stdout.write(` ${dim('Press Enter to open the picker · Ctrl+C to abort.')}\n`);
3115
+ await _quickPrompt(' ▶ ');
3116
+ // Delegate to the real onboard flow with --pick so the picker UI
3117
+ // fires regardless of how this entry point was reached. cmdOnboard
3118
+ // owns config writing.
3119
+ try {
3120
+ await cmdOnboard({ pick: true });
3121
+ } catch (e) {
3122
+ process.stderr.write(`onboard error: ${e?.message || e}\n`);
3123
+ }
3124
+ process.stdout.write('\n');
3125
+ }
3126
+
3085
3127
  async function cmdLauncher() {
3086
3128
  await ensureRegistry();
3087
- const cfg = readConfig();
3088
- const provider = cfg.provider || '(unset pick during onboard)';
3129
+ let cfg = readConfig();
3130
+ // First-run guard: a fresh install has no `provider` set, so any
3131
+ // menu pick that calls a provider (Chat / Agent / Doctor / etc.)
3132
+ // would error halfway through with a confusing "missing api key"
3133
+ // or "unknown provider". Detect that state up front and walk the
3134
+ // user through onboard before showing the menu — once they've
3135
+ // picked, re-read the config and continue normally.
3136
+ if (!cfg.provider) {
3137
+ await _runFirstTimeOnboard();
3138
+ cfg = readConfig();
3139
+ // If they cancelled / aborted onboard we still don't have a
3140
+ // provider — drop straight out instead of showing a menu where
3141
+ // every item leads to the same error.
3142
+ if (!cfg.provider) {
3143
+ process.stdout.write('\n Setup not completed — exiting.\n Run `lazyclaw onboard` when ready, then try `lazyclaw` again.\n\n');
3144
+ process.exit(0);
3145
+ }
3146
+ }
3147
+ const provider = cfg.provider;
3089
3148
  const model = cfg.model || '(default)';
3090
3149
  const items = [
3091
3150
  { id: 'chat', label: 'Chat', desc: 'interactive REPL with the configured provider', argv: ['chat'] },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazyclaw",
3
- "version": "3.99.4",
3
+ "version": "3.99.5",
4
4
  "description": "Lazy, elegant terminal CLI for chatting with Claude / OpenAI / Gemini / Ollama and orchestrating multi-step LLM workflows. Banner-on-launch, slash-command ghost autocomplete, persistent sessions, local HTTP gateway.",
5
5
  "keywords": [
6
6
  "claude",
@@ -50,15 +50,20 @@ export const mockProvider = {
50
50
 
51
51
  export { anthropicProvider, openaiProvider, ollamaProvider, geminiProvider, claudeCliProvider };
52
52
 
53
+ // Insertion order is the picker order. The list goes first-to-last in
54
+ // rough "user-familiar / popular" order so a first-time onboard lands
55
+ // the cursor on a vendor most users recognise. v3.99.5 reordered per
56
+ // user feedback ("gemini, codex 이런거 먼저 나오게끔").
53
57
  export const PROVIDERS = {
54
- mock: mockProvider,
55
- // claude-cli (subscription-backed, no API key) listed before
56
- // anthropic so first-time onboarding surfaces it as the default.
58
+ // Tier 1 — popular / brand-name vendors users come in looking for.
59
+ gemini: geminiProvider,
60
+ openai: openaiProvider, // surfaces gpt-5-codex / gpt-5 / o3-pro etc.
61
+ // Tier 2 — Claude. CLI variant first because it's keyless.
57
62
  'claude-cli': claudeCliProvider,
58
63
  anthropic: anthropicProvider,
59
- openai: openaiProvider,
60
- gemini: geminiProvider,
64
+ // Tier 3 — local + dev/test.
61
65
  ollama: ollamaProvider,
66
+ mock: mockProvider,
62
67
  };
63
68
 
64
69
  // Static metadata for `lazyclaw providers list/info`. Kept next to PROVIDERS