xibecode 0.5.4 → 0.6.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.
Files changed (88) hide show
  1. package/README.md +32 -9
  2. package/dist/commands/chat.d.ts.map +1 -1
  3. package/dist/commands/chat.js +133 -34
  4. package/dist/commands/chat.js.map +1 -1
  5. package/dist/commands/config.d.ts.map +1 -1
  6. package/dist/commands/config.js +33 -42
  7. package/dist/commands/config.js.map +1 -1
  8. package/dist/commands/run.d.ts +1 -0
  9. package/dist/commands/run.d.ts.map +1 -1
  10. package/dist/commands/run.js +7 -1
  11. package/dist/commands/run.js.map +1 -1
  12. package/dist/core/agent.d.ts +9 -7
  13. package/dist/core/agent.d.ts.map +1 -1
  14. package/dist/core/agent.js +102 -28
  15. package/dist/core/agent.js.map +1 -1
  16. package/dist/core/background-agent.d.ts +23 -0
  17. package/dist/core/background-agent.d.ts.map +1 -0
  18. package/dist/core/background-agent.js +138 -0
  19. package/dist/core/background-agent.js.map +1 -0
  20. package/dist/core/code-graph.d.ts +18 -0
  21. package/dist/core/code-graph.d.ts.map +1 -0
  22. package/dist/core/code-graph.js +105 -0
  23. package/dist/core/code-graph.js.map +1 -0
  24. package/dist/core/conflict-solver.d.ts +26 -0
  25. package/dist/core/conflict-solver.d.ts.map +1 -0
  26. package/dist/core/conflict-solver.js +108 -0
  27. package/dist/core/conflict-solver.js.map +1 -0
  28. package/dist/core/docs-scraper.d.ts +2 -1
  29. package/dist/core/docs-scraper.d.ts.map +1 -1
  30. package/dist/core/docs-scraper.js +10 -1
  31. package/dist/core/docs-scraper.js.map +1 -1
  32. package/dist/core/modes.d.ts +1 -1
  33. package/dist/core/modes.d.ts.map +1 -1
  34. package/dist/core/modes.js +105 -5
  35. package/dist/core/modes.js.map +1 -1
  36. package/dist/core/pattern-miner.d.ts +43 -0
  37. package/dist/core/pattern-miner.d.ts.map +1 -0
  38. package/dist/core/pattern-miner.js +123 -0
  39. package/dist/core/pattern-miner.js.map +1 -0
  40. package/dist/core/planMode.d.ts +2 -1
  41. package/dist/core/planMode.d.ts.map +1 -1
  42. package/dist/core/planMode.js +6 -2
  43. package/dist/core/planMode.js.map +1 -1
  44. package/dist/core/session-bridge.d.ts +5 -1
  45. package/dist/core/session-bridge.d.ts.map +1 -1
  46. package/dist/core/session-bridge.js +13 -0
  47. package/dist/core/session-bridge.js.map +1 -1
  48. package/dist/core/skills.d.ts +2 -1
  49. package/dist/core/skills.d.ts.map +1 -1
  50. package/dist/core/skills.js.map +1 -1
  51. package/dist/core/swarm.d.ts +19 -0
  52. package/dist/core/swarm.d.ts.map +1 -0
  53. package/dist/core/swarm.js +77 -0
  54. package/dist/core/swarm.js.map +1 -0
  55. package/dist/core/tools.d.ts +8 -0
  56. package/dist/core/tools.d.ts.map +1 -1
  57. package/dist/core/tools.js +289 -8
  58. package/dist/core/tools.js.map +1 -1
  59. package/dist/core/visual-feedback.d.ts +20 -0
  60. package/dist/core/visual-feedback.d.ts.map +1 -0
  61. package/dist/core/visual-feedback.js +117 -0
  62. package/dist/core/visual-feedback.js.map +1 -0
  63. package/dist/index.js +2 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/utils/config.d.ts +76 -5
  66. package/dist/utils/config.d.ts.map +1 -1
  67. package/dist/utils/config.js +99 -22
  68. package/dist/utils/config.js.map +1 -1
  69. package/dist/utils/git.d.ts +14 -0
  70. package/dist/utils/git.d.ts.map +1 -1
  71. package/dist/utils/git.js +101 -0
  72. package/dist/utils/git.js.map +1 -1
  73. package/dist/webui/server.d.ts.map +1 -1
  74. package/dist/webui/server.js +78 -19
  75. package/dist/webui/server.js.map +1 -1
  76. package/package.json +23 -22
  77. package/webui-dist/assets/index-CSla6Lzy.css +32 -0
  78. package/webui-dist/assets/{index-D1p8sGlX.js → index-jeWUzIG0.js} +102 -95
  79. package/webui-dist/assets/index-jeWUzIG0.js.map +1 -0
  80. package/webui-dist/assets/{xterm-Da3kUA9L.js → xterm-B4aZdZLt.js} +2 -2
  81. package/webui-dist/assets/{xterm-Da3kUA9L.js.map → xterm-B4aZdZLt.js.map} +1 -1
  82. package/webui-dist/assets/{xterm-addon-fit-BUikER34.js → xterm-addon-fit-CY2T_uda.js} +2 -2
  83. package/webui-dist/assets/{xterm-addon-fit-BUikER34.js.map → xterm-addon-fit-CY2T_uda.js.map} +1 -1
  84. package/webui-dist/assets/{xterm-addon-web-links-DUxNSHSG.js → xterm-addon-web-links-D93WX0PV.js} +2 -2
  85. package/webui-dist/assets/{xterm-addon-web-links-DUxNSHSG.js.map → xterm-addon-web-links-D93WX0PV.js.map} +1 -1
  86. package/webui-dist/index.html +2 -2
  87. package/webui-dist/assets/index-6lisHL5w.css +0 -32
  88. package/webui-dist/assets/index-D1p8sGlX.js.map +0 -1
