@pellux/goodvibes-tui 0.25.0 → 0.27.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 (146) hide show
  1. package/CHANGELOG.md +22 -3
  2. package/README.md +12 -7
  3. package/docs/foundation-artifacts/operator-contract.json +2422 -1040
  4. package/package.json +2 -2
  5. package/src/cli/bundle-command.ts +2 -1
  6. package/src/cli/service-posture.ts +2 -1
  7. package/src/core/conversation-rendering.ts +2 -2
  8. package/src/core/conversation.ts +49 -2
  9. package/src/core/session-recovery.ts +24 -18
  10. package/src/core/system-message-router.ts +42 -26
  11. package/src/core/turn-event-wiring.ts +12 -16
  12. package/src/daemon/{calendar → handlers/calendar}/caldav-client.ts +29 -24
  13. package/src/daemon/handlers/calendar/index.ts +316 -0
  14. package/src/daemon/handlers/context.ts +29 -0
  15. package/src/daemon/handlers/contracts.ts +77 -0
  16. package/src/daemon/{channels → handlers}/drafts/draft-store.ts +114 -50
  17. package/src/daemon/handlers/drafts/index.ts +17 -0
  18. package/src/daemon/handlers/drafts/register.ts +331 -0
  19. package/src/daemon/handlers/email/config.ts +164 -0
  20. package/src/daemon/handlers/email/index.ts +43 -0
  21. package/src/daemon/handlers/email/read-handlers.ts +80 -0
  22. package/src/daemon/handlers/email/runtime.ts +140 -0
  23. package/src/daemon/handlers/email/validation.ts +147 -0
  24. package/src/daemon/handlers/email/write-handlers.ts +133 -0
  25. package/src/daemon/handlers/errors.ts +18 -0
  26. package/src/daemon/{channels → handlers}/inbox/cursor-store.ts +58 -66
  27. package/src/daemon/handlers/inbox/index.ts +211 -0
  28. package/src/daemon/{channels → handlers}/inbox/mapping.ts +8 -6
  29. package/src/daemon/{channels → handlers}/inbox/poller.ts +6 -5
  30. package/src/daemon/{channels → handlers}/inbox/provider-adapter.ts +14 -10
  31. package/src/daemon/{channels → handlers}/inbox/providers/discord.ts +10 -11
  32. package/src/daemon/{channels → handlers}/inbox/providers/email.ts +2 -1
  33. package/src/daemon/{channels → handlers}/inbox/providers/imap-client.ts +1 -1
  34. package/src/daemon/{channels → handlers}/inbox/providers/route-util.ts +4 -3
  35. package/src/daemon/{channels → handlers}/inbox/providers/slack.ts +11 -12
  36. package/src/daemon/handlers/index.ts +107 -0
  37. package/src/daemon/handlers/register.ts +161 -0
  38. package/src/daemon/{remote → handlers/remote}/backends/cloud-terminal.ts +8 -3
  39. package/src/daemon/{remote → handlers/remote}/backends/docker.ts +2 -3
  40. package/src/daemon/handlers/remote/backends/index.ts +40 -0
  41. package/src/daemon/{remote → handlers/remote}/backends/process-runner.ts +16 -40
  42. package/src/daemon/{remote → handlers/remote}/backends/ssh.ts +8 -3
  43. package/src/daemon/{remote → handlers/remote}/backends/types.ts +29 -3
  44. package/src/daemon/{remote → handlers/remote}/dispatcher.ts +27 -6
  45. package/src/daemon/handlers/remote/index.ts +119 -0
  46. package/src/daemon/{remote → handlers/remote}/peer-registry.ts +47 -11
  47. package/src/daemon/handlers/remote/service.ts +191 -0
  48. package/src/daemon/{channels → handlers}/routing/inbox-bridge.ts +33 -20
  49. package/src/daemon/handlers/routing/index.ts +261 -0
  50. package/src/daemon/{channels → handlers}/routing/route-store.ts +57 -16
  51. package/src/daemon/{channels → handlers}/routing/routing-resolver.ts +1 -1
  52. package/src/daemon/{operator → handlers}/sqlite-store.ts +5 -5
  53. package/src/daemon/handlers/triage/index.ts +57 -0
  54. package/src/daemon/handlers/triage/integration.ts +213 -0
  55. package/src/daemon/{triage → handlers/triage}/pipeline.ts +60 -71
  56. package/src/daemon/{triage → handlers/triage}/scorer.ts +21 -21
  57. package/src/daemon/handlers/triage/tagger/discord.ts +187 -0
  58. package/src/daemon/handlers/triage/tagger/imap.ts +384 -0
  59. package/src/daemon/handlers/triage/tagger/index.ts +184 -0
  60. package/src/daemon/handlers/triage/tagger/shared.ts +70 -0
  61. package/src/daemon/handlers/triage/tagger/slack.ts +69 -0
  62. package/src/daemon/handlers/triage/types.ts +50 -0
  63. package/src/export/gist-uploader.ts +3 -1
  64. package/src/input/command-registry.ts +1 -0
  65. package/src/input/commands/cloudflare-runtime.ts +2 -1
  66. package/src/input/commands/guidance-runtime.ts +2 -4
  67. package/src/input/commands/health-runtime.ts +13 -7
  68. package/src/input/commands/knowledge.ts +2 -1
  69. package/src/input/commands/runtime-services.ts +40 -10
  70. package/src/input/handler-command-route.ts +1 -1
  71. package/src/input/handler-interactions.ts +2 -1
  72. package/src/input/handler-modal-routes.ts +2 -1
  73. package/src/input/handler-onboarding-cloudflare.ts +2 -1
  74. package/src/input/handler-onboarding.ts +8 -8
  75. package/src/input/handler-ui-state.ts +1 -1
  76. package/src/input/tts-settings-actions.ts +2 -1
  77. package/src/main.ts +52 -59
  78. package/src/panels/agent-inspector-panel.ts +72 -2
  79. package/src/panels/agent-logs-panel.ts +127 -19
  80. package/src/panels/base-panel.ts +2 -1
  81. package/src/panels/builtin/agent.ts +3 -1
  82. package/src/panels/builtin/development.ts +1 -0
  83. package/src/panels/builtin/session.ts +1 -1
  84. package/src/panels/context-visualizer-panel.ts +24 -14
  85. package/src/panels/cost-tracker-panel.ts +7 -13
  86. package/src/panels/debug-panel.ts +11 -22
  87. package/src/panels/docs-panel.ts +14 -24
  88. package/src/panels/file-explorer-panel.ts +2 -1
  89. package/src/panels/file-preview-panel.ts +2 -1
  90. package/src/panels/git-panel.ts +10 -17
  91. package/src/panels/marketplace-panel.ts +2 -1
  92. package/src/panels/memory-panel.ts +2 -1
  93. package/src/panels/project-planning-panel.ts +5 -4
  94. package/src/panels/provider-health-panel.ts +56 -67
  95. package/src/panels/schedule-panel.ts +4 -7
  96. package/src/panels/session-browser-panel.ts +13 -21
  97. package/src/panels/skills-panel.ts +2 -1
  98. package/src/panels/tasks-panel.ts +2 -7
  99. package/src/panels/thinking-panel.ts +6 -11
  100. package/src/panels/token-budget-panel.ts +31 -15
  101. package/src/panels/tool-inspector-panel.ts +10 -18
  102. package/src/panels/work-plan-panel.ts +2 -1
  103. package/src/panels/wrfc-panel.ts +37 -35
  104. package/src/renderer/agent-detail-modal.ts +2 -2
  105. package/src/renderer/modal-utils.ts +0 -10
  106. package/src/renderer/process-modal.ts +2 -2
  107. package/src/runtime/bootstrap-command-context.ts +3 -0
  108. package/src/runtime/bootstrap-command-parts.ts +3 -1
  109. package/src/runtime/bootstrap-core.ts +31 -31
  110. package/src/runtime/bootstrap-shell.ts +1 -0
  111. package/src/runtime/onboarding/apply.ts +4 -3
  112. package/src/runtime/onboarding/snapshot.ts +4 -3
  113. package/src/runtime/process-lifecycle.ts +195 -0
  114. package/src/runtime/services.ts +52 -36
  115. package/src/runtime/wrfc-persistence.ts +20 -5
  116. package/src/shell/ui-openers.ts +3 -2
  117. package/src/verification/live-verifier.ts +4 -3
  118. package/src/version.ts +1 -1
  119. package/src/core/context-auto-compact.ts +0 -110
  120. package/src/daemon/calendar/index.ts +0 -52
  121. package/src/daemon/calendar/register.ts +0 -527
  122. package/src/daemon/channels/drafts/index.ts +0 -22
  123. package/src/daemon/channels/drafts/register.ts +0 -449
  124. package/src/daemon/channels/inbox/index.ts +0 -58
  125. package/src/daemon/channels/inbox/register.ts +0 -247
  126. package/src/daemon/channels/routing/index.ts +0 -39
  127. package/src/daemon/channels/routing/register.ts +0 -296
  128. package/src/daemon/email/index.ts +0 -68
  129. package/src/daemon/email/register.ts +0 -715
  130. package/src/daemon/operator/index.ts +0 -43
  131. package/src/daemon/operator/register-helper.ts +0 -150
  132. package/src/daemon/operator/surfaces.ts +0 -137
  133. package/src/daemon/operator/types.ts +0 -207
  134. package/src/daemon/remote/backends/index.ts +0 -34
  135. package/src/daemon/remote/index.ts +0 -74
  136. package/src/daemon/remote/register.ts +0 -411
  137. package/src/daemon/triage/index.ts +0 -59
  138. package/src/daemon/triage/integration.ts +0 -179
  139. package/src/daemon/triage/register.ts +0 -231
  140. package/src/daemon/triage/tagger.ts +0 -777
  141. /package/src/daemon/{calendar → handlers/calendar}/ics.ts +0 -0
  142. /package/src/daemon/{operator/credential-store.ts → handlers/credentials.ts} +0 -0
  143. /package/src/daemon/{email → handlers/email}/imap-connector.ts +0 -0
  144. /package/src/daemon/{email → handlers/email}/imap-parsing.ts +0 -0
  145. /package/src/daemon/{email → handlers/email}/smtp-connector.ts +0 -0
  146. /package/src/daemon/{remote → handlers/remote}/backends/local-process.ts +0 -0
