@pellux/goodvibes-agent 0.1.117 → 1.0.1

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 (255) hide show
  1. package/CHANGELOG.md +20 -4
  2. package/README.md +35 -14
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +176093 -171065
  5. package/docs/README.md +11 -5
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +3 -3
  8. package/docs/getting-started.md +29 -15
  9. package/docs/knowledge-artifacts-and-multimodal.md +91 -0
  10. package/docs/project-planning.md +79 -0
  11. package/docs/providers-and-routing.md +46 -0
  12. package/docs/release-and-publishing.md +44 -9
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +2 -5
  16. package/src/agent/channel-delivery.ts +201 -0
  17. package/src/agent/media-generation.ts +159 -0
  18. package/src/agent/memory-prompt.ts +0 -1
  19. package/src/agent/note-registry.ts +329 -0
  20. package/src/agent/operator-actions.ts +343 -0
  21. package/src/agent/persona-registry.ts +15 -14
  22. package/src/agent/record-labels.ts +107 -0
  23. package/src/agent/reminder-schedule-format.ts +33 -24
  24. package/src/agent/reminder-schedule.ts +26 -25
  25. package/src/agent/routine-registry.ts +13 -12
  26. package/src/agent/routine-schedule-args.ts +2 -1
  27. package/src/agent/routine-schedule-format.ts +77 -53
  28. package/src/agent/routine-schedule-promotion.ts +34 -32
  29. package/src/agent/routine-schedule-receipts.ts +28 -26
  30. package/src/agent/runtime-profile-starters.ts +2 -2
  31. package/src/agent/runtime-profile.ts +18 -17
  32. package/src/agent/skill-registry.ts +25 -24
  33. package/src/cli/agent-knowledge-args.ts +5 -1
  34. package/src/cli/agent-knowledge-command.ts +39 -33
  35. package/src/cli/agent-knowledge-format.ts +80 -67
  36. package/src/cli/agent-knowledge-methods.ts +1 -1
  37. package/src/cli/agent-knowledge-runtime.ts +32 -26
  38. package/src/cli/bundle-command.ts +13 -8
  39. package/src/cli/config-overrides.ts +37 -36
  40. package/src/cli/external-runtime.ts +10 -4
  41. package/src/cli/help.ts +29 -11
  42. package/src/cli/local-library-command.ts +159 -73
  43. package/src/cli/management-commands.ts +98 -62
  44. package/src/cli/management.ts +52 -26
  45. package/src/cli/memory-command.ts +66 -32
  46. package/src/cli/parser.ts +37 -24
  47. package/src/cli/profiles-command.ts +52 -35
  48. package/src/cli/provider-auth-routes.ts +2 -1
  49. package/src/cli/routines-command.ts +59 -39
  50. package/src/cli/service-posture.ts +6 -6
  51. package/src/cli/status.ts +46 -121
  52. package/src/core/conversation-message-snapshot.ts +131 -0
  53. package/src/input/agent-workspace-activation.ts +33 -7
  54. package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
  55. package/src/input/agent-workspace-basic-command-editors.ts +30 -10
  56. package/src/input/agent-workspace-categories.ts +276 -64
  57. package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
  58. package/src/input/agent-workspace-channel-command-editors.ts +23 -5
  59. package/src/input/agent-workspace-channels.ts +35 -2
  60. package/src/input/agent-workspace-command-editor.ts +18 -2
  61. package/src/input/agent-workspace-config-reader.ts +16 -0
  62. package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
  63. package/src/input/agent-workspace-editors.ts +140 -2
  64. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  65. package/src/input/agent-workspace-knowledge-url-editor.ts +4 -11
  66. package/src/input/agent-workspace-learned-behavior.ts +2 -2
  67. package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
  68. package/src/input/agent-workspace-library-command-editors.ts +2 -2
  69. package/src/input/agent-workspace-local-operations.ts +218 -0
  70. package/src/input/agent-workspace-local-selection.ts +75 -0
  71. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  72. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  73. package/src/input/agent-workspace-memory-command-editors.ts +1 -1
  74. package/src/input/agent-workspace-memory-editor.ts +2 -2
  75. package/src/input/agent-workspace-navigation.ts +38 -2
  76. package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
  77. package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
  78. package/src/input/agent-workspace-operations-command-editors.ts +80 -3
  79. package/src/input/agent-workspace-panel-route.ts +43 -0
  80. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  81. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  82. package/src/input/agent-workspace-search.ts +169 -0
  83. package/src/input/agent-workspace-setup.ts +22 -11
  84. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
  85. package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
  86. package/src/input/agent-workspace-snapshot.ts +112 -13
  87. package/src/input/agent-workspace-task-command-editors.ts +4 -4
  88. package/src/input/agent-workspace-token.ts +18 -2
  89. package/src/input/agent-workspace-types.ts +92 -4
  90. package/src/input/agent-workspace-voice-media.ts +3 -6
  91. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  92. package/src/input/agent-workspace.ts +136 -208
  93. package/src/input/command-registry.ts +4 -1
  94. package/src/input/commands/agent-local-library-args.ts +52 -0
  95. package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
  96. package/src/input/commands/agent-skills-runtime.ts +87 -99
  97. package/src/input/commands/agent-workspace-runtime.ts +23 -7
  98. package/src/input/commands/brief-runtime.ts +25 -24
  99. package/src/input/commands/channels-runtime.ts +145 -31
  100. package/src/input/commands/delegation-runtime.ts +29 -23
  101. package/src/input/commands/experience-runtime.ts +6 -4
  102. package/src/input/commands/guidance-runtime.ts +4 -4
  103. package/src/input/commands/health-runtime.ts +140 -115
  104. package/src/input/commands/knowledge.ts +57 -56
  105. package/src/input/commands/local-provider-runtime.ts +36 -18
  106. package/src/input/commands/local-runtime.ts +138 -16
  107. package/src/input/commands/local-setup-review.ts +7 -7
  108. package/src/input/commands/mcp-runtime.ts +118 -50
  109. package/src/input/commands/notify-runtime.ts +38 -9
  110. package/src/input/commands/operator-actions-runtime.ts +138 -0
  111. package/src/input/commands/operator-runtime.ts +6 -17
  112. package/src/input/commands/personas-runtime.ts +49 -59
  113. package/src/input/commands/planning-runtime.ts +1 -1
  114. package/src/input/commands/platform-access-runtime.ts +29 -29
  115. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  116. package/src/input/commands/qrcode-runtime.ts +45 -6
  117. package/src/input/commands/recall-bundle.ts +11 -11
  118. package/src/input/commands/recall-capture.ts +13 -11
  119. package/src/input/commands/recall-query.ts +29 -21
  120. package/src/input/commands/recall-review.ts +2 -1
  121. package/src/input/commands/routines-runtime.ts +63 -72
  122. package/src/input/commands/schedule-runtime.ts +33 -20
  123. package/src/input/commands/security-runtime.ts +4 -4
  124. package/src/input/commands/session-content.ts +80 -78
  125. package/src/input/commands/session-workflow.ts +132 -93
  126. package/src/input/commands/session.ts +3 -174
  127. package/src/input/commands/shell-core.ts +32 -17
  128. package/src/input/commands/subscription-runtime.ts +53 -179
  129. package/src/input/commands/tasks-runtime.ts +20 -20
  130. package/src/input/commands/work-plan-runtime.ts +33 -8
  131. package/src/input/commands.ts +2 -2
  132. package/src/input/feed-context-factory.ts +2 -1
  133. package/src/input/file-picker.ts +3 -2
  134. package/src/input/handler-command-route.ts +4 -7
  135. package/src/input/handler-content-actions.ts +89 -1
  136. package/src/input/handler-feed-routes.ts +19 -12
  137. package/src/input/handler-feed.ts +6 -3
  138. package/src/input/handler-interactions.ts +7 -5
  139. package/src/input/handler-modal-stack.ts +3 -3
  140. package/src/input/handler-onboarding.ts +24 -80
  141. package/src/input/handler-shortcuts.ts +15 -4
  142. package/src/input/handler.ts +47 -17
  143. package/src/input/input-history.ts +5 -6
  144. package/src/input/keybindings.ts +22 -11
  145. package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
  146. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  147. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
  148. package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
  149. package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
  150. package/src/input/onboarding/onboarding-wizard.ts +68 -0
  151. package/src/input/profile-picker-modal.ts +31 -12
  152. package/src/input/session-picker-modal.ts +22 -4
  153. package/src/input/settings-modal-behavior.ts +0 -3
  154. package/src/input/settings-modal-subscriptions.ts +3 -3
  155. package/src/input/settings-modal-types.ts +2 -13
  156. package/src/input/settings-modal.ts +6 -52
  157. package/src/input/submission-intent.ts +0 -1
  158. package/src/input/submission-router.ts +3 -3
  159. package/src/main.ts +18 -8
  160. package/src/panels/approval-panel.ts +8 -8
  161. package/src/panels/automation-control-panel.ts +2 -2
  162. package/src/panels/base-panel.ts +1 -1
  163. package/src/panels/builtin/agent.ts +1 -1
  164. package/src/panels/builtin/operations.ts +1 -10
  165. package/src/panels/builtin/session.ts +9 -9
  166. package/src/panels/builtin/shared.ts +2 -2
  167. package/src/panels/cost-tracker-panel.ts +1 -1
  168. package/src/panels/docs-panel.ts +5 -3
  169. package/src/panels/index.ts +0 -1
  170. package/src/panels/knowledge-panel.ts +6 -5
  171. package/src/panels/memory-panel.ts +7 -6
  172. package/src/panels/panel-list-panel.ts +36 -80
  173. package/src/panels/project-planning-panel.ts +18 -11
  174. package/src/panels/provider-account-snapshot.ts +51 -25
  175. package/src/panels/provider-accounts-panel.ts +33 -18
  176. package/src/panels/provider-health-domains.ts +45 -4
  177. package/src/panels/provider-health-panel.ts +5 -4
  178. package/src/panels/qr-panel.ts +1 -1
  179. package/src/panels/schedule-panel.ts +9 -17
  180. package/src/panels/security-panel.ts +8 -8
  181. package/src/panels/session-browser-panel.ts +10 -10
  182. package/src/panels/subscription-panel.ts +3 -3
  183. package/src/panels/system-messages-panel.ts +1 -1
  184. package/src/panels/tasks-panel.ts +20 -13
  185. package/src/panels/tool-inspector-panel.ts +19 -12
  186. package/src/panels/work-plan-panel.ts +5 -5
  187. package/src/planning/project-planning-coordinator.ts +1 -1
  188. package/src/provider-auth-route-display.ts +9 -0
  189. package/src/renderer/agent-workspace-style.ts +34 -0
  190. package/src/renderer/agent-workspace.ts +228 -52
  191. package/src/renderer/autocomplete-overlay.ts +25 -6
  192. package/src/renderer/bookmark-modal.ts +19 -4
  193. package/src/renderer/buffer.ts +4 -2
  194. package/src/renderer/context-inspector.ts +50 -13
  195. package/src/renderer/diff.ts +1 -1
  196. package/src/renderer/file-picker-overlay.ts +19 -6
  197. package/src/renderer/help-overlay.ts +106 -33
  198. package/src/renderer/history-search-overlay.ts +19 -4
  199. package/src/renderer/live-tail-modal.ts +27 -5
  200. package/src/renderer/mcp-workspace.ts +164 -50
  201. package/src/renderer/model-picker-overlay.ts +58 -2
  202. package/src/renderer/model-workspace.ts +104 -20
  203. package/src/renderer/process-modal.ts +27 -6
  204. package/src/renderer/profile-picker-modal.ts +20 -4
  205. package/src/renderer/search-overlay.ts +25 -5
  206. package/src/renderer/selection-modal-overlay.ts +46 -14
  207. package/src/renderer/session-picker-modal.ts +18 -1
  208. package/src/renderer/settings-modal-helpers.ts +2 -40
  209. package/src/renderer/settings-modal.ts +83 -50
  210. package/src/renderer/tool-call.ts +20 -11
  211. package/src/runtime/agent-runtime-events.ts +6 -6
  212. package/src/runtime/bootstrap-command-context.ts +7 -1
  213. package/src/runtime/bootstrap-command-parts.ts +9 -7
  214. package/src/runtime/bootstrap-core.ts +19 -1
  215. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  216. package/src/runtime/bootstrap-shell.ts +4 -4
  217. package/src/runtime/bootstrap.ts +31 -22
  218. package/src/runtime/connected-host-auth.ts +7 -2
  219. package/src/runtime/diagnostics/panels/index.ts +2 -2
  220. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  221. package/src/runtime/index.ts +2 -1
  222. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  223. package/src/runtime/onboarding/apply.ts +80 -79
  224. package/src/runtime/onboarding/derivation.ts +5 -8
  225. package/src/runtime/onboarding/snapshot.ts +0 -15
  226. package/src/runtime/onboarding/types.ts +8 -19
  227. package/src/runtime/onboarding/verify.ts +32 -10
  228. package/src/runtime/operator-token-cleanup.ts +1 -1
  229. package/src/runtime/services.ts +91 -22
  230. package/src/runtime/store/selectors/index.ts +3 -3
  231. package/src/runtime/store/state.ts +1 -4
  232. package/src/runtime/surface-feature-flags.ts +41 -6
  233. package/src/runtime/ui-read-models.ts +3 -4
  234. package/src/runtime/ui-services.ts +6 -6
  235. package/src/shell/blocking-input.ts +2 -1
  236. package/src/shell/ui-openers.ts +3 -13
  237. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  238. package/src/tools/agent-channel-send-tool.ts +133 -0
  239. package/src/tools/agent-context-policy.ts +1 -1
  240. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  241. package/src/tools/agent-knowledge-tool.ts +170 -0
  242. package/src/tools/agent-local-registry-tool.ts +269 -69
  243. package/src/tools/agent-media-generate-tool.ts +133 -0
  244. package/src/tools/agent-notify-tool.ts +143 -0
  245. package/src/tools/agent-operator-action-tool.ts +137 -0
  246. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  247. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  248. package/src/tools/agent-tool-policy-guard.ts +8 -8
  249. package/src/tools/agent-work-plan-tool.ts +256 -0
  250. package/src/version.ts +1 -1
  251. package/src/input/commands/policy-dispatch.ts +0 -339
  252. package/src/input/commands/policy.ts +0 -13
  253. package/src/panels/panel-picker.ts +0 -105
  254. package/src/panels/policy-panel.ts +0 -308
  255. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -28,6 +28,47 @@ export interface ProviderHealthDomainInputs {
28
28
  readonly session: UiSessionSnapshot;
29
29
  }
