@pellux/goodvibes-agent 1.5.5 → 1.5.6

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 (165) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +1 -1
  3. package/dist/package/main.js +94130 -79335
  4. package/docs/tools-and-commands.md +2 -1
  5. package/package.json +6 -3
  6. package/src/agent/autonomy-schedule-format.ts +1 -1
  7. package/src/agent/autonomy-schedule.ts +3 -3
  8. package/src/agent/calendar/calendar-oauth-service.ts +324 -0
  9. package/src/agent/calendar-subscription-registry.ts +497 -0
  10. package/src/agent/email/email-service.ts +57 -0
  11. package/src/agent/email/smtp-client.ts +30 -10
  12. package/src/agent/memory-prompt.ts +143 -12
  13. package/src/agent/operator-actions.ts +26 -22
  14. package/src/agent/prompt-context-receipts.ts +45 -18
  15. package/src/agent/reminder-schedule-format.ts +1 -1
  16. package/src/agent/reminder-schedule.ts +3 -3
  17. package/src/agent/routine-schedule-format.ts +2 -2
  18. package/src/agent/routine-schedule-promotion.ts +5 -5
  19. package/src/agent/routine-schedule-receipts.ts +2 -2
  20. package/src/agent/schedule-edit-format.ts +1 -1
  21. package/src/agent/schedule-edit.ts +5 -5
  22. package/src/agent/session-registration.ts +281 -0
  23. package/src/agent/vibe-file.ts +50 -0
  24. package/src/cli/local-library-command-shared.ts +146 -0
  25. package/src/cli/management.ts +2 -1
  26. package/src/cli/personas-command.ts +252 -0
  27. package/src/cli/resume-relaunch-notice.ts +151 -0
  28. package/src/cli/routines-command.ts +25 -2
  29. package/src/cli/service-posture.ts +3 -2
  30. package/src/cli/skill-bundle-command.ts +175 -0
  31. package/src/cli/skills-command.ts +309 -0
  32. package/src/cli/status.ts +43 -7
  33. package/src/cli/tui-startup.ts +24 -1
  34. package/src/config/agent-settings-policy.ts +0 -1
  35. package/src/config/secret-config.ts +4 -0
  36. package/src/core/conversation-rendering.ts +20 -11
  37. package/src/core/focus-tracker.ts +41 -0
  38. package/src/core/system-message-noise.ts +108 -0
  39. package/src/core/system-message-router.ts +54 -1
  40. package/src/core/thinking-overlay.ts +83 -0
  41. package/src/input/agent-workspace-access-command-editor-submission.ts +75 -108
  42. package/src/input/agent-workspace-access-command-editors.ts +108 -128
  43. package/src/input/agent-workspace-activation.ts +15 -0
  44. package/src/input/agent-workspace-basic-command-editor-submission.ts +292 -513
  45. package/src/input/agent-workspace-basic-command-editors.ts +433 -564
  46. package/src/input/agent-workspace-calendar-connect-editor.ts +116 -0
  47. package/src/input/agent-workspace-calendar-oauth-editor.ts +152 -0
  48. package/src/input/agent-workspace-calendar-subscribe-editor.ts +128 -0
  49. package/src/input/agent-workspace-categories.ts +7 -2
  50. package/src/input/agent-workspace-channel-command-editor-submission.ts +38 -52
  51. package/src/input/agent-workspace-channel-command-editors.ts +42 -46
  52. package/src/input/agent-workspace-command-editor-engine.ts +133 -0
  53. package/src/input/agent-workspace-command-editor.ts +4 -0
  54. package/src/input/agent-workspace-direct-editor-submission.ts +59 -0
  55. package/src/input/agent-workspace-email-connect-editor.ts +162 -0
  56. package/src/input/agent-workspace-knowledge-command-editor-submission.ts +52 -81
  57. package/src/input/agent-workspace-knowledge-command-editors.ts +71 -71
  58. package/src/input/agent-workspace-library-command-editor-submission.ts +10 -28
  59. package/src/input/agent-workspace-library-command-editors.ts +16 -2
  60. package/src/input/agent-workspace-live-counters.ts +55 -0
  61. package/src/input/agent-workspace-mcp-command-editor-submission.ts +60 -82
  62. package/src/input/agent-workspace-mcp-command-editors.ts +52 -0
  63. package/src/input/agent-workspace-media-command-editor-submission.ts +12 -39
  64. package/src/input/agent-workspace-media-command-editors.ts +10 -8
  65. package/src/input/agent-workspace-memory-command-editor-submission.ts +76 -151
  66. package/src/input/agent-workspace-memory-command-editors.ts +116 -141
  67. package/src/input/agent-workspace-operations-command-editor-submission.ts +131 -184
  68. package/src/input/agent-workspace-operations-command-editors.ts +150 -162
  69. package/src/input/agent-workspace-provider-command-editor-submission.ts +60 -106
  70. package/src/input/agent-workspace-provider-command-editors.ts +58 -68
  71. package/src/input/agent-workspace-search.ts +8 -1
  72. package/src/input/agent-workspace-session-command-editor-submission.ts +104 -132
  73. package/src/input/agent-workspace-session-command-editors.ts +160 -195
  74. package/src/input/agent-workspace-settings.ts +40 -1
  75. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +55 -71
  76. package/src/input/agent-workspace-skill-bundle-command-editors.ts +65 -69
  77. package/src/input/agent-workspace-snapshot-builders.ts +431 -0
  78. package/src/input/agent-workspace-snapshot-config.ts +43 -0
  79. package/src/input/agent-workspace-snapshot.ts +198 -432
  80. package/src/input/agent-workspace-task-command-editor-submission.ts +34 -44
  81. package/src/input/agent-workspace-task-command-editors.ts +27 -28
  82. package/src/input/agent-workspace-types.ts +35 -1
  83. package/src/input/agent-workspace.ts +5 -14
  84. package/src/input/command-registry.ts +23 -1
  85. package/src/input/commands/calendar-connect-runtime.ts +226 -0
  86. package/src/input/commands/calendar-runtime.ts +110 -7
  87. package/src/input/commands/calendar-subscription-runtime.ts +225 -0
  88. package/src/input/commands/email-runtime.ts +100 -40
  89. package/src/input/commands/knowledge.ts +1 -1
  90. package/src/input/commands/network-scan-runtime.ts +75 -0
  91. package/src/input/commands/operator-actions-runtime.ts +9 -6
  92. package/src/input/commands/personas-runtime.ts +1 -1
  93. package/src/input/commands/schedule-runtime.ts +4 -4
  94. package/src/input/commands/session-content.ts +13 -1
  95. package/src/input/commands/session-workflow.ts +15 -20
  96. package/src/input/commands/session.ts +3 -1
  97. package/src/input/commands/shell-core.ts +20 -6
  98. package/src/input/commands.ts +2 -2
  99. package/src/input/delete-key-policy.ts +46 -0
  100. package/src/input/feed-context-factory.ts +10 -0
  101. package/src/input/handler-feed.ts +87 -0
  102. package/src/input/handler-modal-routes.ts +6 -1
  103. package/src/input/handler.ts +5 -0
  104. package/src/input/panel-paste-flood-guard.ts +94 -0
  105. package/src/input/settings-modal-types.ts +5 -3
  106. package/src/input/settings-modal.ts +21 -0
  107. package/src/main.ts +36 -36
  108. package/src/permissions/approval-posture.ts +141 -0
  109. package/src/renderer/agent-workspace-context-lines.ts +10 -2
  110. package/src/renderer/compositor.ts +27 -4
  111. package/src/renderer/diff.ts +61 -18
  112. package/src/renderer/fullscreen-primitives.ts +37 -18
  113. package/src/renderer/markdown.ts +20 -10
  114. package/src/renderer/modal-factory.ts +25 -15
  115. package/src/renderer/overlay-box.ts +23 -12
  116. package/src/renderer/process-indicator.ts +8 -3
  117. package/src/renderer/prompt-content-width.ts +16 -0
  118. package/src/renderer/settings-modal-helpers.ts +2 -0
  119. package/src/renderer/settings-modal.ts +2 -0
  120. package/src/renderer/startup-theme-probe.ts +35 -0
  121. package/src/renderer/status-glyphs.ts +11 -15
  122. package/src/renderer/system-message.ts +17 -2
  123. package/src/renderer/term-caps.ts +318 -0
  124. package/src/renderer/terminal-bg-probe.ts +373 -0
  125. package/src/renderer/terminal-escapes.ts +24 -0
  126. package/src/renderer/theme-mode-config.ts +87 -0
  127. package/src/renderer/theme.ts +241 -0
  128. package/src/renderer/thinking.ts +12 -3
  129. package/src/renderer/tool-call.ts +7 -3
  130. package/src/renderer/ui-factory.ts +92 -36
  131. package/src/renderer/ui-primitives.ts +33 -93
  132. package/src/runtime/bootstrap-core.ts +15 -0
  133. package/src/runtime/bootstrap-hook-bridge.ts +6 -0
  134. package/src/runtime/bootstrap-shell.ts +2 -0
  135. package/src/runtime/bootstrap.ts +68 -5
  136. package/src/runtime/calendar-boot-refresh.ts +105 -0
  137. package/src/runtime/lan-scan-consent.ts +253 -0
  138. package/src/runtime/services.ts +127 -2
  139. package/src/runtime/session-spine-rest-transport.ts +160 -0
  140. package/src/runtime/terminal-output-guard.ts +6 -1
  141. package/src/runtime/ui-services.ts +3 -0
  142. package/src/shell/agent-workspace-fullscreen.ts +5 -0
  143. package/src/shell/terminal-focus-mode.ts +120 -0
  144. package/src/shell/ui-openers.ts +13 -4
  145. package/src/tools/agent-harness-autonomy-intake.ts +5 -5
  146. package/src/tools/agent-harness-autonomy-queue.ts +1 -1
  147. package/src/tools/agent-harness-background-processes.ts +2 -1
  148. package/src/tools/agent-harness-metadata.ts +16 -8
  149. package/src/tools/agent-harness-operator-methods.ts +44 -8
  150. package/src/tools/agent-harness-personal-ops-discovery.ts +57 -10
  151. package/src/tools/agent-harness-personal-ops-lanes.ts +17 -5
  152. package/src/tools/agent-harness-personal-ops-operations.ts +7 -7
  153. package/src/tools/agent-harness-personal-ops-types.ts +6 -0
  154. package/src/tools/agent-harness-prompt-context.ts +26 -12
  155. package/src/tools/agent-harness-workspace-actions.ts +4 -0
  156. package/src/tools/agent-local-registry-args.ts +117 -0
  157. package/src/tools/agent-local-registry-memory.ts +227 -0
  158. package/src/tools/agent-local-registry-tool.ts +19 -237
  159. package/src/tools/agent-operator-briefing-tool.ts +2 -2
  160. package/src/tools/agent-operator-method-tool.ts +13 -0
  161. package/src/tools/agent-policy-explanation.ts +39 -4
  162. package/src/tools/agent-schedule-tool.ts +5 -5
  163. package/src/utils/terminal-width.ts +98 -1
  164. package/src/version.ts +1 -1
  165. package/src/cli/local-library-command.ts +0 -825
