@pellux/goodvibes-tui 0.20.3 → 0.22.0
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/CHANGELOG.md +50 -0
- package/README.md +23 -2
- package/docs/foundation-artifacts/operator-contract.json +78 -1
- package/package.json +4 -2
- package/src/audio/spoken-turn-controller.ts +31 -1
- package/src/audio/spoken-turn-wiring.ts +26 -4
- package/src/cli/bundle-command.ts +1 -1
- package/src/cli/completions/generate.ts +658 -0
- package/src/cli/config-overrides.ts +68 -0
- package/src/cli/entrypoint.ts +6 -0
- package/src/cli/help.ts +4 -2
- package/src/cli/management-commands.ts +1 -1
- package/src/cli/management.ts +1 -8
- package/src/cli/parser.ts +31 -18
- package/src/cli/service-command.ts +1 -1
- package/src/cli/surface-command.ts +1 -1
- package/src/cli/tui-startup.ts +72 -10
- package/src/cli/types.ts +14 -3
- package/src/cli-flags.ts +1 -0
- package/src/config/atomic-write.ts +70 -0
- package/src/config/goodvibes-home-audit.ts +2 -0
- package/src/config/read-versioned.ts +115 -0
- package/src/core/context-auto-compact.ts +77 -0
- package/src/core/conversation-rendering.ts +49 -15
- package/src/core/conversation.ts +101 -16
- package/src/core/format-user-error.ts +192 -0
- package/src/core/stream-event-wiring.ts +144 -0
- package/src/core/stream-stall-watchdog.ts +103 -0
- package/src/core/system-message-router.ts +5 -1
- package/src/core/turn-event-wiring.ts +124 -0
- package/src/daemon/cli.ts +5 -0
- package/src/export/cost-utils.ts +71 -0
- package/src/export/gist-uploader.ts +136 -0
- package/src/input/command-registry.ts +32 -1
- package/src/input/commands/control-room-runtime.ts +10 -10
- package/src/input/commands/experience-runtime.ts +5 -4
- package/src/input/commands/knowledge.ts +1 -1
- package/src/input/commands/local-auth-runtime.ts +27 -5
- package/src/input/commands/local-setup.ts +4 -6
- package/src/input/commands/memory-product-runtime.ts +8 -6
- package/src/input/commands/operator-panel-runtime.ts +1 -1
- package/src/input/commands/operator-runtime.ts +3 -10
- package/src/input/commands/{integration-runtime.ts → plugin-runtime.ts} +1 -1
- package/src/input/commands/provider.ts +57 -3
- package/src/input/commands/recall-review.ts +26 -2
- package/src/input/commands/services-runtime.ts +2 -2
- package/src/input/commands/session-workflow.ts +8 -16
- package/src/input/commands/session.ts +70 -20
- package/src/input/commands/share-runtime.ts +99 -12
- package/src/input/commands/tts-runtime.ts +30 -4
- package/src/input/commands.ts +2 -4
- package/src/input/delete-key-policy.ts +46 -0
- package/src/input/feed-context-factory.ts +2 -0
- package/src/input/handler-feed.ts +3 -0
- package/src/input/handler-interactions.ts +2 -15
- package/src/input/handler-modal-routes.ts +128 -12
- package/src/input/handler-modal-token-routes.ts +22 -5
- package/src/input/handler-onboarding-cloudflare.ts +1 -1
- package/src/input/handler-onboarding.ts +73 -69
- package/src/input/handler-types.ts +163 -0
- package/src/input/handler.ts +6 -2
- package/src/input/input-history.ts +76 -6
- package/src/input/model-picker-filter.ts +265 -0
- package/src/input/model-picker-items.ts +208 -0
- package/src/input/model-picker.ts +92 -325
- package/src/input/onboarding/handler-onboarding-routes.ts +7 -2
- package/src/input/onboarding/onboarding-verification-helpers.ts +76 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +14 -4
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +16 -2
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +8 -8
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +2 -29
- package/src/input/onboarding/onboarding-wizard-rules.ts +28 -28
- package/src/input/onboarding/onboarding-wizard-state.ts +20 -20
- package/src/input/onboarding/onboarding-wizard-steps.ts +24 -25
- package/src/input/onboarding/onboarding-wizard-types.ts +145 -3
- package/src/input/onboarding/onboarding-wizard-validation.ts +77 -0
- package/src/input/onboarding/onboarding-wizard.ts +3 -3
- package/src/input/settings-modal-behavior.ts +5 -0
- package/src/input/settings-modal-data.ts +378 -0
- package/src/input/settings-modal-mutations.ts +157 -0
- package/src/input/settings-modal-reset.ts +154 -0
- package/src/input/settings-modal.ts +236 -232
- package/src/main.ts +93 -85
- package/src/panels/agent-inspector-panel.ts +120 -18
- package/src/panels/agent-inspector-shared.ts +29 -0
- package/src/panels/builtin/agent.ts +4 -1
- package/src/panels/builtin/development.ts +5 -1
- package/src/panels/builtin/knowledge.ts +14 -13
- package/src/panels/builtin/operations.ts +22 -1
- package/src/panels/builtin/shared.ts +7 -0
- package/src/panels/cockpit-panel.ts +123 -3
- package/src/panels/cockpit-read-model.ts +232 -0
- package/src/panels/confirm-state.ts +27 -12
- package/src/panels/cost-tracker-panel.ts +23 -67
- package/src/panels/eval-panel.ts +10 -9
- package/src/panels/index.ts +1 -1
- package/src/panels/knowledge-graph-panel.ts +84 -0
- package/src/panels/local-auth-panel.ts +124 -4
- package/src/panels/memory-panel.ts +370 -40
- package/src/panels/project-planning-panel.ts +42 -4
- package/src/panels/search-focus.ts +11 -5
- package/src/panels/session-maintenance.ts +66 -15
- package/src/panels/subscription-panel.ts +33 -25
- package/src/panels/types.ts +28 -1
- package/src/panels/wrfc-panel.ts +224 -41
- package/src/renderer/agent-detail-modal.ts +118 -13
- package/src/renderer/code-block.ts +10 -2
- package/src/renderer/compositor.ts +18 -4
- package/src/renderer/context-inspector.ts +1 -5
- package/src/renderer/context-status-hint.ts +54 -0
- package/src/renderer/diff.ts +94 -21
- package/src/renderer/markdown.ts +29 -13
- package/src/renderer/settings-modal-helpers.ts +1 -1
- package/src/renderer/settings-modal.ts +90 -10
- package/src/renderer/shell-surface.ts +10 -0
- package/src/renderer/syntax-highlighter.ts +10 -3
- package/src/renderer/term-caps.ts +318 -0
- package/src/renderer/theme.ts +158 -0
- package/src/renderer/tool-call.ts +12 -2
- package/src/renderer/ui-factory.ts +50 -6
- package/src/runtime/bootstrap-command-context.ts +1 -0
- package/src/runtime/bootstrap-command-parts.ts +18 -0
- package/src/runtime/bootstrap-core.ts +145 -13
- package/src/runtime/bootstrap-shell.ts +11 -0
- package/src/runtime/bootstrap.ts +9 -0
- package/src/runtime/onboarding/apply.ts +4 -6
- package/src/runtime/onboarding/index.ts +1 -0
- package/src/runtime/onboarding/markers.ts +42 -49
- package/src/runtime/onboarding/progress.ts +148 -0
- package/src/runtime/onboarding/state.ts +133 -55
- package/src/runtime/onboarding/types.ts +20 -0
- package/src/runtime/services.ts +27 -1
- package/src/runtime/wrfc-persistence.ts +237 -0
- package/src/shell/blocking-input.ts +20 -5
- package/src/tools/wrfc-agent-guard.ts +64 -3
- package/src/utils/format-elapsed.ts +30 -0
- package/src/utils/terminal-width.ts +45 -0
- package/src/version.ts +1 -1
- package/src/work-plans/work-plan-store.ts +4 -6
- package/src/panels/knowledge-panel.ts +0 -345
- package/src/planning/project-planning-coordinator.ts +0 -543
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session maintenance types and local evaluator.
|
|
3
|
+
*
|
|
4
|
+
* The canonical evaluator is the SDK version exported from @/runtime/index.ts
|
|
5
|
+
* (via operations.evaluateSessionMaintenance), which reads from configManager.
|
|
6
|
+
*
|
|
7
|
+
* This module provides:
|
|
8
|
+
* - The shared type surface used across TUI panels.
|
|
9
|
+
* - A thin local evaluator kept in sync with the SDK signature so panel code
|
|
10
|
+
* that passes configManager has a coherent call site.
|
|
11
|
+
*/
|
|
12
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
13
|
+
|
|
1
14
|
export type PanelGuidanceMode = 'off' | 'minimal' | 'guided';
|
|
2
15
|
export type PanelSessionMaintenanceLevel = 'stable' | 'watch' | 'suggest-compact' | 'compacting' | 'needs-repair' | 'unknown';
|
|
3
16
|
|
|
@@ -9,9 +22,12 @@ export interface PanelSessionMaintenanceSession {
|
|
|
9
22
|
readonly lineage?: readonly PanelSessionMaintenanceLineageEntry[];
|
|
10
23
|
readonly lastCompactedAt?: number;
|
|
11
24
|
readonly compactionMessageCount?: number;
|
|
25
|
+
readonly compactionState?: string;
|
|
12
26
|
}
|
|
13
27
|
|
|
14
28
|
export interface PanelSessionMaintenanceInput {
|
|
29
|
+
/** ConfigManager used to read behavior.autoCompactThreshold and related keys. */
|
|
30
|
+
readonly configManager: Pick<ConfigManager, 'get'>;
|
|
15
31
|
readonly currentTokens: number;
|
|
16
32
|
readonly contextWindow: number;
|
|
17
33
|
readonly messageCount?: number;
|
|
@@ -27,7 +43,15 @@ export interface PanelSessionMaintenanceStatus {
|
|
|
27
43
|
readonly guidanceMode: PanelGuidanceMode;
|
|
28
44
|
readonly usagePct: number;
|
|
29
45
|
readonly remainingTokens: number;
|
|
46
|
+
/**
|
|
47
|
+
* Compact threshold as a percent integer.
|
|
48
|
+
* SDK schema range is [10, 100]; default is 80.
|
|
49
|
+
*/
|
|
30
50
|
readonly thresholdPct: number;
|
|
51
|
+
/**
|
|
52
|
+
* True when autoCompactThreshold is in its valid range (>0).
|
|
53
|
+
* With SDK default (80), auto-compact is active unless explicitly lowered below 10.
|
|
54
|
+
*/
|
|
31
55
|
readonly autoCompactEnabled: boolean;
|
|
32
56
|
readonly sessionMemoryCount: number;
|
|
33
57
|
readonly compactionCount: number;
|
|
@@ -35,19 +59,33 @@ export interface PanelSessionMaintenanceStatus {
|
|
|
35
59
|
readonly compactRecommended: boolean;
|
|
36
60
|
}
|
|
37
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Evaluate session maintenance from config-driven thresholds.
|
|
64
|
+
*
|
|
65
|
+
* behavior.autoCompactThreshold (percent integer, SDK schema range [10, 100], default 80):
|
|
66
|
+
* - [10, 100] → threshold at that percent; autoCompactEnabled = true.
|
|
67
|
+
* - 0 (defensive fallback for null/missing config only; not a valid schema value).
|
|
68
|
+
*
|
|
69
|
+
* NOTE: The SDK's evaluateSessionMaintenance (from @/runtime/index.ts) is the
|
|
70
|
+
* canonical implementation used in production. This local version exists so
|
|
71
|
+
* panel tests can import types without crossing the SDK boundary.
|
|
72
|
+
*/
|
|
38
73
|
export function evaluateSessionMaintenance(input: PanelSessionMaintenanceInput): PanelSessionMaintenanceStatus {
|
|
39
|
-
const guidanceMode: PanelGuidanceMode = 'minimal';
|
|
40
|
-
const
|
|
41
|
-
const
|
|
74
|
+
const guidanceMode: PanelGuidanceMode = (input.configManager.get('behavior.guidanceMode') as PanelGuidanceMode | undefined) ?? 'minimal';
|
|
75
|
+
const rawThreshold = Number(input.configManager.get('behavior.autoCompactThreshold') ?? 0);
|
|
76
|
+
const thresholdPct = Math.max(0, Number.isFinite(rawThreshold) ? rawThreshold : 0);
|
|
77
|
+
const autoCompactEnabled = thresholdPct > 0;
|
|
78
|
+
|
|
42
79
|
const usagePct = input.contextWindow > 0 ? Math.min(100, Math.round((Math.max(0, input.currentTokens) / input.contextWindow) * 100)) : 0;
|
|
43
80
|
const remainingTokens = Math.max(0, input.contextWindow - input.currentTokens);
|
|
44
81
|
const sessionMemoryCount = Math.max(0, input.sessionMemoryCount ?? 0);
|
|
45
82
|
const compactionCount = Math.max(0, input.session?.lineage?.filter((entry) => entry.branchReason === 'compaction').length ?? 0);
|
|
46
83
|
const lastCompactedAt = input.session?.lastCompactedAt;
|
|
47
84
|
const messageCount = Math.max(0, input.messageCount ?? 0);
|
|
48
|
-
const staleByMessageGrowth =
|
|
85
|
+
const staleByMessageGrowth = (input.session?.compactionMessageCount ?? 0) > 0
|
|
49
86
|
? messageCount - (input.session?.compactionMessageCount ?? 0) >= 12
|
|
50
87
|
: messageCount >= 24;
|
|
88
|
+
|
|
51
89
|
if (input.contextWindow <= 0) {
|
|
52
90
|
return {
|
|
53
91
|
level: 'unknown',
|
|
@@ -66,32 +104,45 @@ export function evaluateSessionMaintenance(input: PanelSessionMaintenanceInput):
|
|
|
66
104
|
};
|
|
67
105
|
}
|
|
68
106
|
|
|
107
|
+
if (input.session?.compactionState === 'failed') {
|
|
108
|
+
return {
|
|
109
|
+
level: 'needs-repair',
|
|
110
|
+
summary: 'Compaction needs operator repair.',
|
|
111
|
+
reasons: ['Compaction failed and the session may need manual recovery.'],
|
|
112
|
+
nextSteps: ['/compact', '/health review'],
|
|
113
|
+
guidanceMode,
|
|
114
|
+
usagePct,
|
|
115
|
+
remainingTokens,
|
|
116
|
+
thresholdPct,
|
|
117
|
+
autoCompactEnabled,
|
|
118
|
+
sessionMemoryCount,
|
|
119
|
+
compactionCount,
|
|
120
|
+
lastCompactedAt,
|
|
121
|
+
compactRecommended: true,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
69
125
|
const reasons: string[] = [];
|
|
70
126
|
const nextSteps: string[] = [];
|
|
71
127
|
let summary = 'Session maintenance is stable.';
|
|
72
128
|
let compactRecommended = false;
|
|
73
129
|
let level: PanelSessionMaintenanceLevel = 'stable';
|
|
74
130
|
|
|
75
|
-
|
|
76
|
-
|
|
131
|
+
const atThreshold = autoCompactEnabled ? usagePct >= thresholdPct : usagePct >= 80;
|
|
132
|
+
if (atThreshold || remainingTokens <= 15_000) {
|
|
133
|
+
level = 'suggest-compact';
|
|
77
134
|
summary = `Compact now to recover context headroom (${usagePct}% used).`;
|
|
78
135
|
reasons.push(`Context pressure is high at ${usagePct}% usage.`);
|
|
79
136
|
nextSteps.push('/compact', '/panel tokens');
|
|
80
137
|
compactRecommended = true;
|
|
81
|
-
} else if (usagePct >= thresholdPct
|
|
82
|
-
level = 'suggest-compact';
|
|
83
|
-
summary = `Watch context growth (${usagePct}% used).`;
|
|
84
|
-
reasons.push(`Context pressure is climbing at ${usagePct}% usage.`);
|
|
85
|
-
nextSteps.push('/panel tokens');
|
|
86
|
-
compactRecommended = true;
|
|
87
|
-
} else if (usagePct >= 70 || staleByMessageGrowth) {
|
|
138
|
+
} else if (usagePct >= Math.max(70, autoCompactEnabled ? thresholdPct - 10 : 70) || staleByMessageGrowth) {
|
|
88
139
|
level = 'watch';
|
|
89
140
|
summary = staleByMessageGrowth
|
|
90
141
|
? `Conversation has grown ${messageCount.toLocaleString()} messages since the last maintenance checkpoint.`
|
|
91
142
|
: `Watch context growth (${usagePct}% used, threshold ${thresholdPct}%).`;
|
|
92
143
|
reasons.push(staleByMessageGrowth
|
|
93
144
|
? `Conversation has grown ${messageCount.toLocaleString()} messages since the last maintenance checkpoint.`
|
|
94
|
-
: `Context usage is climbing toward the ${thresholdPct}% maintenance
|
|
145
|
+
: `Context usage is climbing toward the ${thresholdPct > 0 ? `${thresholdPct}% auto-compact threshold` : 'maintenance band'}.`);
|
|
95
146
|
nextSteps.push('/panel tokens');
|
|
96
147
|
} else {
|
|
97
148
|
reasons.push('Context pressure is currently within the stable operating band.');
|
|
@@ -104,7 +155,7 @@ export function evaluateSessionMaintenance(input: PanelSessionMaintenanceInput):
|
|
|
104
155
|
reasons.push(`Last compaction ran ${lastCompactedAt ? new Date(lastCompactedAt).toISOString() : 'recently'}.`);
|
|
105
156
|
}
|
|
106
157
|
if (!autoCompactEnabled) {
|
|
107
|
-
reasons.push('Auto-
|
|
158
|
+
reasons.push('Auto-compaction is disabled; maintenance stays fully manual.');
|
|
108
159
|
}
|
|
109
160
|
|
|
110
161
|
return {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { Line } from '../types/grid.ts';
|
|
2
2
|
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
4
|
+
import type { KeyName } from './types.ts';
|
|
4
5
|
import type { ProviderSubscription, PendingSubscriptionLogin } from '@pellux/goodvibes-sdk/platform/config';
|
|
5
6
|
import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
|
|
7
|
+
import { type ConfirmState, handleConfirmInput } from './confirm-state.ts';
|
|
6
8
|
import type { ServiceInspectionQuery, SubscriptionAccessQuery } from '../runtime/ui-service-queries.ts';
|
|
7
9
|
import {
|
|
8
10
|
buildEmptyState,
|
|
@@ -57,7 +59,8 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
|
|
|
57
59
|
private readonly serviceRegistry: Pick<ServiceInspectionQuery, 'getAll'>;
|
|
58
60
|
private readonly subscriptionManager: SubscriptionAccessQuery;
|
|
59
61
|
private rows: SubscriptionRow[] = [];
|
|
60
|
-
|
|
62
|
+
/** Pending logout confirmation — uses project-standard ConfirmState contract. */
|
|
63
|
+
private confirm: ConfirmState<string> | null = null;
|
|
61
64
|
|
|
62
65
|
public constructor(
|
|
63
66
|
serviceRegistry: Pick<ServiceInspectionQuery, 'getAll'>,
|
|
@@ -98,42 +101,47 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
|
|
|
98
101
|
], C, { selected, selectedBg: C.selectedBg });
|
|
99
102
|
}
|
|
100
103
|
|
|
101
|
-
public handleInput(key:
|
|
104
|
+
public handleInput(key: KeyName): boolean {
|
|
105
|
+
// Project-standard confirm contract: Enter/y confirm; n/Esc cancel; other absorbed.
|
|
106
|
+
const confirmResult = handleConfirmInput(this.confirm, key);
|
|
107
|
+
if (confirmResult === 'confirmed') {
|
|
108
|
+
const provider = this.confirm!.subject;
|
|
109
|
+
this.confirm = null;
|
|
110
|
+
this.subscriptionManager.logout(provider);
|
|
111
|
+
this.refresh();
|
|
112
|
+
this.markDirty();
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
if (confirmResult === 'cancelled') {
|
|
116
|
+
this.confirm = null;
|
|
117
|
+
this.markDirty();
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
if (confirmResult === 'absorbed') return true;
|
|
121
|
+
|
|
102
122
|
if (this.rows.length === 0) return false;
|
|
103
123
|
const selected = this.rows[this.selectedIndex] ?? null;
|
|
104
|
-
if (key === '
|
|
124
|
+
if (key === 'up' || key === 'k') {
|
|
105
125
|
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
106
|
-
this.
|
|
126
|
+
this.confirm = null;
|
|
107
127
|
this.markDirty();
|
|
108
128
|
return true;
|
|
109
129
|
}
|
|
110
|
-
if (key === '
|
|
130
|
+
if (key === 'down' || key === 'j') {
|
|
111
131
|
this.selectedIndex = Math.min(this.rows.length - 1, this.selectedIndex + 1);
|
|
112
|
-
this.
|
|
132
|
+
this.confirm = null;
|
|
113
133
|
this.markDirty();
|
|
114
134
|
return true;
|
|
115
135
|
}
|
|
116
|
-
if (key === 'enter' || key === '
|
|
136
|
+
if (key === 'enter' || key === 'return') {
|
|
117
137
|
if (!selected?.subscription) return false;
|
|
118
|
-
|
|
119
|
-
this.logoutConfirmationTarget = selected.provider;
|
|
120
|
-
this.markDirty();
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
this.subscriptionManager.logout(selected.provider);
|
|
124
|
-
this.logoutConfirmationTarget = null;
|
|
125
|
-
this.refresh();
|
|
126
|
-
this.markDirty();
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
if ((key === 'n' || key === 'escape') && this.logoutConfirmationTarget) {
|
|
130
|
-
this.logoutConfirmationTarget = null;
|
|
138
|
+
this.confirm = { subject: selected.provider, label: selected.provider };
|
|
131
139
|
this.markDirty();
|
|
132
140
|
return true;
|
|
133
141
|
}
|
|
134
142
|
if (key === 'r') {
|
|
135
143
|
this.refresh();
|
|
136
|
-
this.
|
|
144
|
+
this.confirm = null;
|
|
137
145
|
this.markDirty();
|
|
138
146
|
return true;
|
|
139
147
|
}
|
|
@@ -206,7 +214,7 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
|
|
|
206
214
|
sections: [{ lines: [...summaryLines, ...emptyLines] }],
|
|
207
215
|
footerLines: [
|
|
208
216
|
buildGuidanceLine(width, '/subscription login <provider> start', 'start browser-based provider login from the packaged subscription surface', C),
|
|
209
|
-
buildPanelLine(width, [[' Up/Down move Enter
|
|
217
|
+
buildPanelLine(width, [[' Up/Down move Enter sign out selected provider y/Esc confirm/cancel r refresh', C.dim]]),
|
|
210
218
|
],
|
|
211
219
|
palette: C,
|
|
212
220
|
});
|
|
@@ -236,8 +244,8 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
|
|
|
236
244
|
: 'Stored for subscription-backed flows. Ambient API-key resolution remains unchanged.'}`,
|
|
237
245
|
C.dim,
|
|
238
246
|
]]));
|
|
239
|
-
if (this.
|
|
240
|
-
detailRows.push(buildPanelLine(width, [[` Press
|
|
247
|
+
if (this.confirm?.subject === selectedRow.provider) {
|
|
248
|
+
detailRows.push(buildPanelLine(width, [[` Sign out ${selectedRow.provider}? Press y or Enter to confirm, n or Esc to cancel.`, C.warn]]));
|
|
241
249
|
}
|
|
242
250
|
} else if (selectedRow.pending) {
|
|
243
251
|
detailRows.push(buildPanelLine(width, [[' Login is pending. Finish with /subscription login <provider> finish <code>.', C.warn]]));
|
|
@@ -256,7 +264,7 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
|
|
|
256
264
|
footer: [
|
|
257
265
|
...detailRows,
|
|
258
266
|
buildGuidanceLine(width, '/subscription login <provider> start', 'start browser-based provider login from the packaged subscription surface', C),
|
|
259
|
-
buildPanelLine(width, [[' Up/Down move Enter
|
|
267
|
+
buildPanelLine(width, [[' Up/Down move Enter sign out selected provider y/Esc confirm/cancel r refresh', C.dim]]),
|
|
260
268
|
],
|
|
261
269
|
});
|
|
262
270
|
}
|
package/src/panels/types.ts
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import type { Line } from '../types/grid.ts';
|
|
2
2
|
import type { ComponentResourceContract, ComponentHealthState } from '../runtime/perf/panel-contracts.ts';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Named logical key identifiers emitted by the input tokenizer.
|
|
6
|
+
* These are the ONLY key names that will appear in `handleInput` calls;
|
|
7
|
+
* the tokenizer never emits DOM/browser-style names like 'ArrowUp' or 'Enter'.
|
|
8
|
+
*
|
|
9
|
+
* Printable single-character input is passed through as-is; the `string & {}`
|
|
10
|
+
* fallback preserves that handling while making named-key completions discoverable
|
|
11
|
+
* in editors and keeping non-null single-character values compatible.
|
|
12
|
+
*/
|
|
13
|
+
export type NamedKey =
|
|
14
|
+
| 'up' | 'down' | 'left' | 'right'
|
|
15
|
+
| 'home' | 'end' | 'pageup' | 'pagedown'
|
|
16
|
+
| 'insert' | 'delete' | 'backspace'
|
|
17
|
+
| 'enter' | 'return' | 'escape' | 'space' | 'tab'
|
|
18
|
+
| 'f1' | 'f2' | 'f3' | 'f4' | 'f5' | 'f6'
|
|
19
|
+
| 'f7' | 'f8' | 'f9' | 'f10' | 'f11' | 'f12';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The full key type accepted by `Panel.handleInput`.
|
|
23
|
+
*
|
|
24
|
+
* Named keys (arrow keys, modifiers, function keys) are represented by
|
|
25
|
+
* lowercase `NamedKey` members. Single printable characters are passed
|
|
26
|
+
* verbatim via the `string & {}` escape hatch so panels can handle 'j', 'k',
|
|
27
|
+
* 'r', etc. without losing type safety on the named members.
|
|
28
|
+
*/
|
|
29
|
+
export type KeyName = NamedKey | (string & {});
|
|
30
|
+
|
|
4
31
|
export type PanelCategory = 'development' | 'agent' | 'monitoring' | 'session' | 'ai';
|
|
5
32
|
|
|
6
33
|
export interface Panel {
|
|
@@ -35,7 +62,7 @@ export interface Panel {
|
|
|
35
62
|
healthState?: Readonly<ComponentHealthState>;
|
|
36
63
|
|
|
37
64
|
// Input (optional)
|
|
38
|
-
handleInput?(key:
|
|
65
|
+
handleInput?(key: KeyName): boolean;
|
|
39
66
|
|
|
40
67
|
// Scroll input (optional)
|
|
41
68
|
// Positive delta scrolls down; negative delta scrolls up.
|