@pencil-agent/nano-pencil 1.11.27 → 1.11.28

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.
@@ -272,6 +272,7 @@ export class ModelSelectorComponent extends Container {
272
272
  "dashscope-coding": "DashScope API key (sk-sp-...)",
273
273
  "qianfan-coding": "Qianfan API key",
274
274
  "ark-coding": "Ark API key",
275
+ openrouter: "OpenRouter API key",
275
276
  };
276
277
  const prompt = providerHints[model.provider] ?? `${model.provider} API key`;
277
278
  const key = await promptForApiKey({ prompt: `Enter ${prompt}` });
@@ -293,6 +293,10 @@ export declare class InteractiveMode {
293
293
  * Handle /apikey command - allow user to update API key for current provider
294
294
  */
295
295
  private handleApiKeyCommand;
296
+ private getStoredApiKey;
297
+ private resolveProviderId;
298
+ private promptForProviderApiKey;
299
+ private handleLoginCommand;
296
300
  private handleProviderCredentialsCommand;
297
301
  private ensureProviderConfiguredForSelection;
298
302
  private configureCustomProtocolProvider;
@@ -1760,8 +1760,8 @@ export class InteractiveMode {
1760
1760
  this.editor.setText("");
1761
1761
  return;
1762
1762
  }
1763
- if (text === "/login") {
1764
- this.showOAuthSelector("login");
1763
+ if (text === "/login" || text.startsWith("/login ")) {
1764
+ await this.handleLoginCommand(text);
1765
1765
  this.editor.setText("");
1766
1766
  return;
1767
1767
  }
@@ -3079,6 +3079,66 @@ export class InteractiveMode {
3079
3079
  async handleApiKeyCommand() {
3080
3080
  await this.handleProviderCredentialsCommand();
3081
3081
  }
3082
+ getStoredApiKey(provider) {
3083
+ const credential = this.session.modelRegistry.authStorage.get(provider);
3084
+ return credential?.type === "api_key" ? credential.key : undefined;
3085
+ }
3086
+ resolveProviderId(input) {
3087
+ const normalized = input.trim().toLowerCase();
3088
+ if (!normalized)
3089
+ return undefined;
3090
+ const providerMap = new Map();
3091
+ for (const model of this.session.modelRegistry.getAll()) {
3092
+ providerMap.set(model.provider.toLowerCase(), model.provider);
3093
+ }
3094
+ for (const provider of getOAuthProviders()) {
3095
+ providerMap.set(provider.id.toLowerCase(), provider.id);
3096
+ }
3097
+ return providerMap.get(normalized);
3098
+ }
3099
+ async promptForProviderApiKey(provider, options = {}) {
3100
+ const currentApiKey = this.getStoredApiKey(provider);
3101
+ const title = options.title ?? `Update API key for ${provider}`;
3102
+ const apiKey = await this.showExtensionInput(title, "API key", {
3103
+ initialValue: currentApiKey,
3104
+ });
3105
+ if (apiKey === undefined) {
3106
+ this.showStatus("Configuration cancelled");
3107
+ return false;
3108
+ }
3109
+ const trimmedApiKey = apiKey.trim();
3110
+ if (!trimmedApiKey) {
3111
+ this.showStatus("Configuration cancelled");
3112
+ return false;
3113
+ }
3114
+ this.session.modelRegistry.authStorage.set(provider, {
3115
+ type: "api_key",
3116
+ key: trimmedApiKey,
3117
+ });
3118
+ this.session.modelRegistry.refresh();
3119
+ this.showStatus(`Updated API key for ${provider}`);
3120
+ return true;
3121
+ }
3122
+ async handleLoginCommand(text) {
3123
+ const rawProvider = text.startsWith("/login ") ? text.slice(7).trim() : "";
3124
+ if (!rawProvider) {
3125
+ this.showOAuthSelector("login");
3126
+ return;
3127
+ }
3128
+ const providerId = this.resolveProviderId(rawProvider);
3129
+ if (!providerId) {
3130
+ this.showError(`Unknown provider: ${rawProvider}`);
3131
+ return;
3132
+ }
3133
+ const oauthProvider = getOAuthProviders().find((provider) => provider.id === providerId);
3134
+ if (oauthProvider) {
3135
+ await this.showLoginDialog(oauthProvider.id);
3136
+ return;
3137
+ }
3138
+ await this.promptForProviderApiKey(providerId, {
3139
+ title: `Set API key for ${providerId}`,
3140
+ });
3141
+ }
3082
3142
  async handleProviderCredentialsCommand() {
3083
3143
  const currentModel = this.session.model;
3084
3144
  if (!currentModel) {
@@ -3096,22 +3156,7 @@ export class InteractiveMode {
3096
3156
  }
3097
3157
  return;
3098
3158
  }
3099
- const apiKey = await this.showExtensionInput(`Update API key for ${provider}`, "API key");
3100
- if (apiKey === undefined) {
3101
- this.showStatus("Configuration cancelled");
3102
- return;
3103
- }
3104
- const trimmedApiKey = apiKey.trim();
3105
- if (!trimmedApiKey) {
3106
- this.showStatus("Configuration cancelled");
3107
- return;
3108
- }
3109
- this.session.modelRegistry.authStorage.set(provider, {
3110
- type: "api_key",
3111
- key: trimmedApiKey,
3112
- });
3113
- this.session.modelRegistry.refresh();
3114
- this.showStatus(`Updated API key for ${provider}`);
3159
+ await this.promptForProviderApiKey(provider);
3115
3160
  }
3116
3161
  catch (error) {
3117
3162
  this.showError(error instanceof Error ? error.message : String(error));
@@ -3131,6 +3176,7 @@ export class InteractiveMode {
3131
3176
  definition.defaultBaseUrl;
3132
3177
  const currentModelName = getCustomProtocolProviderModelName(modelsPath, provider) ??
3133
3178
  "custom-model";
3179
+ const currentApiKey = this.getStoredApiKey(provider) ?? "";
3134
3180
  const hasExistingApiKey = authStorage.has(provider);
3135
3181
  if (!options.force &&
3136
3182
  hasExistingApiKey &&
@@ -3149,7 +3195,7 @@ export class InteractiveMode {
3149
3195
  }
3150
3196
  const apiKeyInput = await this.showExtensionInput(`${definition.label} API key`, hasExistingApiKey && options.force
3151
3197
  ? "Leave empty to keep the current API key"
3152
- : "API key");
3198
+ : "API key", { initialValue: currentApiKey });
3153
3199
  if (apiKeyInput === undefined) {
3154
3200
  return false;
3155
3201
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pencil-agent/nano-pencil",
3
- "version": "1.11.27",
3
+ "version": "1.11.28",
4
4
  "description": "CLI writing agent with read, bash, edit, write tools and session management. Based on pi; supports DashScope Coding Plan. Soul enabled by default for AI personality evolution.",
5
5
  "type": "module",
6
6
  "bin": {