30
30
 
31
+ type ProviderHealthMcpServer = UiSecuritySnapshot['mcpServers'][number];
32
+ type ProviderHealthRemoteSession = UiRemoteSnapshot['supervisor']['sessions'][number];
33
+ type ProviderHealthStatusValue =
34
+ | ProviderHealthMcpServer['schemaFreshness']
35
+ | ProviderHealthMcpServer['trustMode']
36
+ | ProviderHealthRemoteSession['transportState']
37
+ | ProviderHealthRemoteSession['heartbeat']['status'];
38
+
39
+ function formatProviderHealthStatus(value: ProviderHealthStatusValue): string {
40
+ if (value === 'quarantined') return 'needs review';
41
+ return value.replace(/[_-]+/g, ' ');
42
+ }
43
+
44
+ function formatProviderHealthTrustMode(mode: ProviderHealthMcpServer['trustMode']): string {
45
+ if (mode === 'ask-on-risk') return 'ask on risky actions';
46
+ if (mode === 'allow-all') return 'allow all actions';
47
+ return formatProviderHealthStatus(mode);
48
+ }
49
+
50
+ function formatMcpServerDetail(server: ProviderHealthMcpServer): string {
51
+ const parts = [
52
+ `${server.name}: trust ${formatProviderHealthTrustMode(server.trustMode)}`,
53
+ `status ${formatProviderHealthStatus(server.schemaFreshness)}`,
54
+ ];
55
+ if (server.quarantineReason) {
56
+ parts.push(`review reason ${server.quarantineReason}`);
57
+ }
58
+ return parts.join('; ');
59
+ }
60
+
61
+ function formatRemoteSessionDetail(session: ProviderHealthRemoteSession): string {
62
+ const parts = [
63
+ `${session.runnerId}: transport ${formatProviderHealthStatus(session.transportState)}`,
64
+ `heartbeat ${formatProviderHealthStatus(session.heartbeat.status)}`,
65
+ ];
66
+ if (session.lastError) {
67
+ parts.push(`error ${session.lastError}`);
68
+ }
69
+ return parts.join('; ');
70
+ }
71
+
31
72
  export function buildProviderHealthDomainSummaries(
32
73
  input: ProviderHealthDomainInputs,
33
74
  ): HealthDomainSummary[] {
@@ -66,13 +107,13 @@ export function buildProviderHealthDomainSummaries(
66
107
  summary: !settings.available
67
108
  ? 'settings API unavailable'
68
109
  : settingIssueCount > 0
69
- ? `${settings.conflictCount} conflicts / ${settings.recentFailureCount} failures${settings.hasStagedManagedBundle ? ' / staged bundle' : ''}`
110
+ ? `${settings.conflictCount} conflicts / ${settings.recentFailureCount} failures${settings.hasStagedManagedBundle ? ' / pending managed bundle' : ''}`
70
111
  : 'settings API clean',
71
112
  next: settingIssueCount > 0 ? '/settings' : '/config <key>',
72
113
  details: [
73
114
  settings.conflictCount > 0 ? `${settings.conflictCount} unresolved import conflict(s)` : '',
74
115
  settings.recentFailureCount > 0 ? `${settings.recentFailureCount} recent sync or managed failure(s)` : '',
75
- settings.hasStagedManagedBundle ? 'staged managed bundle awaits apply or rollback' : '',
116
+ settings.hasStagedManagedBundle ? 'pending managed settings bundle awaits apply or rollback' : '',
76
117
  settings.managedLockCount > 0 ? `${settings.managedLockCount} managed lock(s) enforced` : '',
77
118
  ].filter(Boolean),
78
119
  nextSteps: settingIssueCount > 0
@@ -97,7 +138,7 @@ export function buildProviderHealthDomainSummaries(
97
138
  || entry.heartbeat.status !== 'fresh'
98
139
  || Boolean(entry.lastError))
99
140
  .slice(0, 3)
100
- .map((entry) => `${entry.runnerId}: transport=${entry.transportState} heartbeat=${entry.heartbeat.status}${entry.lastError ? ` error=${entry.lastError}` : ''}`),
141
+ .map(formatRemoteSessionDetail),
101
142
  nextSteps: remote.supervisor.degradedConnections > 0
102
143
  ? ['/delegate <build/fix/review task>', '/health remote']
103
144
  : ['/health remote'],
@@ -120,7 +161,7 @@ export function buildProviderHealthDomainSummaries(
120
161
  ? (security.mcpServers.length === 0 ? ['no MCP servers registered'] : ['all MCP servers are healthy'])
121
162
  : degradedServers
122
163
  .slice(0, 3)
123
- .map((server) => `${server.name}: trust=${server.trustMode} schema=${server.schemaFreshness}${server.quarantineReason ? ` quarantine=${server.quarantineReason}` : ''}`),
164
+ .map(formatMcpServerDetail),
124
165
  nextSteps: degradedServers.length > 0
125
166
  ? ['/mcp review', '/mcp auth-review', '/mcp repair']
126
167
  : ['/mcp review'],
@@ -37,6 +37,7 @@ import {
37
37
  resolvePrimaryScrollableSection,
38
38
  type PanelWorkspaceSection,
39
39
  } from './polish.ts';
40
+ import { formatProviderAuthRouteId } from '../provider-auth-route-display.ts';
40
41
 
41
42
  // ---------------------------------------------------------------------------
42
43
  // Types
@@ -646,17 +647,17 @@ export class ProviderHealthPanel extends BasePanel {
646
647
  }
647
648
  if (selectedAccount) {
648
649
  selectedLines.push(buildKeyValueLine(width, [
649
- { label: 'route', value: selectedAccount.activeRoute, valueColor: routeColor(selectedAccount.activeRoute) },
650
- { label: 'preferred', value: selectedAccount.preferredRoute, valueColor: C.dim },
650
+ { label: 'route', value: formatProviderAuthRouteId(selectedAccount.activeRoute), valueColor: routeColor(selectedAccount.activeRoute) },
651
+ { label: 'preferred', value: formatProviderAuthRouteId(selectedAccount.preferredRoute), valueColor: C.dim },
651
652
  { label: 'freshness', value: selectedAccount.authFreshness, valueColor: freshnessColor(selectedAccount.authFreshness) },
652
653
  ], { ...DEFAULT_PANEL_PALETTE, header: C.title, headerBg: '#0f172a' }));
653
654
  selectedLines.push(buildKeyValueLine(width, [
654
655
  { label: 'models', value: String(selectedAccount.modelCount), valueColor: C.value },
655
656
  { label: 'active', value: selectedAccount.active ? 'yes' : 'no', valueColor: selectedAccount.active ? C.online : C.dim },
656
657
  ], { ...DEFAULT_PANEL_PALETTE, header: C.title, headerBg: '#0f172a' }));
657
- selectedLines.push(...buildBodyText(width, `Auth route: ${selectedAccount.activeRouteReason}`, { ...DEFAULT_PANEL_PALETTE, header: C.title, headerBg: '#0f172a' }, C.dim));
658
+ selectedLines.push(...buildBodyText(width, `Route reason: ${selectedAccount.activeRouteReason}`, { ...DEFAULT_PANEL_PALETTE, header: C.title, headerBg: '#0f172a' }, C.dim));
658
659
  if (selectedAccount.fallbackRisk) {
659
- selectedLines.push(...buildBodyText(width, `Fallback: ${selectedAccount.fallbackRisk}`, { ...DEFAULT_PANEL_PALETTE, header: C.title, headerBg: '#0f172a' }, C.rateLimit));
660
+ selectedLines.push(...buildBodyText(width, `Routing risk: ${selectedAccount.fallbackRisk}`, { ...DEFAULT_PANEL_PALETTE, header: C.title, headerBg: '#0f172a' }, C.rateLimit));
660
661
  }
661
662
  if (selectedAccount.issues.length > 0) {
662
663
  selectedLines.push(...buildBodyText(width, `Issue: ${selectedAccount.issues[0]!}`, { ...DEFAULT_PANEL_PALETTE, header: C.title, headerBg: '#0f172a' }, C.errMsg));
@@ -163,7 +163,7 @@ export class QrPanel extends BasePanel {
163
163
  );
164
164
  lines.push(
165
165
  buildPanelLine(width, [
166
- [' Start or repair the owning GoodVibes host, then reopen this panel. ', C.dim],
166
+ [' Provision or repair connected-host access through the owning GoodVibes host, then reopen this panel. ', C.dim],
167
167
  ]),
168
168
  );
169
169
  }
@@ -80,14 +80,13 @@ function formatEveryInterval(intervalMs: number): string {
80
80
  // ---------------------------------------------------------------------------
81
81
 
82
82
  /**
83
- * SchedulePanel — displays all scheduled tasks with next run time,
84
- * enable/disable toggle, and run history.
83
+ * SchedulePanel — displays connected schedule posture with next run time and run history.
84
+ * It does not create, enable, disable, or run schedules from panel keypresses.
85
85
  */
86
86
  export class SchedulePanel extends BasePanel {
87
87
  private items: ViewItem[] = [];
88
88
  private selectedIndex = 0;
89
89
  private scrollOffset = 0;
90
- private refreshTimerId: ReturnType<typeof setInterval> | null = null;
91
90
  private readonly automationManager: ScheduleAutomationManager;
92
91
 
93
92
  constructor(automationManager: ScheduleAutomationManager) {
@@ -102,17 +101,10 @@ export class SchedulePanel extends BasePanel {
102
101
  override onActivate(): void {
103
102
  super.onActivate();
104
103
  this.rebuild();
105
- this.refreshTimerId = this.registerTimer(setInterval(() => {
106
- this.rebuild();
107
- this.markDirty();
108
- }, 5_000));
109
104
  }
110
105
 
111
106
  override onDeactivate(): void {
112
- if (this.refreshTimerId !== null) {
113
- this.clearTimer(this.refreshTimerId);
114
- this.refreshTimerId = null;
115
- }
107
+ this.scrollOffset = 0;
116
108
  }
117
109
 
118
110
  override onDestroy(): void {
@@ -171,11 +163,11 @@ export class SchedulePanel extends BasePanel {
171
163
  }
172
164
  case 'return':
173
165
  case ' ': {
174
- this.setError('Schedule mutation is read-only in GoodVibes Agent; use explicit runtime approval routes later.');
166
+ this.setError('Schedule mutation is read-only in GoodVibes Agent. Schedule changes require an exact command with --yes; panel keypresses never mutate connected schedules.');
175
167
  return true;
176
168
  }
177
169
  case 'r': {
178
- this.setError('Schedule run is blocked in GoodVibes Agent; local automation spawns are disabled.');
170
+ this.setError('Schedule run is blocked in GoodVibes Agent. Use /schedule run <schedule-id> --yes only when you explicitly want to run that connected schedule.');
179
171
  return true;
180
172
  }
181
173
  case 'R': {
@@ -205,7 +197,7 @@ export class SchedulePanel extends BasePanel {
205
197
  lines: buildEmptyState(
206
198
  width,
207
199
  ' No scheduled tasks',
208
- 'Schedule mutation and run controls are blocked in GoodVibes Agent. Use /schedule list for read-only history.',
200
+ 'Schedule mutation and run controls are blocked. Use /schedule list for read-only history, or exact --yes commands for connected schedule actions.',
209
201
  [],
210
202
  DEFAULT_PANEL_PALETTE,
211
203
  ),
@@ -213,7 +205,7 @@ export class SchedulePanel extends BasePanel {
213
205
  ],
214
206
  footerLines: [
215
207
  ...(this.renderErrorLine(width) ? [this.renderErrorLine(width)!] : []),
216
- buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' mutation/run blocked', DEFAULT_PANEL_PALETTE.warn]]),
208
+ buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' no keypress mutations', DEFAULT_PANEL_PALETTE.warn]]),
217
209
  ],
218
210
  palette: DEFAULT_PANEL_PALETTE,
219
211
  });
@@ -236,7 +228,7 @@ export class SchedulePanel extends BasePanel {
236
228
  intro: 'Review recurring scheduled tasks, next run timing, recent history, and enablement state.',
237
229
  footerLines: [
238
230
  ...(this.renderErrorLine(width) ? [this.renderErrorLine(width)!] : []),
239
- buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' mutation/run blocked', DEFAULT_PANEL_PALETTE.warn]]),
231
+ buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' no keypress mutations', DEFAULT_PANEL_PALETTE.warn]]),
240
232
  ],