package/README.md CHANGED
@@ -10,7 +10,32 @@ AI-powered autonomous coding assistant for your terminal, browser, and desktop.
10
10
 
11
11
  XibeCode is a CLI agent that can read and edit code, run commands, and iterate on tasks from your terminal using LLMs. It includes a **WebUI** for a browser-based experience, a **Desktop App** (Electron) for native IDE-like usage, **AI-powered test generation**, and **multi-model support** for both Anthropic and OpenAI models.
12
12
 
13
- ## What's New in v0.5.4
13
+ ## What's New in v0.5.7
14
+
15
+ ### 🚀 Native Gemini Support
16
+
17
+ XibeCode now supports Google Gemini natively via their OpenAI-compatible endpoint.
18
+
19
+ - **New Models**: Gemini 3 Deep Think, Gemini 3 Flash Preview, Gemini 2.5 Pro.
20
+ - **Direct Integration**: Use your Google API Key without proxies.
21
+
22
+ ### 🔒 Settings Security & UI
23
+
24
+ - **Eye Toggle**: Added visibility toggle for API keys in Settings.
25
+ - **Improved Masking**: Better feedback for existing keys.
26
+ - **Native Providers**: Added native Google option in the provider dropdown.
27
+
28
+ ### ⚡ Comprehensive Model Update (2025-2026)
29
+
30
+ Verified support for the latest flagships from OpenAI (GPT-5.2), Anthropic (Claude 4.6), Zhipu AI (GLM-5), and more.
31
+
32
+ ### ✨ Feature Improvements
33
+
34
+ - **Enhanced Custom Providers**: Explicit "API Format" selection for custom endpoints.
35
+ - **UI Fixes**: Improved "Apply Custom Model" button feedback and settings persistence.
36
+ - **Performance**: Optimized model list loading and configuration handling.
37
+
38
+ ### v0.5.4
14
39
 
15
40
  - **Context Chips** - Terminal context (full buffer or selections) is now added as "chips" to the chat instead of raw text, keeping the interface clean while giving the AI full context.
16
41
  - **Interactive Plan Mode** - Plan mode now asks clarifying questions, searches the web, and generates detailed `implementations.md` with checkboxes. Click "Build" to auto-execute the plan.
@@ -274,16 +299,10 @@ Type `/` in the input to open the command palette:
274
299
  | `/mode agent` | 🤖 | Autonomous coding (default) |
275
300
  | `/mode plan` | 📝 | Interactive planning with web research |
276
301
  | `/mode tester` | 🧪 | Testing and QA |
277
- | `/mode debugger` | 🐛 | Bug investigation |
278
302
  | `/mode security` | 🔒 | Security analysis |
303
+ | `/mode pentest` | 🔓 | Penetration testing - run app and probe for vulnerabilities |
279
304
  | `/mode review` | 👀 | Code review |
280
305
  | `/mode team_leader` | 👑 | Coordinate team |
