@pencil-agent/nano-pencil 1.11.29 → 1.11.30
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.
|
@@ -5,20 +5,26 @@
|
|
|
5
5
|
* [COVENANT]: Change → update this header
|
|
6
6
|
*/
|
|
7
7
|
import { Container } from "@pencil-agent/tui";
|
|
8
|
-
|
|
8
|
+
export interface ProviderSelectorItem {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
authType: "oauth" | "api_key";
|
|
12
|
+
loggedIn?: boolean;
|
|
13
|
+
}
|
|
9
14
|
/**
|
|
10
|
-
* Component that renders
|
|
15
|
+
* Component that renders a provider selector
|
|
11
16
|
*/
|
|
12
17
|
export declare class OAuthSelectorComponent extends Container {
|
|
13
18
|
private listContainer;
|
|
14
19
|
private allProviders;
|
|
15
20
|
private selectedIndex;
|
|
16
21
|
private mode;
|
|
17
|
-
private authStorage;
|
|
18
22
|
private onSelectCallback;
|
|
19
23
|
private onCancelCallback;
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
private title;
|
|
25
|
+
constructor(mode: "login" | "logout", providers: ProviderSelectorItem[], onSelect: (providerId: string) => void, onCancel: () => void, options?: {
|
|
26
|
+
title?: string;
|
|
27
|
+
});
|
|
22
28
|
private updateList;
|
|
23
29
|
handleInput(keyData: string): void;
|
|
24
30
|
}
|
|
@@ -4,35 +4,33 @@
|
|
|
4
4
|
* [LOCUS]: modes/interactive/components/oauth-selector.ts -
|
|
5
5
|
* [COVENANT]: Change → update this header
|
|
6
6
|
*/
|
|
7
|
-
import { getOAuthProviders } from "@pencil-agent/ai";
|
|
8
7
|
import { Container, getEditorKeybindings, Spacer, TruncatedText } from "@pencil-agent/tui";
|
|
9
8
|
import { theme } from "../theme/theme.js";
|
|
10
9
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
11
10
|
/**
|
|
12
|
-
* Component that renders
|
|
11
|
+
* Component that renders a provider selector
|
|
13
12
|
*/
|
|
14
13
|
export class OAuthSelectorComponent extends Container {
|
|
15
14
|
listContainer;
|
|
16
15
|
allProviders = [];
|
|
17
16
|
selectedIndex = 0;
|
|
18
17
|
mode;
|
|
19
|
-
authStorage;
|
|
20
18
|
onSelectCallback;
|
|
21
19
|
onCancelCallback;
|
|
22
|
-
|
|
20
|
+
title;
|
|
21
|
+
constructor(mode, providers, onSelect, onCancel, options) {
|
|
23
22
|
super();
|
|
24
23
|
this.mode = mode;
|
|
25
|
-
this.
|
|
24
|
+
this.allProviders = providers;
|
|
26
25
|
this.onSelectCallback = onSelect;
|
|
27
26
|
this.onCancelCallback = onCancel;
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
this.title =
|
|
28
|
+
options?.title ?? (mode === "login" ? "Select provider to login:" : "Select provider to logout:");
|
|
30
29
|
// Add top border
|
|
31
30
|
this.addChild(new DynamicBorder());
|
|
32
31
|
this.addChild(new Spacer(1));
|
|
33
32
|
// Add title
|
|
34
|
-
|
|
35
|
-
this.addChild(new TruncatedText(theme.bold(title)));
|
|
33
|
+
this.addChild(new TruncatedText(theme.bold(this.title)));
|
|
36
34
|
this.addChild(new Spacer(1));
|
|
37
35
|
// Create list container
|
|
38
36
|
this.listContainer = new Container();
|
|
@@ -43,9 +41,6 @@ export class OAuthSelectorComponent extends Container {
|
|
|
43
41
|
// Initial render
|
|
44
42
|
this.updateList();
|
|
45
43
|
}
|
|
46
|
-
loadProviders() {
|
|
47
|
-
this.allProviders = getOAuthProviders();
|
|
48
|
-
}
|
|
49
44
|
updateList() {
|
|
50
45
|
this.listContainer.clear();
|
|
51
46
|
for (let i = 0; i < this.allProviders.length; i++) {
|
|
@@ -53,10 +48,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
53
48
|
if (!provider)
|
|
54
49
|
continue;
|
|
55
50
|
const isSelected = i === this.selectedIndex;
|
|
56
|
-
|
|
57
|
-
const credentials = this.authStorage.get(provider.id);
|
|
58
|
-
const isLoggedIn = credentials?.type === "oauth";
|
|
59
|
-
const statusIndicator = isLoggedIn ? theme.fg("success", " ✓ logged in") : "";
|
|
51
|
+
const statusIndicator = provider.loggedIn ? theme.fg("success", " ✓ configured") : "";
|
|
60
52
|
let line = "";
|
|
61
53
|
if (isSelected) {
|
|
62
54
|
const prefix = theme.fg("accent", "→ ");
|
|
@@ -71,7 +63,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
71
63
|
}
|
|
72
64
|
// Show "no providers" if empty
|
|
73
65
|
if (this.allProviders.length === 0) {
|
|
74
|
-
const message = this.mode === "login" ? "No
|
|
66
|
+
const message = this.mode === "login" ? "No providers available" : "No providers logged in. Use /login first.";
|
|
75
67
|
this.listContainer.addChild(new TruncatedText(theme.fg("muted", ` ${message}`), 0, 0));
|
|
76
68
|
}
|
|
77
69
|
}
|
|
@@ -315,6 +315,7 @@ export declare class InteractiveMode {
|
|
|
315
315
|
private showSessionSelector;
|
|
316
316
|
private handleResumeSession;
|
|
317
317
|
private showOAuthSelector;
|
|
318
|
+
private getLoginSelectorProviders;
|
|
318
319
|
private showLoginDialog;
|
|
319
320
|
private handleReloadCommand;
|
|
320
321
|
private handleExportCommand;
|
|
@@ -48,7 +48,7 @@ import { FooterComponent } from "./components/footer.js";
|
|
|
48
48
|
import { appKey, appKeyHint, editorKey, keyHint, rawKeyHint, } from "./components/keybinding-hints.js";
|
|
49
49
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
50
50
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
51
|
-
import { OAuthSelectorComponent } from "./components/oauth-selector.js";
|
|
51
|
+
import { OAuthSelectorComponent, } from "./components/oauth-selector.js";
|
|
52
52
|
import { formatSoulStats } from "./components/soul-stats.js";
|
|
53
53
|
import { ProviderSelectorComponent } from "./components/provider-selector.js";
|
|
54
54
|
import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
|
|
@@ -3647,19 +3647,26 @@ export class InteractiveMode {
|
|
|
3647
3647
|
this.showStatus("Resumed session");
|
|
3648
3648
|
}
|
|
3649
3649
|
async showOAuthSelector(mode) {
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
}
|
|
3650
|
+
const providers = this.getLoginSelectorProviders(mode);
|
|
3651
|
+
if (providers.length === 0) {
|
|
3652
|
+
this.showStatus(mode === "login"
|
|
3653
|
+
? "No providers available."
|
|
3654
|
+
: "No providers logged in. Use /login first.");
|
|
3655
|
+
return;
|
|
3657
3656
|
}
|
|
3658
3657
|
this.showSelector((done) => {
|
|
3659
|
-
const selector = new OAuthSelectorComponent(mode,
|
|
3658
|
+
const selector = new OAuthSelectorComponent(mode, providers, async (providerId) => {
|
|
3660
3659
|
done();
|
|
3661
3660
|
if (mode === "login") {
|
|
3662
|
-
|
|
3661
|
+
const oauthProvider = getOAuthProviders().find((p) => p.id === providerId);
|
|
3662
|
+
if (oauthProvider) {
|
|
3663
|
+
await this.showLoginDialog(providerId);
|
|
3664
|
+
}
|
|
3665
|
+
else {
|
|
3666
|
+
await this.promptForProviderApiKey(providerId, {
|
|
3667
|
+
title: `Set API key for ${providerId}`,
|
|
3668
|
+
});
|
|
3669
|
+
}
|
|
3663
3670
|
}
|
|
3664
3671
|
else {
|
|
3665
3672
|
// Logout flow
|
|
@@ -3678,10 +3685,47 @@ export class InteractiveMode {
|
|
|
3678
3685
|
}, () => {
|
|
3679
3686
|
done();
|
|
3680
3687
|
this.ui.requestRender();
|
|
3688
|
+
}, {
|
|
3689
|
+
title: mode === "login"
|
|
3690
|
+
? "Select provider to login or configure:"
|
|
3691
|
+
: "Select provider to logout:",
|
|
3681
3692
|
});
|
|
3682
3693
|
return { component: selector, focus: selector };
|
|
3683
3694
|
});
|
|
3684
3695
|
}
|
|
3696
|
+
getLoginSelectorProviders(mode) {
|
|
3697
|
+
const oauthProviders = getOAuthProviders().map((provider) => ({
|
|
3698
|
+
id: provider.id,
|
|
3699
|
+
name: provider.name,
|
|
3700
|
+
authType: "oauth",
|
|
3701
|
+
loggedIn: this.session.modelRegistry.authStorage.get(provider.id)?.type ===
|
|
3702
|
+
"oauth",
|
|
3703
|
+
}));
|
|
3704
|
+
if (mode === "logout") {
|
|
3705
|
+
return oauthProviders.filter((provider) => provider.loggedIn);
|
|
3706
|
+
}
|
|
3707
|
+
const items = [...oauthProviders];
|
|
3708
|
+
const providerIds = new Set(items.map((provider) => provider.id));
|
|
3709
|
+
const apiKeyProviders = [
|
|
3710
|
+
{ id: "openrouter", name: "OpenRouter" },
|
|
3711
|
+
];
|
|
3712
|
+
for (const provider of apiKeyProviders) {
|
|
3713
|
+
if (providerIds.has(provider.id))
|
|
3714
|
+
continue;
|
|
3715
|
+
const hasModels = this.session.modelRegistry
|
|
3716
|
+
.getAll()
|
|
3717
|
+
.some((model) => model.provider === provider.id);
|
|
3718
|
+
if (!hasModels)
|
|
3719
|
+
continue;
|
|
3720
|
+
items.push({
|
|
3721
|
+
id: provider.id,
|
|
3722
|
+
name: provider.name,
|
|
3723
|
+
authType: "api_key",
|
|
3724
|
+
loggedIn: !!this.getStoredApiKey(provider.id),
|
|
3725
|
+
});
|
|
3726
|
+
}
|
|
3727
|
+
return items;
|
|
3728
|
+
}
|
|
3685
3729
|
async showLoginDialog(providerId) {
|
|
3686
3730
|
const providerInfo = getOAuthProviders().find((p) => p.id === providerId);
|
|
3687
3731
|
const providerName = providerInfo?.name || providerId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pencil-agent/nano-pencil",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.30",
|
|
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": {
|