@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.
- package/dist/src/cli/handlers/agents.js +33 -1
- package/dist/src/cli/handlers/auth.js +7 -2
- package/dist/src/cli/handlers/modelList.js +89 -0
- package/dist/src/components/FeedbackSurvey/FeedbackSurveyView.js +1 -1
- package/dist/src/main.js +12 -2
- package/dist/src/utils/auth.js +20 -7
- package/dist/src/utils/envUtils.js +2 -4
- package/dist/src/utils/model/providers.js +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
61
|
-
|
|
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 = '
|
|
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')) {
|
package/dist/src/utils/auth.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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 (
|
|
1673
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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",
|