@pellux/goodvibes-agent 1.1.7 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/README.md +46 -30
  3. package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
  4. package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
  5. package/dist/package/main.js +138903 -91477
  6. package/docs/README.md +14 -7
  7. package/docs/channels-remote-and-api.md +8 -5
  8. package/docs/connected-host.md +14 -12
  9. package/docs/getting-started.md +58 -30
  10. package/docs/knowledge-artifacts-and-multimodal.md +7 -5
  11. package/docs/project-planning.md +2 -2
  12. package/docs/providers-and-routing.md +11 -3
  13. package/docs/tools-and-commands.md +116 -45
  14. package/docs/voice-and-live-tts.md +3 -1
  15. package/package.json +3 -2
  16. package/release/release-notes.md +142 -5
  17. package/release/release-readiness.json +124 -94
  18. package/src/agent/assistant-cockpit.ts +247 -0
  19. package/src/agent/autonomy-schedule-format.ts +96 -0
  20. package/src/agent/autonomy-schedule.ts +514 -0
  21. package/src/agent/channel-delivery-receipts.ts +292 -0
  22. package/src/agent/competitive-feature-inventory.ts +294 -0
  23. package/src/agent/document-registry-types.ts +106 -0
  24. package/src/agent/document-registry.ts +734 -0
  25. package/src/agent/harness-control.ts +2 -2
  26. package/src/agent/memory-prompt.ts +2 -2
  27. package/src/agent/operator-actions.ts +50 -6
  28. package/src/agent/persona-registry.ts +8 -0
  29. package/src/agent/project-context-files.ts +273 -0
  30. package/src/agent/prompt-context-receipts.ts +502 -0
  31. package/src/agent/reminder-schedule-format.ts +16 -2
  32. package/src/agent/research-run-registry.ts +582 -0
  33. package/src/agent/research-source-registry.ts +441 -0
  34. package/src/agent/routine-registry.ts +19 -3
  35. package/src/agent/routine-schedule-format.ts +27 -2
  36. package/src/agent/runtime-profile-starters.ts +7 -0
  37. package/src/agent/runtime-profile.ts +106 -4
  38. package/src/agent/schedule-edit-format.ts +129 -0
  39. package/src/agent/schedule-edit.ts +496 -0
  40. package/src/agent/schedule-next-routes.ts +42 -0
  41. package/src/agent/setup-wizard-artifact-receipts.ts +366 -0
  42. package/src/agent/setup-wizard-checkpoint.ts +140 -0
  43. package/src/agent/setup-wizard.ts +683 -0
  44. package/src/agent/skill-registry-types.ts +102 -0
  45. package/src/agent/skill-registry.ts +81 -107
  46. package/src/agent/vibe-confirmation-routes.ts +62 -0
  47. package/src/agent/vibe-file.ts +285 -0
  48. package/src/cli/agent-knowledge-command.ts +45 -2
  49. package/src/cli/help.ts +3 -0
  50. package/src/cli/profiles-command.ts +25 -11
  51. package/src/config/agent-settings-policy.ts +1 -18
  52. package/src/input/agent-workspace-activation.ts +53 -0
  53. package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
  54. package/src/input/agent-workspace-artifact-metadata.ts +17 -0
  55. package/src/input/agent-workspace-basic-command-editors.ts +5 -1
  56. package/src/input/agent-workspace-categories.ts +153 -155
  57. package/src/input/agent-workspace-channel-triage.ts +481 -0
  58. package/src/input/agent-workspace-channels.ts +263 -0
  59. package/src/input/agent-workspace-command-editor.ts +152 -0
  60. package/src/input/agent-workspace-context-snapshot.ts +349 -0
  61. package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
  62. package/src/input/agent-workspace-document-editor.ts +502 -0
  63. package/src/input/agent-workspace-document-ops-editor.ts +523 -0
  64. package/src/input/agent-workspace-host-category.ts +1 -1
  65. package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
  66. package/src/input/agent-workspace-model-compare-editor.ts +376 -0
  67. package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
  68. package/src/input/agent-workspace-model-compare-types.ts +82 -0
  69. package/src/input/agent-workspace-model-compare-utils.ts +35 -0
  70. package/src/input/agent-workspace-onboarding-categories.ts +141 -0
  71. package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
  72. package/src/input/agent-workspace-operations-command-editors.ts +22 -0
  73. package/src/input/agent-workspace-research-report-editor.ts +212 -0
  74. package/src/input/agent-workspace-research-run-editor.ts +144 -0
  75. package/src/input/agent-workspace-research-source-editor.ts +167 -0
  76. package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
  77. package/src/input/agent-workspace-review-packet-utils.ts +265 -0
  78. package/src/input/agent-workspace-settings.ts +313 -30
  79. package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
  80. package/src/input/agent-workspace-setup-snapshot.ts +217 -0
  81. package/src/input/agent-workspace-setup.ts +61 -1
  82. package/src/input/agent-workspace-snapshot.ts +184 -149
  83. package/src/input/agent-workspace-types.ts +287 -2
  84. package/src/input/agent-workspace.ts +23 -1
  85. package/src/input/command-registry.ts +9 -2
  86. package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
  87. package/src/input/commands/channels-runtime.ts +102 -114
  88. package/src/input/commands/delegation-runtime.ts +87 -24
  89. package/src/input/commands/knowledge-browser-flags.ts +12 -0
  90. package/src/input/commands/knowledge.ts +28 -14
  91. package/src/input/commands/operator-actions-runtime.ts +6 -3
  92. package/src/input/commands/schedule-runtime.ts +71 -14
  93. package/src/input/commands/session-content.ts +2 -2
  94. package/src/input/commands/shell-core.ts +2 -0
  95. package/src/input/commands/vibe-runtime.ts +140 -0
  96. package/src/input/commands.ts +2 -0
  97. package/src/input/connected-host-routes.ts +123 -0
  98. package/src/input/settings-modal-types.ts +14 -0
  99. package/src/input/setup-wizard-live-receipts.ts +76 -0
  100. package/src/main.ts +15 -15
  101. package/src/panels/qr-panel.ts +2 -2
  102. package/src/renderer/agent-workspace-context-lines.ts +701 -0
  103. package/src/renderer/agent-workspace.ts +68 -421
  104. package/src/renderer/settings-modal-helpers.ts +12 -0
  105. package/src/renderer/settings-modal.ts +12 -0
  106. package/src/runtime/bootstrap-command-context.ts +11 -1
  107. package/src/runtime/bootstrap-command-parts.ts +14 -3
  108. package/src/runtime/bootstrap-core.ts +39 -1
  109. package/src/runtime/bootstrap-shell.ts +6 -0
  110. package/src/runtime/bootstrap.ts +113 -30
  111. package/src/runtime/connected-host-auth.ts +3 -2
  112. package/src/runtime/execution-ledger.ts +231 -0
  113. package/src/runtime/services.ts +88 -10
  114. package/src/runtime/tool-permission-safety.ts +199 -5
  115. package/src/shell/session-continuity-hints.ts +39 -0
  116. package/src/tools/agent-artifacts-tool.ts +606 -0
  117. package/src/tools/agent-audit-tool.ts +155 -0
  118. package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
  119. package/src/tools/agent-autonomy-tool.ts +140 -0
  120. package/src/tools/agent-channel-send-tool.ts +24 -2
  121. package/src/tools/agent-channels-tool.ts +140 -0
  122. package/src/tools/agent-computer-tool.ts +168 -0
  123. package/src/tools/agent-context-policy.ts +137 -7
  124. package/src/tools/agent-context-tool.ts +143 -0
  125. package/src/tools/agent-delegation-tool.ts +128 -0
  126. package/src/tools/agent-device-tool.ts +240 -0
  127. package/src/tools/agent-documents-tool.ts +684 -0
  128. package/src/tools/agent-execution-tool.ts +230 -0
  129. package/src/tools/agent-harness-agent-orchestration-policy.ts +75 -0
  130. package/src/tools/agent-harness-agent-orchestration.ts +791 -0
  131. package/src/tools/agent-harness-autonomy-intake.ts +785 -0
  132. package/src/tools/agent-harness-autonomy-live-records.ts +742 -0
  133. package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
  134. package/src/tools/agent-harness-autonomy-queue.ts +571 -0
  135. package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
  136. package/src/tools/agent-harness-background-processes-types.ts +35 -0
  137. package/src/tools/agent-harness-background-processes.ts +798 -0
  138. package/src/tools/agent-harness-browser-cockpit-route.ts +373 -0
  139. package/src/tools/agent-harness-browser-control.ts +346 -0
  140. package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -0
  141. package/src/tools/agent-harness-channel-metadata.ts +168 -10
  142. package/src/tools/agent-harness-cli-command-policy.ts +110 -0
  143. package/src/tools/agent-harness-command-catalog.ts +4 -2
  144. package/src/tools/agent-harness-command-runner.ts +42 -0
  145. package/src/tools/agent-harness-connected-host-status.ts +7 -4
  146. package/src/tools/agent-harness-delegation-posture.ts +234 -19
  147. package/src/tools/agent-harness-device-live-read-models.ts +366 -0
  148. package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
  149. package/src/tools/agent-harness-document-ops-types.ts +72 -0
  150. package/src/tools/agent-harness-document-ops.ts +671 -0
  151. package/src/tools/agent-harness-execution-history.ts +489 -0
  152. package/src/tools/agent-harness-execution-posture.ts +385 -0
  153. package/src/tools/agent-harness-file-recovery.ts +135 -0
  154. package/src/tools/agent-harness-interactive-runtime-records.ts +421 -0
  155. package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
  156. package/src/tools/agent-harness-learning-curator-common.ts +102 -0
  157. package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
  158. package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
  159. package/src/tools/agent-harness-learning-curator-types.ts +151 -0
  160. package/src/tools/agent-harness-learning-curator.ts +417 -0
  161. package/src/tools/agent-harness-local-model-benchmarks.ts +269 -0
  162. package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
  163. package/src/tools/agent-harness-local-model-endpoints.ts +788 -0
  164. package/src/tools/agent-harness-local-model-smoke.ts +277 -0
  165. package/src/tools/agent-harness-local-model-url.ts +78 -0
  166. package/src/tools/agent-harness-media-posture.ts +223 -2
  167. package/src/tools/agent-harness-memory-external-providers.ts +796 -0
  168. package/src/tools/agent-harness-memory-posture.ts +672 -0
  169. package/src/tools/agent-harness-memory-provider-certification.ts +219 -0
  170. package/src/tools/agent-harness-memory-refinement.ts +340 -0
  171. package/src/tools/agent-harness-metadata.ts +100 -168
  172. package/src/tools/agent-harness-mode-catalog.ts +86 -33
  173. package/src/tools/agent-harness-model-catalog.ts +162 -0
  174. package/src/tools/agent-harness-model-provider-health.ts +283 -0
  175. package/src/tools/agent-harness-model-readiness.ts +432 -0
  176. package/src/tools/agent-harness-model-routing-types.ts +327 -0
  177. package/src/tools/agent-harness-model-routing-utils.ts +30 -0
  178. package/src/tools/agent-harness-model-routing.ts +165 -193
  179. package/src/tools/agent-harness-operator-methods.ts +115 -133
  180. package/src/tools/agent-harness-pairing-posture.ts +452 -18
  181. package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
  182. package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
  183. package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
  184. package/src/tools/agent-harness-personal-ops-lanes.ts +270 -0
  185. package/src/tools/agent-harness-personal-ops-operations.ts +225 -0
  186. package/src/tools/agent-harness-personal-ops-provider-records.ts +358 -0
  187. package/src/tools/agent-harness-personal-ops-provider-task-records.ts +321 -0
  188. package/src/tools/agent-harness-personal-ops-records.ts +684 -0
  189. package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
  190. package/src/tools/agent-harness-personal-ops-types.ts +240 -0
  191. package/src/tools/agent-harness-personal-ops.ts +613 -0
  192. package/src/tools/agent-harness-project-context.ts +144 -0
  193. package/src/tools/agent-harness-prompt-context.ts +589 -0
  194. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  195. package/src/tools/agent-harness-release-evidence.ts +9 -7
  196. package/src/tools/agent-harness-release-readiness.ts +9 -7
  197. package/src/tools/agent-harness-remote-read-models.ts +541 -0
  198. package/src/tools/agent-harness-research-briefing.ts +446 -0
  199. package/src/tools/agent-harness-research-live-read-models.ts +500 -0
  200. package/src/tools/agent-harness-research-queue.ts +250 -0
  201. package/src/tools/agent-harness-research-runs.ts +307 -0
  202. package/src/tools/agent-harness-research-workflow.ts +395 -0
  203. package/src/tools/agent-harness-security-posture.ts +2 -2
  204. package/src/tools/agent-harness-service-posture.ts +9 -9
  205. package/src/tools/agent-harness-session-metadata.ts +3 -3
  206. package/src/tools/agent-harness-setup-connected-host.ts +501 -0
  207. package/src/tools/agent-harness-setup-describe.ts +557 -0
  208. package/src/tools/agent-harness-setup-handoffs.ts +502 -0
  209. package/src/tools/agent-harness-setup-model-helpers.ts +102 -0
  210. package/src/tools/agent-harness-setup-plan.ts +253 -0
  211. package/src/tools/agent-harness-setup-posture-types.ts +218 -0
  212. package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
  213. package/src/tools/agent-harness-setup-posture.ts +449 -221
  214. package/src/tools/agent-harness-setup-smoke.ts +533 -0
  215. package/src/tools/agent-harness-sudo-posture.ts +114 -0
  216. package/src/tools/agent-harness-tool-schema.ts +142 -7
  217. package/src/tools/agent-harness-tool-types.ts +83 -0
  218. package/src/tools/agent-harness-tool-utils.ts +43 -0
  219. package/src/tools/agent-harness-tool.ts +319 -370
  220. package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
  221. package/src/tools/agent-harness-ui-surface-types.ts +46 -0
  222. package/src/tools/agent-harness-vibe-health.ts +105 -0
  223. package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
  224. package/src/tools/agent-harness-workspace-actions.ts +114 -8
  225. package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
  226. package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
  227. package/src/tools/agent-host-tool.ts +159 -0
  228. package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
  229. package/src/tools/agent-learning-consolidation-core.ts +327 -0
  230. package/src/tools/agent-learning-consolidation-tool.ts +758 -0
  231. package/src/tools/agent-memory-tool.ts +253 -0
  232. package/src/tools/agent-model-compare-export.ts +315 -0
  233. package/src/tools/agent-model-compare-handoff.ts +592 -0
  234. package/src/tools/agent-model-compare-judgment.ts +633 -0
  235. package/src/tools/agent-model-compare-run.ts +735 -0
  236. package/src/tools/agent-model-compare-tool.ts +698 -0
  237. package/src/tools/agent-model-compare-types.ts +191 -0
  238. package/src/tools/agent-model-compare-utils.ts +93 -0
  239. package/src/tools/agent-models-tool.ts +208 -0
  240. package/src/tools/agent-operator-action-tool.ts +1 -1
  241. package/src/tools/agent-operator-method-tool.ts +643 -0
  242. package/src/tools/agent-personal-ops-tool.ts +197 -0
  243. package/src/tools/agent-policy-explanation.ts +415 -0
  244. package/src/tools/agent-research-report-tool.ts +608 -0
  245. package/src/tools/agent-research-runner.ts +367 -0
  246. package/src/tools/agent-research-runs-tool.ts +434 -0
  247. package/src/tools/agent-research-sources-tool.ts +443 -0
  248. package/src/tools/agent-research-tool.ts +515 -0
  249. package/src/tools/agent-review-packet-presets-core.ts +757 -0
  250. package/src/tools/agent-review-packet-presets-tool.ts +466 -0
  251. package/src/tools/agent-review-packet-share-tool.ts +305 -0
  252. package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
  253. package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
  254. package/src/tools/agent-route-planner-candidates-work.ts +251 -0
  255. package/src/tools/agent-route-planner-helpers.ts +667 -0
  256. package/src/tools/agent-route-planner.ts +185 -0
  257. package/src/tools/agent-route-tool.ts +105 -0
  258. package/src/tools/agent-schedule-edit-tool.ts +210 -0
  259. package/src/tools/agent-schedule-tool.ts +282 -0
  260. package/src/tools/agent-security-tool.ts +145 -0
  261. package/src/tools/agent-sessions-tool.ts +122 -0
  262. package/src/tools/agent-settings-import-tool.ts +104 -0
  263. package/src/tools/agent-settings-tool.ts +176 -0
  264. package/src/tools/agent-setup-tool.ts +226 -0
  265. package/src/tools/agent-support-tool.ts +122 -0
  266. package/src/tools/agent-terminal-process-tools.ts +167 -0
  267. package/src/tools/agent-tool-policy-guard-types.ts +77 -0
  268. package/src/tools/agent-tool-policy-guard.ts +106 -85
  269. package/src/tools/agent-vibe-tool.ts +297 -0
  270. package/src/tools/agent-work-plan-tool.ts +265 -6
  271. package/src/tools/agent-workspace-tool.ts +305 -0
  272. package/src/tools/artifact-archive.ts +169 -0
  273. package/src/tools/tool-definition-compaction.ts +36 -0
  274. package/src/version.ts +1 -1