281
- | `/mode architect` | 🏛️ | System design |
282
- | `/mode engineer` | 🛠️ | Implementation |
283
- | `/mode seo` | 🌐 | SEO optimization |
284
- | `/mode product` | 🔥 | Product strategy |
285
- | `/mode data` | 📊 | Data analysis |
286
- | `/mode researcher` | 📚 | Deep research |
287
306
 
288
307
  ### File References (`@`)
289
308
 
@@ -447,7 +466,7 @@ POST /api/tests/run # Run project tests
447
466
 
448
467
  ## Project Structure
449
468
 
450
- ```
469
+ ```text
451
470
  xibecode/
452
471
  ├── src/
453
472
  │ ├── core/ # Agent, tools, context
@@ -460,6 +479,10 @@ xibecode/
460
479
  └── tests/ # Test suites
461
480
  ```
462
481
 
482
+ ## Dependency Map
483
+
484
+ ![Dependency Map](dependencies.svg)
485
+
463
486
  ## Project Docs
464
487
 
465
488
  - `CHANGELOG.md` — release history
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAqBA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,iBA64CrD"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAqBA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,iBA8+CrD"}
@@ -72,7 +72,7 @@ export async function chatCommand(options) {
72
72
  model,
73
73
  maxIterations: 10,
74
74
  verbose: false,
75
- }, (currentProvider || 'anthropic'));
75
+ }, currentProvider || 'anthropic');
76
76
  // Gemini‑style intro screen
77
77
  ui.chatBanner(process.cwd(), model, baseUrl);
78
78
  let enableTools = true;
@@ -90,6 +90,8 @@ export async function chatCommand(options) {
90
90
  model,
91
91
  maxIterations: 150,
92
92
  verbose: false,
93
+ provider: currentProvider,
94
+ customProviderFormat: config.get('customProviderFormat'),
93
95
  }, currentProvider);
94
96
  const allModes = getAllModes();
95
97
  let currentMode = agent.getMode();
@@ -126,9 +128,23 @@ export async function chatCommand(options) {
126
128
  // File might not exist yet
127
129
  }
128
130
  }
131
+ // Check for [[PENTEST_READY]] tag
132
+ if (text.includes('[[PENTEST_READY]]')) {
133
+ const fs = require('fs');
134
+ const path = require('path');
135
+ const reportPath = path.join(process.cwd(), 'pentest-report.md');
136
+ try {
137
+ const reportContent = fs.readFileSync(reportPath, 'utf-8');
138
+ SessionBridge.onPentestReady(reportContent, 'pentest-report.md');
139
+ }
140
+ catch {
141
+ // File might not exist yet
142
+ }
143
+ }
129
144
  }
130
145
  async function handlePlannerQuestions(questions) {
131
146
  try {
147
+ closeRL();
132
148
  const inquirer = (await import('inquirer')).default;
133
149
  const answers = {};
134
150
  for (const q of questions) {
@@ -189,6 +205,9 @@ export async function chatCommand(options) {
189
205
  catch {
190
206
  // Inquirer not available or error
191
207
  }
208
+ finally {
209
+ createRL();
210
+ }
192
211
  }
193
212
  function setupAgentHandlers() {
194
213
  agent.removeAllListeners('event');
@@ -308,18 +327,87 @@ export async function chatCommand(options) {
308
327
  messages: agent.getMessages(),
309
328
  isProcessing: false,
310
329
  });
311
- // Queue for WebUI messages and resolver for interrupting TUI input
312
- let pendingWebUIMessage = null;
313
- let webUIMessageResolver = null;
330
+ const inputQueue = [];
331
+ let inputResolver = null;
332
+ let isAgentRunning = false;
333
+ let rl = null;
334
+ let sigintCount = 0;
335
+ let lastSigintTime = 0;
336
+ function handleSigint() {
337
+ const now = Date.now();
338
+ // debounce in case both rl and keypress emit SIGINT
339
+ if (now - lastSigintTime < 100)
340
+ return;
341
+ lastSigintTime = now;
342
+ if (sigintCount === 0) {
343
+ console.log('');
344
+ ui.warning('Press Ctrl+C again to exit.');
345
+ if (!isAgentRunning)
346
+ promptUser();
347
+ sigintCount++;
348
+ setTimeout(() => { sigintCount = 0; }, 3000);
349
+ }
350
+ else {
351
+ process.exit(0);
352
+ }
353
+ }
354
+ function promptUser() {
355
+ process.stdout.write(chalk.hex('#00E676').bold('❯ You ') + '');
356
+ }
357
+ function createRL() {
358
+ if (rl)
359
+ return;
360
+ rl = readline.createInterface({
361
+ input: process.stdin,
362
+ output: process.stdout,
363
+ terminal: true
364
+ });
365
+ rl.on('line', (line) => {
366
+ const msg = line.trim();
367
+ if (!msg) {
368
+ if (!isAgentRunning)
369
+ promptUser();
370
+ return;
371
+ }
372
+ if (isAgentRunning) {
373
+ agent.injectMessage(msg);
374
+ console.log('');
375
+ ui.success(`Message queued for agent's next step.`);
376
+ }
377
+ else {
378
+ const item = { message: msg, source: 'tui' };
379
+ if (inputResolver) {
380
+ inputResolver(item);
381
+ }
382
+ else {
383
+ inputQueue.push(item);
384
+ }
385
+ }
386
+ });
387
+ rl.on('SIGINT', handleSigint);
388
+ }
389
+ function closeRL() {
390
+ if (rl) {
391
+ rl.close();
392
+ rl = null;
393
+ }
394
+ }
314
395
  // Listen for messages from WebUI