@@ -7,15 +7,6 @@ import { AutomationDeliveryManager, AutomationManager, AutomationRouteStore } fr
7
7
  import { ChannelPluginRegistry, ChannelPolicyManager, RouteBindingManager, SurfaceRegistry } from '@pellux/goodvibes-sdk/platform/channels';
8
8
  import { ChannelDeliveryRouter } from '@pellux/goodvibes-sdk/platform/channels';
9
9
  import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
10
- import {
11
- registerDaemonOperatorSurfaces,
12
- type DaemonOperatorSurfaces,
13
- } from '../daemon/operator/surfaces.ts';
14
- import type {
15
- OperatorContext,
16
- OperatorLogger,
17
- } from '../daemon/operator/index.ts';
18
- import { attachRemoteInvokeRoute } from '../daemon/remote/index.ts';
19
10
  import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
20
11
  import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
21
12
  import {
@@ -72,6 +63,7 @@ import { CacheHitTracker } from '@pellux/goodvibes-sdk/platform/providers';
72
63
  import { FavoritesStore } from '@pellux/goodvibes-sdk/platform/providers';
73
64
  import { BenchmarkStore } from '@pellux/goodvibes-sdk/platform/providers';
74
65
  import { ModelLimitsService } from '@pellux/goodvibes-sdk/platform/providers';
66
+ import { inferFallbackContextWindow } from '@pellux/goodvibes-sdk/platform/providers';
75
67
  import { KeybindingsManager } from '../input/keybindings.ts';
76
68
  import { SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
77
69
  import { SessionLineageTracker } from '@pellux/goodvibes-sdk/platform/core';
@@ -96,6 +88,19 @@ import {
96
88
  type WorkflowServices,
97
89
  } from '@pellux/goodvibes-sdk/platform/tools';
98
90
  import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
91
+ import {
92
+ registerDaemonHandlers,
93
+ type DaemonHandlerSurfaces,
94
+ } from '../daemon/handlers/index.ts';
95
+ import type { HandlerContext, HandlerLogger } from '../daemon/handlers/context.ts';
96
+ import { createDaemonCredentialStore } from '../daemon/handlers/credentials.ts';
97
+ import { registerRouting } from '../daemon/handlers/routing/index.ts';
98
+ import { registerInboxMethods } from '../daemon/handlers/inbox/index.ts';
99
+ import { registerTriagedInbox } from '../daemon/handlers/triage/index.ts';
100
+ import { registerDraftMethods } from '../daemon/handlers/drafts/index.ts';
101
+ import { registerCalendar } from '../daemon/handlers/calendar/index.ts';
102
+ import { registerEmailMethods } from '../daemon/handlers/email/index.ts';
103
+ import { registerRemoteSurface } from '../daemon/handlers/remote/index.ts';
99
104
 
100
105
  const REGULAR_KNOWLEDGE_DB_FILE = 'knowledge-wiki.sqlite';
101
106
  const HOME_GRAPH_KNOWLEDGE_DB_FILE = 'knowledge-home-graph.sqlite';
@@ -119,7 +124,9 @@ function buildFallbackModelDefinition(provider: string, modelId: string): ModelD
119
124
  reasoning: isReasoningProvider,
120
125
  multimodal: isReasoningProvider,
121
126
  },
122
- contextWindow: isReasoningProvider ? 128_000 : 32_000,
127
+ // Pre-catalog fallback uses the SDK's family-aware inference (SDK 0.35.0+),
128
+ // matching the post-catalog window so the meter/compaction denominator agrees.
129
+ contextWindow: inferFallbackContextWindow(provider, modelId),
123
130
  contextWindowProvenance: 'fallback',
124
131
  selectable: true,
125
132
  tier: 'standard',
@@ -178,7 +185,6 @@ export interface RuntimeServices {
178
185
  readonly deliveryManager: AutomationDeliveryManager;
179
186
  readonly automationManager: AutomationManager;
180
187
  readonly gatewayMethods: GatewayMethodCatalog;
181
- readonly operatorSurfaces: DaemonOperatorSurfaces;
182
188
  readonly artifactStore: ArtifactStore;
183
189
  readonly knowledgeService: KnowledgeService;
184
190
  readonly agentKnowledgeService: KnowledgeService;
@@ -225,6 +231,7 @@ export interface RuntimeServices {
225
231
  readonly providerRegistry: ProviderRegistry;
226
232
  readonly toolLLM: ToolLLM;
227
233
  readonly distributedRuntime: DistributedRuntimeManager;
234
+ readonly daemonHandlers: DaemonHandlerSurfaces;
228
235
  readonly remoteRunnerRegistry: RemoteRunnerRegistry;
229
236
  readonly remoteSupervisor: RemoteSupervisor;
230
237
  readonly sessionMemoryStore: SessionMemoryStore;
@@ -281,30 +288,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
281
288
  globalHome: homeDirectory,
282
289
  configManager,
283
290
  });
284
- // Wire the daemon operator surfaces (routing / triaged inbox / drafts /
285
- // calendar / email / remote) against the shared gateway-method catalog. Each
286
- // surface initializes its stores lazily, so this stays synchronous.
287
- const operatorLogger: OperatorLogger = {
288
- info: (msg, meta) => console.info(`[operator] ${msg}`, meta ?? ''),
289
- warn: (msg, meta) => console.warn(`[operator] ${msg}`, meta ?? ''),
290
- error: (msg, meta) => console.error(`[operator] ${msg}`, meta ?? ''),
291
- };
292
- const operatorContext: OperatorContext = {
293
- catalog: gatewayMethods,
294
- secrets: secretsManager,
295
- configManager,
296
- workingDirectory,
297
- homeDirectory,
298
- logger: operatorLogger,
299
- };
300
- const operatorSurfaces = registerDaemonOperatorSurfaces(operatorContext);
301
- // Wire the remote.peers.invoke route to the remote dispatch adapter, replacing
302
- // the SDK builtin stub. This is the single faithful integration point: the
303
- // DaemonHttpRouter resolves POST /api/remote/peers/{peerId}/invoke to
304
- // catalog.invoke('remote.peers.invoke', ...), which now reaches the
305
- // Docker/SSH/cloud-terminal/local-process backends via the dispatch adapter
306
- // (which enforces confirm:true + explicitUserRequest before dispatch).
307
- attachRemoteInvokeRoute(gatewayMethods, operatorSurfaces.remoteDispatch);
308
291
  const subscriptionManager = new SubscriptionManager(
309
292
  shellPaths.resolveUserPath('tui', 'subscriptions.json'),
310
293
  );
@@ -551,6 +534,39 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
551
534
  approvalBridge: approvalBroker,
552
535
  automationBridge: automationManager,
553
536
  });
