@pellux/goodvibes-agent 1.0.43 → 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 CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Product-facing release notes for GoodVibes Agent.
4
4
 
5
+ ## 1.0.44 - 2026-06-05
6
+
7
+ - Compact Agent workspace top-pane copy across every category so the fullscreen onboarding surface keeps settings and actions visible.
8
+
5
9
  ## 1.0.43 - 2026-06-05
6
10
 
7
11
  - Keep the Agent Home and Setup workspace top pane compact so setup actions stay visible.
@@ -817087,7 +817087,7 @@ var createStyledCell = (char, overrides = {}) => ({
817087
817087
  // src/version.ts
817088
817088
  import { readFileSync } from "fs";
817089
817089
  import { join } from "path";
817090
- var _version = "1.0.43";
817090
+ var _version = "1.0.44";
817091
817091
  try {
817092
817092
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
817093
817093
  _version = typeof pkg.version === "string" ? pkg.version : _version;
@@ -849793,13 +849793,13 @@ init_state3();
849793
849793
 
849794
849794
  // src/input/commands/recall-shared.ts
849795
849795
  var VALID_CLASSES = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
849796
- var VALID_SCOPES2 = ["session", "project", "team"];
849796
+ var VALID_SCOPES = ["session", "project", "team"];
849797
849797
  var VALID_REVIEW_STATES = ["fresh", "reviewed", "stale", "contradicted"];
849798
849798
  function isValidClass(s4) {
849799
849799
  return VALID_CLASSES.includes(s4);
849800
849800
  }
849801
849801
  function isValidScope(s4) {
849802
- return VALID_SCOPES2.includes(s4);
849802
+ return VALID_SCOPES.includes(s4);
849803
849803
  }
849804
849804
  function isValidReviewState(s4) {
849805
849805
  return VALID_REVIEW_STATES.includes(s4);
@@ -849842,7 +849842,7 @@ function handleRecallSearch(args2, context) {
849842
849842
  if (isValidScope(scope))
849843
849843
  filter.scope = scope;
849844
849844
  else {
849845
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
849845
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
849846
849846
  return;
849847
849847
  }
849848
849848
  }
@@ -850017,7 +850017,7 @@ function handleRecallList(args2, context) {
850017
850017
  if (scopeIdx !== -1 && args2[scopeIdx + 1]) {
850018
850018
  const scope = args2[scopeIdx + 1];
850019
850019
  if (!isValidScope(scope)) {
850020
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850020
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
850021
850021
  return;
850022
850022
  }
850023
850023
  filter.scope = scope;
@@ -850067,7 +850067,7 @@ async function handleRecallAdd(args2, context) {
850067
850067
  const tags = tagsRaw ? tagsRaw.split(",").map((token) => token.trim()).filter(Boolean) : [];
850068
850068
  const scope = scopeRaw && isValidScope(scopeRaw) ? scopeRaw : "project";
850069
850069
  if (scopeRaw && !isValidScope(scopeRaw)) {
850070
- context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850070
+ context.print(`[memory] Invalid scope "${scopeRaw}". Valid values ${VALID_SCOPES.join(", ")}.`);
850071
850071
  return;
850072
850072
  }
850073
850073
  const provenance = [];
@@ -850201,7 +850201,7 @@ function handleRecallExport(args2, context) {
850201
850201
  if (scopeIdx !== -1 && commandArgs[scopeIdx + 1]) {
850202
850202
  const scope = commandArgs[scopeIdx + 1];
850203
850203
  if (!isValidScope(scope)) {
850204
- context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850204
+ context.print(`[memory] Unknown scope "${scope}". Valid values ${VALID_SCOPES.join(", ")}.`);
850205
850205
  return;
850206
850206
  }
850207
850207
  filter.scope = scope;
@@ -850280,7 +850280,7 @@ function handleRecallHandoffExport(args2, context) {
850280
850280
  const scopeIdx = commandArgs.indexOf("--scope");
850281
850281
  const scopeRaw = scopeIdx !== -1 ? commandArgs[scopeIdx + 1] : "team";
850282
850282
  if (!scopeRaw || !isValidScope(scopeRaw)) {
850283
- context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES2.join(", ")}.`);
850283
+ context.print(`[memory] Unknown scope "${scopeRaw ?? ""}". Valid values ${VALID_SCOPES.join(", ")}.`);
850284
850284
  return;
850285
850285
  }
850286
850286
  const bundle = memory.exportBundle({ scope: scopeRaw });
@@ -850396,7 +850396,7 @@ function handleRecallPromote(args2, context) {
850396
850396
  const id = parsed.rest[0];
850397
850397
  const scope = parsed.rest[1];
850398
850398
  if (!id || !scope || !isValidScope(scope)) {
850399
- context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES2.join("|")}> --yes`);
850399
+ context.print(`[memory] Usage: /memory promote <id> <${VALID_SCOPES.join("|")}> --yes`);
850400
850400
  return;
850401
850401
  }
850402
850402
  if (!parsed.yes) {
@@ -866501,7 +866501,7 @@ import { mkdirSync as mkdirSync66, readFileSync as readFileSync88, writeFileSync
866501
866501
  import { dirname as dirname63, resolve as resolve39 } from "path";
866502
866502
  init_state3();
866503
866503
  var VALID_CLASSES2 = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
866504
- var VALID_SCOPES4 = ["session", "project", "team"];
866504
+ var VALID_SCOPES3 = ["session", "project", "team"];
866505
866505
  var VALID_REVIEW_STATES3 = ["fresh", "reviewed", "stale", "contradicted"];
866506
866506
  var VALID_PROVENANCE_KINDS = ["session", "turn", "task", "event", "file"];
866507
866507
  var VALUE_OPTIONS = new Set([
@@ -866601,7 +866601,7 @@ function isMemoryClass2(value) {
866601
866601
  return VALID_CLASSES2.includes(value);
866602
866602
  }
866603
866603
  function isMemoryScope2(value) {
866604
- return VALID_SCOPES4.includes(value);
866604
+ return VALID_SCOPES3.includes(value);
866605
866605
  }
866606
866606
  function isReviewState(value) {
866607
866607
  return VALID_REVIEW_STATES3.includes(value);
@@ -866616,7 +866616,7 @@ function requireClass(value) {
866616
866616
  }
866617
866617
  function requireScope(value) {
866618
866618
  if (!value || !isMemoryScope2(value))
866619
- throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES4.join(", ")}`);
866619
+ throw new Error(`Invalid memory scope "${value ?? ""}". Valid values ${VALID_SCOPES3.join(", ")}`);
866620
866620
  return value;
866621
866621
  }
866622
866622
  function optionalScope(value) {
@@ -902224,6 +902224,20 @@ function setupCounts(snapshot2) {
902224
902224
  function setupStatusLabel(status) {
902225
902225
  return status === "ready" ? "Ready" : status === "recommended" ? "Recommended" : status === "blocked" ? "Blocked" : "Optional";
902226
902226
  }
902227
+ function compactText3(text, maxWidth = 104) {
902228
+ const normalized3 = text.replace(/\s+/g, " ").trim();
902229
+ if (normalized3.length === 0)
902230
+ return "";
902231
+ const firstSentence = normalized3.match(/^.*?[.!?](?:\s|$)/)?.[0]?.trim();
902232
+ const source = firstSentence && firstSentence.length <= maxWidth ? firstSentence : normalized3;
902233
+ return truncateDisplay(source, maxWidth, "...");
902234
+ }
902235
+ function actionMetaLine(action2) {
902236
+ return {
902237
+ text: `${actionCommand(action2)}; ${action2.safety}`,
902238
+ fg: action2.kind === "command" ? FULLSCREEN_PALETTE.info : safetyColor(action2)
902239
+ };
902240
+ }
902227
902241
  function setupAttentionItems(snapshot2, limit3) {
902228
902242
  return [
902229
902243
  ...snapshot2.setupChecklist.filter((item) => item.status === "blocked"),
@@ -902280,46 +902294,33 @@ function companionAccessLine(snapshot2) {
902280
902294
  const tokenState = access3.tokenReadable ? `ready sha256:${access3.tokenFingerprint ?? "unknown"}` : access3.tokenPresent ? "present but unreadable" : "missing";
902281
902295
  const error53 = access3.tokenError ? `; token read error ${access3.tokenError}` : "";
902282
902296
  return {
902283
- text: `Companion: ${access3.surface}; token ${tokenState}; QR ${access3.qrCommand}; manual token text hidden${error53}.`,
902297
+ text: `Companion: ${access3.surface}; token ${tokenState}; QR ${access3.qrCommand}${error53}.`,
902284
902298
  fg: access3.pairingReady ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn
902285
902299
  };
902286
902300
  }
902287
- function localLibraryLines(title, items, emptyText, selectedId) {
902288
- const lines = [
902289
- { text: title, fg: FULLSCREEN_PALETTE.title, bold: true }
902290
- ];
902301
+ function compactLocalLibraryLines(title, items, emptyText, selectedId) {
902302
+ const lines = [];
902291
902303
  if (items.length === 0) {
902292
- lines.push({ text: emptyText, fg: FULLSCREEN_PALETTE.warn });
902304
+ lines.push({ text: `${title}: 0. ${emptyText}`, fg: FULLSCREEN_PALETTE.warn });
902293
902305
  return lines;
902294
902306
  }
902295
- for (const item of items.slice(0, 8)) {
902296
- const selected = item.id === selectedId;
902297
- const status = [
902298
- selected ? "selected" : "",
902299
- item.active ? "active" : "",
902300
- item.enabled === true ? "enabled" : item.enabled === false ? "disabled" : "",
902301
- item.scope && item.cls ? `${item.scope}/${item.cls}` : "",
902302
- item.confidence !== undefined ? `${item.confidence}%` : "",
902303
- item.requirementCount !== undefined && item.requirementCount > 0 ? item.missingRequirementCount && item.missingRequirementCount > 0 ? `needs ${item.missingRequirementCount}/${item.requirementCount}` : `ready ${item.requirementCount}/${item.requirementCount}` : "",
902304
- formatAgentRecordReviewState(item.reviewState),
902305
- item.source ? `origin ${item.source}` : "",
902306
- item.startCount !== undefined ? `starts ${item.startCount}` : ""
902307
- ].filter(Boolean).join(" / ");
902308
- const tags = item.tags.length > 0 ? ` tags ${item.tags.join(",")}` : "";
902309
- const triggers = item.triggers.length > 0 ? ` triggers ${item.triggers.join(",")}` : "";
902310
- const marker = selected ? `${GLYPHS.navigation.selected} ` : "";
902311
- lines.push({
902312
- text: `${marker}${item.id}: ${item.name} (${status})`,
902313
- fg: item.reviewState === "stale" ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info,
902314
- bold: selected || item.active === true
902315
- });
902316
- lines.push({ text: ` ${item.description}${tags}${triggers}`, fg: FULLSCREEN_PALETTE.muted });
902317
- if (item.missingRequirements && item.missingRequirements.length > 0) {
902318
- lines.push({ text: ` missing setup: ${item.missingRequirements.join(", ")}`, fg: FULLSCREEN_PALETTE.warn });
902319
- }
902320
- }
902321
- if (items.length > 8) {
902322
- lines.push({ text: `${items.length - 8} more item(s). Open the library command for the full list.`, fg: FULLSCREEN_PALETTE.dim });
902307
+ const selected = items.find((item) => item.id === selectedId) ?? items[0];
902308
+ const status = [
902309
+ selected.active ? "active" : "",
902310
+ selected.enabled === true ? "enabled" : selected.enabled === false ? "disabled" : "",
902311
+ selected.scope && selected.cls ? `${selected.scope}/${selected.cls}` : "",
902312
+ selected.confidence !== undefined ? `${selected.confidence}%` : "",
902313
+ selected.requirementCount !== undefined && selected.requirementCount > 0 ? selected.missingRequirementCount && selected.missingRequirementCount > 0 ? `needs ${selected.missingRequirementCount}/${selected.requirementCount}` : `ready ${selected.requirementCount}/${selected.requirementCount}` : "",
902314
+ formatAgentRecordReviewState(selected.reviewState),
902315
+ selected.startCount !== undefined ? `starts ${selected.startCount}` : ""
902316
+ ].filter(Boolean).join(", ");
902317
+ lines.push({
902318
+ text: `${title}: ${items.length}; selected ${selected.name}${status ? ` (${status})` : ""}.`,
902319
+ fg: selected.reviewState === "stale" ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info,
902320
+ bold: selected.active === true
902321
+ });
902322
+ if (selected.missingRequirements && selected.missingRequirements.length > 0) {
902323
+ lines.push({ text: `Missing setup: ${selected.missingRequirements.join(", ")}`, fg: FULLSCREEN_PALETTE.warn });
902323
902324
  }
902324
902325
  return lines;
902325
902326
  }
@@ -902354,23 +902355,18 @@ function routineNextActionLine(snapshot2) {
902354
902355
  }
902355
902356
  return { text: "Next routine action: Start selected in the main conversation, inspect receipts, or reconcile connected schedules.", fg: FULLSCREEN_PALETTE.info, bold: true };
902356
902357
  }
902357
- function routineScheduleReceiptLines(snapshot2) {
902358
+ function compactRoutineReceiptLine(snapshot2) {
902358
902359
  const latest = snapshot2.latestRoutineScheduleReceipt;
902359
- const lines = [
902360
- {
902361
- text: `Promotion receipts: ${snapshot2.routineScheduleReceiptCount}; created: ${snapshot2.successfulRoutineScheduleReceiptCount}; failed: ${snapshot2.failedRoutineScheduleReceiptCount}`,
902362
- fg: snapshot2.failedRoutineScheduleReceiptCount > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info
902363
- }
902364
- ];
902365
- if (latest) {
902366
- lines.push({
902367
- text: `Latest receipt: ${latest.id} ${latest.status} routine=${latest.routineId} schedule="${latest.scheduleName}" ${latest.scheduleKind} ${latest.scheduleValue}`,
902368
- fg: latest.status === "failed" ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.good
902369
- });
902370
- } else {
902371
- lines.push({ text: "No schedule promotion receipts yet. Confirm a routine promotion from Automation when ready.", fg: FULLSCREEN_PALETTE.muted });
902360
+ if (!latest) {
902361
+ return {
902362
+ text: `Promotion receipts: ${snapshot2.routineScheduleReceiptCount}; none created yet.`,
902363
+ fg: FULLSCREEN_PALETTE.muted
902364
+ };
902372
902365
  }
902373
- return lines;
902366
+ return {
902367
+ text: `Promotion receipts: ${snapshot2.routineScheduleReceiptCount}; latest ${latest.status} ${latest.routineId}.`,
902368
+ fg: latest.status === "failed" ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.good
902369
+ };
902374
902370
  }
902375
902371
  function automationNextActionLine(snapshot2) {
902376
902372
  const ready = readyRoutineItems(snapshot2);
@@ -902390,55 +902386,6 @@ function automationNextActionLine(snapshot2) {
902390
902386
  }
902391
902387
  return { text: "Next automation action: Create a reminder, or create/import a routine before recurring workflow promotion.", fg: FULLSCREEN_PALETTE.warn, bold: true };
902392
902388
  }
902393
- function profileLines(snapshot2) {
902394
- const lines = [
902395
- { text: "Agent Profiles", fg: FULLSCREEN_PALETTE.title, bold: true }
902396
- ];
902397
- if (snapshot2.runtimeProfiles.length === 0) {
902398
- lines.push({ text: "No isolated Agent profiles yet. Use Create Agent profile in this workspace.", fg: FULLSCREEN_PALETTE.warn });
902399
- return lines;
902400
- }
902401
- for (const profile5 of snapshot2.runtimeProfiles.slice(0, 6)) {
902402
- const starter = profile5.starterTemplateId ? ` starter=${profile5.starterTemplateId}` : " starter=none";
902403
- const created = profile5.createdAt ? ` created ${profile5.createdAt.slice(0, 10)}` : "";
902404
- const states = [
902405
- profile5.id === snapshot2.activeRuntimeProfile ? "active" : "",
902406
- profile5.id === snapshot2.selectedRuntimeProfile ? "default" : ""
902407
- ].filter(Boolean).join(", ");
902408
- const stateText = states ? ` [${states}]` : "";
902409
- lines.push({
902410
- text: `${profile5.id}${stateText}${starter}${created}`,
902411
- fg: profile5.id === snapshot2.selectedRuntimeProfile ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.info,
902412
- bold: profile5.id === snapshot2.activeRuntimeProfile || profile5.id === snapshot2.selectedRuntimeProfile
902413
- });
902414
- lines.push({ text: ` home: ${profile5.homeDirectory}`, fg: FULLSCREEN_PALETTE.muted });
902415
- }
902416
- if (snapshot2.runtimeProfiles.length > 6) {
902417
- lines.push({ text: `${snapshot2.runtimeProfiles.length - 6} more profile(s).`, fg: FULLSCREEN_PALETTE.dim });
902418
- }
902419
- return lines;
902420
- }
902421
- function starterTemplateLines(snapshot2) {
902422
- const lines = [
902423
- { text: "Starter Templates", fg: FULLSCREEN_PALETTE.title, bold: true }
902424
- ];
902425
- for (const template of snapshot2.runtimeStarterTemplates.slice(0, 6)) {
902426
- const origin = template.source === "local" ? "Local" : formatAgentRecordSource(template.source);
902427
- lines.push({
902428
- text: `${template.id}: ${template.name} [${origin}]`,
902429
- fg: template.source === "local" ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.info,
902430
- bold: template.id === "research"
902431
- });
902432
- lines.push({
902433
- text: ` ${template.description} Persona ${template.personaName}; skills ${template.skillNames.join(", ")}; routines ${template.routineNames.join(", ")}.`,
902434
- fg: FULLSCREEN_PALETTE.muted
902435
- });
902436
- }
902437
- if (snapshot2.runtimeStarterTemplates.length > 6) {
902438
- lines.push({ text: `${snapshot2.runtimeStarterTemplates.length - 6} more starter template(s).`, fg: FULLSCREEN_PALETTE.dim });
902439
- }
902440
- return lines;
902441
- }
902442
902389
  function snapshotLines(workspace, category, snapshot2) {
902443
902390
  if (!snapshot2)
902444
902391
  return [{ text: "Runtime context is not loaded yet.", fg: FULLSCREEN_PALETTE.warn }];
@@ -902449,92 +902396,50 @@ function snapshotLines(workspace, category, snapshot2) {
902449
902396
  base2.push(...setupOverviewLines(snapshot2));
902450
902397
  } else if (category.id === "artifacts") {
902451
902398
  const mediaReady = snapshot2.voiceMediaReadiness.readyMediaProviderCount;
902452
- base2.push({ text: `Chat route: ${snapshot2.provider} / ${snapshot2.modelDisplayName}`, fg: FULLSCREEN_PALETTE.info }, { text: `Agent Knowledge route: ${snapshot2.knowledgeRoute}`, fg: FULLSCREEN_PALETTE.info }, { text: `Media providers: ${mediaReady}/${snapshot2.mediaProviderCount} ready; generation-capable ${snapshot2.mediaGenerationProviderCount}.`, fg: mediaReady > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, { text: "Use this area for concrete files and generated output: attach images, export transcripts, ingest reviewed sources, inspect source records, and generate media.", fg: FULLSCREEN_PALETTE.good }, { text: "Agent Knowledge ingest writes only to the isolated Agent segment. Default knowledge and non-Agent routes are not fallback storage.", fg: FULLSCREEN_PALETTE.warn }, { text: "Generated media is stored as artifacts and referenced by id; the TUI should not print inline base64.", fg: FULLSCREEN_PALETTE.muted }, { text: `Workspace path: ${snapshot2.workingDirectory}`, fg: FULLSCREEN_PALETTE.muted });
902399
+ base2.push({ text: `Chat: ${snapshot2.provider} / ${snapshot2.modelDisplayName}; Knowledge: ${snapshot2.knowledgeRoute}`, fg: FULLSCREEN_PALETTE.info }, { text: `Media: ${mediaReady}/${snapshot2.mediaProviderCount} ready; generation ${snapshot2.mediaGenerationProviderCount}.`, fg: mediaReady > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, { text: "Files: attach, export, inspect, ingest reviewed sources, or generate media.", fg: FULLSCREEN_PALETTE.good }, { text: "Knowledge ingest and media generation require explicit actions.", fg: FULLSCREEN_PALETTE.warn });
902453
902400
  } else if (category.id === "channels") {
902454
902401
  const enabledCount = snapshot2.channels.filter((channel) => channel.enabled).length;
902455
902402
  const readyCount = snapshot2.channels.filter((channel) => channel.ready).length;
902456
902403
  const configuredDefaults = snapshot2.channels.filter((channel) => channel.defaultTarget === "configured").length;
902457
- const readyChannels = snapshot2.channels.filter((channel) => channel.ready).map((channel) => channel.label);
902458
902404
  const needsTarget = snapshot2.channels.filter((channel) => channel.setupState === "needs-target");
902459
902405
  const needsConfig = snapshot2.channels.filter((channel) => channel.setupState === "needs-config");
902460
902406
  const nextAttentionChannel = needsConfig[0] ?? needsTarget[0] ?? snapshot2.channels.find((channel) => !channel.enabled);
902461
- const disabledChannels = snapshot2.channels.filter((channel) => !channel.enabled).map((channel) => channel.label);
902462
- const disabledPreview = disabledChannels.slice(0, 6).join(", ");
902463
- const disabledSuffix = disabledChannels.length > 6 ? `, +${disabledChannels.length - 6} more` : "";
902464
- const orderedChannels = [
902465
- ...snapshot2.channels.filter((channel) => channel.enabled),
902466
- ...snapshot2.channels.filter((channel) => !channel.enabled)
902467
- ].slice(0, 3);
902468
- base2.push({ text: `GoodVibes API: ${snapshot2.runtimeBaseUrl}`, fg: FULLSCREEN_PALETTE.info }, companionAccessLine(snapshot2), { text: `Readiness: ${readyCount}/${snapshot2.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} default target(s) configured.`, fg: FULLSCREEN_PALETTE.info }, { text: "Setup path: pair companion -> inspect readiness -> review accounts/policies/status -> fix one channel -> add explicit notification target if needed.", fg: FULLSCREEN_PALETTE.good }, { text: `Next channel action: ${nextAttentionChannel ? `${nextAttentionChannel.label} - ${nextAttentionChannel.nextStep}` : "All enabled channels are ready; keep delivery explicit and review policies before sending."}`, fg: nextAttentionChannel ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.good }, { text: `Ready channels: ${readyChannels.join(", ") || "none"}.`, fg: readyChannels.length > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, { text: `Needs default target: ${needsTarget.map((channel) => `${channel.label} -> ${channel.defaultTargetKeys.join("|")}`).join(", ") || "none"}.`, fg: needsTarget.length > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: `Needs config: ${needsConfig.map((channel) => `${channel.label} -> ${channel.missingRequiredKeys.join("|")}`).join(", ") || "none"}.`, fg: needsConfig.length > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: `Disabled channels: ${disabledPreview || "none"}${disabledSuffix}.`, fg: FULLSCREEN_PALETTE.dim }, { text: "Safety: no secret values; sends and public exposure require explicit user action and Agent policy.", fg: FULLSCREEN_PALETTE.warn });
902469
- for (const channel of orderedChannels) {
902470
- const ready = channel.ready ? "ready" : `${channel.missingConfigCount} missing`;
902471
- base2.push({
902472
- text: `${channel.label}: ${channel.setupState}; ${ready}; target ${channel.defaultTarget}; delivery ${channel.delivery}; risk ${channel.risk}.`,
902473
- fg: channel.ready ? FULLSCREEN_PALETTE.good : channel.enabled ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.dim
902474
- });
902475
- }
902407
+ base2.push({ text: `API: ${snapshot2.runtimeBaseUrl}`, fg: FULLSCREEN_PALETTE.info }, companionAccessLine(snapshot2), { text: `Channels: ${readyCount}/${snapshot2.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} target(s).`, fg: FULLSCREEN_PALETTE.info }, { text: `Next: ${nextAttentionChannel ? `${nextAttentionChannel.label} - ${compactText3(nextAttentionChannel.nextStep)}` : "All enabled channels ready."}`, fg: nextAttentionChannel ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.good }, { text: "Safety: secrets hidden; sends require explicit action.", fg: FULLSCREEN_PALETTE.warn });
902476
902408
  } else if (category.id === "knowledge") {
902477
- base2.push({ text: `Route family: ${snapshot2.knowledgeRoute}/{status,ask,search}`, fg: FULLSCREEN_PALETTE.info }, { text: `Isolation: ${snapshot2.knowledgeIsolation}; no default knowledge or non-Agent fallback`, fg: FULLSCREEN_PALETTE.good }, { text: "Ingest: URL, URL-list, and bookmark imports require explicit --yes and write only to Agent Knowledge.", fg: FULLSCREEN_PALETTE.info }, { text: "Review: queue, issues, candidates, reports, reindex, and consolidation stay inside the Agent segment.", fg: FULLSCREEN_PALETTE.muted }, { text: "Agent-owned content appears here only after explicit Agent knowledge ingestion.", fg: FULLSCREEN_PALETTE.muted });
902409
+ base2.push({ text: `Route: ${snapshot2.knowledgeRoute}; isolation ${snapshot2.knowledgeIsolation}.`, fg: FULLSCREEN_PALETTE.info }, { text: "Ask/search, ingest, review, reindex, and reports stay Agent-owned.", fg: FULLSCREEN_PALETTE.good }, { text: "Ingest requires explicit confirmation.", fg: FULLSCREEN_PALETTE.warn });
902478
902410
  } else if (category.id === "research") {
902479
- base2.push({ text: `Chat route: ${snapshot2.provider} / ${snapshot2.modelDisplayName}`, fg: FULLSCREEN_PALETTE.info }, { text: `Agent Knowledge route: ${snapshot2.knowledgeRoute}`, fg: FULLSCREEN_PALETTE.info }, { text: `Browser tools: ${snapshot2.voiceMediaReadiness.browserToolState}; public base URL ${snapshot2.browserToolPublicBaseUrl}.`, fg: snapshot2.browserToolExposureEnabled ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: snapshot2.voiceMediaReadiness.browserToolNextStep, fg: FULLSCREEN_PALETTE.muted }, { text: "Research requests are submitted to the main conversation. Agent may use connected read-only web tools when the user asks.", fg: FULLSCREEN_PALETTE.good }, { text: "URL references and web research do not ingest into Agent Knowledge. Ingestion is a separate confirmed Agent Knowledge action.", fg: FULLSCREEN_PALETTE.warn }, { text: "Use Agent Knowledge ask/search first for known source-backed context; use web research for current or external sources.", fg: FULLSCREEN_PALETTE.info }, { text: "External sends, browser-side effects, package installs, and connected-host mutations are outside this read-only research lane.", fg: FULLSCREEN_PALETTE.warn });
902411
+ base2.push({ text: `Chat: ${snapshot2.provider} / ${snapshot2.modelDisplayName}; Knowledge: ${snapshot2.knowledgeRoute}`, fg: FULLSCREEN_PALETTE.info }, { text: `Browser: ${snapshot2.voiceMediaReadiness.browserToolState}; public URL ${snapshot2.browserToolPublicBaseUrl}.`, fg: snapshot2.browserToolExposureEnabled ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: "Research is read-only. Knowledge ingest is a separate confirmed action.", fg: FULLSCREEN_PALETTE.good }, { text: compactText3(snapshot2.voiceMediaReadiness.browserToolNextStep), fg: FULLSCREEN_PALETTE.muted });
902480
902412
  } else if (category.id === "tools") {
902481
- base2.push({ text: `MCP servers: ${snapshot2.mcpConnectedServerCount}/${snapshot2.mcpServerCount} connected; quarantined ${snapshot2.mcpQuarantinedServerCount}; allow-all ${snapshot2.mcpAllowAllServerCount}.`, fg: snapshot2.mcpQuarantinedServerCount > 0 || snapshot2.mcpAllowAllServerCount > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info }, { text: "Open MCP workspace for live server status, tool inventory, config paths, and confirmed add/remove/reload actions.", fg: FULLSCREEN_PALETTE.info }, { text: "Add/update requires typed confirmation and dispatches through the TUI command router.", fg: FULLSCREEN_PALETTE.good }, { text: "Trust changes remain explicit; allow-all is kept behind the settings workspace.", fg: FULLSCREEN_PALETTE.warn }, { text: "Useful first actions: /mcp review, /mcp tools, /mcp config, and Add MCP server.", fg: FULLSCREEN_PALETTE.muted }, { text: "Normal assistant chat can use tools serially when policy allows; onboarding does not start hidden tool work.", fg: FULLSCREEN_PALETTE.muted });
902413
+ base2.push({ text: `MCP servers: ${snapshot2.mcpConnectedServerCount}/${snapshot2.mcpServerCount} connected; quarantined ${snapshot2.mcpQuarantinedServerCount}; allow-all ${snapshot2.mcpAllowAllServerCount}.`, fg: snapshot2.mcpQuarantinedServerCount > 0 || snapshot2.mcpAllowAllServerCount > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info }, { text: "Add/update/reload and trust changes require confirmation.", fg: FULLSCREEN_PALETTE.good }, { text: "Start: /mcp review, /mcp tools, /mcp config, Add MCP server.", fg: FULLSCREEN_PALETTE.muted });
902482
902414
  } else if (category.id === "voice-media") {
902483
902415
  const readiness = snapshot2.voiceMediaReadiness;
902484
- const voiceRows = readiness.voiceProviders.slice(0, 6);
902485
- const mediaRows = readiness.mediaProviders.slice(0, 6);
902486
- base2.push({ text: `Voice providers: ${snapshot2.voiceProviderCount}; streaming TTS: ${snapshot2.voiceStreamingProviderCount}; STT: ${snapshot2.voiceSttProviderCount}; realtime: ${snapshot2.voiceRealtimeProviderCount}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Voice interaction: ${snapshot2.voiceSurfaceEnabled ? "enabled" : "disabled"}; ready providers ${readiness.readyVoiceProviderCount}/${snapshot2.voiceProviderCount}.`, fg: snapshot2.voiceSurfaceEnabled ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: `TTS config: provider ${snapshot2.ttsProvider}; voice ${snapshot2.ttsVoice}; response model ${snapshot2.ttsResponseModel}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Selected TTS readiness: ${readiness.selectedTtsProviderLabel} -> ${readiness.selectedTtsProviderStatus}; voice ${readiness.ttsVoiceConfigured ? "configured" : "default"}; response route ${readiness.ttsResponseRouteConfigured ? "configured" : "chat route"}.`, fg: readiness.selectedTtsProviderStatus === "ready" ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, { text: `Media providers: ${snapshot2.mediaProviderCount}; understanding: ${snapshot2.mediaUnderstandingProviderCount}; generation: ${snapshot2.mediaGenerationProviderCount}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Ready media providers: ${readiness.readyMediaProviderCount}/${snapshot2.mediaProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, { text: `Browser tools: ${readiness.browserToolState}; public base URL ${snapshot2.browserToolPublicBaseUrl}.`, fg: snapshot2.browserToolExposureEnabled ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: readiness.browserToolNextStep, fg: FULLSCREEN_PALETTE.muted }, { text: "Voice provider readiness", fg: FULLSCREEN_PALETTE.title, bold: true });
902487
- for (const provider5 of voiceRows) {
902488
- const selected = provider5.selected ? "selected; " : "";
902489
- const missing = provider5.missingSecretKeyOptions.length > 0 ? `; needs ${provider5.missingSecretKeyOptions.join("|")}` : "";
902490
- base2.push({
902491
- text: `${provider5.label}: ${selected}${provider5.setupState}; ${provider5.features.join(", ") || "registered"}${missing}.`,
902492
- fg: provider5.setupState === "ready" ? FULLSCREEN_PALETTE.good : provider5.setupState === "needs-secret" ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted
902493
- });
902494
- }
902495
- if (snapshot2.voiceProviderCount > voiceRows.length)
902496
- base2.push({ text: `${snapshot2.voiceProviderCount - voiceRows.length} more voice provider(s).`, fg: FULLSCREEN_PALETTE.dim });
902497
- base2.push({ text: "Media provider readiness", fg: FULLSCREEN_PALETTE.title, bold: true });
902498
- for (const provider5 of mediaRows) {
902499
- const missing = provider5.missingSecretKeyOptions.length > 0 ? `; needs ${provider5.missingSecretKeyOptions.join("|")}` : "";
902500
- base2.push({
902501
- text: `${provider5.label}: ${provider5.setupState}; ${provider5.features.join(", ") || "registered"}${missing}.`,
902502
- fg: provider5.setupState === "ready" ? FULLSCREEN_PALETTE.good : provider5.setupState === "needs-secret" ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted
902503
- });
902504
- }
902505
- if (snapshot2.mediaProviderCount > mediaRows.length)
902506
- base2.push({ text: `${snapshot2.mediaProviderCount - mediaRows.length} more media provider(s).`, fg: FULLSCREEN_PALETTE.dim });
902507
- for (const step of readiness.nextSteps.slice(0, 4))
902508
- base2.push({ text: `Next: ${step}`, fg: FULLSCREEN_PALETTE.info });
902509
- base2.push({ text: "No secret values are rendered. Voice, browser, and generated media side effects require explicit user action.", fg: FULLSCREEN_PALETTE.warn }, { text: "Image input uses prompt attachments; media generation/provider setup stays behind explicit commands and configured providers.", fg: FULLSCREEN_PALETTE.muted });
902416
+ base2.push({ text: `Voice: ${readiness.readyVoiceProviderCount}/${snapshot2.voiceProviderCount} ready; TTS ${snapshot2.ttsProvider}; voice ${snapshot2.ttsVoice}.`, fg: readiness.readyVoiceProviderCount > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, { text: `Media: ${readiness.readyMediaProviderCount}/${snapshot2.mediaProviderCount} ready; generation ${snapshot2.mediaGenerationProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, { text: `Browser: ${readiness.browserToolState}; public URL ${snapshot2.browserToolPublicBaseUrl}.`, fg: snapshot2.browserToolExposureEnabled ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.muted }, { text: readiness.nextSteps[0] ? `Next: ${compactText3(readiness.nextSteps[0])}` : "Next: voice/media setup is ready.", fg: readiness.nextSteps.length > 0 ? FULLSCREEN_PALETTE.info : FULLSCREEN_PALETTE.good }, { text: "Secrets hidden; voice, browser, and media side effects require explicit action.", fg: FULLSCREEN_PALETTE.warn });
902510
902417
  } else if (category.id === "profiles") {
902511
902418
  const defaultProfile = snapshot2.selectedRuntimeProfile ? `${snapshot2.selectedRuntimeProfile}${snapshot2.selectedRuntimeProfileExists ? "" : " (missing)"}` : "(base Agent home)";
902512
- base2.push({ text: `Active Agent profile: ${snapshot2.activeRuntimeProfile}`, fg: FULLSCREEN_PALETTE.info }, { text: `Default for next launch: ${defaultProfile}`, fg: snapshot2.selectedRuntimeProfileExists || !snapshot2.selectedRuntimeProfile ? FULLSCREEN_PALETTE.info : FULLSCREEN_PALETTE.warn }, { text: `Agent profiles under this home: ${snapshot2.runtimeProfileCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Starter templates: ${snapshot2.runtimeStarterTemplateCount}; local custom: ${snapshot2.localStarterTemplateCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Starter ids: ${snapshot2.runtimeStarterTemplates.map((template) => template.id).join(", ") || "none"}`, fg: FULLSCREEN_PALETTE.info }, { text: "Starter Templates", fg: FULLSCREEN_PALETTE.title, bold: true }, { text: `Agent profile root: ${snapshot2.runtimeProfileRoot}`, fg: FULLSCREEN_PALETTE.muted }, { text: "" }, ...profileLines(snapshot2), { text: "" }, ...starterTemplateLines(snapshot2), { text: "" }, { text: "Named Agent profiles isolate local config, sessions, memory, personas, skills, routines, setup, and bundles.", fg: FULLSCREEN_PALETTE.good }, { text: "Starter authoring: browse, export, edit, import, and create Agent profiles from inside this workspace.", fg: FULLSCREEN_PALETTE.info }, { text: "The connected GoodVibes host stays shared unless that host is configured separately.", fg: FULLSCREEN_PALETTE.warn }, { text: "Portable bundles require explicit export/import commands with real paths and --yes.", fg: FULLSCREEN_PALETTE.muted });
902419
+ base2.push({ text: `Profiles: active ${snapshot2.activeRuntimeProfile}; default ${defaultProfile}.`, fg: snapshot2.selectedRuntimeProfileExists || !snapshot2.selectedRuntimeProfile ? FULLSCREEN_PALETTE.info : FULLSCREEN_PALETTE.warn }, { text: `Local profiles: ${snapshot2.runtimeProfileCount}; starters ${snapshot2.runtimeStarterTemplateCount}; custom ${snapshot2.localStarterTemplateCount}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Starter ids: ${truncateDisplay(snapshot2.runtimeStarterTemplates.map((template) => template.id).join(", ") || "none", 96, "...")}`, fg: FULLSCREEN_PALETTE.muted }, { text: "Profiles isolate local Agent config, sessions, memory, personas, skills, routines, setup, and bundles.", fg: FULLSCREEN_PALETTE.good });
902513
902420
  } else if (category.id === "memory") {
902514
- base2.push({ text: `Session memories: ${snapshot2.sessionMemoryCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Agent memory: ${snapshot2.localMemoryCount}; prompt-active: ${snapshot2.localMemoryPromptActiveCount}; review queue: ${snapshot2.localMemoryReviewQueueCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Scratchpad notes: ${snapshot2.localNoteCount}; review queue: ${snapshot2.localNoteReviewQueueCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Local routines: ${snapshot2.localRoutineCount}; enabled: ${snapshot2.enabledRoutineCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Local skills: ${snapshot2.localSkillCount}; enabled: ${snapshot2.enabledSkillCount}; bundles: ${snapshot2.localSkillBundleCount}; active skills: ${snapshot2.activeSkillCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Local personas: ${snapshot2.localPersonaCount}; active: ${snapshot2.activePersonaName}`, fg: FULLSCREEN_PALETTE.info }, { text: "Durable memory, scratchpad notes, routines, skills, and personas remain Agent-local until shared registry contracts exist.", fg: FULLSCREEN_PALETTE.good }, { text: "Secrets are rejected/redacted; store secret references instead of secret values.", fg: FULLSCREEN_PALETTE.warn }, { text: "" }, ...localLibraryLines("Agent Memory", snapshot2.localMemories, "No Agent memory yet. Create one here with Create memory.", workspace.selectedLocalLibraryItem("memory")?.id ?? null));
902421
+ base2.push({ text: `Memory: ${snapshot2.localMemoryCount}; prompt ${snapshot2.localMemoryPromptActiveCount}; queue ${snapshot2.localMemoryReviewQueueCount}; session ${snapshot2.sessionMemoryCount}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Notes: ${snapshot2.localNoteCount}; skills ${snapshot2.localSkillCount}/${snapshot2.enabledSkillCount}; routines ${snapshot2.localRoutineCount}/${snapshot2.enabledRoutineCount}; personas ${snapshot2.localPersonaCount}.`, fg: FULLSCREEN_PALETTE.info }, { text: `Active persona: ${snapshot2.activePersonaName}.`, fg: FULLSCREEN_PALETTE.info }, ...compactLocalLibraryLines("Agent Memory", snapshot2.localMemories, "Create one with Create memory.", workspace.selectedLocalLibraryItem("memory")?.id ?? null), { text: "Secrets are rejected or redacted; use secret references.", fg: FULLSCREEN_PALETTE.warn });
902515
902422
  } else if (category.id === "notes") {
902516
- base2.push({ text: `Scratchpad notes: ${snapshot2.localNoteCount}; review queue: ${snapshot2.localNoteReviewQueueCount}`, fg: FULLSCREEN_PALETTE.info }, { text: "Notes are Agent-local working context for source triage, temporary decisions, and operator handoff.", fg: FULLSCREEN_PALETTE.good }, { text: "Notes do not become memory and are not ingested into Agent Knowledge unless the user takes a separate explicit action.", fg: FULLSCREEN_PALETTE.warn }, { text: "Use reviewed notes to prefill durable memory, skills, routines, or personas, or to decide that a reviewed source deserves Agent Knowledge ingest.", fg: FULLSCREEN_PALETTE.muted }, { text: "" }, ...localLibraryLines("Scratchpad Notes", snapshot2.localNotes, "No local notes yet. Create one here with Create note.", workspace.selectedLocalLibraryItem("note")?.id ?? null));
902423
+ base2.push({ text: `Scratchpad notes: ${snapshot2.localNoteCount}; review queue: ${snapshot2.localNoteReviewQueueCount}`, fg: FULLSCREEN_PALETTE.info }, ...compactLocalLibraryLines("Scratchpad Notes", snapshot2.localNotes, "Create one with Create note.", workspace.selectedLocalLibraryItem("note")?.id ?? null), { text: "Notes stay local unless promoted by explicit action.", fg: FULLSCREEN_PALETTE.warn });
902517
902424
  } else if (category.id === "personas") {
902518
- base2.push({ text: `Personas: ${snapshot2.localPersonaCount}; active: ${snapshot2.activePersonaName}`, fg: FULLSCREEN_PALETTE.info }, { text: "Personas are local behavior profiles for the serial main-conversation assistant, not separate Agent jobs.", fg: FULLSCREEN_PALETTE.good }, { text: "Use them for tone, role, domain constraints, tool posture, and repeatable operating preferences.", fg: FULLSCREEN_PALETTE.muted }, { text: "" }, ...localLibraryLines("Persona Library", snapshot2.localPersonas, "No local personas yet. Create one here with Create persona.", workspace.selectedLocalLibraryItem("persona")?.id ?? null));
902425
+ base2.push({ text: `Personas: ${snapshot2.localPersonaCount}; active: ${snapshot2.activePersonaName}`, fg: FULLSCREEN_PALETTE.info }, ...compactLocalLibraryLines("Persona Library", snapshot2.localPersonas, "Create one with Create persona.", workspace.selectedLocalLibraryItem("persona")?.id ?? null), { text: "Personas shape the serial main-conversation assistant.", fg: FULLSCREEN_PALETTE.good });
902519
902426
  } else if (category.id === "skills") {
902520
- base2.push({ text: `Skills: ${snapshot2.localSkillCount}; enabled: ${snapshot2.enabledSkillCount}; bundles: ${snapshot2.localSkillBundleCount}; enabled bundles: ${snapshot2.enabledSkillBundleCount}; active skills: ${snapshot2.activeSkillCount}`, fg: FULLSCREEN_PALETTE.info }, { text: "Skills are reusable local procedures the assistant can apply from the main conversation.", fg: FULLSCREEN_PALETTE.good }, { text: "Enabled skills and enabled bundles are injected as operating guidance; secret-looking content is rejected.", fg: FULLSCREEN_PALETTE.warn }, { text: "" }, ...localLibraryLines("Skill Library", snapshot2.localSkills, "No local skills yet. Create one here with Create skill.", workspace.selectedLocalLibraryItem("skill")?.id ?? null), { text: "" }, ...localLibraryLines("Skill Bundles", snapshot2.localSkillBundles, "No local skill bundles yet. Use Skill bundles and Create bundle after creating skills.", null));
902427
+ base2.push({ text: `Skills: ${snapshot2.localSkillCount}; enabled: ${snapshot2.enabledSkillCount}; bundles: ${snapshot2.localSkillBundleCount}; enabled bundles: ${snapshot2.enabledSkillBundleCount}; active skills: ${snapshot2.activeSkillCount}`, fg: FULLSCREEN_PALETTE.info }, ...compactLocalLibraryLines("Skill Library", snapshot2.localSkills, "Create one with Create skill.", workspace.selectedLocalLibraryItem("skill")?.id ?? null), ...compactLocalLibraryLines("Skill Bundles", snapshot2.localSkillBundles, "Create one after adding skills.", null), { text: "Enabled skills/bundles become operating guidance; secrets are rejected.", fg: FULLSCREEN_PALETTE.warn });
902521
902428
  } else if (category.id === "routines") {
902522
902429
  const ready = readyRoutineItems(snapshot2);
902523
902430
  const needsSetup = routinesNeedingSetup(snapshot2);
902524
902431
  const needsReview = routinesNeedingReview(snapshot2);
902525
- base2.push({ text: `Routines: ${snapshot2.localRoutineCount}; enabled: ${snapshot2.enabledRoutineCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Schedule-ready routines: ${ready.length}; setup gaps: ${needsSetup.length}; review needed: ${needsReview.length}`, fg: needsSetup.length > 0 || needsReview.length > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.good }, { text: "Routines are repeatable main-conversation workflows. Starting one does not create hidden jobs.", fg: FULLSCREEN_PALETTE.good }, { text: "Scheduling a reviewed routine is explicit and requires a confirmed schedule command.", fg: FULLSCREEN_PALETTE.warn }, routineNextActionLine(snapshot2), ...routineScheduleReceiptLines(snapshot2), { text: "" }, ...localLibraryLines("Routine Library", snapshot2.localRoutines, "No local routines yet. Create one here with Create routine.", workspace.selectedLocalLibraryItem("routine")?.id ?? null));
902432
+ base2.push({ text: `Routines: ${snapshot2.localRoutineCount}; enabled: ${snapshot2.enabledRoutineCount}`, fg: FULLSCREEN_PALETTE.info }, { text: `Schedule-ready routines: ${ready.length}; setup gaps: ${needsSetup.length}; review needed: ${needsReview.length}`, fg: needsSetup.length > 0 || needsReview.length > 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.good }, routineNextActionLine(snapshot2), compactRoutineReceiptLine(snapshot2), ...compactLocalLibraryLines("Routine Library", snapshot2.localRoutines, "Create one with Create routine.", workspace.selectedLocalLibraryItem("routine")?.id ?? null), { text: "Scheduling requires a confirmed action.", fg: FULLSCREEN_PALETTE.warn });
902526
902433
  } else if (category.id === "work") {
902527
- base2.push({ text: "Work plan and approvals are read or explicitly confirmed through public operator routes.", fg: FULLSCREEN_PALETTE.info }, { text: "This workspace does not approve, deny, cancel, or mutate requests by selection alone.", fg: FULLSCREEN_PALETTE.good }, { text: "Approve, deny, and cancel forms require an approval id and typed confirmation.", fg: FULLSCREEN_PALETTE.warn });
902434
+ base2.push({ text: "Work plans and approvals are read or explicitly confirmed.", fg: FULLSCREEN_PALETTE.info }, { text: "Selection alone does not approve, deny, cancel, or mutate requests.", fg: FULLSCREEN_PALETTE.good }, { text: "Approval actions require id plus typed confirmation.", fg: FULLSCREEN_PALETTE.warn });
902528
902435
  } else if (category.id === "automation") {
902529
902436
  const ready = readyRoutineItems(snapshot2);
902530
- base2.push({ text: "Automation and schedules default to read-only observability; side effects require confirmed forms.", fg: FULLSCREEN_PALETTE.info }, { text: "Confirmed reminders and routine promotion use connected schedules only.", fg: FULLSCREEN_PALETTE.info }, { text: "Local scheduler mutation controls remain blocked; job/run/schedule controls go through the connected host.", fg: FULLSCREEN_PALETTE.warn }, { text: "Reminder path: Create reminder -> choose at/every/cron -> optional delivery target -> confirm yes.", fg: FULLSCREEN_PALETTE.good }, { text: "Operator path: choose job/run/schedule action -> enter id -> type yes -> dispatch once.", fg: FULLSCREEN_PALETTE.good }, { text: "Routine path: Routines -> resolve setup -> review selected -> Promote routine -> Reconcile schedules.", fg: FULLSCREEN_PALETTE.good }, { text: `Schedule-ready routines: ${ready.length}; local promotion receipts: ${snapshot2.routineScheduleReceiptCount}`, fg: ready.length > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, automationNextActionLine(snapshot2), ...routineScheduleReceiptLines(snapshot2));
902437
+ base2.push({ text: `Automation: ${ready.length} schedule-ready routine(s); receipts ${snapshot2.routineScheduleReceiptCount}.`, fg: ready.length > 0 ? FULLSCREEN_PALETTE.good : FULLSCREEN_PALETTE.warn }, automationNextActionLine(snapshot2), compactRoutineReceiptLine(snapshot2), { text: "Reminders and routine promotion require confirmation.", fg: FULLSCREEN_PALETTE.warn });
902531
902438
  } else if (category.id === "delegate") {
902532
- base2.push({ text: "Build/fix/review work is handed to GoodVibes TUI/shared-session contracts.", fg: FULLSCREEN_PALETTE.info }, { text: `Delegated review policy: ${snapshot2.delegatedReviewPolicy}`, fg: FULLSCREEN_PALETTE.warn }, { text: "Agent does not create coding-role Agent jobs.", fg: FULLSCREEN_PALETTE.good });
902439
+ base2.push({ text: "Build/fix/review work is handed to GoodVibes TUI.", fg: FULLSCREEN_PALETTE.info }, { text: `Delegated review policy: ${snapshot2.delegatedReviewPolicy}`, fg: FULLSCREEN_PALETTE.warn }, { text: "No coding-role Agent jobs are created here.", fg: FULLSCREEN_PALETTE.good });
902533
902440
  }
902534
902441
  if (snapshot2.warnings.length > 0) {
902535
- base2.push({ text: "", dim: true }, { text: "Warnings", fg: FULLSCREEN_PALETTE.warn, bold: true });
902536
- for (const warning of snapshot2.warnings)
902537
- base2.push({ text: warning, fg: FULLSCREEN_PALETTE.warn });
902442
+ base2.push({ text: `Warnings: ${snapshot2.warnings.map((warning) => compactText3(warning, 60)).join("; ")}`, fg: FULLSCREEN_PALETTE.warn });
902538
902443
  }
902539
902444
  return base2;
902540
902445
  }
@@ -902542,53 +902447,36 @@ function editorContextLines(editor) {
902542
902447
  const selected = editor.fields[editor.selectedFieldIndex];
902543
902448
  const lines = [
902544
902449
  { text: editor.title, fg: FULLSCREEN_PALETTE.title, bold: true },
902545
- { text: editor.message, fg: editor.message.includes("required") || editor.message.includes("cannot") || editor.message.includes("Cannot") ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info },
902546
- { text: "Enter advances fields and saves from the final field. Ctrl-J adds a line inside multiline fields. Esc cancels without writing.", fg: FULLSCREEN_PALETTE.muted }
902450
+ { text: compactText3(editor.message), fg: editor.message.includes("required") || editor.message.includes("cannot") || editor.message.includes("Cannot") ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info },
902451
+ { text: "Enter next/save; Ctrl-J newline; Esc cancel.", fg: FULLSCREEN_PALETTE.muted }
902547
902452
  ];
902548
902453
  if (selected) {
902549
- lines.push({ text: "" }, { text: `Editing: ${selected.label}${selected.required ? " (required)" : ""}`, fg: FULLSCREEN_PALETTE.title, bold: true }, { text: selected.hint, fg: FULLSCREEN_PALETTE.muted });
902454
+ lines.push({ text: `Editing: ${selected.label}${selected.required ? " (required)" : ""}`, fg: FULLSCREEN_PALETTE.title, bold: true }, { text: compactText3(selected.hint), fg: FULLSCREEN_PALETTE.muted });
902550
902455
  }
902551
902456
  return lines;
902552
902457
  }
902553
902458
  function buildContextRows(workspace, category, action2, width) {
902554
- const compactPrimarySurface = category.id === "home" || category.id === "setup";
902555
902459
  const lines = [
902556
902460
  { text: category.label, fg: FULLSCREEN_PALETTE.title, bold: true },
902557
902461
  { text: category.summary, fg: FULLSCREEN_PALETTE.subtitle },
902558
- ...compactPrimarySurface ? [] : [
902559
- { text: "" },
902560
- { text: category.detail, fg: FULLSCREEN_PALETTE.text }
902561
- ],
902562
902462
  ...workspace.actionSearchActive ? [
902563
- { text: "" },
902564
902463
  { text: "Action Search", fg: FULLSCREEN_PALETTE.title, bold: true },
902565
902464
  {
902566
902465
  text: workspace.actionSearchQuery.length > 0 ? `Query: ${workspace.actionSearchQuery} (${workspace.actionSearchResults.length} result${workspace.actionSearchResults.length === 1 ? "" : "s"})` : "Type to search every Agent workspace action.",
902567
902466
  fg: workspace.actionSearchQuery.length > 0 && workspace.actionSearchResults.length === 0 ? FULLSCREEN_PALETTE.warn : FULLSCREEN_PALETTE.info
902568
902467
  },
902569
- { text: "Enter opens the selected result. Esc clears search and returns to normal workspace navigation.", fg: FULLSCREEN_PALETTE.muted },
902570
- { text: "" }
902468
+ { text: "Enter opens; Esc clears.", fg: FULLSCREEN_PALETTE.muted }
902571
902469
  ] : [],
902572
- ...workspace.localEditor ? editorContextLines(workspace.localEditor) : [],
902573
- ...workspace.localEditor ? [{ text: "" }] : []
902470
+ ...workspace.localEditor ? editorContextLines(workspace.localEditor) : []
902574
902471
  ];
902575
902472
  const selectedActionLines = action2 ? [
902576
- { text: "" },
902577
902473
  { text: `Selected: ${action2.label}`, fg: FULLSCREEN_PALETTE.title, bold: true },
902578
- { text: action2.detail, fg: FULLSCREEN_PALETTE.text },
902579
- { text: `Command: ${actionCommand(action2)}`, fg: action2.kind === "command" ? FULLSCREEN_PALETTE.info : FULLSCREEN_PALETTE.muted },
902580
- { text: `Safety: ${action2.safety}`, fg: safetyColor(action2) }
902474
+ actionMetaLine(action2)
902581
902475
  ] : [];
902582
- const snapshotContextLines = [
902583
- { text: "" },
902584
- ...snapshotLines(workspace, category, workspace.runtimeSnapshot)
902585
- ];
902586
- if (compactPrimarySurface)
902587
- lines.push(...selectedActionLines, ...snapshotContextLines);
902588
- else
902589
- lines.push(...snapshotContextLines, ...selectedActionLines);
902476
+ const snapshotContextLines = snapshotLines(workspace, category, workspace.runtimeSnapshot);
902477
+ lines.push(...selectedActionLines, ...snapshotContextLines);
902590
902478
  if (workspace.lastActionResult) {
902591
- lines.push({ text: "" }, { text: "Action Result", fg: FULLSCREEN_PALETTE.title, bold: true }, { text: workspace.lastActionResult.title, fg: actionResultColor(workspace.lastActionResult), bold: true }, { text: workspace.lastActionResult.detail, fg: FULLSCREEN_PALETTE.text });
902479
+ lines.push({ text: "Action Result", fg: FULLSCREEN_PALETTE.title, bold: true }, { text: workspace.lastActionResult.title, fg: actionResultColor(workspace.lastActionResult), bold: true }, { text: compactText3(workspace.lastActionResult.detail), fg: FULLSCREEN_PALETTE.text });
902592
902480
  if (workspace.lastActionResult.command) {
902593
902481
  lines.push({ text: `Command: ${workspace.lastActionResult.command}`, fg: FULLSCREEN_PALETTE.muted });
902594
902482
  }
@@ -902721,12 +902609,11 @@ function footerText3(workspace) {
902721
902609
  function renderAgentWorkspace(workspace, width, height) {
902722
902610
  const category = workspace.selectedActionCategory;
902723
902611
  const action2 = workspace.selectedAction;
902724
- const compactPrimarySurface = category.id === "home" || category.id === "setup";
902725
902612
  const layoutOptions = {
902726
902613
  width,
902727
902614
  height,
902728
902615
  leftWidth: width < 90 ? undefined : 30,
902729
- contextRatio: compactPrimarySurface ? 0.4 : 0.62,
902616
+ contextRatio: 0.4,
902730
902617
  minContextRows: 10
902731
902618
  };
902732
902619
  const metrics = getFullscreenWorkspaceMetrics(layoutOptions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "1.0.43",
3
+ "version": "1.0.44",
4
4
  "private": false,
5
5
  "description": "GoodVibes personal operator assistant TUI with a proactive Agent product brain, isolated Agent Knowledge, local profiles, routines, skills, personas, and explicit build delegation.",
6
6
  "type": "module",
@@ -5,9 +5,9 @@ import type {
5
5
  AgentWorkspaceLocalEditor,
6
6
  AgentWorkspaceRuntimeSnapshot,
7
7
  } from '../input/agent-workspace.ts';
8
- import { formatAgentRecordReviewState, formatAgentRecordSource } from '../agent/record-labels.ts';
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,
@@ -81,6 +81,21 @@ function setupStatusLabel(status: AgentWorkspaceRuntimeSnapshot['setupChecklist'
81
81
  : 'Optional';
82
82
  }
83
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
+
84
99
  function setupAttentionItems(snapshot: AgentWorkspaceRuntimeSnapshot, limit: number): AgentWorkspaceRuntimeSnapshot['setupChecklist'] {
85
100
  return [
86
101
  ...snapshot.setupChecklist.filter((item) => item.status === 'blocked'),
@@ -145,54 +160,41 @@ function companionAccessLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLi
145
160
  : 'missing';
146
161
  const error = access.tokenError ? `; token read error ${access.tokenError}` : '';
147
162
  return {
148
- text: `Companion: ${access.surface}; token ${tokenState}; QR ${access.qrCommand}; manual token text hidden${error}.`,
163
+ text: `Companion: ${access.surface}; token ${tokenState}; QR ${access.qrCommand}${error}.`,
149
164
  fg: access.pairingReady ? PALETTE.good : PALETTE.warn,
150
165
  };
151
166
  }
152
167
 
153
- function localLibraryLines(
168
+ function compactLocalLibraryLines(
154
169
  title: string,
155
170
  items: readonly AgentWorkspaceRuntimeSnapshot['localPersonas'][number][],
156
171
  emptyText: string,
157
172
  selectedId: string | null,
158
173
  ): ContextLine[] {
159
- const lines: ContextLine[] = [
160
- { text: title, fg: PALETTE.title, bold: true },
161
- ];
174
+ const lines: ContextLine[] = [];
162
175
  if (items.length === 0) {
163
- lines.push({ text: emptyText, fg: PALETTE.warn });
176
+ lines.push({ text: `${title}: 0. ${emptyText}`, fg: PALETTE.warn });
164
177
  return lines;
165
178
  }
166
- for (const item of items.slice(0, 8)) {
167
- const selected = item.id === selectedId;
168
- const status = [
169
- selected ? 'selected' : '',
170
- item.active ? 'active' : '',
171
- item.enabled === true ? 'enabled' : item.enabled === false ? 'disabled' : '',
172
- item.scope && item.cls ? `${item.scope}/${item.cls}` : '',
173
- item.confidence !== undefined ? `${item.confidence}%` : '',
174
- item.requirementCount !== undefined && item.requirementCount > 0
175
- ? (item.missingRequirementCount && item.missingRequirementCount > 0 ? `needs ${item.missingRequirementCount}/${item.requirementCount}` : `ready ${item.requirementCount}/${item.requirementCount}`)
176
- : '',
177
- formatAgentRecordReviewState(item.reviewState),
178
- item.source ? `origin ${item.source}` : '',
179
- item.startCount !== undefined ? `starts ${item.startCount}` : '',
180
- ].filter(Boolean).join(' / ');
181
- const tags = item.tags.length > 0 ? ` tags ${item.tags.join(',')}` : '';
182
- const triggers = item.triggers.length > 0 ? ` triggers ${item.triggers.join(',')}` : '';
183
- const marker = selected ? `${GLYPHS.navigation.selected} ` : '';
184
- lines.push({
185
- text: `${marker}${item.id}: ${item.name} (${status})`,
186
- fg: item.reviewState === 'stale' ? PALETTE.warn : PALETTE.info,
187
- bold: selected || item.active === true,
188
- });
189
- lines.push({ text: ` ${item.description}${tags}${triggers}`, fg: PALETTE.muted });
190
- if (item.missingRequirements && item.missingRequirements.length > 0) {
191
- lines.push({ text: ` missing setup: ${item.missingRequirements.join(', ')}`, fg: PALETTE.warn });
192
- }
193
- }
194
- if (items.length > 8) {
195
- 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 });
196
198
  }
197
199
  return lines;
198
200
  }
@@ -239,23 +241,18 @@ function routineNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): Context
239
241
  return { text: 'Next routine action: Start selected in the main conversation, inspect receipts, or reconcile connected schedules.', fg: PALETTE.info, bold: true };
240
242
  }
241
243
 
242
- function routineScheduleReceiptLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
244
+ function compactRoutineReceiptLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
243
245
  const latest = snapshot.latestRoutineScheduleReceipt;
244
- const lines: ContextLine[] = [
245
- {
246
- text: `Promotion receipts: ${snapshot.routineScheduleReceiptCount}; created: ${snapshot.successfulRoutineScheduleReceiptCount}; failed: ${snapshot.failedRoutineScheduleReceiptCount}`,
247
- fg: snapshot.failedRoutineScheduleReceiptCount > 0 ? PALETTE.warn : PALETTE.info,
248
- },
249
- ];
250
- if (latest) {
251
- lines.push({
252
- text: `Latest receipt: ${latest.id} ${latest.status} routine=${latest.routineId} schedule="${latest.scheduleName}" ${latest.scheduleKind} ${latest.scheduleValue}`,
253
- fg: latest.status === 'failed' ? PALETTE.warn : PALETTE.good,
254
- });
255
- } else {
256
- 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
+ };
257
251
  }
258
- return lines;
252
+ return {
253
+ text: `Promotion receipts: ${snapshot.routineScheduleReceiptCount}; latest ${latest.status} ${latest.routineId}.`,
254
+ fg: latest.status === 'failed' ? PALETTE.warn : PALETTE.good,
255
+ };
259
256
  }
260
257
 
261
258
  function automationNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
@@ -277,57 +274,6 @@ function automationNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): Cont
277
274
  return { text: 'Next automation action: Create a reminder, or create/import a routine before recurring workflow promotion.', fg: PALETTE.warn, bold: true };
278
275
  }
279
276
 
280
- function profileLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
281
- const lines: ContextLine[] = [
282
- { text: 'Agent Profiles', fg: PALETTE.title, bold: true },
283
- ];
284
- if (snapshot.runtimeProfiles.length === 0) {
285
- lines.push({ text: 'No isolated Agent profiles yet. Use Create Agent profile in this workspace.', fg: PALETTE.warn });
286
- return lines;
287
- }
288
- for (const profile of snapshot.runtimeProfiles.slice(0, 6)) {
289
- const starter = profile.starterTemplateId ? ` starter=${profile.starterTemplateId}` : ' starter=none';
290
- const created = profile.createdAt ? ` created ${profile.createdAt.slice(0, 10)}` : '';
291
- const states = [
292
- profile.id === snapshot.activeRuntimeProfile ? 'active' : '',
293
- profile.id === snapshot.selectedRuntimeProfile ? 'default' : '',
294
- ].filter(Boolean).join(', ');
295
- const stateText = states ? ` [${states}]` : '';
296
- lines.push({
297
- text: `${profile.id}${stateText}${starter}${created}`,
298
- fg: profile.id === snapshot.selectedRuntimeProfile ? PALETTE.good : PALETTE.info,
299
- bold: profile.id === snapshot.activeRuntimeProfile || profile.id === snapshot.selectedRuntimeProfile,
300
- });
301
- lines.push({ text: ` home: ${profile.homeDirectory}`, fg: PALETTE.muted });
302
- }
303
- if (snapshot.runtimeProfiles.length > 6) {
304
- lines.push({ text: `${snapshot.runtimeProfiles.length - 6} more profile(s).`, fg: PALETTE.dim });
305
- }
306
- return lines;
307
- }
308
-
309
- function starterTemplateLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
310
- const lines: ContextLine[] = [
311
- { text: 'Starter Templates', fg: PALETTE.title, bold: true },
312
- ];
313
- for (const template of snapshot.runtimeStarterTemplates.slice(0, 6)) {
314
- const origin = template.source === 'local' ? 'Local' : formatAgentRecordSource(template.source);
315
- lines.push({
316
- text: `${template.id}: ${template.name} [${origin}]`,
317
- fg: template.source === 'local' ? PALETTE.good : PALETTE.info,
318
- bold: template.id === 'research',
319
- });
320
- lines.push({
321
- text: ` ${template.description} Persona ${template.personaName}; skills ${template.skillNames.join(', ')}; routines ${template.routineNames.join(', ')}.`,
322
- fg: PALETTE.muted,
323
- });
324
- }
325
- if (snapshot.runtimeStarterTemplates.length > 6) {
326
- lines.push({ text: `${snapshot.runtimeStarterTemplates.length - 6} more starter template(s).`, fg: PALETTE.dim });
327
- }
328
- return lines;
329
- }
330
-
331
277
  function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCategory, snapshot: AgentWorkspaceRuntimeSnapshot | null): ContextLine[] {
332
278
  if (!snapshot) return [{ text: 'Runtime context is not loaded yet.', fg: PALETTE.warn }];
333
279
  const base: ContextLine[] = [];
@@ -346,175 +292,89 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
346
292
  } else if (category.id === 'artifacts') {
347
293
  const mediaReady = snapshot.voiceMediaReadiness.readyMediaProviderCount;
348
294
  base.push(
349
- { text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
350
- { text: `Agent Knowledge route: ${snapshot.knowledgeRoute}`, fg: PALETTE.info },
351
- { text: `Media providers: ${mediaReady}/${snapshot.mediaProviderCount} ready; generation-capable ${snapshot.mediaGenerationProviderCount}.`, fg: mediaReady > 0 ? PALETTE.good : PALETTE.warn },
352
- { 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 },
353
- { text: 'Agent Knowledge ingest writes only to the isolated Agent segment. Default knowledge and non-Agent routes are not fallback storage.', fg: PALETTE.warn },
354
- { text: 'Generated media is stored as artifacts and referenced by id; the TUI should not print inline base64.', fg: PALETTE.muted },
355
- { 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 },
356
299
  );
357
300
  } else if (category.id === 'channels') {
358
301
  const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
359
302
  const readyCount = snapshot.channels.filter((channel) => channel.ready).length;
360
303
  const configuredDefaults = snapshot.channels.filter((channel) => channel.defaultTarget === 'configured').length;
361
- const readyChannels = snapshot.channels.filter((channel) => channel.ready).map((channel) => channel.label);
362
304
  const needsTarget = snapshot.channels.filter((channel) => channel.setupState === 'needs-target');
363
305
  const needsConfig = snapshot.channels.filter((channel) => channel.setupState === 'needs-config');
364
306
  const nextAttentionChannel = needsConfig[0] ?? needsTarget[0] ?? snapshot.channels.find((channel) => !channel.enabled);
365
- const disabledChannels = snapshot.channels.filter((channel) => !channel.enabled).map((channel) => channel.label);
366
- const disabledPreview = disabledChannels.slice(0, 6).join(', ');
367
- const disabledSuffix = disabledChannels.length > 6 ? `, +${disabledChannels.length - 6} more` : '';
368
- const orderedChannels = [
369
- ...snapshot.channels.filter((channel) => channel.enabled),
370
- ...snapshot.channels.filter((channel) => !channel.enabled),
371
- ].slice(0, 3);
372
307
  base.push(
373
- { text: `GoodVibes API: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
308
+ { text: `API: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
374
309
  companionAccessLine(snapshot),
375
- { text: `Readiness: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} default target(s) configured.`, fg: PALETTE.info },
376
- { text: 'Setup path: pair companion -> inspect readiness -> review accounts/policies/status -> fix one channel -> add explicit notification target if needed.', fg: PALETTE.good },
377
- { 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 },
378
- { text: `Ready channels: ${readyChannels.join(', ') || 'none'}.`, fg: readyChannels.length > 0 ? PALETTE.good : PALETTE.warn },
379
- { text: `Needs default target: ${needsTarget.map((channel) => `${channel.label} -> ${channel.defaultTargetKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsTarget.length > 0 ? PALETTE.warn : PALETTE.muted },
380
- { text: `Needs config: ${needsConfig.map((channel) => `${channel.label} -> ${channel.missingRequiredKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsConfig.length > 0 ? PALETTE.warn : PALETTE.muted },
381
- { text: `Disabled channels: ${disabledPreview || 'none'}${disabledSuffix}.`, fg: PALETTE.dim },
382
- { 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 },
383
313
  );
384
- for (const channel of orderedChannels) {
385
- const ready = channel.ready ? 'ready' : `${channel.missingConfigCount} missing`;
386
- base.push({
387
- text: `${channel.label}: ${channel.setupState}; ${ready}; target ${channel.defaultTarget}; delivery ${channel.delivery}; risk ${channel.risk}.`,
388
- fg: channel.ready ? PALETTE.good : channel.enabled ? PALETTE.warn : PALETTE.dim,
389
- });
390
- }
391
314
  } else if (category.id === 'knowledge') {
392
315
  base.push(
393
- { text: `Route family: ${snapshot.knowledgeRoute}/{status,ask,search}`, fg: PALETTE.info },
394
- { text: `Isolation: ${snapshot.knowledgeIsolation}; no default knowledge or non-Agent fallback`, fg: PALETTE.good },
395
- { text: 'Ingest: URL, URL-list, and bookmark imports require explicit --yes and write only to Agent Knowledge.', fg: PALETTE.info },
396
- { text: 'Review: queue, issues, candidates, reports, reindex, and consolidation stay inside the Agent segment.', fg: PALETTE.muted },
397
- { 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 },
398
319
  );
399
320
  } else if (category.id === 'research') {
400
321
  base.push(
401
- { text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
402
- { text: `Agent Knowledge route: ${snapshot.knowledgeRoute}`, fg: PALETTE.info },
403
- { text: `Browser tools: ${snapshot.voiceMediaReadiness.browserToolState}; public base URL ${snapshot.browserToolPublicBaseUrl}.`, fg: snapshot.browserToolExposureEnabled ? PALETTE.warn : PALETTE.muted },
404
- { text: snapshot.voiceMediaReadiness.browserToolNextStep, fg: PALETTE.muted },
405
- { text: 'Research requests are submitted to the main conversation. Agent may use connected read-only web tools when the user asks.', fg: PALETTE.good },
406
- { text: 'URL references and web research do not ingest into Agent Knowledge. Ingestion is a separate confirmed Agent Knowledge action.', fg: PALETTE.warn },
407
- { text: 'Use Agent Knowledge ask/search first for known source-backed context; use web research for current or external sources.', fg: PALETTE.info },
408
- { 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 },
409
326
  );
410
327
  } else if (category.id === 'tools') {
411
328
  base.push(
412
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 },
413
- { text: 'Open MCP workspace for live server status, tool inventory, config paths, and confirmed add/remove/reload actions.', fg: PALETTE.info },
414
- { text: 'Add/update requires typed confirmation and dispatches through the TUI command router.', fg: PALETTE.good },
415
- { text: 'Trust changes remain explicit; allow-all is kept behind the settings workspace.', fg: PALETTE.warn },
416
- { text: 'Useful first actions: /mcp review, /mcp tools, /mcp config, and Add MCP server.', fg: PALETTE.muted },
417
- { 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 },
418
332
  );
419
333
  } else if (category.id === 'voice-media') {
420
334
  const readiness = snapshot.voiceMediaReadiness;
421
- const voiceRows = readiness.voiceProviders.slice(0, 6);
422
- const mediaRows = readiness.mediaProviders.slice(0, 6);
423
335
  base.push(
424
- { text: `Voice providers: ${snapshot.voiceProviderCount}; streaming TTS: ${snapshot.voiceStreamingProviderCount}; STT: ${snapshot.voiceSttProviderCount}; realtime: ${snapshot.voiceRealtimeProviderCount}.`, fg: PALETTE.info },
425
- { text: `Voice interaction: ${snapshot.voiceSurfaceEnabled ? 'enabled' : 'disabled'}; ready providers ${readiness.readyVoiceProviderCount}/${snapshot.voiceProviderCount}.`, fg: snapshot.voiceSurfaceEnabled ? PALETTE.warn : PALETTE.muted },
426
- { text: `TTS config: provider ${snapshot.ttsProvider}; voice ${snapshot.ttsVoice}; response model ${snapshot.ttsResponseModel}.`, fg: PALETTE.info },
427
- { text: `Selected TTS readiness: ${readiness.selectedTtsProviderLabel} -> ${readiness.selectedTtsProviderStatus}; voice ${readiness.ttsVoiceConfigured ? 'configured' : 'default'}; response route ${readiness.ttsResponseRouteConfigured ? 'configured' : 'chat route'}.`, fg: readiness.selectedTtsProviderStatus === 'ready' ? PALETTE.good : PALETTE.warn },
428
- { text: `Media providers: ${snapshot.mediaProviderCount}; understanding: ${snapshot.mediaUnderstandingProviderCount}; generation: ${snapshot.mediaGenerationProviderCount}.`, fg: PALETTE.info },
429
- { text: `Ready media providers: ${readiness.readyMediaProviderCount}/${snapshot.mediaProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? PALETTE.good : PALETTE.warn },
430
- { text: `Browser tools: ${readiness.browserToolState}; public base URL ${snapshot.browserToolPublicBaseUrl}.`, fg: snapshot.browserToolExposureEnabled ? PALETTE.warn : PALETTE.muted },
431
- { text: readiness.browserToolNextStep, fg: PALETTE.muted },
432
- { text: 'Voice provider readiness', fg: PALETTE.title, bold: true },
433
- );
434
- for (const provider of voiceRows) {
435
- const selected = provider.selected ? 'selected; ' : '';
436
- const missing = provider.missingSecretKeyOptions.length > 0 ? `; needs ${provider.missingSecretKeyOptions.join('|')}` : '';
437
- base.push({
438
- text: `${provider.label}: ${selected}${provider.setupState}; ${provider.features.join(', ') || 'registered'}${missing}.`,
439
- fg: provider.setupState === 'ready' ? PALETTE.good : provider.setupState === 'needs-secret' ? PALETTE.warn : PALETTE.muted,
440
- });
441
- }
442
- if (snapshot.voiceProviderCount > voiceRows.length) base.push({ text: `${snapshot.voiceProviderCount - voiceRows.length} more voice provider(s).`, fg: PALETTE.dim });
443
- base.push({ text: 'Media provider readiness', fg: PALETTE.title, bold: true });
444
- for (const provider of mediaRows) {
445
- const missing = provider.missingSecretKeyOptions.length > 0 ? `; needs ${provider.missingSecretKeyOptions.join('|')}` : '';
446
- base.push({
447
- text: `${provider.label}: ${provider.setupState}; ${provider.features.join(', ') || 'registered'}${missing}.`,
448
- fg: provider.setupState === 'ready' ? PALETTE.good : provider.setupState === 'needs-secret' ? PALETTE.warn : PALETTE.muted,
449
- });
450
- }
451
- if (snapshot.mediaProviderCount > mediaRows.length) base.push({ text: `${snapshot.mediaProviderCount - mediaRows.length} more media provider(s).`, fg: PALETTE.dim });
452
- for (const step of readiness.nextSteps.slice(0, 4)) base.push({ text: `Next: ${step}`, fg: PALETTE.info });
453
- base.push(
454
- { text: 'No secret values are rendered. Voice, browser, and generated media side effects require explicit user action.', fg: PALETTE.warn },
455
- { 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 },
456
341
  );
457
342
  } else if (category.id === 'profiles') {
458
343
  const defaultProfile = snapshot.selectedRuntimeProfile
459
344
  ? `${snapshot.selectedRuntimeProfile}${snapshot.selectedRuntimeProfileExists ? '' : ' (missing)'}`
460
345
  : '(base Agent home)';
461
346
  base.push(
462
- { text: `Active Agent profile: ${snapshot.activeRuntimeProfile}`, fg: PALETTE.info },
463
- { text: `Default for next launch: ${defaultProfile}`, fg: snapshot.selectedRuntimeProfileExists || !snapshot.selectedRuntimeProfile ? PALETTE.info : PALETTE.warn },
464
- { text: `Agent profiles under this home: ${snapshot.runtimeProfileCount}`, fg: PALETTE.info },
465
- { text: `Starter templates: ${snapshot.runtimeStarterTemplateCount}; local custom: ${snapshot.localStarterTemplateCount}`, fg: PALETTE.info },
466
- { text: `Starter ids: ${snapshot.runtimeStarterTemplates.map((template) => template.id).join(', ') || 'none'}`, fg: PALETTE.info },
467
- { text: 'Starter Templates', fg: PALETTE.title, bold: true },
468
- { text: `Agent profile root: ${snapshot.runtimeProfileRoot}`, fg: PALETTE.muted },
469
- { text: '' },
470
- ...profileLines(snapshot),
471
- { text: '' },
472
- ...starterTemplateLines(snapshot),
473
- { text: '' },
474
- { text: 'Named Agent profiles isolate local config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
475
- { text: 'Starter authoring: browse, export, edit, import, and create Agent profiles from inside this workspace.', fg: PALETTE.info },
476
- { text: 'The connected GoodVibes host stays shared unless that host is configured separately.', fg: PALETTE.warn },
477
- { 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 },
478
351
  );
479
352
  } else if (category.id === 'memory') {
480
353
  base.push(
481
- { text: `Session memories: ${snapshot.sessionMemoryCount}`, fg: PALETTE.info },
482
- { text: `Agent memory: ${snapshot.localMemoryCount}; prompt-active: ${snapshot.localMemoryPromptActiveCount}; review queue: ${snapshot.localMemoryReviewQueueCount}`, fg: PALETTE.info },
483
- { text: `Scratchpad notes: ${snapshot.localNoteCount}; review queue: ${snapshot.localNoteReviewQueueCount}`, fg: PALETTE.info },
484
- { text: `Local routines: ${snapshot.localRoutineCount}; enabled: ${snapshot.enabledRoutineCount}`, fg: PALETTE.info },
485
- { text: `Local skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}; bundles: ${snapshot.localSkillBundleCount}; active skills: ${snapshot.activeSkillCount}`, fg: PALETTE.info },
486
- { text: `Local personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
487
- { text: 'Durable memory, scratchpad notes, routines, skills, and personas remain Agent-local until shared registry contracts exist.', fg: PALETTE.good },
488
- { text: 'Secrets are rejected/redacted; store secret references instead of secret values.', fg: PALETTE.warn },
489
- { text: '' },
490
- ...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 },
491
359
  );
492
360
  } else if (category.id === 'notes') {
493
361
  base.push(
494
362
  { text: `Scratchpad notes: ${snapshot.localNoteCount}; review queue: ${snapshot.localNoteReviewQueueCount}`, fg: PALETTE.info },
495
- { text: 'Notes are Agent-local working context for source triage, temporary decisions, and operator handoff.', fg: PALETTE.good },
496
- { text: 'Notes do not become memory and are not ingested into Agent Knowledge unless the user takes a separate explicit action.', fg: PALETTE.warn },
497
- { 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 },
498
- { text: '' },
499
- ...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 },
500
365
  );
501
366
  } else if (category.id === 'personas') {
502
367
  base.push(
503
368
  { text: `Personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
504
- { text: 'Personas are local behavior profiles for the serial main-conversation assistant, not separate Agent jobs.', fg: PALETTE.good },
505
- { text: 'Use them for tone, role, domain constraints, tool posture, and repeatable operating preferences.', fg: PALETTE.muted },
506
- { text: '' },
507
- ...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 },
508
371
  );
509
372
  } else if (category.id === 'skills') {
510
373
  base.push(
511
374
  { text: `Skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}; bundles: ${snapshot.localSkillBundleCount}; enabled bundles: ${snapshot.enabledSkillBundleCount}; active skills: ${snapshot.activeSkillCount}`, fg: PALETTE.info },
512
- { text: 'Skills are reusable local procedures the assistant can apply from the main conversation.', fg: PALETTE.good },
513
- { text: 'Enabled skills and enabled bundles are injected as operating guidance; secret-looking content is rejected.', fg: PALETTE.warn },
514
- { text: '' },
515
- ...localLibraryLines('Skill Library', snapshot.localSkills, 'No local skills yet. Create one here with Create skill.', workspace.selectedLocalLibraryItem('skill')?.id ?? null),
516
- { text: '' },
517
- ...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 },
518
378
  );
519
379
  } else if (category.id === 'routines') {
520
380
  const ready = readyRoutineItems(snapshot);
@@ -523,42 +383,34 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
523
383
  base.push(
524
384
  { text: `Routines: ${snapshot.localRoutineCount}; enabled: ${snapshot.enabledRoutineCount}`, fg: PALETTE.info },
525
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 },
526
- { text: 'Routines are repeatable main-conversation workflows. Starting one does not create hidden jobs.', fg: PALETTE.good },
527
- { text: 'Scheduling a reviewed routine is explicit and requires a confirmed schedule command.', fg: PALETTE.warn },
528
386
  routineNextActionLine(snapshot),
529
- ...routineScheduleReceiptLines(snapshot),
530
- { text: '' },
531
- ...localLibraryLines('Routine Library', snapshot.localRoutines, 'No local routines yet. Create one here with Create routine.', workspace.selectedLocalLibraryItem('routine')?.id ?? null),
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 },
532
390
  );
533
391
  } else if (category.id === 'work') {
534
392
  base.push(
535
- { text: 'Work plan and approvals are read or explicitly confirmed through public operator routes.', fg: PALETTE.info },
536
- { text: 'This workspace does not approve, deny, cancel, or mutate requests by selection alone.', fg: PALETTE.good },
537
- { text: 'Approve, deny, and cancel forms require an approval id and typed confirmation.', fg: PALETTE.warn },
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 },
538
396
  );
539
397
  } else if (category.id === 'automation') {
540
398
  const ready = readyRoutineItems(snapshot);
541
399
  base.push(
542
- { text: 'Automation and schedules default to read-only observability; side effects require confirmed forms.', fg: PALETTE.info },
543
- { text: 'Confirmed reminders and routine promotion use connected schedules only.', fg: PALETTE.info },
544
- { text: 'Local scheduler mutation controls remain blocked; job/run/schedule controls go through the connected host.', fg: PALETTE.warn },
545
- { text: 'Reminder path: Create reminder -> choose at/every/cron -> optional delivery target -> confirm yes.', fg: PALETTE.good },
546
- { text: 'Operator path: choose job/run/schedule action -> enter id -> type yes -> dispatch once.', fg: PALETTE.good },
547
- { text: 'Routine path: Routines -> resolve setup -> review selected -> Promote routine -> Reconcile schedules.', fg: PALETTE.good },
548
- { 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 },
549
401
  automationNextActionLine(snapshot),
550
- ...routineScheduleReceiptLines(snapshot),
402
+ compactRoutineReceiptLine(snapshot),
403
+ { text: 'Reminders and routine promotion require confirmation.', fg: PALETTE.warn },
551
404
  );
552
405
  } else if (category.id === 'delegate') {
553
406
  base.push(
554
- { text: 'Build/fix/review work is handed to GoodVibes TUI/shared-session contracts.', fg: PALETTE.info },
407
+ { text: 'Build/fix/review work is handed to GoodVibes TUI.', fg: PALETTE.info },
555
408
  { text: `Delegated review policy: ${snapshot.delegatedReviewPolicy}`, fg: PALETTE.warn },
556
- { text: 'Agent does not create coding-role Agent jobs.', fg: PALETTE.good },
409
+ { text: 'No coding-role Agent jobs are created here.', fg: PALETTE.good },
557
410
  );
558
411
  }
559
412
  if (snapshot.warnings.length > 0) {
560
- base.push({ text: '', dim: true }, { text: 'Warnings', fg: PALETTE.warn, bold: true });
561
- 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 });
562
414
  }
563
415
  return base;
564
416
  }
@@ -567,30 +419,23 @@ function editorContextLines(editor: AgentWorkspaceLocalEditor): ContextLine[] {
567
419
  const selected = editor.fields[editor.selectedFieldIndex];
568
420
  const lines: ContextLine[] = [
569
421
  { text: editor.title, fg: PALETTE.title, bold: true },
570
- { text: editor.message, fg: editor.message.includes('required') || editor.message.includes('cannot') || editor.message.includes('Cannot') ? PALETTE.warn : PALETTE.info },
571
- { text: 'Enter advances fields and saves from the final field. Ctrl-J adds a line inside multiline fields. Esc cancels without writing.', fg: PALETTE.muted },
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 },
572
424
  ];
573
425
  if (selected) {
574
426
  lines.push(
575
- { text: '' },
576
427
  { text: `Editing: ${selected.label}${selected.required ? ' (required)' : ''}`, fg: PALETTE.title, bold: true },
577
- { text: selected.hint, fg: PALETTE.muted },
428
+ { text: compactText(selected.hint), fg: PALETTE.muted },
578
429
  );
579
430
  }
580
431
  return lines;
581
432
  }
582
433
 
583
434
  function buildContextRows(workspace: AgentWorkspace, category: AgentWorkspaceCategory, action: AgentWorkspaceAction | null, width: number): WorkspaceRow[] {
584
- const compactPrimarySurface = category.id === 'home' || category.id === 'setup';
585
435
  const lines: ContextLine[] = [
586
436
  { text: category.label, fg: PALETTE.title, bold: true },
587
437
  { text: category.summary, fg: PALETTE.subtitle },
588
- ...(compactPrimarySurface ? [] : [
589
- { text: '' },
590
- { text: category.detail, fg: PALETTE.text },
591
- ] satisfies ContextLine[]),
592
438
  ...(workspace.actionSearchActive ? [
593
- { text: '' },
594
439
  { text: 'Action Search', fg: PALETTE.title, bold: true },
595
440
  {
596
441
  text: workspace.actionSearchQuery.length > 0
@@ -598,35 +443,25 @@ function buildContextRows(workspace: AgentWorkspace, category: AgentWorkspaceCat
598
443
  : 'Type to search every Agent workspace action.',
599
444
  fg: workspace.actionSearchQuery.length > 0 && workspace.actionSearchResults.length === 0 ? PALETTE.warn : PALETTE.info,
600
445
  },
601
- { text: 'Enter opens the selected result. Esc clears search and returns to normal workspace navigation.', fg: PALETTE.muted },
602
- { text: '' },
446
+ { text: 'Enter opens; Esc clears.', fg: PALETTE.muted },
603
447
  ] satisfies ContextLine[] : []),
604
448
  ...(workspace.localEditor ? editorContextLines(workspace.localEditor) : []),
605
- ...(workspace.localEditor ? [{ text: '' }] : []),
606
449
  ];
607
450
 
608
451
  const selectedActionLines: ContextLine[] = action
609
452
  ? [
610
- { text: '' },
611
453
  { text: `Selected: ${action.label}`, fg: PALETTE.title, bold: true },
612
- { text: action.detail, fg: PALETTE.text },
613
- { text: `Command: ${actionCommand(action)}`, fg: action.kind === 'command' ? PALETTE.info : PALETTE.muted },
614
- { text: `Safety: ${action.safety}`, fg: safetyColor(action) },
454
+ actionMetaLine(action),
615
455
  ]
616
456
  : [];
617
- const snapshotContextLines: ContextLine[] = [
618
- { text: '' },
619
- ...snapshotLines(workspace, category, workspace.runtimeSnapshot),
620
- ];
621
- if (compactPrimarySurface) lines.push(...selectedActionLines, ...snapshotContextLines);
622
- else lines.push(...snapshotContextLines, ...selectedActionLines);
457
+ const snapshotContextLines = snapshotLines(workspace, category, workspace.runtimeSnapshot);
458
+ lines.push(...selectedActionLines, ...snapshotContextLines);
623
459
 
624
460
  if (workspace.lastActionResult) {
625
461
  lines.push(
626
- { text: '' },
627
462
  { text: 'Action Result', fg: PALETTE.title, bold: true },
628
463
  { text: workspace.lastActionResult.title, fg: actionResultColor(workspace.lastActionResult), bold: true },
629
- { text: workspace.lastActionResult.detail, fg: PALETTE.text },
464
+ { text: compactText(workspace.lastActionResult.detail), fg: PALETTE.text },
630
465
  );
631
466
  if (workspace.lastActionResult.command) {
632
467
  lines.push({ text: `Command: ${workspace.lastActionResult.command}`, fg: PALETTE.muted });
@@ -762,12 +597,11 @@ function footerText(workspace: AgentWorkspace): string {
762
597
  export function renderAgentWorkspace(workspace: AgentWorkspace, width: number, height: number): Line[] {
763
598
  const category = workspace.selectedActionCategory;
764
599
  const action = workspace.selectedAction;
765
- const compactPrimarySurface = category.id === 'home' || category.id === 'setup';
766
600
  const layoutOptions = {
767
601
  width,
768
602
  height,
769
603
  leftWidth: width < 90 ? undefined : 30,
770
- contextRatio: compactPrimarySurface ? 0.4 : 0.62,
604
+ contextRatio: 0.4,
771
605
  minContextRows: 10,
772
606
  };
773
607
  const metrics = getFullscreenWorkspaceMetrics(layoutOptions);
package/src/version.ts CHANGED
@@ -6,7 +6,7 @@ import { join } from 'node:path';
6
6
  // The prebuild script updates the fallback value before compilation.
7
7
  // Uses import.meta.dir (Bun) to locate package.json relative to this file,
8
8
  // which is correct regardless of the process working directory.
9
- let _version = '1.0.43';
9
+ let _version = '1.0.44';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
12
12
  readonly version?: unknown;