315
396
  SessionBridge.on('user_message', async (content, source) => {
316
397
  if (source === 'webui') {
317
- pendingWebUIMessage = content;
318
- // If TUI is waiting for input, resolve immediately with WebUI message
319
- if (webUIMessageResolver) {
320
- webUIMessageResolver(content);
321
- webUIMessageResolver = null;
322
- pendingWebUIMessage = null;
398
+ if (isAgentRunning) {
399
+ agent.injectMessage(content);
400
+ console.log('');
401
+ ui.info(`WebUI message injected into agent's thought process.`);
402
+ }
403
+ else {
404
+ const item = { message: content, source: 'webui' };
405
+ if (inputResolver) {
406
+ inputResolver(item);
407
+ }
408
+ else {
409
+ inputQueue.push(item);
410
+ }
323
411
  }
324
412
  }
325
413
  });
@@ -327,33 +415,16 @@ export async function chatCommand(options) {
327
415
  * Get input from either TUI or WebUI (whichever comes first)
328
416
  */
329
417
  async function getInput() {
330
- // Check if there's already a pending WebUI message
331
- if (pendingWebUIMessage) {
332
- const msg = pendingWebUIMessage;
333
- pendingWebUIMessage = null;
334
- return { message: msg, source: 'webui' };
418
+ createRL();
419
+ if (inputQueue.length > 0) {
420
+ return inputQueue.shift();
335
421
  }
336
422
  return new Promise((resolve) => {
337
- // Set up resolver for WebUI messages
338
- webUIMessageResolver = (msg) => {
339
- rl.close();
340
- resolve({ message: msg, source: 'webui' });
423
+ promptUser();
424
+ inputResolver = (input) => {
425
+ inputResolver = null;
426
+ resolve(input);
341
427
  };
342
- // Create readline interface for TUI input
343
- const rl = readline.createInterface({
344
- input: process.stdin,
345
- output: process.stdout,
346
- });
347
- // Show prompt
348
- process.stdout.write(chalk.hex('#00E676').bold('❯ You ') + '');
349
- rl.on('line', (line) => {
350
- webUIMessageResolver = null;
351
- rl.close();
352
- resolve({ message: line, source: 'tui' });
353
- });
354
- rl.on('close', () => {
355
- webUIMessageResolver = null;
356
- });
357
428
  });
358
429
  }
359
430
  async function showPathSuggestions(raw) {
@@ -477,6 +548,7 @@ export async function chatCommand(options) {
477
548
  ui.info('No saved sessions yet.');
478
549
  return;
479
550
  }
551
+ closeRL();
480
552
  const { picked } = await inquirer.prompt([
481
553
  {
482
554
  type: 'list',
@@ -488,6 +560,7 @@ export async function chatCommand(options) {
488
560
  })),
489
561
  },
490
562
  ]);
563
+ createRL();
491
564
  const loaded = await sessionManager.loadSession(picked);
492
565
  if (!loaded) {
493
566
  ui.error('Failed to load selected session');
@@ -505,6 +578,8 @@ export async function chatCommand(options) {
505
578
  model,
506
579
  maxIterations: 150,
507
580
  verbose: false,
581
+ provider: currentProvider || config.get('provider'),
582
+ customProviderFormat: config.get('customProviderFormat'),
508
583
  }, currentProvider || config.get('provider'));
509
584
  setupAgentHandlers();
510
585
  currentMode = agent.getMode();
@@ -519,6 +594,7 @@ export async function chatCommand(options) {
519
594
  ];
520
595
  const customModels = (config.get('customModels') || []);
521
596
  const unique = Array.from(new Set([current, ...fixedModels, ...customModels.map(m => m.id)]));
597
+ closeRL();
522
598
  const { picked } = await inquirer.prompt([
523
599
  {
524
600
  type: 'list',
@@ -532,11 +608,13 @@ export async function chatCommand(options) {
532
608
  }),
533
609
  },
534
610
  ]);
611
+ createRL();
535
612
  config.set('model', picked);
536
613
  ui.success(`Model set to: ${picked}`);
537
614
  }
538
615
  async function handleThemesCommand() {
539
616
  const current = ui.getThemeName();
617
+ closeRL();
540
618
  const { picked } = await inquirer.prompt([
541
619
  {
542
620
  type: 'list',
@@ -548,6 +626,7 @@ export async function chatCommand(options) {
548
626
  })),
549
627
  },
550
628
  ]);