537
+
538
+ // Daemon handler surfaces: attach HOST handlers to the SDK-auto-registered
539
+ // builtin gateway descriptors (channels.* / email.* / calendar.*). The SDK
540
+ // owns every id/descriptor/schema; this only fills the handler slot via
541
+ // catalog.register(descriptor, handler, { replace: true }). Routing returns
542
+ // the resolver the inbox surface consumes; triage decorates channels.inbox.list.
543
+ // The remote surface reuses the SAME DistributedRuntimeManager the SDK facade
544
+ // injects, so its peer/work methods share one persistent store; remote.peers.*
545
+ // stay SDK-published routes (not catalog methods).
546
+ const handlerLogger: HandlerLogger = {
547
+ info: (message, meta) => console.info(message, meta ?? ''),
548
+ warn: (message, meta) => console.warn(message, meta ?? ''),
549
+ error: (message, meta) => console.error(message, meta ?? ''),
550
+ };
551
+ const handlerContext: HandlerContext = {
552
+ catalog: gatewayMethods,
553
+ credentials: createDaemonCredentialStore(secretsManager),
554
+ configManager,
555
+ workingDirectory,
556
+ homeDirectory,
557
+ logger: handlerLogger,
558
+ };
559
+ const daemonHandlers = registerDaemonHandlers(handlerContext, {
560
+ registerRouting,
561
+ registerInbox: (ctx, routing) =>
562
+ registerTriagedInbox(ctx, (inboxCtx) => registerInboxMethods(inboxCtx, routing))
563
+ .unregister,
564
+ registerDrafts: (ctx) => registerDraftMethods(ctx),
565
+ registerCalendar,
566
+ registerEmail: (ctx) => registerEmailMethods(ctx),
567
+ registerRemote: (ctx) => registerRemoteSurface(ctx, { manager: distributedRuntime }),
568
+ });
569
+
554
570
  const remoteRunnerRegistry = new RemoteRunnerRegistry(agentManager);
