codeep 1.3.42 → 2.0.1
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/README.md +208 -0
- package/dist/acp/commands.js +770 -7
- package/dist/acp/protocol.d.ts +11 -2
- package/dist/acp/server.js +179 -11
- package/dist/acp/session.d.ts +3 -0
- package/dist/acp/session.js +5 -0
- package/dist/api/index.js +39 -6
- package/dist/config/index.d.ts +13 -0
- package/dist/config/index.js +45 -0
- package/dist/config/providers.js +76 -1
- package/dist/renderer/App.d.ts +12 -0
- package/dist/renderer/App.js +109 -4
- package/dist/renderer/agentExecution.js +5 -0
- package/dist/renderer/commands.js +638 -2
- package/dist/renderer/components/Help.js +28 -0
- package/dist/renderer/components/Login.d.ts +1 -0
- package/dist/renderer/components/Login.js +24 -9
- package/dist/renderer/handlers.d.ts +11 -1
- package/dist/renderer/handlers.js +30 -0
- package/dist/renderer/main.js +73 -0
- package/dist/utils/agent.d.ts +17 -0
- package/dist/utils/agent.js +91 -7
- package/dist/utils/agentChat.d.ts +10 -2
- package/dist/utils/agentChat.js +48 -9
- package/dist/utils/agentStream.js +6 -2
- package/dist/utils/checkpoints.d.ts +93 -0
- package/dist/utils/checkpoints.js +205 -0
- package/dist/utils/context.d.ts +24 -0
- package/dist/utils/context.js +57 -0
- package/dist/utils/customCommands.d.ts +62 -0
- package/dist/utils/customCommands.js +201 -0
- package/dist/utils/hooks.d.ts +97 -0
- package/dist/utils/hooks.js +223 -0
- package/dist/utils/mcpClient.d.ts +229 -0
- package/dist/utils/mcpClient.js +497 -0
- package/dist/utils/mcpConfig.d.ts +55 -0
- package/dist/utils/mcpConfig.js +177 -0
- package/dist/utils/mcpMarketplace.d.ts +49 -0
- package/dist/utils/mcpMarketplace.js +175 -0
- package/dist/utils/mcpRegistry.d.ts +129 -0
- package/dist/utils/mcpRegistry.js +427 -0
- package/dist/utils/mcpSamplingBridge.d.ts +32 -0
- package/dist/utils/mcpSamplingBridge.js +88 -0
- package/dist/utils/mcpStreamableHttp.d.ts +65 -0
- package/dist/utils/mcpStreamableHttp.js +207 -0
- package/dist/utils/openrouterPrefs.d.ts +36 -0
- package/dist/utils/openrouterPrefs.js +83 -0
- package/dist/utils/skillBundles.d.ts +84 -0
- package/dist/utils/skillBundles.js +257 -0
- package/dist/utils/skillBundlesCloud.d.ts +69 -0
- package/dist/utils/skillBundlesCloud.js +202 -0
- package/dist/utils/tokenTracker.d.ts +14 -2
- package/dist/utils/tokenTracker.js +59 -41
- package/dist/utils/toolExecution.d.ts +17 -1
- package/dist/utils/toolExecution.js +184 -6
- package/dist/utils/tools.d.ts +22 -6
- package/dist/utils/tools.js +83 -8
- package/package.json +3 -2
- package/bin/codeep-macos-arm64 +0 -0
- package/bin/codeep-macos-x64 +0 -0
package/dist/config/providers.js
CHANGED
|
@@ -275,6 +275,42 @@ export const PROVIDERS = {
|
|
|
275
275
|
groupLabel: 'Google AI',
|
|
276
276
|
hint: 'Pay-per-use via Google AI API key (aistudio.google.com).',
|
|
277
277
|
},
|
|
278
|
+
'openrouter': {
|
|
279
|
+
name: 'OpenRouter',
|
|
280
|
+
description: 'Unified access to 100+ models via one API key',
|
|
281
|
+
protocols: {
|
|
282
|
+
openai: {
|
|
283
|
+
baseUrl: 'https://openrouter.ai/api/v1',
|
|
284
|
+
authHeader: 'Bearer',
|
|
285
|
+
supportsNativeTools: true,
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
// Top 12 — the full catalog (100+) is fetched lazily via
|
|
289
|
+
// fetchOpenRouterModels() because dynamicModels is true.
|
|
290
|
+
// We keep these hardcoded so first-time users without network
|
|
291
|
+
// get a working dropdown.
|
|
292
|
+
models: [
|
|
293
|
+
{ id: 'openrouter/auto', name: 'Auto-route', description: 'OpenRouter picks the best model for the task' },
|
|
294
|
+
{ id: 'anthropic/claude-opus-4', name: 'Claude Opus 4', description: 'Anthropic — most capable' },
|
|
295
|
+
{ id: 'anthropic/claude-sonnet-4', name: 'Claude Sonnet 4', description: 'Anthropic — balanced' },
|
|
296
|
+
{ id: 'openai/gpt-5.5', name: 'GPT-5.5', description: 'OpenAI — flagship' },
|
|
297
|
+
{ id: 'openai/gpt-5.4-mini', name: 'GPT-5.4 Mini', description: 'OpenAI — fast/cheap' },
|
|
298
|
+
{ id: 'google/gemini-3.1-pro', name: 'Gemini 3.1 Pro', description: 'Google — multimodal' },
|
|
299
|
+
{ id: 'meta-llama/llama-3.1-405b-instruct', name: 'Llama 3.1 405B', description: 'Meta — open weights, largest' },
|
|
300
|
+
{ id: 'meta-llama/llama-3.1-70b-instruct', name: 'Llama 3.1 70B', description: 'Meta — open weights, fast' },
|
|
301
|
+
{ id: 'deepseek/deepseek-v4', name: 'DeepSeek V4', description: 'DeepSeek via OpenRouter' },
|
|
302
|
+
{ id: 'mistralai/mistral-large', name: 'Mistral Large', description: 'Mistral — flagship' },
|
|
303
|
+
{ id: 'qwen/qwen-2.5-coder-32b-instruct', name: 'Qwen 2.5 Coder 32B', description: 'Alibaba — coding-tuned' },
|
|
304
|
+
{ id: 'x-ai/grok-2', name: 'Grok 2', description: 'xAI via OpenRouter' },
|
|
305
|
+
],
|
|
306
|
+
defaultModel: 'anthropic/claude-opus-4',
|
|
307
|
+
defaultProtocol: 'openai',
|
|
308
|
+
envKey: 'OPENROUTER_API_KEY',
|
|
309
|
+
subscribeUrl: 'https://openrouter.ai/keys',
|
|
310
|
+
dynamicModels: true,
|
|
311
|
+
groupLabel: 'OpenRouter — Aggregator',
|
|
312
|
+
hint: 'One key for 100+ models. Pay-per-use via openrouter.ai.',
|
|
313
|
+
},
|
|
278
314
|
'ollama': {
|
|
279
315
|
name: 'Ollama (local)',
|
|
280
316
|
description: 'Run models locally with Ollama',
|
|
@@ -299,8 +335,47 @@ export const PROVIDERS = {
|
|
|
299
335
|
export function getProvider(id) {
|
|
300
336
|
return PROVIDERS[id] || null;
|
|
301
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* Curated display order for the first-run login flow + `/provider` /
|
|
340
|
+
* `/login` pickers. Headline / popular providers float to the top so
|
|
341
|
+
* brand-new users see them first; regional + parameter-variant entries
|
|
342
|
+
* (Z.AI China, MiniMax variants) trail. Any provider id not in this
|
|
343
|
+
* list is appended afterward in object-declaration order, so adding a
|
|
344
|
+
* new provider to PROVIDERS without touching this list still shows up.
|
|
345
|
+
*/
|
|
346
|
+
const DISPLAY_ORDER = [
|
|
347
|
+
'anthropic',
|
|
348
|
+
'openai',
|
|
349
|
+
'openrouter', // 100+ models, one key — surfaced high on purpose for 2.0.0.
|
|
350
|
+
'z.ai',
|
|
351
|
+
'z.ai-api',
|
|
352
|
+
'deepseek',
|
|
353
|
+
'google',
|
|
354
|
+
'minimax',
|
|
355
|
+
'minimax-api',
|
|
356
|
+
'ollama',
|
|
357
|
+
'z.ai-cn',
|
|
358
|
+
'z.ai-cn-api',
|
|
359
|
+
'minimax-cn',
|
|
360
|
+
];
|
|
302
361
|
export function getProviderList() {
|
|
303
|
-
|
|
362
|
+
const all = Object.entries(PROVIDERS);
|
|
363
|
+
const byId = new Map(all);
|
|
364
|
+
const ordered = [];
|
|
365
|
+
// 1) Curated order first.
|
|
366
|
+
for (const id of DISPLAY_ORDER) {
|
|
367
|
+
const cfg = byId.get(id);
|
|
368
|
+
if (cfg) {
|
|
369
|
+
ordered.push([id, cfg]);
|
|
370
|
+
byId.delete(id);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// 2) Anything else, in declaration order.
|
|
374
|
+
for (const entry of all) {
|
|
375
|
+
if (byId.has(entry[0]))
|
|
376
|
+
ordered.push(entry);
|
|
377
|
+
}
|
|
378
|
+
return ordered.map(([id, config]) => ({
|
|
304
379
|
id,
|
|
305
380
|
name: config.name,
|
|
306
381
|
description: config.description,
|
package/dist/renderer/App.d.ts
CHANGED
|
@@ -69,7 +69,11 @@ export declare class App {
|
|
|
69
69
|
private confirmSelection;
|
|
70
70
|
private menuOpen;
|
|
71
71
|
private menuTitle;
|
|
72
|
+
/** Filtered view shown to the user; derived from `menuItemsAll` + `menuFilter`. */
|
|
72
73
|
private menuItems;
|
|
74
|
+
/** Full unfiltered list captured on `showSelect`. */
|
|
75
|
+
private menuItemsAll;
|
|
76
|
+
private menuFilter;
|
|
73
77
|
private menuIndex;
|
|
74
78
|
private menuCurrentValue;
|
|
75
79
|
private menuCallback;
|
|
@@ -271,6 +275,7 @@ export declare class App {
|
|
|
271
275
|
showLogin(providers: Array<{
|
|
272
276
|
id: string;
|
|
273
277
|
name: string;
|
|
278
|
+
description?: string;
|
|
274
279
|
subscribeUrl?: string;
|
|
275
280
|
}>, callback: (result: {
|
|
276
281
|
providerId: string;
|
|
@@ -284,6 +289,13 @@ export declare class App {
|
|
|
284
289
|
* Show inline menu (renders below status bar)
|
|
285
290
|
*/
|
|
286
291
|
showSelect(title: string, items: SelectItem[], currentValue: string, callback: (item: SelectItem) => void): void;
|
|
292
|
+
/**
|
|
293
|
+
* Recompute the visible menu list from the current filter string.
|
|
294
|
+
* Matches across key/label/description, case-insensitive. Keeps the
|
|
295
|
+
* current value highlighted if it survives the filter; otherwise
|
|
296
|
+
* cursor returns to the top.
|
|
297
|
+
*/
|
|
298
|
+
private applyMenuFilter;
|
|
287
299
|
/**
|
|
288
300
|
* Handle keyboard input
|
|
289
301
|
*/
|
package/dist/renderer/App.js
CHANGED
|
@@ -82,6 +82,15 @@ const COMMAND_DESCRIPTIONS = {
|
|
|
82
82
|
'profile': 'Save/load settings profiles',
|
|
83
83
|
'tasks': 'Show pending tasks from codeep.dev dashboard',
|
|
84
84
|
'sync': 'Sync learning preferences and profiles to codeep.dev',
|
|
85
|
+
// 2.0 — surfaced for `/` autocomplete; documented in /help too.
|
|
86
|
+
'compact': 'Summarize older messages to free up context',
|
|
87
|
+
'commands': 'List custom slash commands in .codeep/commands/*.md',
|
|
88
|
+
'checkpoint': 'Snapshot the session (conversation + provider/model + git HEAD)',
|
|
89
|
+
'checkpoints': 'List saved checkpoints for this workspace',
|
|
90
|
+
'rewind': 'Restore conversation from a saved checkpoint',
|
|
91
|
+
'hooks': 'List installed lifecycle hooks (.codeep/hooks/<event>.sh)',
|
|
92
|
+
'mcp': 'Manage MCP servers (browse, install, add, remove, resources, prompts)',
|
|
93
|
+
'openrouter': 'Tune OpenRouter routing (preferred / ignore providers, fallbacks, privacy)',
|
|
85
94
|
};
|
|
86
95
|
import { helpCategories, keyboardShortcuts } from './components/Help.js';
|
|
87
96
|
import { handleSettingsKey, SETTINGS } from './components/Settings.js';
|
|
@@ -142,7 +151,11 @@ export class App {
|
|
|
142
151
|
// Inline menu state (renders below input/status)
|
|
143
152
|
menuOpen = false;
|
|
144
153
|
menuTitle = '';
|
|
154
|
+
/** Filtered view shown to the user; derived from `menuItemsAll` + `menuFilter`. */
|
|
145
155
|
menuItems = [];
|
|
156
|
+
/** Full unfiltered list captured on `showSelect`. */
|
|
157
|
+
menuItemsAll = [];
|
|
158
|
+
menuFilter = '';
|
|
146
159
|
menuIndex = 0;
|
|
147
160
|
menuCurrentValue = '';
|
|
148
161
|
menuCallback = null;
|
|
@@ -213,6 +226,10 @@ export class App {
|
|
|
213
226
|
'provider', 'model', 'protocol', 'lang', 'grant', 'login', 'logout',
|
|
214
227
|
'context-save', 'context-load', 'context-clear', 'learn',
|
|
215
228
|
'cost', 'tasks', 'account', 'sync',
|
|
229
|
+
// 2.0 — extensions, checkpoints, MCP, custom commands, OpenRouter prefs.
|
|
230
|
+
// Keep in lockstep with COMMAND_DESCRIPTIONS below and helpCategories.
|
|
231
|
+
'compact', 'commands', 'checkpoint', 'checkpoints', 'rewind',
|
|
232
|
+
'hooks', 'mcp', 'openrouter',
|
|
216
233
|
'c', 't', 'd', 'r', 'f', 'e', 'o', 'b', 'p',
|
|
217
234
|
];
|
|
218
235
|
constructor(options) {
|
|
@@ -723,7 +740,9 @@ export class App {
|
|
|
723
740
|
*/
|
|
724
741
|
showSelect(title, items, currentValue, callback) {
|
|
725
742
|
this.menuTitle = title;
|
|
743
|
+
this.menuItemsAll = items;
|
|
726
744
|
this.menuItems = items;
|
|
745
|
+
this.menuFilter = '';
|
|
727
746
|
this.menuCurrentValue = currentValue;
|
|
728
747
|
this.menuCallback = callback;
|
|
729
748
|
this.menuOpen = true;
|
|
@@ -732,6 +751,27 @@ export class App {
|
|
|
732
751
|
this.menuIndex = currentIndex >= 0 ? currentIndex : 0;
|
|
733
752
|
this.scheduleRender();
|
|
734
753
|
}
|
|
754
|
+
/**
|
|
755
|
+
* Recompute the visible menu list from the current filter string.
|
|
756
|
+
* Matches across key/label/description, case-insensitive. Keeps the
|
|
757
|
+
* current value highlighted if it survives the filter; otherwise
|
|
758
|
+
* cursor returns to the top.
|
|
759
|
+
*/
|
|
760
|
+
applyMenuFilter(next) {
|
|
761
|
+
this.menuFilter = next;
|
|
762
|
+
if (!next) {
|
|
763
|
+
this.menuItems = this.menuItemsAll;
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
const f = next.toLowerCase();
|
|
767
|
+
this.menuItems = this.menuItemsAll.filter((item) => item.key.toLowerCase().includes(f) ||
|
|
768
|
+
item.label.toLowerCase().includes(f) ||
|
|
769
|
+
(item.description?.toLowerCase().includes(f) ?? false));
|
|
770
|
+
}
|
|
771
|
+
const surviving = this.menuItems.findIndex((item) => item.key === this.menuCurrentValue);
|
|
772
|
+
this.menuIndex = surviving >= 0 ? surviving : 0;
|
|
773
|
+
this.scheduleRender();
|
|
774
|
+
}
|
|
735
775
|
/**
|
|
736
776
|
* Handle keyboard input
|
|
737
777
|
*/
|
|
@@ -1157,10 +1197,14 @@ export class App {
|
|
|
1157
1197
|
const callback = this.menuCallback;
|
|
1158
1198
|
this.menuOpen = false;
|
|
1159
1199
|
this.menuCallback = null;
|
|
1200
|
+
this.menuFilter = '';
|
|
1201
|
+
this.menuItemsAll = [];
|
|
1160
1202
|
if (selected && callback)
|
|
1161
1203
|
callback(selected);
|
|
1162
1204
|
},
|
|
1163
1205
|
render: () => this.scheduleRender(),
|
|
1206
|
+
filter: this.menuFilter,
|
|
1207
|
+
setFilter: (v) => this.applyMenuFilter(v),
|
|
1164
1208
|
});
|
|
1165
1209
|
}
|
|
1166
1210
|
/**
|
|
@@ -1524,7 +1568,10 @@ export class App {
|
|
|
1524
1568
|
// Menu open (provider, model, lang, etc.)
|
|
1525
1569
|
if (this.menuOpen) {
|
|
1526
1570
|
this.screen.write(0, y, '> ', fg.gray);
|
|
1527
|
-
this.
|
|
1571
|
+
const hint = this.menuItemsAll.length > 10
|
|
1572
|
+
? 'Type to filter, ↑↓ to navigate, Enter to pick…'
|
|
1573
|
+
: 'Select an option below…';
|
|
1574
|
+
this.screen.write(2, y, hint, fg.yellow);
|
|
1528
1575
|
this.screen.showCursor(false);
|
|
1529
1576
|
return;
|
|
1530
1577
|
}
|
|
@@ -1669,7 +1716,7 @@ export class App {
|
|
|
1669
1716
|
*/
|
|
1670
1717
|
renderInlineMenu(startY, width) {
|
|
1671
1718
|
const items = this.menuItems;
|
|
1672
|
-
const maxVisible = Math.min(items.length, 10);
|
|
1719
|
+
const maxVisible = Math.min(Math.max(items.length, 1), 10);
|
|
1673
1720
|
// Calculate visible range with scroll
|
|
1674
1721
|
let visibleStart = 0;
|
|
1675
1722
|
if (items.length > maxVisible) {
|
|
@@ -1681,6 +1728,17 @@ export class App {
|
|
|
1681
1728
|
this.screen.horizontalLine(y++, '─', PRIMARY_COLOR);
|
|
1682
1729
|
// Title
|
|
1683
1730
|
this.screen.writeLine(y++, this.menuTitle, PRIMARY_COLOR + style.bold);
|
|
1731
|
+
// Filter line — only rendered while filtering, so the menu looks
|
|
1732
|
+
// identical to the pre-filter UI by default.
|
|
1733
|
+
if (this.menuFilter) {
|
|
1734
|
+
const matchInfo = items.length === 0
|
|
1735
|
+
? ' (no matches)'
|
|
1736
|
+
: ` (${items.length}/${this.menuItemsAll.length})`;
|
|
1737
|
+
this.screen.writeLine(y++, `Filter: ${this.menuFilter}█${matchInfo}`, fg.cyan);
|
|
1738
|
+
}
|
|
1739
|
+
if (items.length === 0) {
|
|
1740
|
+
this.screen.writeLine(y++, ' No items match. Backspace to edit, Esc to clear.', fg.gray);
|
|
1741
|
+
}
|
|
1684
1742
|
// Items
|
|
1685
1743
|
for (let i = 0; i < visibleItems.length; i++) {
|
|
1686
1744
|
const item = visibleItems[i];
|
|
@@ -1700,7 +1758,8 @@ export class App {
|
|
|
1700
1758
|
}
|
|
1701
1759
|
// Footer with navigation hints
|
|
1702
1760
|
const scrollInfo = items.length > maxVisible ? ` (${visibleStart + 1}-${visibleStart + visibleItems.length}/${items.length})` : '';
|
|
1703
|
-
this.
|
|
1761
|
+
const escHint = this.menuFilter ? 'Esc clear · Esc Esc cancel' : 'Esc cancel';
|
|
1762
|
+
this.screen.writeLine(y, `↑↓ navigate • Enter select • type to filter • ${escHint}${scrollInfo}`, fg.gray);
|
|
1704
1763
|
}
|
|
1705
1764
|
/**
|
|
1706
1765
|
* Render inline settings below status bar
|
|
@@ -2440,6 +2499,20 @@ export class App {
|
|
|
2440
2499
|
continue;
|
|
2441
2500
|
}
|
|
2442
2501
|
}
|
|
2502
|
+
// Strikethrough: ~~text~~ — using the SGR strikethrough escape (\x1b[9m).
|
|
2503
|
+
// Widely supported in modern terminals (iTerm2, Kitty, WezTerm, Alacritty,
|
|
2504
|
+
// gnome-terminal, Windows Terminal). Falls back gracefully to the dim
|
|
2505
|
+
// text colour on terminals that don't render the SGR.
|
|
2506
|
+
if (text.slice(i, i + 2) === '~~') {
|
|
2507
|
+
const end = text.indexOf('~~', i + 2);
|
|
2508
|
+
if (end !== -1) {
|
|
2509
|
+
const inner = text.slice(i + 2, end);
|
|
2510
|
+
result += '\x1b[9m' + fg.rgb(140, 140, 140) + inner + '\x1b[0m';
|
|
2511
|
+
hasFormatting = true;
|
|
2512
|
+
i = end + 2;
|
|
2513
|
+
continue;
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2443
2516
|
result += text[i];
|
|
2444
2517
|
i++;
|
|
2445
2518
|
}
|
|
@@ -2479,6 +2552,25 @@ export class App {
|
|
|
2479
2552
|
});
|
|
2480
2553
|
continue;
|
|
2481
2554
|
}
|
|
2555
|
+
// Blockquote: `> text` — render with a left accent bar (PRIMARY_COLOR)
|
|
2556
|
+
// and the body in a dimmer grey so it visually sits behind regular text.
|
|
2557
|
+
// Strips one level of `> ` so nested quotes render with their own bar.
|
|
2558
|
+
const quoteMatch = line.match(/^(\s*)>\s?(.*)$/);
|
|
2559
|
+
if (quoteMatch) {
|
|
2560
|
+
const indent = quoteMatch[1];
|
|
2561
|
+
const quoteText = quoteMatch[2];
|
|
2562
|
+
const { formatted, hasFormatting } = this.applyInlineMarkdown(quoteText);
|
|
2563
|
+
const body = hasFormatting ? formatted : quoteText;
|
|
2564
|
+
// Vertical bar + space, then dim grey body. Skip if the body is
|
|
2565
|
+
// empty so an isolated `>` renders cleanly.
|
|
2566
|
+
const barred = PRIMARY_COLOR + '│' + '\x1b[0m' + (body ? ' ' + fg.rgb(160, 160, 160) + body + '\x1b[0m' : '');
|
|
2567
|
+
lines.push({
|
|
2568
|
+
text: prefix + indent + barred,
|
|
2569
|
+
style: prefixStyle,
|
|
2570
|
+
raw: true,
|
|
2571
|
+
});
|
|
2572
|
+
continue;
|
|
2573
|
+
}
|
|
2482
2574
|
// List items: - item or * item or numbered 1. item
|
|
2483
2575
|
const listMatch = line.match(/^(\s*)([-*]|\d+\.)\s+(.+)$/);
|
|
2484
2576
|
if (listMatch) {
|
|
@@ -2621,12 +2713,25 @@ export class App {
|
|
|
2621
2713
|
// Provider selection
|
|
2622
2714
|
this.screen.writeLine(y++, 'Select Provider', fg.cyan + style.bold);
|
|
2623
2715
|
y++;
|
|
2716
|
+
// Name column width — pad so descriptions align in a column.
|
|
2717
|
+
// Description is clipped to remaining terminal width with an ellipsis;
|
|
2718
|
+
// on narrow panes the user still sees the name and a hint of the
|
|
2719
|
+
// description rather than a silent overrun past the right edge.
|
|
2720
|
+
const longestName = this.loginProviders.reduce((m, p) => Math.max(m, p.name.length), 0);
|
|
2721
|
+
const descStartX = 2 + longestName + 2;
|
|
2722
|
+
const descBudget = Math.max(0, width - descStartX - 1);
|
|
2624
2723
|
for (let i = 0; i < this.loginProviders.length; i++) {
|
|
2625
2724
|
const provider = this.loginProviders[i];
|
|
2626
2725
|
const isSelected = i === this.loginProviderIndex;
|
|
2627
2726
|
const prefix = isSelected ? '→ ' : ' ';
|
|
2628
2727
|
this.screen.write(0, y, prefix, isSelected ? fg.green : '');
|
|
2629
|
-
this.screen.write(2, y, provider.name, isSelected ? fg.green + style.bold : fg.white);
|
|
2728
|
+
this.screen.write(2, y, provider.name.padEnd(longestName + 2), isSelected ? fg.green + style.bold : fg.white);
|
|
2729
|
+
if (provider.description && descBudget > 0) {
|
|
2730
|
+
const desc = provider.description.length > descBudget
|
|
2731
|
+
? provider.description.slice(0, Math.max(1, descBudget - 1)) + '…'
|
|
2732
|
+
: provider.description;
|
|
2733
|
+
this.screen.write(descStartX, y, desc, isSelected ? fg.white : fg.gray);
|
|
2734
|
+
}
|
|
2630
2735
|
y++;
|
|
2631
2736
|
}
|
|
2632
2737
|
y++;
|
|
@@ -179,6 +179,11 @@ export async function executeAgentTask(task, dryRun, ctx) {
|
|
|
179
179
|
dryRun,
|
|
180
180
|
onRequestPermission,
|
|
181
181
|
chatHistory: app.getChatHistory(),
|
|
182
|
+
// Route MCP-prefixed tool calls through the shared TUI session id.
|
|
183
|
+
// Servers were registered against this id at app startup (see
|
|
184
|
+
// renderer/main.ts) so the agent picks up any `.codeep/mcp_servers.json`
|
|
185
|
+
// entries plus global ones at runtime.
|
|
186
|
+
mcpSessionId: 'codeep-tui',
|
|
182
187
|
onIteration: (iteration, message) => {
|
|
183
188
|
app.updateAgentProgress(iteration);
|
|
184
189
|
app.setAgentWaitingForAI(true); // Waiting for AI response between tool calls
|