241
233
  palette: DEFAULT_PANEL_PALETTE,
242
234
  beforeSections: [summarySection],
@@ -260,7 +252,7 @@ export class SchedulePanel extends BasePanel {
260
252
  sections,
261
253
  footerLines: [
262
254
  ...(this.renderErrorLine(width) ? [this.renderErrorLine(width)!] : []),
263
- buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' mutation/run blocked', DEFAULT_PANEL_PALETTE.warn]]),
255
+ buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' no keypress mutations', DEFAULT_PANEL_PALETTE.warn]]),
264
256
  ],
265
257
  palette: DEFAULT_PANEL_PALETTE,
266
258
  });
@@ -71,12 +71,12 @@ export class SecurityPanel extends ScrollableListPanel<TokenAuditResult> {
71
71
  }
72
72
 
73
73
  protected override getPalette() { return C; }
74
- protected override getEmptyStateMessage() { return ' No API tokens are registered with the security auditor yet.'; }
74
+ protected override getEmptyStateMessage() { return ' No API tokens are registered for security review yet.'; }
75
75
  protected override getEmptyStateActions() {
76
76
  return [
77
- { command: '/storage review', summary: 'inspect secure secret storage and environment overrides' },
78
- { command: '/policy preflight', summary: 'run a live preflight posture review' },
79
- { command: '/mcp trust', summary: 'inspect active MCP trust and quarantine posture' },
77
+ { command: '/secrets list', summary: 'inspect stored secret references without printing values' },
78
+ { command: '/security review', summary: 'review token, policy, MCP, plugin, and incident posture' },
79
+ { command: '/mcp auth-review', summary: 'inspect active MCP trust and quarantine posture' },
80
80
  ];
81
81
  }