555
571
  const remoteSupervisor = new RemoteSupervisor(remoteRunnerRegistry);
556
572
  const sandboxSessionRegistry = new SandboxSessionRegistry(workingDirectory);
@@ -657,7 +673,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
657
673
  deliveryManager,
658
674
  automationManager,
659
675
  gatewayMethods,
660
- operatorSurfaces,
661
676
  artifactStore,
662
677
  knowledgeService,
663
678
  agentKnowledgeService,
@@ -704,6 +719,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
704
719
  providerRegistry,
705
720
  toolLLM,
706
721
  distributedRuntime,
722
+ daemonHandlers,
707
723
  remoteRunnerRegistry,
708
724
  remoteSupervisor,
709
725
  sessionMemoryStore,
@@ -10,10 +10,11 @@
10
10
  *
11
11
  * 2. `WrfcPersistence.rehydrate(router)` is called once on boot (after the
12
12
  * SystemMessageRouter is available). It reads the snapshot, identifies
13
- * chains that were in a non-terminal state at last write, and emits a
14
- * high-priority 'wrfc' system message per interrupted chain. The
15
- * `interruptedChains` accessor makes the data available for panel reads
16
- * without coupling this module to wrfc-panel.ts.
13
+ * chains that were in a non-terminal state at last write, emits a
14
+ * high-priority 'wrfc' system message per interrupted chain, and re-imports
15
+ * each interrupted chain into the WrfcController so it reappears as a panel
16
+ * row and can be resumed by the operator. The `interruptedChains` accessor
17
+ * additionally exposes the recovered set for inspection.
17
18
  *
