@compilr-dev/cli 0.8.8 → 0.8.9

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/dist/agent.js CHANGED
@@ -157,15 +157,19 @@ function resolveProviderConfig(options) {
157
157
  `Run /keys to set it, or: export ${meta.envVar}=...` +
158
158
  (providerType === 'claude' ? '\nOr use --provider ollama for local models.' : ''));
159
159
  }
160
- const model = options.model ?? getDefaultModelForTier(providerType, 'balanced')?.id;
161
- const baseUrl = providerType === 'ollama'
160
+ // Both Ollama variants hit the same local server; only the endpoint differs.
161
+ const isOllama = providerType === 'ollama' || providerType === 'ollama-anthropic';
162
+ // ollama-anthropic has no registry rows — default to classic ollama's balanced local model.
163
+ const tierSource = providerType === 'ollama-anthropic' ? 'ollama' : providerType;
164
+ const model = options.model ?? getDefaultModelForTier(tierSource, 'balanced')?.id;
165
+ const baseUrl = isOllama
162
166
  ? ((typeof getSetting('ollamaBaseUrl') === 'string'
163
167
  ? getSetting('ollamaBaseUrl')
164
168
  : undefined) ?? process.env.OLLAMA_BASE_URL ?? 'http://localhost:11434')
165
169
  : undefined;