629
+ createRL();
551
630
  ui.setTheme(picked);
552
631
  config.set('theme', picked);
553
632
  ui.success(`Theme set to: ${picked}`);
@@ -663,6 +742,10 @@ export async function chatCommand(options) {
663
742
  process.stdin.on('keypress', (_str, key) => {
664
743
  if (!key)
665
744
  return;
745
+ if (key.ctrl && key.name === 'c') {
746
+ handleSigint();
747
+ return;
748
+ }
666
749
  if (key.name === 'tab') {
667
750
  const idx = allModes.indexOf(currentMode);
668
751
  const next = allModes[(idx + 1) % allModes.length];
@@ -713,6 +796,7 @@ export async function chatCommand(options) {
713
796
  value: entry.name + (isDir ? '/' : ''),
714
797
  };
715
798
  });
799
+ closeRL();
716
800
  const { picked } = await inquirer.prompt([
717
801
  {
718
802
  type: 'list',
@@ -730,9 +814,11 @@ export async function chatCommand(options) {
730
814
  default: '@' + picked,
731
815
  },
732
816
  ]);
817
+ createRL();
733
818
  message = followUp.message;
734
819
  }
735
820
  catch (error) {
821
+ createRL();
736
822
  ui.error('Failed to list files for selection', error);
737
823
  continue;
738
824
  }
@@ -804,6 +890,7 @@ export async function chatCommand(options) {
804
890
  continue;
805
891
  }
806
892
  if (lowerMessage === '/provider') {
893
+ closeRL();
807
894
  const { picked } = await inquirer.prompt([
808
895
  {
809
896
  type: 'list',
@@ -815,6 +902,7 @@ export async function chatCommand(options) {
815
902
  ],
816
903
  },
817
904
  ]);
905
+ createRL();
818
906
  currentProvider = picked;
819
907
  config.set('provider', picked);
820
908
  // Recreate agent with new provider but keep conversation history
@@ -1040,6 +1128,7 @@ export async function chatCommand(options) {
1040
1128
  });
1041
1129
  console.log('');
1042
1130
  // Prompt to install
1131
+ closeRL();
1043
1132
  const { installChoice } = await inquirer.prompt([
1044
1133
  {
1045
1134
  type: 'list',
@@ -1054,6 +1143,7 @@ export async function chatCommand(options) {
1054
1143
  ],
1055
1144
  },
1056
1145
  ]);
1146
+ createRL();
1057
1147
  if (installChoice === '__cancel__') {
1058
1148
  continue;
1059
1149
  }
@@ -1244,10 +1334,19 @@ export async function chatCommand(options) {
1244
1334
  if (messageSource === 'tui') {
1245
1335
  SessionBridge.onTUIUserMessage(message);
1246
1336
  }
1337
+ isAgentRunning = true;
1247
1338
  // agent.run() resets its iteration/tool counters but KEEPS
1248
1339
  // the conversation history (this.messages), so the AI has
1249
1340
  // full context of everything discussed in this session.
1250
1341
  await agent.run(message, tools, toolExecutor);
1342
+ isAgentRunning = false;
1343
+ const unhandled = agent.getInjectedMessages();
1344
+ if (unhandled.length > 0) {
1345
+ agent.clearInjectedMessages();
1346
+ for (const msg of unhandled) {
1347
+ inputQueue.push({ message: msg, source: 'tui' });
1348
+ }
1349
+ }
1251
1350
  const stats = agent.getStats();
1252
1351
  // Update SessionBridge with latest messages
1253
1352
  SessionBridge.updateState({ messages: agent.getMessages() });