18
19
  * 3. Snapshot lifecycle:
19
20
  * - Terminal chains ('passed' | 'failed') are pruned from the snapshot
@@ -57,6 +58,14 @@ interface WrfcSnapshot {
57
58
  /** Subset of WrfcController needed by this module. */
58
59
  export interface WrfcControllerReader {
59
60
  listChains(): WrfcChain[];
61
+ /**
62
+ * Re-import a chain recovered from a previous process so it reappears in the
63
+ * controller's in-memory map and becomes selectable/resumable from the panel.
64
+ * Optional so read-only test doubles can omit it; the real WrfcController
65
+ * provides it. `force` is left at its default — on a fresh start the map is
66
+ * empty so importing never clobbers a live chain.
67
+ */
68
+ importChain?(chain: WrfcChain, force?: boolean): boolean;
60
69
  }
61
70
 
62
71
  export interface WrfcPersistenceOptions {
@@ -64,7 +73,7 @@ export interface WrfcPersistenceOptions {
64
73
  readonly snapshotPath: string;
65
74
  /** Factory for the current SystemMessageRouter — may return null before it is wired. */
66
75
  readonly getSystemMessageRouter: () => SystemMessageRouter | null;
67
- /** WrfcController readeronly listChains() is needed. */
76
+ /** WrfcController access — listChains() (read) plus optional importChain() (re-import on rehydrate). */
68
77
  readonly controller: WrfcControllerReader;
69
78
  }
70
79
 
@@ -140,6 +149,12 @@ class WrfcPersistenceImpl implements WrfcPersistence {
140
149
 
141
150
  const router = this.getSystemMessageRouter();
142
151
  for (const chain of interrupted) {
152
+ // Re-import so the chain reappears in the controller's in-memory map and
153
+ // becomes selectable/resumable from the panel. On a fresh process start
154
+ // the map is empty, so importChain (force=false) never clobbers a live
155
+ // chain. The accessor is optional for read-only test doubles.
156
+ this.controller.importChain?.(chain);
157
+
143
158
  const msg =
144
159
  `[WRFC] Chain ${chain.id.slice(0, 12)} (${chain.task.slice(0, 60).trim()}) ` +
145
160
  `was interrupted by a restart — state was '${chain.state}' ` +
@@ -13,6 +13,7 @@ import type { SecretsManager } from '@pellux/goodvibes-sdk/platform/config';
13
13
  import type { ServiceInspectionQuery } from '../runtime/ui-service-queries.ts';
14
14
  import type { ModelPickerTargetInfo } from '../input/model-picker.ts';
15
15
  import { syncServiceSettingToPlatform } from './service-settings-sync.ts';
16
+ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
16
17
 
17
18
  type WireShellUiOpenersOptions = {
18
19
  commandContext: CommandContext;
@@ -203,7 +204,7 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
203
204
  input.modelPicker.openAllModels(models, getCurrentModelForPickerTarget());
204
205
  render();
205
206
  })().catch((error: unknown) => {
206
- commandContext.print?.(`Model picker failed to open: ${error instanceof Error ? error.message : String(error)}`);
207
+ commandContext.print?.(`Model picker failed to open: ${summarizeError(error)}`);
207
208
  render();
208
209
  });
209
210
  };
@@ -223,7 +224,7 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
223
224
  input.modelPicker.openProviders(providers, getCurrentProviderForPickerTarget());
224
225
  render();
225
226
  })().catch((error: unknown) => {
226
- commandContext.print?.(`Provider picker failed to open: ${error instanceof Error ? error.message : String(error)}`);
227
+ commandContext.print?.(`Provider picker failed to open: ${summarizeError(error)}`);
227
228
  render();
228
229
  });
