@pellux/goodvibes-agent 1.4.4 → 1.5.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 +14 -0
- package/README.md +7 -7
- package/dist/package/main.js +7424 -12241
- package/docs/README.md +2 -2
- package/docs/channels-remote-and-api.md +1 -1
- package/docs/getting-started.md +2 -2
- package/docs/release-and-publishing.md +1 -1
- package/docs/tools-and-commands.md +5 -5
- package/package.json +4 -2
- package/release/performance-snapshot.json +2 -2
- package/release/release-notes.md +11 -7
- package/release/release-readiness.json +6 -6
- package/src/agent/behavior-discovery-summary.ts +4 -18
- package/src/agent/calendar-registry.ts +322 -0
- package/src/agent/competitive-feature-inventory.ts +268 -130
- package/src/agent/document-registry.ts +5 -1
- package/src/agent/email/email-service.ts +350 -0
- package/src/agent/email/imap-client.ts +596 -0
- package/src/agent/email/smtp-client.ts +453 -0
- package/src/agent/ics-calendar.ts +662 -0
- package/src/agent/ics-timezone.ts +172 -0
- package/src/agent/markdown-frontmatter.ts +31 -0
- package/src/agent/memory-safety.ts +1 -1
- package/src/agent/note-registry.ts +3 -9
- package/src/agent/persona-discovery.ts +3 -15
- package/src/agent/persona-registry.ts +1 -10
- package/src/agent/research-source-registry.ts +5 -1
- package/src/agent/routine-discovery.ts +3 -15
- package/src/agent/runtime-profile.ts +3 -0
- package/src/agent/skill-discovery.ts +3 -15
- package/src/agent/skill-draft-proposer.ts +203 -0
- package/src/agent/skill-draft-runner.ts +201 -0
- package/src/agent/skill-registry.ts +36 -1
- package/src/agent/skill-standard.ts +99 -0
- package/src/agent/vibe-file.ts +7 -22
- package/src/cli/completion.ts +1 -1
- package/src/cli/config-overrides.ts +10 -1
- package/src/cli/redaction.ts +17 -5
- package/src/config/provider-model.ts +2 -1
- package/src/config/secret-config.ts +13 -6
- package/src/core/activity-feed.ts +97 -0
- package/src/core/away-digest.ts +161 -0
- package/src/core/conversation-rendering.ts +7 -3
- package/src/core/conversation.ts +22 -15
- package/src/core/hardware-profile.ts +362 -0
- package/src/core/last-seen-store.ts +78 -0
- package/src/core/plain-language.ts +52 -0
- package/src/core/setup-incomplete-hint.ts +90 -0
- package/src/core/system-message-router.ts +38 -87
- package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
- package/src/input/agent-workspace-basic-command-editors.ts +39 -141
- package/src/input/agent-workspace-categories.ts +40 -125
- package/src/input/agent-workspace-command-editor.ts +4 -0
- package/src/input/agent-workspace-host-category.ts +0 -5
- package/src/input/agent-workspace-local-editor-submission.ts +3 -1
- package/src/input/agent-workspace-navigation.ts +10 -3
- package/src/input/agent-workspace-onboarding-actions.ts +132 -0
- package/src/input/agent-workspace-onboarding-categories.ts +29 -26
- package/src/input/agent-workspace-onboarding-finish.ts +11 -4
- package/src/input/agent-workspace-onboarding-state.ts +111 -0
- package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
- package/src/input/agent-workspace-profile-editors.ts +155 -0
- package/src/input/agent-workspace-subscription-editor.ts +7 -0
- package/src/input/agent-workspace-types.ts +5 -1
- package/src/input/agent-workspace.ts +65 -39
- package/src/input/command-registry.ts +18 -5
- package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
- package/src/input/commands/agent-skills-runtime.ts +60 -3
- package/src/input/commands/calendar-runtime.ts +209 -0
- package/src/input/commands/channels-runtime.ts +1 -0
- package/src/input/commands/command-error.ts +9 -0
- package/src/input/commands/compat-runtime.ts +1 -0
- package/src/input/commands/config.ts +1 -0
- package/src/input/commands/conversation-runtime.ts +1 -1
- package/src/input/commands/delegation-runtime.ts +5 -6
- package/src/input/commands/email-runtime.ts +387 -0
- package/src/input/commands/experience-runtime.ts +17 -4
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/health-runtime.ts +6 -1
- package/src/input/commands/knowledge-format.ts +73 -0
- package/src/input/commands/knowledge.ts +9 -74
- package/src/input/commands/local-provider-runtime.ts +2 -1
- package/src/input/commands/local-runtime.ts +10 -4
- package/src/input/commands/mcp-runtime.ts +7 -0
- package/src/input/commands/notify-runtime.ts +17 -1
- package/src/input/commands/onboarding-runtime.ts +1 -0
- package/src/input/commands/operator-actions-runtime.ts +1 -0
- package/src/input/commands/operator-runtime.ts +3 -0
- package/src/input/commands/personas-runtime.ts +1 -0
- package/src/input/commands/platform-access-runtime.ts +40 -17
- package/src/input/commands/product-runtime.ts +6 -1
- package/src/input/commands/provider-accounts-runtime.ts +3 -2
- package/src/input/commands/qrcode-runtime.ts +1 -0
- package/src/input/commands/routines-runtime.ts +1 -0
- package/src/input/commands/runtime-services.ts +0 -13
- package/src/input/commands/security-runtime.ts +1 -0
- package/src/input/commands/session-content.ts +1 -0
- package/src/input/commands/shell-core.ts +5 -2
- package/src/input/commands/subscription-runtime.ts +33 -9
- package/src/input/commands/support-bundle-runtime.ts +8 -1
- package/src/input/commands/tasks-runtime.ts +1 -0
- package/src/input/commands/tts-runtime.ts +1 -0
- package/src/input/commands/vibe-runtime.ts +1 -0
- package/src/input/commands.ts +4 -0
- package/src/input/feed-context-factory.ts +3 -12
- package/src/input/handler-command-route.ts +7 -60
- package/src/input/handler-feed-routes.ts +0 -194
- package/src/input/handler-feed.ts +2 -54
- package/src/input/handler-interactions.ts +0 -2
- package/src/input/handler-modal-stack.ts +0 -9
- package/src/input/handler-picker-routes.ts +24 -1
- package/src/input/handler-shortcuts.ts +11 -40
- package/src/input/handler-ui-state.ts +13 -0
- package/src/input/handler.ts +8 -35
- package/src/input/keybindings.ts +40 -17
- package/src/input/model-picker-local-fit.ts +130 -0
- package/src/input/submission-router.ts +0 -5
- package/src/main.ts +111 -89
- package/src/renderer/activity-sidebar.ts +186 -0
- package/src/renderer/agent-workspace-context-lines.ts +5 -48
- package/src/renderer/agent-workspace-style.ts +1 -1
- package/src/renderer/agent-workspace.ts +14 -2
- package/src/renderer/compositor.ts +37 -125
- package/src/renderer/conversation-overlays.ts +3 -3
- package/src/renderer/help-overlay.ts +7 -5
- package/src/renderer/model-workspace.ts +101 -86
- package/src/{panels → renderer}/polish.ts +3 -3
- package/src/renderer/shell-surface.ts +4 -5
- package/src/renderer/status-token.ts +31 -11
- package/src/renderer/tab-strip.ts +1 -1
- package/src/renderer/tool-call.ts +7 -8
- package/src/renderer/tool-labels.ts +92 -0
- package/src/renderer/ui-factory.ts +48 -96
- package/src/runtime/bootstrap-command-context.ts +0 -5
- package/src/runtime/bootstrap-command-parts.ts +6 -15
- package/src/runtime/bootstrap-core.ts +34 -13
- package/src/runtime/bootstrap-hook-bridge.ts +3 -1
- package/src/runtime/bootstrap-shell.ts +3 -50
- package/src/runtime/bootstrap.ts +3 -4
- package/src/runtime/context.ts +1 -1
- package/src/runtime/diagnostics/panels/index.ts +0 -1
- package/src/runtime/diagnostics/panels/policy.ts +1 -1
- package/src/runtime/execution-ledger.ts +16 -1
- package/src/runtime/index.ts +6 -1
- package/src/runtime/onboarding/index.ts +1 -0
- package/src/runtime/onboarding/onboarding-state.ts +200 -0
- package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
- package/src/runtime/services.ts +16 -4
- package/src/runtime/terminal-output-guard.ts +7 -0
- package/src/runtime/tool-permission-safety.ts +1 -1
- package/src/runtime/ui/model-picker/data-provider.ts +1 -1
- package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
- package/src/runtime/ui/model-picker/types.ts +2 -2
- package/src/runtime/ui/provider-health/data-provider.ts +3 -3
- package/src/runtime/ui/provider-health/types.ts +2 -2
- package/src/runtime/ui-services.ts +0 -2
- package/src/shell/agent-workspace-fullscreen.ts +0 -1
- package/src/shell/autonomy-surfacing.ts +272 -0
- package/src/shell/session-continuity-hints.ts +0 -6
- package/src/shell/startup-wiring.ts +221 -0
- package/src/shell/ui-openers.ts +18 -29
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-harness-background-processes.ts +4 -4
- package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
- package/src/tools/agent-harness-command-runner.ts +6 -1
- package/src/tools/agent-harness-document-ops.ts +26 -53
- package/src/tools/agent-harness-execution-history.ts +1 -13
- package/src/tools/agent-harness-execution-posture.ts +0 -15
- package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
- package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
- package/src/tools/agent-harness-metadata.ts +16 -0
- package/src/tools/agent-harness-mode-catalog.ts +2 -9
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
- package/src/tools/agent-harness-tool-schema.ts +13 -14
- package/src/tools/agent-harness-tool.ts +27 -23
- package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
- package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
- package/src/tools/agent-workspace-tool.ts +2 -33
- package/src/utils/terminal-width.ts +9 -3
- package/src/version.ts +1 -1
- package/src/input/agent-workspace-panel-route.ts +0 -44
- package/src/input/panel-integration-actions.ts +0 -26
- package/src/panels/approval-panel.ts +0 -149
- package/src/panels/automation-control-panel.ts +0 -212
- package/src/panels/base-panel.ts +0 -254
- package/src/panels/builtin/agent.ts +0 -58
- package/src/panels/builtin/knowledge.ts +0 -26
- package/src/panels/builtin/operations.ts +0 -121
- package/src/panels/builtin/session.ts +0 -138
- package/src/panels/builtin/shared.ts +0 -275
- package/src/panels/builtin/usage.ts +0 -21
- package/src/panels/builtin-panels.ts +0 -23
- package/src/panels/confirm-state.ts +0 -61
- package/src/panels/context-visualizer-panel.ts +0 -204
- package/src/panels/cost-tracker-panel.ts +0 -444
- package/src/panels/docs-panel.ts +0 -285
- package/src/panels/index.ts +0 -25
- package/src/panels/knowledge-panel.ts +0 -417
- package/src/panels/memory-panel.ts +0 -226
- package/src/panels/panel-list-panel.ts +0 -464
- package/src/panels/panel-manager.ts +0 -570
- package/src/panels/provider-accounts-panel.ts +0 -233
- package/src/panels/provider-health-domains.ts +0 -208
- package/src/panels/provider-health-panel.ts +0 -720
- package/src/panels/provider-health-tracker.ts +0 -115
- package/src/panels/provider-stats-panel.ts +0 -366
- package/src/panels/qr-panel.ts +0 -207
- package/src/panels/schedule-panel.ts +0 -321
- package/src/panels/scrollable-list-panel.ts +0 -491
- package/src/panels/search-focus.ts +0 -32
- package/src/panels/security-panel.ts +0 -295
- package/src/panels/session-browser-panel.ts +0 -395
- package/src/panels/session-maintenance.ts +0 -125
- package/src/panels/subscription-panel.ts +0 -263
- package/src/panels/system-messages-panel.ts +0 -230
- package/src/panels/tasks-panel.ts +0 -344
- package/src/panels/thinking-panel.ts +0 -304
- package/src/panels/token-budget-panel.ts +0 -475
- package/src/panels/tool-inspector-panel.ts +0 -436
- package/src/panels/types.ts +0 -54
- package/src/renderer/panel-composite.ts +0 -158
- package/src/renderer/panel-tab-bar.ts +0 -69
- package/src/renderer/panel-workspace-bar.ts +0 -42
- package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
- package/src/tools/agent-harness-panel-metadata.ts +0 -211
- /package/src/runtime/perf/{panel-health-monitor.ts → component-health.ts} +0 -0
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import type { Line } from '../types/grid.ts';
|
|
2
|
-
import { createEmptyLine } from '../types/grid.ts';
|
|
3
|
-
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
4
|
-
import {
|
|
5
|
-
buildDetailBlock,
|
|
6
|
-
buildEmptyState,
|
|
7
|
-
buildGuidanceLine,
|
|
8
|
-
buildKeyValueLine,
|
|
9
|
-
buildPanelListRow,
|
|
10
|
-
buildPanelLine,
|
|
11
|
-
buildSummaryBlock,
|
|
12
|
-
buildPanelWorkspace,
|
|
13
|
-
DEFAULT_PANEL_PALETTE,
|
|
14
|
-
resolvePrimaryScrollableSection,
|
|
15
|
-
type PanelWorkspaceSection,
|
|
16
|
-
} from './polish.ts';
|
|
17
|
-
import {
|
|
18
|
-
type ProviderAuthRoute,
|
|
19
|
-
type ProviderAccountRecord,
|
|
20
|
-
type ProviderAccountSnapshot,
|
|
21
|
-
type ProviderAccountSnapshotQuery,
|
|
22
|
-
} from './provider-account-snapshot.ts';
|
|
23
|
-
import { formatProviderAuthRouteId } from '../provider-auth-route-display.ts';
|
|
24
|
-
|
|
25
|
-
export interface ProviderAccountsPanelDeps {
|
|
26
|
-
readonly providerAccounts: ProviderAccountSnapshotQuery;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const C = {
|
|
30
|
-
...DEFAULT_PANEL_PALETTE,
|
|
31
|
-
selectBg: '#1e293b',
|
|
32
|
-
} as const;
|
|
33
|
-
|
|
34
|
-
function routeColor(route: ProviderAuthRoute): string {
|
|
35
|
-
if (route === 'subscription') return C.info;
|
|
36
|
-
if (route === 'api-key') return C.warn;
|
|
37
|
-
if (route === 'service-oauth') return C.value;
|
|
38
|
-
if (route === 'unconfigured') return C.bad;
|
|
39
|
-
return C.dim;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function formatRouteList(routes: readonly ProviderAuthRoute[]): string {
|
|
43
|
-
return routes.map((route) => formatProviderAuthRouteId(route)).join(', ');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export class ProviderAccountsPanel extends ScrollableListPanel<ProviderAccountRecord> {
|
|
47
|
-
private records: ProviderAccountRecord[] = [];
|
|
48
|
-
private loading = false;
|
|
49
|
-
private readonly providerAccounts: ProviderAccountSnapshotQuery;
|
|
50
|
-
|
|
51
|
-
public constructor(deps: ProviderAccountsPanelDeps) {
|
|
52
|
-
super('accounts', 'Accounts', 'Q', 'monitoring');
|
|
53
|
-
this.showSelectionGutter = true; // I5: non-color selection affordance
|
|
54
|
-
this.providerAccounts = deps.providerAccounts;
|
|
55
|
-
void this.refresh();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public override onActivate(): void {
|
|
59
|
-
super.onActivate();
|
|
60
|
-
if (!this.loading) void this.refresh();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
protected getItems(): readonly ProviderAccountRecord[] {
|
|
64
|
-
return this.records;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
protected renderItem(item: ProviderAccountRecord, _index: number, selected: boolean, width: number): Line {
|
|
68
|
-
const activeRoute = formatProviderAuthRouteId(item.activeRoute);
|
|
69
|
-
return buildPanelListRow(width, [
|
|
70
|
-
{ text: item.providerId.padEnd(16), fg: item.active ? C.good : C.value },
|
|
71
|
-
{ text: ` ${activeRoute.padEnd(14)}`, fg: routeColor(item.activeRoute) },
|
|
72
|
-
{ text: ` models ${String(item.modelCount).padEnd(4)}`, fg: C.dim },
|
|
73
|
-
{ text: ` ${item.authFreshness.padEnd(10)}`, fg: item.authFreshness === 'expired' ? C.bad : item.authFreshness === 'expiring' || item.authFreshness === 'pending' ? C.warn : C.dim },
|
|
74
|
-
{ text: ` issues ${String(item.issues.length).padEnd(2)}`, fg: item.issues.length > 0 ? C.bad : C.good },
|
|
75
|
-
], C, { selected });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public handleInput(key: string): boolean {
|
|
79
|
-
if (key === 'r') {
|
|
80
|
-
void this.refresh();
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
return super.handleInput(key);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
private async refresh(): Promise<void> {
|
|
87
|
-
this.loading = true;
|
|
88
|
-
this.markDirty();
|
|
89
|
-
const snapshot = await this.buildSnapshot();
|
|
90
|
-
this.records = [...snapshot.providers];
|
|
91
|
-
this.clampSelection();
|
|
92
|
-
this.loading = false;
|
|
93
|
-
this.markDirty();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private async buildSnapshot(): Promise<ProviderAccountSnapshot> {
|
|
97
|
-
return this.providerAccounts.loadSnapshot();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public render(width: number, height: number): Line[] {
|
|
101
|
-
this.needsRender = false;
|
|
102
|
-
const intro = 'Provider auth routes, subscription posture, quota-window hints, and routing-safety notes.';
|
|
103
|
-
const footerLines = [buildPanelLine(width, [[' Up/Down move r refresh /accounts routes <provider> /accounts repair <provider>', C.dim]])];
|
|
104
|
-
if (this.loading && this.records.length === 0) {
|
|
105
|
-
const lines = buildPanelWorkspace(width, height, {
|
|
106
|
-
title: 'Provider Account Control Room',
|
|
107
|
-
intro,
|
|
108
|
-
sections: [{ lines: [buildPanelLine(width, [[' Loading provider account posture...', C.info]])] }],
|
|
109
|
-
palette: C,
|
|
110
|
-
});
|
|
111
|
-
while (lines.length < height) lines.push(createEmptyLine(width));
|
|
112
|
-
return lines;
|
|
113
|
-
}
|
|
114
|
-
if (this.records.length === 0) {
|
|
115
|
-
const lines = buildPanelWorkspace(width, height, {
|
|
116
|
-
title: 'Provider Account Control Room',
|
|
117
|
-
intro,
|
|
118
|
-
sections: [{
|
|
119
|
-
lines: buildEmptyState(width, ' No provider accounts discovered.', 'Configure API keys or subscriptions to populate account routing posture.', [{ command: '/provider', summary: 'review current provider and model posture' }], C),
|
|
120
|
-
}],
|
|
121
|
-
palette: C,
|
|
122
|
-
});
|
|
123
|
-
while (lines.length < height) lines.push(createEmptyLine(width));
|
|
124
|
-
return lines;
|
|
125
|
-
}
|
|
126
|
-
const issueCount = this.records.reduce((sum, record) => sum + record.issues.length + (record.fallbackRisk ? 1 : 0), 0);
|
|
127
|
-
const expiredCount = this.records.filter((record) => record.authFreshness === 'expired').length;
|
|
128
|
-
const pendingCount = this.records.filter((record) => record.pendingLogin).length;
|
|
129
|
-
const fallbackCount = this.records.filter((record) => Boolean(record.fallbackRisk)).length;
|
|
130
|
-
const selected = this.records[this.selectedIndex]!;
|
|
131
|
-
const postureLines: Line[] = [
|
|
132
|
-
buildKeyValueLine(width, [
|
|
133
|
-
{ label: 'providers', value: String(this.records.length), valueColor: C.value },
|
|
134
|
-
{ label: 'expired auth', value: String(expiredCount), valueColor: expiredCount > 0 ? C.bad : C.good },
|
|
135
|
-
{ label: 'pending login', value: String(pendingCount), valueColor: pendingCount > 0 ? C.warn : C.dim },
|
|
136
|
-
{ label: 'routing risk', value: String(fallbackCount), valueColor: fallbackCount > 0 ? C.warn : C.good },
|
|
137
|
-
], C),
|
|
138
|
-
buildKeyValueLine(width, [
|
|
139
|
-
{ label: 'total issues', value: String(issueCount), valueColor: issueCount > 0 ? C.bad : C.good },
|
|
140
|
-
{ label: 'selected', value: selected.providerId, valueColor: C.info },
|
|
141
|
-
{ label: 'route', value: formatProviderAuthRouteId(selected.activeRoute), valueColor: routeColor(selected.activeRoute) },
|
|
142
|
-
{ label: 'freshness', value: selected.authFreshness, valueColor: selected.authFreshness === 'expired' ? C.bad : selected.authFreshness === 'expiring' || selected.authFreshness === 'pending' ? C.warn : C.good },
|
|
143
|
-
], C),
|
|
144
|
-
buildGuidanceLine(width, '/accounts repair <provider>', 'review routing safety, fallback cost, and provider-specific recovery steps', C),
|
|
145
|
-
];
|
|
146
|
-
const detailRows: Line[] = [
|
|
147
|
-
buildKeyValueLine(width, [
|
|
148
|
-
{ label: 'provider', value: selected.providerId, valueColor: C.value },
|
|
149
|
-
{ label: 'active route', value: formatProviderAuthRouteId(selected.activeRoute), valueColor: routeColor(selected.activeRoute) },
|
|
150
|
-
{ label: 'preferred route', value: formatProviderAuthRouteId(selected.preferredRoute), valueColor: C.dim },
|
|
151
|
-
{ label: 'freshness', value: selected.authFreshness, valueColor: selected.authFreshness === 'expired' ? C.bad : selected.authFreshness === 'expiring' || selected.authFreshness === 'pending' ? C.warn : C.good },
|
|
152
|
-
], C),
|
|
153
|
-
buildKeyValueLine(width, [
|
|
154
|
-
{ label: 'configured', value: selected.configured ? 'yes' : 'no', valueColor: selected.configured ? C.good : C.bad },
|
|
155
|
-
{ label: 'oauth ready', value: selected.oauthReady ? 'yes' : 'no', valueColor: selected.oauthReady ? C.info : C.dim },
|
|
156
|
-
{ label: 'pending login', value: selected.pendingLogin ? 'yes' : 'no', valueColor: selected.pendingLogin ? C.warn : C.dim },
|
|
157
|
-
], C),
|
|
158
|
-
buildPanelLine(width, [[` Route reason ${selected.activeRouteReason}`.slice(0, width), C.dim]]),
|
|
159
|
-
buildPanelLine(width, [[` Available routes ${formatRouteList(selected.availableRoutes) || 'unconfigured'}`.slice(0, width), C.dim]]),
|
|
160
|
-
];
|
|
161
|
-
if (selected.expiresAt) {
|
|
162
|
-
detailRows.push(buildPanelLine(width, [
|
|
163
|
-
[' Expires ', C.label],
|
|
164
|
-
[new Date(selected.expiresAt).toISOString(), C.dim],
|
|
165
|
-
[' Token ', C.label],
|
|
166
|
-
[selected.tokenType ?? 'n/a', C.value],
|
|
167
|
-
]));
|
|
168
|
-
}
|
|
169
|
-
if (selected.fallbackRisk) {
|
|
170
|
-
detailRows.push(buildPanelLine(width, [[` routing risk ${selected.fallbackRisk}`.slice(0, width), C.warn]]));
|
|
171
|
-
}
|
|
172
|
-
for (const route of selected.routeRecords) {
|
|
173
|
-
detailRows.push(buildPanelLine(width, [[
|
|
174
|
-
` route ${formatProviderAuthRouteId(route.route)} ${route.usable ? 'usable' : 'blocked'} • ${route.freshness} • ${route.detail}`.slice(0, width),
|
|
175
|
-
route.usable ? C.dim : C.bad,
|
|
176
|
-
]]));
|
|
177
|
-
for (const issue of route.issues) {
|
|
178
|
-
detailRows.push(buildPanelLine(width, [[` issue ${issue}`.slice(0, width), C.bad]]));
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
for (const windowHint of selected.usageWindows) {
|
|
182
|
-
detailRows.push(buildPanelLine(width, [[` ${windowHint.label} ${windowHint.detail}`.slice(0, width), C.dim]]));
|
|
183
|
-
}
|
|
184
|
-
for (const issue of selected.issues) {
|
|
185
|
-
detailRows.push(buildPanelLine(width, [[` issue ${issue}`.slice(0, width), C.bad]]));
|
|
186
|
-
}
|
|
187
|
-
for (const note of selected.notes) {
|
|
188
|
-
detailRows.push(buildPanelLine(width, [[` note ${note}`.slice(0, width), C.info]]));
|
|
189
|
-
}
|
|
190
|
-
for (const action of selected.recommendedActions) {
|
|
191
|
-
detailRows.push(buildPanelLine(width, [[` next ${action}`.slice(0, width), C.value]]));
|
|
192
|
-
}
|
|
193
|
-
if (selected.issues.length === 0 && selected.notes.length === 0 && selected.usageWindows.length === 0 && selected.recommendedActions.length === 0) {
|
|
194
|
-
detailRows.push(buildPanelLine(width, [[' No active account warnings for this provider.', C.dim]]));
|
|
195
|
-
}
|
|
196
|
-
const postureSection: PanelWorkspaceSection = { lines: buildSummaryBlock(width, 'Provider posture', postureLines, C) };
|
|
197
|
-
const detailsSection: PanelWorkspaceSection = { lines: buildDetailBlock(width, 'Selected provider', detailRows, C) };
|
|
198
|
-
const rawProviderLines: Line[] = this.records.map((record, absolute) =>
|
|
199
|
-
this.renderItem(record, absolute, absolute === this.selectedIndex, width),
|
|
200
|
-
);
|
|
201
|
-
const resolvedProvidersSection = resolvePrimaryScrollableSection(width, height, {
|
|
202
|
-
intro,
|
|
203
|
-
footerLines,
|
|
204
|
-
palette: C,
|
|
205
|
-
beforeSections: [postureSection],
|
|
206
|
-
section: {
|
|
207
|
-
title: 'Providers',
|
|
208
|
-
scrollableLines: rawProviderLines,
|
|
209
|
-
selectedIndex: this.selectedIndex,
|
|
210
|
-
scrollOffset: this.scrollStart,
|
|
211
|
-
guardRows: 1,
|
|
212
|
-
minRows: 4,
|
|
213
|
-
appendWindowSummary: { dimColor: C.dim },
|
|
214
|
-
},
|
|
215
|
-
afterSections: [detailsSection],
|
|
216
|
-
});
|
|
217
|
-
this.scrollStart = resolvedProvidersSection.scrollOffset;
|
|
218
|
-
const sections: PanelWorkspaceSection[] = [
|
|
219
|
-
postureSection,
|
|
220
|
-
resolvedProvidersSection.section,
|
|
221
|
-
detailsSection,
|
|
222
|
-
];
|
|
223
|
-
const lines = buildPanelWorkspace(width, height, {
|
|
224
|
-
title: 'Provider Account Control Room',
|
|
225
|
-
intro,
|
|
226
|
-
sections,
|
|
227
|
-
footerLines,
|
|
228
|
-
palette: C,
|
|
229
|
-
});
|
|
230
|
-
while (lines.length < height) lines.push(createEmptyLine(width));
|
|
231
|
-
return lines.slice(0, height);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
2
|
-
import { evaluateSessionMaintenance } from '@/runtime/index.ts';
|
|
3
|
-
import type {
|
|
4
|
-
UiContinuitySnapshot,
|
|
5
|
-
UiLocalAuthSnapshot,
|
|
6
|
-
UiRemoteSnapshot,
|
|
7
|
-
UiSecuritySnapshot,
|
|
8
|
-
UiSessionSnapshot,
|
|
9
|
-
UiSettingsSnapshot,
|
|
10
|
-
} from '../runtime/ui-read-models.ts';
|
|
11
|
-
|
|
12
|
-
export interface HealthDomainSummary {
|
|
13
|
-
readonly name: string;
|
|
14
|
-
readonly level: 'good' | 'warn' | 'bad' | 'info';
|
|
15
|
-
readonly summary: string;
|
|
16
|
-
readonly next: string;
|
|
17
|
-
readonly details: readonly string[];
|
|
18
|
-
readonly nextSteps: readonly string[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface ProviderHealthDomainInputs {
|
|
22
|
-
readonly configManager: Pick<ConfigManager, 'get'>;
|
|
23
|
-
readonly auth: UiLocalAuthSnapshot;
|
|
24
|
-
readonly settings: UiSettingsSnapshot;
|
|
25
|
-
readonly remote: UiRemoteSnapshot;
|
|
26
|
-
readonly security: UiSecuritySnapshot;
|
|
27
|
-
readonly continuity: UiContinuitySnapshot;
|
|
28
|
-
readonly session: UiSessionSnapshot;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
type ProviderHealthMcpServer = UiSecuritySnapshot['mcpServers'][number];
|
|
32
|
-
type ProviderHealthRemoteSession = UiRemoteSnapshot['supervisor']['sessions'][number];
|
|
33
|
-
type ProviderHealthStatusValue =
|
|
34
|
-
| ProviderHealthMcpServer['schemaFreshness']
|
|
35
|
-
| ProviderHealthMcpServer['trustMode']
|
|
36
|
-
| ProviderHealthRemoteSession['transportState']
|
|
37
|
-
| ProviderHealthRemoteSession['heartbeat']['status'];
|
|
38
|
-
|
|
39
|
-
function formatProviderHealthStatus(value: ProviderHealthStatusValue): string {
|
|
40
|
-
if (value === 'quarantined') return 'needs review';
|
|
41
|
-
return value.replace(/[_-]+/g, ' ');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function formatProviderHealthTrustMode(mode: ProviderHealthMcpServer['trustMode']): string {
|
|
45
|
-
if (mode === 'ask-on-risk') return 'ask on risky actions';
|
|
46
|
-
if (mode === 'allow-all') return 'allow all actions';
|
|
47
|
-
return formatProviderHealthStatus(mode);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function formatMcpServerDetail(server: ProviderHealthMcpServer): string {
|
|
51
|
-
const parts = [
|
|
52
|
-
`${server.name}: trust ${formatProviderHealthTrustMode(server.trustMode)}`,
|
|
53
|
-
`status ${formatProviderHealthStatus(server.schemaFreshness)}`,
|
|
54
|
-
];
|
|
55
|
-
if (server.quarantineReason) {
|
|
56
|
-
parts.push(`review reason ${server.quarantineReason}`);
|
|
57
|
-
}
|
|
58
|
-
return parts.join('; ');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function formatRemoteSessionDetail(session: ProviderHealthRemoteSession): string {
|
|
62
|
-
const parts = [
|
|
63
|
-
`${session.runnerId}: transport ${formatProviderHealthStatus(session.transportState)}`,
|
|
64
|
-
`heartbeat ${formatProviderHealthStatus(session.heartbeat.status)}`,
|
|
65
|
-
];
|
|
66
|
-
if (session.lastError) {
|
|
67
|
-
parts.push(`error ${session.lastError}`);
|
|
68
|
-
}
|
|
69
|
-
return parts.join('; ');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function buildProviderHealthDomainSummaries(
|
|
73
|
-
input: ProviderHealthDomainInputs,
|
|
74
|
-
): HealthDomainSummary[] {
|
|
75
|
-
const summaries: HealthDomainSummary[] = [];
|
|
76
|
-
const {
|
|
77
|
-
configManager,
|
|
78
|
-
auth,
|
|
79
|
-
settings,
|
|
80
|
-
remote,
|
|
81
|
-
security,
|
|
82
|
-
continuity,
|
|
83
|
-
session,
|
|
84
|
-
} = input;
|
|
85
|
-
|
|
86
|
-
summaries.push({
|
|
87
|
-
name: 'auth',
|
|
88
|
-
level: auth.bootstrapCredentialPresent ? 'warn' : 'info',
|
|
89
|
-
summary: auth.bootstrapCredentialPresent
|
|
90
|
-
? 'connected-host bootstrap credential visible in local compatibility state'
|
|
91
|
-
: 'connected-host auth administration belongs outside Agent',
|
|
92
|
-
next: '/auth review',
|
|
93
|
-
details: [
|
|
94
|
-
'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-host auth users or sessions.',
|
|
95
|
-
`${auth.userCount} compatibility user record(s) and ${auth.sessionCount} session record(s) are visible for diagnostics only.`,
|
|
96
|
-
auth.bootstrapCredentialPresent ? 'Bootstrap cleanup must be done in the owning GoodVibes host.' : '',
|
|
97
|
-
].filter(Boolean),
|
|
98
|
-
nextSteps: auth.bootstrapCredentialPresent
|
|
99
|
-
? ['/auth review', '/provider', '/subscription providers']
|
|
100
|
-
: ['/auth review', '/provider'],
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const settingIssueCount = settings.conflictCount + settings.recentFailureCount + (settings.hasStagedManagedBundle ? 1 : 0);
|
|
104
|
-
summaries.push({
|
|
105
|
-
name: 'settings',
|
|
106
|
-
level: !settings.available ? 'info' : settingIssueCount > 0 ? 'warn' : 'good',
|
|
107
|
-
summary: !settings.available
|
|
108
|
-
? 'settings API unavailable'
|
|
109
|
-
: settingIssueCount > 0
|
|
110
|
-
? `${settings.conflictCount} conflicts / ${settings.recentFailureCount} failures${settings.hasStagedManagedBundle ? ' / pending managed bundle' : ''}`
|
|
111
|
-
: 'settings API clean',
|
|
112
|
-
next: settingIssueCount > 0 ? '/settings' : '/config <key>',
|
|
113
|
-
details: [
|
|
114
|
-
settings.conflictCount > 0 ? `${settings.conflictCount} unresolved import conflict(s)` : '',
|
|
115
|
-
settings.recentFailureCount > 0 ? `${settings.recentFailureCount} recent sync or managed failure(s)` : '',
|
|
116
|
-
settings.hasStagedManagedBundle ? 'pending managed settings bundle awaits apply or rollback' : '',
|
|
117
|
-
settings.managedLockCount > 0 ? `${settings.managedLockCount} managed lock(s) enforced` : '',
|
|
118
|
-
].filter(Boolean),
|
|
119
|
-
nextSteps: settingIssueCount > 0
|
|
120
|
-
? ['/settings', '/config <key>', '/health settings']
|
|
121
|
-
: ['/config <key>'],
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
summaries.push({
|
|
125
|
-
name: 'remote',
|
|
126
|
-
level: remote.supervisor.degradedConnections > 0 ? 'warn' : remote.supervisor.sessions.length > 0 ? 'good' : 'info',
|
|
127
|
-
summary: remote.supervisor.sessions.length === 0
|
|
128
|
-
? 'no remote sessions tracked'
|
|
129
|
-
: `${remote.supervisor.sessions.length} sessions / ${remote.supervisor.degradedConnections} degraded`,
|
|
130
|
-
next: remote.supervisor.degradedConnections > 0 ? '/delegate <build/fix/review task>' : '/health remote',
|
|
131
|
-
details: remote.supervisor.sessions.length === 0
|
|
132
|
-
? ['no remote sessions have been attached yet']
|
|
133
|
-
: remote.supervisor.sessions
|
|
134
|
-
.filter((entry) =>
|
|
135
|
-
entry.transportState === 'degraded'
|
|
136
|
-
|| entry.transportState === 'reconnecting'
|
|
137
|
-
|| entry.transportState === 'terminal_failure'
|
|
138
|
-
|| entry.heartbeat.status !== 'fresh'
|
|
139
|
-
|| Boolean(entry.lastError))
|
|
140
|
-
.slice(0, 3)
|
|
141
|
-
.map(formatRemoteSessionDetail),
|
|
142
|
-
nextSteps: remote.supervisor.degradedConnections > 0
|
|
143
|
-
? ['/delegate <build/fix/review task>', '/health remote']
|
|
144
|
-
: ['/health remote'],
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
const degradedServers = security.mcpServers.filter((server) =>
|
|
148
|
-
!server.connected
|
|
149
|
-
|| server.schemaFreshness !== 'fresh'
|
|
150
|
-
|| Boolean(server.quarantineReason)
|
|
151
|
-
|| server.trustMode === 'allow-all');
|
|
152
|
-
const connectedServerCount = security.mcpServers.filter((server) => server.connected).length;
|
|
153
|
-
summaries.push({
|
|
154
|
-
name: 'mcp',
|
|
155
|
-
level: degradedServers.length > 0 ? 'warn' : security.mcpServers.length > 0 ? 'good' : 'info',
|
|
156
|
-
summary: security.mcpServers.length === 0
|
|
157
|
-
? 'no MCP servers configured'
|
|
158
|
-
: `${connectedServerCount}/${security.mcpServers.length} connected, ${degradedServers.length} need review`,
|
|
159
|
-
next: degradedServers.length > 0 ? '/mcp repair' : '/mcp review',
|
|
160
|
-
details: degradedServers.length === 0
|
|
161
|
-
? (security.mcpServers.length === 0 ? ['no MCP servers registered'] : ['all MCP servers are healthy'])
|
|
162
|
-
: degradedServers
|
|
163
|
-
.slice(0, 3)
|
|
164
|
-
.map(formatMcpServerDetail),
|
|
165
|
-
nextSteps: degradedServers.length > 0
|
|
166
|
-
? ['/mcp review', '/mcp auth-review', '/mcp repair']
|
|
167
|
-
: ['/mcp review'],
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const maintenance = evaluateSessionMaintenance({
|
|
171
|
-
configManager,
|
|
172
|
-
currentTokens: session.estimatedContextTokens,
|
|
173
|
-
contextWindow: session.contextWindow,
|
|
174
|
-
messageCount: session.messageCount,
|
|
175
|
-
session: session.session,
|
|
176
|
-
});
|
|
177
|
-
summaries.push({
|
|
178
|
-
name: 'maintenance',
|
|
179
|
-
level: maintenance.level === 'needs-repair'
|
|
180
|
-
? 'bad'
|
|
181
|
-
: maintenance.level === 'suggest-compact' || maintenance.level === 'watch'
|
|
182
|
-
? 'warn'
|
|
183
|
-
: 'good',
|
|
184
|
-
summary: maintenance.summary,
|
|
185
|
-
next: maintenance.nextSteps[0] ?? '/health maintenance',
|
|
186
|
-
details: maintenance.reasons.slice(0, 3),
|
|
187
|
-
nextSteps: maintenance.nextSteps,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
summaries.push({
|
|
191
|
-
name: 'continuity',
|
|
192
|
-
level: continuity.recoveryFilePresent ? 'warn' : continuity.lastSessionPointer ? 'good' : 'info',
|
|
193
|
-
summary: continuity.recoveryFilePresent
|
|
194
|
-
? `recovery file present for ${continuity.sessionId || '(unknown session)'}`
|
|
195
|
-
: continuity.lastSessionPointer ? `last session pointer ${continuity.lastSessionPointer}` : 'no last-session pointer',
|
|
196
|
-
next: continuity.recoveryFilePresent ? '/session resume <id>' : '/session list',
|
|
197
|
-
details: [
|
|
198
|
-
continuity.returnContext ? `last activity: ${continuity.returnContext.activityLabel}` : '',
|
|
199
|
-
continuity.returnContext ? `resume posture: ${continuity.returnContext.statusLabel}` : '',
|
|
200
|
-
!continuity.lastSessionPointer ? 'no persisted last-session pointer recorded' : '',
|
|
201
|
-
].filter(Boolean),
|
|
202
|
-
nextSteps: continuity.recoveryFilePresent
|
|
203
|
-
? ['/session list', '/session resume <id>', '/health continuity']
|
|
204
|
-
: ['/session list'],
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
return summaries;
|
|
208
|
-
}
|