@pellux/goodvibes-agent 1.4.4 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +7 -7
  3. package/dist/package/main.js +7424 -12241
  4. package/docs/README.md +2 -2
  5. package/docs/channels-remote-and-api.md +1 -1
  6. package/docs/getting-started.md +2 -2
  7. package/docs/release-and-publishing.md +1 -1
  8. package/docs/tools-and-commands.md +5 -5
  9. package/package.json +4 -2
  10. package/release/performance-snapshot.json +2 -2
  11. package/release/release-notes.md +11 -7
  12. package/release/release-readiness.json +6 -6
  13. package/src/agent/behavior-discovery-summary.ts +4 -18
  14. package/src/agent/calendar-registry.ts +322 -0
  15. package/src/agent/competitive-feature-inventory.ts +268 -130
  16. package/src/agent/document-registry.ts +5 -1
  17. package/src/agent/email/email-service.ts +350 -0
  18. package/src/agent/email/imap-client.ts +596 -0
  19. package/src/agent/email/smtp-client.ts +453 -0
  20. package/src/agent/ics-calendar.ts +662 -0
  21. package/src/agent/ics-timezone.ts +172 -0
  22. package/src/agent/markdown-frontmatter.ts +31 -0
  23. package/src/agent/memory-safety.ts +1 -1
  24. package/src/agent/note-registry.ts +3 -9
  25. package/src/agent/persona-discovery.ts +3 -15
  26. package/src/agent/persona-registry.ts +1 -10
  27. package/src/agent/research-source-registry.ts +5 -1
  28. package/src/agent/routine-discovery.ts +3 -15
  29. package/src/agent/runtime-profile.ts +3 -0
  30. package/src/agent/skill-discovery.ts +3 -15
  31. package/src/agent/skill-draft-proposer.ts +203 -0
  32. package/src/agent/skill-draft-runner.ts +201 -0
  33. package/src/agent/skill-registry.ts +36 -1
  34. package/src/agent/skill-standard.ts +99 -0
  35. package/src/agent/vibe-file.ts +7 -22
  36. package/src/cli/completion.ts +1 -1
  37. package/src/cli/config-overrides.ts +10 -1
  38. package/src/cli/redaction.ts +17 -5
  39. package/src/config/provider-model.ts +2 -1
  40. package/src/config/secret-config.ts +13 -6
  41. package/src/core/activity-feed.ts +97 -0
  42. package/src/core/away-digest.ts +161 -0
  43. package/src/core/conversation-rendering.ts +7 -3
  44. package/src/core/conversation.ts +22 -15
  45. package/src/core/hardware-profile.ts +362 -0
  46. package/src/core/last-seen-store.ts +78 -0
  47. package/src/core/plain-language.ts +52 -0
  48. package/src/core/setup-incomplete-hint.ts +90 -0
  49. package/src/core/system-message-router.ts +38 -87
  50. package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
  51. package/src/input/agent-workspace-basic-command-editors.ts +39 -141
  52. package/src/input/agent-workspace-categories.ts +40 -125
  53. package/src/input/agent-workspace-command-editor.ts +4 -0
  54. package/src/input/agent-workspace-host-category.ts +0 -5
  55. package/src/input/agent-workspace-local-editor-submission.ts +3 -1
  56. package/src/input/agent-workspace-navigation.ts +10 -3
  57. package/src/input/agent-workspace-onboarding-actions.ts +132 -0
  58. package/src/input/agent-workspace-onboarding-categories.ts +29 -26
  59. package/src/input/agent-workspace-onboarding-finish.ts +11 -4
  60. package/src/input/agent-workspace-onboarding-state.ts +111 -0
  61. package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
  62. package/src/input/agent-workspace-profile-editors.ts +155 -0
  63. package/src/input/agent-workspace-subscription-editor.ts +7 -0
  64. package/src/input/agent-workspace-types.ts +5 -1
  65. package/src/input/agent-workspace.ts +65 -39
  66. package/src/input/command-registry.ts +18 -5
  67. package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
  68. package/src/input/commands/agent-skills-runtime.ts +60 -3
  69. package/src/input/commands/calendar-runtime.ts +209 -0
  70. package/src/input/commands/channels-runtime.ts +1 -0
  71. package/src/input/commands/command-error.ts +9 -0
  72. package/src/input/commands/compat-runtime.ts +1 -0
  73. package/src/input/commands/config.ts +1 -0
  74. package/src/input/commands/conversation-runtime.ts +1 -1
  75. package/src/input/commands/delegation-runtime.ts +5 -6
  76. package/src/input/commands/email-runtime.ts +387 -0
  77. package/src/input/commands/experience-runtime.ts +17 -4
  78. package/src/input/commands/guidance-runtime.ts +1 -1
  79. package/src/input/commands/health-runtime.ts +6 -1
  80. package/src/input/commands/knowledge-format.ts +73 -0
  81. package/src/input/commands/knowledge.ts +9 -74
  82. package/src/input/commands/local-provider-runtime.ts +2 -1
  83. package/src/input/commands/local-runtime.ts +10 -4
  84. package/src/input/commands/mcp-runtime.ts +7 -0
  85. package/src/input/commands/notify-runtime.ts +17 -1
  86. package/src/input/commands/onboarding-runtime.ts +1 -0
  87. package/src/input/commands/operator-actions-runtime.ts +1 -0
  88. package/src/input/commands/operator-runtime.ts +3 -0
  89. package/src/input/commands/personas-runtime.ts +1 -0
  90. package/src/input/commands/platform-access-runtime.ts +40 -17
  91. package/src/input/commands/product-runtime.ts +6 -1
  92. package/src/input/commands/provider-accounts-runtime.ts +3 -2
  93. package/src/input/commands/qrcode-runtime.ts +1 -0
  94. package/src/input/commands/routines-runtime.ts +1 -0
  95. package/src/input/commands/runtime-services.ts +0 -13
  96. package/src/input/commands/security-runtime.ts +1 -0
  97. package/src/input/commands/session-content.ts +1 -0
  98. package/src/input/commands/shell-core.ts +5 -2
  99. package/src/input/commands/subscription-runtime.ts +33 -9
  100. package/src/input/commands/support-bundle-runtime.ts +8 -1
  101. package/src/input/commands/tasks-runtime.ts +1 -0
  102. package/src/input/commands/tts-runtime.ts +1 -0
  103. package/src/input/commands/vibe-runtime.ts +1 -0
  104. package/src/input/commands.ts +4 -0
  105. package/src/input/feed-context-factory.ts +3 -12
  106. package/src/input/handler-command-route.ts +7 -60
  107. package/src/input/handler-feed-routes.ts +0 -194
  108. package/src/input/handler-feed.ts +2 -54
  109. package/src/input/handler-interactions.ts +0 -2
  110. package/src/input/handler-modal-stack.ts +0 -9
  111. package/src/input/handler-picker-routes.ts +24 -1
  112. package/src/input/handler-shortcuts.ts +11 -40
  113. package/src/input/handler-ui-state.ts +13 -0
  114. package/src/input/handler.ts +8 -35
  115. package/src/input/keybindings.ts +40 -17
  116. package/src/input/model-picker-local-fit.ts +130 -0
  117. package/src/input/submission-router.ts +0 -5
  118. package/src/main.ts +111 -89
  119. package/src/renderer/activity-sidebar.ts +186 -0
  120. package/src/renderer/agent-workspace-context-lines.ts +5 -48
  121. package/src/renderer/agent-workspace-style.ts +1 -1
  122. package/src/renderer/agent-workspace.ts +14 -2
  123. package/src/renderer/compositor.ts +37 -125
  124. package/src/renderer/conversation-overlays.ts +3 -3
  125. package/src/renderer/help-overlay.ts +7 -5
  126. package/src/renderer/model-workspace.ts +101 -86
  127. package/src/{panels → renderer}/polish.ts +3 -3
  128. package/src/renderer/shell-surface.ts +4 -5
  129. package/src/renderer/status-token.ts +31 -11
  130. package/src/renderer/tab-strip.ts +1 -1
  131. package/src/renderer/tool-call.ts +7 -8
  132. package/src/renderer/tool-labels.ts +92 -0
  133. package/src/renderer/ui-factory.ts +48 -96
  134. package/src/runtime/bootstrap-command-context.ts +0 -5
  135. package/src/runtime/bootstrap-command-parts.ts +6 -15
  136. package/src/runtime/bootstrap-core.ts +34 -13
  137. package/src/runtime/bootstrap-hook-bridge.ts +3 -1
  138. package/src/runtime/bootstrap-shell.ts +3 -50
  139. package/src/runtime/bootstrap.ts +3 -4
  140. package/src/runtime/context.ts +1 -1
  141. package/src/runtime/diagnostics/panels/index.ts +0 -1
  142. package/src/runtime/diagnostics/panels/policy.ts +1 -1
  143. package/src/runtime/execution-ledger.ts +16 -1
  144. package/src/runtime/index.ts +6 -1
  145. package/src/runtime/onboarding/index.ts +1 -0
  146. package/src/runtime/onboarding/onboarding-state.ts +200 -0
  147. package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
  148. package/src/runtime/services.ts +16 -4
  149. package/src/runtime/terminal-output-guard.ts +7 -0
  150. package/src/runtime/tool-permission-safety.ts +1 -1
  151. package/src/runtime/ui/model-picker/data-provider.ts +1 -1
  152. package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
  153. package/src/runtime/ui/model-picker/types.ts +2 -2
  154. package/src/runtime/ui/provider-health/data-provider.ts +3 -3
  155. package/src/runtime/ui/provider-health/types.ts +2 -2
  156. package/src/runtime/ui-services.ts +0 -2
  157. package/src/shell/agent-workspace-fullscreen.ts +0 -1
  158. package/src/shell/autonomy-surfacing.ts +272 -0
  159. package/src/shell/session-continuity-hints.ts +0 -6
  160. package/src/shell/startup-wiring.ts +221 -0
  161. package/src/shell/ui-openers.ts +18 -29
  162. package/src/tools/agent-context-policy.ts +1 -1
  163. package/src/tools/agent-harness-background-processes.ts +4 -4
  164. package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
  165. package/src/tools/agent-harness-command-runner.ts +6 -1
  166. package/src/tools/agent-harness-document-ops.ts +26 -53
  167. package/src/tools/agent-harness-execution-history.ts +1 -13
  168. package/src/tools/agent-harness-execution-posture.ts +0 -15
  169. package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
  170. package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
  171. package/src/tools/agent-harness-metadata.ts +16 -0
  172. package/src/tools/agent-harness-mode-catalog.ts +2 -9
  173. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  174. package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
  175. package/src/tools/agent-harness-tool-schema.ts +13 -14
  176. package/src/tools/agent-harness-tool.ts +27 -23
  177. package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
  178. package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
  179. package/src/tools/agent-workspace-tool.ts +2 -33
  180. package/src/utils/terminal-width.ts +9 -3
  181. package/src/version.ts +1 -1
  182. package/src/input/agent-workspace-panel-route.ts +0 -44
  183. package/src/input/panel-integration-actions.ts +0 -26
  184. package/src/panels/approval-panel.ts +0 -149
  185. package/src/panels/automation-control-panel.ts +0 -212
  186. package/src/panels/base-panel.ts +0 -254
  187. package/src/panels/builtin/agent.ts +0 -58
  188. package/src/panels/builtin/knowledge.ts +0 -26
  189. package/src/panels/builtin/operations.ts +0 -121
  190. package/src/panels/builtin/session.ts +0 -138
  191. package/src/panels/builtin/shared.ts +0 -275
  192. package/src/panels/builtin/usage.ts +0 -21
  193. package/src/panels/builtin-panels.ts +0 -23
  194. package/src/panels/confirm-state.ts +0 -61
  195. package/src/panels/context-visualizer-panel.ts +0 -204
  196. package/src/panels/cost-tracker-panel.ts +0 -444
  197. package/src/panels/docs-panel.ts +0 -285
  198. package/src/panels/index.ts +0 -25
  199. package/src/panels/knowledge-panel.ts +0 -417
  200. package/src/panels/memory-panel.ts +0 -226
  201. package/src/panels/panel-list-panel.ts +0 -464
  202. package/src/panels/panel-manager.ts +0 -570
  203. package/src/panels/provider-accounts-panel.ts +0 -233
  204. package/src/panels/provider-health-domains.ts +0 -208
  205. package/src/panels/provider-health-panel.ts +0 -720
  206. package/src/panels/provider-health-tracker.ts +0 -115
  207. package/src/panels/provider-stats-panel.ts +0 -366
  208. package/src/panels/qr-panel.ts +0 -207
  209. package/src/panels/schedule-panel.ts +0 -321
  210. package/src/panels/scrollable-list-panel.ts +0 -491
  211. package/src/panels/search-focus.ts +0 -32
  212. package/src/panels/security-panel.ts +0 -295
  213. package/src/panels/session-browser-panel.ts +0 -395
  214. package/src/panels/session-maintenance.ts +0 -125
  215. package/src/panels/subscription-panel.ts +0 -263
  216. package/src/panels/system-messages-panel.ts +0 -230
  217. package/src/panels/tasks-panel.ts +0 -344
  218. package/src/panels/thinking-panel.ts +0 -304
  219. package/src/panels/token-budget-panel.ts +0 -475
  220. package/src/panels/tool-inspector-panel.ts +0 -436
  221. package/src/panels/types.ts +0 -54
  222. package/src/renderer/panel-composite.ts +0 -158
  223. package/src/renderer/panel-tab-bar.ts +0 -69
  224. package/src/renderer/panel-workspace-bar.ts +0 -42
  225. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  226. package/src/tools/agent-harness-panel-metadata.ts +0 -211
  227. /package/src/runtime/perf/{panel-health-monitor.ts → component-health.ts} +0 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * LastSeenStore — persists the timestamp of the user's last TUI session.