82
82
 
@@ -117,8 +117,8 @@ export class SecurityPanel extends ScrollableListPanel<TokenAuditResult> {
117
117
  const quarantinedPlugins = snapshot.quarantinedPlugins;
118
118
  const untrustedPlugins = snapshot.untrustedPlugins;
119
119
  const attackPathReview = snapshot.attackPathReview;
120
- const intro = 'Token audit, policy posture, MCP attack-path review, plugin trust, and incident pressure.';
121
- const footerLine = buildGuidanceLine(width, '/policy preflight', 'run a proactive policy review before risky work starts', C);
120
+ const intro = 'Token review, policy posture, MCP attack-path review, plugin trust, and incident pressure.';
121
+ const footerLine = buildGuidanceLine(width, '/security review', 'review proactive policy posture before risky work starts', C);
122
122
 
123
123
  const governanceLines: Line[] = [
124
124
  buildPanelLine(width, [
@@ -179,7 +179,7 @@ export class SecurityPanel extends ScrollableListPanel<TokenAuditResult> {
179
179
  ...buildEmptyState(
180
180
  width,
181
181
  this.getEmptyStateMessage(),
182
- 'The security control room can already review policy, MCP, plugin, and incident posture, but token-specific scope and rotation audit data has not been registered.',
182
+ 'The security control room can already review policy, MCP, plugin, and incident posture, but token-specific scope and rotation data has not been registered.',
183
183
  this.getEmptyStateActions(),
184
184
  C,
185
185
  ),
@@ -245,7 +245,7 @@ export class SecurityPanel extends ScrollableListPanel<TokenAuditResult> {
245
245
  [String(Math.floor(selected.rotation.ageMs / (24 * 60 * 60 * 1000))), C.value],
246
246
  ]));
247
247
  detailLines.push(buildPanelLine(width, [[
248
- `Last audit: ${view.lastAuditAt ? new Date(view.lastAuditAt).toISOString() : 'never'} Press r to refresh.`,
248
+ `Last review: ${view.lastAuditAt ? new Date(view.lastAuditAt).toISOString() : 'never'} Press r to refresh.`,
249
249
  C.dim,
250
250
  ]]));
251
251
  if (preflightStatus !== 'n/a') {
@@ -63,13 +63,13 @@ function formatReturnContextLines(returnContext: SessionInfo['returnContext']):
63
63
  if (returnContext.activityLabel) lines.push(`activity: ${returnContext.activityLabel}`);
64
64
  if (returnContext.statusLabel) lines.push(`status: ${returnContext.statusLabel}`);
65
65
  if (returnContext.activeTasks || returnContext.blockedTasks || returnContext.pendingApprovals) {
66
- lines.push(`tasks: active=${returnContext.activeTasks ?? 0} blocked=${returnContext.blockedTasks ?? 0} approvals=${returnContext.pendingApprovals ?? 0}`);
66
+ lines.push(`tasks: active ${returnContext.activeTasks ?? 0}; blocked ${returnContext.blockedTasks ?? 0}; approvals ${returnContext.pendingApprovals ?? 0}`);
67
67
  }
68
68
  if (returnContext.remoteRunners?.length) {
69
- lines.push(`remote workers: ${returnContext.remoteRunners.join(', ')}`);
69
+ lines.push(`remote build hosts: ${returnContext.remoteRunners.join(', ')}`);
70
70
  }
71
71
  if (returnContext.openPanels?.length) {
72
- lines.push(`open panels: ${returnContext.openPanels.join(', ')}`);
72
+ lines.push(`saved panels ignored: ${returnContext.openPanels.join(', ')}`);
73
73
  }
74
74
  return lines;
75
75
  }
@@ -177,14 +177,14 @@ export class SessionBrowserPanel extends BasePanel {
177
177
  const count = this.filtered.length;
178
178
  const total = this.sessions.length;
179
179
  const searchLine = this.searching
180
- ? ` Search: ${this.searchQuery}_`
180
+ ? ` Search ${this.searchQuery}_`
181
181
  : this.loadError
182
- ? ` Error: ${this.loadError}`
182
+ ? ` Error ${this.loadError}`
183
183
  : this.deleteError
184
- ? ` Error: ${this.deleteError}`
184
+ ? ` Error ${this.deleteError}`
185
185
  : this.searchQuery
186
- ? ` Filter: ${this.searchQuery} (/ or up at top to edit)`
187
- : ` / or up at top to search Enter: resume d: delete r: refresh`;
186
+ ? ` Filter ${this.searchQuery} (/ or up at top to edit)`
187
+ : ` / or up at top to search Enter resume d delete r refresh`;
188
188
  const statusFg = this.loadError || this.deleteError ? DEFAULT_PANEL_PALETTE.bad : this.searching ? DEFAULT_PANEL_PALETTE.info : DEFAULT_PANEL_PALETTE.dim;
189
189
  const footerLines = [
190
190
  buildSearchInputLine(width, '', searchLine.trimStart(), DEFAULT_PANEL_PALETTE, { active: this.searching, valueColor: statusFg }),
@@ -260,8 +260,8 @@ export class SessionBrowserPanel extends BasePanel {
260
260
  buildPanelLine(width, [
261
261
  [' Remote ', DEFAULT_PANEL_PALETTE.label],
262
262
  [String(selected.returnContext?.remoteRunners?.length ?? 0), (selected.returnContext?.remoteRunners?.length ?? 0) > 0 ? DEFAULT_PANEL_PALETTE.info : DEFAULT_PANEL_PALETTE.dim],
263
- [' Panels ', DEFAULT_PANEL_PALETTE.label],
264
- [String(selected.returnContext?.openPanels?.length ?? 0), (selected.returnContext?.openPanels?.length ?? 0) > 0 ? DEFAULT_PANEL_PALETTE.good : DEFAULT_PANEL_PALETTE.dim],
263
+ [' Saved Panels ', DEFAULT_PANEL_PALETTE.label],
264
+ [String(selected.returnContext?.openPanels?.length ?? 0), (selected.returnContext?.openPanels?.length ?? 0) > 0 ? DEFAULT_PANEL_PALETTE.warn : DEFAULT_PANEL_PALETTE.dim],
265
265
  ]),
266
266
  ...formatReturnContextLines(selected.returnContext).map((line) =>
267
267
  buildPanelLine(width, [[' ', DEFAULT_PANEL_PALETTE.dim], [truncateDisplay(line, Math.max(0, width - 2)), DEFAULT_PANEL_PALETTE.dim]])
@@ -172,7 +172,7 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
172
172
  public render(width: number, height: number): Line[] {
173
173
  this.refresh();
174
174
  this.clampSelection();
175
- const intro = 'Review provider login state, subscription-backed routing, and pending browser auth handshakes.';
175
+ const intro = 'Review provider login state, subscription-backed routing, and pending browser sign-ins.';
176
176
 
177
177
  const activeCount = this.rows.filter((row) => row.subscription).length;
178
178
  const pendingCount = this.rows.filter((row) => row.pending).length;
@@ -187,7 +187,7 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
187
187
  { label: 'selected', value: (this.rows[this.selectedIndex]?.provider ?? 'none'), valueColor: this.rows[this.selectedIndex] ? C.value : C.dim },
188
188
  { label: 'status', value: this.rows[this.selectedIndex] ? statusOf(this.rows[this.selectedIndex]!) : 'n/a', valueColor: this.rows[this.selectedIndex] ? statusColor(statusOf(this.rows[this.selectedIndex]!)) : C.dim },
189
189
  ], C),
190
- buildGuidanceLine(width, '/subscription login <provider> start --yes', 'start or repair browser login for the selected provider route', C),
190
+ buildGuidanceLine(width, '/subscription login <provider> start --yes', 'start browser login, then finish manually with the callback code or URL', C),
191
191
  ];
192
192
 
193
193
  // Empty state: render posture + base empty state
@@ -205,7 +205,7 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
205
205
  intro,
206
206
  sections: [{ lines: [...summaryLines, ...emptyLines] }],
207
207
  footerLines: [
208
- buildGuidanceLine(width, '/subscription login <provider> start --yes', 'start browser-based provider login from the packaged subscription flow', C),
208
+ buildGuidanceLine(width, '/subscription login <provider> start --yes', 'start browser login, then finish explicitly from the Agent command or workspace form', C),
209
209
  buildPanelLine(width, [[' Up/Down move Enter/X sign out selected provider r refresh', C.dim]]),
210
210
  ],
211
211
  palette: C,
@@ -145,7 +145,7 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
145
145
  'Model switches, scan notices, provider/system state, and other operational updates will appear here once the runtime starts emitting them.',
146
146
  [
147
147
  { command: '/help', summary: 'review commands and operator workflows' },
148
- { command: '/cockpit', summary: 'open the unified runtime control room' },
148
+ { command: '/agent', summary: 'open the Agent operator workspace' },
149
149
  ],
150
150
  C,
151
151
  ),
@@ -46,16 +46,23 @@ function formatDuration(startedAt?: number, endedAt?: number): string {
46
46
  function kindLabel(kind: RuntimeTask['kind']): string {
47
47
  switch (kind) {
48
48
  case 'exec': return 'exec';
49
- case 'agent': return 'agent';
50
- case 'acp': return 'acp';
49
+ case 'agent': return 'task';
50
+ case 'acp': return 'delegate';
51
51
  case 'scheduler': return 'scheduler';
52
- case 'daemon': return 'daemon';
52
+ case 'daemon': return 'host';
53
53
  case 'mcp': return 'mcp';
54
54
  case 'plugin': return 'plugin';
55
55
  case 'integration': return 'integration';
56
56
  }
57
57
  }
58
58
 
59
+ function descriptorOriginLabel(source: string | undefined): string {
60
+ const normalized = source?.trim();
61
+ if (!normalized || normalized === 'builtin/runtime') return 'runtime';
62
+ if (normalized === 'daemon' || normalized === 'daemon-runtime') return 'host';
63
+ return normalized.replace(/[-_/]+/g, ' ');
64
+ }
65
+
59
66
  function statusColor(status: TaskLifecycleState): string {
60
67
  switch (status) {
61
68
  case 'queued':
@@ -137,7 +144,7 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
137
144
  protected override getEmptyStateMessage() { return ' No tasks recorded yet.'; }
138
145
  protected override getEmptyStateActions() {
139
146
  return [
140
- { command: '/tasks create', summary: 'create a tracked task from the shell' },
147
+ { command: '/workplan', summary: 'track visible Agent work in the workspace' },
141
148
  { command: '/delegate <task>', summary: 'send explicit build/fix/review work to GoodVibes TUI' },
142
149
  ];
143
150
  }
@@ -173,7 +180,7 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
173
180
 
174
181
  public render(width: number, height: number): Line[] {
175
182
  this.clampSelection();
176
- const intro = 'Live task lifecycle, ownership, retries, and result/error details across runtime execution domains.';
183
+ const intro = 'Connected-host task lifecycle, ownership, retries, and result/error details for operator visibility.';
177
184
  const footerLines = [buildPanelLine(width, [[' Up/Down move Home/End jump', C.dim]])];
178
185
 
179
186
  if (!this.readModel) {
@@ -184,8 +191,8 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
184
191
  lines: buildEmptyState(
185
192
  width,
186
193
  ' Connected-host task state is unavailable.',
187
- 'Use /tasks list for the supported Agent task summary. This deferred panel does not start or mutate task execution.',
188
- [{ command: '/tasks', summary: 'inspect connected-host tasks without launching local workers' }],
194
+ 'This operator view is read-only. Use /tasks list for compact transcript output; task execution stays unchanged.',
195
+ [{ command: '/tasks', summary: 'review connected-host tasks without changing execution' }],
189
196
  C,
190
197
  ),
191
198
  }],
@@ -229,13 +236,13 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
229
236
  [' status ', C.label],
230
237
  [selected.status, statusColor(selected.status)],
231
238
  [' kind ', C.label],
232
- [selected.kind, C.value],
239
+ [kindLabel(selected.kind), C.value],
233
240
  [' owner ', C.label],
234
241
  [selected.owner.slice(0, Math.max(0, width - 46)), C.dim],
235
242
  ]));
236
243
  }
237
244
  postureLines.push(
238
- buildGuidanceLine(width, '/tasks', 'inspect connected-host task posture without launching local workers', C),
245
+ buildGuidanceLine(width, '/tasks', 'review connected-host task posture without changing execution', C),
239
246
  buildGuidanceLine(width, '/delegate <task>', 'delegate explicit build/fix/review work to GoodVibes TUI when code execution is required', C),
240
247
  );
241
248
 
@@ -248,7 +255,7 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
248
255
  [' Status: ', C.label],
249
256
  [selected.status, statusColor(selected.status)],
250
257
  [' Kind: ', C.label],
251
- [selected.kind, C.value],
258
+ [kindLabel(selected.kind), C.value],
252
259
  ]));