@@ -5,9 +5,8 @@ import type {
5
5
  AgentWorkspaceLocalEditor,
6
6
  AgentWorkspaceRuntimeSnapshot,
7
7
  } from '../input/agent-workspace.ts';
8
- import { formatAgentRecordReviewState } from '../agent/record-labels.ts';
9
8
  import type { Line } from '../types/grid.ts';
10
- import { truncateDisplay, wrapText } from '../utils/terminal-width.ts';
9
+ import { wrapText } from '../utils/terminal-width.ts';
11
10
  import { GLYPHS } from './ui-primitives.ts';
12
11
  import {
13
12
  getFullscreenWorkspaceMetrics,
@@ -17,7 +16,8 @@ import {
17
16
  WORKSPACE_PALETTE as PALETTE,
18
17
  type WorkspaceRow,
19
18
  } from './fullscreen-workspace.ts';
20
- import { actionResultColor, setupStatusColor, type AgentWorkspaceContextLine as ContextLine } from './agent-workspace-style.ts';
19
+ import { actionResultColor, type AgentWorkspaceContextLine as ContextLine } from './agent-workspace-style.ts';
20
+ import { compactText, reviewerReadinessContextLines, snapshotLines } from './agent-workspace-context-lines.ts';
21
21
 
22
22
  function buildLeftRows(workspace: AgentWorkspace, height: number): WorkspaceRow[] {
23
23
  const rows: WorkspaceRow[] = [];
@@ -59,6 +59,7 @@ function actionCommand(action: AgentWorkspaceAction): string {
59
59
  if (action.kind === 'editor') return action.editorKind ? `edit ${action.editorKind}` : 'edit form';
60
60
  if (action.kind === 'setting') return action.settingKey ? `setting ${action.settingKey}` : 'setting';
61
61
  if (action.kind === 'settings-import') return 'import GoodVibes settings';
62
+ if (action.kind === 'setup-checkpoint') return action.setupCheckpointOperation ? `setup checkpoint ${action.setupCheckpointOperation}` : 'setup checkpoint';
62
63
  if (action.kind === 'model-picker') return action.modelPickerFlow === 'model' ? 'model picker' : 'provider/model picker';
63
64
  if (action.kind === 'settings-modal') return action.settingsTarget ? `settings ${action.settingsTarget}` : 'settings';
64
65
  if (action.kind === 'local-selection') return action.selectionDelta && action.selectionDelta < 0 ? 'select previous' : 'select next';
@@ -67,428 +68,46 @@ function actionCommand(action: AgentWorkspaceAction): string {
67
68
  return action.command ?? '(guidance)';
68
69
  }
69
70
 
70
- function setupCounts(snapshot: AgentWorkspaceRuntimeSnapshot): { ready: number; recommended: number; optional: number; blocked: number } {
71
- return {
72
- ready: snapshot.setupChecklist.filter((item) => item.status === 'ready').length,
73
- recommended: snapshot.setupChecklist.filter((item) => item.status === 'recommended').length,
74
- optional: snapshot.setupChecklist.filter((item) => item.status === 'optional').length,
75
- blocked: snapshot.setupChecklist.filter((item) => item.status === 'blocked').length,
76
- };
77
- }
78
-
79
- function setupStatusLabel(status: AgentWorkspaceRuntimeSnapshot['setupChecklist'][number]['status']): string {
80
- return status === 'ready'
81
- ? 'Ready'
82
- : status === 'recommended'
83
- ? 'Recommended'
84
- : status === 'blocked'
85
- ? 'Blocked'
86
- : 'Optional';
87
- }
88
-
89
- function formatMegabytes(bytes: number): string {
90
- if (!Number.isFinite(bytes) || bytes <= 0) return '0 MB';
91
- return `${Math.round(bytes / (1024 * 1024))} MB`;
92
- }
93
-
94
- function compactText(text: string, maxWidth = 104): string {
95
- const normalized = text.replace(/\s+/g, ' ').trim();
96
- if (normalized.length === 0) return '';
97
- const firstSentence = normalized.match(/^.*?[.!?](?:\s|$)/)?.[0]?.trim();
98
- const source = firstSentence && firstSentence.length <= maxWidth ? firstSentence : normalized;
99
- return truncateDisplay(source, maxWidth, '...');
100
- }
101
-
102
- function actionMetaLine(action: AgentWorkspaceAction): ContextLine {
103
- return {
104
- text: `Does: ${actionCommand(action)}`,
105
- fg: action.safety === 'blocked' ? PALETTE.warn : action.kind === 'command' ? PALETTE.info : PALETTE.muted,
106
- };
71
+ function isOnboardingCategory(category: AgentWorkspaceCategory): boolean {
72
+ return category.group === 'ONBOARDING';
107
73
  }
108
74
 
109
- function setupAttentionItems(snapshot: AgentWorkspaceRuntimeSnapshot, limit: number): AgentWorkspaceRuntimeSnapshot['setupChecklist'] {
110
- return [
111
- ...snapshot.setupChecklist.filter((item) => item.status === 'blocked'),
112
- ...snapshot.setupChecklist.filter((item) => item.status === 'recommended'),
113
- ...snapshot.setupChecklist.filter((item) => item.status === 'optional'),
114
- ].slice(0, limit);
115
- }
116
-
117
- function conciseSetupLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
118
- const counts = setupCounts(snapshot);
119
- return {
120
- text: `Setup: ${counts.ready}/${snapshot.setupChecklist.length} ready; ${counts.recommended} recommended; ${counts.blocked} blocked.`,
121
- fg: counts.blocked > 0 ? PALETTE.warn : PALETTE.info,
122
- };
123
- }
124
-
125
- function setupOverviewLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
126
- const counts = setupCounts(snapshot);
127
- const nextItems = setupAttentionItems(snapshot, 3);
128
- const lines: ContextLine[] = [
129
- { text: 'Onboarding', fg: PALETTE.title, bold: true },
130
- { text: `${counts.ready}/${snapshot.setupChecklist.length} ready; ${counts.recommended} recommended; ${counts.optional} optional; ${counts.blocked} blocked.`, fg: counts.blocked > 0 ? PALETTE.warn : PALETTE.info },
131
- { text: `Chat: ${snapshot.provider} / ${snapshot.modelDisplayName}.`, fg: PALETTE.info },
132
- { text: `Local: ${snapshot.localPersonaCount} personas, ${snapshot.localSkillCount} skills, ${snapshot.localRoutineCount} routines, ${snapshot.localMemoryCount} memories.`, fg: PALETTE.info },
133
- ];
134
- if (nextItems.length > 0) {
135
- const item = nextItems[0]!;
136
- lines.push({
137
- text: `Next: ${item.label} (${setupStatusLabel(item.status).toLowerCase()})`,
138
- fg: setupStatusColor(item.status),
139
- bold: item.status === 'blocked',
140
- });
75
+ function onboardingActionChange(workspace: AgentWorkspace, action: AgentWorkspaceAction): string {
76
+ if (action.kind === 'setting') {
77
+ return workspace.settingActionPreview(action) ?? 'Update setting';
141
78
  }
142
- return lines;
143
- }
144
-
145
- function homeNextActionLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
146
- const candidates = setupAttentionItems(snapshot, 3);
147
- if (candidates.length === 0) {
148
- return [
149
- { text: 'Next Actions', fg: PALETTE.title, bold: true },
150
- { text: 'Core setup is ready. Continue normal assistant work, review Knowledge sources, or tune local skills/routines as needed.', fg: PALETTE.good },
151
- ];
79
+ if (action.kind === 'settings-import') return 'Import compatible GoodVibes preferences';
80
+ if (action.kind === 'setup-checkpoint') {
81
+ if (action.setupCheckpointOperation === 'show') return 'Show saved setup progress';
82
+ if (action.setupCheckpointOperation === 'mark-current') return 'Save current setup progress';
83
+ if (action.setupCheckpointOperation === 'clear') return 'Clear saved setup progress';
84
+ return 'Review setup progress';
152
85
  }
153
- const lines: ContextLine[] = [{ text: 'Next Actions', fg: PALETTE.title, bold: true }];
154
- for (const item of candidates) {
155
- lines.push({
156
- text: `${setupStatusLabel(item.status)}: ${item.label}`,
157
- fg: setupStatusColor(item.status),
158
- bold: item.status === 'blocked',
159
- });
160
- }
161
- return lines;
162
- }
163
-
164
- function companionAccessLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
165
- const access = snapshot.companionAccess;
166
- const tokenState = access.tokenReadable
167
- ? `ready sha256:${access.tokenFingerprint ?? 'unknown'}`
168
- : access.tokenPresent
169
- ? 'present but unreadable'
170
- : 'missing';
171
- const error = access.tokenError ? `; token read error ${access.tokenError}` : '';
172
- return {
173
- text: `Companion: ${access.surface}; token ${tokenState}; QR ${access.qrCommand}${error}.`,
174
- fg: access.pairingReady ? PALETTE.good : PALETTE.warn,
175
- };
86
+ if (action.kind === 'model-picker') return action.modelPickerFlow === 'model' ? 'Choose a model' : 'Choose provider and model';
87
+ if (action.kind === 'settings-modal') return 'Open settings';
88
+ if (action.kind === 'workspace') return 'Open setup area';
89
+ if (action.kind === 'editor') return 'Open guided form';
90
+ if (action.kind === 'local-selection') return 'Move selection';
91
+ if (action.kind === 'local-operation') return 'Apply selected library action';
92
+ if (action.kind === 'onboarding-complete') return 'Save setup completion';
93
+ if (action.safety === 'read-only') return 'Review readiness';
94
+ if (action.safety === 'blocked') return 'Unavailable in this setup step';
95
+ return 'Open option';
176
96
  }
177
97
 
178
- function compactLocalLibraryLines(
179
- title: string,
180
- items: readonly AgentWorkspaceRuntimeSnapshot['localPersonas'][number][],
181
- emptyText: string,
182
- selectedId: string | null,
183
- ): ContextLine[] {
184
- const lines: ContextLine[] = [];
185
- if (items.length === 0) {
186
- lines.push({ text: `${title}: 0. ${emptyText}`, fg: PALETTE.warn });
187
- return lines;
188
- }
189
- const selected = items.find((item) => item.id === selectedId) ?? items[0]!;
190
- const status = [
191
- selected.active ? 'active' : '',
192
- selected.enabled === true ? 'enabled' : selected.enabled === false ? 'disabled' : '',
193
- selected.scope && selected.cls ? `${selected.scope}/${selected.cls}` : '',
194
- selected.confidence !== undefined ? `${selected.confidence}%` : '',
195
- selected.requirementCount !== undefined && selected.requirementCount > 0
196
- ? (selected.missingRequirementCount && selected.missingRequirementCount > 0 ? `needs ${selected.missingRequirementCount}/${selected.requirementCount}` : `ready ${selected.requirementCount}/${selected.requirementCount}`)
197
- : '',
198
- formatAgentRecordReviewState(selected.reviewState),
199
- selected.startCount !== undefined ? `starts ${selected.startCount}` : '',
200
- ].filter(Boolean).join(', ');
201
- lines.push({
202
- text: `${title}: ${items.length}; selected ${selected.name}${status ? ` (${status})` : ''}.`,
203
- fg: selected.reviewState === 'stale' ? PALETTE.warn : PALETTE.info,
204
- bold: selected.active === true,
205
- });
206
- if (selected.missingRequirements && selected.missingRequirements.length > 0) {
207
- lines.push({ text: `Missing setup: ${selected.missingRequirements.join(', ')}`, fg: PALETTE.warn });
208
- }
209
- return lines;
210
- }
211
-
212
- type LocalRoutineItem = AgentWorkspaceRuntimeSnapshot['localRoutines'][number];
213
-
214
- function readyRoutineItems(snapshot: AgentWorkspaceRuntimeSnapshot): readonly LocalRoutineItem[] {
215
- return snapshot.localRoutines.filter((routine) =>
216
- routine.enabled === true
217
- && routine.reviewState === 'reviewed'
218
- && (routine.missingRequirementCount ?? 0) === 0
219
- );
220
- }
221
-
222
- function routinesNeedingSetup(snapshot: AgentWorkspaceRuntimeSnapshot): readonly LocalRoutineItem[] {
223
- return snapshot.localRoutines.filter((routine) => (routine.missingRequirementCount ?? 0) > 0);
224
- }
225
-
226
- function routinesNeedingReview(snapshot: AgentWorkspaceRuntimeSnapshot): readonly LocalRoutineItem[] {
227
- return snapshot.localRoutines.filter((routine) => routine.reviewState !== 'reviewed');
228
- }
229
-
230
- function routineNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
231
- const discovered = snapshot.discoveredBehavior.routines.count;
232
- const ready = readyRoutineItems(snapshot);
233
- const needsSetup = routinesNeedingSetup(snapshot);
234
- const needsReview = routinesNeedingReview(snapshot);
235
-
236
- if (snapshot.localRoutineCount === 0 && discovered > 0) {
237
- return { text: 'Next routine action: Discover routine files, preview one, then import it from this workspace.', fg: PALETTE.warn, bold: true };
238
- }
239
- if (snapshot.localRoutineCount === 0) {
240
- return { text: 'Next routine action: Create routine for a repeatable main-conversation workflow.', fg: PALETTE.warn, bold: true };
241
- }
242
- if (needsSetup.length > 0) {
243
- return { text: `Next routine action: Needs setup for ${needsSetup[0]?.id ?? 'a routine'} before it can be trusted for schedule promotion.`, fg: PALETTE.warn, bold: true };
244
- }
245
- if (needsReview.length > 0) {
246
- return { text: `Next routine action: Review selected or inspect ${needsReview[0]?.id ?? 'a routine'} before schedule promotion.`, fg: PALETTE.warn, bold: true };
247
- }
248
- if (ready.length > 0 && snapshot.routineScheduleReceiptCount === 0) {
249
- return { text: `Next routine action: Promote ${ready[0]?.id ?? 'a reviewed routine'} to a connected schedule when you have a real cadence.`, fg: PALETTE.good, bold: true };
250
- }
251
- return { text: 'Next routine action: Start selected in the main conversation, inspect receipts, or reconcile connected schedules.', fg: PALETTE.info, bold: true };
98
+ function actionChange(workspace: AgentWorkspace, category: AgentWorkspaceCategory, action: AgentWorkspaceAction): string {
99
+ return isOnboardingCategory(category) ? onboardingActionChange(workspace, action) : actionCommand(action);
252
100
  }
253
101
 
254
- function compactRoutineReceiptLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
255
- const latest = snapshot.latestRoutineScheduleReceipt;
256
- if (!latest) {
257
- return {
258
- text: `Promotion receipts: ${snapshot.routineScheduleReceiptCount}; none created yet.`,
259
- fg: PALETTE.muted,
260
- };
261
- }
102
+ function actionMetaLine(workspace: AgentWorkspace, category: AgentWorkspaceCategory, action: AgentWorkspaceAction): ContextLine {
103
+ const onboarding = isOnboardingCategory(category);
262
104
  return {
263
- text: `Promotion receipts: ${snapshot.routineScheduleReceiptCount}; latest ${latest.status} ${latest.routineId}.`,
264
- fg: latest.status === 'failed' ? PALETTE.warn : PALETTE.good,
105
+ text: `${onboarding ? 'Change' : 'Does'}: ${actionChange(workspace, category, action)}`,
106
+ fg: action.safety === 'blocked' ? PALETTE.warn : !onboarding && action.kind === 'command' ? PALETTE.info : PALETTE.muted,
265
107
  };
266
108
  }
267
109
 
268
- function automationNextActionLine(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine {
269
- const ready = readyRoutineItems(snapshot);
270
- const needsSetup = routinesNeedingSetup(snapshot);
271
- const needsReview = routinesNeedingReview(snapshot);
272
- if (snapshot.routineScheduleReceiptCount > 0) {
273
- return { text: 'Next automation action: Reconcile schedules to compare local receipts with the connected host.', fg: PALETTE.info, bold: true };
274
- }
275
- if (ready.length > 0) {
276
- return { text: `Next automation action: Promote ${ready[0]?.id ?? 'a reviewed routine'} or create a one-off reminder.`, fg: PALETTE.good, bold: true };
277
- }
278
- if (needsSetup.length > 0) {
279
- return { text: `Next automation action: Resolve routine setup gaps in ${needsSetup[0]?.id ?? 'Routines'} before promotion, or create a reminder.`, fg: PALETTE.warn, bold: true };
280
- }
281
- if (needsReview.length > 0) {
282
- return { text: `Next automation action: Review ${needsReview[0]?.id ?? 'a routine'} in Routines before schedule promotion, or create a reminder.`, fg: PALETTE.warn, bold: true };
283
- }
284
- return { text: 'Next automation action: Create a reminder, or create/import a routine before recurring workflow promotion.', fg: PALETTE.warn, bold: true };
285
- }
286
-
287
- function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCategory, snapshot: AgentWorkspaceRuntimeSnapshot | null): ContextLine[] {
288
- if (!snapshot) return [{ text: 'Runtime context is not loaded yet.', fg: PALETTE.warn }];
289
- const base: ContextLine[] = [];
290
- if (category.id === 'home') {
291
- base.push(
292
- { text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
293
- { text: `Session: ${snapshot.sessionId}`, fg: PALETTE.muted },
294
- { text: `Policy: ${snapshot.executionPolicy}; delegated review ${snapshot.delegatedReviewPolicy}`, fg: PALETTE.good },
295
- conciseSetupLine(snapshot),
296
- ...homeNextActionLines(snapshot),
297
- );
298
- } else if (category.id === 'setup') {
299
- base.push(
300
- ...setupOverviewLines(snapshot),
301
- );
302
- } else if (category.id === 'account-model') {
303
- base.push(
304
- { text: `Chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`, fg: PALETTE.info },
305
- { text: `Subscriptions: ${snapshot.activeSubscriptionCount} active; ${snapshot.pendingSubscriptionCount} pending; ${snapshot.availableSubscriptionProviderCount} available.`, fg: snapshot.activeSubscriptionCount > 0 ? PALETTE.good : snapshot.pendingSubscriptionCount > 0 ? PALETTE.warn : PALETTE.muted },
306
- { text: `Embedding: ${snapshot.embeddingProvider}; reasoning ${snapshot.reasoningEffort}.`, fg: PALETTE.info },
307
- { text: `Helper: ${snapshot.helperEnabled ? 'enabled' : 'disabled'}; Tool LLM: ${snapshot.toolLlmEnabled ? 'enabled' : 'disabled'}.`, fg: snapshot.helperEnabled || snapshot.toolLlmEnabled ? PALETTE.good : PALETTE.muted },
308
- { text: `Cache: ${snapshot.cacheEnabled ? snapshot.cacheStableTtl : 'off'}; monitor ${snapshot.cacheMonitorHitRate ? snapshot.cacheHitRateWarningThreshold : 'off'}; failure hints ${snapshot.providerFailureHints ? 'on' : 'off'}.`, fg: snapshot.cacheEnabled ? PALETTE.info : PALETTE.muted },
309
- );
310
- } else if (category.id === 'assistant-behavior') {
311
- base.push(
312
- { text: `Interaction: ${snapshot.hitlMode}; guidance ${snapshot.guidanceMode}; history ${snapshot.saveHistory ? 'saved' : 'off'}.`, fg: PALETTE.info },
313
- { text: `Context: compact at ${snapshot.autoCompactThreshold}; stale warnings ${snapshot.staleContextWarnings ? 'on' : 'off'}.`, fg: PALETTE.info },
314
- { text: `Reasoning display: thinking ${snapshot.showThinking ? 'on' : 'off'}; summaries ${snapshot.showReasoningSummary ? 'on' : 'off'}.`, fg: PALETTE.muted },
315
- );
316
- } else if (category.id === 'tools-permissions') {
317
- base.push(
318
- { text: `Permission mode: ${snapshot.permissionMode}.`, fg: snapshot.permissionMode === 'allow-all' ? PALETTE.warn : PALETTE.info },
319
- { text: `Auto-approve ${snapshot.autoApprove ? 'on' : 'off'}; tool auto-heal ${snapshot.toolAutoHeal ? 'on' : 'off'}; token budget ${snapshot.toolsDefaultTokenBudget}.`, fg: snapshot.autoApprove ? PALETTE.warn : PALETTE.info },
320
- { text: `Artifact limit ${formatMegabytes(snapshot.artifactMaxBytes)}; raw prompt telemetry ${snapshot.rawPromptTelemetry ? 'on' : 'off'}.`, fg: snapshot.rawPromptTelemetry ? PALETTE.warn : PALETTE.muted },
321
- { text: `MCP servers: ${snapshot.mcpConnectedServerCount}/${snapshot.mcpServerCount} connected; quarantined ${snapshot.mcpQuarantinedServerCount}.`, fg: snapshot.mcpQuarantinedServerCount > 0 ? PALETTE.warn : PALETTE.info },
322
- { text: 'MCP and secret setup use forms; selecting a row does not run arbitrary tools.', fg: PALETTE.good },
323
- );
324
- } else if (category.id === 'onboarding-display') {
325
- base.push(
326
- { text: `Theme: ${snapshot.theme}; streaming ${snapshot.stream ? 'on' : 'off'}; line numbers ${snapshot.lineNumbers}.`, fg: PALETTE.info },
327
- { text: `Messages: operational ${snapshot.operationalMessages}; system ${snapshot.systemMessages}.`, fg: PALETTE.info },
328
- { text: `Release channel: ${snapshot.releaseChannel}.`, fg: PALETTE.muted },
329
- );
330
- } else if (category.id === 'onboarding-channels') {
331
- const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
332
- const readyCount = snapshot.channels.filter((channel) => channel.ready).length;
333
- const needsConfig = snapshot.channels.filter((channel) => channel.setupState === 'needs-config');
334
- const needsTarget = snapshot.channels.filter((channel) => channel.setupState === 'needs-target');
335
- base.push(
336
- { text: `Channels: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled.`, fg: enabledCount > 0 ? PALETTE.info : PALETTE.muted },
337
- { text: `Needs config: ${needsConfig.length}; needs target: ${needsTarget.length}.`, fg: needsConfig.length > 0 || needsTarget.length > 0 ? PALETTE.warn : PALETTE.good },
338
- { text: 'Enable only the channels you want; hidden channel fields appear after the channel is enabled.', fg: PALETTE.good },
339
- );
340
- } else if (category.id === 'onboarding-voice-media') {
341
- const readiness = snapshot.voiceMediaReadiness;
342
- base.push(
343
- { text: `Voice: ${snapshot.voiceSurfaceEnabled ? 'enabled' : 'disabled'}; TTS ${snapshot.ttsProvider}; voice ${snapshot.ttsVoice}.`, fg: snapshot.voiceSurfaceEnabled ? PALETTE.good : PALETTE.info },
344
- { text: `Media readiness: ${readiness.readyMediaProviderCount}/${snapshot.mediaProviderCount}; generation providers ${snapshot.mediaGenerationProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? PALETTE.good : PALETTE.muted },
345
- { text: `Telephony channel: ${snapshot.channels.find((channel) => channel.id === 'telephony')?.setupState ?? 'disabled'}.`, fg: PALETTE.info },
346
- );
347
- } else if (category.id === 'onboarding-context') {
348
- base.push(
349
- { text: `Local context: ${snapshot.localMemoryCount} memories, ${snapshot.localNoteCount} notes, ${snapshot.localPersonaCount} personas.`, fg: PALETTE.info },
350
- { text: `Skills: ${snapshot.enabledSkillCount}/${snapshot.localSkillCount} enabled; routines ${snapshot.enabledRoutineCount}/${snapshot.localRoutineCount} enabled.`, fg: PALETTE.info },
351
- { text: `Discovered files: personas ${snapshot.discoveredBehavior.personas.count}, skills ${snapshot.discoveredBehavior.skills.count}, routines ${snapshot.discoveredBehavior.routines.count}.`, fg: PALETTE.muted },
352
- );
353
- } else if (category.id === 'onboarding-automation') {
354
- base.push(
355
- { text: `Automation: ${snapshot.automationEnabled ? 'enabled' : 'disabled'}; max ${snapshot.automationMaxConcurrentRuns} concurrent; history ${snapshot.automationRunHistoryLimit}.`, fg: snapshot.automationEnabled ? PALETTE.good : PALETTE.muted },
356
- { text: `Timeout ${snapshot.automationDefaultTimeoutMs} ms; catch-up ${snapshot.automationCatchUpWindowMinutes} min; cooldown ${snapshot.automationFailureCooldownMs} ms.`, fg: PALETTE.info },
357
- { text: `Delete one-shot jobs after success: ${snapshot.automationDeleteAfterRun ? 'yes' : 'no'}.`, fg: snapshot.automationDeleteAfterRun ? PALETTE.info : PALETTE.muted },
358
- );
359
- } else if (category.id === 'artifacts') {
360
- const mediaReady = snapshot.voiceMediaReadiness.readyMediaProviderCount;
361
- base.push(
362
- { text: `Chat: ${snapshot.provider} / ${snapshot.modelDisplayName}; Knowledge: ${snapshot.knowledgeRoute}`, fg: PALETTE.info },
363
- { text: `Media: ${mediaReady}/${snapshot.mediaProviderCount} ready; generation ${snapshot.mediaGenerationProviderCount}.`, fg: mediaReady > 0 ? PALETTE.good : PALETTE.warn },
364
- { text: 'Files: attach, export, inspect, ingest reviewed sources, or generate media.', fg: PALETTE.good },
365
- { text: 'Knowledge ingest and media generation require explicit actions.', fg: PALETTE.warn },
366
- );
367
- } else if (category.id === 'channels') {
368
- const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
369
- const readyCount = snapshot.channels.filter((channel) => channel.ready).length;
370
- const configuredDefaults = snapshot.channels.filter((channel) => channel.defaultTarget === 'configured').length;
371
- const needsTarget = snapshot.channels.filter((channel) => channel.setupState === 'needs-target');
372
- const needsConfig = snapshot.channels.filter((channel) => channel.setupState === 'needs-config');
373
- const nextAttentionChannel = needsConfig[0] ?? needsTarget[0] ?? snapshot.channels.find((channel) => !channel.enabled);
374
- base.push(
375
- { text: `API: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
376
- companionAccessLine(snapshot),
377
- { text: `Channels: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} target(s).`, fg: PALETTE.info },
378
- { text: `Next: ${nextAttentionChannel ? `${nextAttentionChannel.label} - ${compactText(nextAttentionChannel.nextStep)}` : 'All enabled channels ready.'}`, fg: nextAttentionChannel ? PALETTE.warn : PALETTE.good },
379
- { text: 'Secrets hidden; sends require explicit action.', fg: PALETTE.warn },
380
- );
381
- } else if (category.id === 'knowledge') {
382
- base.push(
383
- { text: `Route: ${snapshot.knowledgeRoute}; isolation ${snapshot.knowledgeIsolation}.`, fg: PALETTE.info },
384
- { text: 'Ask/search, ingest, review, reindex, and reports stay Agent-owned.', fg: PALETTE.good },
385
- { text: 'Ingest requires explicit confirmation.', fg: PALETTE.warn },
386
- );
387
- } else if (category.id === 'research') {
388
- base.push(
389
- { text: `Chat: ${snapshot.provider} / ${snapshot.modelDisplayName}; Knowledge: ${snapshot.knowledgeRoute}`, fg: PALETTE.info },
390
- { text: `Browser: ${snapshot.voiceMediaReadiness.browserToolState}; public URL ${snapshot.browserToolPublicBaseUrl}.`, fg: snapshot.browserToolExposureEnabled ? PALETTE.warn : PALETTE.muted },
391
- { text: 'Research is read-only. Knowledge ingest is a separate confirmed action.', fg: PALETTE.good },
392
- { text: compactText(snapshot.voiceMediaReadiness.browserToolNextStep), fg: PALETTE.muted },
393
- );
394
- } else if (category.id === 'tools') {
395
- base.push(
396
- { 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 },
397
- { text: 'Add/update/reload and trust changes require confirmation.', fg: PALETTE.good },
398
- { text: 'Start: /mcp review, /mcp tools, /mcp config, Add MCP server.', fg: PALETTE.muted },
399
- );
400
- } else if (category.id === 'voice-media') {
401
- const readiness = snapshot.voiceMediaReadiness;
402
- base.push(
403
- { text: `Voice: ${readiness.readyVoiceProviderCount}/${snapshot.voiceProviderCount} ready; TTS ${snapshot.ttsProvider}; voice ${snapshot.ttsVoice}.`, fg: readiness.readyVoiceProviderCount > 0 ? PALETTE.good : PALETTE.warn },
404
- { text: `Media: ${readiness.readyMediaProviderCount}/${snapshot.mediaProviderCount} ready; generation ${snapshot.mediaGenerationProviderCount}.`, fg: readiness.readyMediaProviderCount > 0 ? PALETTE.good : PALETTE.warn },
405
- { text: `Browser: ${readiness.browserToolState}; public URL ${snapshot.browserToolPublicBaseUrl}.`, fg: snapshot.browserToolExposureEnabled ? PALETTE.warn : PALETTE.muted },
406
- { text: readiness.nextSteps[0] ? `Next: ${compactText(readiness.nextSteps[0])}` : 'Next: voice/media setup is ready.', fg: readiness.nextSteps.length > 0 ? PALETTE.info : PALETTE.good },
407
- { text: 'Secrets hidden; voice, browser, and media side effects require explicit action.', fg: PALETTE.warn },
408
- );
409
- } else if (category.id === 'profiles') {
410
- const defaultProfile = snapshot.selectedRuntimeProfile
411
- ? `${snapshot.selectedRuntimeProfile}${snapshot.selectedRuntimeProfileExists ? '' : ' (missing)'}`
412
- : '(base Agent home)';
413
- base.push(
414
- { text: `Profiles: active ${snapshot.activeRuntimeProfile}; default ${defaultProfile}.`, fg: snapshot.selectedRuntimeProfileExists || !snapshot.selectedRuntimeProfile ? PALETTE.info : PALETTE.warn },
415
- { text: `Local profiles: ${snapshot.runtimeProfileCount}; starters ${snapshot.runtimeStarterTemplateCount}; custom ${snapshot.localStarterTemplateCount}.`, fg: PALETTE.info },
416
- { text: `Starter ids: ${truncateDisplay(snapshot.runtimeStarterTemplates.map((template) => template.id).join(', ') || 'none', 96, '...')}`, fg: PALETTE.muted },
417
- { text: 'Profiles isolate local Agent config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
418
- );
419
- } else if (category.id === 'memory') {
420
- base.push(
421
- { text: `Memory: ${snapshot.localMemoryCount}; prompt ${snapshot.localMemoryPromptActiveCount}; queue ${snapshot.localMemoryReviewQueueCount}; session ${snapshot.sessionMemoryCount}.`, fg: PALETTE.info },
422
- { text: `Notes: ${snapshot.localNoteCount}; skills ${snapshot.localSkillCount}/${snapshot.enabledSkillCount}; routines ${snapshot.localRoutineCount}/${snapshot.enabledRoutineCount}; personas ${snapshot.localPersonaCount}.`, fg: PALETTE.info },
423
- { text: `Active persona: ${snapshot.activePersonaName}.`, fg: PALETTE.info },
424
- ...compactLocalLibraryLines('Agent Memory', snapshot.localMemories, 'Create one with Create memory.', workspace.selectedLocalLibraryItem('memory')?.id ?? null),
425
- { text: 'Secrets are rejected or redacted; use secret references.', fg: PALETTE.warn },
426
- );
427
- } else if (category.id === 'notes') {
428
- base.push(
429
- { text: `Scratchpad notes: ${snapshot.localNoteCount}; review queue: ${snapshot.localNoteReviewQueueCount}`, fg: PALETTE.info },
430
- ...compactLocalLibraryLines('Scratchpad Notes', snapshot.localNotes, 'Create one with Create note.', workspace.selectedLocalLibraryItem('note')?.id ?? null),
431
- { text: 'Notes stay local unless promoted by explicit action.', fg: PALETTE.warn },
432
- );
433
- } else if (category.id === 'personas') {
434
- base.push(
435
- { text: `Personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
436
- ...compactLocalLibraryLines('Persona Library', snapshot.localPersonas, 'Create one with Create persona.', workspace.selectedLocalLibraryItem('persona')?.id ?? null),
437
- { text: 'Personas shape the serial main-conversation assistant.', fg: PALETTE.good },
438
- );
439
- } else if (category.id === 'skills') {
440
- base.push(
441
- { text: `Skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}; bundles: ${snapshot.localSkillBundleCount}; enabled bundles: ${snapshot.enabledSkillBundleCount}; active skills: ${snapshot.activeSkillCount}`, fg: PALETTE.info },
442
- ...compactLocalLibraryLines('Skill Library', snapshot.localSkills, 'Create one with Create skill.', workspace.selectedLocalLibraryItem('skill')?.id ?? null),
443
- ...compactLocalLibraryLines('Skill Bundles', snapshot.localSkillBundles, 'Create one after adding skills.', null),
444
- { text: 'Enabled skills/bundles become operating guidance; secrets are rejected.', fg: PALETTE.warn },
445
- );
446
- } else if (category.id === 'routines') {
447
- const ready = readyRoutineItems(snapshot);
448
- const needsSetup = routinesNeedingSetup(snapshot);
449
- const needsReview = routinesNeedingReview(snapshot);
450
- base.push(
451
- { text: `Routines: ${snapshot.localRoutineCount}; enabled: ${snapshot.enabledRoutineCount}`, fg: PALETTE.info },
452
- { 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 },
453
- routineNextActionLine(snapshot),
454
- compactRoutineReceiptLine(snapshot),
455
- ...compactLocalLibraryLines('Routine Library', snapshot.localRoutines, 'Create one with Create routine.', workspace.selectedLocalLibraryItem('routine')?.id ?? null),
456
- { text: 'Scheduling requires a confirmed action.', fg: PALETTE.warn },
457
- );
458
- } else if (category.id === 'work') {
459
- base.push(
460
- { text: 'Work plans and approvals are read or explicitly confirmed.', fg: PALETTE.info },
461
- { text: 'Selection alone does not approve, deny, cancel, or mutate requests.', fg: PALETTE.good },
462
- { text: 'Approval actions require id plus typed confirmation.', fg: PALETTE.warn },
463
- );
464
- } else if (category.id === 'automation') {
465
- const ready = readyRoutineItems(snapshot);
466
- base.push(
467
- { text: `Automation: ${ready.length} schedule-ready routine(s); receipts ${snapshot.routineScheduleReceiptCount}.`, fg: ready.length > 0 ? PALETTE.good : PALETTE.warn },
468
- automationNextActionLine(snapshot),
469
- compactRoutineReceiptLine(snapshot),
470
- { text: 'Reminders and routine promotion require confirmation.', fg: PALETTE.warn },
471
- );
472
- } else if (category.id === 'delegate') {
473
- base.push(
474
- { text: 'Build/fix/review work is handed to GoodVibes TUI.', fg: PALETTE.info },
475
- { text: `Delegated review policy: ${snapshot.delegatedReviewPolicy}`, fg: PALETTE.warn },
476
- { text: 'No coding-role Agent jobs are created here.', fg: PALETTE.good },
477
- );
478
- } else if (category.id === 'finish') {
479
- base.push(
480
- { text: 'Apply & close marks onboarding finished for this user.', fg: PALETTE.good },
481
- { text: 'Future normal launches start in the main conversation.', fg: PALETTE.info },
482
- { text: 'Use /agent, /setup, or /onboarding to reopen this workspace later.', fg: PALETTE.muted },
483
- );
484
- }
485
- if (snapshot.warnings.length > 0) {
486
- base.push({ text: `Warnings: ${snapshot.warnings.map((warning) => compactText(warning, 60)).join('; ')}`, fg: PALETTE.warn });
487
- }
488
- return base;
489
- }
490
-
491
- function editorContextLines(editor: AgentWorkspaceLocalEditor): ContextLine[] {
110
+ function editorContextLines(editor: AgentWorkspaceLocalEditor, snapshot: AgentWorkspaceRuntimeSnapshot | null): ContextLine[] {
492
111
  const selected = editor.fields[editor.selectedFieldIndex];
493
112
  const lines: ContextLine[] = [
494
113
  { text: editor.title, fg: PALETTE.title, bold: true },
@@ -501,6 +120,30 @@ function editorContextLines(editor: AgentWorkspaceLocalEditor): ContextLine[] {
501
120
  { text: compactText(selected.hint), fg: PALETTE.muted },
502
121
  );
503
122
  }
123
+ lines.push(...reviewerReadinessContextLines(editor, snapshot));
124
+ if (editor.kind === 'model-compare-handoff-diff') {
125
+ const left = editor.fields.find((field) => field.id === 'leftArtifactId')?.value.trim();
126
+ const right = editor.fields.find((field) => field.id === 'rightArtifactId')?.value.trim();
127
+ lines.push(
128
+ { text: 'Split view: compare left and right reviewer handoff artifacts without changing model routing.', fg: PALETTE.good },
129
+ { text: 'Section jumps: all, metadata, policy, related, comparison.', fg: PALETTE.info },
130
+ left && right
131
+ ? { text: `Current diff: ${left} -> ${right}.`, fg: PALETTE.good }
132
+ : { text: 'No complete handoff pair selected; submitting lists recent saved handoffs.', fg: PALETTE.info },
133
+ );
134
+ if (snapshot?.recentReviewerHandoffArtifacts.length) {
135
+ const choices = snapshot.recentReviewerHandoffArtifacts
136
+ .slice(0, 4)
137
+ .map((artifact) => `${artifact.id} (${artifact.sourceKind}; related ${artifact.relatedArtifactCount})`)
138
+ .join(', ');
139
+ lines.push({ text: `Recent choices: ${choices}.`, fg: PALETTE.muted });
140
+ }
141
+ } else if (editor.kind === 'document-reviewer-readiness') {
142
+ lines.push(
143
+ { text: 'Preflight checks: comments, suggestions, source artifacts, comparison reveal, route decisions, handoff evidence.', fg: PALETTE.info },
144
+ { text: 'Use before export, handoff archive, or applying a comparison winner.', fg: PALETTE.good },
145
+ );
146
+ }
504
147
  return lines;
505
148
  }
506
149
 
@@ -518,25 +161,26 @@ function buildContextRows(workspace: AgentWorkspace, category: AgentWorkspaceCat
518
161
  },
519
162
  { text: 'Enter opens; Esc clears.', fg: PALETTE.muted },
520
163
  ] satisfies ContextLine[] : []),
521
- ...(workspace.localEditor ? editorContextLines(workspace.localEditor) : []),
164
+ ...(workspace.localEditor ? editorContextLines(workspace.localEditor, workspace.runtimeSnapshot) : []),
522
165
  ];
523
166
 
524
167
  const selectedActionLines: ContextLine[] = action
525
168
  ? [
526
169
  { text: `Selected: ${action.label}`, fg: PALETTE.title, bold: true },
527
- actionMetaLine(action),
170
+ actionMetaLine(workspace, category, action),
528
171
  ]
529
172
  : [];
530
173
  const snapshotContextLines = snapshotLines(workspace, category, workspace.runtimeSnapshot);
531
174
  lines.push(...selectedActionLines, ...snapshotContextLines);
532
175
 
176
+ const onboarding = isOnboardingCategory(category);
533
177
  if (workspace.lastActionResult) {
534
178
  lines.push(
535
- { text: 'Action Result', fg: PALETTE.title, bold: true },
179
+ { text: onboarding ? 'Result' : 'Action Result', fg: PALETTE.title, bold: true },
536
180
  { text: workspace.lastActionResult.title, fg: actionResultColor(workspace.lastActionResult), bold: true },
537
181
  { text: compactText(workspace.lastActionResult.detail), fg: PALETTE.text },
538
182
  );
539
- if (workspace.lastActionResult.command) {
183
+ if (!onboarding && workspace.lastActionResult.command) {
540
184
  lines.push({ text: `Command: ${workspace.lastActionResult.command}`, fg: PALETTE.muted });
541
185
  }
542
186
  }
@@ -602,6 +246,8 @@ function buildEditorFieldRows(editor: AgentWorkspaceLocalEditor, index: number,
602
246
 
603
247
  function buildActionRows(workspace: AgentWorkspace, width: number, height: number): WorkspaceRow[] {
604
248
  if (workspace.localEditor) return buildEditorRows(workspace.localEditor, width, height);
249
+ const category = workspace.selectedActionCategory;
250
+ const onboarding = isOnboardingCategory(category);
605
251
  const rows: WorkspaceRow[] = [];
606
252
  const labelWidth = Math.min(34, Math.max(18, Math.floor(width * 0.38)));
607
253
  const commandWidth = Math.max(10, width - labelWidth - 6);
@@ -613,7 +259,7 @@ function buildActionRows(workspace: AgentWorkspace, width: number, height: numbe
613
259
  });
614
260
  }
615
261
  rows.push({
616
- text: ` ${padDisplay(workspace.actionSearchActive ? 'Result' : 'Action', labelWidth)} ${padDisplay('Does', commandWidth)}`,
262
+ text: ` ${padDisplay(workspace.actionSearchActive ? 'Result' : onboarding ? 'Option' : 'Action', labelWidth)} ${padDisplay(onboarding ? 'Change' : 'Does', commandWidth)}`,
617
263
  fg: PALETTE.muted,
618
264
  bold: true,
619
265
  });
@@ -627,10 +273,11 @@ function buildActionRows(workspace: AgentWorkspace, width: number, height: numbe
627
273
  const action = actions[index]!;
628
274
  const selected = index === workspace.selectedActionIndex;
629
275
  const searchResult = workspace.actionSearchActive ? workspace.actionSearchResults[index] : null;
276
+ const actionCategory = searchResult?.category ?? category;
630
277
  const label = searchResult ? `${searchResult.category.label} / ${action.label}` : action.label;
631
278
  const marker = selected ? GLYPHS.navigation.selected : ' ';
632
279
  rows.push({
633
- text: `${marker} ${padDisplay(label, labelWidth)} ${padDisplay(actionCommand(action), commandWidth)}`,
280
+ text: `${marker} ${padDisplay(label, labelWidth)} ${padDisplay(actionChange(workspace, actionCategory, action), commandWidth)}`,
634
281
  selected: selected && workspace.focusPane === 'actions',
635
282
  fg: action.safety === 'blocked' ? PALETTE.warn : selected ? PALETTE.text : PALETTE.info,
636
283
  bold: selected,
@@ -642,11 +289,11 @@ function buildActionRows(workspace: AgentWorkspace, width: number, height: numbe
642
289
  rows.push({ text: `Status: ${workspace.status}`, fg: PALETTE.muted });
643
290
  if (workspace.lastActionResult) {
644
291
  rows.push({ text: '' });
645
- rows.push({ text: `Action Result: ${workspace.lastActionResult.title}`, fg: actionResultColor(workspace.lastActionResult), bold: true });
292
+ rows.push({ text: `${onboarding ? 'Result' : 'Action Result'}: ${workspace.lastActionResult.title}`, fg: actionResultColor(workspace.lastActionResult), bold: true });
646
293
  for (const line of wrapText(workspace.lastActionResult.detail, Math.max(1, width - 2))) {
647
294
  rows.push({ text: ` ${line}`, fg: PALETTE.text });
648
295
  }
649
- if (workspace.lastActionResult.command) {
296
+ if (!onboarding && workspace.lastActionResult.command) {
650
297
  rows.push({ text: ` Command: ${workspace.lastActionResult.command}`, fg: PALETTE.muted });
651
298
  }
652
299
  }
@@ -85,6 +85,18 @@ export const CATEGORY_LABELS: Record<(typeof SETTINGS_CATEGORIES)[number], strin
85
85
  helper: 'Helper',
86
86
  tts: 'TTS',
87
87
  automation: 'Automation',
88
+ service: 'Service',
89
+ controlPlane: 'Control Plane',
90
+ httpListener: 'HTTP Listener',
91
+ web: 'Web',
92
+ watchers: 'Watchers',
93
+ network: 'Network',
94
+ orchestration: 'Orchestration',
95
+ runtime: 'Runtime',
96
+ sandbox: 'Sandbox',
97
+ batch: 'Batch',
98
+ cloudflare: 'Cloudflare',
99
+ wrfc: 'WRFC',
88
100
  telemetry: 'Telemetry',
89
101
  cache: 'Cache',
90
102
  mcp: 'MCP',
@@ -34,6 +34,18 @@ const CATEGORY_INFO: Record<SettingsCategory, string> = {
34
34
  helper: 'Helper model defaults used by helper subsystems when they do not use the main chat route.',
35
35
  tts: 'Text-to-speech provider, voice, and optional spoken-turn LLM overrides.',
36
36
  automation: 'Scheduled and automated run settings, concurrency, timeout, catch-up, cooldown, and retention behavior.',
37
+ service: 'GoodVibes daemon service posture and restart/autostart preferences.',
38
+ controlPlane: 'Control-plane endpoint, stream, remote access, and TLS settings used by daemon-backed operator routes.',
39
+ httpListener: 'HTTP listener binding, trust proxy, and TLS settings for inbound companion/channel routes.',
40
+ web: 'Web companion surface settings including host, port, public URL, and static asset path.',
41
+ watchers: 'Polling watcher and heartbeat behavior for runtime recovery and periodic checks.',
42
+ network: 'Outbound TLS and remote fetch network policy.',
43
+ orchestration: 'Visible agent orchestration limits such as recursion and active-agent caps.',
44
+ runtime: 'Runtime service limits and event bus settings.',
45
+ sandbox: 'Isolation settings for REPL, MCP, and VM-backed sessions.',
46
+ batch: 'Batch queue backend, limits, and provider batching behavior.',
47
+ cloudflare: 'Cloudflare worker, tunnel, queue, storage, and token-reference settings.',
48
+ wrfc: 'WRFC review/fix chain scoring, fix attempts, and commit preferences.',
37
49
  telemetry: 'Telemetry payload policy.',
38
50
  cache: 'Provider and model cache behavior, TTL, and hit-rate monitoring.',
39
51
  mcp: 'MCP server trust and scope review. Trust changes can expose local files, tools, databases, browsers, or remote automation depending on the server.',