3
+ *
4
+ * Used by the away-digest feature to know what happened since the user was
5
+ * last present. Follows the same file-backed JSON pattern as the agent
6
+ * registries (see src/agent/routine-registry.ts).
7
+ *
8
+ * File layout:
9
+ * { version: 1, lastSeenAt: <epoch-ms> }
10
+ */
11
+
12
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
13
+ import { dirname } from 'node:path';
14
+ import type { ShellPathService } from '@/runtime/index.ts';
15
+ import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
16
+
17
+ interface LastSeenFile {
18
+ readonly version: 1;
19
+ readonly lastSeenAt: number;
20
+ }
21
+
22
+ function isRecord(value: unknown): value is Record<string, unknown> {
23
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
24
+ }
25
+
26
+ function parseFile(raw: string): LastSeenFile | null {
27
+ try {
28
+ const parsed: unknown = JSON.parse(raw);
29
+ if (!isRecord(parsed)) return null;
30
+ if (parsed['version'] !== 1) return null;
31
+ const ts = parsed['lastSeenAt'];
32
+ if (typeof ts !== 'number' || !Number.isFinite(ts) || ts <= 0) return null;
33
+ return { version: 1, lastSeenAt: ts };
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ type AgentLocalStorePaths = Pick<ShellPathService, 'resolveUserPath'>;
40
+
41
+ export function lastSeenStorePath(shellPaths: AgentLocalStorePaths): string {
42
+ return shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'last-seen.json');
43
+ }
44
+
45
+ export class LastSeenStore {
46
+ public constructor(private readonly storePath: string) {}
47
+
48
+ public static fromShellPaths(shellPaths: AgentLocalStorePaths): LastSeenStore {
49
+ return new LastSeenStore(lastSeenStorePath(shellPaths));
50
+ }
51
+
52
+ /**
53
+ * Read the persisted lastSeenAt value.
54
+ * Returns null when the file doesn't exist or is corrupt (first run).
55
+ */
56
+ public read(): number | null {
57
+ try {
58
+ const raw = readFileSync(this.storePath, 'utf-8');
59
+ return parseFile(raw)?.lastSeenAt ?? null;
60
+ } catch {
61
+ return null;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Persist the current time as the new lastSeenAt.
67
+ * Silently ignores write errors to avoid crashing on shutdown.
68
+ */
69
+ public save(at: number = Date.now()): void {
70
+ try {
71
+ mkdirSync(dirname(this.storePath), { recursive: true });
72
+ const data: LastSeenFile = { version: 1, lastSeenAt: at };
73
+ writeFileSync(this.storePath, JSON.stringify(data, null, 2), 'utf-8');
74
+ } catch {
75
+ // Silently ignore — last-seen is a best-effort hint, not critical state.
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Plain-language vocabulary gate.
3
+ *
4
+ * Exports the banned-term lists and a validate helper so that the release-gate
5
+ * test and any future caller share a single definition.
6
+ *
7
+ * WHY EACH TERM IS BANNED
8
+ * ───────────────────────
9
+ * FIRST_GLANCE_BANNED — terms the user sees on labels, summaries, and action
10
+ * labels (the copy they read without clicking through). These must never appear
11
+ * in first-glance copy because they are internal implementation vocabulary that
12
+ * a non-technical user would not understand or would find confusing:
13
+ *
14
+ * WRFC — internal code-review workflow acronym, never user-facing
15
+ * daemon — Unix process jargon; user-facing name is "assistant service"
16
+ * posture — internal policy/config term; meaningless to end users
17
+ * modelRoute — internal routing key; end users pick a "model", not a "route"
18
+ * agent_harness — raw tool identifier; end users never see tool names
19
+ * action:" — raw tool parameter syntax that leaks protocol details
20
+ * mode:" — raw tool parameter syntax that leaks protocol details
21
+ * cli — developer-facing term; never appears on operator UX labels
22
+ *
23
+ * EVERYWHERE_BANNED — terms that must not appear even in action detail copy
24
+ * (which technical users may read after clicking through):
25
+ *
26
+ * WRFC — internal workflow acronym with no end-user meaning
27
+ * modelRoute — internal routing key never intended for user-facing copy
28
+ */
29
+
30
+ export const FIRST_GLANCE_BANNED: readonly RegExp[] = [
31
+ /\bWRFC\b/,
32
+ /\bdaemon\b/i,
33
+ /\bposture\b/i,
34
+ /\bmodelRoute\b/,
35
+ /\bagent_harness\b/,
36
+ /action:"/,
37
+ /mode:"/,
38
+ /\bcli\b/i,
39
+ ];
40
+
41
+ export const EVERYWHERE_BANNED: readonly RegExp[] = [
42
+ /\bWRFC\b/,
43
+ /\bmodelRoute\b/,
44
+ ];
45
+
46
+ /**
47
+ * Return the subset of rules that match `text`.
48
+ * Returns an empty array when there are no violations.
49
+ */
50
+ export function validate(text: string, rules: readonly RegExp[]): RegExp[] {
51
+ return rules.filter((rule) => rule.test(text));
52
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Pure builder for the "setup not finished" hint shown once at startup
3
+ * when the user has started but not completed onboarding.
4
+ *
5
+ * No side effects, no imports from the runtime or shell — testable in isolation.
6
+ */
7
+
8
+ import type { OnboardingState } from '../runtime/onboarding/onboarding-state.ts';
9
+
10
+ export interface SetupIncompleteHintResult {
11
+ readonly lines: string[];
12
+ }
13
+
14
+ /**
15
+ * Build a plain-language hint reminding the user that setup isn't finished
16
+ * and pointing them at /agent.
17
+ *
18
+ * Returns null when:
19
+ * - phase === 'complete' — setup is done, no nag needed
20
+ * - phase === 'fresh' — first-run users get the full workspace, not a nag
21
+ *
22
+ * Only phase === 'in-progress' produces a hint (the user has opened /agent
23
+ * at least once but hasn't finished).
24
+ *
25
+ * @param state The current OnboardingState (from deriveOnboardingState).
26
+ * @param hostReady True = assistant service is reachable; false = not yet running;
27
+ * null/undefined = unknown (omit the host line entirely).
28
+ */
29
+ export function buildSetupIncompleteHint(
30
+ state: OnboardingState,
31
+ hostReady?: boolean | null,
32
+ ): SetupIncompleteHintResult | null {
33
+ if (state.phase !== 'in-progress') return null;
34
+
35
+ const lines: string[] = [];
36
+
37
+ // ── Line 1: readiness / chat availability ────────────────────────────────
38
+ if (!state.readyToChat) {
39
+ // Model not configured — that's the most urgent thing.
40
+ lines.push('Pick a model to start — run /agent to continue setup.');
41
+ } else {
42
+ // Chat works but setup isn't done.
43
+ // NOTE: progressLabel is intentionally omitted here — the hint's plan may be
44
+ // a reduced subset of the full setup plan, so any 'N of M' count would
45
+ // misrepresent real progress and mislead the user.
46
+ const nextStep = pickNextStep(state);
47
+ if (nextStep) {
48
+ lines.push(
49
+ `You can chat now. Still finishing setup — ${nextStep} — run /agent to complete it.`,
50
+ );
51
+ } else {
52
+ lines.push(
53
+ 'You can chat now. Some background features still need setup — run /agent to finish.',
54
+ );
55
+ }
56
+ }
57
+
58
+ // ── Line 2 (optional): assistant service / background work status ─────────
59
+ // Only append when the caller has a reliable live signal. Never fabricate.
60
+ if (hostReady === true) {
61
+ lines.push('Background work (reminders, schedules) is active.');
62
+ } else if (hostReady === false) {
63
+ lines.push('Background work (reminders, schedules) is not running yet.');
64
+ }
65
+ // hostReady === null or undefined → omit line entirely.
66
+
67
+ return { lines };
68
+ }
69
+
70
+ /**
71
+ * Pick the single most actionable next-step phrase from the state.
72
+ * Prefers the first autonomy-blocking step, then the first non-ready step.
73
+ * Returns undefined when no useful step hint is available.
74
+ */
75
+ function pickNextStep(state: OnboardingState): string | undefined {
76
+ const step =
77
+ state.blockers[0] ??
78
+ state.steps.find((s) => s.status !== 'ready');
79
+
80
+ if (!step) return undefined;
81
+
82
+ // Use the step's nextLabel if it reads like plain language (no slash syntax).
83
+ // Fall back to the step's label.
84
+ const label = step.nextLabel && !step.nextLabel.startsWith('/') && !step.nextLabel.includes('action:')
85
+ ? step.nextLabel
86
+ : step.label;
87
+
88
+ // Truncate to keep the hint compact (max ~60 chars for the next-step phrase).
89
+ return label.length > 60 ? `${label.slice(0, 58)}…` : label;
90
+ }
@@ -1,37 +1,25 @@
1
1
  /**
2
- * SystemMessageRouter — routes system messages to the appropriate surfaces
3
- * based on priority.
2
+ * SystemMessageRouter — routes system messages to the right surfaces.
4
3
  *
5
- * Two tiers:
6
- * - 'high' appears in both the main conversation AND the SystemMessagesPanel.
7
- * Use for: fatal errors, model/provider confirmations, session save/load,
8
- * compaction events (e.g. [Compaction] completed).
9
- * - 'low' — appears in the SystemMessagesPanel only (panel-only routing).
10
- * Use for: scan results, provider discovery, plugin load/unload, feature
11
- * flag changes, tool execution status, permission decisions,
12
- * health/cascade events, debug/operational info.
13
- *
14
- * Usage:
15
- * ```ts
16
- * const router = createSystemMessageRouter(conversation, panel);
17
- * router.routeSystemMessage('[Provider] anthropic registered', 'low');
18
- * router.routeSystemMessage('[Session] Saved session abc123', 'high');
19
- * ```
4
+ * Every message lands in the ActivityFeed (the ambient "Recent" record shown
5
+ * in the Activity sidebar). High-priority messages errors, confirmations the
6
+ * user explicitly caused, session lifecycle additionally land in the main
7
+ * conversation so they are impossible to miss.
20
8
  *
21
- * The router can also be used as a drop-in replacement for
22
- * conversation.addSystemMessage() calls it classifies messages by priority
23
- * automatically when using routeAuto().
9
+ * Two tiers:
10
+ * - 'high' — conversation AND activity feed. Use for: fatal errors,
11
+ * model/provider confirmations, session save/load, compaction events.
12
+ * - 'low' — activity feed only. Use for: scan results, provider discovery,
13
+ * plugin load/unload, tool execution status, permission decisions,
14
+ * health events, debug/operational info.
24
15
  *
25
- * @remarks
26
- * This router handles system messages (operational status, errors). It is
27
- * distinct from NotificationRouter which handles domain-specific typed
28
- * notifications with policy-based routing.
16
+ * The `ui.systemMessages` / `ui.operationalMessages` settings keep their
17
+ * historical values ('panel' | 'conversation' | 'both'); 'panel' now means
18
+ * "activity feed only".
29
19
  */
30
20
 
31
- import { getConfigSnapshot } from '../config/index.ts';
32
- import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
33
21
  import type { ConversationManager } from './conversation';
34
- import type { SystemMessagesPanel, SystemMessagePriority } from '../panels/system-messages-panel.ts';
22
+ import type { ActivityFeed } from './activity-feed.ts';
35
23
  import {
36
24
  classifySystemMessageKind,
37
25
  classifySystemMessagePriority,
@@ -46,51 +34,30 @@ export type {
46
34
  SystemMessageTarget,
47
35
  } from '@/runtime/index.ts';
48
36
 
49
- function targetForKind(
50
- configManager: Pick<ConfigManager, 'getRaw'>,
51
- kind: SystemMessageKind,
52
- ): SystemMessageTarget {
53
- const ui = getConfigSnapshot(configManager).ui;
54
- if (kind === 'wrfc') return ui.wrfcMessages;
55
- if (kind === 'operational') return ui.operationalMessages;
56
- return ui.systemMessages;
57
- }
58
-
59
- // ---------------------------------------------------------------------------
60
- // SystemMessageRouter
61
- // ---------------------------------------------------------------------------
37
+ export type SystemMessagePriority = 'high' | 'low';
62
38
 
63
39
  /**
64
- * Routes system messages to the conversation and/or the SystemMessagesPanel
65
- * based on priority level.
40
+ * Routes system messages to the conversation and/or the ActivityFeed
41
+ * based on priority level and per-kind targets.
66
42
  */
67
43
  export class SystemMessageRouter {
68
44
  constructor(
69
45
  private readonly conversation: ConversationManager,
70
- private panel: SystemMessagesPanel | null,
46
+ private feed: ActivityFeed | null,
71
47
  private readonly getTargetForKind: (kind: SystemMessageKind) => SystemMessageTarget = defaultSystemMessageTarget,
72
48
  ) {}
73
49
 
74
- // ── Public API ────────────────────────────────────────────────────────────
50
+ // ── Public API ────────────────────────────────────────────────────────────────
75
51
 
76
- /**
77
- * Route a system message with explicit priority.
78
- *
79
- * - 'high': delivered to both conversation AND panel.
80
- * - 'low': delivered to panel only (conversation is not touched).
81
- *
82
- * @param message - Message text.
83
- * @param priority - 'high' | 'low'.
84
- */
85
52
  routeTypedSystemMessage(
86
53
  message: string,
87
54
  priority: SystemMessagePriority,
88
55
  kind: SystemMessageKind,
89
56
  ): void {
90
57
  const target = this.getTargetForKind(kind);
91
- const delivery = resolveSystemMessageDelivery(target, this.panel !== null);
58
+ const delivery = resolveSystemMessageDelivery(target, this.feed !== null);
92
59
  if (delivery.toPanel) {
93
- this.panel?.push(message, priority);
60
+ this.feed?.push(message, priority);
94
61
  }
95
62
  if (delivery.toConversation) {
96
63
  this.conversation.addSystemMessage(message);
@@ -103,29 +70,19 @@ export class SystemMessageRouter {
103
70
 
104
71
  /**
105
72
  * Automatically classify the message priority by content and route.
106
- *
107
- * Useful as a drop-in replacement for conversation.addSystemMessage()
108
- * when you want the router to determine priority.
109
- *
110
- * @param message - Message text.
73
+ * Drop-in replacement for conversation.addSystemMessage().
111
74
  */
112
75
  routeAuto(message: string): void {
113
76
  const priority: SystemMessagePriority = classifySystemMessagePriority(message);
114
77
  this.routeTypedSystemMessage(message, priority, classifySystemMessageKind(message));
115
78
  }
116
79
 
117
- /**
118
- * High-priority convenience shortcut.
119
- * Equivalent to routeSystemMessage(message, 'high').
120
- */
80
+ /** High-priority shortcut — conversation + activity feed. */
121
81
  high(message: string): void {
122
82
  this.routeSystemMessage(message, 'high');
123
83
  }
124
84
 
125
- /**
126
- * Low-priority convenience shortcut.
127
- * Equivalent to routeSystemMessage(message, 'low').
128
- */
85
+ /** Low-priority shortcut — activity feed only. */
129
86
  low(message: string): void {
130
87
  this.routeSystemMessage(message, 'low');
131
88
  }
@@ -134,38 +91,32 @@ export class SystemMessageRouter {
134
91
  this.routeTypedSystemMessage(message, priority, 'wrfc');
135
92
  }
136
93
 
137
- /**
138
- * Returns the current panel reference.
139
- */
140
- getPanel(): SystemMessagesPanel | null {
141
- return this.panel;
94
+ /** Returns the current activity feed reference. */
95
+ getFeed(): ActivityFeed | null {
96
+ return this.feed;
142
97
  }
143
98
 
144
99
  /**
145
- * Replace the panel reference after construction (late binding).
146
- * Pass null to detach the panel.
100
+ * Replace the feed reference after construction (late binding).
101
+ * Pass null to detach.
147
102
  */
148
- setPanel(panel: SystemMessagesPanel | null): void {
149
- this.panel = panel;
103
+ setFeed(feed: ActivityFeed | null): void {
104
+ this.feed = feed;
150
105
  }
151
106
  }
152
107
 
153
- // ---------------------------------------------------------------------------
154
- // Factory
155
- // ---------------------------------------------------------------------------
156
-
157
108
  /**
158
- * Create a SystemMessageRouter wired to the given conversation and panel.
109
+ * Create a SystemMessageRouter wired to the given conversation and feed.
159
110
  *
160
111
  * @param conversation - The ConversationManager for high-priority messages.
161
- * @param panel - The SystemMessagesPanel for all messages. Can be null
162
- * (router still works; messages to panel are silently
163
- * dropped until a panel is available).
112
+ * @param feed - The ActivityFeed for ambient traffic. Can be null
113
+ * (router still works; feed routing is dropped until
114
+ * a feed is attached).
164
115
  */
165
116
  export function createSystemMessageRouter(
166
117
  conversation: ConversationManager,
167
- panel: SystemMessagesPanel | null = null,
118
+ feed: ActivityFeed | null = null,
168
119
  getTargetForKind: (kind: SystemMessageKind) => SystemMessageTarget = defaultSystemMessageTarget,
169
120
  ): SystemMessageRouter {
170
- return new SystemMessageRouter(conversation, panel, getTargetForKind);
121
+ return new SystemMessageRouter(conversation, feed, getTargetForKind);
171
122
  }