@pellux/goodvibes-agent 0.1.116 → 1.0.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 +48 -661
- package/README.md +64 -57
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +199180 -192185
- package/docs/README.md +15 -8
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +59 -0
- package/docs/getting-started.md +61 -50
- package/docs/knowledge-artifacts-and-multimodal.md +91 -0
- package/docs/project-planning.md +79 -0
- package/docs/providers-and-routing.md +46 -0
- package/docs/release-and-publishing.md +48 -11
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +3 -6
- package/src/agent/behavior-discovery-summary.ts +1 -3
- package/src/agent/channel-delivery.ts +201 -0
- package/src/agent/media-generation.ts +159 -0
- package/src/agent/memory-prompt.ts +0 -1
- package/src/agent/note-registry.ts +329 -0
- package/src/agent/operator-actions.ts +343 -0
- package/src/agent/persona-discovery.ts +1 -3
- package/src/agent/persona-registry.ts +19 -16
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +27 -26
- package/src/agent/routine-registry.ts +54 -14
- package/src/agent/routine-schedule-args.ts +2 -1
- package/src/agent/routine-schedule-format.ts +77 -53
- package/src/agent/routine-schedule-promotion.ts +35 -33
- package/src/agent/routine-schedule-receipts.ts +29 -27
- package/src/agent/runtime-profile-starters.ts +5 -5
- package/src/agent/runtime-profile.ts +91 -12
- package/src/agent/skill-registry.ts +210 -32
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +40 -34
- package/src/cli/agent-knowledge-format.ts +80 -67
- package/src/cli/agent-knowledge-methods.ts +1 -1
- package/src/cli/agent-knowledge-runtime.ts +32 -26
- package/src/cli/bundle-command.ts +14 -9
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/entrypoint.ts +16 -7
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +54 -29
- package/src/cli/local-library-command.ts +203 -83
- package/src/cli/management-commands.ts +105 -68
- package/src/cli/management.ts +55 -74
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -3
- package/src/cli/profiles-command.ts +166 -31
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +176 -40
- package/src/cli/service-posture.ts +16 -16
- package/src/cli/status.ts +56 -135
- package/src/core/conversation-message-snapshot.ts +131 -0
- 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 +35 -8
- package/src/input/agent-workspace-basic-command-editor-submission.ts +351 -94
- package/src/input/agent-workspace-basic-command-editors.ts +502 -9
- package/src/input/agent-workspace-categories.ts +423 -51
- package/src/input/agent-workspace-channel-command-editor-submission.ts +83 -0
- package/src/input/agent-workspace-channel-command-editors.ts +65 -0
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +41 -3
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
- package/src/input/agent-workspace-editors.ts +166 -1
- 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-knowledge-query-editor.ts +1 -1
- 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-local-operations.ts +218 -0
- package/src/input/agent-workspace-local-selection.ts +75 -0
- package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
- package/src/input/agent-workspace-media-command-editors.ts +27 -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-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +81 -0
- package/src/input/agent-workspace-notify-editor-submission.ts +121 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +208 -0
- package/src/input/agent-workspace-operations-command-editors.ts +196 -0
- package/src/input/agent-workspace-panel-route.ts +43 -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-reminder-schedule-editor.ts +1 -1
- package/src/input/agent-workspace-requirements.ts +11 -0
- package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
- package/src/input/agent-workspace-search.ts +169 -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 +37 -16
- 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 +162 -21
- 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-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +212 -4
- package/src/input/agent-workspace-voice-media.ts +4 -7
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
- package/src/input/agent-workspace.ts +178 -240
- package/src/input/command-registry.ts +5 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +126 -37
- package/src/input/commands/agent-skills-runtime.ts +149 -72
- package/src/input/commands/agent-workspace-runtime.ts +23 -6
- package/src/input/commands/brief-runtime.ts +55 -25
- package/src/input/commands/channels-runtime.ts +147 -33
- package/src/input/commands/compat-runtime.ts +32 -0
- package/src/input/commands/delegation-runtime.ts +29 -23
- package/src/input/commands/experience-runtime.ts +6 -4
- package/src/input/commands/guidance-runtime.ts +4 -4
- package/src/input/commands/health-runtime.ts +149 -126
- package/src/input/commands/knowledge.ts +82 -60
- package/src/input/commands/local-provider-runtime.ts +43 -21
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +10 -20
- package/src/input/commands/mcp-runtime.ts +63 -46
- package/src/input/commands/notify-runtime.ts +38 -9
- package/src/input/commands/operator-actions-runtime.ts +138 -0
- package/src/input/commands/operator-runtime.ts +6 -76
- package/src/input/commands/personas-runtime.ts +46 -31
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +35 -98
- package/src/input/commands/product-runtime.ts +2 -2
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +50 -9
- package/src/input/commands/recall-bundle.ts +11 -11
- package/src/input/commands/recall-capture.ts +13 -11
- package/src/input/commands/recall-query.ts +29 -21
- package/src/input/commands/recall-review.ts +2 -1
- package/src/input/commands/routines-runtime.ts +99 -45
- package/src/input/commands/runtime-services.ts +1 -14
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +6 -11
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +134 -104
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +38 -17
- package/src/input/commands/subscription-runtime.ts +54 -185
- package/src/input/commands/support-bundle-runtime.ts +53 -0
- package/src/input/commands/tasks-runtime.ts +21 -21
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +6 -2
- package/src/input/feed-context-factory.ts +2 -2
- package/src/input/file-picker.ts +3 -2
- package/src/input/handler-command-route.ts +4 -7
- package/src/input/handler-content-actions.ts +89 -26
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -5
- package/src/input/handler-interactions.ts +9 -36
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +52 -91
- package/src/input/handler-shortcuts.ts +16 -7
- package/src/input/handler.ts +50 -23
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +27 -16
- 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 +62 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +223 -55
- package/src/input/onboarding/onboarding-wizard-steps.ts +59 -35
- package/src/input/onboarding/onboarding-wizard-types.ts +4 -1
- package/src/input/onboarding/onboarding-wizard.ts +87 -2
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +21 -4
- package/src/input/settings-modal-agent-policy.ts +6 -6
- package/src/input/settings-modal-behavior.ts +0 -3
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal-types.ts +2 -13
- package/src/input/settings-modal.ts +20 -66
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -10
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +4 -4
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +3 -12
- package/src/panels/builtin/session.ts +32 -24
- package/src/panels/builtin/shared.ts +7 -7
- package/src/panels/cost-tracker-panel.ts +1 -1
- package/src/panels/docs-panel.ts +5 -3
- package/src/panels/index.ts +0 -1
- package/src/panels/knowledge-panel.ts +6 -5
- package/src/panels/memory-panel.ts +7 -6
- package/src/panels/panel-list-panel.ts +36 -80
- package/src/panels/project-planning-panel.ts +19 -12
- package/src/panels/provider-account-snapshot.ts +51 -25
- package/src/panels/provider-accounts-panel.ts +33 -18
- package/src/panels/provider-health-domains.ts +48 -7
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +44 -20
- package/src/panels/schedule-panel.ts +9 -17
- package/src/panels/security-panel.ts +8 -8
- package/src/panels/session-browser-panel.ts +10 -10
- package/src/panels/subscription-panel.ts +6 -6
- package/src/panels/system-messages-panel.ts +3 -3
- package/src/panels/tasks-panel.ts +21 -14
- package/src/panels/tool-inspector-panel.ts +19 -12
- package/src/panels/work-plan-panel.ts +5 -5
- package/src/planning/project-planning-coordinator.ts +3 -3
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +254 -57
- package/src/renderer/autocomplete-overlay.ts +25 -6
- package/src/renderer/block-actions.ts +1 -3
- package/src/renderer/bookmark-modal.ts +19 -4
- package/src/renderer/buffer.ts +4 -2
- package/src/renderer/context-inspector.ts +50 -13
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +19 -6
- package/src/renderer/help-overlay.ts +112 -34
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +176 -43
- package/src/renderer/model-picker-overlay.ts +58 -3
- package/src/renderer/model-workspace.ts +104 -22
- package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +21 -5
- package/src/renderer/search-overlay.ts +25 -5
- package/src/renderer/selection-modal-overlay.ts +46 -14
- package/src/renderer/session-picker-modal.ts +18 -1
- package/src/renderer/settings-modal-helpers.ts +2 -40
- package/src/renderer/settings-modal.ts +88 -55
- package/src/renderer/system-message.ts +1 -1
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +129 -0
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +11 -8
- package/src/runtime/bootstrap-core.ts +23 -65
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +46 -8
- package/src/runtime/bootstrap.ts +36 -46
- package/src/runtime/connected-host-auth.ts +47 -0
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -5
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +288 -74
- package/src/runtime/onboarding/derivation.ts +10 -13
- package/src/runtime/onboarding/snapshot.ts +2 -17
- package/src/runtime/onboarding/types.ts +34 -20
- package/src/runtime/onboarding/verify.ts +105 -4
- package/src/runtime/operator-token-cleanup.ts +3 -3
- package/src/runtime/services.ts +95 -11
- package/src/runtime/store/selectors/index.ts +3 -3
- package/src/runtime/store/state.ts +1 -4
- package/src/runtime/surface-feature-flags.ts +41 -6
- package/src/runtime/ui-read-models.ts +3 -4
- package/src/runtime/ui-services.ts +6 -6
- package/src/shell/blocking-input.ts +2 -1
- package/src/shell/service-settings-sync.ts +7 -7
- package/src/shell/ui-openers.ts +17 -38
- package/src/tools/agent-analysis-registry-policy.ts +0 -1
- package/src/tools/agent-channel-send-tool.ts +133 -0
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
- package/src/tools/agent-knowledge-tool.ts +170 -0
- package/src/tools/agent-local-registry-tool.ts +279 -73
- package/src/tools/agent-media-generate-tool.ts +133 -0
- package/src/tools/agent-notify-tool.ts +143 -0
- package/src/tools/agent-operator-action-tool.ts +137 -0
- package/src/tools/agent-operator-briefing-tool.ts +217 -0
- package/src/tools/agent-reminder-schedule-tool.ts +237 -0
- package/src/tools/agent-tool-policy-guard.ts +13 -15
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/docs/connected-services.md +0 -51
- package/src/cli/package-verification.ts +0 -274
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -17
- package/src/panels/panel-picker.ts +0 -105
- package/src/panels/policy-panel.ts +0 -308
- package/src/renderer/panel-picker-overlay.ts +0 -202
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentWorkspace,
|
|
3
3
|
AgentWorkspaceAction,
|
|
4
|
-
AgentWorkspaceActionResult,
|
|
5
4
|
AgentWorkspaceCategory,
|
|
6
5
|
AgentWorkspaceLocalEditor,
|
|
7
6
|
AgentWorkspaceRuntimeSnapshot,
|
|
8
7
|
} from '../input/agent-workspace.ts';
|
|
8
|
+
import { formatAgentRecordReviewState, formatAgentRecordSource } from '../agent/record-labels.ts';
|
|
9
9
|
import type { Line } from '../types/grid.ts';
|
|
10
10
|
import { wrapText } from '../utils/terminal-width.ts';
|
|
11
11
|
import { GLYPHS } from './ui-primitives.ts';
|
|
@@ -17,20 +17,7 @@ import {
|
|
|
17
17
|
WORKSPACE_PALETTE as PALETTE,
|
|
18
18
|
type WorkspaceRow,
|
|
19
19
|
} from './fullscreen-workspace.ts';
|
|
20
|
-
|
|
21
|
-
function safetyColor(action: AgentWorkspaceAction): string {
|
|
22
|
-
if (action.safety === 'safe') return PALETTE.good;
|
|
23
|
-
if (action.safety === 'read-only') return PALETTE.info;
|
|
24
|
-
if (action.safety === 'delegates') return PALETTE.warn;
|
|
25
|
-
return PALETTE.bad;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function actionResultColor(result: AgentWorkspaceActionResult): string {
|
|
29
|
-
if (result.kind === 'blocked' || result.kind === 'error') return PALETTE.bad;
|
|
30
|
-
if (result.kind === 'dispatched') return PALETTE.info;
|
|
31
|
-
if (result.kind === 'refreshed') return PALETTE.good;
|
|
32
|
-
return PALETTE.muted;
|
|
33
|
-
}
|
|
20
|
+
import { actionResultColor, safetyColor, setupStatusColor, type AgentWorkspaceContextLine as ContextLine } from './agent-workspace-style.ts';
|
|
34
21
|
|
|
35
22
|
function buildLeftRows(workspace: AgentWorkspace, height: number): WorkspaceRow[] {
|
|
36
23
|
const rows: WorkspaceRow[] = [];
|
|
@@ -75,15 +62,6 @@ function actionCommand(action: AgentWorkspaceAction): string {
|
|
|
75
62
|
return action.command ?? '(guidance)';
|
|
76
63
|
}
|
|
77
64
|
|
|
78
|
-
type ContextLine = { readonly text: string; readonly fg?: string; readonly bold?: boolean; readonly dim?: boolean };
|
|
79
|
-
|
|
80
|
-
function setupStatusColor(status: AgentWorkspaceRuntimeSnapshot['setupChecklist'][number]['status']): string {
|
|
81
|
-
if (status === 'ready') return PALETTE.good;
|
|
82
|
-
if (status === 'recommended') return PALETTE.warn;
|
|
83
|
-
if (status === 'blocked') return PALETTE.bad;
|
|
84
|
-
return PALETTE.muted;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
65
|
function setupChecklistLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
88
66
|
const readyCount = snapshot.setupChecklist.filter((item) => item.status === 'ready').length;
|
|
89
67
|
const recommendedCount = snapshot.setupChecklist.filter((item) => item.status === 'recommended').length;
|
|
@@ -104,22 +82,60 @@ function setupChecklistLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLi
|
|
|
104
82
|
return lines;
|
|
105
83
|
}
|
|
106
84
|
|
|
107
|
-
function
|
|
85
|
+
function homeNextActionLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
86
|
+
const blocked = snapshot.setupChecklist.filter((item) => item.status === 'blocked');
|
|
87
|
+
const recommended = snapshot.setupChecklist.filter((item) => item.status === 'recommended');
|
|
88
|
+
const optional = snapshot.setupChecklist.filter((item) => item.status === 'optional');
|
|
89
|
+
const candidates = [...blocked, ...recommended, ...optional].slice(0, 5);
|
|
90
|
+
if (candidates.length === 0) {
|
|
91
|
+
return [
|
|
92
|
+
{ text: 'Next Actions', fg: PALETTE.title, bold: true },
|
|
93
|
+
{ text: 'Core setup is ready. Continue normal assistant work, review Knowledge sources, or tune local skills/routines as needed.', fg: PALETTE.good },
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
const lines: ContextLine[] = [{ text: 'Next Actions', fg: PALETTE.title, bold: true }];
|
|
97
|
+
for (const item of candidates) {
|
|
98
|
+
const command = item.command ? ` -> ${item.command}` : '';
|
|
99
|
+
lines.push({
|
|
100
|
+
text: `${item.status.toUpperCase()} ${item.label}${command}`,
|
|
101
|
+
fg: setupStatusColor(item.status),
|
|
102
|
+
bold: item.status === 'blocked',
|
|
103
|
+
});
|
|
104
|
+
lines.push({ text: ` ${item.detail}`, fg: PALETTE.muted });
|
|
105
|
+
}
|
|
106
|
+
return lines;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function companionAccessLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
|
|
110
|
+
const access = snapshot.companionAccess;
|
|
111
|
+
const tokenState = access.tokenReadable
|
|
112
|
+
? `ready sha256:${access.tokenFingerprint ?? 'unknown'}`
|
|
113
|
+
: access.tokenPresent
|
|
114
|
+
? 'present but unreadable'
|
|
115
|
+
: 'missing';
|
|
116
|
+
const error = access.tokenError ? `; token read error ${access.tokenError}` : '';
|
|
117
|
+
return {
|
|
118
|
+
text: `Companion: ${access.surface}; token ${tokenState}; QR ${access.qrCommand}; manual token text hidden${error}.`,
|
|
119
|
+
fg: access.pairingReady ? PALETTE.good : PALETTE.warn,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function discoverySummaryLine(label: string, summary: AgentWorkspaceRuntimeSnapshot['discoveredBehavior']['personas'], actionLabel: string): ContextLine[] {
|
|
108
124
|
if (summary.count === 0) return [];
|
|
109
125
|
const names = summary.names.length > 0
|
|
110
126
|
? ` ${summary.names.join(', ')}${summary.count > summary.names.length ? `, +${summary.count - summary.names.length} more` : ''}.`
|
|
111
127
|
: '';
|
|
112
128
|
return [
|
|
113
129
|
{ text: `${label}: ${summary.count} discovered; project ${summary.projectLocalCount}; global ${summary.globalCount}.`, fg: PALETTE.info, bold: true },
|
|
114
|
-
{ text: ` ${
|
|
130
|
+
{ text: ` Choose ${actionLabel} to preview, then use the import form after review.${names}`, fg: PALETTE.muted },
|
|
115
131
|
];
|
|
116
132
|
}
|
|
117
133
|
|
|
118
134
|
function behaviorDiscoveryLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
119
135
|
const lines: ContextLine[] = [
|
|
120
|
-
...discoverySummaryLine('Discovered personas', snapshot.discoveredBehavior.personas, '
|
|
121
|
-
...discoverySummaryLine('Discovered skills', snapshot.discoveredBehavior.skills, '
|
|
122
|
-
...discoverySummaryLine('Discovered routines', snapshot.discoveredBehavior.routines, '
|
|
136
|
+
...discoverySummaryLine('Discovered personas', snapshot.discoveredBehavior.personas, 'Personas -> Discover persona files'),
|
|
137
|
+
...discoverySummaryLine('Discovered skills', snapshot.discoveredBehavior.skills, 'Skills -> Discover skill files'),
|
|
138
|
+
...discoverySummaryLine('Discovered routines', snapshot.discoveredBehavior.routines, 'Routines -> Discover routine files'),
|
|
123
139
|
];
|
|
124
140
|
if (lines.length === 0) return [];
|
|
125
141
|
return [
|
|
@@ -150,11 +166,15 @@ function localLibraryLines(
|
|
|
150
166
|
item.enabled === true ? 'enabled' : item.enabled === false ? 'disabled' : '',
|
|
151
167
|
item.scope && item.cls ? `${item.scope}/${item.cls}` : '',
|
|
152
168
|
item.confidence !== undefined ? `${item.confidence}%` : '',
|
|
153
|
-
item.
|
|
169
|
+
item.requirementCount !== undefined && item.requirementCount > 0
|
|
170
|
+
? (item.missingRequirementCount && item.missingRequirementCount > 0 ? `needs ${item.missingRequirementCount}/${item.requirementCount}` : `ready ${item.requirementCount}/${item.requirementCount}`)
|
|
171
|
+
: '',
|
|
172
|
+
formatAgentRecordReviewState(item.reviewState),
|
|
173
|
+
item.source ? `origin ${item.source}` : '',
|
|
154
174
|
item.startCount !== undefined ? `starts ${item.startCount}` : '',
|
|
155
175
|
].filter(Boolean).join(' / ');
|
|
156
|
-
const tags = item.tags.length > 0 ? ` tags
|
|
157
|
-
const triggers = item.triggers.length > 0 ? ` triggers
|
|
176
|
+
const tags = item.tags.length > 0 ? ` tags ${item.tags.join(',')}` : '';
|
|
177
|
+
const triggers = item.triggers.length > 0 ? ` triggers ${item.triggers.join(',')}` : '';
|
|
158
178
|
const marker = selected ? `${GLYPHS.navigation.selected} ` : '';
|
|
159
179
|
lines.push({
|
|
160
180
|
text: `${marker}${item.id}: ${item.name} (${status})`,
|
|
@@ -162,6 +182,9 @@ function localLibraryLines(
|
|
|
162
182
|
bold: selected || item.active === true,
|
|
163
183
|
});
|
|
164
184
|
lines.push({ text: ` ${item.description}${tags}${triggers}`, fg: PALETTE.muted });
|
|
185
|
+
if (item.missingRequirements && item.missingRequirements.length > 0) {
|
|
186
|
+
lines.push({ text: ` missing setup: ${item.missingRequirements.join(', ')}`, fg: PALETTE.warn });
|
|
187
|
+
}
|
|
165
188
|
}
|
|
166
189
|
if (items.length > 8) {
|
|
167
190
|
lines.push({ text: `${items.length - 8} more item(s). Open the library command for the full list.`, fg: PALETTE.dim });
|
|
@@ -169,6 +192,86 @@ function localLibraryLines(
|
|
|
169
192
|
return lines;
|
|
170
193
|
}
|
|
171
194
|
|
|
195
|
+
type LocalRoutineItem = AgentWorkspaceRuntimeSnapshot['localRoutines'][number];
|
|
196
|
+
|
|
197
|
+
function readyRoutineItems(snapshot: AgentWorkspaceRuntimeSnapshot): readonly LocalRoutineItem[] {
|
|
198
|
+
return snapshot.localRoutines.filter((routine) =>
|
|
199
|
+
routine.enabled === true
|
|
200
|
+
&& routine.reviewState === 'reviewed'
|
|
201
|
+
&& (routine.missingRequirementCount ?? 0) === 0
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function routinesNeedingSetup(snapshot: AgentWorkspaceRuntimeSnapshot): readonly LocalRoutineItem[] {
|
|
206
|
+
return snapshot.localRoutines.filter((routine) => (routine.missingRequirementCount ?? 0) > 0);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function routinesNeedingReview(snapshot: AgentWorkspaceRuntimeSnapshot): readonly LocalRoutineItem[] {
|
|
210
|
+
return snapshot.localRoutines.filter((routine) => routine.reviewState !== 'reviewed');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function routineNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
|
|
214
|
+
const discovered = snapshot.discoveredBehavior.routines.count;
|
|
215
|
+
const ready = readyRoutineItems(snapshot);
|
|
216
|
+
const needsSetup = routinesNeedingSetup(snapshot);
|
|
217
|
+
const needsReview = routinesNeedingReview(snapshot);
|
|
218
|
+
|
|
219
|
+
if (snapshot.localRoutineCount === 0 && discovered > 0) {
|
|
220
|
+
return { text: 'Next routine action: Discover routine files, preview one, then import it from this workspace.', fg: PALETTE.warn, bold: true };
|
|
221
|
+
}
|
|
222
|
+
if (snapshot.localRoutineCount === 0) {
|
|
223
|
+
return { text: 'Next routine action: Create routine for a repeatable main-conversation workflow.', fg: PALETTE.warn, bold: true };
|
|
224
|
+
}
|
|
225
|
+
if (needsSetup.length > 0) {
|
|
226
|
+
return { text: `Next routine action: Needs setup for ${needsSetup[0]?.id ?? 'a routine'} before it can be trusted for schedule promotion.`, fg: PALETTE.warn, bold: true };
|
|
227
|
+
}
|
|
228
|
+
if (needsReview.length > 0) {
|
|
229
|
+
return { text: `Next routine action: Review selected or inspect ${needsReview[0]?.id ?? 'a routine'} before schedule promotion.`, fg: PALETTE.warn, bold: true };
|
|
230
|
+
}
|
|
231
|
+
if (ready.length > 0 && snapshot.routineScheduleReceiptCount === 0) {
|
|
232
|
+
return { text: `Next routine action: Promote ${ready[0]?.id ?? 'a reviewed routine'} to a connected schedule when you have a real cadence.`, fg: PALETTE.good, bold: true };
|
|
233
|
+
}
|
|
234
|
+
return { text: 'Next routine action: Start selected in the main conversation, inspect receipts, or reconcile connected schedules.', fg: PALETTE.info, bold: true };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function routineScheduleReceiptLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
238
|
+
const latest = snapshot.latestRoutineScheduleReceipt;
|
|
239
|
+
const lines: ContextLine[] = [
|
|
240
|
+
{
|
|
241
|
+
text: `Promotion receipts: ${snapshot.routineScheduleReceiptCount}; created: ${snapshot.successfulRoutineScheduleReceiptCount}; failed: ${snapshot.failedRoutineScheduleReceiptCount}`,
|
|
242
|
+
fg: snapshot.failedRoutineScheduleReceiptCount > 0 ? PALETTE.warn : PALETTE.info,
|
|
243
|
+
},
|
|
244
|
+
];
|
|
245
|
+
if (latest) {
|
|
246
|
+
lines.push({
|
|
247
|
+
text: `Latest receipt: ${latest.id} ${latest.status} routine=${latest.routineId} schedule="${latest.scheduleName}" ${latest.scheduleKind} ${latest.scheduleValue}`,
|
|
248
|
+
fg: latest.status === 'failed' ? PALETTE.warn : PALETTE.good,
|
|
249
|
+
});
|
|
250
|
+
} else {
|
|
251
|
+
lines.push({ text: 'No schedule promotion receipts yet. Confirm a routine promotion from Automation when ready.', fg: PALETTE.muted });
|
|
252
|
+
}
|
|
253
|
+
return lines;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function automationNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
|
|
257
|
+
const ready = readyRoutineItems(snapshot);
|
|
258
|
+
const needsSetup = routinesNeedingSetup(snapshot);
|
|
259
|
+
const needsReview = routinesNeedingReview(snapshot);
|
|
260
|
+
if (snapshot.routineScheduleReceiptCount > 0) {
|
|
261
|
+
return { text: 'Next automation action: Reconcile schedules to compare local receipts with the connected host.', fg: PALETTE.info, bold: true };
|
|
262
|
+
}
|
|
263
|
+
if (ready.length > 0) {
|
|
264
|
+
return { text: `Next automation action: Promote ${ready[0]?.id ?? 'a reviewed routine'} or create a one-off reminder.`, fg: PALETTE.good, bold: true };
|
|
265
|
+
}
|
|
266
|
+
if (needsSetup.length > 0) {
|
|
267
|
+
return { text: `Next automation action: Resolve routine setup gaps in ${needsSetup[0]?.id ?? 'Routines'} before promotion, or create a reminder.`, fg: PALETTE.warn, bold: true };
|
|
268
|
+
}
|
|
269
|
+
if (needsReview.length > 0) {
|
|
270
|
+
return { text: `Next automation action: Review ${needsReview[0]?.id ?? 'a routine'} in Routines before schedule promotion, or create a reminder.`, fg: PALETTE.warn, bold: true };
|
|
271
|
+
}
|
|
272
|
+
return { text: 'Next automation action: Create a reminder, or create/import a routine before recurring workflow promotion.', fg: PALETTE.warn, bold: true };
|
|
273
|
+
}
|
|
274
|
+
|
|
172
275
|
function profileLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
173
276
|
const lines: ContextLine[] = [
|
|
174
277
|
{ text: 'Agent Profiles', fg: PALETTE.title, bold: true },
|
|
@@ -179,8 +282,17 @@ function profileLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
|
179
282
|
}
|
|
180
283
|
for (const profile of snapshot.runtimeProfiles.slice(0, 6)) {
|
|
181
284
|
const starter = profile.starterTemplateId ? ` starter=${profile.starterTemplateId}` : ' starter=none';
|
|
182
|
-
const created = profile.createdAt ? ` created
|
|
183
|
-
|
|
285
|
+
const created = profile.createdAt ? ` created ${profile.createdAt.slice(0, 10)}` : '';
|
|
286
|
+
const states = [
|
|
287
|
+
profile.id === snapshot.activeRuntimeProfile ? 'active' : '',
|
|
288
|
+
profile.id === snapshot.selectedRuntimeProfile ? 'default' : '',
|
|
289
|
+
].filter(Boolean).join(', ');
|
|
290
|
+
const stateText = states ? ` [${states}]` : '';
|
|
291
|
+
lines.push({
|
|
292
|
+
text: `${profile.id}${stateText}${starter}${created}`,
|
|
293
|
+
fg: profile.id === snapshot.selectedRuntimeProfile ? PALETTE.good : PALETTE.info,
|
|
294
|
+
bold: profile.id === snapshot.activeRuntimeProfile || profile.id === snapshot.selectedRuntimeProfile,
|
|
295
|
+
});
|
|
184
296
|
lines.push({ text: ` home: ${profile.homeDirectory}`, fg: PALETTE.muted });
|
|
185
297
|
}
|
|
186
298
|
if (snapshot.runtimeProfiles.length > 6) {
|
|
@@ -194,8 +306,9 @@ function starterTemplateLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextL
|
|
|
194
306
|
{ text: 'Starter Templates', fg: PALETTE.title, bold: true },
|
|
195
307
|
];
|
|
196
308
|
for (const template of snapshot.runtimeStarterTemplates.slice(0, 6)) {
|
|
309
|
+
const origin = template.source === 'local' ? 'Local' : formatAgentRecordSource(template.source);
|
|
197
310
|
lines.push({
|
|
198
|
-
text: `${template.id}: ${template.name} [${
|
|
311
|
+
text: `${template.id}: ${template.name} [${origin}]`,
|
|
199
312
|
fg: template.source === 'local' ? PALETTE.good : PALETTE.info,
|
|
200
313
|
bold: template.id === 'research',
|
|
201
314
|
});
|
|
@@ -217,7 +330,12 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
217
330
|
base.push(
|
|
218
331
|
{ text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
|
|
219
332
|
{ text: `Session: ${snapshot.sessionId}`, fg: PALETTE.muted },
|
|
220
|
-
{ text: `Policy: ${snapshot.executionPolicy};
|
|
333
|
+
{ text: `Policy: ${snapshot.executionPolicy}; delegated review ${snapshot.delegatedReviewPolicy}`, fg: PALETTE.good },
|
|
334
|
+
{ text: `Knowledge: ${snapshot.knowledgeRoute}; ${snapshot.knowledgeIsolation}; no fallback`, fg: PALETTE.good },
|
|
335
|
+
{ text: `Local: ${snapshot.localMemoryCount} memory, ${snapshot.localNoteCount} notes, ${snapshot.localPersonaCount} personas, ${snapshot.localSkillCount} skills, ${snapshot.localRoutineCount} routines.`, fg: PALETTE.info },
|
|
336
|
+
{ text: `Channels: ${snapshot.channels.filter((channel) => channel.ready).length}/${snapshot.channels.length} ready; MCP ${snapshot.mcpConnectedServerCount}/${snapshot.mcpServerCount} connected; voice/media ${snapshot.voiceProviderCount}/${snapshot.mediaProviderCount}.`, fg: PALETTE.info },
|
|
337
|
+
{ text: '' },
|
|
338
|
+
...homeNextActionLines(snapshot),
|
|
221
339
|
);
|
|
222
340
|
} else if (category.id === 'setup') {
|
|
223
341
|
base.push(
|
|
@@ -229,6 +347,17 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
229
347
|
{ text: `Workspace: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
|
|
230
348
|
{ text: `Home: ${snapshot.homeDirectory}`, fg: PALETTE.muted },
|
|
231
349
|
);
|
|
350
|
+
} else if (category.id === 'artifacts') {
|
|
351
|
+
const mediaReady = snapshot.voiceMediaReadiness.readyMediaProviderCount;
|
|
352
|
+
base.push(
|
|
353
|
+
{ text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
|
|
354
|
+
{ text: `Agent Knowledge route: ${snapshot.knowledgeRoute}`, fg: PALETTE.info },
|
|
355
|
+
{ text: `Media providers: ${mediaReady}/${snapshot.mediaProviderCount} ready; generation-capable ${snapshot.mediaGenerationProviderCount}.`, fg: mediaReady > 0 ? PALETTE.good : PALETTE.warn },
|
|
356
|
+
{ text: 'Use this area for concrete files and generated output: attach images, export transcripts, ingest reviewed sources, inspect source records, and generate media.', fg: PALETTE.good },
|
|
357
|
+
{ text: 'Agent Knowledge ingest writes only to the isolated Agent segment. Default knowledge and non-Agent routes are not fallback storage.', fg: PALETTE.warn },
|
|
358
|
+
{ text: 'Generated media is stored as artifacts and referenced by id; the TUI should not print inline base64.', fg: PALETTE.muted },
|
|
359
|
+
{ text: `Workspace path: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
|
|
360
|
+
);
|
|
232
361
|
} else if (category.id === 'channels') {
|
|
233
362
|
const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
|
|
234
363
|
const readyCount = snapshot.channels.filter((channel) => channel.ready).length;
|
|
@@ -236,16 +365,20 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
236
365
|
const readyChannels = snapshot.channels.filter((channel) => channel.ready).map((channel) => channel.label);
|
|
237
366
|
const needsTarget = snapshot.channels.filter((channel) => channel.setupState === 'needs-target');
|
|
238
367
|
const needsConfig = snapshot.channels.filter((channel) => channel.setupState === 'needs-config');
|
|
368
|
+
const nextAttentionChannel = needsConfig[0] ?? needsTarget[0] ?? snapshot.channels.find((channel) => !channel.enabled);
|
|
239
369
|
const disabledChannels = snapshot.channels.filter((channel) => !channel.enabled).map((channel) => channel.label);
|
|
240
370
|
const disabledPreview = disabledChannels.slice(0, 6).join(', ');
|
|
241
371
|
const disabledSuffix = disabledChannels.length > 6 ? `, +${disabledChannels.length - 6} more` : '';
|
|
242
372
|
const orderedChannels = [
|
|
243
373
|
...snapshot.channels.filter((channel) => channel.enabled),
|
|
244
374
|
...snapshot.channels.filter((channel) => !channel.enabled),
|
|
245
|
-
].slice(0,
|
|
375
|
+
].slice(0, 3);
|
|
246
376
|
base.push(
|
|
247
377
|
{ text: `GoodVibes API: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
|
|
378
|
+
companionAccessLine(snapshot),
|
|
248
379
|
{ text: `Readiness: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} default target(s) configured.`, fg: PALETTE.info },
|
|
380
|
+
{ text: 'Setup path: pair companion -> inspect readiness -> review accounts/policies/status -> fix one channel -> add explicit notification target if needed.', fg: PALETTE.good },
|
|
381
|
+
{ text: `Next channel action: ${nextAttentionChannel ? `${nextAttentionChannel.label} - ${nextAttentionChannel.nextStep}` : 'All enabled channels are ready; keep delivery explicit and review policies before sending.'}`, fg: nextAttentionChannel ? PALETTE.warn : PALETTE.good },
|
|
249
382
|
{ text: `Ready channels: ${readyChannels.join(', ') || 'none'}.`, fg: readyChannels.length > 0 ? PALETTE.good : PALETTE.warn },
|
|
250
383
|
{ text: `Needs default target: ${needsTarget.map((channel) => `${channel.label} -> ${channel.defaultTargetKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsTarget.length > 0 ? PALETTE.warn : PALETTE.muted },
|
|
251
384
|
{ text: `Needs config: ${needsConfig.map((channel) => `${channel.label} -> ${channel.missingRequiredKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsConfig.length > 0 ? PALETTE.warn : PALETTE.muted },
|
|
@@ -259,21 +392,30 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
259
392
|
fg: channel.ready ? PALETTE.good : channel.enabled ? PALETTE.warn : PALETTE.dim,
|
|
260
393
|
});
|
|
261
394
|
}
|
|
262
|
-
base.push({ text: 'Only config key names and readiness state are rendered here.', fg: PALETTE.muted });
|
|
263
|
-
base.push({ text: 'Pairing: use /pair or /qrcode; inspect notification targets with /notify list and health with /health review.', fg: PALETTE.info });
|
|
264
395
|
} else if (category.id === 'knowledge') {
|
|
265
396
|
base.push(
|
|
266
397
|
{ text: `Route family: ${snapshot.knowledgeRoute}/{status,ask,search}`, fg: PALETTE.info },
|
|
267
|
-
{ text: `Isolation: ${snapshot.knowledgeIsolation}; no default
|
|
398
|
+
{ text: `Isolation: ${snapshot.knowledgeIsolation}; no default knowledge or non-Agent fallback`, fg: PALETTE.good },
|
|
268
399
|
{ text: 'Ingest: URL, URL-list, and bookmark imports require explicit --yes and write only to Agent Knowledge.', fg: PALETTE.info },
|
|
269
400
|
{ text: 'Review: queue, issues, candidates, reports, reindex, and consolidation stay inside the Agent segment.', fg: PALETTE.muted },
|
|
270
401
|
{ text: 'Agent-owned content appears here only after explicit Agent knowledge ingestion.', fg: PALETTE.muted },
|
|
271
402
|
);
|
|
403
|
+
} else if (category.id === 'research') {
|
|
404
|
+
base.push(
|
|
405
|
+
{ text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
|
|
406
|
+
{ text: `Agent Knowledge route: ${snapshot.knowledgeRoute}`, fg: PALETTE.info },
|
|
407
|
+
{ text: `Browser tools: ${snapshot.voiceMediaReadiness.browserToolState}; public base URL ${snapshot.browserToolPublicBaseUrl}.`, fg: snapshot.browserToolExposureEnabled ? PALETTE.warn : PALETTE.muted },
|
|
408
|
+
{ text: snapshot.voiceMediaReadiness.browserToolNextStep, fg: PALETTE.muted },
|
|
409
|
+
{ text: 'Research requests are submitted to the main conversation. Agent may use connected read-only web tools when the user asks.', fg: PALETTE.good },
|
|
410
|
+
{ text: 'URL references and web research do not ingest into Agent Knowledge. Ingestion is a separate confirmed Agent Knowledge action.', fg: PALETTE.warn },
|
|
411
|
+
{ text: 'Use Agent Knowledge ask/search first for known source-backed context; use web research for current or external sources.', fg: PALETTE.info },
|
|
412
|
+
{ text: 'External sends, browser-side effects, package installs, and connected-host mutations are outside this read-only research lane.', fg: PALETTE.warn },
|
|
413
|
+
);
|
|
272
414
|
} else if (category.id === 'tools') {
|
|
273
415
|
base.push(
|
|
274
416
|
{ text: `MCP servers: ${snapshot.mcpConnectedServerCount}/${snapshot.mcpServerCount} connected; quarantined ${snapshot.mcpQuarantinedServerCount}; allow-all ${snapshot.mcpAllowAllServerCount}.`, fg: snapshot.mcpQuarantinedServerCount > 0 || snapshot.mcpAllowAllServerCount > 0 ? PALETTE.warn : PALETTE.info },
|
|
275
|
-
{ text: 'Open MCP workspace for live server status, tool inventory, config paths, and
|
|
276
|
-
{ text: 'Add/update requires typed confirmation and dispatches
|
|
417
|
+
{ text: 'Open MCP workspace for live server status, tool inventory, config paths, and confirmed add/remove/reload actions.', fg: PALETTE.info },
|
|
418
|
+
{ text: 'Add/update requires typed confirmation and dispatches through the TUI command router.', fg: PALETTE.good },
|
|
277
419
|
{ text: 'Trust changes remain explicit; allow-all is kept behind the settings workspace.', fg: PALETTE.warn },
|
|
278
420
|
{ text: 'Useful first actions: /mcp review, /mcp tools, /mcp config, and Add MCP server.', fg: PALETTE.muted },
|
|
279
421
|
{ text: 'Normal assistant chat can use tools serially when policy allows; onboarding does not start hidden tool work.', fg: PALETTE.muted },
|
|
@@ -317,8 +459,12 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
317
459
|
{ text: 'Image input uses prompt attachments; media generation/provider setup stays behind explicit commands and configured providers.', fg: PALETTE.muted },
|
|
318
460
|
);
|
|
319
461
|
} else if (category.id === 'profiles') {
|
|
462
|
+
const defaultProfile = snapshot.selectedRuntimeProfile
|
|
463
|
+
? `${snapshot.selectedRuntimeProfile}${snapshot.selectedRuntimeProfileExists ? '' : ' (missing)'}`
|
|
464
|
+
: '(base Agent home)';
|
|
320
465
|
base.push(
|
|
321
466
|
{ text: `Active Agent profile: ${snapshot.activeRuntimeProfile}`, fg: PALETTE.info },
|
|
467
|
+
{ text: `Default for next launch: ${defaultProfile}`, fg: snapshot.selectedRuntimeProfileExists || !snapshot.selectedRuntimeProfile ? PALETTE.info : PALETTE.warn },
|
|
322
468
|
{ text: `Agent profiles under this home: ${snapshot.runtimeProfileCount}`, fg: PALETTE.info },
|
|
323
469
|
{ text: `Starter templates: ${snapshot.runtimeStarterTemplateCount}; local custom: ${snapshot.localStarterTemplateCount}`, fg: PALETTE.info },
|
|
324
470
|
{ text: `Starter ids: ${snapshot.runtimeStarterTemplates.map((template) => template.id).join(', ') || 'none'}`, fg: PALETTE.info },
|
|
@@ -331,25 +477,35 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
331
477
|
{ text: '' },
|
|
332
478
|
{ text: 'Named Agent profiles isolate local config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
|
|
333
479
|
{ text: 'Starter authoring: browse, export, edit, import, and create Agent profiles from inside this workspace.', fg: PALETTE.info },
|
|
334
|
-
{ text: '
|
|
480
|
+
{ text: 'The connected GoodVibes host stays shared unless that host is configured separately.', fg: PALETTE.warn },
|
|
335
481
|
{ text: 'Portable bundles require explicit export/import commands with real paths and --yes.', fg: PALETTE.muted },
|
|
336
482
|
);
|
|
337
483
|
} else if (category.id === 'memory') {
|
|
338
484
|
base.push(
|
|
339
485
|
{ text: `Session memories: ${snapshot.sessionMemoryCount}`, fg: PALETTE.info },
|
|
340
486
|
{ text: `Agent memory: ${snapshot.localMemoryCount}; prompt-active: ${snapshot.localMemoryPromptActiveCount}; review queue: ${snapshot.localMemoryReviewQueueCount}`, fg: PALETTE.info },
|
|
487
|
+
{ text: `Scratchpad notes: ${snapshot.localNoteCount}; review queue: ${snapshot.localNoteReviewQueueCount}`, fg: PALETTE.info },
|
|
341
488
|
{ text: `Local routines: ${snapshot.localRoutineCount}; enabled: ${snapshot.enabledRoutineCount}`, fg: PALETTE.info },
|
|
342
489
|
{ text: `Local skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}; bundles: ${snapshot.localSkillBundleCount}; active skills: ${snapshot.activeSkillCount}`, fg: PALETTE.info },
|
|
343
490
|
{ text: `Local personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
|
|
344
|
-
{ text: 'Durable memory, routines, skills, and personas remain Agent-local until shared registry contracts exist.', fg: PALETTE.good },
|
|
491
|
+
{ text: 'Durable memory, scratchpad notes, routines, skills, and personas remain Agent-local until shared registry contracts exist.', fg: PALETTE.good },
|
|
345
492
|
{ text: 'Secrets are rejected/redacted; store secret references instead of secret values.', fg: PALETTE.warn },
|
|
346
493
|
{ text: '' },
|
|
347
494
|
...localLibraryLines('Agent Memory', snapshot.localMemories, 'No Agent memory yet. Create one here with Create memory.', workspace.selectedLocalLibraryItem('memory')?.id ?? null),
|
|
348
495
|
);
|
|
496
|
+
} else if (category.id === 'notes') {
|
|
497
|
+
base.push(
|
|
498
|
+
{ text: `Scratchpad notes: ${snapshot.localNoteCount}; review queue: ${snapshot.localNoteReviewQueueCount}`, fg: PALETTE.info },
|
|
499
|
+
{ text: 'Notes are Agent-local working context for source triage, temporary decisions, and operator handoff.', fg: PALETTE.good },
|
|
500
|
+
{ text: 'Notes do not become memory and are not ingested into Agent Knowledge unless the user takes a separate explicit action.', fg: PALETTE.warn },
|
|
501
|
+
{ text: 'Use reviewed notes to prefill durable memory, skills, routines, or personas, or to decide that a reviewed source deserves Agent Knowledge ingest.', fg: PALETTE.muted },
|
|
502
|
+
{ text: '' },
|
|
503
|
+
...localLibraryLines('Scratchpad Notes', snapshot.localNotes, 'No local notes yet. Create one here with Create note.', workspace.selectedLocalLibraryItem('note')?.id ?? null),
|
|
504
|
+
);
|
|
349
505
|
} else if (category.id === 'personas') {
|
|
350
506
|
base.push(
|
|
351
507
|
{ text: `Personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
|
|
352
|
-
{ text: 'Personas are local behavior profiles for the serial main-conversation assistant, not
|
|
508
|
+
{ text: 'Personas are local behavior profiles for the serial main-conversation assistant, not separate Agent jobs.', fg: PALETTE.good },
|
|
353
509
|
{ text: 'Use them for tone, role, domain constraints, tool posture, and repeatable operating preferences.', fg: PALETTE.muted },
|
|
354
510
|
{ text: '' },
|
|
355
511
|
...localLibraryLines('Persona Library', snapshot.localPersonas, 'No local personas yet. Create one here with Create persona.', workspace.selectedLocalLibraryItem('persona')?.id ?? null),
|
|
@@ -365,10 +521,16 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
365
521
|
...localLibraryLines('Skill Bundles', snapshot.localSkillBundles, 'No local skill bundles yet. Use Skill bundles and Create bundle after creating skills.', null),
|
|
366
522
|
);
|
|
367
523
|
} else if (category.id === 'routines') {
|
|
524
|
+
const ready = readyRoutineItems(snapshot);
|
|
525
|
+
const needsSetup = routinesNeedingSetup(snapshot);
|
|
526
|
+
const needsReview = routinesNeedingReview(snapshot);
|
|
368
527
|
base.push(
|
|
369
528
|
{ text: `Routines: ${snapshot.localRoutineCount}; enabled: ${snapshot.enabledRoutineCount}`, fg: PALETTE.info },
|
|
529
|
+
{ text: `Schedule-ready routines: ${ready.length}; setup gaps: ${needsSetup.length}; review needed: ${needsReview.length}`, fg: needsSetup.length > 0 || needsReview.length > 0 ? PALETTE.warn : PALETTE.good },
|
|
370
530
|
{ text: 'Routines are repeatable main-conversation workflows. Starting one does not create hidden jobs.', fg: PALETTE.good },
|
|
371
531
|
{ text: 'Scheduling a reviewed routine is explicit and requires a confirmed schedule command.', fg: PALETTE.warn },
|
|
532
|
+
routineNextActionLine(snapshot),
|
|
533
|
+
...routineScheduleReceiptLines(snapshot),
|
|
372
534
|
{ text: '' },
|
|
373
535
|
...localLibraryLines('Routine Library', snapshot.localRoutines, 'No local routines yet. Create one here with Create routine.', workspace.selectedLocalLibraryItem('routine')?.id ?? null),
|
|
374
536
|
);
|
|
@@ -376,18 +538,26 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
376
538
|
base.push(
|
|
377
539
|
{ text: 'Work plan and approvals are read or explicitly confirmed through public operator routes.', fg: PALETTE.info },
|
|
378
540
|
{ text: 'This workspace does not approve, deny, cancel, or mutate requests by selection alone.', fg: PALETTE.good },
|
|
541
|
+
{ text: 'Approve, deny, and cancel forms require an approval id and typed confirmation.', fg: PALETTE.warn },
|
|
379
542
|
);
|
|
380
543
|
} else if (category.id === 'automation') {
|
|
544
|
+
const ready = readyRoutineItems(snapshot);
|
|
381
545
|
base.push(
|
|
382
|
-
{ text: 'Automation and schedules default to read-only observability.', fg: PALETTE.info },
|
|
546
|
+
{ text: 'Automation and schedules default to read-only observability; side effects require confirmed forms.', fg: PALETTE.info },
|
|
383
547
|
{ text: 'Confirmed reminders and routine promotion use connected schedules only.', fg: PALETTE.info },
|
|
384
|
-
{ text: 'Local scheduler mutation/run controls
|
|
548
|
+
{ text: 'Local scheduler mutation controls remain blocked; job/run/schedule controls go through the connected host.', fg: PALETTE.warn },
|
|
549
|
+
{ text: 'Reminder path: Create reminder -> choose at/every/cron -> optional delivery target -> confirm yes.', fg: PALETTE.good },
|
|
550
|
+
{ text: 'Operator path: choose job/run/schedule action -> enter id -> type yes -> dispatch once.', fg: PALETTE.good },
|
|
551
|
+
{ text: 'Routine path: Routines -> resolve setup -> review selected -> Promote routine -> Reconcile schedules.', fg: PALETTE.good },
|
|
552
|
+
{ text: `Schedule-ready routines: ${ready.length}; local promotion receipts: ${snapshot.routineScheduleReceiptCount}`, fg: ready.length > 0 ? PALETTE.good : PALETTE.warn },
|
|
553
|
+
automationNextActionLine(snapshot),
|
|
554
|
+
...routineScheduleReceiptLines(snapshot),
|
|
385
555
|
);
|
|
386
556
|
} else if (category.id === 'delegate') {
|
|
387
557
|
base.push(
|
|
388
558
|
{ text: 'Build/fix/review work is handed to GoodVibes TUI/shared-session contracts.', fg: PALETTE.info },
|
|
389
|
-
{ text: `
|
|
390
|
-
{ text: 'Agent does not
|
|
559
|
+
{ text: `Delegated review policy: ${snapshot.delegatedReviewPolicy}`, fg: PALETTE.warn },
|
|
560
|
+
{ text: 'Agent does not create coding-role Agent jobs.', fg: PALETTE.good },
|
|
391
561
|
);
|
|
392
562
|
}
|
|
393
563
|
if (snapshot.warnings.length > 0) {
|
|
@@ -421,6 +591,17 @@ function buildContextRows(workspace: AgentWorkspace, category: AgentWorkspaceCat
|
|
|
421
591
|
{ text: '' },
|
|
422
592
|
{ text: category.detail, fg: PALETTE.text },
|
|
423
593
|
{ text: '' },
|
|
594
|
+
...(workspace.actionSearchActive ? [
|
|
595
|
+
{ text: 'Action Search', fg: PALETTE.title, bold: true },
|
|
596
|
+
{
|
|
597
|
+
text: workspace.actionSearchQuery.length > 0
|
|
598
|
+
? `Query: ${workspace.actionSearchQuery} (${workspace.actionSearchResults.length} result${workspace.actionSearchResults.length === 1 ? '' : 's'})`
|
|
599
|
+
: 'Type to search every Agent workspace action.',
|
|
600
|
+
fg: workspace.actionSearchQuery.length > 0 && workspace.actionSearchResults.length === 0 ? PALETTE.warn : PALETTE.info,
|
|
601
|
+
},
|
|
602
|
+
{ text: 'Enter opens the selected result. Esc clears search and returns to normal workspace navigation.', fg: PALETTE.muted },
|
|
603
|
+
{ text: '' },
|
|
604
|
+
] satisfies ContextLine[] : []),
|
|
424
605
|
...(workspace.localEditor ? editorContextLines(workspace.localEditor) : []),
|
|
425
606
|
...(workspace.localEditor ? [{ text: '' }] : []),
|
|
426
607
|
...snapshotLines(workspace, category, workspace.runtimeSnapshot),
|
|
@@ -486,7 +667,9 @@ function buildEditorFieldRows(editor: AgentWorkspaceLocalEditor, index: number,
|
|
|
486
667
|
const selected = index === editor.selectedFieldIndex;
|
|
487
668
|
const marker = selected ? GLYPHS.navigation.selected : ' ';
|
|
488
669
|
const required = field.required ? ' *' : '';
|
|
489
|
-
const value = field.value.length > 0
|
|
670
|
+
const value = field.value.length > 0
|
|
671
|
+
? field.redact ? '*'.repeat(Math.min(12, Math.max(6, Array.from(field.value).length))) : field.value
|
|
672
|
+
: '(empty)';
|
|
490
673
|
const color = selected ? PALETTE.text : field.value.length > 0 ? PALETTE.info : PALETTE.muted;
|
|
491
674
|
const rows: WorkspaceRow[] = [{
|
|
492
675
|
text: `${marker} ${field.label}${required}`,
|
|
@@ -511,23 +694,32 @@ function buildActionRows(workspace: AgentWorkspace, width: number, height: numbe
|
|
|
511
694
|
const labelWidth = Math.min(28, Math.max(16, Math.floor(width * 0.30)));
|
|
512
695
|
const safetyWidth = 10;
|
|
513
696
|
const commandWidth = Math.max(10, width - labelWidth - safetyWidth - 9);
|
|
697
|
+
if (workspace.actionSearchActive) {
|
|
698
|
+
rows.push({
|
|
699
|
+
text: ` Search: ${workspace.actionSearchQuery || '(type to filter actions)'}`,
|
|
700
|
+
fg: workspace.actionSearchQuery.length > 0 && workspace.actions.length === 0 ? PALETTE.warn : PALETTE.info,
|
|
701
|
+
bold: true,
|
|
702
|
+
});
|
|
703
|
+
}
|
|
514
704
|
rows.push({
|
|
515
|
-
text: ` ${padDisplay('Action', labelWidth)} ${padDisplay('Safety', safetyWidth)} ${padDisplay('Command', commandWidth)}`,
|
|
705
|
+
text: ` ${padDisplay(workspace.actionSearchActive ? 'Result' : 'Action', labelWidth)} ${padDisplay('Safety', safetyWidth)} ${padDisplay('Command', commandWidth)}`,
|
|
516
706
|
fg: PALETTE.muted,
|
|
517
707
|
bold: true,
|
|
518
708
|
});
|
|
519
709
|
|
|
520
710
|
const actions = workspace.actions;
|
|
521
|
-
const visible = Math.max(1, height - 2);
|
|
711
|
+
const visible = Math.max(1, height - (workspace.actionSearchActive ? 3 : 2));
|
|
522
712
|
const window = stableWindow(actions.length, workspace.selectedActionIndex, visible);
|
|
523
713
|
if (window.start > 0) rows.push({ text: `${GLYPHS.navigation.moreAbove} ${window.start} more action(s) above`, kind: 'more', fg: PALETTE.dim, dim: true });
|
|
524
714
|
|
|
525
715
|
for (let index = window.start; index < window.end; index += 1) {
|
|
526
716
|
const action = actions[index]!;
|
|
527
717
|
const selected = index === workspace.selectedActionIndex;
|
|
718
|
+
const searchResult = workspace.actionSearchActive ? workspace.actionSearchResults[index] : null;
|
|
719
|
+
const label = searchResult ? `${searchResult.category.label} / ${action.label}` : action.label;
|
|
528
720
|
const marker = selected ? GLYPHS.navigation.selected : ' ';
|
|
529
721
|
rows.push({
|
|
530
|
-
text: `${marker} ${padDisplay(
|
|
722
|
+
text: `${marker} ${padDisplay(label, labelWidth)} ${padDisplay(action.safety, safetyWidth)} ${padDisplay(actionCommand(action), commandWidth)}`,
|
|
531
723
|
selected: selected && workspace.focusPane === 'actions',
|
|
532
724
|
fg: safetyColor(action),
|
|
533
725
|
bold: selected,
|
|
@@ -556,12 +748,15 @@ function footerText(workspace: AgentWorkspace): string {
|
|
|
556
748
|
if (workspace.localEditor) {
|
|
557
749
|
return `Agent workspace · editing ${workspace.localEditor.kind} · Enter next/save · Ctrl-J newline · Esc cancel`;
|
|
558
750
|
}
|
|
751
|
+
if (workspace.actionSearchActive) {
|
|
752
|
+
return 'Agent workspace · action search · type filter · Up/Down results · Enter open · Esc clear';
|
|
753
|
+
}
|
|
559
754
|
const focus = workspace.focusPane === 'categories' ? 'categories' : 'actions';
|
|
560
|
-
return `Agent workspace ·
|
|
755
|
+
return `Agent workspace · ${focus} · / search · Up/Down · Left/Right · Ctrl+[/] area · Enter open/action · R refresh · Esc close`;
|
|
561
756
|
}
|
|
562
757
|
|
|
563
758
|
export function renderAgentWorkspace(workspace: AgentWorkspace, width: number, height: number): Line[] {
|
|
564
|
-
const category = workspace.
|
|
759
|
+
const category = workspace.selectedActionCategory;
|
|
565
760
|
const action = workspace.selectedAction;
|
|
566
761
|
const setupCategory = category.id === 'setup';
|
|
567
762
|
const layoutOptions = {
|
|
@@ -577,9 +772,11 @@ export function renderAgentWorkspace(workspace: AgentWorkspace, width: number, h
|
|
|
577
772
|
width,
|
|
578
773
|
height,
|
|
579
774
|
title: 'GoodVibes Agent / Operator Workspace',
|
|
580
|
-
stateLabel: workspace.localEditor ? 'Editor' : workspace.focusPane === 'categories' ? 'Categories' : 'Actions',
|
|
775
|
+
stateLabel: workspace.localEditor ? 'Editor' : workspace.actionSearchActive ? 'Search' : workspace.focusPane === 'categories' ? 'Categories' : 'Actions',
|
|
581
776
|
leftHeader: 'Operator Areas',
|
|
582
|
-
mainHeader:
|
|
777
|
+
mainHeader: workspace.actionSearchActive
|
|
778
|
+
? `Search actions · ${workspace.actions.length} result(s)`
|
|
779
|
+
: `${category.label} · ${category.actions.length} action(s)`,
|
|
583
780
|
leftRows: buildLeftRows(workspace, metrics.bodyRows),
|
|
584
781
|
contextRows: buildContextRows(workspace, category, action, metrics.contextWidth),
|
|
585
782
|
controlRows: buildActionRows(workspace, metrics.contextWidth, metrics.controlRows),
|
|
@@ -15,6 +15,9 @@ const TITLE_FG = DEFAULT_OVERLAY_PALETTE.titleFg;
|
|
|
15
15
|
const BODY_FG = DEFAULT_OVERLAY_PALETTE.bodyFg;
|
|
16
16
|
const MUTED_FG = DEFAULT_OVERLAY_PALETTE.mutedFg;
|
|
17
17
|
const SELECTED_BG = DEFAULT_OVERLAY_PALETTE.selectedBg;
|
|
18
|
+
const AUTOCOMPLETE_TITLE = ' Commands';
|
|
19
|
+
const AUTOCOMPLETE_EMPTY_QUERY = '/';
|
|
20
|
+
const AUTOCOMPLETE_HINTS = '[Tab] Complete [Up/Down] Navigate [Enter] Execute [Esc] Cancel';
|
|
18
21
|
|
|
19
22
|
interface CellStyle {
|
|
20
23
|
fg: string;
|
|
@@ -27,6 +30,23 @@ function putText(line: Line, startX: number, maxWidth: number, text: string, sty
|
|
|
27
30
|
putOverlayText(line, startX, maxWidth, text, style);
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
function autocompleteQueryText(query: string): string {
|
|
34
|
+
return query ? `/${query}` : AUTOCOMPLETE_EMPTY_QUERY;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function autocompleteScrollText(selected: string | number, total: string | number): string {
|
|
38
|
+
return `${selected}/${total}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function renderAutocompletePackageText(): string {
|
|
42
|
+
return [
|
|
43
|
+
AUTOCOMPLETE_TITLE.trim(),
|
|
44
|
+
autocompleteQueryText('<query>'),
|
|
45
|
+
autocompleteScrollText('<selected>', '<total>'),
|
|
46
|
+
AUTOCOMPLETE_HINTS,
|
|
47
|
+
].join('\n');
|
|
48
|
+
}
|
|
49
|
+
|
|
30
50
|
/**
|
|
31
51
|
* Render the slash command autocomplete dropdown as Line[] for overlay in the viewport.
|
|
32
52
|
*/
|
|
@@ -51,8 +71,8 @@ export function renderAutocompleteOverlay(
|
|
|
51
71
|
lines.push(createOverlayBorderLine(width, layout, '┌', '─', '┐', BORDER_FG));
|
|
52
72
|
|
|
53
73
|
const titleLine = createOverlayContentLine(width, layout);
|
|
54
|
-
const titleText =
|
|
55
|
-
const queryText = state.query
|
|
74
|
+
const titleText = AUTOCOMPLETE_TITLE;
|
|
75
|
+
const queryText = autocompleteQueryText(state.query);
|
|
56
76
|
const queryWidth = Math.min(Math.floor(layout.innerWidth / 2), Math.max(8, layout.innerWidth - getDisplayWidth(titleText) - 2));
|
|
57
77
|
const leftText = fitDisplay(titleText, Math.max(0, layout.innerWidth - queryWidth));
|
|
58
78
|
const rightText = truncateDisplay(queryText, queryWidth);
|
|
@@ -126,8 +146,8 @@ export function renderAutocompleteOverlay(
|
|
|
126
146
|
}
|
|
127
147
|
|
|
128
148
|
if (total > maxVisible) {
|
|
129
|
-
|
|
130
|
-
const scrollText =
|
|
149
|
+
const scrollLine = createOverlayContentLine(width, layout);
|
|
150
|
+
const scrollText = autocompleteScrollText(state.selectedIndex + 1, total);
|
|
131
151
|
putText(
|
|
132
152
|
scrollLine,
|
|
133
153
|
layout.margin + 2 + Math.max(0, layout.innerWidth - getDisplayWidth(scrollText)),
|
|
@@ -139,12 +159,11 @@ export function renderAutocompleteOverlay(
|
|
|
139
159
|
}
|
|
140
160
|
|
|
141
161
|
const footerLine = createOverlayContentLine(width, layout);
|
|
142
|
-
const hints = '[Tab] Complete [Up/Down] Navigate [Enter] Execute [Esc] Cancel';
|
|
143
162
|
putText(
|
|
144
163
|
footerLine,
|
|
145
164
|
layout.margin + 2,
|
|
146
165
|
layout.innerWidth,
|
|
147
|
-
fitDisplay(truncateDisplay(
|
|
166
|
+
fitDisplay(truncateDisplay(AUTOCOMPLETE_HINTS, layout.innerWidth), layout.innerWidth),
|
|
148
167
|
{ fg: MUTED_FG, dim: true },
|
|
149
168
|
);
|
|
150
169
|
lines.push(footerLine);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BlockMeta } from '../core/conversation';
|
|
2
2
|
|
|
3
|
-
export type BlockActionId = 'copy' | 'bookmark' | 'toggle' | '
|
|
3
|
+
export type BlockActionId = 'copy' | 'bookmark' | 'toggle' | 'rerun';
|
|
4
4
|
|
|
5
5
|
export interface BlockAction {
|
|
6
6
|
id: BlockActionId;
|
|
@@ -12,7 +12,6 @@ const ALL_ACTIONS: BlockAction[] = [
|
|
|
12
12
|
{ id: 'copy', label: 'Copy', key: 'c' },
|
|
13
13
|
{ id: 'bookmark', label: 'Bookmark', key: 'b' },
|
|
14
14
|
{ id: 'toggle', label: 'Collapse/Expand',key: 'Tab' },
|
|
15
|
-
{ id: 'apply', label: 'Diff apply blocked', key: 'a' },
|
|
16
15
|
{ id: 'rerun', label: 'Re-run tool', key: 'r' },
|
|
17
16
|
];
|
|
18
17
|
|
|
@@ -36,7 +35,6 @@ export class BlockActionsMenu {
|
|
|
36
35
|
open(block: BlockMeta): void {
|
|
37
36
|
this.block = block;
|
|
38
37
|
this.actions = ALL_ACTIONS.filter(a => {
|
|
39
|
-
if (a.id === 'apply') return block.type === 'diff';
|
|
40
38
|
if (a.id === 'rerun') return block.type === 'tool';
|
|
41
39
|
return true;
|
|
42
40
|
});
|