@pellux/goodvibes-agent 0.1.114 → 0.1.117
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 +41 -650
- package/README.md +40 -50
- package/dist/package/main.js +38224 -35673
- package/docs/README.md +5 -4
- package/docs/{connected-services.md → connected-host.md} +18 -10
- package/docs/getting-started.md +43 -42
- package/docs/release-and-publishing.md +6 -4
- package/package.json +3 -3
- package/src/agent/behavior-discovery-summary.ts +165 -0
- package/src/agent/persona-discovery.ts +1 -3
- package/src/agent/persona-registry.ts +5 -3
- package/src/agent/reminder-schedule-format.ts +6 -6
- package/src/agent/reminder-schedule.ts +1 -1
- package/src/agent/routine-registry.ts +43 -4
- package/src/agent/routine-schedule-format.ts +6 -6
- package/src/agent/routine-schedule-promotion.ts +1 -1
- package/src/agent/routine-schedule-receipts.ts +1 -1
- package/src/agent/runtime-profile-starters.ts +331 -0
- package/src/agent/runtime-profile.ts +228 -330
- package/src/agent/skill-registry.ts +190 -13
- package/src/cli/agent-knowledge-command.ts +2 -2
- package/src/cli/agent-knowledge-format.ts +2 -2
- package/src/cli/agent-knowledge-runtime.ts +1 -1
- package/src/cli/bundle-command.ts +1 -1
- package/src/cli/entrypoint.ts +16 -7
- package/src/cli/help.ts +26 -19
- package/src/cli/local-library-command.ts +75 -21
- package/src/cli/management-commands.ts +7 -6
- package/src/cli/management.ts +6 -51
- package/src/cli/parser.ts +23 -2
- package/src/cli/profiles-command.ts +247 -1
- package/src/cli/routines-command.ts +139 -11
- package/src/cli/service-posture.ts +11 -11
- package/src/cli/status.ts +21 -25
- package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
- package/src/input/agent-workspace-access-command-editors.ts +170 -0
- package/src/input/agent-workspace-activation.ts +2 -1
- package/src/input/agent-workspace-basic-command-editor-submission.ts +787 -0
- package/src/input/agent-workspace-basic-command-editors.ts +524 -459
- package/src/input/agent-workspace-categories.ts +177 -14
- package/src/input/agent-workspace-channel-command-editor-submission.ts +49 -0
- package/src/input/agent-workspace-channel-command-editors.ts +47 -0
- package/src/input/agent-workspace-command-editor.ts +25 -1
- package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
- package/src/input/agent-workspace-editors.ts +27 -0
- package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
- package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
- package/src/input/agent-workspace-learned-behavior.ts +67 -0
- package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
- package/src/input/agent-workspace-library-command-editors.ts +35 -0
- package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
- package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
- package/src/input/agent-workspace-memory-command-editors.ts +180 -0
- package/src/input/agent-workspace-navigation.ts +45 -0
- package/src/input/agent-workspace-notify-editor-submission.ts +107 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +146 -0
- package/src/input/agent-workspace-operations-command-editors.ts +119 -0
- package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
- package/src/input/agent-workspace-provider-command-editors.ts +93 -0
- package/src/input/agent-workspace-requirements.ts +11 -0
- package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
- package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
- package/src/input/agent-workspace-session-command-editors.ts +249 -0
- package/src/input/agent-workspace-setup.ts +49 -19
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
- package/src/input/agent-workspace-snapshot.ts +56 -8
- package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
- package/src/input/agent-workspace-task-command-editors.ts +47 -0
- package/src/input/agent-workspace-types.ts +124 -0
- package/src/input/agent-workspace-voice-media.ts +1 -1
- package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
- package/src/input/agent-workspace.ts +47 -37
- package/src/input/command-registry.ts +1 -1
- package/src/input/commands/agent-runtime-profile-runtime.ts +160 -6
- package/src/input/commands/agent-skills-runtime.ts +76 -12
- package/src/input/commands/agent-workspace-runtime.ts +4 -3
- package/src/input/commands/brief-runtime.ts +38 -9
- package/src/input/commands/channels-runtime.ts +3 -3
- package/src/input/commands/compat-runtime.ts +32 -0
- package/src/input/commands/health-runtime.ts +22 -24
- package/src/input/commands/knowledge.ts +26 -5
- package/src/input/commands/local-provider-runtime.ts +7 -3
- package/src/input/commands/local-setup-review.ts +4 -14
- package/src/input/commands/mcp-runtime.ts +8 -12
- package/src/input/commands/operator-runtime.ts +8 -67
- package/src/input/commands/personas-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +7 -70
- package/src/input/commands/policy-dispatch.ts +1 -1
- package/src/input/commands/policy.ts +1 -5
- package/src/input/commands/product-runtime.ts +2 -2
- package/src/input/commands/qrcode-runtime.ts +6 -4
- package/src/input/commands/routines-runtime.ts +44 -6
- package/src/input/commands/runtime-services.ts +1 -14
- package/src/input/commands/security-runtime.ts +3 -8
- package/src/input/commands/session-content.ts +1 -1
- package/src/input/commands/session-workflow.ts +5 -14
- package/src/input/commands/shell-core.ts +8 -2
- package/src/input/commands/subscription-runtime.ts +1 -6
- package/src/input/commands/support-bundle-runtime.ts +53 -0
- package/src/input/commands/tasks-runtime.ts +2 -2
- package/src/input/commands.ts +4 -0
- package/src/input/feed-context-factory.ts +0 -1
- package/src/input/handler-content-actions.ts +0 -25
- package/src/input/handler-feed.ts +0 -2
- package/src/input/handler-interactions.ts +2 -31
- package/src/input/handler-onboarding.ts +29 -12
- package/src/input/handler-shortcuts.ts +1 -3
- package/src/input/handler.ts +4 -7
- package/src/input/keybindings.ts +9 -9
- package/src/input/mcp-workspace.ts +90 -26
- package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +49 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +126 -11
- package/src/input/onboarding/onboarding-wizard-steps.ts +15 -8
- package/src/input/onboarding/onboarding-wizard-types.ts +1 -0
- package/src/input/onboarding/onboarding-wizard.ts +19 -2
- package/src/input/profile-picker-modal.ts +2 -2
- package/src/input/settings-modal-agent-policy.ts +6 -6
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal.ts +14 -14
- package/src/main.ts +0 -2
- package/src/panels/automation-control-panel.ts +3 -3
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +2 -2
- package/src/panels/builtin/session.ts +26 -18
- package/src/panels/builtin/shared.ts +6 -6
- package/src/panels/project-planning-panel.ts +1 -1
- package/src/panels/provider-health-domains.ts +3 -3
- package/src/panels/qr-panel.ts +44 -20
- package/src/panels/subscription-panel.ts +3 -3
- package/src/panels/system-messages-panel.ts +2 -2
- package/src/panels/tasks-panel.ts +4 -4
- package/src/planning/project-planning-coordinator.ts +2 -2
- package/src/renderer/agent-workspace.ts +52 -5
- package/src/renderer/block-actions.ts +1 -3
- package/src/renderer/help-overlay.ts +13 -8
- package/src/renderer/mcp-workspace.ts +32 -13
- package/src/renderer/model-picker-overlay.ts +0 -1
- package/src/renderer/model-workspace.ts +0 -2
- package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
- package/src/renderer/panel-picker-overlay.ts +1 -1
- package/src/renderer/profile-picker-modal.ts +2 -2
- package/src/renderer/settings-modal-helpers.ts +23 -23
- package/src/renderer/settings-modal.ts +18 -18
- package/src/renderer/system-message.ts +1 -1
- package/src/runtime/agent-runtime-events.ts +129 -0
- package/src/runtime/bootstrap-command-parts.ts +3 -2
- package/src/runtime/bootstrap-core.ts +4 -64
- package/src/runtime/bootstrap-shell.ts +42 -4
- package/src/runtime/bootstrap.ts +8 -27
- package/src/runtime/connected-host-auth.ts +42 -0
- package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
- package/src/runtime/index.ts +1 -5
- package/src/runtime/onboarding/apply.ts +213 -0
- package/src/runtime/onboarding/derivation.ts +25 -6
- package/src/runtime/onboarding/snapshot.ts +4 -2
- package/src/runtime/onboarding/types.ts +28 -1
- package/src/runtime/onboarding/verify.ts +81 -2
- package/src/runtime/operator-token-cleanup.ts +2 -2
- package/src/runtime/services.ts +27 -12
- package/src/shell/service-settings-sync.ts +7 -7
- package/src/shell/ui-openers.ts +27 -38
- package/src/tools/agent-local-registry-tool.ts +10 -4
- package/src/tools/agent-tool-policy-guard.ts +5 -7
- package/src/version.ts +1 -1
- package/src/cli/package-verification.ts +0 -274
|
@@ -145,7 +145,7 @@ export class ProfilePickerModal {
|
|
|
145
145
|
const profile = this.getSelected();
|
|
146
146
|
if (!profile) return false;
|
|
147
147
|
this.deleteConfirmationTarget = null;
|
|
148
|
-
this.statusMessage = `
|
|
148
|
+
this.statusMessage = `Config-profile deletion is disabled in Agent for ${profile.name}. Use /agent profiles for isolated Agent profile homes.`;
|
|
149
149
|
return false;
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -158,7 +158,7 @@ export class ProfilePickerModal {
|
|
|
158
158
|
return false;
|
|
159
159
|
}
|
|
160
160
|
void configManager;
|
|
161
|
-
this.statusMessage = `
|
|
161
|
+
this.statusMessage = `Config-profile saving is disabled in Agent for ${name}. Use /agent profiles to create isolated Agent homes.`;
|
|
162
162
|
return false;
|
|
163
163
|
}
|
|
164
164
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON = 'GoodVibes Agent uses a connected GoodVibes host. Change host lifecycle and bind posture from the owning host; Agent settings are read-only for those controls.';
|
|
2
2
|
|
|
3
3
|
const AGENT_HIDDEN_SETTING_PREFIXES = [
|
|
4
4
|
['cloud', 'flare.'].join(''),
|
|
@@ -21,21 +21,21 @@ const AGENT_HIDDEN_SETTING_KEYS = new Set<string>([
|
|
|
21
21
|
'ui.wrfcMessages',
|
|
22
22
|
]);
|
|
23
23
|
|
|
24
|
-
const
|
|
24
|
+
const EXTERNAL_HOST_SETTING_PREFIXES = [
|
|
25
25
|
'service.',
|
|
26
26
|
'controlPlane.',
|
|
27
27
|
'httpListener.',
|
|
28
28
|
'web.',
|
|
29
29
|
] as const;
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const EXTERNAL_HOST_SETTING_KEYS = new Set<string>([
|
|
32
32
|
'danger.daemon',
|
|
33
33
|
'danger.httpListener',
|
|
34
34
|
]);
|
|
35
35
|
|
|
36
|
-
export function
|
|
37
|
-
return
|
|
38
|
-
||
|
|
36
|
+
export function isExternalHostOwnedSettingKey(key: string): boolean {
|
|
37
|
+
return EXTERNAL_HOST_SETTING_KEYS.has(key)
|
|
38
|
+
|| EXTERNAL_HOST_SETTING_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export function isAgentHiddenSettingKey(key: string): boolean {
|
|
@@ -23,7 +23,7 @@ export function buildSubscriptionEntries(
|
|
|
23
23
|
activeRoute: 'unconfigured',
|
|
24
24
|
authFreshness: 'unconfigured',
|
|
25
25
|
routeReason: 'Built-in subscription adapter is available, but no active subscription session is stored yet.',
|
|
26
|
-
nextActions: [`
|
|
26
|
+
nextActions: [`Open /agent setup and choose Start subscription login for ${provider}.`],
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -38,7 +38,7 @@ export function buildSubscriptionEntries(
|
|
|
38
38
|
activeRoute: providers.get(provider)?.activeRoute ?? 'unconfigured',
|
|
39
39
|
authFreshness: providers.get(provider)?.authFreshness ?? 'unconfigured',
|
|
40
40
|
routeReason: providers.get(provider)?.routeReason ?? 'OAuth metadata is configured for this provider.',
|
|
41
|
-
nextActions: providers.get(provider)?.nextActions ?? [`
|
|
41
|
+
nextActions: providers.get(provider)?.nextActions ?? [`Open /agent setup and choose Start subscription login for ${provider}.`],
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -51,7 +51,7 @@ export function buildSubscriptionEntries(
|
|
|
51
51
|
activeRoute: 'unconfigured',
|
|
52
52
|
authFreshness: 'pending',
|
|
53
53
|
routeReason: 'OAuth login is pending completion for this provider.',
|
|
54
|
-
nextActions: [`Finish
|
|
54
|
+
nextActions: [`Open /agent setup and choose Finish subscription login for ${pending.provider}.`],
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
type SettingsModalOpenOptions,
|
|
35
35
|
type SubscriptionEntry,
|
|
36
36
|
} from './settings-modal-types.ts';
|
|
37
|
-
import {
|
|
37
|
+
import { AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON, isAgentHiddenSettingKey, isExternalHostOwnedSettingKey } from './settings-modal-agent-policy.ts';
|
|
38
38
|
|
|
39
39
|
export {
|
|
40
40
|
SETTINGS_CATEGORIES,
|
|
@@ -50,7 +50,7 @@ export {
|
|
|
50
50
|
type SettingsModalOpenOptions,
|
|
51
51
|
type SubscriptionEntry,
|
|
52
52
|
} from './settings-modal-types.ts';
|
|
53
|
-
export {
|
|
53
|
+
export { AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON, isExternalHostOwnedSettingKey } from './settings-modal-agent-policy.ts';
|
|
54
54
|
export { isAgentHiddenSettingKey } from './settings-modal-agent-policy.ts';
|
|
55
55
|
|
|
56
56
|
// ---------------------------------------------------------------------------
|
|
@@ -352,7 +352,7 @@ export class SettingsModal {
|
|
|
352
352
|
|
|
353
353
|
const entry = this.getSelected();
|
|
354
354
|
if (!entry || !this.configManager) return;
|
|
355
|
-
if (this.
|
|
355
|
+
if (this._blockExternalHostOwnedSetting(entry)) return;
|
|
356
356
|
|
|
357
357
|
const { setting } = entry;
|
|
358
358
|
|
|
@@ -417,7 +417,7 @@ export class SettingsModal {
|
|
|
417
417
|
|
|
418
418
|
const entry = this.getSelected();
|
|
419
419
|
if (!entry || !this.configManager) return;
|
|
420
|
-
if (this.
|
|
420
|
+
if (this._blockExternalHostOwnedSetting(entry)) return;
|
|
421
421
|
const { setting } = entry;
|
|
422
422
|
|
|
423
423
|
if (setting.type === 'boolean') {
|
|
@@ -539,7 +539,7 @@ export class SettingsModal {
|
|
|
539
539
|
|
|
540
540
|
const entry = this.getSelected();
|
|
541
541
|
if (!entry || !this.configManager) return false;
|
|
542
|
-
if (this.
|
|
542
|
+
if (this._blockExternalHostOwnedSetting(entry)) {
|
|
543
543
|
this.editingMode = false;
|
|
544
544
|
this.editBuffer = '';
|
|
545
545
|
return false;
|
|
@@ -590,7 +590,7 @@ export class SettingsModal {
|
|
|
590
590
|
if (this.editingMode || !this.configManager) return null;
|
|
591
591
|
const entry = this.getSelected();
|
|
592
592
|
if (!entry) return null;
|
|
593
|
-
if (this.
|
|
593
|
+
if (this._blockExternalHostOwnedSetting(entry)) return null;
|
|
594
594
|
const key = entry.setting.key as ConfigKey;
|
|
595
595
|
this._setValue(key, entry.setting.default);
|
|
596
596
|
if (isSecretConfigKey(key) && this.secretsManager) {
|
|
@@ -627,16 +627,16 @@ export class SettingsModal {
|
|
|
627
627
|
const cat = rawCat as SettingsCategory;
|
|
628
628
|
const currentValue = configManager.get(setting.key as ConfigKey);
|
|
629
629
|
const resolved = getResolvedSettingLookup(configManager, setting.key as ConfigKey)?.entry;
|
|
630
|
-
const
|
|
630
|
+
const hostOwned = isExternalHostOwnedSettingKey(setting.key);
|
|
631
631
|
const entry: SettingEntry = {
|
|
632
632
|
setting,
|
|
633
633
|
currentValue,
|
|
634
634
|
isDefault: currentValue === setting.default,
|
|
635
635
|
effectiveSource: resolved?.effectiveSource,
|
|
636
|
-
locked:
|
|
636
|
+
locked: hostOwned || resolved?.locked,
|
|
637
637
|
conflict: resolved?.conflict,
|
|
638
638
|
sourceLabel: resolved?.sourceLabel,
|
|
639
|
-
lockReason:
|
|
639
|
+
lockReason: hostOwned ? AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON : resolved?.lockReason,
|
|
640
640
|
};
|
|
641
641
|
if (this.groups.has(cat)) this.groups.get(cat)!.push(entry);
|
|
642
642
|
if ((rawCat === 'controlPlane' || rawCat === 'httpListener' || rawCat === 'web') && this.groups.has('network')) {
|
|
@@ -745,8 +745,8 @@ export class SettingsModal {
|
|
|
745
745
|
|
|
746
746
|
private _setValue(key: ConfigKey, value: unknown): void {
|
|
747
747
|
if (!this.configManager) return;
|
|
748
|
-
if (
|
|
749
|
-
this.lastSettingEffectMessage =
|
|
748
|
+
if (isExternalHostOwnedSettingKey(key)) {
|
|
749
|
+
this.lastSettingEffectMessage = AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON;
|
|
750
750
|
return;
|
|
751
751
|
}
|
|
752
752
|
// Diff previous value before writing — avoids false restart notices on no-op saves
|
|
@@ -787,9 +787,9 @@ export class SettingsModal {
|
|
|
787
787
|
}
|
|
788
788
|
}
|
|
789
789
|
|
|
790
|
-
private
|
|
791
|
-
if (!
|
|
792
|
-
this.lastSettingEffectMessage = entry.lockReason ??
|
|
790
|
+
private _blockExternalHostOwnedSetting(entry: SettingEntry): boolean {
|
|
791
|
+
if (!isExternalHostOwnedSettingKey(entry.setting.key)) return false;
|
|
792
|
+
this.lastSettingEffectMessage = entry.lockReason ?? AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON;
|
|
793
793
|
return true;
|
|
794
794
|
}
|
|
795
795
|
|
package/src/main.ts
CHANGED
|
@@ -11,7 +11,6 @@ import { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
|
11
11
|
import { registerAllTools } from '@pellux/goodvibes-sdk/platform/tools';
|
|
12
12
|
import { FileUndoManager } from '@pellux/goodvibes-sdk/platform/state';
|
|
13
13
|
import { PermissionManager } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
14
|
-
import { AcpManager } from '@pellux/goodvibes-sdk/platform/acp';
|
|
15
14
|
import { PermissionPromptUI } from './permissions/prompt.ts';
|
|
16
15
|
import { CommandRegistry } from './input/command-registry.ts';
|
|
17
16
|
import type { CommandContext } from './input/command-registry.ts';
|
|
@@ -114,7 +113,6 @@ async function main() {
|
|
|
114
113
|
sessionLineageTracker: ctx.services.sessionLineageTracker,
|
|
115
114
|
idempotencyStore: ctx.services.idempotencyStore,
|
|
116
115
|
});
|
|
117
|
-
ctx.services.wrfcController.setPlanManager(ctx.services.planManager);
|
|
118
116
|
let activeConversationWidth = stdout.columns || 80;
|
|
119
117
|
conversation.setWidthProvider(() => activeConversationWidth);
|
|
120
118
|
{
|
|
@@ -102,9 +102,9 @@ export class AutomationControlPanel extends ScrollableListPanel<AutomationRun> {
|
|
|
102
102
|
sections: [{
|
|
103
103
|
lines: buildEmptyState(
|
|
104
104
|
width,
|
|
105
|
-
'
|
|
106
|
-
'
|
|
107
|
-
[{ command: '/schedule list', summary: 'review automation
|
|
105
|
+
' Connected-host automation state is unavailable.',
|
|
106
|
+
'Use /schedule list for the supported Agent schedule summary. This deferred panel does not start or mutate automation.',
|
|
107
|
+
[{ command: '/schedule list', summary: 'review automation without starting hidden work' }],
|
|
108
108
|
C,
|
|
109
109
|
),
|
|
110
110
|
}],
|
|
@@ -80,7 +80,7 @@ export function registerAgentPanels(manager: PanelManager, deps: ResolvedBuiltin
|
|
|
80
80
|
name: 'Schedule',
|
|
81
81
|
icon: 'Z',
|
|
82
82
|
category: 'agent',
|
|
83
|
-
description: 'Read-only schedule posture from connected GoodVibes
|
|
83
|
+
description: 'Read-only schedule posture from the connected GoodVibes host; local Agent schedule mutation is blocked',
|
|
84
84
|
factory: () => new SchedulePanel(requireAutomationManager(deps)),
|
|
85
85
|
});
|
|
86
86
|
}
|
|
@@ -45,7 +45,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
|
|
|
45
45
|
name: 'Automation',
|
|
46
46
|
icon: 'M',
|
|
47
47
|
category: 'monitoring',
|
|
48
|
-
description: 'Read-only automation jobs, runs, deliveries, and failure posture from connected GoodVibes
|
|
48
|
+
description: 'Read-only automation jobs, runs, deliveries, and failure posture from the connected GoodVibes host',
|
|
49
49
|
factory: () => new AutomationControlPanel(ui.readModels.automation),
|
|
50
50
|
});
|
|
51
51
|
|
|
@@ -81,7 +81,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
|
|
|
81
81
|
name: 'Tasks',
|
|
82
82
|
icon: 'J',
|
|
83
83
|
category: 'monitoring',
|
|
84
|
-
description: 'Queued, running, blocked, failed, and completed task summaries from connected GoodVibes
|
|
84
|
+
description: 'Queued, running, blocked, failed, and completed task summaries from the connected GoodVibes host',
|
|
85
85
|
factory: () => new TasksPanel(ui.readModels.tasks),
|
|
86
86
|
});
|
|
87
87
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { networkInterfaces } from 'node:os';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import type { PanelManager } from '../panel-manager.ts';
|
|
4
4
|
import { SessionBrowserPanel } from '../session-browser-panel.ts';
|
|
5
5
|
import { QrPanel } from '../qr-panel.ts';
|
|
@@ -9,8 +9,6 @@ import { TokenBudgetPanel } from '../token-budget-panel.ts';
|
|
|
9
9
|
import type { ResolvedBuiltinPanelDeps } from './shared.ts';
|
|
10
10
|
import { requireUiServices } from './shared.ts';
|
|
11
11
|
import {
|
|
12
|
-
getOrCreateCompanionToken,
|
|
13
|
-
regenerateCompanionToken,
|
|
14
12
|
buildCompanionConnectionInfo,
|
|
15
13
|
} from '@pellux/goodvibes-sdk/platform/pairing';
|
|
16
14
|
import { copyToClipboard } from '../../utils/clipboard.ts';
|
|
@@ -42,6 +40,18 @@ function readBootstrapPassword(credentialPath: string): string | undefined {
|
|
|
42
40
|
return undefined;
|
|
43
41
|
}
|
|
44
42
|
|
|
43
|
+
function readOperatorToken(tokenPath: string): string | null {
|
|
44
|
+
if (!existsSync(tokenPath)) return null;
|
|
45
|
+
try {
|
|
46
|
+
const parsed = JSON.parse(readFileSync(tokenPath, 'utf-8')) as unknown;
|
|
47
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
|
|
48
|
+
const token = (parsed as Record<string, unknown>)['token'];
|
|
49
|
+
return typeof token === 'string' && token.trim().length > 0 ? token : null;
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
45
55
|
export function registerSessionPanels(manager: PanelManager, deps: ResolvedBuiltinPanelDeps): void {
|
|
46
56
|
manager.registerType({
|
|
47
57
|
id: 'qr-code',
|
|
@@ -51,28 +61,26 @@ export function registerSessionPanels(manager: PanelManager, deps: ResolvedBuilt
|
|
|
51
61
|
description: 'QR code for companion app pairing — scan to connect a mobile or desktop companion',
|
|
52
62
|
factory: () => {
|
|
53
63
|
if (!deps.daemonHomeDir) throw new Error('daemonHomeDir must be provided to the session panel factory via BuiltinPanelDeps');
|
|
54
|
-
const
|
|
55
|
-
const tokenRecord = getOrCreateCompanionToken(GOODVIBES_AGENT_PAIRING_SURFACE, { daemonHomeDir });
|
|
64
|
+
const token = readOperatorToken(`${deps.daemonHomeDir}/operator-tokens.json`);
|
|
56
65
|
const daemonPort = deps.configManager.get('controlPlane.port');
|
|
57
66
|
const daemonHost = String(process.env['GOODVIBES_DAEMON_HOST'] ?? getLocalNetworkIp());
|
|
58
67
|
const daemonUrl = `http://${daemonHost}:${daemonPort}`;
|
|
59
68
|
const bootstrapPassword = readBootstrapPassword(deps.localUserAuthManager.getBootstrapCredentialPath());
|
|
60
|
-
const connectionInfo =
|
|
61
|
-
|
|
62
|
-
token: tokenRecord.token,
|
|
63
|
-
password: bootstrapPassword,
|
|
64
|
-
surface: GOODVIBES_AGENT_PAIRING_SURFACE,
|
|
65
|
-
});
|
|
66
|
-
const regenerate = (): typeof connectionInfo => {
|
|
67
|
-
const newRecord = regenerateCompanionToken({ daemonHomeDir });
|
|
68
|
-
return buildCompanionConnectionInfo({
|
|
69
|
+
const connectionInfo = token
|
|
70
|
+
? buildCompanionConnectionInfo({
|
|
69
71
|
daemonUrl,
|
|
70
|
-
token
|
|
72
|
+
token,
|
|
71
73
|
password: bootstrapPassword,
|
|
72
74
|
surface: GOODVIBES_AGENT_PAIRING_SURFACE,
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
})
|
|
76
|
+
: {
|
|
77
|
+
url: daemonUrl,
|
|
78
|
+
token: '',
|
|
79
|
+
username: 'admin',
|
|
80
|
+
...(bootstrapPassword !== undefined ? { password: bootstrapPassword } : {}),
|
|
81
|
+
surface: GOODVIBES_AGENT_PAIRING_SURFACE,
|
|
82
|
+
};
|
|
83
|
+
return new QrPanel(connectionInfo, undefined, copyToClipboard);
|
|
76
84
|
},
|
|
77
85
|
});
|
|
78
86
|
|
|
@@ -80,13 +80,13 @@ export interface BuiltinPanelDeps {
|
|
|
80
80
|
tokenAuditor: ApiTokenAuditor;
|
|
81
81
|
/** Shared component-health monitor for rate-limited panels and diagnostics. */
|
|
82
82
|
componentHealthMonitor: ComponentHealthMonitor;
|
|
83
|
-
/**
|
|
83
|
+
/** Copied shell dependency kept inert in Agent; build worktree UX belongs to GoodVibes TUI delegation. */
|
|
84
84
|
worktreeRegistry: WorktreeRegistry;
|
|
85
|
-
/**
|
|
85
|
+
/** Isolation session registry used by MCP internals; Agent does not expose local execution-isolation command UX. */
|
|
86
86
|
sandboxSessionRegistry: SandboxSessionRegistry;
|
|
87
87
|
/**
|
|
88
|
-
* Resolved
|
|
89
|
-
* and passed explicitly so panel factories do not discover cwd/home implicitly.
|
|
88
|
+
* Resolved connected-host token directory (e.g. `~/.goodvibes/daemon`) — owned by the
|
|
89
|
+
* composition root and passed explicitly so panel factories do not discover cwd/home implicitly.
|
|
90
90
|
*/
|
|
91
91
|
daemonHomeDir?: string;
|
|
92
92
|
/** Session memory store for context and token budget panels. */
|
|
@@ -103,7 +103,7 @@ export interface BuiltinPanelDeps {
|
|
|
103
103
|
workPlanStore?: import('../../work-plans/work-plan-store.ts').WorkPlanStore;
|
|
104
104
|
/** Shared system-messages panel instance attached from boot so low-priority chatter stays out of conversation. */
|
|
105
105
|
systemMessagesPanel?: import('../system-messages-panel.ts').SystemMessagesPanel;
|
|
106
|
-
/** Explicit UI-facing runtime services for
|
|
106
|
+
/** Explicit UI-facing runtime services for operator panels and modals. */
|
|
107
107
|
uiServices?: UiRuntimeServices;
|
|
108
108
|
/** Shared plugin manager observer for plugin and security panels. */
|
|
109
109
|
pluginManager?: PluginManagerObserver;
|
|
@@ -240,7 +240,7 @@ export function requireAutomationManager(deps: BuiltinPanelDeps): AutomationMana
|
|
|
240
240
|
|
|
241
241
|
export function requireUiServices(deps: BuiltinPanelDeps): UiRuntimeServices {
|
|
242
242
|
if (!deps.uiServices) {
|
|
243
|
-
throw new Error('UI runtime services must be wired at bootstrap for
|
|
243
|
+
throw new Error('UI runtime services must be wired at bootstrap for operator panels.');
|
|
244
244
|
}
|
|
245
245
|
return deps.uiServices;
|
|
246
246
|
}
|
|
@@ -600,7 +600,7 @@ export class ProjectPlanningPanel extends BasePanel {
|
|
|
600
600
|
return;
|
|
601
601
|
}
|
|
602
602
|
if (!this.submitAnswer) {
|
|
603
|
-
this.setError('Planning answer submission is
|
|
603
|
+
this.setError('Planning answer submission is unavailable in this Agent runtime. Return to the composer and answer there.');
|
|
604
604
|
this.requestRender();
|
|
605
605
|
return;
|
|
606
606
|
}
|
|
@@ -46,11 +46,11 @@ export function buildProviderHealthDomainSummaries(
|
|
|
46
46
|
name: 'auth',
|
|
47
47
|
level: auth.bootstrapCredentialPresent ? 'warn' : 'info',
|
|
48
48
|
summary: auth.bootstrapCredentialPresent
|
|
49
|
-
? 'connected-
|
|
50
|
-
: 'connected-
|
|
49
|
+
? 'connected-host bootstrap credential visible in local compatibility state'
|
|
50
|
+
: 'connected-host auth administration belongs outside Agent',
|
|
51
51
|
next: '/auth review',
|
|
52
52
|
details: [
|
|
53
|
-
'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-
|
|
53
|
+
'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-host auth users or sessions.',
|
|
54
54
|
`${auth.userCount} compatibility user record(s) and ${auth.sessionCount} session record(s) are visible for diagnostics only.`,
|
|
55
55
|
auth.bootstrapCredentialPresent ? 'Bootstrap cleanup must be done in the owning GoodVibes host.' : '',
|
|
56
56
|
].filter(Boolean),
|
package/src/panels/qr-panel.ts
CHANGED
|
@@ -79,13 +79,15 @@ export class QrPanel extends BasePanel {
|
|
|
79
79
|
this.connectionInfo = this.regenerateToken();
|
|
80
80
|
this.lastStatus = 'Token regenerated.';
|
|
81
81
|
} else {
|
|
82
|
-
this.lastStatus = '
|
|
82
|
+
this.lastStatus = 'Token rotation belongs to the connected host.';
|
|
83
83
|
}
|
|
84
84
|
this.markDirty();
|
|
85
85
|
return true;
|
|
86
86
|
}
|
|
87
87
|
if (key === 'c') {
|
|
88
|
-
if (this.
|
|
88
|
+
if (!this.connectionInfo.token) {
|
|
89
|
+
this.lastStatus = 'No connected-host token is available to copy.';
|
|
90
|
+
} else if (this.copyToClipboard) {
|
|
89
91
|
this.copyToClipboard(this.connectionInfo.token);
|
|
90
92
|
this.lastStatus = 'Token copied to clipboard.';
|
|
91
93
|
} else {
|
|
@@ -134,18 +136,36 @@ export class QrPanel extends BasePanel {
|
|
|
134
136
|
lines.push(createEmptyLine(width));
|
|
135
137
|
|
|
136
138
|
// ── QR code ────────────────────────────────────────────────────────────
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
139
|
+
if (this.connectionInfo.token) {
|
|
140
|
+
const payload = encodeConnectionPayload({
|
|
141
|
+
url: this.connectionInfo.url,
|
|
142
|
+
token: this.connectionInfo.token,
|
|
143
|
+
username: this.connectionInfo.username,
|
|
144
|
+
...(this.connectionInfo.password !== undefined ? { password: this.connectionInfo.password } : {}),
|
|
145
|
+
version: this.connectionInfo.version ?? '0.0.0',
|
|
146
|
+
surface: this.connectionInfo.surface ?? GOODVIBES_AGENT_PAIRING_SURFACE,
|
|
147
|
+
});
|
|
148
|
+
const matrix = generateQrMatrix(payload);
|
|
149
|
+
const qrLines = renderQrMatrix(matrix.modules, width, { fg: C.qrFg, bg: C.qrBg });
|
|
150
|
+
for (const qrLine of qrLines) {
|
|
151
|
+
lines.push(qrLine);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
lines.push(
|
|
155
|
+
buildPanelLine(width, [
|
|
156
|
+
[' Pairing unavailable ', C.hint],
|
|
157
|
+
]),
|
|
158
|
+
);
|
|
159
|
+
lines.push(
|
|
160
|
+
buildPanelLine(width, [
|
|
161
|
+
[' Connected-host operator token is missing. Agent does not create or rotate host auth tokens. ', C.dim],
|
|
162
|
+
]),
|
|
163
|
+
);
|
|
164
|
+
lines.push(
|
|
165
|
+
buildPanelLine(width, [
|
|
166
|
+
[' Start or repair the owning GoodVibes host, then reopen this panel. ', C.dim],
|
|
167
|
+
]),
|
|
168
|
+
);
|
|
149
169
|
}
|
|
150
170
|
|
|
151
171
|
lines.push(createEmptyLine(width));
|
|
@@ -160,12 +180,16 @@ export class QrPanel extends BasePanel {
|
|
|
160
180
|
}
|
|
161
181
|
|
|
162
182
|
// ── Hints ──────────────────────────────────────────────────────────────
|
|
163
|
-
const
|
|
164
|
-
[
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
183
|
+
const hintParts: Array<[string, string]> = this.connectionInfo.token
|
|
184
|
+
? [
|
|
185
|
+
[' c ', C.hint],
|
|
186
|
+
['copy token', C.dim],
|
|
187
|
+
]
|
|
188
|
+
: [
|
|
189
|
+
[' h ', C.hint],
|
|
190
|
+
['host auth required', C.dim],
|
|
191
|
+
];
|
|
192
|
+
const hintsLine = buildPanelLine(width, hintParts);
|
|
169
193
|
|
|
170
194
|
// Push hints at the bottom if we have room, otherwise append after QR
|
|
171
195
|
const remaining = height - lines.length;
|
|
@@ -79,8 +79,8 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
|
|
|
79
79
|
protected override getEmptyStateActions() {
|
|
80
80
|
return [
|
|
81
81
|
{ command: '/subscription login openai start --yes', summary: 'start the first-class OpenAI subscription flow' },
|
|
82
|
-
{ command: '/login provider <
|
|
83
|
-
{ command: '/auth review', summary: 'inspect connected-
|
|
82
|
+
{ command: '/subscription login <provider> finish <code> --yes', summary: 'finish a pending provider subscription login' },
|
|
83
|
+
{ command: '/auth review', summary: 'inspect connected-host auth posture without exposing token values' },
|
|
84
84
|
];
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -196,7 +196,7 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
|
|
|
196
196
|
const emptyLines = buildEmptyState(
|
|
197
197
|
width,
|
|
198
198
|
this.getEmptyStateMessage(),
|
|
199
|
-
'Built-in OAuth-capable providers and configured
|
|
199
|
+
'Built-in OAuth-capable providers and configured provider routes will appear here once available for browser login or session import.',
|
|
200
200
|
this.getEmptyStateActions(),
|
|
201
201
|
C,
|
|
202
202
|
);
|
|
@@ -171,9 +171,9 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
|
|
|
171
171
|
buildKeyValueLine(width, [
|
|
172
172
|
{ label: 'system route', value: ui.systemMessages, valueColor: C.info },
|
|
173
173
|
{ label: 'ops route', value: ui.operationalMessages, valueColor: C.info },
|
|
174
|
-
{ label: '
|
|
174
|
+
{ label: 'review route', value: ui.wrfcMessages, valueColor: C.info },
|
|
175
175
|
], C),
|
|
176
|
-
buildGuidanceLine(width, '/settings', 'adjust where operational and
|
|
176
|
+
buildGuidanceLine(width, '/settings', 'adjust where operational and delegated review/build messages render across panels and conversation', C),
|
|
177
177
|
];
|
|
178
178
|
|
|
179
179
|
const selected = this._messages[this.selectedIndex]!;
|
|
@@ -183,9 +183,9 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
|
|
|
183
183
|
sections: [{
|
|
184
184
|
lines: buildEmptyState(
|
|
185
185
|
width,
|
|
186
|
-
'
|
|
187
|
-
'Use
|
|
188
|
-
[{ command: '/tasks', summary: 'inspect connected-
|
|
186
|
+
' Connected-host task state is unavailable.',
|
|
187
|
+
'Use /tasks list for the supported Agent task summary. This deferred panel does not start or mutate task execution.',
|
|
188
|
+
[{ command: '/tasks', summary: 'inspect connected-host tasks without launching local workers' }],
|
|
189
189
|
C,
|
|
190
190
|
),
|
|
191
191
|
}],
|
|
@@ -235,7 +235,7 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
|
|
|
235
235
|
]));
|
|
236
236
|
}
|
|
237
237
|
postureLines.push(
|
|
238
|
-
buildGuidanceLine(width, '/tasks', 'inspect
|
|
238
|
+
buildGuidanceLine(width, '/tasks', 'inspect connected-host task posture without launching local workers', C),
|
|
239
239
|
buildGuidanceLine(width, '/delegate <task>', 'delegate explicit build/fix/review work to GoodVibes TUI when code execution is required', C),
|
|
240
240
|
);
|
|
241
241
|
|
|
@@ -288,7 +288,7 @@ export class ProjectPlanningCoordinator {
|
|
|
288
288
|
const cleanGoal = goal.trim() || 'the requested change';
|
|
289
289
|
return [
|
|
290
290
|
`First pass: make "${cleanGoal}" work end-to-end for the primary local TUI workflow.`,
|
|
291
|
-
'Include the minimum TUI,
|
|
291
|
+
'Include the minimum TUI, connected-host wiring, configuration persistence, documentation, and verification required for the feature to actually work.',
|
|
292
292
|
'Exclude unrelated cleanup, broad refactors, polish-only changes, third-party integrations, and advanced distributed behavior unless they directly block the primary workflow.',
|
|
293
293
|
].join(' ');
|
|
294
294
|
}
|
|
@@ -344,7 +344,7 @@ export class ProjectPlanningCoordinator {
|
|
|
344
344
|
{
|
|
345
345
|
id: 'wire-user-surface',
|
|
346
346
|
title: `Wire the user-facing path for ${cleanGoal}`,
|
|
347
|
-
why: 'The feature must be reachable through the intended TUI/
|
|
347
|
+
why: 'The feature must be reachable through the intended TUI/connected-host/config surface, not just internal code.',
|
|
348
348
|
status: 'pending',
|
|
349
349
|
dependencies: ['implement-core-behavior'],
|
|
350
350
|
verification: ['A command, panel, route, or setting path exercises the behavior from the user-facing entry point.'],
|