profclaw 0.0.1-beta.1 → 0.0.1-beta.2

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 (151) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/openclaw.js +1 -1
  3. package/dist/agents/executor.js +38 -6
  4. package/dist/auth/auth-service.js +8 -6
  5. package/dist/auth/device-identity.js +7 -5
  6. package/dist/auth/github-oauth.js +3 -1
  7. package/dist/auth/pairing-codes.js +6 -4
  8. package/dist/browser/service.js +5 -3
  9. package/dist/chat/execution/guardrails.js +3 -1
  10. package/dist/chat/execution/workflows/executor.js +4 -2
  11. package/dist/chat/memory.js +3 -1
  12. package/dist/chat/proactive/index.js +13 -11
  13. package/dist/chat/tools.js +8 -7
  14. package/dist/cli/commands/auth.js +22 -13
  15. package/dist/cli/commands/onboard.js +248 -59
  16. package/dist/cli/commands/setup.js +180 -104
  17. package/dist/cron/issue-poller.js +1 -1
  18. package/dist/hooks/agent-webhook.js +10 -7
  19. package/dist/hooks/prompt-submit.js +5 -6
  20. package/dist/hooks/session-end.js +10 -6
  21. package/dist/hooks/tool-use.js +9 -6
  22. package/dist/integrations/github-ticket-sync.js +8 -6
  23. package/dist/integrations/github.js +8 -6
  24. package/dist/integrations/jira.js +5 -3
  25. package/dist/mcp/server.js +12 -9
  26. package/dist/memory/experience-store.js +15 -14
  27. package/dist/notifications/slack.js +4 -2
  28. package/dist/providers/types.d.ts +2 -2
  29. package/dist/queue/failure-handler.js +15 -13
  30. package/dist/queue/index.js +6 -4
  31. package/dist/queue/memory-queue.js +23 -27
  32. package/dist/queue/task-queue.js +18 -22
  33. package/dist/routes/agents.js +3 -1
  34. package/dist/routes/auth.js +11 -9
  35. package/dist/routes/devices.js +17 -15
  36. package/dist/routes/gateway.js +3 -1
  37. package/dist/routes/hooks.js +7 -5
  38. package/dist/routes/import.js +10 -8
  39. package/dist/routes/labels.js +11 -9
  40. package/dist/routes/oobe.js +8 -6
  41. package/dist/routes/openapi.js +1 -1
  42. package/dist/routes/projects.js +27 -25
  43. package/dist/routes/settings.js +7 -5
  44. package/dist/routes/setup.js +12 -11
  45. package/dist/routes/slack.js +28 -27
  46. package/dist/routes/stats.js +6 -4
  47. package/dist/routes/summaries.js +4 -3
  48. package/dist/routes/sync.js +7 -5
  49. package/dist/routes/tasks.js +10 -8
  50. package/dist/routes/tickets.js +26 -26
  51. package/dist/routes/tokens.js +5 -3
  52. package/dist/routes/users.js +14 -12
  53. package/dist/routes/webhooks.js +5 -3
  54. package/dist/settings/index.js +3 -1
  55. package/dist/storage/index.d.ts +2 -1
  56. package/dist/storage/index.js +9 -4
  57. package/dist/storage/libsql.js +29 -21
  58. package/dist/storage/schema.d.ts +107 -46
  59. package/dist/summaries/storage.js +3 -1
  60. package/dist/tickets/index.js +10 -8
  61. package/dist/utils/circuit-breaker.js +10 -5
  62. package/dist/utils/logger.d.ts +5 -1
  63. package/dist/utils/logger.js +23 -7
  64. package/package.json +4 -3
  65. package/ui/dist/assets/{ActivityView-CkPgKhwm.js → ActivityView-DIPQSJ_d.js} +1 -1
  66. package/ui/dist/assets/{AgentList-C3SVdeEz.js → AgentList-CqyaYrcq.js} +1 -1
  67. package/ui/dist/assets/{AnalyticsDashboard-DVU--vlP.js → AnalyticsDashboard-C-mjuGHT.js} +1 -1
  68. package/ui/dist/assets/{AreaChart-B5qMEGWj.js → AreaChart-CfYWmbtr.js} +1 -1
  69. package/ui/dist/assets/{CartesianChart-B50bcUJi.js → CartesianChart-BaQ3It0c.js} +1 -1
  70. package/ui/dist/assets/{ChatView-BZFJs7w_.js → ChatView-DxxQy6pl.js} +1 -1
  71. package/ui/dist/assets/CostsDashboard-CDBBcGkg.js +1 -0
  72. package/ui/dist/assets/{EstimateSelect-CLpB4NQO.js → EstimateSelect-CDjf5qKl.js} +1 -1
  73. package/ui/dist/assets/{FloatingChatbot-CBzBY9a0.js → FloatingChatbot-CZHjvJIe.js} +1 -1
  74. package/ui/dist/assets/{InviteCodeManagement-DsbdPa6W.js → InviteCodeManagement-DTm-IPTm.js} +1 -1
  75. package/ui/dist/assets/{ProjectDetail-BEM3tFXg.js → ProjectDetail-DlYUcOss.js} +1 -1
  76. package/ui/dist/assets/{ProjectIcon-CN1FmFAk.js → ProjectIcon-BMRpnM04.js} +1 -1
  77. package/ui/dist/assets/{ProjectList-DSDaNhxQ.js → ProjectList-D85TN0i0.js} +1 -1
  78. package/ui/dist/assets/{Settings-dPVcqC_d.js → Settings-CgPqzUvj.js} +3 -3
  79. package/ui/dist/assets/{StatusIndicator-DA3NAo_b.js → StatusIndicator-yig0uZEA.js} +1 -1
  80. package/ui/dist/assets/{SummaryDetail-Bjnf9lT8.js → SummaryDetail-CwLAfHgJ.js} +1 -1
  81. package/ui/dist/assets/{SummaryList-ENwKDBKW.js → SummaryList-BvS5Idnu.js} +1 -1
  82. package/ui/dist/assets/{TaskDetail-DnwG6MzB.js → TaskDetail-zarC1fOt.js} +1 -1
  83. package/ui/dist/assets/{TaskList-D9Ug_HiV.js → TaskList-CyJq3ANE.js} +1 -1
  84. package/ui/dist/assets/{TicketBoard-CviH1571.js → TicketBoard-BlWr3-iH.js} +1 -1
  85. package/ui/dist/assets/{TicketDetail-8Jk8O-33.js → TicketDetail-DmqWKj2W.js} +1 -1
  86. package/ui/dist/assets/{TicketList-B-iV4rRA.js → TicketList-Scj4pMWa.js} +1 -1
  87. package/ui/dist/assets/{UserManagement-CPZ8s7s2.js → UserManagement-BH7uG7dw.js} +1 -1
  88. package/ui/dist/assets/{ViewSwitcher-BUyOOWDI.js → ViewSwitcher-3HzZUdWn.js} +1 -1
  89. package/ui/dist/assets/{alert-dialog-BOmnTkN-.js → alert-dialog-DWPb2IfQ.js} +1 -1
  90. package/ui/dist/assets/{archive-D5my9zOG.js → archive-CGck7gxR.js} +1 -1
  91. package/ui/dist/assets/{badge-B4ov81_m.js → badge-DEmc3Z_l.js} +1 -1
  92. package/ui/dist/assets/{brain-C53ElFLD.js → brain-CfFdLVqb.js} +1 -1
  93. package/ui/dist/assets/{bug-D0TJoCYn.js → bug-DqSGPUUE.js} +1 -1
  94. package/ui/dist/assets/{calendar-BkWIhKa1.js → calendar-BuZ4zbPW.js} +1 -1
  95. package/ui/dist/assets/{chevron-up-BRTtndUZ.js → chevron-up-DcJ4LL_N.js} +1 -1
  96. package/ui/dist/assets/{circle-x-BN89YhbS.js → circle-x-C78PNZjF.js} +1 -1
  97. package/ui/dist/assets/{constants-fc7TFI7u.js → constants-DhDjZe4P.js} +1 -1
  98. package/ui/dist/assets/{cpu-B41x1-vV.js → cpu-Ck6AoG8c.js} +1 -1
  99. package/ui/dist/assets/{database-D9Cnfmzj.js → database-CA2w8Lvt.js} +1 -1
  100. package/ui/dist/assets/{dialog-DrWB4EYD.js → dialog-BOdGWhgE.js} +1 -1
  101. package/ui/dist/assets/{ellipsis-NuUWekvu.js → ellipsis-FhHKRbfl.js} +1 -1
  102. package/ui/dist/assets/{ellipsis-vertical-BueMfuCw.js → ellipsis-vertical-CO0UqE4-.js} +1 -1
  103. package/ui/dist/assets/{file-code-HR9829Jc.js → file-code-ChnhYYj1.js} +1 -1
  104. package/ui/dist/assets/{folder-open-C_7oYEqe.js → folder-open-CHwA1-ve.js} +1 -1
  105. package/ui/dist/assets/{funnel-B5gmNXGf.js → funnel-ByEjRFNB.js} +1 -1
  106. package/ui/dist/assets/{git-branch-BRMiJmV3.js → git-branch-GTOPQgU4.js} +1 -1
  107. package/ui/dist/assets/{git-commit-horizontal-CXOUQeJI.js → git-commit-horizontal-F5M84Kut.js} +1 -1
  108. package/ui/dist/assets/{globe-CCspjvus.js → globe-CQWfr7hT.js} +1 -1
  109. package/ui/dist/assets/{hash-g3102kPC.js → hash-nKC9gtLg.js} +1 -1
  110. package/ui/dist/assets/{history-CNqcBBrV.js → history-DfFSA9xJ.js} +1 -1
  111. package/ui/dist/assets/{index-kb4AJXUB.js → index--JkIxVXb.js} +3 -3
  112. package/ui/dist/assets/index-Ca3vk7Gq.js +1 -0
  113. package/ui/dist/assets/{index-C9jNQXzL.js → index-DHGvP9mp.js} +1 -1
  114. package/ui/dist/assets/index-DeI8lKRR.js +1 -0
  115. package/ui/dist/assets/{index-DURTouJI.js → index-Z4-RtZcs.js} +1 -1
  116. package/ui/dist/assets/{index-CEZ6R2Uw.js → index-a4Fxq0Hb.js} +1 -1
  117. package/ui/dist/assets/{layers-CLXiHN6o.js → layers-DFeLExSa.js} +1 -1
  118. package/ui/dist/assets/{layout-dashboard-B07MFhBs.js → layout-dashboard-WmgjMhWF.js} +1 -1
  119. package/ui/dist/assets/{lightbulb-B2dgG5ks.js → lightbulb-Bo8hEr7B.js} +1 -1
  120. package/ui/dist/assets/{link-2-BxNmr9hL.js → link-2-YqrpQXBH.js} +1 -1
  121. package/ui/dist/assets/{markdown-renderer-CjU6hBcW.js → markdown-renderer-Croje6Xe.js} +1 -1
  122. package/ui/dist/assets/{message-square-Bf2-CVbt.js → message-square-CD0H5hot.js} +1 -1
  123. package/ui/dist/assets/{pencil-D096Ey62.js → pencil-DpFnj5dn.js} +1 -1
  124. package/ui/dist/assets/{play-DfdcSI3x.js → play-DVgea_jT.js} +1 -1
  125. package/ui/dist/assets/{popover-BV0QJDQq.js → popover-JXecfWG5.js} +1 -1
  126. package/ui/dist/assets/{progress-DjPEDJfI.js → progress-C1ghf1Fu.js} +1 -1
  127. package/ui/dist/assets/{rocket-CPsTc-5G.js → rocket-BFxPYGx9.js} +1 -1
  128. package/ui/dist/assets/{select-LsO16slr.js → select-MADP8m6Q.js} +1 -1
  129. package/ui/dist/assets/{send-BDYBZDUZ.js → send-eYnW_7n-.js} +1 -1
  130. package/ui/dist/assets/{server-B3k6noce.js → server-CPMaysH8.js} +1 -1
  131. package/ui/dist/assets/{settings-2-Cu4xTjhG.js → settings-2-scXUOuE_.js} +1 -1
  132. package/ui/dist/assets/{sheet-BScLnPKX.js → sheet-r6NSOxi-.js} +1 -1
  133. package/ui/dist/assets/{shield-check-CQqkwufI.js → shield-check-PEr7nmVw.js} +1 -1
  134. package/ui/dist/assets/{shield-off-ZFruH9KO.js → shield-off-CLtXio62.js} +1 -1
  135. package/ui/dist/assets/{skeleton-CtkIA_MU.js → skeleton-C9oEzNlU.js} +1 -1
  136. package/ui/dist/assets/{smartphone-DnoksVkc.js → smartphone-DusFfY0U.js} +1 -1
  137. package/ui/dist/assets/{square-uD9ZHMfW.js → square-e1yxB2eR.js} +1 -1
  138. package/ui/dist/assets/{switch-MQPnwGJK.js → switch-tNs0n-kz.js} +1 -1
  139. package/ui/dist/assets/{table-B8cqlywA.js → table-CXxtLicg.js} +1 -1
  140. package/ui/dist/assets/{tag-wEJQRWlV.js → tag-tAwMmQ9G.js} +1 -1
  141. package/ui/dist/assets/{textarea-D5LJCOGl.js → textarea-BjiEeIWh.js} +1 -1
  142. package/ui/dist/assets/{timer-mbGHegmr.js → timer-Vel1N3RP.js} +1 -1
  143. package/ui/dist/assets/{tooltip-Df1CunSp.js → tooltip-ZMwtfr1J.js} +1 -1
  144. package/ui/dist/assets/{trash-2-B4oAXsX-.js → trash-2-eM-CNwsZ.js} +1 -1
  145. package/ui/dist/assets/{trending-up-BGWxvlmZ.js → trending-up-BGafmjRo.js} +1 -1
  146. package/ui/dist/assets/{wand-sparkles-CZy4xvL3.js → wand-sparkles-DPvcd9Pi.js} +1 -1
  147. package/ui/dist/assets/{wrench-ByZkjO6m.js → wrench-B8s3zYVV.js} +1 -1
  148. package/ui/dist/index.html +1 -1
  149. package/ui/dist/assets/CostsDashboard-ChfH8BlG.js +0 -1
  150. package/ui/dist/assets/index-27mTPKuh.js +0 -1
  151. package/ui/dist/assets/index-BMx3fH-e.js +0 -1