@@ -1,292 +1,181 @@
1
1
  import { basename, sep } from 'node:path';
2
- import { listAvailableSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
3
- import type { ArtifactDescriptor } from '@pellux/goodvibes-sdk/platform/artifacts';
4
- import type { MemoryRecord } from '@pellux/goodvibes-sdk/platform/state';
5
2
  import type { CommandContext } from './command-registry.ts';
6
- import { AgentNoteRegistry, type AgentNoteRecord } from '../agent/note-registry.ts';
7
- import { AgentDocumentRegistry, type AgentDocumentRecord } from '../agent/document-registry.ts';
8
- import { AgentPersonaRegistry, type AgentPersonaRecord } from '../agent/persona-registry.ts';
9
- import { formatAgentRecordOrigin } from '../agent/record-labels.ts';
10
- import { AgentRoutineRegistry, evaluateAgentRoutineReadiness, type AgentRoutineRecord } from '../agent/routine-registry.ts';
11
- import { AgentResearchRunRegistry, researchRunLogTail } from '../agent/research-run-registry.ts';
12
- import { AgentResearchSourceRegistry } from '../agent/research-source-registry.ts';
13
- import {
14
- AgentSkillRegistry,
15
- evaluateAgentSkillBundleReadiness,
16
- evaluateAgentSkillReadiness,
17
- formatAgentSkillRequirement,
18
- type AgentSkillBundleRecord,
19
- type AgentSkillRecord,
20
- } from '../agent/skill-registry.ts';
3
+ import { AgentRoutineRegistry } from '../agent/routine-registry.ts';
4
+ import { describeMemoryPromptEligibility, isPromptActiveMemory } from '../agent/memory-prompt.ts';
21
5
  import { summarizeAgentBehaviorDiscovery } from '../agent/behavior-discovery-summary.ts';
22
- import { isPromptActiveMemory } from '../agent/memory-prompt.ts';
23
- import type { PromptContextReceipt } from '../agent/prompt-context-receipts.ts';
24
- import { discoverProjectContextFiles } from '../agent/project-context-files.ts';
25
- import { getAgentRuntimeProfilesRoot, listAgentRuntimeProfiles, listAgentRuntimeProfileTemplates, readAgentRuntimeProfileSelection } from '../agent/runtime-profile.ts';
26
- import { RoutineScheduleReceiptStore } from '../agent/routine-schedule-receipts.ts';
27
6
  import { buildSetupWizardDurableReceipts } from '../agent/setup-wizard-artifact-receipts.ts';
28
7
  import { mergeSetupWizardDurableReceipts, setupWizardLiveDurableReceipts } from './setup-wizard-live-receipts.ts';
29
- import { readSetupWizardCheckpoint } from '../agent/setup-wizard-checkpoint.ts';
30
- import { discoverVibeFiles } from '../agent/vibe-file.ts';
31
- import {
32
- DEFAULT_AGENT_SETUP_WIZARD_CLEAR_CHECKPOINT_ROUTE,
33
- DEFAULT_AGENT_SETUP_WIZARD_INSPECT_CHECKPOINT_ROUTE,
34
- DEFAULT_AGENT_SETUP_WIZARD_MARK_CHECKPOINT_ROUTE,
35
- DEFAULT_AGENT_SETUP_WIZARD_RERUN_SMOKE_ROUTE,
36
- DEFAULT_AGENT_SETUP_WIZARD_SAVE_SMOKE_ROUTE,
37
- buildAgentSetupWizard,
38
- emptyAgentSetupSmokeHistory,
39
- emptyAgentSetupWizardCheckpoint,
40
- setupStepHasSatisfyingReceipt,
41
- type AgentSetupWizard,
42
- type AgentSetupWizardBlockedCheckFrequency,
43
- type AgentSetupWizardCheckpoint,
44
- type AgentSetupWizardSmokeHistory,
45
- type AgentSetupWizardSourceItem,
46
- } from '../agent/setup-wizard.ts';
47
- import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
48
- import { connectedHostOperatorTokenFingerprint, readConnectedHostOperatorToken, type ConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
8
+ import { setupStepHasSatisfyingReceipt } from '../agent/setup-wizard.ts';
49
9
  import { buildAgentWorkspaceChannelSetupGuide, buildAgentWorkspaceChannels } from './agent-workspace-channels.ts';
50
- import { getAgentWorkspaceConfigReader } from './agent-workspace-config-reader.ts';
51
- import { buildAgentWorkspaceSetupChecklist, type AgentWorkspaceSetupChecklistItem } from './agent-workspace-setup.ts';
52
- import { buildAgentWorkspaceVoiceMediaReadiness, type AgentWorkspaceVoiceMediaProviderDescriptor } from './agent-workspace-voice-media.ts';
10
+ import { buildAgentWorkspaceSetupChecklist } from './agent-workspace-setup.ts';
11
+ import { buildAgentWorkspaceVoiceMediaReadiness } from './agent-workspace-voice-media.ts';
53
12
  import { buildProcessSupervisionSummary, buildProjectContextSummary, buildPromptContextReceiptTimeline, buildResearchBrowserRunnerContract, buildResearchVisualReportContract, buildVibeSummary } from './agent-workspace-context-snapshot.ts';
54
- import { summarizeMemoryItem, summarizeNoteItem, summarizePersonaItem, summarizeResearchRunItem, summarizeRoutineItem, summarizeRoutineScheduleReceipt, summarizeRuntimeProfile, summarizeSkillBundleItem, summarizeSkillItem, summarizeStarterTemplate } from './agent-workspace-local-library-snapshot.ts';
13
+ import { summarizeMemoryItem, summarizeRoutineItem, summarizeRuntimeProfile, summarizeStarterTemplate } from './agent-workspace-local-library-snapshot.ts';
55
14
  import { buildReviewPacketDefaults, buildReviewPacketTimeline, buildReviewPacketWizard, readDocumentDrafts, reviewerReadinessBadge } from './agent-workspace-review-packet-snapshot.ts';
56
- import { isReviewerHandoffArtifact, summarizeReviewerHandoffArtifact } from './agent-workspace-review-packet-utils.ts';
57
15
  import { buildSetupSmokeHistory, buildSetupWizardCheckpoint, buildWorkspaceSetupWizard, setupCompletionMarkerExists } from './agent-workspace-setup-snapshot.ts';
58
- import { readOnboardingCompletionMarker } from '../runtime/onboarding/index.ts';
59
- import type { AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
16
+ import { readConfigNumber, readConfigString } from './agent-workspace-snapshot-config.ts';
17
+ import {
18
+ buildAgentWorkspaceArtifactListSnapshot,
19
+ buildAgentWorkspaceCalendarOAuthConfigStatus,
20
+ buildAgentWorkspaceCompanionAccessSnapshot,
21
+ buildAgentWorkspaceConfigSettingsSnapshot,
22
+ buildAgentWorkspaceCurrentModelSnapshot,
23
+ buildAgentWorkspaceEmailConnectStatus,
24
+ buildAgentWorkspaceMcpServerSnapshot,
25
+ buildAgentWorkspaceNoteSnapshot,
26
+ buildAgentWorkspacePersonaSnapshot,
27
+ buildAgentWorkspaceRecentReviewerHandoffsSnapshot,
28
+ buildAgentWorkspaceResearchRunSnapshot,
29
+ buildAgentWorkspaceResearchSourceSnapshot,
30
+ buildAgentWorkspaceRoutineScheduleReceiptsSnapshot,
31
+ buildAgentWorkspaceRuntimeProfilesSnapshot,
32
+ buildAgentWorkspaceSessionMemoryCount,
33
+ buildAgentWorkspaceSkillSnapshot,
34
+ buildAgentWorkspaceSubscriptionSnapshot,
35
+ buildAgentWorkspaceVoiceMediaProvidersSnapshot,
36
+ } from './agent-workspace-snapshot-builders.ts';
37
+ import type { AgentWorkspaceLocalLibraryItem, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
60
38
 
61
- function readConfigString(context: CommandContext, key: string, fallback: string): string {
62
- try {
63
- const configManager = getAgentWorkspaceConfigReader(context);
64
- const value = configManager?.get(key);
65
- return typeof value === 'string' && value.trim().length > 0 ? value.trim() : fallback;
66
- } catch {
67
- return fallback;
68
- }
39
+ // Re-exported so this module's public surface matches the pre-split file (W4-A5
40
+ // added and exported this builder here before the W4-H2 split moved its body to
41
+ // agent-workspace-snapshot-builders.ts).
42
+ export { buildAgentWorkspaceEmailConnectStatus } from './agent-workspace-snapshot-builders.ts';
43
+
44
+ function inferActiveRuntimeProfile(homeDirectory: string): string {
45
+ const marker = `${sep}.goodvibes${sep}agent${sep}profile-homes${sep}`;
46
+ return homeDirectory.includes(marker) ? basename(homeDirectory) : '(default home)';
69
47
  }
70
48
 
71
- function readConfigNumber(context: CommandContext, key: string, fallback: number): number {
72
- try {
73
- const configManager = getAgentWorkspaceConfigReader(context);
74
- const value = configManager?.get(key);
75
- const numberValue = typeof value === 'number' ? value : Number(value);
76
- return Number.isFinite(numberValue) ? numberValue : fallback;
77
- } catch {
78
- return fallback;
79
- }
49
+ function inferRuntimeProfileBaseHome(homeDirectory: string): string {
50
+ const marker = `${sep}.goodvibes${sep}agent${sep}profile-homes${sep}`;
51
+ const markerIndex = homeDirectory.indexOf(marker);
52
+ return markerIndex >= 0 ? homeDirectory.slice(0, markerIndex) : homeDirectory;
53
+ }
54
+
55
+ export interface AgentWorkspaceLiveMemoryCounters {
56
+ readonly count: number;
57
+ readonly reviewQueueCount: number;
58
+ readonly promptActiveCount: number;
59
+ readonly items: readonly AgentWorkspaceLocalLibraryItem[];
80
60
  }
81
61
 
82
- function readConfigBoolean(context: CommandContext, key: string, fallback: boolean): boolean {
62
+ /**
63
+ * Reads the Agent memory count + items directly from the live memory API
64
+ * (no caching). Throws if the read itself fails (e.g. the memory API errors
65
+ * mid-call) rather than swallowing it — callers that need a best-effort,
66
+ * never-throws default (the full runtime snapshot builder below) should use
67
+ * buildAgentWorkspaceMemorySnapshot instead. The render-path live-counter
68
+ * refresh (AgentWorkspace.syncLiveCountersForRender, W4-A6) calls this
69
+ * directly so a genuine read failure can be surfaced as "stale" instead of
70
+ * being silently rewritten to a fabricated 0.
71
+ *
72
+ * NOTE (W4-H1 observability flag): these live process/state counters are
73
+ * flagged as observability-shaped content whose eventual surface home is the
74
+ * fleet/observability layer, not this admin-console snapshot builder. Nothing
75
+ * moves today (no observability layer exists yet); this function is kept
76
+ * intact and separate rather than folded into the sibling sub-builders in
77
+ * agent-workspace-snapshot-builders.ts extracted alongside it in W4-H2.
78
+ */
79
+ export function readLiveAgentMemoryCounters(context: CommandContext): AgentWorkspaceLiveMemoryCounters {
80
+ const memory = context.clients?.agentKnowledgeApi?.memory;
81
+ if (!memory) return { count: 0, reviewQueueCount: 0, promptActiveCount: 0, items: [] };
82
+ const records = [...memory.getAll()].sort((left, right) => right.updatedAt - left.updatedAt);
83
+ return {
84
+ count: records.length,
85
+ reviewQueueCount: memory.reviewQueue(100).length,
86
+ promptActiveCount: records.filter(isPromptActiveMemory).length,
87
+ // Each item carries the honest, per-record eligibility reason straight from
88
+ // describeMemoryPromptEligibility (Wave-4 W4-A1B) — the same wording source
89
+ // prompt-context-receipts.ts and agent-harness-prompt-context.ts use for prompt
90
+ // recall. No locally invented "not reviewed"/"outside prompt limit" paraphrase here.
91
+ items: records.map((record) => ({
92
+ ...summarizeMemoryItem(record),
93
+ promptEligible: isPromptActiveMemory(record),
94
+ promptEligibilityReason: describeMemoryPromptEligibility(record).reason,
95
+ })),
96
+ };
97
+ }
98
+
99
+ /**
100
+ * Best-effort variant of readLiveAgentMemoryCounters for the full runtime
101
+ * snapshot builder: never throws, defaults to empty on any read failure.
102
+ */
103
+ export function buildAgentWorkspaceMemorySnapshot(context: CommandContext): AgentWorkspaceLiveMemoryCounters {
83
104
  try {
84
- const configManager = getAgentWorkspaceConfigReader(context);
85
- const value = configManager?.get(key);
86
- if (typeof value === 'boolean') return value;
87
- if (typeof value === 'string') {
88
- const normalized = value.trim().toLowerCase();
89
- if (normalized === 'true') return true;
90
- if (normalized === 'false') return false;
91
- }
92
- return fallback;
105
+ return readLiveAgentMemoryCounters(context);
93
106
  } catch {
94
- return fallback;
107
+ return { count: 0, reviewQueueCount: 0, promptActiveCount: 0, items: [] };
95
108
  }
96
109
  }
97
110
 
98
- function inferActiveRuntimeProfile(homeDirectory: string): string {
99
- const marker = `${sep}.goodvibes${sep}agent${sep}profile-homes${sep}`;
100
- return homeDirectory.includes(marker) ? basename(homeDirectory) : '(default home)';
111
+ export interface AgentWorkspaceLiveRoutineCounters {
112
+ readonly count: number;
113
+ readonly enabled: number;
114
+ readonly items: readonly AgentWorkspaceLocalLibraryItem[];
101
115
  }
102
116
 
103
- function inferRuntimeProfileBaseHome(homeDirectory: string): string {
104
- const marker = `${sep}.goodvibes${sep}agent${sep}profile-homes${sep}`;
105
- const markerIndex = homeDirectory.indexOf(marker);
106
- return markerIndex >= 0 ? homeDirectory.slice(0, markerIndex) : homeDirectory;
117
+ /**
118
+ * Reads the Agent routine count + items (including each routine's live
119
+ * startCount) directly from the on-disk routine store (no caching). Throws
120
+ * if the store read fails (e.g. a corrupt/unreadable routines.json —
121
+ * AgentRoutineRegistry.snapshot() itself throws in that case) rather than
122
+ * swallowing it; see readLiveAgentMemoryCounters above for why the
123
+ * render-path live-counter refresh (W4-A6) wants that.
124
+ *
125
+ * NOTE (W4-H1 observability flag): see readLiveAgentMemoryCounters above —
126
+ * the same flag applies to these routine counters.
127
+ */
128
+ export function readLiveAgentRoutineCounters(context: CommandContext): AgentWorkspaceLiveRoutineCounters {
129
+ const shellPaths = context.workspace?.shellPaths;
130
+ if (!shellPaths) return { count: 0, enabled: 0, items: [] };
131
+ const snapshot = AgentRoutineRegistry.fromShellPaths(shellPaths).snapshot();
132
+ return {
133
+ count: snapshot.routines.length,
134
+ enabled: snapshot.enabledRoutines.length,
135
+ items: snapshot.routines.map(summarizeRoutineItem),
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Best-effort variant of readLiveAgentRoutineCounters for the full runtime
141
+ * snapshot builder: never throws, defaults to empty on any read failure.
142
+ */
143
+ export function buildAgentWorkspaceRoutineCounters(context: CommandContext): AgentWorkspaceLiveRoutineCounters {
144
+ try {
145
+ return readLiveAgentRoutineCounters(context);
146
+ } catch {
147
+ return { count: 0, enabled: 0, items: [] };
148
+ }
107
149
  }
108
150
 
151
+ /**
152
+ * Assembles the full Agent workspace runtime snapshot. Composes the
153
+ * sub-builders in agent-workspace-snapshot-builders.ts (W4-H2 split of what
154
+ * was previously one ~516-line function) plus the two live-counter builders
155
+ * above, then maps everything onto the AgentWorkspaceRuntimeSnapshot shape.
156
+ */
109
157
  export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): AgentWorkspaceRuntimeSnapshot {
110
158
  const host = readConfigString(context, 'controlPlane.host', '127.0.0.1');
111
159
  const port = readConfigNumber(context, 'controlPlane.port', 3421);
112
160
  const model = context.session?.runtime?.model ?? 'unknown';
113
161
  const provider = context.session?.runtime?.provider ?? 'unknown';
114
- const currentModel = (() => {
115
- try {
116
- return context.provider?.providerRegistry?.getCurrentModel?.();
117
- } catch {
118
- return null;
119
- }
120
- })();
121
- const sessionMemoryCount = (() => {
122
- try {
123
- return context.session?.sessionMemoryStore?.list?.().length ?? 0;
124
- } catch {
125
- return 0;
126
- }
127
- })();
128
- const memorySnapshot = (() => {
129
- try {
130
- const memory = context.clients?.agentKnowledgeApi?.memory;
131
- if (!memory) return { count: 0, reviewQueueCount: 0, promptActiveCount: 0, items: [] };
132
- const records = [...memory.getAll()].sort((left, right) => right.updatedAt - left.updatedAt);
133
- return {
134
- count: records.length,
135
- reviewQueueCount: memory.reviewQueue(100).length,
136
- promptActiveCount: records.filter(isPromptActiveMemory).length,
137
- items: records.map(summarizeMemoryItem),
138
- };
139
- } catch {
140
- return { count: 0, reviewQueueCount: 0, promptActiveCount: 0, items: [] };
141
- }
142
- })();
143
- const personaSnapshot = (() => {
144
- try {
145
- const shellPaths = context.workspace?.shellPaths;
146
- if (!shellPaths) return { count: 0, activeName: '(none)', items: [] };
147
- const snapshot = AgentPersonaRegistry.fromShellPaths(shellPaths).snapshot();
148
- return {
149
- count: snapshot.personas.length,
150
- activeName: snapshot.activePersona?.name ?? '(none)',
151
- items: snapshot.personas.map((persona) => summarizePersonaItem(persona, snapshot.activePersonaId)),
152
- };
153
- } catch {
154
- return { count: 0, activeName: '(unavailable)', items: [] };
155
- }
156
- })();
157
- const noteSnapshot = (() => {
158
- try {
159
- const shellPaths = context.workspace?.shellPaths;
160
- if (!shellPaths) return { count: 0, reviewQueueCount: 0, items: [] };
161
- const snapshot = AgentNoteRegistry.fromShellPaths(shellPaths).snapshot();
162
- return {
163
- count: snapshot.notes.length,
164
- reviewQueueCount: snapshot.reviewQueue.length,
165
- items: snapshot.notes.map(summarizeNoteItem),
166
- };
167
- } catch {
168
- return { count: 0, reviewQueueCount: 0, items: [] };
169
- }
170
- })();
171
- const skillSnapshot = (() => {
172
- try {
173
- const shellPaths = context.workspace?.shellPaths;
174
- if (!shellPaths) return { count: 0, enabled: 0, active: 0, bundleCount: 0, enabledBundleCount: 0, items: [], bundleItems: [] };
175
- const snapshot = AgentSkillRegistry.fromShellPaths(shellPaths).snapshot();
176
- return {
177
- count: snapshot.skills.length,
178
- enabled: snapshot.enabledSkills.length,
179
- active: snapshot.activeSkills.length,
180
- bundleCount: snapshot.bundles.length,
181
- enabledBundleCount: snapshot.enabledBundles.length,
182
- items: snapshot.skills.map(summarizeSkillItem),
183
- bundleItems: snapshot.bundles.map((bundle) => summarizeSkillBundleItem(bundle, snapshot.skills)),
184
- };
185
- } catch {
186
- return { count: 0, enabled: 0, active: 0, bundleCount: 0, enabledBundleCount: 0, items: [], bundleItems: [] };
187
- }
188
- })();
189
- const routineSnapshot = (() => {
190
- try {
191
- const shellPaths = context.workspace?.shellPaths;
192
- if (!shellPaths) return { count: 0, enabled: 0, items: [] };
193
- const snapshot = AgentRoutineRegistry.fromShellPaths(shellPaths).snapshot();
194
- return {
195
- count: snapshot.routines.length,
196
- enabled: snapshot.enabledRoutines.length,
197
- items: snapshot.routines.map(summarizeRoutineItem),
198
- };
199
- } catch {
200
- return { count: 0, enabled: 0, items: [] };
201
- }
202
- })();
203
- const routineScheduleReceipts = (() => {
204
- try {
205
- const shellPaths = context.workspace?.shellPaths;
206
- if (!shellPaths) return { count: 0, successful: 0, failed: 0, latest: null };
207
- const receipts = RoutineScheduleReceiptStore.fromShellPaths(shellPaths).snapshot().receipts;
208
- return {
209
- count: receipts.length,
210
- successful: receipts.filter((receipt) => receipt.status === 'created').length,
211
- failed: receipts.filter((receipt) => receipt.status === 'failed').length,
212
- latest: receipts[0] ? summarizeRoutineScheduleReceipt(receipts[0]) : null,
213
- };
214
- } catch {
215
- return { count: 0, successful: 0, failed: 0, latest: null };
216
- }
217
- })();
218
- const researchSourceSnapshot = (() => {
219
- try {
220
- const shellPaths = context.workspace?.shellPaths;
221
- if (!shellPaths) return { count: 0, candidate: 0, reviewed: 0, rejected: 0, used: 0 };
222
- const snapshot = AgentResearchSourceRegistry.fromShellPaths(shellPaths).snapshot();
223
- return {
224
- count: snapshot.sources.length,
225
- candidate: snapshot.candidates.length,
226
- reviewed: snapshot.reviewed.length,
227
- rejected: snapshot.rejected.length,
228
- used: snapshot.used.length,
229
- };
230
- } catch {
231
- return { count: 0, candidate: 0, reviewed: 0, rejected: 0, used: 0 };
232
- }
233
- })();
234
- const researchRunSnapshot = (() => {
235
- try {
236
- const shellPaths = context.workspace?.shellPaths;
237
- if (!shellPaths) return { count: 0, planned: 0, running: 0, paused: 0, blocked: 0, terminal: 0, items: [] };
238
- const snapshot = AgentResearchRunRegistry.fromShellPaths(shellPaths).snapshot();
239
- const actionable = [
240
- ...snapshot.blocked,
241
- ...snapshot.running,
242
- ...snapshot.paused,
243
- ...snapshot.planned,
244
- ...snapshot.failed,
245
- ...snapshot.completed,
246
- ...snapshot.cancelled,
247
- ];
248
- return {
249
- count: snapshot.runs.length,
250
- planned: snapshot.planned.length,
251
- running: snapshot.running.length,
252
- paused: snapshot.paused.length,
253
- blocked: snapshot.blocked.length,
254
- terminal: snapshot.cancelled.length + snapshot.completed.length + snapshot.failed.length,
255
- items: actionable.slice(0, 8).map(summarizeResearchRunItem),
256
- };
257
- } catch {
258
- return { count: 0, planned: 0, running: 0, paused: 0, blocked: 0, terminal: 0, items: [] };
259
- }
260
- })();
261
- const artifactListSnapshot = (() => {
262
- try {
263
- const list = context.platform?.artifactStore?.list;
264
- return {
265
- available: Boolean(list),
266
- items: [...(list?.(100) ?? [])],
267
- };
268
- } catch {
269
- return { available: false, items: [] };
270
- }
271
- })();
162
+ const currentModel = buildAgentWorkspaceCurrentModelSnapshot(context);
163
+ const sessionMemoryCount = buildAgentWorkspaceSessionMemoryCount(context);
164
+ const memorySnapshot = buildAgentWorkspaceMemorySnapshot(context);
165
+ const personaSnapshot = buildAgentWorkspacePersonaSnapshot(context);
166
+ const noteSnapshot = buildAgentWorkspaceNoteSnapshot(context);
167
+ const skillSnapshot = buildAgentWorkspaceSkillSnapshot(context);
168
+ const routineSnapshot = buildAgentWorkspaceRoutineCounters(context);
169
+ const routineScheduleReceipts = buildAgentWorkspaceRoutineScheduleReceiptsSnapshot(context);
170
+ const researchSourceSnapshot = buildAgentWorkspaceResearchSourceSnapshot(context);
171
+ const researchRunSnapshot = buildAgentWorkspaceResearchRunSnapshot(context);
172
+ const artifactListSnapshot = buildAgentWorkspaceArtifactListSnapshot(context);
272
173
  const setupSmokeHistory = buildSetupSmokeHistory(artifactListSnapshot.items, artifactListSnapshot.available);
273
174
  const durableSetupReceipts = mergeSetupWizardDurableReceipts(
274
175
  buildSetupWizardDurableReceipts(artifactListSnapshot.items),
275
176
  setupWizardLiveDurableReceipts(context),
276
177
  );
277
- const recentReviewerHandoffs = (() => {
278
- try {
279
- const handoffs = artifactListSnapshot.items
280
- .filter(isReviewerHandoffArtifact)
281
- .sort((left, right) => right.createdAt - left.createdAt);
282
- return {
283
- count: handoffs.length,
284
- items: handoffs.slice(0, 6).map(summarizeReviewerHandoffArtifact),
285
- };
286
- } catch {
287
- return { count: 0, items: [] };
288
- }
289
- })();
178
+ const recentReviewerHandoffs = buildAgentWorkspaceRecentReviewerHandoffsSnapshot(artifactListSnapshot.items);
290
179
  const documentDrafts = readDocumentDrafts(context);
291
180
  const reviewerBadge = reviewerReadinessBadge(
292
181
  documentDrafts,
@@ -309,65 +198,15 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
309
198
  );
310
199
  const discoveredBehavior = summarizeAgentBehaviorDiscovery(context.workspace?.shellPaths);
311
200
  const profileBaseHome = inferRuntimeProfileBaseHome(context.workspace?.shellPaths?.homeDirectory ?? '');
312
- const runtimeProfiles = (() => {
313
- try {
314
- return listAgentRuntimeProfiles(profileBaseHome);
315
- } catch {
316
- return [];
317
- }
318
- })();
319
- const runtimeStarterTemplates = (() => {
320
- try {
321
- return listAgentRuntimeProfileTemplates(profileBaseHome);
322
- } catch {
323
- return [];
324
- }
325
- })();
326
- const selectedRuntimeProfile = (() => {
327
- try {
328
- return readAgentRuntimeProfileSelection(profileBaseHome);
329
- } catch {
330
- return null;
331
- }
332
- })();
333
- const voiceProviders = (() => {
334
- try {
335
- return context.platform?.voiceProviderRegistry?.list?.() ?? [];
336
- } catch {
337
- return [];
338
- }
339
- })();
340
- const mediaProviders = (() => {
341
- try {
342
- return context.platform?.mediaProviderRegistry?.list?.() ?? [];
343
- } catch {
344
- return [];
345
- }
346
- })();
347
- const mcpSnapshot = (() => {
348
- try {
349
- const servers = context.clients?.mcpApi?.listServerSecurity?.() ?? context.extensions?.mcpRegistry?.listServerSecurity?.() ?? [];
350
- return {
351
- serverCount: servers.length,
352
- connectedCount: servers.filter((server) => server.connected).length,
353
- quarantinedCount: servers.filter((server) => server.schemaFreshness === 'quarantined').length,
354
- allowAllCount: servers.filter((server) => server.trustMode === 'allow-all').length,
355
- };
356
- } catch {
357
- return {
358
- serverCount: 0,
359
- connectedCount: 0,
360
- quarantinedCount: 0,
361
- allowAllCount: 0,
362
- };
363
- }
364
- })();
365
- const voiceProviderDescriptors: readonly AgentWorkspaceVoiceMediaProviderDescriptor[] = voiceProviders.map((provider) => ({
201
+ const { runtimeProfiles, runtimeStarterTemplates, selectedRuntimeProfile, runtimeProfileRoot } = buildAgentWorkspaceRuntimeProfilesSnapshot(profileBaseHome);
202
+ const { voiceProviders, mediaProviders } = buildAgentWorkspaceVoiceMediaProvidersSnapshot(context);
203
+ const mcpSnapshot = buildAgentWorkspaceMcpServerSnapshot(context);
204
+ const voiceProviderDescriptors = voiceProviders.map((provider) => ({
366
205
  id: provider.id,
367
206
  label: provider.label,
368
207
  capabilities: provider.capabilities,
369
208
  }));
370
- const mediaProviderDescriptors: readonly AgentWorkspaceVoiceMediaProviderDescriptor[] = mediaProviders.map((provider) => ({
209
+ const mediaProviderDescriptors = mediaProviders.map((provider) => ({
371
210
  id: provider.id,
372
211
  label: provider.label,
373
212
  capabilities: provider.capabilities,
@@ -375,84 +214,10 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
375
214
  const warnings: string[] = [];
376
215
  if (provider === 'unknown' || model === 'unknown') warnings.push('Provider/model unavailable in this runtime context.');
377
216
  if (!context.executeCommand) warnings.push('Command dispatch is unavailable; workspace actions will show guidance only.');
378
- const ttsProvider = readConfigString(context, 'tts.provider', '(provider default)');
379
- const ttsVoice = readConfigString(context, 'tts.voice', '(voice default)');
380
- const ttsLlmProvider = readConfigString(context, 'tts.llmProvider', '');
381
- const ttsLlmModel = readConfigString(context, 'tts.llmModel', '');
382
- const embeddingProvider = readConfigString(context, 'provider.embeddingProvider', '(provider default)');
383
- const reasoningEffort = readConfigString(context, 'provider.reasoningEffort', '(default)');
384
- const helperEnabled = readConfigBoolean(context, 'helper.enabled', false);
385
- const toolLlmEnabled = readConfigBoolean(context, 'tools.llmEnabled', false);
386
- const providerFailureHints = readConfigBoolean(context, 'behavior.suggestAlternativeOnProviderFail', false);
387
- const cacheEnabled = readConfigBoolean(context, 'cache.enabled', true);
388
- const cacheStableTtl = readConfigString(context, 'cache.stableTtl', '(default)');
389
- const cacheMonitorHitRate = readConfigBoolean(context, 'cache.monitorHitRate', true);
390
- const cacheHitRateWarningThreshold = readConfigNumber(context, 'cache.hitRateWarningThreshold', 0.3);
391
- const hitlMode = readConfigString(context, 'behavior.hitlMode', '(default)');
392
- const guidanceMode = readConfigString(context, 'behavior.guidanceMode', '(default)');
393
- const saveHistory = readConfigBoolean(context, 'behavior.saveHistory', true);
394
- const autoApprove = readConfigBoolean(context, 'behavior.autoApprove', false);
395
- const autoCompactThreshold = readConfigNumber(context, 'behavior.autoCompactThreshold', 0);
396
- const staleContextWarnings = readConfigBoolean(context, 'behavior.staleContextWarnings', false);
397
- const showThinking = readConfigBoolean(context, 'display.showThinking', false);
398
- const showReasoningSummary = readConfigBoolean(context, 'display.showReasoningSummary', false);
399
- const theme = readConfigString(context, 'display.theme', '(default)');
400
- const stream = readConfigBoolean(context, 'display.stream', true);
401
- const lineNumbers = readConfigString(context, 'display.lineNumbers', '(default)');
402
- const operationalMessages = readConfigString(context, 'ui.operationalMessages', '(default)');
403
- const systemMessages = readConfigString(context, 'ui.systemMessages', '(default)');
404
- const releaseChannel = readConfigString(context, 'release.channel', '(default)');
405
- const permissionMode = readConfigString(context, 'permissions.mode', '(default)');
406
- const toolAutoHeal = readConfigBoolean(context, 'tools.autoHeal', false);
407
- const toolsDefaultTokenBudget = readConfigNumber(context, 'tools.defaultTokenBudget', 5000);
408
- const artifactMaxBytes = readConfigNumber(context, 'storage.artifacts.maxBytes', 512 * 1024 * 1024);
409
- const rawPromptTelemetry = readConfigBoolean(context, 'telemetry.includeRawPrompts', false);
410
- const automationEnabled = readConfigBoolean(context, 'automation.enabled', false);
411
- const automationMaxConcurrentRuns = readConfigNumber(context, 'automation.maxConcurrentRuns', 4);
412
- const automationRunHistoryLimit = readConfigNumber(context, 'automation.runHistoryLimit', 100);
413
- const automationDefaultTimeoutMs = readConfigNumber(context, 'automation.defaultTimeoutMs', 15 * 60 * 1000);
414
- const automationCatchUpWindowMinutes = readConfigNumber(context, 'automation.catchUpWindowMinutes', 30);
415
- const automationFailureCooldownMs = readConfigNumber(context, 'automation.failureCooldownMs', 5 * 60 * 1000);
416
- const automationDeleteAfterRun = readConfigBoolean(context, 'automation.deleteAfterRun', false);
217
+ const config = buildAgentWorkspaceConfigSettingsSnapshot(context);
417
218
  const runtimeBaseUrl = `http://${host}:${port}`;
418
- const companionAccess = (() => {
419
- const homeDirectory = context.workspace?.shellPaths?.homeDirectory ?? '';
420
- const tokenRecord: ConnectedHostOperatorToken = homeDirectory.length > 0
421
- ? readConnectedHostOperatorToken(homeDirectory)
422
- : { path: '(Agent home unavailable)', present: false, token: null };
423
- const tokenFingerprint = tokenRecord.token ? connectedHostOperatorTokenFingerprint(tokenRecord.token) : null;
424
- const pairingReady = Boolean(tokenRecord.token);
425
- const nextStep = tokenRecord.error
426
- ? 'Repair the connected-host operator token file through the owning GoodVibes host, then rerun /pair.'
427
- : pairingReady
428
- ? 'Use /pair to scan the QR code. Manual token display stays hidden unless /pair --show-token --yes is used.'
429
- : 'Pair or provision connected-host access through the owning GoodVibes host, then rerun /pair.';
430
- return {
431
- surface: GOODVIBES_AGENT_PAIRING_SURFACE,
432
- hostUrl: runtimeBaseUrl,
433
- tokenPath: tokenRecord.path,
434
- tokenPresent: tokenRecord.present,
435
- tokenReadable: Boolean(tokenRecord.token),
436
- tokenFingerprint,
437
- tokenError: tokenRecord.error ?? null,
438
- pairingReady,
439
- qrCommand: '/pair',
440
- manualTokenCommand: '/pair --show-token --yes',
441
- nextStep,
442
- } as const;
443
- })();
444
- const subscriptionSnapshot = (() => {
445
- try {
446
- const manager = context.platform?.subscriptionManager;
447
- const services = context.platform?.serviceRegistry;
448
- const active = manager?.list?.().length ?? 0;
449
- const pending = manager?.listPending?.().length ?? 0;
450
- const available = services ? listAvailableSubscriptionProviders(services.getAll()).length : 0;
451
- return { active, pending, available };
452
- } catch {
453
- return { active: 0, pending: 0, available: 0 };
454
- }
455
- })();
219
+ const companionAccess = buildAgentWorkspaceCompanionAccessSnapshot(context, runtimeBaseUrl);
220
+ const subscriptionSnapshot = buildAgentWorkspaceSubscriptionSnapshot(context);
456
221
  const channels = buildAgentWorkspaceChannels(context);
457
222
  const channelSetupGuide = buildAgentWorkspaceChannelSetupGuide(channels);
458
223
  const voiceMediaReadiness = buildAgentWorkspaceVoiceMediaReadiness({
@@ -460,8 +225,6 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
460
225
  voiceProviders: voiceProviderDescriptors,
461
226
  mediaProviders: mediaProviderDescriptors,
462
227
  });
463
- const browserPwaEnabled = readConfigBoolean(context, 'web.enabled', false);
464
- const browserPwaPublicBaseUrl = readConfigString(context, 'web.publicBaseUrl', '(not configured)');
465
228
  const connectedHostAuthReceiptReady = setupStepHasSatisfyingReceipt(durableSetupReceipts, 'connected-host-auth');
466
229
  const setupChecklist = buildAgentWorkspaceSetupChecklist({
467
230
  provider,
@@ -516,41 +279,41 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
516
279
  provider,
517
280
  model,
518
281
  modelDisplayName: currentModel?.displayName ?? model,
519
- embeddingProvider,
520
- reasoningEffort,
521
- helperEnabled,
522
- toolLlmEnabled,
523
- providerFailureHints,
524
- cacheEnabled,
525
- cacheStableTtl,
526
- cacheMonitorHitRate,
527
- cacheHitRateWarningThreshold,
528
- hitlMode,
529
- guidanceMode,
530
- saveHistory,
531
- autoApprove,
532
- autoCompactThreshold,
533
- staleContextWarnings,
534
- showThinking,
535
- showReasoningSummary,
536
- theme,
537
- stream,
538
- lineNumbers,
539
- operationalMessages,
540
- systemMessages,
541
- releaseChannel,
542
- permissionMode,
543
- toolAutoHeal,
544
- toolsDefaultTokenBudget,
545
- artifactMaxBytes,
546
- rawPromptTelemetry,
547
- automationEnabled,
548
- automationMaxConcurrentRuns,
549
- automationRunHistoryLimit,
550
- automationDefaultTimeoutMs,
551
- automationCatchUpWindowMinutes,
552
- automationFailureCooldownMs,
553
- automationDeleteAfterRun,
282
+ embeddingProvider: config.embeddingProvider,
283
+ reasoningEffort: config.reasoningEffort,
284
+ helperEnabled: config.helperEnabled,
285
+ toolLlmEnabled: config.toolLlmEnabled,
286
+ providerFailureHints: config.providerFailureHints,
287
+ cacheEnabled: config.cacheEnabled,
288
+ cacheStableTtl: config.cacheStableTtl,
289
+ cacheMonitorHitRate: config.cacheMonitorHitRate,
290
+ cacheHitRateWarningThreshold: config.cacheHitRateWarningThreshold,
291
+ hitlMode: config.hitlMode,
292
+ guidanceMode: config.guidanceMode,
293
+ saveHistory: config.saveHistory,
294
+ autoApprove: config.autoApprove,
295
+ autoCompactThreshold: config.autoCompactThreshold,
296
+ staleContextWarnings: config.staleContextWarnings,
297
+ showThinking: config.showThinking,
298
+ showReasoningSummary: config.showReasoningSummary,
299
+ theme: config.theme,
300
+ stream: config.stream,
301
+ lineNumbers: config.lineNumbers,
302
+ operationalMessages: config.operationalMessages,
303
+ systemMessages: config.systemMessages,
304
+ releaseChannel: config.releaseChannel,
305
+ permissionMode: config.permissionMode,
306
+ toolAutoHeal: config.toolAutoHeal,
307
+ toolsDefaultTokenBudget: config.toolsDefaultTokenBudget,
308
+ artifactMaxBytes: config.artifactMaxBytes,
309
+ rawPromptTelemetry: config.rawPromptTelemetry,
310
+ automationEnabled: config.automationEnabled,
311
+ automationMaxConcurrentRuns: config.automationMaxConcurrentRuns,
312
+ automationRunHistoryLimit: config.automationRunHistoryLimit,
313
+ automationDefaultTimeoutMs: config.automationDefaultTimeoutMs,
314
+ automationCatchUpWindowMinutes: config.automationCatchUpWindowMinutes,
315
+ automationFailureCooldownMs: config.automationFailureCooldownMs,
316
+ automationDeleteAfterRun: config.automationDeleteAfterRun,
554
317
  sessionId: context.session?.runtime?.sessionId ?? 'unknown',
555
318
  workingDirectory: context.workspace?.shellPaths?.workingDirectory ?? 'unavailable',
556
319
  homeDirectory: context.workspace?.shellPaths?.homeDirectory ?? 'unavailable',
@@ -620,10 +383,10 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
620
383
  voiceStreamingProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('tts-stream')).length,
621
384
  voiceSttProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('stt')).length,
622
385
  voiceRealtimeProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('realtime')).length,
623
- ttsProvider,
624
- ttsVoice,
625
- ttsResponseModel: ttsLlmProvider && ttsLlmModel ? `${ttsLlmProvider}/${ttsLlmModel}` : '(chat route)',
626
- voiceSurfaceEnabled: readConfigBoolean(context, 'ui.voiceEnabled', false),
386
+ ttsProvider: config.ttsProvider,
387
+ ttsVoice: config.ttsVoice,
388
+ ttsResponseModel: config.ttsLlmProvider && config.ttsLlmModel ? `${config.ttsLlmProvider}/${config.ttsLlmModel}` : '(chat route)',
389
+ voiceSurfaceEnabled: config.voiceSurfaceEnabled,
627
390
  mediaProviderCount: mediaProviders.length,
628
391
  mediaUnderstandingProviderCount: mediaProviders.filter((entry) => entry.capabilities.includes('understand')).length,
629
392
  mediaGenerationProviderCount: mediaProviders.filter((entry) => entry.capabilities.includes('generate')).length,
@@ -632,20 +395,23 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
632
395
  mcpConnectedServerCount: mcpSnapshot.connectedCount,
633
396
  mcpQuarantinedServerCount: mcpSnapshot.quarantinedCount,
634
397
  mcpAllowAllServerCount: mcpSnapshot.allowAllCount,
635
- browserToolExposureEnabled: browserPwaEnabled,
636
- browserToolPublicBaseUrl: browserPwaPublicBaseUrl,
398
+ browserToolExposureEnabled: config.browserPwaEnabled,
399
+ browserToolPublicBaseUrl: config.browserPwaPublicBaseUrl,
637
400
  activeRuntimeProfile: inferActiveRuntimeProfile(context.workspace?.shellPaths?.homeDirectory ?? ''),
638
401
  selectedRuntimeProfile: selectedRuntimeProfile?.id ?? null,
639
402
  selectedRuntimeProfileExists: selectedRuntimeProfile?.exists ?? false,
640
403
  selectedRuntimeProfileSelectedAt: selectedRuntimeProfile?.selectedAt ?? null,
641
404
  runtimeProfileCount: runtimeProfiles.length,
642
405
  runtimeProfiles: runtimeProfiles.map(summarizeRuntimeProfile),
643
- runtimeProfileRoot: getAgentRuntimeProfilesRoot(profileBaseHome),
406
+ runtimeProfileRoot,
644
407
  runtimeStarterTemplateCount: runtimeStarterTemplates.length,
645
408
  localStarterTemplateCount: runtimeStarterTemplates.filter((template) => template.source === 'local').length,
646
409
  runtimeStarterTemplates: runtimeStarterTemplates.map(summarizeStarterTemplate),
647
410
  setupChecklist,
648
411
  setupWizard,
649
412
  warnings,
413
+ liveCountersStale: false,
414
+ emailConnectStatus: buildAgentWorkspaceEmailConnectStatus(context),
415
+ calendarOAuthConfigStatus: buildAgentWorkspaceCalendarOAuthConfigStatus(context),
650
416
  };
651
417
  }