166
170
  if (!options.quiet) {
167
171
  log.info({ component: 'agent', provider: meta.displayName, model: model ?? 'default' }, 'Provider configured');
168
- if (providerType === 'ollama' && baseUrl !== 'http://localhost:11434') {
172
+ if (isOllama && baseUrl !== 'http://localhost:11434') {
169
173
  log.info({ component: 'agent', baseUrl }, 'Ollama server');
170
174
  }
171
175
  }
Binary file
@@ -23,6 +23,7 @@ export function getDefaultModelsForUI() {
23
23
  openai: 1,
24
24
  gemini: 2,
25
25
  ollama: 3,
26
+ 'ollama-anthropic': 3,
26
27
  together: 4,
27
28
  groq: 5,
28
29
  fireworks: 6,
@@ -15,6 +15,7 @@ const CREDENTIAL_KEYS = {
15
15
  openai: 'openai',
16
16
  gemini: 'google',
17
17
  ollama: 'ollama',
18
+ 'ollama-anthropic': 'ollama', // keyless; reuses ollama's credential slot
18
19
  together: 'together',
19
20
  groq: 'groq',
20
21
  fireworks: 'fireworks',
@@ -7,7 +7,7 @@
7
7
  export type { PermissionRule, PermissionMode, PermissionLevel } from '@compilr-dev/sdk';
8
8
  import type { PermissionRule, PermissionMode, PermissionLevel } from '@compilr-dev/sdk';
9
9
  export type NotificationMode = 'auto' | 'bell' | 'disabled';
10
- export type ProviderType = 'auto' | 'claude' | 'openai' | 'gemini' | 'ollama' | 'together' | 'groq' | 'fireworks' | 'perplexity' | 'openrouter' | 'custom';
10
+ export type ProviderType = 'auto' | 'claude' | 'openai' | 'gemini' | 'ollama' | 'ollama-anthropic' | 'together' | 'groq' | 'fireworks' | 'perplexity' | 'openrouter' | 'custom';
11
11
  export type StartupMode = 'menu' | 'repl';
12
12
  export type ProjectStartupMode = 'last' | 'off';
13
13
  export type MascotSetting = 'none' | 'random' | 'neutral' | 'thinking' | 'looking_left' | 'looking_right' | 'sleeping' | 'alert' | 'error' | 'success' | 'success_minimal' | 'searching' | 'skeptical';
@@ -30,14 +30,25 @@ const TIER_WIDTH = 14;
30
30
  const LABEL_WIDTH = 14;
31
31
  const MODEL_NAME_WIDTH = 28;
32
32
  /** Primary providers that show tier-based selection */
33
- const PRIMARY_PROVIDERS = ['claude', 'openai', 'gemini', 'ollama'];
33
+ const PRIMARY_PROVIDERS = ['claude', 'openai', 'gemini', 'ollama', 'ollama-anthropic'];
34
34
  const PROVIDER_TABS = [
35
35
  { id: 'claude', label: 'Claude' },
36
36
  { id: 'openai', label: 'OpenAI' },
37
37
  { id: 'gemini', label: 'Gemini' },
38
38
  { id: 'ollama', label: 'Ollama (local)' },
39
+ { id: 'ollama-anthropic', label: 'Ollama (Claude API)' },
39
40
  { id: 'others', label: 'Others' },
40
41
  ];
42
+ /** Both Ollama providers share local-model behavior + installed-model discovery
43
+ * (same server/port); only the API endpoint differs. */
44
+ function isOllamaProvider(p) {
45
+ return p === 'ollama' || p === 'ollama-anthropic';
46
+ }
47
+ /** `ollama-anthropic` has no registry rows of its own — it borrows the classic
48
+ * `ollama` local-model tiers (same local models, different endpoint). */
49
+ function registryProviderFor(p) {
50
+ return p === 'ollama-anthropic' ? 'ollama' : p;
51
+ }
41
52
  /** All model tiers in display order */
42
53
  const ALL_TIERS = [...MODEL_TIERS];
43
54
  /**
@@ -47,11 +58,13 @@ function getListItems() {
47
58
  const items = [];
48
59
  // For each primary provider, add 3 tier items
49
60
  for (const provider of PRIMARY_PROVIDERS) {
61
+ // ollama-anthropic has no registry rows — resolve tiers from classic ollama.
62
+ const tierSource = registryProviderFor(provider);
50
63
  for (const tier of ALL_TIERS) {
51
64
  // Get default model from registry
52
- const defaultModel = getDefaultModelForTier(provider, tier);
65
+ const defaultModel = getDefaultModelForTier(tierSource, tier);
53
66
  // Get current model (may have user override)
54
- const currentModelId = getModelForTier(provider, tier);
67
+ const currentModelId = getModelForTier(tierSource, tier);
55
68
  const currentModelInfo = getModelInfo(currentModelId);
56
69
  items.push({
57
70
  type: 'tier',
@@ -446,7 +459,7 @@ class TierDetailScreen extends BaseScreen {
446
459
  this.state = {
447
460
  editMode: false,
448
461
  // For Ollama, start with URL field; otherwise just model
449
- selectedField: tierItem.provider === 'ollama' ? 'url' : 'model',
462
+ selectedField: isOllamaProvider(tierItem.provider) ? 'url' : 'model',
450
463
  editValue: '',
451
464
  cursorPos: 0,
452
465
  testing: false,
@@ -462,7 +475,7 @@ class TierDetailScreen extends BaseScreen {
462
475
  */
463
476
  buildAvailableModels() {
464
477
  const models = [];
465
- const registryModels = getModelsForProvider(this.tierItem.provider);
478
+ const registryModels = getModelsForProvider(registryProviderFor(this.tierItem.provider));
466
479
  // Add registry models (supported ones)
467
480
  for (const model of registryModels) {
468
481
  if (model.status !== 'supported')
@@ -470,7 +483,7 @@ class TierDetailScreen extends BaseScreen {
470
483
  const isDefault = model.id === this.tierItem.defaultModelId;
471
484
  // For Ollama: check if locally available
472
485
  let isLocal;
473
- if (this.tierItem.provider === 'ollama') {
486
+ if (isOllamaProvider(this.tierItem.provider)) {
474
487
  const modelName = model.id.toLowerCase();
475
488
  const baseName = modelName.split(':')[0];
476
489
  isLocal = this.ollamaState.availableModels.has(modelName) ||
@@ -484,7 +497,7 @@ class TierDetailScreen extends BaseScreen {
484
497
  });
485
498
  }
486
499
  // For Ollama: add any local models not in registry
487
- if (this.tierItem.provider === 'ollama') {
500
+ if (isOllamaProvider(this.tierItem.provider)) {
488
501
  const registryIds = new Set(models.map(m => m.id.toLowerCase()));
489
502
  for (const localModel of this.ollamaState.availableModels) {
490
503
  // Skip base names (we only want full model:tag names)
@@ -574,7 +587,7 @@ class TierDetailScreen extends BaseScreen {
574
587
  lines.push(` ${s.muted('Tier:'.padEnd(LABEL_WIDTH))}${tierInfo.label} ${s.muted(`- ${tierInfo.shortDescription}`)}`);
575
588
  lines.push('');
576
589
  // API Key Status (not shown for Ollama - no auth needed)
577
- if (this.tierItem.provider !== 'ollama') {
590
+ if (!isOllamaProvider(this.tierItem.provider)) {
578
591
  const keyStatus = checkApiKeyStatus(this.tierItem.provider);
579
592
  const keyIndicator = keyStatus.hasKey ? s.success('● Set') : s.error('○ Not set');
580
593
  const keyHint = !keyStatus.hasKey && keyStatus.hint ? s.warning(` (${keyStatus.hint})`) : '';
@@ -582,7 +595,7 @@ class TierDetailScreen extends BaseScreen {
582
595
  lines.push('');
583
596
  }
584
597
  // Ollama Server URL (only for Ollama provider)
585
- if (this.tierItem.provider === 'ollama') {
598
+ if (isOllamaProvider(this.tierItem.provider)) {
586
599
  const isUrlSelected = this.state.editMode && this.state.selectedField === 'url';
587
600
  const sectionHeader = isUrlSelected ? s.primary('─── Server URL ───') : s.muted('─── Server URL ───');
588
601
  lines.push(` ${sectionHeader}`);
@@ -648,7 +661,7 @@ class TierDetailScreen extends BaseScreen {
648
661
  const displayName = currentModelInfo?.displayName ?? this.currentModelId;
649
662
  // For Ollama: show local availability
650
663
  let localBadge = '';
651
- if (this.tierItem.provider === 'ollama' && currentModelInfo) {
664
+ if (isOllamaProvider(this.tierItem.provider) && currentModelInfo) {
652
665
  localBadge = currentModelInfo.isLocal ? s.success(' ●') : s.warning(' ○');
653
666
  }
654
667
  lines.push(` ${s.muted('Current:'.padEnd(LABEL_WIDTH))}${currentStyle(displayName)}${localBadge}${cycleIndicator}`);
@@ -676,7 +689,7 @@ class TierDetailScreen extends BaseScreen {
676
689
  lines.push(` ${s.warning('Testing model...')}`);
677
690
  }
678
691
  else if (this.state.editMode) {
679
- const arrowHint = this.tierItem.provider === 'ollama' ? '↑↓ Switch field · ' : '';
692
+ const arrowHint = isOllamaProvider(this.tierItem.provider) ? '↑↓ Switch field · ' : '';
680
693
  lines.push(` ${s.muted(`${arrowHint}Enter Save · Esc Cancel · Clear = Reset to default`)}`);
681
694
  }
682
695
  else {
@@ -737,7 +750,7 @@ class TierDetailScreen extends BaseScreen {
737
750
  if (char === 'e') {
738
751
  this.state.editMode = true;
739
752
  // For Ollama, start with URL field; otherwise just model
740
- if (this.tierItem.provider === 'ollama') {
753
+ if (isOllamaProvider(this.tierItem.provider)) {
741
754
  this.state.selectedField = 'url';
742
755
  this.state.editValue = this.currentOllamaUrl;
743
756
  this.state.cursorPos = this.currentOllamaUrl.length;
@@ -805,7 +818,7 @@ class TierDetailScreen extends BaseScreen {
805
818
  return stay(true);
806
819
  }
807
820
  // Up/Down arrows - switch between fields (only for Ollama)
808
- if (this.tierItem.provider === 'ollama') {
821
+ if (isOllamaProvider(this.tierItem.provider)) {
809
822
  // Up arrow
810
823
  if (data[2] === 0x41) {
811
824
  if (this.state.selectedField === 'model') {
@@ -915,7 +928,7 @@ class TierDetailScreen extends BaseScreen {
915
928
  }
916
929
  getMinHeight() {
917
930
  // Ollama needs more height for the URL section
918
- return this.tierItem.provider === 'ollama' ? 26 : 22;
931
+ return isOllamaProvider(this.tierItem.provider) ? 26 : 22;
919
932
  }
920
933
  }
921
934
  // =============================================================================
@@ -986,7 +999,7 @@ export class ModelOverlayV2 extends TabbedListOverlayV2 {
986
999
  const isActive = item.currentModelId === activeModel && item.provider === activeProvider;
987
1000
  // For Ollama, show availability status; for others, show API key status
988
1001
  let statusIndicator;
989
- if (item.provider === 'ollama') {
1002
+ if (isOllamaProvider(item.provider)) {
990
1003
  const isLocallyAvailable = this.ollamaState.availableModels.has(item.currentModelId.toLowerCase()) ||
991
1004
  this.ollamaState.availableModels.has(item.currentModelId.split(':')[0].toLowerCase());
992
1005
  statusIndicator = isLocallyAvailable ? styles.success('●') : styles.warning('○');
@@ -1014,8 +1027,8 @@ export class ModelOverlayV2 extends TabbedListOverlayV2 {
1014
1027
  if (currentTabId === 'others') {
1015
1028
  return 'Tab · ↑↓ · / Search · Enter Details · q Close';
1016
1029
  }
1017
- // Ollama doesn't need API key
1018
- if (currentTabId === 'ollama') {
1030
+ // Ollama (both variants) doesn't need an API key
1031
+ if (currentTabId === 'ollama' || currentTabId === 'ollama-anthropic') {
1019
1032
  return 'Tab · ↑↓ · / Search · Enter Details · q Close';
1020
1033
  }
1021
1034
  // Standard providers: show s Set Key option
@@ -1026,8 +1039,8 @@ export class ModelOverlayV2 extends TabbedListOverlayV2 {
1026
1039
  // Skip for "Others" tab (has its own detail screen)
1027
1040
  if (tabId === 'others')
1028
1041
  return [];
1029
- // Ollama: show connection status
1030
- if (tabId === 'ollama') {
1042
+ // Ollama (both variants): show connection status
1043
+ if (tabId === 'ollama' || tabId === 'ollama-anthropic') {
1031
1044
  const status = this.ollamaState.status;
1032
1045
  let indicator;
1033
1046
  switch (status) {
@@ -1057,7 +1070,7 @@ export class ModelOverlayV2 extends TabbedListOverlayV2 {
1057
1070
  // Handle 's' key to set API key for current provider
1058
1071
  handleCustomKey: (key, tabId) => {
1059
1072
  const char = key.toString();
1060
- if (char === 's' && tabId !== 'others' && tabId !== 'ollama') {
1073
+ if (char === 's' && tabId !== 'others' && tabId !== 'ollama' && tabId !== 'ollama-anthropic') {
1061
1074
  const providerName = PROVIDER_TABS.find(t => t.id === tabId)?.label ?? tabId;
1062
1075
  return {
1063
1076
  handled: true,
@@ -71,4 +71,4 @@ export declare function getProvidersByCategory(category: ProviderCategory): Prov
71
71
  /**
72
72
  * Map provider type from settings to credential provider key
73
73
  */
74
- export declare function settingsProviderToCredentialKey(provider: 'auto' | 'claude' | 'openai' | 'gemini' | 'ollama' | 'together' | 'groq' | 'fireworks' | 'perplexity' | 'openrouter' | 'custom'): ProviderKey;
74
+ export declare function settingsProviderToCredentialKey(provider: 'auto' | 'claude' | 'openai' | 'gemini' | 'ollama' | 'ollama-anthropic' | 'together' | 'groq' | 'fireworks' | 'perplexity' | 'openrouter' | 'custom'): ProviderKey;
@@ -364,6 +364,7 @@ export function settingsProviderToCredentialKey(provider) {
364
364
  case 'openai':
365
365
  return 'openai';
366
366
  case 'ollama':
367
+ case 'ollama-anthropic':
367
368
  return 'ollama';
368
369
  case 'together':
369
370
  return 'together';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/cli",
3
- "version": "0.8.8",
3
+ "version": "0.8.9",
4
4
  "description": "AI-powered coding assistant CLI using @compilr-dev/agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -60,7 +60,7 @@
60
60
  "@compilr-dev/editor-core": "^0.0.3",
61
61
  "@compilr-dev/factory": "^0.1.35",
62
62
  "@compilr-dev/logger": "^0.1.0",
63
- "@compilr-dev/sdk": "^0.18.9",
63
+ "@compilr-dev/sdk": "^0.18.10",
64
64
  "@compilr-dev/ui-core": "^0.0.1",
65
65
  "@modelcontextprotocol/sdk": "^1.23.0",
66
66
  "ansi-escapes": "^7.3.0",