229
230
  };
@@ -3,6 +3,7 @@ import { join, resolve } from 'node:path';
3
3
  import { spawn } from 'node:child_process';
4
4
  import { auditGoodVibesHome } from '../config/goodvibes-home-audit.ts';
5
5
  import { buildVerificationLedger } from './verification-ledger.ts';
6
+ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
6
7
 
7
8
  export type LiveVerificationStatus = 'pass' | 'warn' | 'fail' | 'skip';
8
9
 
@@ -111,7 +112,7 @@ function runCommand(command: string, args: string[], cwd: string, timeoutMs = 15
111
112
  resolveCommand({
112
113
  exitCode: -1,
113
114
  stdout: '',
114
- stderr: error instanceof Error ? error.message : String(error),
115
+ stderr: summarizeError(error),
115
116
  timedOut,
116
117
  });
117
118
  });
@@ -161,7 +162,7 @@ function commandCheck(
161
162
  title,
162
163
  status: 'fail',
163
164
  summary: 'Command succeeded but did not return valid JSON.',
164
- detail: error instanceof Error ? error.message : String(error),
165
+ detail: summarizeError(error),
165
166
  };
166
167
  }
167
168
  }
@@ -208,7 +209,7 @@ async function fetchCheck(
208
209
  title,
209
210
  status: 'fail',
210
211
  summary: 'Request failed.',
211
- detail: error instanceof Error ? error.message : String(error),
212
+ detail: summarizeError(error),
212
213
  };