253
260
  detailRows.push(buildPanelLine(width, [
254
261
  [' Owner: ', C.label],
@@ -272,8 +279,8 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
272
279
  [descriptor?.mode ?? 'n/a', C.value],
273
280
  [' Family: ', C.label],
274
281
  [descriptor?.family ?? 'n/a', C.info],
275
- [' Source: ', C.label],
276
- [descriptor?.source ?? 'builtin/runtime', C.dim],
282
+ [' Origin: ', C.label],
283
+ [descriptorOriginLabel(descriptor?.source), C.dim],
277
284
  ]));
278
285
  }
279
286
  if (descriptor?.reviewMode || descriptor?.executionProtocol || descriptor?.template) {
@@ -310,7 +317,7 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
310
317
  }
311
318
  if (selected.error) {
312
319
  detailRows.push(buildPanelLine(width, [
313
- [' Error: ', C.label],
320
+ [' Error ', C.label],
314
321
  [selected.error.slice(0, Math.max(0, width - 10)), C.failed],
315
322
  ]));
316
323
  }
@@ -74,17 +74,24 @@ function truncateJson(val: unknown, maxLen = 120): string {
74
74
  return s.length > maxLen ? s.slice(0, maxLen - 1) + '\u2026' : s;
75
75
  }
76
76
 