@@ -11,7 +11,7 @@
11
11
  import { Command } from 'commander';
12
12
  import chalk from 'chalk';
13
13
  import figlet from 'figlet';
14
- import { createInterface } from 'readline/promises';
14
+ import { select, search, input, Separator } from '@inquirer/prompts';
15
15
  import { existsSync, writeFileSync, readFileSync } from 'node:fs';
16
16
  import { join } from 'node:path';
17
17
  import { execSync } from 'node:child_process';
@@ -125,6 +125,14 @@ function generateEnvFile(opts) {
125
125
  lines.push(`OLLAMA_BASE_URL=${opts.ollamaUrl}`);
126
126
  lines.push('');
127
127
  }
128
+ // Write any extra env vars from selected providers
129
+ if (opts.extraEnvVars) {
130
+ for (const [key, value] of Object.entries(opts.extraEnvVars)) {
131
+ lines.push(`${key}=${value}`);
132
+ }
133
+ if (Object.keys(opts.extraEnvVars).length > 0)
134
+ lines.push('');
135
+ }
128
136
  if (opts.mode === 'pro') {
129
137
  lines.push('# Redis (required for pro mode)');
130
138
  lines.push('REDIS_URL=redis://localhost:6379');
@@ -133,24 +141,6 @@ function generateEnvFile(opts) {
133
141
  return lines.join('\n');
134
142
  }
135
143
  // Interactive Onboarding
136
- async function prompt(rl, question) {
137
- const answer = await rl.question(chalk.bold(question));
138
- return answer.trim();
139
- }
140
- async function promptChoice(rl, question, options) {
141
- console.log('');
142
- console.log(chalk.bold(question));
143
- for (const opt of options) {
144
- console.log(` ${chalk.cyan(opt.key)}) ${opt.label}`);
145
- }
146
- const validKeys = options.map(o => o.key);
147
- while (true) {
148
- const answer = await prompt(rl, `Choice [${validKeys.join('/')}]: `);
149
- if (validKeys.includes(answer))
150
- return answer;
151
- console.log(chalk.red(` Invalid choice. Options: ${validKeys.join(', ')}`));
152
- }
153
- }
154
144
  async function runInteractive() {
155
145
  const banner = figlet.textSync('profClaw', { font: 'Standard' });
156
146
  console.log(chalk.cyan(banner));
@@ -161,58 +151,258 @@ async function runInteractive() {
161
151
  spin.start();
162
152
  const env = await detectEnvironment();
163
153
  spin.stop();
164
- const mark = (ok) => (ok ? chalk.green(' +') : chalk.dim(' -'));
165
- console.log(`${mark(true)} OS: ${env.os} (${env.arch})`);
166
- console.log(`${mark(true)} Node: ${env.nodeVersion}`);
167
- console.log(`${mark(true)} RAM: ${env.totalMemoryMb} MB`);
168
- console.log(`${mark(env.isDocker)} Docker: ${env.isDocker ? 'yes' : 'no'}`);
169
- console.log(`${mark(env.hasRedis)} Redis: ${env.hasRedis ? 'connected' : 'not found'}`);
170
- console.log(`${mark(env.hasOllama)} Ollama: ${env.hasOllama ? 'running' : 'not found'}`);
171
- console.log(`${mark(env.hasClaude)} Claude CLI: ${env.hasClaude ? 'found' : 'not found'}`);
172
- console.log(`${mark(env.hasGit)} Git: ${env.hasGit ? 'found' : 'not found'}`);
154
+ // Helpers for display
155
+ const ok = (label, value) => console.log(` ${chalk.green('+')} ${chalk.white(label.padEnd(14))} ${value}`);
156
+ const no = (label, value, hint) => {
157
+ console.log(` ${chalk.yellow('~')} ${chalk.dim(label.padEnd(14))} ${chalk.dim(value)}`);
158
+ if (hint)
159
+ console.log(` ${chalk.dim('\u2514')} ${chalk.yellow(hint)}`);
160
+ };
161
+ const ramGb = (env.totalMemoryMb / 1024).toFixed(0);
162
+ const ramBar = (() => {
163
+ const total = 16; // bar width
164
+ const filled = Math.min(total, Math.round((env.totalMemoryMb / 65536) * total));
165
+ return chalk.green('\u2588'.repeat(filled)) + chalk.dim('\u2591'.repeat(total - filled));
166
+ })();
167
+ const ramWarn = env.totalMemoryMb < 512
168
+ ? chalk.red(' (low - pico mode recommended)')
169
+ : env.totalMemoryMb < 2048
170
+ ? chalk.yellow(' (limited - mini mode recommended)')
171
+ : '';
172
+ // -- System --
173
+ console.log('');
174
+ console.log(` ${chalk.bold.cyan('System')}`);
175
+ ok('OS', `${env.os} (${env.arch})`);
176
+ ok('Node', env.nodeVersion);
177
+ ok('RAM', `${ramGb} GB ${ramBar}${ramWarn}`);
178
+ if (env.isDocker) {
179
+ ok('Docker', 'Running in container');
180
+ }
181
+ // -- Services --
182
+ console.log('');
183
+ console.log(` ${chalk.bold.cyan('Services')}`);
184
+ if (env.hasRedis) {
185
+ ok('Redis', chalk.green('connected'));
186
+ }
187
+ else {
188
+ no('Redis', 'not found (optional)', 'Install: brew install redis | docker run -d -p 6379:6379 redis:alpine');
189
+ }
190
+ if (env.hasOllama) {
191
+ ok('Ollama', chalk.green('running') + ' (free local AI)');
192
+ }
193
+ else {
194
+ no('Ollama', 'not running (optional)', 'Install: brew install ollama && ollama serve | https://ollama.com/download');
195
+ }
196
+ // -- Tools --
197
+ console.log('');
198
+ console.log(` ${chalk.bold.cyan('Tools')}`);
199
+ if (env.hasClaude) {
200
+ ok('Claude CLI', 'found');
201
+ }
202
+ else {
203
+ no('Claude CLI', 'not found (optional)', 'Install: npm install -g @anthropic-ai/claude-code');
204
+ }
205
+ if (env.hasGit) {
206
+ ok('Git', 'found');
207
+ }
208
+ else {
209
+ no('Git', 'not found', 'Install: brew install git | https://git-scm.com/downloads');
210
+ }
211
+ // -- Existing Data --
212
+ if (env.existingEnv || env.existingDb) {
213
+ console.log('');
214
+ console.log(` ${chalk.bold.cyan('Existing Data')}`);
215
+ if (env.existingEnv)
216
+ ok('.env', 'found');
217
+ if (env.existingDb)
218
+ ok('Database', 'found');
219
+ }
173
220
  const recommended = recommendMode(env);
174
- console.log(`\n ${chalk.cyan('Recommended mode:')} ${chalk.bold(recommended)}`);
175
- const rl = createInterface({ input: process.stdin, output: process.stdout });
176
- // Step 2: Choose mode
221
+ console.log('');
222
+ console.log(` ${chalk.cyan('Recommended mode:')} ${chalk.bold(recommended)}`);
223
+ // Step 2: Choose mode (arrow keys)
177
224
  console.log(chalk.bold.white('\n Step 2: Deployment Mode\n'));
178
- const modeChoice = await promptChoice(rl, ' Select deployment mode:', [
179
- { key: '1', label: `Pico -- Agent + tools only, ~50MB RAM${recommended === 'pico' ? chalk.green(' (recommended)') : ''}` },
180
- { key: '2', label: `Mini -- + Dashboard, cron, integrations, ~150MB RAM${recommended === 'mini' ? chalk.green(' (recommended)') : ''}` },
181
- { key: '3', label: `Pro -- Everything, Redis required, ~300MB RAM${recommended === 'pro' ? chalk.green(' (recommended)') : ''}` },
182
- ]);
183
- const mode = modeChoice === '1' ? 'pico' : modeChoice === '2' ? 'mini' : 'pro';
225
+ let mode;
226
+ try {
227
+ mode = await select({
228
+ message: 'Select deployment mode',
229
+ default: recommended,
230
+ choices: [
231
+ {
232
+ name: `Pico - Agent + tools only, ~50MB RAM${recommended === 'pico' ? chalk.green(' (recommended)') : ''}`,
233
+ value: 'pico',
234
+ description: 'Minimal footprint. CLI agent, tool execution, no web UI.',
235
+ },
236
+ {
237
+ name: `Mini - Dashboard, cron, integrations, ~150MB RAM${recommended === 'mini' ? chalk.green(' (recommended)') : ''}`,
238
+ value: 'mini',
239
+ description: 'Web dashboard, scheduled jobs, GitHub/Jira/Linear webhooks.',
240
+ },
241
+ {
242
+ name: `Pro - Everything, Redis required, ~300MB RAM${recommended === 'pro' ? chalk.green(' (recommended)') : ''}`,
243
+ value: 'pro',
244
+ description: 'BullMQ queues, plugins, sync engine, multi-agent orchestration.',
245
+ },
246
+ ],
247
+ theme: { prefix: ' ', style: { highlight: (text) => chalk.cyan.bold(text) } },
248
+ });
249
+ }
250
+ catch {
251
+ console.log(chalk.dim('\n Cancelled.'));
252
+ process.exit(0);
253
+ }
184
254
  success(`Mode: ${mode}`);
185
- // Step 3: AI Provider
255
+ // Step 3: AI Provider (searchable list)
186
256
  console.log(chalk.bold.white('\n Step 3: AI Provider\n'));
187
257
  let anthropicKey;
188
258
  let openaiKey;
189
259
  let ollamaUrl;
190
260
  const hasExistingProvider = !!process.env.ANTHROPIC_API_KEY || !!process.env.OPENAI_API_KEY;
191
261
  if (hasExistingProvider) {
192
- info('AI provider already configured from environment.');
262
+ const which = process.env.ANTHROPIC_API_KEY ? 'Anthropic' : 'OpenAI';
263
+ info(`AI provider already configured from environment (${which}).`);
193
264
  }
194
265
  else {
195
- const providerChoice = await promptChoice(rl, ' Select AI provider:', [
196
- { key: '1', label: 'Anthropic (Claude) -- recommended' },
197
- { key: '2', label: 'OpenAI (GPT-4o)' },
198
- { key: '3', label: `Ollama (free, local)${env.hasOllama ? chalk.green(' -- detected!') : ''}` },
199
- { key: '4', label: 'Skip for now' },
200
- ]);
201
- if (providerChoice === '1') {
202
- anthropicKey = await prompt(rl, ' Anthropic API Key: ');
203
- if (anthropicKey)
204
- success('Anthropic key saved.');
266
+ // Provider catalog
267
+ const providers = [
268
+ { key: 'anthropic', name: 'Anthropic', models: 'Claude 4.x, 3.5 Sonnet', envVar: 'ANTHROPIC_API_KEY', category: 'Popular', tag: 'recommended' },
269
+ { key: 'openai', name: 'OpenAI', models: 'GPT-4o, o1, o3', envVar: 'OPENAI_API_KEY', category: 'Popular', tag: '' },
270
+ { key: 'google', name: 'Google AI', models: 'Gemini 2.x, Flash', envVar: 'GOOGLE_GENERATIVE_AI_API_KEY', category: 'Popular', tag: '' },
271
+ { key: 'ollama', name: 'Ollama', models: 'Llama, Mistral, Qwen', envVar: 'OLLAMA_BASE_URL', category: 'Popular', tag: env.hasOllama ? 'detected' : 'free, local' },
272
+ { key: 'groq', name: 'Groq', models: 'Llama, Mixtral', envVar: 'GROQ_API_KEY', category: 'Fast Inference', tag: 'fast' },
273
+ { key: 'cerebras', name: 'Cerebras', models: 'Llama 3.3 70B', envVar: 'CEREBRAS_API_KEY', category: 'Fast Inference', tag: 'fast' },
274
+ { key: 'fireworks', name: 'Fireworks', models: 'Llama, Mixtral', envVar: 'FIREWORKS_API_KEY', category: 'Fast Inference', tag: '' },
275
+ { key: 'together', name: 'Together', models: 'Open models', envVar: 'TOGETHER_API_KEY', category: 'Fast Inference', tag: '' },
276
+ { key: 'azure', name: 'Azure OpenAI', models: 'GPT-4o', envVar: 'AZURE_OPENAI_API_KEY', category: 'Enterprise', tag: 'enterprise' },
277
+ { key: 'bedrock', name: 'AWS Bedrock', models: 'Claude, Titan, Llama', envVar: 'AWS_ACCESS_KEY_ID', category: 'Enterprise', tag: 'enterprise' },
278
+ { key: 'watsonx', name: 'IBM Watsonx', models: 'Granite, Llama', envVar: 'WATSONX_API_KEY', category: 'Enterprise', tag: 'enterprise' },
279
+ { key: 'deepseek', name: 'DeepSeek', models: 'V3, R1 (reasoning)', envVar: 'DEEPSEEK_API_KEY', category: 'More Providers', tag: '' },
280
+ { key: 'mistral', name: 'Mistral', models: 'Large, Codestral', envVar: 'MISTRAL_API_KEY', category: 'More Providers', tag: '' },
281
+ { key: 'xai', name: 'xAI', models: 'Grok', envVar: 'XAI_API_KEY', category: 'More Providers', tag: '' },
282
+ { key: 'perplexity', name: 'Perplexity', models: 'Sonar (search)', envVar: 'PERPLEXITY_API_KEY', category: 'More Providers', tag: 'search' },
283
+ { key: 'cohere', name: 'Cohere', models: 'Command R+', envVar: 'COHERE_API_KEY', category: 'More Providers', tag: '' },
284
+ { key: 'openrouter', name: 'OpenRouter', models: 'Any model (proxy)', envVar: 'OPENROUTER_API_KEY', category: 'Aggregators', tag: 'multi-model' },
285
+ { key: 'replicate', name: 'Replicate', models: 'Open-source models', envVar: 'REPLICATE_API_TOKEN', category: 'Aggregators', tag: '' },
286
+ { key: 'github-models', name: 'GitHub Models', models: 'Azure-backed', envVar: 'GITHUB_TOKEN', category: 'Aggregators', tag: '' },
287
+ { key: 'huggingface', name: 'HuggingFace', models: 'Inference API', envVar: 'HF_TOKEN', category: 'Aggregators', tag: '' },
288
+ { key: 'nvidia-nim', name: 'NVIDIA NIM', models: 'Llama, Nemotron', envVar: 'NVIDIA_NIM_API_KEY', category: 'Aggregators', tag: '' },
289
+ { key: 'zhipu', name: 'Zhipu AI', models: 'GLM-4, GLM-5', envVar: 'ZHIPU_API_KEY', category: 'Asia', tag: '' },
290
+ { key: 'moonshot', name: 'Moonshot', models: 'Kimi (128K context)', envVar: 'MOONSHOT_API_KEY', category: 'Asia', tag: '' },
291
+ { key: 'qwen', name: 'Qwen', models: 'Qwen Max, Plus', envVar: 'QWEN_API_KEY', category: 'Asia', tag: '' },
292
+ { key: 'minimax', name: 'MiniMax', models: 'abab series', envVar: 'MINIMAX_API_KEY', category: 'Asia', tag: '' },
293
+ { key: 'volcengine', name: 'Volcengine', models: 'Doubao (Bytedance)', envVar: 'VOLCENGINE_API_KEY', category: 'Asia', tag: '' },
294
+ { key: 'qianfan', name: 'Qianfan', models: 'ERNIE (Baidu)', envVar: 'QIANFAN_API_KEY', category: 'Asia', tag: '' },
295
+ ];
296
+ // Check which providers have keys in env
297
+ const detected = new Set();
298
+ for (const p of providers) {
299
+ if (process.env[p.envVar])
300
+ detected.add(p.key);
301
+ }
302
+ if (env.hasOllama)
303
+ detected.add('ollama');
304
+ // Build searchable choices grouped by category
305
+ let chosenProvider;
306
+ try {
307
+ chosenProvider = await search({
308
+ message: 'Select AI provider (type to filter, arrows to navigate)',
309
+ source: (term) => {
310
+ const results = [];
311
+ const filter = (term || '').toLowerCase();
312
+ let lastCategory = '';
313
+ for (const p of providers) {
314
+ // Filter by name, key, models, category, or tag
315
+ if (filter && ![p.name, p.key, p.models, p.category, p.tag]
316
+ .some(s => s.toLowerCase().includes(filter))) {
317
+ continue;
318
+ }
319
+ // Add category separator
320
+ if (p.category !== lastCategory) {
321
+ if (results.length > 0)
322
+ results.push(new Separator());
323
+ results.push(new Separator(chalk.bold.cyan(` ${p.category} `)));
324
+ lastCategory = p.category;
325
+ }
326
+ const det = detected.has(p.key) ? chalk.green(' *') : '';
327
+ const tag = p.tag ? ` ${chalk.dim(`[${p.tag}]`)}` : '';
328
+ results.push({
329
+ name: `${p.name.padEnd(16)} ${chalk.dim(p.models)}${tag}${det}`,
330
+ value: p.key,
331
+ description: `${p.envVar}`,
332
+ short: p.name,
333
+ });
334
+ }
335
+ // Always add skip option at the end
336
+ if (!filter || 'skip'.includes(filter)) {
337
+ results.push(new Separator());
338
+ results.push({
339
+ name: chalk.dim('Skip for now'),
340
+ value: 'skip',
341
+ description: 'Configure later with: profclaw provider',
342
+ short: 'Skip',
343
+ });
344
+ }
345
+ return results;
346
+ },
347
+ theme: { prefix: ' ', style: { highlight: (text) => chalk.cyan.bold(text) } },
348
+ });
349
+ }
350
+ catch {
351
+ console.log(chalk.dim('\n Cancelled.'));
352
+ process.exit(0);
205
353
  }
206
- else if (providerChoice === '2') {
207
- openaiKey = await prompt(rl, ' OpenAI API Key: ');
208
- if (openaiKey)
209
- success('OpenAI key saved.');
354
+ if (chosenProvider !== 'skip') {
355
+ const chosen = providers.find(p => p.key === chosenProvider);
356
+ console.log(`\n ${chalk.bold(chosen.name)} selected`);
357
+ console.log(chalk.dim(` Env var: ${chosen.envVar}`));
358
+ if (chosen.key === 'ollama') {
359
+ if (env.hasOllama) {
360
+ ollamaUrl = process.env.OLLAMA_BASE_URL || 'http://localhost:11434';
361
+ }
362
+ else {
363
+ try {
364
+ ollamaUrl = await input({
365
+ message: 'Ollama URL',
366
+ default: 'http://localhost:11434',
367
+ theme: { prefix: ' ' },
368
+ });
369
+ }
370
+ catch {
371
+ ollamaUrl = 'http://localhost:11434';
372
+ }
373
+ }
374
+ success(`Ollama: ${ollamaUrl}`);
375
+ }
376
+ else if (detected.has(chosen.key)) {
377
+ success(`${chosen.name} already configured from ${chosen.envVar}`);
378
+ }
379
+ else {
380
+ try {
381
+ const keyInput = await input({
382
+ message: chosen.envVar,
383
+ theme: { prefix: ' ' },
384
+ });
385
+ if (keyInput) {
386
+ if (chosen.key === 'anthropic')
387
+ anthropicKey = keyInput;
388
+ else if (chosen.key === 'openai')
389
+ openaiKey = keyInput;
390
+ else {
391
+ process.env[chosen.envVar] = keyInput;
392
+ }
393
+ success(`${chosen.name} configured.`);
394
+ }
395
+ else {
396
+ warn('No key provided, skipping.');
397
+ }
398
+ }
399
+ catch {
400
+ warn('Input cancelled, skipping provider.');
401
+ }
402
+ }
210
403
  }
211
- else if (providerChoice === '3') {
212
- ollamaUrl = env.hasOllama
213
- ? (process.env.OLLAMA_BASE_URL || 'http://localhost:11434')
214
- : await prompt(rl, ' Ollama URL [http://localhost:11434]: ') || 'http://localhost:11434';
215
- success(`Ollama: ${ollamaUrl}`);
404
+ else {
405
+ info('AI provider skipped. Configure later: profclaw provider');
216
406
  }
217
407
  }
218
408
  // Step 4: Generate .env
@@ -247,7 +437,6 @@ async function runInteractive() {
247
437
  writeFileSync(envPath, content);
248
438
  success(`PROFCLAW_MODE=${mode} set in .env`);
249
439
  }
250
- rl.close();
251
440
  // Step 5: Run setup wizard
252
441
  console.log(chalk.bold.white('\n Step 5: Setup\n'));
253
442
  info('Launching setup wizard for admin account and provider configuration...\n');