213
214
  }
214
215
  }
package/src/version.ts CHANGED
@@ -6,7 +6,7 @@ import { join } from 'node:path';
6
6
  // The prebuild script updates the fallback value before compilation.
7
7
  // Uses import.meta.dir (Bun) to locate package.json relative to this file,
8
8
  // which is correct regardless of the process working directory.
9
- let _version = '0.25.0';
9
+ let _version = '0.27.0';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
12
12
  _version = pkg.version ?? _version;
@@ -1,110 +0,0 @@
1
- /**
2
- * Auto-compaction helper — TASK-058.
3
- *
4
- * Evaluates whether auto-compact should run after a turn completes and, if so,
5
- * triggers compaction and posts an honest transcript notice.
6
- *
7
- * behavior.autoCompactThreshold: SDK schema range [10, 100], default 80.
8
- * Auto-compact is active whenever the threshold is in its valid range (>0).
9
- * The display/suggestion path (hint + meter) is always active regardless.
10
- */
11
-
12
- import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
13
- import type { ConversationManager } from './conversation';
14
- import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
15
- import type { SystemMessageRouter } from './system-message-router';
16
- import { logger } from '@pellux/goodvibes-sdk/platform/utils';
17
- import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
18
- import { getLastCompactionEvent } from '@pellux/goodvibes-sdk/platform/core';
19
- import type { CompactionContext } from '@pellux/goodvibes-sdk/platform/core';
20
- import { buildCompactionPreview, buildCompactionAfterNotice } from '../renderer/compaction-preview.ts';
21
-
22
- export interface AutoCompactDeps {
23
- readonly configManager: Pick<ConfigManager, 'get'>;
24
- readonly conversation: ConversationManager;
25
- readonly providerRegistry: ProviderRegistry;
26
- readonly systemMessageRouter: SystemMessageRouter;
27
- readonly model: string;
28
- readonly provider: string;
29
- readonly lastInputTokens: number;
30
- readonly contextWindow: number;
31
- }
32
-
33
- /**
34
- * Run after each TURN_COMPLETED event.
35
- *
36
- * Reads behavior.autoCompactThreshold from config (SDK default: 80, range [10, 100]).
37
- * When usage is at or above the threshold, compacts the conversation and posts
38
- * an honest transcript notice so the user understands any summary discontinuity.
39
- *
40
- * This function is intentionally non-throwing; failures are logged and
41
- * surfaced via the system message router.
42
- */
43
- export async function maybeAutoCompact(deps: AutoCompactDeps): Promise<void> {
44
- // SDK schema default is 80; valid range is [10, 100]. The ?? 0 fallback is a
45
- // defensive guard for missing/null values only — not a normal operating state.
46
- const rawThreshold = Number(deps.configManager.get('behavior.autoCompactThreshold') ?? 0);
47
- const thresholdPct = Number.isFinite(rawThreshold) ? rawThreshold : 0;
48
-
49
- // Defensive guard: skip only when threshold is missing/non-positive (real config defaults to 80).
50
- if (thresholdPct <= 0 || deps.contextWindow <= 0) return;
51
-
52
- const usagePct = Math.min(100, Math.round((Math.max(0, deps.lastInputTokens) / deps.contextWindow) * 100));
53
- if (usagePct < thresholdPct) return;
54
-
55
- try {
56
- logger.debug('auto-compact triggered', { usagePct, thresholdPct });
57
- // Pre-compact preview — uses buildCompactionPreview for an honest estimate.
58
- const messages = deps.conversation.getMessagesForLLM();
59
- const sessionMemoryStore = deps.conversation.getSessionMemoryStore();
60
- const sessionMemories = sessionMemoryStore?.list() ?? [];
61
- const pinnedMemoryCount = sessionMemories.length;
62
- const preview = buildCompactionPreview({
63
- messages,
64
- contextWindow: deps.contextWindow,
65
- pinnedMemoryCount,
66
- trigger: 'auto',
67
- });
68
- deps.systemMessageRouter.routeSystemMessage(preview, 'high');
69
- const eventBefore = getLastCompactionEvent();
70
- const compactionCtx: CompactionContext = {
71
- messages,
72
- sessionMemories,
73
- agents: [],
74
- wrfcChains: [],
75
- activePlan: null,
76
- lineageEntries: [],
77
- compactionCount: 0,
78
- contextWindow: deps.contextWindow,
79
- trigger: 'auto',
80
- extractionModelId: deps.model,
81
- extractionProvider: deps.provider,
82
- };
83
- await deps.conversation.compact(
84
- deps.providerRegistry,
85
- deps.model,
86
- 'auto',
87
- deps.provider,
88
- compactionCtx,
89
- );
90
- // Post-compact notice using real CompactionEvent figures.
91
- const eventAfter = getLastCompactionEvent();
92
- if (eventAfter !== null && eventAfter !== eventBefore) {
93
- deps.systemMessageRouter.routeSystemMessage(
94
- buildCompactionAfterNotice({ event: eventAfter, pinnedMemoryCount }),
95
- 'low',
96
- );
97
- } else {
98
- deps.systemMessageRouter.routeSystemMessage(
99
- '[Context] Auto-compact complete — older turns summarised. Use /compact to compact again manually.',
100
- 'low',
101
- );
102
- }
103
- } catch (err) {
104
- logger.error('auto-compact failed', { error: summarizeError(err) });
105
- deps.systemMessageRouter.routeSystemMessage(
106
- `[Context] Auto-compact failed: ${summarizeError(err)}. Use /compact to try manually.`,
107
- 'high',
108
- );
109
- }
110
- }
@@ -1,52 +0,0 @@
1
- // Public surface barrel for the CalDAV calendar connector.
2
- //
3
- // Integration registers the surface by calling registerCalendarMethods(ctx).
4
- // All other exports are types / helpers for consumers and tests.
5
-
6
- export { registerCalendarMethods, CALENDAR_METHOD_IDS } from './register.ts';
7
- export type {
8
- RegisterCalendarOptions,
9
- CalDavClientFactory,
10
- CalendarEventDetail,
11
- CalendarEventSummaryResult,
12
- } from './register.ts';
13
-
14
- export {
15
- createCalDavClient,
16
- resolveCalDavConfig,
17
- toRelativeHref,
18
- parseMultiStatus,
19
- } from './caldav-client.ts';
20
- export type {
21
- CalDavClient,
22
- CalDavConfig,
23
- CalDavEvent,
24
- CreateCalDavClientOptions,
25
- CreateEventInput,
26
- CreatedEvent,
27
- ImportResult,
28
- ExportResult,
29
- ListEventsOptions,
30
- FetchLike,
31
- } from './caldav-client.ts';
32
-
33
- export {
34
- parseICS,
35
- generateICS,
36
- generateCalendar,
37
- foldLine,
38
- unfoldLines,
39
- escapeText,
40
- unescapeText,
41
- formatICalDate,
42
- formatICalDateTime,
43
- parseICalDate,
44
- attendeeDisplayName,
45
- eventToVEvent,
46
- extractUid,
47
- } from './ics.ts';
48
- export type {
49
- ParsedICalEvent,
50
- ICalAttendee,
51
- GenerateICalInput,
52
- } from './ics.ts';