77
+ function isResultSummaryRecord(value: unknown): value is {
78
+ readonly preview?: unknown;
79
+ readonly kind?: unknown;
80
+ readonly byteSize?: unknown;
81
+ } {
82
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
83
+ }
84
+
77
85
  function summarizeResult(result: unknown): string | undefined {
78
86
  // SDK OBS-05 (0.21.31+): TOOL_SUCCEEDED/TOOL_FAILED.result is a ToolResultSummary
79
87
  // { kind: 'text' | 'json' | 'binary' | 'error' | 'empty'; byteSize: number; preview?: string }.
80
- if (!result || typeof result !== 'object') return undefined;
81
- const record = result as Record<string, unknown>;
82
- if (typeof record.preview === 'string' && record.preview.trim()) {
83
- const compact = record.preview.replace(/\s+/g, ' ').trim();
88
+ if (!isResultSummaryRecord(result)) return undefined;
89
+ if (typeof result.preview === 'string' && result.preview.trim()) {
90
+ const compact = result.preview.replace(/\s+/g, ' ').trim();
84
91
  return compact.length > 72 ? `${compact.slice(0, 69)}\u2026` : compact;
85
92
  }
86
- if (typeof record.kind === 'string' && typeof record.byteSize === 'number') {
87
- return `${record.kind} (${record.byteSize}B)`;
93
+ if (typeof result.kind === 'string' && typeof result.byteSize === 'number') {
94
+ return `${result.kind} (${result.byteSize}B)`;
88
95
  }
89
96
  return undefined;
90
97
  }
@@ -303,23 +310,23 @@ export class ToolInspectorPanel extends BasePanel {
303
310
 
304
311
  if (rec.expanded) {
305
312
  const argsStr = truncateJson(rec.args, 200);
306
- flat.push({ kind: 'detail', text: `Args: ${argsStr}`, isError: false });
307
- flat.push({ kind: 'detail', text: `Risk: ${risk}${rec.approved === undefined ? '' : ` Approved: ${rec.approved ? 'yes' : 'no'}`}`, isError: false });
313
+ flat.push({ kind: 'detail', text: `Args ${argsStr}`, isError: false });
314
+ flat.push({ kind: 'detail', text: `Risk ${risk}${rec.approved === undefined ? '' : ` Approved ${rec.approved ? 'yes' : 'no'}`}`, isError: false });
308
315
  if (rec.policyAction || rec.spillBackend) {
309
316
  flat.push({
310
317
  kind: 'detail',
311
- text: `Output policy: ${rec.policyAction ?? 'none'}${rec.spillBackend ? ` Spill: ${rec.spillBackend}` : ''}`,
318
+ text: `Output policy ${rec.policyAction ?? 'none'}${rec.spillBackend ? ` Spill ${rec.spillBackend}` : ''}`,
312
319
  isError: false,
313
320
  });
314
321
  }
315
322
  if (rec.resultSummary) {
316
- flat.push({ kind: 'detail', text: `Summary: ${rec.resultSummary}`, isError: false });
323
+ flat.push({ kind: 'detail', text: `Summary ${rec.resultSummary}`, isError: false });
317
324
  }
318
325
  if (rec.result !== undefined) {
319
- flat.push({ kind: 'detail', text: `Result: ${truncateJson(rec.result, 200)}`, isError: false });
326
+ flat.push({ kind: 'detail', text: `Result ${truncateJson(rec.result, 200)}`, isError: false });
320
327
  }
321
328
  if (rec.error) {
322
- flat.push({ kind: 'detail', text: `Error: ${rec.error}`, isError: true });
329
+ flat.push({ kind: 'detail', text: `Error ${rec.error}`, isError: true });
323
330
  }
324
331
  }
325
332
  }
@@ -151,18 +151,18 @@ export class WorkPlanPanel extends ScrollableListPanel<WorkPlanItem> {
151
151
  const active = this.items[this.selectedIndex];
152
152
  const header = [
153
153
  line(`Persistent Work Plan`, width, { fg: '#22d3ee', bold: true }),
154
- line(`Project: ${plan.projectRoot}`, width, { fg: '#cbd5e1' }),
154
+ line(`Project ${plan.projectRoot}`, width, { fg: '#cbd5e1' }),
155
155
  line(
156
- `Items: ${plan.items.length} pending ${counts.get('pending') ?? 0} active ${counts.get('in_progress') ?? 0} blocked ${counts.get('blocked') ?? 0} done ${counts.get('done') ?? 0}`,
156
+ `Items ${plan.items.length} pending ${counts.get('pending') ?? 0} active ${counts.get('in_progress') ?? 0} blocked ${counts.get('blocked') ?? 0} done ${counts.get('done') ?? 0}`,
157
157
  width,
158
158
  { fg: '#94a3b8' },
159
159
  ),
160
- line(`Saved: ${this.store.filePath}`, width, { fg: '#64748b' }),
160
+ line(`Saved ${this.store.filePath}`, width, { fg: '#64748b' }),
161
161
  ];
162
162
  if (active) {
163
163
  header.push(line('', width));
164
- header.push(line(`Selected: ${active.id} ${statusName(active.status)} updated ${compactDate(active.updatedAt)}`, width, { fg: '#a5b4fc' }));
165
- if (active.notes) header.push(line(`Notes: ${active.notes}`, width, { fg: '#cbd5e1' }));
164
+ header.push(line(`Selected ${active.id} ${statusName(active.status)} updated ${compactDate(active.updatedAt)}`, width, { fg: '#a5b4fc' }));
165
+ if (active.notes) header.push(line(`Notes ${active.notes}`, width, { fg: '#cbd5e1' }));
166
166
  }
167
167
  return header;
168
168
  }
@@ -472,7 +472,7 @@ export class ProjectPlanningCoordinator {
472
472
 
473
473
  return [
474
474
  'Agent-owned planning loop is active for this turn.',
475
- 'Do not execute code changes, spawn agents, or claim implementation is complete unless the user explicitly approves execution after the plan is structurally ready.',
475
+ 'Do not execute code changes, create separate Agent jobs, or claim implementation is complete unless the user explicitly approves execution after the plan is structurally ready.',
476
476
  'Be relentless and thorough: challenge vague wording, inspect relevant context before proposing execution, and ask exactly one focused question when information is missing.',
477
477
  'Do not ask broad questions like "what is in scope?" without examples. Break broad planning gaps into concrete choices, explain tradeoffs, and recommend a default the user can accept or correct.',
478
478
  '',
@@ -0,0 +1,9 @@
1
+ export function formatProviderAuthRouteId(route: string): string {
2
+ return route === 'service-oauth' ? 'provider-oauth' : route;
3
+ }
4
+
5
+ export function formatProviderAuthRouteLabel(route: string, label?: string): string {
6
+ if (route === 'service-oauth') return 'Provider OAuth';
7
+ const trimmed = label?.trim();
8
+ return trimmed && trimmed.length > 0 ? trimmed : formatProviderAuthRouteId(route);
9
+ }
@@ -0,0 +1,34 @@
1
+ import type {
2
+ AgentWorkspaceAction,
3
+ AgentWorkspaceActionResult,
4
+ AgentWorkspaceRuntimeSnapshot,
5
+ } from '../input/agent-workspace.ts';
6
+ import { WORKSPACE_PALETTE as PALETTE } from './fullscreen-workspace.ts';
7
+
8
+ export type AgentWorkspaceContextLine = {
9
+ readonly text: string;
10
+ readonly fg?: string;
11
+ readonly bold?: boolean;
12
+ readonly dim?: boolean;
13
+ };
14
+
15
+ export function safetyColor(action: AgentWorkspaceAction): string {
16
+ if (action.safety === 'safe') return PALETTE.good;
17
+ if (action.safety === 'read-only') return PALETTE.info;
18
+ if (action.safety === 'delegates') return PALETTE.warn;
19
+ return PALETTE.bad;
20
+ }
21
+
22
+ export function actionResultColor(result: AgentWorkspaceActionResult): string {
23
+ if (result.kind === 'blocked' || result.kind === 'error') return PALETTE.bad;
24
+ if (result.kind === 'dispatched') return PALETTE.info;
25
+ if (result.kind === 'refreshed') return PALETTE.good;
26
+ return PALETTE.muted;
27
+ }
28
+
29
+ export function setupStatusColor(status: AgentWorkspaceRuntimeSnapshot['setupChecklist'][number]['status']): string {
30
+ if (status === 'ready') return PALETTE.good;
31
+ if (status === 'recommended') return PALETTE.warn;
32
+ if (status === 'blocked') return PALETTE.bad;
33
+ return PALETTE.muted;
34
+ }