@iaforged/context-code 1.2.5 → 1.2.8

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.
@@ -16,11 +16,43 @@ function formatAgent(agent) {
16
16
  }
17
17
  return parts.join(' · ');
18
18
  }
19
- export async function agentsHandler() {
19
+ export async function agentsHandler(opts = {}) {
20
20
  const cwd = getCwd();
21
21
  const { allAgents } = await getAgentDefinitionsWithOverrides(cwd);
22
22
  const activeAgents = getActiveAgentsFromList(allAgents);
23
23
  const resolvedAgents = resolveAgentOverrides(allAgents, activeAgents);
24
+ if (opts.json) {
25
+ const entries = [];
26
+ for (const { source } of AGENT_SOURCE_GROUPS) {
27
+ const groupAgents = resolvedAgents
28
+ .filter(a => a.source === source)
29
+ .sort(compareAgentsByName);
30
+ for (const agent of groupAgents) {
31
+ entries.push({
32
+ name: agent.agentType,
33
+ source: agent.source,
34
+ description: agent.whenToUse ?? '',
35
+ model: resolveAgentModelDisplay(agent) || null,
36
+ provider: agent.provider ?? null,
37
+ tools: agent.tools ?? null,
38
+ disallowedTools: agent.disallowedTools ?? null,
39
+ permissionMode: agent.permissionMode ?? null,
40
+ memory: agent.memory ?? null,
41
+ color: agent.color ?? null,
42
+ skills: agent.skills ?? null,
43
+ filename: agent.filename ?? null,
44
+ baseDir: agent.baseDir ?? null,
45
+ background: !!agent.background,
46
+ shadowed: !!agent.overriddenBy,
47
+ shadowedBy: agent.overriddenBy
48
+ ? getOverrideSourceLabel(agent.overriddenBy)
49
+ : null,
50
+ });
51
+ }
52
+ }
53
+ process.stdout.write(JSON.stringify({ cwd, agents: entries }) + '\n');
54
+ return;
55
+ }
24
56
  const lines = [];
25
57
  let totalActive = 0;
26
58
  for (const { label, source } of AGENT_SOURCE_GROUPS) {
@@ -56,9 +56,14 @@ async function clearProviderSession(provider) {
56
56
  const secureStorage = getSecureStorage();
57
57
  const existingData = secureStorage.read();
58
58
  if (existingData) {
59
+ const providerProfileOauth = Object.fromEntries(Object.entries(existingData.providerProfileOauth ?? {}).filter(([key]) => !key.startsWith('claude/')));
59
60
  const { claudeAiOauth: _removed, ...rest } = existingData;
60
- if (Object.keys(rest).length > 0) {
61
- secureStorage.update(rest);
61
+ const nextData = {
62
+ ...rest,
63
+ providerProfileOauth,
64
+ };
65
+ if (Object.keys(nextData).length > 0) {
66
+ secureStorage.update(nextData);
62
67
  }
63
68
  else {
64
69
  secureStorage.delete();
@@ -0,0 +1,89 @@
1
+ /* eslint-disable custom-rules/no-process-exit -- CLI subcommand handler intentionally exits */
2
+ import { fetchProviderModels } from '../../utils/model/providerModels.js';
3
+ import { VISIBLE_PROVIDERS } from '../../utils/model/providerCatalog.js';
4
+ import { getAPIProvider } from '../../utils/model/providers.js';
5
+ const CLAUDE_DEFAULT_MODELS = [
6
+ { id: 'claude-opus-4-7', label: 'Opus 4.7', description: 'Mas capaz, ideal para tareas complejas.' },
7
+ { id: 'claude-sonnet-4-6', label: 'Sonnet 4.6', description: 'Balanceado, recomendado para uso general.' },
8
+ { id: 'claude-haiku-4-5-20251001', label: 'Haiku 4.5', description: 'Rapido y economico.' },
9
+ { id: 'opus', label: 'opus (alias)', description: 'Alias dinamico al Opus por defecto.' },
10
+ { id: 'sonnet', label: 'sonnet (alias)', description: 'Alias dinamico al Sonnet por defecto.' },
11
+ { id: 'haiku', label: 'haiku (alias)', description: 'Alias dinamico al Haiku por defecto.' },
12
+ ];
13
+ const PROVIDER_PREF_TO_API = {
14
+ claude: 'firstParty',
15
+ openai: 'openai',
16
+ openrouter: 'openrouter',
17
+ ollama: 'ollama',
18
+ 'ollama-cloud': 'ollama-cloud',
19
+ 'gemini-api': 'gemini-api',
20
+ 'gemini-google': 'gemini-google',
21
+ zai: 'zai',
22
+ minimax: 'minimax',
23
+ nvidia: 'nvidia',
24
+ bedrock: 'bedrock',
25
+ vertex: 'vertex',
26
+ foundry: 'foundry',
27
+ firstparty: 'firstParty',
28
+ anthropic: 'firstParty',
29
+ };
30
+ function resolveProviderInput(input) {
31
+ if (!input)
32
+ return null;
33
+ const lower = input.trim().toLowerCase();
34
+ if (PROVIDER_PREF_TO_API[lower])
35
+ return PROVIDER_PREF_TO_API[lower];
36
+ const visible = VISIBLE_PROVIDERS.find(v => v.label.toLowerCase() === lower);
37
+ if (visible)
38
+ return PROVIDER_PREF_TO_API[visible.id] ?? null;
39
+ const partial = VISIBLE_PROVIDERS.find(v => v.label.toLowerCase().includes(lower) || lower.includes(v.id));
40
+ if (partial)
41
+ return PROVIDER_PREF_TO_API[partial.id] ?? null;
42
+ return null;
43
+ }
44
+ function isClaudeFamilyProvider(provider) {
45
+ return provider === 'firstParty' || provider === 'bedrock' || provider === 'vertex' || provider === 'foundry';
46
+ }
47
+ export async function modelListHandler(opts) {
48
+ let provider;
49
+ if (opts.provider) {
50
+ const resolved = resolveProviderInput(opts.provider);
51
+ if (!resolved) {
52
+ process.stderr.write(`Provider desconocido: ${opts.provider}\n`);
53
+ process.exit(2);
54
+ }
55
+ provider = resolved;
56
+ }
57
+ else {
58
+ provider = getAPIProvider();
59
+ }
60
+ let models = [];
61
+ let fetchError = null;
62
+ try {
63
+ const fetched = await fetchProviderModels(provider);
64
+ models = fetched.map(m => ({ id: m.value, label: m.label, description: m.description }));
65
+ }
66
+ catch (err) {
67
+ fetchError = err instanceof Error ? err.message : String(err);
68
+ }
69
+ if (models.length === 0 && isClaudeFamilyProvider(provider)) {
70
+ models = CLAUDE_DEFAULT_MODELS;
71
+ }
72
+ if (opts.json) {
73
+ process.stdout.write(JSON.stringify({ provider, models, error: fetchError }) + '\n');
74
+ }
75
+ else {
76
+ process.stdout.write(`Modelos disponibles (${provider}):\n`);
77
+ if (models.length === 0) {
78
+ process.stdout.write(` (sin modelos detectados)\n`);
79
+ if (fetchError)
80
+ process.stdout.write(` Error: ${fetchError}\n`);
81
+ }
82
+ for (const m of models) {
83
+ process.stdout.write(` ${m.id}${m.label && m.label !== m.id ? ` - ${m.label}` : ''}\n`);
84
+ if (m.description)
85
+ process.stdout.write(` ${m.description}\n`);
86
+ }
87
+ }
88
+ process.exit(0);
89
+ }
@@ -10,7 +10,7 @@ const inputToResponse = {
10
10
  '3': 'good'
11
11
  };
12
12
  export const isValidResponseInput = (input) => RESPONSE_INPUTS.includes(input);
13
- const DEFAULT_MESSAGE = 'How is Claude doing this session? (optional)';
13
+ const DEFAULT_MESSAGE = '¿Cómo está Claude en esta sesión? (opcional)';
14
14
  export function FeedbackSurveyView(t0) {
15
15
  const $ = _c(15);
16
16
  const { onSelect, inputValue, setInputValue, message: t1 } = t0;
package/dist/src/main.js CHANGED
@@ -3752,6 +3752,16 @@ async function run() {
3752
3752
  const { providerListHandler } = await import('./cli/handlers/provider.js');
3753
3753
  await providerListHandler();
3754
3754
  });
3755
+ // context model
3756
+ const modelCmd = program.command('model').description('Inspeccionar modelos disponibles por provider').configureHelp(createSortedHelpConfig());
3757
+ modelCmd.command('list')
3758
+ .description('Listar modelos disponibles del provider activo o de uno especifico')
3759
+ .option('--provider <id>', 'ID del provider (claude, minimax, zai, openai, ...) o label (Claude, MiniMax, ...)')
3760
+ .option('--json', 'Salida en formato JSON')
3761
+ .action(async (opts) => {
3762
+ const { modelListHandler } = await import('./cli/handlers/modelList.js');
3763
+ await modelListHandler(opts);
3764
+ });
3755
3765
  /**
3756
3766
  * Función auxiliar para manejar errores del comando marketplace de forma consistente.
3757
3767
  * Registra el error y sale del proceso con estado 1.
@@ -3822,9 +3832,9 @@ async function run() {
3822
3832
  await setupTokenHandler(root);
3823
3833
  });
3824
3834
  // Comando agents - listar agentes configurados
3825
- program.command('agents').description('Listar agentes configurados').option('--setting-sources <sources>', 'Lista de fuentes de configuración a cargar separadas por comas (user, project, local).').action(async () => {
3835
+ program.command('agents').description('Listar agentes configurados').option('--setting-sources <sources>', 'Lista de fuentes de configuración a cargar separadas por comas (user, project, local).').option('--json', 'Salida en formato JSON estructurado para consumo por herramientas externas').action(async (opts) => {
3826
3836
  const { agentsHandler } = await import('./cli/handlers/agents.js');
3827
- await agentsHandler();
3837
+ await agentsHandler({ json: !!opts.json });
3828
3838
  process.exit(0);
3829
3839
  });
3830
3840
  if (feature('TRANSCRIPT_CLASSIFIER')) {
@@ -116,11 +116,13 @@ export function getAuthTokenSource() {
116
116
  if (process.env.ANTHROPIC_AUTH_TOKEN && !isManagedOAuthContext()) {
117
117
  return { source: 'ANTHROPIC_AUTH_TOKEN', hasToken: true };
118
118
  }
119
- if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
119
+ if (isManagedOAuthContext() && process.env.CLAUDE_CODE_OAUTH_TOKEN) {
120
120
  return { source: 'CLAUDE_CODE_OAUTH_TOKEN', hasToken: true };
121
121
  }
122
122
  // Check for OAuth token from file descriptor (or its CCR disk fallback)
123
- const oauthTokenFromFd = getOAuthTokenFromFileDescriptor();
123
+ const oauthTokenFromFd = isManagedOAuthContext()
124
+ ? getOAuthTokenFromFileDescriptor()
125
+ : null;
124
126
  if (oauthTokenFromFd) {
125
127
  // getOAuthTokenFromFileDescriptor has a disk fallback for CCR subprocesses
126
128
  // that can't inherit the pipe FD. Distinguish by env var presence so the
@@ -154,6 +156,9 @@ export function getAuthTokenSource() {
154
156
  function getProviderOauthStorageKey(provider) {
155
157
  return provider === 'claude' ? 'claudeAiOauth' : 'openAiOauth';
156
158
  }
159
+ function shouldUseLegacyProviderOauthFallback(provider) {
160
+ return provider !== 'claude';
161
+ }
157
162
  export function getStoredProviderOAuthTokens(provider, profileId) {
158
163
  try {
159
164
  const storage = getSecureStorage().read();
@@ -169,6 +174,9 @@ export function getStoredProviderOAuthTokens(provider, profileId) {
169
174
  if (provider === 'gemini-google') {
170
175
  return null;
171
176
  }
177
+ if (!shouldUseLegacyProviderOauthFallback(provider)) {
178
+ return null;
179
+ }
172
180
  const legacy = storage?.[getProviderOauthStorageKey(provider)];
173
181
  return legacy?.accessToken ? legacy : null;
174
182
  }
@@ -187,6 +195,9 @@ export function hasStoredProviderOAuthTokens(provider, profileId) {
187
195
  value !== null &&
188
196
  typeof value.accessToken === 'string' &&
189
197
  value.accessToken.trim());
198
+ if (!shouldUseLegacyProviderOauthFallback(provider)) {
199
+ return Boolean(scoped);
200
+ }
190
201
  return Boolean(scoped || storage?.[getProviderOauthStorageKey(provider)]?.accessToken);
191
202
  }
192
203
  catch {
@@ -1151,7 +1162,6 @@ export function saveOAuthTokensIfNeeded(tokens, explicitProfileId) {
1151
1162
  subscriptionType: tokens.subscriptionType ?? existingOauth?.subscriptionType ?? null,
1152
1163
  rateLimitTier: tokens.rateLimitTier ?? existingOauth?.rateLimitTier ?? null,
1153
1164
  };
1154
- storageData.claudeAiOauth = nextOauth;
1155
1165
  if (profileId) {
1156
1166
  ;
1157
1167
  storageData.providerProfileOauth = {
@@ -1228,7 +1238,7 @@ export function getClaudeAIOAuthTokens() {
1228
1238
  if (isBareMode())
1229
1239
  return null;
1230
1240
  // Check for force-set OAuth token from environment variable
1231
- if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
1241
+ if (isManagedOAuthContext() && process.env.CLAUDE_CODE_OAUTH_TOKEN) {
1232
1242
  // Return an inference-only token (unknown refresh and expiry)
1233
1243
  return {
1234
1244
  accessToken: process.env.CLAUDE_CODE_OAUTH_TOKEN,
@@ -1240,7 +1250,9 @@ export function getClaudeAIOAuthTokens() {
1240
1250
  };
1241
1251
  }
1242
1252
  // Check for OAuth token from file descriptor
1243
- const oauthTokenFromFd = getOAuthTokenFromFileDescriptor();
1253
+ const oauthTokenFromFd = isManagedOAuthContext()
1254
+ ? getOAuthTokenFromFileDescriptor()
1255
+ : null;
1244
1256
  if (oauthTokenFromFd) {
1245
1257
  // Return an inference-only token (unknown refresh and expiry)
1246
1258
  return {
@@ -1669,8 +1681,9 @@ export async function getClaudeAIOAuthTokensAsync() {
1669
1681
  if (isBareMode())
1670
1682
  return null;
1671
1683
  // Env var and FD tokens are sync and don't hit the keychain
1672
- if (process.env.CLAUDE_CODE_OAUTH_TOKEN ||
1673
- getOAuthTokenFromFileDescriptor()) {
1684
+ if (isManagedOAuthContext() &&
1685
+ (process.env.CLAUDE_CODE_OAUTH_TOKEN ||
1686
+ getOAuthTokenFromFileDescriptor())) {
1674
1687
  return getClaudeAIOAuthTokens();
1675
1688
  }
1676
1689
  try {
@@ -6,10 +6,8 @@ import { join } from 'path';
6
6
  // Memoized: 150+ callers, many on hot paths. Keyed off CLAUDE_CONFIG_DIR so
7
7
  // tests that change the env var get a fresh value without explicit cache.clear.
8
8
  export const getContextConfigHomeDir = memoize(() => {
9
- return (process.env.CONTEXT_CONFIG_DIR ??
10
- process.env.CLAUDE_CONFIG_DIR ??
11
- join(homedir(), '.context')).normalize('NFC');
12
- }, () => `${process.env.CONTEXT_CONFIG_DIR ?? ''}:${process.env.CLAUDE_CONFIG_DIR ?? ''}`);
9
+ return (process.env.CONTEXT_CONFIG_DIR ?? join(homedir(), '.context')).normalize('NFC');
10
+ }, () => `${process.env.CONTEXT_CONFIG_DIR ?? ''}`);
13
11
  // Backward-compatible internal alias. New code should prefer
14
12
  // getContextConfigHomeDir(), but keeping this avoids a risky whole-codebase
15
13
  // rename in one migration.
@@ -26,7 +26,7 @@ function hasStoredClaudeAIOAuthToken() {
26
26
  value !== null &&
27
27
  typeof value.accessToken === 'string' &&
28
28
  value.accessToken.trim());
29
- return Boolean(scoped || storage?.claudeAiOauth?.accessToken);
29
+ return Boolean(scoped);
30
30
  }
31
31
  catch {
32
32
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iaforged/context-code",
3
- "version": "1.2.5",
3
+ "version": "1.2.8",
4
4
  "description": "Context Code es un asistente de desarrollo para la terminal. Puede revisar tu proyecto, editar archivos, ejecutar comandos y apoyarte en tareas reales de programacion.",
5
5
  "author": "Context AI",
6
6
  "license": "MIT",