@pellux/goodvibes-agent 1.0.42 → 1.0.44
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 +10 -0
- package/dist/package/main.js +139 -299
- package/package.json +1 -1
- package/src/renderer/agent-workspace.ts +164 -326
- package/src/version.ts +1 -1
|
@@ -5,9 +5,9 @@ import type {
|
|
|
5
5
|
AgentWorkspaceLocalEditor,
|
|
6
6
|
AgentWorkspaceRuntimeSnapshot,
|
|
7
7
|
} from '../input/agent-workspace.ts';
|
|
8
|
-
import { formatAgentRecordReviewState
|
|
8
|
+
import { formatAgentRecordReviewState } from '../agent/record-labels.ts';
|
|
9
9
|
import type { Line } from '../types/grid.ts';
|
|
10
|
-
import { wrapText } from '../utils/terminal-width.ts';
|
|
10
|
+
import { truncateDisplay, wrapText } from '../utils/terminal-width.ts';
|
|
11
11
|
import { GLYPHS } from './ui-primitives.ts';
|
|
12
12
|
import {
|
|
13
13
|
getFullscreenWorkspaceMetrics,
|
|
@@ -62,31 +62,78 @@ function actionCommand(action: AgentWorkspaceAction): string {
|
|
|
62
62
|
return action.command ?? '(guidance)';
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
function
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
function setupCounts(snapshot: AgentWorkspaceRuntimeSnapshot): { ready: number; recommended: number; optional: number; blocked: number } {
|
|
66
|
+
return {
|
|
67
|
+
ready: snapshot.setupChecklist.filter((item) => item.status === 'ready').length,
|
|
68
|
+
recommended: snapshot.setupChecklist.filter((item) => item.status === 'recommended').length,
|
|
69
|
+
optional: snapshot.setupChecklist.filter((item) => item.status === 'optional').length,
|
|
70
|
+
blocked: snapshot.setupChecklist.filter((item) => item.status === 'blocked').length,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function setupStatusLabel(status: AgentWorkspaceRuntimeSnapshot['setupChecklist'][number]['status']): string {
|
|
75
|
+
return status === 'ready'
|
|
76
|
+
? 'Ready'
|
|
77
|
+
: status === 'recommended'
|
|
78
|
+
? 'Recommended'
|
|
79
|
+
: status === 'blocked'
|
|
80
|
+
? 'Blocked'
|
|
81
|
+
: 'Optional';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function compactText(text: string, maxWidth = 104): string {
|
|
85
|
+
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
86
|
+
if (normalized.length === 0) return '';
|
|
87
|
+
const firstSentence = normalized.match(/^.*?[.!?](?:\s|$)/)?.[0]?.trim();
|
|
88
|
+
const source = firstSentence && firstSentence.length <= maxWidth ? firstSentence : normalized;
|
|
89
|
+
return truncateDisplay(source, maxWidth, '...');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function actionMetaLine(action: AgentWorkspaceAction): ContextLine {
|
|
93
|
+
return {
|
|
94
|
+
text: `${actionCommand(action)}; ${action.safety}`,
|
|
95
|
+
fg: action.kind === 'command' ? PALETTE.info : safetyColor(action),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function setupAttentionItems(snapshot: AgentWorkspaceRuntimeSnapshot, limit: number): AgentWorkspaceRuntimeSnapshot['setupChecklist'] {
|
|
100
|
+
return [
|
|
101
|
+
...snapshot.setupChecklist.filter((item) => item.status === 'blocked'),
|
|
102
|
+
...snapshot.setupChecklist.filter((item) => item.status === 'recommended'),
|
|
103
|
+
...snapshot.setupChecklist.filter((item) => item.status === 'optional'),
|
|
104
|
+
].slice(0, limit);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function conciseSetupLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
|
|
108
|
+
const counts = setupCounts(snapshot);
|
|
109
|
+
return {
|
|
110
|
+
text: `Setup: ${counts.ready}/${snapshot.setupChecklist.length} ready; ${counts.recommended} recommended; ${counts.blocked} blocked.`,
|
|
111
|
+
fg: counts.blocked > 0 ? PALETTE.warn : PALETTE.info,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function setupOverviewLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
116
|
+
const counts = setupCounts(snapshot);
|
|
117
|
+
const nextItems = setupAttentionItems(snapshot, 3);
|
|
69
118
|
const lines: ContextLine[] = [
|
|
70
|
-
{ text: 'Setup
|
|
71
|
-
{ text: `${
|
|
119
|
+
{ text: 'Setup Overview', fg: PALETTE.title, bold: true },
|
|
120
|
+
{ text: `${counts.ready}/${snapshot.setupChecklist.length} ready; ${counts.recommended} recommended; ${counts.optional} optional; ${counts.blocked} blocked.`, fg: counts.blocked > 0 ? PALETTE.warn : PALETTE.info },
|
|
121
|
+
{ text: `Chat: ${snapshot.provider} / ${snapshot.modelDisplayName}.`, fg: PALETTE.info },
|
|
122
|
+
{ text: `Local: ${snapshot.localPersonaCount} personas, ${snapshot.localSkillCount} skills, ${snapshot.localRoutineCount} routines, ${snapshot.localMemoryCount} memories.`, fg: PALETTE.info },
|
|
72
123
|
];
|
|
73
|
-
|
|
74
|
-
const
|
|
124
|
+
if (nextItems.length > 0) {
|
|
125
|
+
const item = nextItems[0]!;
|
|
75
126
|
lines.push({
|
|
76
|
-
text:
|
|
127
|
+
text: `Next: ${item.label} (${setupStatusLabel(item.status).toLowerCase()})`,
|
|
77
128
|
fg: setupStatusColor(item.status),
|
|
78
129
|
bold: item.status === 'blocked',
|
|
79
130
|
});
|
|
80
|
-
lines.push({ text: ` ${item.detail}`, fg: PALETTE.muted });
|
|
81
131
|
}
|
|
82
132
|
return lines;
|
|
83
133
|
}
|
|
84
134
|
|
|
85
135
|
function homeNextActionLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
86
|
-
const
|
|
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);
|
|
136
|
+
const candidates = setupAttentionItems(snapshot, 3);
|
|
90
137
|
if (candidates.length === 0) {
|
|
91
138
|
return [
|
|
92
139
|
{ text: 'Next Actions', fg: PALETTE.title, bold: true },
|
|
@@ -95,13 +142,11 @@ function homeNextActionLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLi
|
|
|
95
142
|
}
|
|
96
143
|
const lines: ContextLine[] = [{ text: 'Next Actions', fg: PALETTE.title, bold: true }];
|
|
97
144
|
for (const item of candidates) {
|
|
98
|
-
const command = item.command ? ` -> ${item.command}` : '';
|
|
99
145
|
lines.push({
|
|
100
|
-
text: `${item.status
|
|
146
|
+
text: `${setupStatusLabel(item.status)}: ${item.label}`,
|
|
101
147
|
fg: setupStatusColor(item.status),
|
|
102
148
|
bold: item.status === 'blocked',
|
|
103
149
|
});
|
|
104
|
-
lines.push({ text: ` ${item.detail}`, fg: PALETTE.muted });
|
|
105
150
|
}
|
|
106
151
|
return lines;
|
|
107
152
|
}
|
|
@@ -115,79 +160,41 @@ function companionAccessLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLi
|
|
|
115
160
|
: 'missing';
|
|
116
161
|
const error = access.tokenError ? `; token read error ${access.tokenError}` : '';
|
|
117
162
|
return {
|
|
118
|
-
text: `Companion: ${access.surface}; token ${tokenState}; QR ${access.qrCommand}
|
|
163
|
+
text: `Companion: ${access.surface}; token ${tokenState}; QR ${access.qrCommand}${error}.`,
|
|
119
164
|
fg: access.pairingReady ? PALETTE.good : PALETTE.warn,
|
|
120
165
|
};
|
|
121
166
|
}
|
|
122
167
|
|
|
123
|
-
function
|
|
124
|
-
if (summary.count === 0) return [];
|
|
125
|
-
const names = summary.names.length > 0
|
|
126
|
-
? ` ${summary.names.join(', ')}${summary.count > summary.names.length ? `, +${summary.count - summary.names.length} more` : ''}.`
|
|
127
|
-
: '';
|
|
128
|
-
return [
|
|
129
|
-
{ text: `${label}: ${summary.count} discovered; project ${summary.projectLocalCount}; global ${summary.globalCount}.`, fg: PALETTE.info, bold: true },
|
|
130
|
-
{ text: ` Choose ${actionLabel} to preview, then use the import form after review.${names}`, fg: PALETTE.muted },
|
|
131
|
-
];
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function behaviorDiscoveryLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
135
|
-
const lines: ContextLine[] = [
|
|
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'),
|
|
139
|
-
];
|
|
140
|
-
if (lines.length === 0) return [];
|
|
141
|
-
return [
|
|
142
|
-
{ text: '' },
|
|
143
|
-
{ text: 'Discovered Behavior Files', fg: PALETTE.title, bold: true },
|
|
144
|
-
...lines,
|
|
145
|
-
];
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function localLibraryLines(
|
|
168
|
+
function compactLocalLibraryLines(
|
|
149
169
|
title: string,
|
|
150
170
|
items: readonly AgentWorkspaceRuntimeSnapshot['localPersonas'][number][],
|
|
151
171
|
emptyText: string,
|
|
152
172
|
selectedId: string | null,
|
|
153
173
|
): ContextLine[] {
|
|
154
|
-
const lines: ContextLine[] = [
|
|
155
|
-
{ text: title, fg: PALETTE.title, bold: true },
|
|
156
|
-
];
|
|
174
|
+
const lines: ContextLine[] = [];
|
|
157
175
|
if (items.length === 0) {
|
|
158
|
-
lines.push({ text: emptyText
|
|
176
|
+
lines.push({ text: `${title}: 0. ${emptyText}`, fg: PALETTE.warn });
|
|
159
177
|
return lines;
|
|
160
178
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
lines.push({
|
|
180
|
-
text: `${marker}${item.id}: ${item.name} (${status})`,
|
|
181
|
-
fg: item.reviewState === 'stale' ? PALETTE.warn : PALETTE.info,
|
|
182
|
-
bold: selected || item.active === true,
|
|
183
|
-
});
|
|
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
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (items.length > 8) {
|
|
190
|
-
lines.push({ text: `${items.length - 8} more item(s). Open the library command for the full list.`, fg: PALETTE.dim });
|
|
179
|
+
const selected = items.find((item) => item.id === selectedId) ?? items[0]!;
|
|
180
|
+
const status = [
|
|
181
|
+
selected.active ? 'active' : '',
|
|
182
|
+
selected.enabled === true ? 'enabled' : selected.enabled === false ? 'disabled' : '',
|
|
183
|
+
selected.scope && selected.cls ? `${selected.scope}/${selected.cls}` : '',
|
|
184
|
+
selected.confidence !== undefined ? `${selected.confidence}%` : '',
|
|
185
|
+
selected.requirementCount !== undefined && selected.requirementCount > 0
|
|
186
|
+
? (selected.missingRequirementCount && selected.missingRequirementCount > 0 ? `needs ${selected.missingRequirementCount}/${selected.requirementCount}` : `ready ${selected.requirementCount}/${selected.requirementCount}`)
|
|
187
|
+
: '',
|
|
188
|
+
formatAgentRecordReviewState(selected.reviewState),
|
|
189
|
+
selected.startCount !== undefined ? `starts ${selected.startCount}` : '',
|
|
190
|
+
].filter(Boolean).join(', ');
|
|
191
|
+
lines.push({
|
|
192
|
+
text: `${title}: ${items.length}; selected ${selected.name}${status ? ` (${status})` : ''}.`,
|
|
193
|
+
fg: selected.reviewState === 'stale' ? PALETTE.warn : PALETTE.info,
|
|
194
|
+
bold: selected.active === true,
|
|
195
|
+
});
|
|
196
|
+
if (selected.missingRequirements && selected.missingRequirements.length > 0) {
|
|
197
|
+
lines.push({ text: `Missing setup: ${selected.missingRequirements.join(', ')}`, fg: PALETTE.warn });
|
|
191
198
|
}
|
|
192
199
|
return lines;
|
|
193
200
|
}
|
|
@@ -234,23 +241,18 @@ function routineNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): Context
|
|
|
234
241
|
return { text: 'Next routine action: Start selected in the main conversation, inspect receipts, or reconcile connected schedules.', fg: PALETTE.info, bold: true };
|
|
235
242
|
}
|
|
236
243
|
|
|
237
|
-
function
|
|
244
|
+
function compactRoutineReceiptLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
|
|
238
245
|
const latest = snapshot.latestRoutineScheduleReceipt;
|
|
239
|
-
|
|
240
|
-
{
|
|
241
|
-
text: `Promotion receipts: ${snapshot.routineScheduleReceiptCount}; created
|
|
242
|
-
fg:
|
|
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 });
|
|
246
|
+
if (!latest) {
|
|
247
|
+
return {
|
|
248
|
+
text: `Promotion receipts: ${snapshot.routineScheduleReceiptCount}; none created yet.`,
|
|
249
|
+
fg: PALETTE.muted,
|
|
250
|
+
};
|
|
252
251
|
}
|
|
253
|
-
return
|
|
252
|
+
return {
|
|
253
|
+
text: `Promotion receipts: ${snapshot.routineScheduleReceiptCount}; latest ${latest.status} ${latest.routineId}.`,
|
|
254
|
+
fg: latest.status === 'failed' ? PALETTE.warn : PALETTE.good,
|
|
255
|
+
};
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
function automationNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
|
|
@@ -272,253 +274,107 @@ function automationNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): Cont
|
|
|
272
274
|
return { text: 'Next automation action: Create a reminder, or create/import a routine before recurring workflow promotion.', fg: PALETTE.warn, bold: true };
|
|
273
275
|
}
|
|
274
276
|
|
|
275
|
-
function profileLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
276
|
-
const lines: ContextLine[] = [
|
|
277
|
-
{ text: 'Agent Profiles', fg: PALETTE.title, bold: true },
|
|
278
|
-
];
|
|
279
|
-
if (snapshot.runtimeProfiles.length === 0) {
|
|
280
|
-
lines.push({ text: 'No isolated Agent profiles yet. Use Create Agent profile in this workspace.', fg: PALETTE.warn });
|
|
281
|
-
return lines;
|
|
282
|
-
}
|
|
283
|
-
for (const profile of snapshot.runtimeProfiles.slice(0, 6)) {
|
|
284
|
-
const starter = profile.starterTemplateId ? ` starter=${profile.starterTemplateId}` : ' starter=none';
|
|
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
|
-
});
|
|
296
|
-
lines.push({ text: ` home: ${profile.homeDirectory}`, fg: PALETTE.muted });
|
|
297
|
-
}
|
|
298
|
-
if (snapshot.runtimeProfiles.length > 6) {
|
|
299
|
-
lines.push({ text: `${snapshot.runtimeProfiles.length - 6} more profile(s).`, fg: PALETTE.dim });
|
|
300
|
-
}
|
|
301
|
-
return lines;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function starterTemplateLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
|
|
305
|
-
const lines: ContextLine[] = [
|
|
306
|
-
{ text: 'Starter Templates', fg: PALETTE.title, bold: true },
|
|
307
|
-
];
|
|
308
|
-
for (const template of snapshot.runtimeStarterTemplates.slice(0, 6)) {
|
|
309
|
-
const origin = template.source === 'local' ? 'Local' : formatAgentRecordSource(template.source);
|
|
310
|
-
lines.push({
|
|
311
|
-
text: `${template.id}: ${template.name} [${origin}]`,
|
|
312
|
-
fg: template.source === 'local' ? PALETTE.good : PALETTE.info,
|
|
313
|
-
bold: template.id === 'research',
|
|
314
|
-
});
|
|
315
|
-
lines.push({
|
|
316
|
-
text: ` ${template.description} Persona ${template.personaName}; skills ${template.skillNames.join(', ')}; routines ${template.routineNames.join(', ')}.`,
|
|
317
|
-
fg: PALETTE.muted,
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
if (snapshot.runtimeStarterTemplates.length > 6) {
|
|
321
|
-
lines.push({ text: `${snapshot.runtimeStarterTemplates.length - 6} more starter template(s).`, fg: PALETTE.dim });
|
|
322
|
-
}
|
|
323
|
-
return lines;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
277
|
function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCategory, snapshot: AgentWorkspaceRuntimeSnapshot | null): ContextLine[] {
|
|
327
278
|
if (!snapshot) return [{ text: 'Runtime context is not loaded yet.', fg: PALETTE.warn }];
|
|
328
|
-
const base: ContextLine[] = [
|
|
279
|
+
const base: ContextLine[] = [];
|
|
329
280
|
if (category.id === 'home') {
|
|
330
281
|
base.push(
|
|
331
282
|
{ text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
|
|
332
283
|
{ text: `Session: ${snapshot.sessionId}`, fg: PALETTE.muted },
|
|
333
284
|
{ text: `Policy: ${snapshot.executionPolicy}; delegated review ${snapshot.delegatedReviewPolicy}`, fg: PALETTE.good },
|
|
334
|
-
|
|
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: '' },
|
|
285
|
+
conciseSetupLine(snapshot),
|
|
338
286
|
...homeNextActionLines(snapshot),
|
|
339
287
|
);
|
|
340
288
|
} else if (category.id === 'setup') {
|
|
341
289
|
base.push(
|
|
342
|
-
|
|
343
|
-
{ text: 'Agent role: interactive operator TUI; setup changes here are Agent-local.', fg: PALETTE.good },
|
|
344
|
-
...setupChecklistLines(snapshot),
|
|
345
|
-
...behaviorDiscoveryLines(snapshot),
|
|
346
|
-
{ text: '' },
|
|
347
|
-
{ text: `Workspace: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
|
|
348
|
-
{ text: `Home: ${snapshot.homeDirectory}`, fg: PALETTE.muted },
|
|
290
|
+
...setupOverviewLines(snapshot),
|
|
349
291
|
);
|
|
350
292
|
} else if (category.id === 'artifacts') {
|
|
351
293
|
const mediaReady = snapshot.voiceMediaReadiness.readyMediaProviderCount;
|
|
352
294
|
base.push(
|
|
353
|
-
{ text: `Chat
|
|
354
|
-
{ text: `
|
|
355
|
-
{ text:
|
|
356
|
-
{ text: '
|
|
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 },
|
|
295
|
+
{ text: `Chat: ${snapshot.provider} / ${snapshot.modelDisplayName}; Knowledge: ${snapshot.knowledgeRoute}`, fg: PALETTE.info },
|
|
296
|
+
{ text: `Media: ${mediaReady}/${snapshot.mediaProviderCount} ready; generation ${snapshot.mediaGenerationProviderCount}.`, fg: mediaReady > 0 ? PALETTE.good : PALETTE.warn },
|
|
297
|
+
{ text: 'Files: attach, export, inspect, ingest reviewed sources, or generate media.', fg: PALETTE.good },
|
|
298
|
+
{ text: 'Knowledge ingest and media generation require explicit actions.', fg: PALETTE.warn },
|
|
360
299
|
);
|
|
361
300
|
} else if (category.id === 'channels') {
|
|
362
301
|
const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
|
|
363
302
|
const readyCount = snapshot.channels.filter((channel) => channel.ready).length;
|
|
364
303
|
const configuredDefaults = snapshot.channels.filter((channel) => channel.defaultTarget === 'configured').length;
|
|
365
|
-
const readyChannels = snapshot.channels.filter((channel) => channel.ready).map((channel) => channel.label);
|
|
366
304
|
const needsTarget = snapshot.channels.filter((channel) => channel.setupState === 'needs-target');
|
|
367
305
|
const needsConfig = snapshot.channels.filter((channel) => channel.setupState === 'needs-config');
|
|
368
306
|
const nextAttentionChannel = needsConfig[0] ?? needsTarget[0] ?? snapshot.channels.find((channel) => !channel.enabled);
|
|
369
|
-
const disabledChannels = snapshot.channels.filter((channel) => !channel.enabled).map((channel) => channel.label);
|
|
370
|
-
const disabledPreview = disabledChannels.slice(0, 6).join(', ');
|
|
371
|
-
const disabledSuffix = disabledChannels.length > 6 ? `, +${disabledChannels.length - 6} more` : '';
|
|
372
|
-
const orderedChannels = [
|
|
373
|
-
...snapshot.channels.filter((channel) => channel.enabled),
|
|
374
|
-
...snapshot.channels.filter((channel) => !channel.enabled),
|
|
375
|
-
].slice(0, 3);
|
|
376
307
|
base.push(
|
|
377
|
-
{ text: `
|
|
308
|
+
{ text: `API: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
|
|
378
309
|
companionAccessLine(snapshot),
|
|
379
|
-
{ text: `
|
|
380
|
-
{ text:
|
|
381
|
-
{ text:
|
|
382
|
-
{ text: `Ready channels: ${readyChannels.join(', ') || 'none'}.`, fg: readyChannels.length > 0 ? PALETTE.good : PALETTE.warn },
|
|
383
|
-
{ text: `Needs default target: ${needsTarget.map((channel) => `${channel.label} -> ${channel.defaultTargetKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsTarget.length > 0 ? PALETTE.warn : PALETTE.muted },
|
|
384
|
-
{ text: `Needs config: ${needsConfig.map((channel) => `${channel.label} -> ${channel.missingRequiredKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsConfig.length > 0 ? PALETTE.warn : PALETTE.muted },
|
|
385
|
-
{ text: `Disabled channels: ${disabledPreview || 'none'}${disabledSuffix}.`, fg: PALETTE.dim },
|
|
386
|
-
{ text: 'Safety: no secret values; sends and public exposure require explicit user action and Agent policy.', fg: PALETTE.warn },
|
|
310
|
+
{ text: `Channels: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} target(s).`, fg: PALETTE.info },
|
|
311
|
+
{ text: `Next: ${nextAttentionChannel ? `${nextAttentionChannel.label} - ${compactText(nextAttentionChannel.nextStep)}` : 'All enabled channels ready.'}`, fg: nextAttentionChannel ? PALETTE.warn : PALETTE.good },
|
|
312
|
+
{ text: 'Safety: secrets hidden; sends require explicit action.', fg: PALETTE.warn },
|
|
387
313
|
);
|
|
388
|
-
for (const channel of orderedChannels) {
|
|
389
|
-
const ready = channel.ready ? 'ready' : `${channel.missingConfigCount} missing`;
|
|
390
|
-
base.push({
|
|
391
|
-
text: `${channel.label}: ${channel.setupState}; ${ready}; target ${channel.defaultTarget}; delivery ${channel.delivery}; risk ${channel.risk}.`,
|
|
392
|
-
fg: channel.ready ? PALETTE.good : channel.enabled ? PALETTE.warn : PALETTE.dim,
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
314
|
} else if (category.id === 'knowledge') {
|
|
396
315
|
base.push(
|
|
397
|
-
{ text: `Route
|
|
398
|
-
{ text:
|
|
399
|
-
{ text: 'Ingest
|
|
400
|
-
{ text: 'Review: queue, issues, candidates, reports, reindex, and consolidation stay inside the Agent segment.', fg: PALETTE.muted },
|
|
401
|
-
{ text: 'Agent-owned content appears here only after explicit Agent knowledge ingestion.', fg: PALETTE.muted },
|
|
316
|
+
{ text: `Route: ${snapshot.knowledgeRoute}; isolation ${snapshot.knowledgeIsolation}.`, fg: PALETTE.info },
|
|
317
|
+
{ text: 'Ask/search, ingest, review, reindex, and reports stay Agent-owned.', fg: PALETTE.good },
|
|
318
|
+
{ text: 'Ingest requires explicit confirmation.', fg: PALETTE.warn },
|
|
402
319
|
);
|
|
403
320
|
} else if (category.id === 'research') {
|
|
404
321
|
base.push(
|
|
405
|
-
{ text: `Chat
|
|
406
|
-
{ text: `
|
|
407
|
-
{ text:
|
|
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 },
|
|
322
|
+
{ text: `Chat: ${snapshot.provider} / ${snapshot.modelDisplayName}; Knowledge: ${snapshot.knowledgeRoute}`, fg: PALETTE.info },
|
|
323
|
+
{ text: `Browser: ${snapshot.voiceMediaReadiness.browserToolState}; public URL ${snapshot.browserToolPublicBaseUrl}.`, fg: snapshot.browserToolExposureEnabled ? PALETTE.warn : PALETTE.muted },
|
|
324
|
+
{ text: 'Research is read-only. Knowledge ingest is a separate confirmed action.', fg: PALETTE.good },
|
|
325
|
+
{ text: compactText(snapshot.voiceMediaReadiness.browserToolNextStep), fg: PALETTE.muted },
|
|
413
326
|
);
|
|
414
327
|
} else if (category.id === 'tools') {
|
|
415
328
|
base.push(
|
|
416
329
|
{ 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 },
|
|
417
|
-
{ text: '
|
|
418
|
-
{ text: '
|
|
419
|
-
{ text: 'Trust changes remain explicit; allow-all is kept behind the settings workspace.', fg: PALETTE.warn },
|
|
420
|
-
{ text: 'Useful first actions: /mcp review, /mcp tools, /mcp config, and Add MCP server.', fg: PALETTE.muted },
|
|
421
|
-
{ text: 'Normal assistant chat can use tools serially when policy allows; onboarding does not start hidden tool work.', fg: PALETTE.muted },
|
|
330
|
+
{ text: 'Add/update/reload and trust changes require confirmation.', fg: PALETTE.good },
|
|
331
|
+
{ text: 'Start: /mcp review, /mcp tools, /mcp config, Add MCP server.', fg: PALETTE.muted },
|
|
422
332
|
);
|
|
423
333
|
} else if (category.id === 'voice-media') {
|
|
424
334
|
const readiness = snapshot.voiceMediaReadiness;
|
|
425
|
-
const voiceRows = readiness.voiceProviders.slice(0, 6);
|
|
426
|
-
const mediaRows = readiness.mediaProviders.slice(0, 6);
|
|
427
335
|
base.push(
|
|
428
|
-
{ text: `Voice
|
|
429
|
-
{ text: `
|
|
430
|
-
{ text: `
|
|
431
|
-
{ text:
|
|
432
|
-
{ text:
|
|
433
|
-
{ text: `Ready media providers: ${readiness.readyMediaProviderCount}/${snapshot.mediaProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? PALETTE.good : PALETTE.warn },
|
|
434
|
-
{ text: `Browser tools: ${readiness.browserToolState}; public base URL ${snapshot.browserToolPublicBaseUrl}.`, fg: snapshot.browserToolExposureEnabled ? PALETTE.warn : PALETTE.muted },
|
|
435
|
-
{ text: readiness.browserToolNextStep, fg: PALETTE.muted },
|
|
436
|
-
{ text: 'Voice provider readiness', fg: PALETTE.title, bold: true },
|
|
437
|
-
);
|
|
438
|
-
for (const provider of voiceRows) {
|
|
439
|
-
const selected = provider.selected ? 'selected; ' : '';
|
|
440
|
-
const missing = provider.missingSecretKeyOptions.length > 0 ? `; needs ${provider.missingSecretKeyOptions.join('|')}` : '';
|
|
441
|
-
base.push({
|
|
442
|
-
text: `${provider.label}: ${selected}${provider.setupState}; ${provider.features.join(', ') || 'registered'}${missing}.`,
|
|
443
|
-
fg: provider.setupState === 'ready' ? PALETTE.good : provider.setupState === 'needs-secret' ? PALETTE.warn : PALETTE.muted,
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
if (snapshot.voiceProviderCount > voiceRows.length) base.push({ text: `${snapshot.voiceProviderCount - voiceRows.length} more voice provider(s).`, fg: PALETTE.dim });
|
|
447
|
-
base.push({ text: 'Media provider readiness', fg: PALETTE.title, bold: true });
|
|
448
|
-
for (const provider of mediaRows) {
|
|
449
|
-
const missing = provider.missingSecretKeyOptions.length > 0 ? `; needs ${provider.missingSecretKeyOptions.join('|')}` : '';
|
|
450
|
-
base.push({
|
|
451
|
-
text: `${provider.label}: ${provider.setupState}; ${provider.features.join(', ') || 'registered'}${missing}.`,
|
|
452
|
-
fg: provider.setupState === 'ready' ? PALETTE.good : provider.setupState === 'needs-secret' ? PALETTE.warn : PALETTE.muted,
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
if (snapshot.mediaProviderCount > mediaRows.length) base.push({ text: `${snapshot.mediaProviderCount - mediaRows.length} more media provider(s).`, fg: PALETTE.dim });
|
|
456
|
-
for (const step of readiness.nextSteps.slice(0, 4)) base.push({ text: `Next: ${step}`, fg: PALETTE.info });
|
|
457
|
-
base.push(
|
|
458
|
-
{ text: 'No secret values are rendered. Voice, browser, and generated media side effects require explicit user action.', fg: PALETTE.warn },
|
|
459
|
-
{ text: 'Image input uses prompt attachments; media generation/provider setup stays behind explicit commands and configured providers.', fg: PALETTE.muted },
|
|
336
|
+
{ text: `Voice: ${readiness.readyVoiceProviderCount}/${snapshot.voiceProviderCount} ready; TTS ${snapshot.ttsProvider}; voice ${snapshot.ttsVoice}.`, fg: readiness.readyVoiceProviderCount > 0 ? PALETTE.good : PALETTE.warn },
|
|
337
|
+
{ text: `Media: ${readiness.readyMediaProviderCount}/${snapshot.mediaProviderCount} ready; generation ${snapshot.mediaGenerationProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? PALETTE.good : PALETTE.warn },
|
|
338
|
+
{ text: `Browser: ${readiness.browserToolState}; public URL ${snapshot.browserToolPublicBaseUrl}.`, fg: snapshot.browserToolExposureEnabled ? PALETTE.warn : PALETTE.muted },
|
|
339
|
+
{ text: readiness.nextSteps[0] ? `Next: ${compactText(readiness.nextSteps[0])}` : 'Next: voice/media setup is ready.', fg: readiness.nextSteps.length > 0 ? PALETTE.info : PALETTE.good },
|
|
340
|
+
{ text: 'Secrets hidden; voice, browser, and media side effects require explicit action.', fg: PALETTE.warn },
|
|
460
341
|
);
|
|
461
342
|
} else if (category.id === 'profiles') {
|
|
462
343
|
const defaultProfile = snapshot.selectedRuntimeProfile
|
|
463
344
|
? `${snapshot.selectedRuntimeProfile}${snapshot.selectedRuntimeProfileExists ? '' : ' (missing)'}`
|
|
464
345
|
: '(base Agent home)';
|
|
465
346
|
base.push(
|
|
466
|
-
{ text: `
|
|
467
|
-
{ text: `
|
|
468
|
-
{ text: `
|
|
469
|
-
{ text:
|
|
470
|
-
{ text: `Starter ids: ${snapshot.runtimeStarterTemplates.map((template) => template.id).join(', ') || 'none'}`, fg: PALETTE.info },
|
|
471
|
-
{ text: 'Starter Templates', fg: PALETTE.title, bold: true },
|
|
472
|
-
{ text: `Agent profile root: ${snapshot.runtimeProfileRoot}`, fg: PALETTE.muted },
|
|
473
|
-
{ text: '' },
|
|
474
|
-
...profileLines(snapshot),
|
|
475
|
-
{ text: '' },
|
|
476
|
-
...starterTemplateLines(snapshot),
|
|
477
|
-
{ text: '' },
|
|
478
|
-
{ text: 'Named Agent profiles isolate local config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
|
|
479
|
-
{ text: 'Starter authoring: browse, export, edit, import, and create Agent profiles from inside this workspace.', fg: PALETTE.info },
|
|
480
|
-
{ text: 'The connected GoodVibes host stays shared unless that host is configured separately.', fg: PALETTE.warn },
|
|
481
|
-
{ text: 'Portable bundles require explicit export/import commands with real paths and --yes.', fg: PALETTE.muted },
|
|
347
|
+
{ text: `Profiles: active ${snapshot.activeRuntimeProfile}; default ${defaultProfile}.`, fg: snapshot.selectedRuntimeProfileExists || !snapshot.selectedRuntimeProfile ? PALETTE.info : PALETTE.warn },
|
|
348
|
+
{ text: `Local profiles: ${snapshot.runtimeProfileCount}; starters ${snapshot.runtimeStarterTemplateCount}; custom ${snapshot.localStarterTemplateCount}.`, fg: PALETTE.info },
|
|
349
|
+
{ text: `Starter ids: ${truncateDisplay(snapshot.runtimeStarterTemplates.map((template) => template.id).join(', ') || 'none', 96, '...')}`, fg: PALETTE.muted },
|
|
350
|
+
{ text: 'Profiles isolate local Agent config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
|
|
482
351
|
);
|
|
483
352
|
} else if (category.id === 'memory') {
|
|
484
353
|
base.push(
|
|
485
|
-
{ text: `
|
|
486
|
-
{ text: `
|
|
487
|
-
{ text: `
|
|
488
|
-
|
|
489
|
-
{ text:
|
|
490
|
-
{ text: `Local personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
|
|
491
|
-
{ text: 'Durable memory, scratchpad notes, routines, skills, and personas remain Agent-local until shared registry contracts exist.', fg: PALETTE.good },
|
|
492
|
-
{ text: 'Secrets are rejected/redacted; store secret references instead of secret values.', fg: PALETTE.warn },
|
|
493
|
-
{ text: '' },
|
|
494
|
-
...localLibraryLines('Agent Memory', snapshot.localMemories, 'No Agent memory yet. Create one here with Create memory.', workspace.selectedLocalLibraryItem('memory')?.id ?? null),
|
|
354
|
+
{ text: `Memory: ${snapshot.localMemoryCount}; prompt ${snapshot.localMemoryPromptActiveCount}; queue ${snapshot.localMemoryReviewQueueCount}; session ${snapshot.sessionMemoryCount}.`, fg: PALETTE.info },
|
|
355
|
+
{ text: `Notes: ${snapshot.localNoteCount}; skills ${snapshot.localSkillCount}/${snapshot.enabledSkillCount}; routines ${snapshot.localRoutineCount}/${snapshot.enabledRoutineCount}; personas ${snapshot.localPersonaCount}.`, fg: PALETTE.info },
|
|
356
|
+
{ text: `Active persona: ${snapshot.activePersonaName}.`, fg: PALETTE.info },
|
|
357
|
+
...compactLocalLibraryLines('Agent Memory', snapshot.localMemories, 'Create one with Create memory.', workspace.selectedLocalLibraryItem('memory')?.id ?? null),
|
|
358
|
+
{ text: 'Secrets are rejected or redacted; use secret references.', fg: PALETTE.warn },
|
|
495
359
|
);
|
|
496
360
|
} else if (category.id === 'notes') {
|
|
497
361
|
base.push(
|
|
498
362
|
{ text: `Scratchpad notes: ${snapshot.localNoteCount}; review queue: ${snapshot.localNoteReviewQueueCount}`, fg: PALETTE.info },
|
|
499
|
-
|
|
500
|
-
{ text: 'Notes
|
|
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),
|
|
363
|
+
...compactLocalLibraryLines('Scratchpad Notes', snapshot.localNotes, 'Create one with Create note.', workspace.selectedLocalLibraryItem('note')?.id ?? null),
|
|
364
|
+
{ text: 'Notes stay local unless promoted by explicit action.', fg: PALETTE.warn },
|
|
504
365
|
);
|
|
505
366
|
} else if (category.id === 'personas') {
|
|
506
367
|
base.push(
|
|
507
368
|
{ text: `Personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
|
|
508
|
-
|
|
509
|
-
{ text: '
|
|
510
|
-
{ text: '' },
|
|
511
|
-
...localLibraryLines('Persona Library', snapshot.localPersonas, 'No local personas yet. Create one here with Create persona.', workspace.selectedLocalLibraryItem('persona')?.id ?? null),
|
|
369
|
+
...compactLocalLibraryLines('Persona Library', snapshot.localPersonas, 'Create one with Create persona.', workspace.selectedLocalLibraryItem('persona')?.id ?? null),
|
|
370
|
+
{ text: 'Personas shape the serial main-conversation assistant.', fg: PALETTE.good },
|
|
512
371
|
);
|
|
513
372
|
} else if (category.id === 'skills') {
|
|
514
373
|
base.push(
|
|
515
374
|
{ text: `Skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}; bundles: ${snapshot.localSkillBundleCount}; enabled bundles: ${snapshot.enabledSkillBundleCount}; active skills: ${snapshot.activeSkillCount}`, fg: PALETTE.info },
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
{ text: '' },
|
|
519
|
-
...localLibraryLines('Skill Library', snapshot.localSkills, 'No local skills yet. Create one here with Create skill.', workspace.selectedLocalLibraryItem('skill')?.id ?? null),
|
|
520
|
-
{ text: '' },
|
|
521
|
-
...localLibraryLines('Skill Bundles', snapshot.localSkillBundles, 'No local skill bundles yet. Use Skill bundles and Create bundle after creating skills.', null),
|
|
375
|
+
...compactLocalLibraryLines('Skill Library', snapshot.localSkills, 'Create one with Create skill.', workspace.selectedLocalLibraryItem('skill')?.id ?? null),
|
|
376
|
+
...compactLocalLibraryLines('Skill Bundles', snapshot.localSkillBundles, 'Create one after adding skills.', null),
|
|
377
|
+
{ text: 'Enabled skills/bundles become operating guidance; secrets are rejected.', fg: PALETTE.warn },
|
|
522
378
|
);
|
|
523
379
|
} else if (category.id === 'routines') {
|
|
524
380
|
const ready = readyRoutineItems(snapshot);
|
|
@@ -527,42 +383,34 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
527
383
|
base.push(
|
|
528
384
|
{ text: `Routines: ${snapshot.localRoutineCount}; enabled: ${snapshot.enabledRoutineCount}`, fg: PALETTE.info },
|
|
529
385
|
{ 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 },
|
|
530
|
-
{ text: 'Routines are repeatable main-conversation workflows. Starting one does not create hidden jobs.', fg: PALETTE.good },
|
|
531
|
-
{ text: 'Scheduling a reviewed routine is explicit and requires a confirmed schedule command.', fg: PALETTE.warn },
|
|
532
386
|
routineNextActionLine(snapshot),
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
387
|
+
compactRoutineReceiptLine(snapshot),
|
|
388
|
+
...compactLocalLibraryLines('Routine Library', snapshot.localRoutines, 'Create one with Create routine.', workspace.selectedLocalLibraryItem('routine')?.id ?? null),
|
|
389
|
+
{ text: 'Scheduling requires a confirmed action.', fg: PALETTE.warn },
|
|
536
390
|
);
|
|
537
391
|
} else if (category.id === 'work') {
|
|
538
392
|
base.push(
|
|
539
|
-
{ text: 'Work
|
|
540
|
-
{ text: '
|
|
541
|
-
{ text: '
|
|
393
|
+
{ text: 'Work plans and approvals are read or explicitly confirmed.', fg: PALETTE.info },
|
|
394
|
+
{ text: 'Selection alone does not approve, deny, cancel, or mutate requests.', fg: PALETTE.good },
|
|
395
|
+
{ text: 'Approval actions require id plus typed confirmation.', fg: PALETTE.warn },
|
|
542
396
|
);
|
|
543
397
|
} else if (category.id === 'automation') {
|
|
544
398
|
const ready = readyRoutineItems(snapshot);
|
|
545
399
|
base.push(
|
|
546
|
-
{ text:
|
|
547
|
-
{ text: 'Confirmed reminders and routine promotion use connected schedules only.', fg: PALETTE.info },
|
|
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 },
|
|
400
|
+
{ text: `Automation: ${ready.length} schedule-ready routine(s); receipts ${snapshot.routineScheduleReceiptCount}.`, fg: ready.length > 0 ? PALETTE.good : PALETTE.warn },
|
|
553
401
|
automationNextActionLine(snapshot),
|
|
554
|
-
|
|
402
|
+
compactRoutineReceiptLine(snapshot),
|
|
403
|
+
{ text: 'Reminders and routine promotion require confirmation.', fg: PALETTE.warn },
|
|
555
404
|
);
|
|
556
405
|
} else if (category.id === 'delegate') {
|
|
557
406
|
base.push(
|
|
558
|
-
{ text: 'Build/fix/review work is handed to GoodVibes TUI
|
|
407
|
+
{ text: 'Build/fix/review work is handed to GoodVibes TUI.', fg: PALETTE.info },
|
|
559
408
|
{ text: `Delegated review policy: ${snapshot.delegatedReviewPolicy}`, fg: PALETTE.warn },
|
|
560
|
-
{ text: '
|
|
409
|
+
{ text: 'No coding-role Agent jobs are created here.', fg: PALETTE.good },
|
|
561
410
|
);
|
|
562
411
|
}
|
|
563
412
|
if (snapshot.warnings.length > 0) {
|
|
564
|
-
base.push({ text:
|
|
565
|
-
for (const warning of snapshot.warnings) base.push({ text: warning, fg: PALETTE.warn });
|
|
413
|
+
base.push({ text: `Warnings: ${snapshot.warnings.map((warning) => compactText(warning, 60)).join('; ')}`, fg: PALETTE.warn });
|
|
566
414
|
}
|
|
567
415
|
return base;
|
|
568
416
|
}
|
|
@@ -571,14 +419,13 @@ function editorContextLines(editor: AgentWorkspaceLocalEditor): ContextLine[] {
|
|
|
571
419
|
const selected = editor.fields[editor.selectedFieldIndex];
|
|
572
420
|
const lines: ContextLine[] = [
|
|
573
421
|
{ text: editor.title, fg: PALETTE.title, bold: true },
|
|
574
|
-
{ text: editor.message, fg: editor.message.includes('required') || editor.message.includes('cannot') || editor.message.includes('Cannot') ? PALETTE.warn : PALETTE.info },
|
|
575
|
-
{ text: 'Enter
|
|
422
|
+
{ text: compactText(editor.message), fg: editor.message.includes('required') || editor.message.includes('cannot') || editor.message.includes('Cannot') ? PALETTE.warn : PALETTE.info },
|
|
423
|
+
{ text: 'Enter next/save; Ctrl-J newline; Esc cancel.', fg: PALETTE.muted },
|
|
576
424
|
];
|
|
577
425
|
if (selected) {
|
|
578
426
|
lines.push(
|
|
579
|
-
{ text: '' },
|
|
580
427
|
{ text: `Editing: ${selected.label}${selected.required ? ' (required)' : ''}`, fg: PALETTE.title, bold: true },
|
|
581
|
-
{ text: selected.hint, fg: PALETTE.muted },
|
|
428
|
+
{ text: compactText(selected.hint), fg: PALETTE.muted },
|
|
582
429
|
);
|
|
583
430
|
}
|
|
584
431
|
return lines;
|
|
@@ -588,9 +435,6 @@ function buildContextRows(workspace: AgentWorkspace, category: AgentWorkspaceCat
|
|
|
588
435
|
const lines: ContextLine[] = [
|
|
589
436
|
{ text: category.label, fg: PALETTE.title, bold: true },
|
|
590
437
|
{ text: category.summary, fg: PALETTE.subtitle },
|
|
591
|
-
{ text: '' },
|
|
592
|
-
{ text: category.detail, fg: PALETTE.text },
|
|
593
|
-
{ text: '' },
|
|
594
438
|
...(workspace.actionSearchActive ? [
|
|
595
439
|
{ text: 'Action Search', fg: PALETTE.title, bold: true },
|
|
596
440
|
{
|
|
@@ -599,30 +443,25 @@ function buildContextRows(workspace: AgentWorkspace, category: AgentWorkspaceCat
|
|
|
599
443
|
: 'Type to search every Agent workspace action.',
|
|
600
444
|
fg: workspace.actionSearchQuery.length > 0 && workspace.actionSearchResults.length === 0 ? PALETTE.warn : PALETTE.info,
|
|
601
445
|
},
|
|
602
|
-
{ text: 'Enter opens
|
|
603
|
-
{ text: '' },
|
|
446
|
+
{ text: 'Enter opens; Esc clears.', fg: PALETTE.muted },
|
|
604
447
|
] satisfies ContextLine[] : []),
|
|
605
448
|
...(workspace.localEditor ? editorContextLines(workspace.localEditor) : []),
|
|
606
|
-
...(workspace.localEditor ? [{ text: '' }] : []),
|
|
607
|
-
...snapshotLines(workspace, category, workspace.runtimeSnapshot),
|
|
608
449
|
];
|
|
609
450
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
{ text: '' },
|
|
451
|
+
const selectedActionLines: ContextLine[] = action
|
|
452
|
+
? [
|
|
613
453
|
{ text: `Selected: ${action.label}`, fg: PALETTE.title, bold: true },
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
454
|
+
actionMetaLine(action),
|
|
455
|
+
]
|
|
456
|
+
: [];
|
|
457
|
+
const snapshotContextLines = snapshotLines(workspace, category, workspace.runtimeSnapshot);
|
|
458
|
+
lines.push(...selectedActionLines, ...snapshotContextLines);
|
|
619
459
|
|
|
620
460
|
if (workspace.lastActionResult) {
|
|
621
461
|
lines.push(
|
|
622
|
-
{ text: '' },
|
|
623
462
|
{ text: 'Action Result', fg: PALETTE.title, bold: true },
|
|
624
463
|
{ text: workspace.lastActionResult.title, fg: actionResultColor(workspace.lastActionResult), bold: true },
|
|
625
|
-
{ text: workspace.lastActionResult.detail, fg: PALETTE.text },
|
|
464
|
+
{ text: compactText(workspace.lastActionResult.detail), fg: PALETTE.text },
|
|
626
465
|
);
|
|
627
466
|
if (workspace.lastActionResult.command) {
|
|
628
467
|
lines.push({ text: `Command: ${workspace.lastActionResult.command}`, fg: PALETTE.muted });
|
|
@@ -758,13 +597,12 @@ function footerText(workspace: AgentWorkspace): string {
|
|
|
758
597
|
export function renderAgentWorkspace(workspace: AgentWorkspace, width: number, height: number): Line[] {
|
|
759
598
|
const category = workspace.selectedActionCategory;
|
|
760
599
|
const action = workspace.selectedAction;
|
|
761
|
-
const setupCategory = category.id === 'setup';
|
|
762
600
|
const layoutOptions = {
|
|
763
601
|
width,
|
|
764
602
|
height,
|
|
765
603
|
leftWidth: width < 90 ? undefined : 30,
|
|
766
|
-
contextRatio:
|
|
767
|
-
minContextRows:
|
|
604
|
+
contextRatio: 0.4,
|
|
605
|
+
minContextRows: 10,
|
|
768
606
|
};
|
|
769
607
|
const metrics = getFullscreenWorkspaceMetrics(layoutOptions);
|
|
770
608
|
|