@pellux/goodvibes-daemon 1.28.9 → 1.28.11

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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,50 @@ All notable changes to the GoodVibes daemon.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.28.11] - 2026-08-05
10
+
11
+ ### Changes
12
+
13
+ - **Fixed: reminders respect being heard** (platform runtime 2.0.9). An
14
+ occasion nudge raises once at the lead boundary and at most once on the
15
+ day; a reply that engages the reminder records an acknowledgment in the
16
+ same turn and mutes that occurrence; the owner's own remember-only dates
17
+ never push at all. Over-nudged machines reconcile on first boot with a
18
+ receipt. The new `occasions.acknowledge` verb carries the acknowledgment;
19
+ `occasions.finalStretchDays` is retired with a receipted migration.
20
+ - Fixed: a dead runtime record reaps itself instead of making daemon-owned
21
+ settings unreadable; wake transcription is daemon-first with failure
22
+ evidence in diagnostics; the managed voice installer supersedes stale
23
+ manual paths by name and proves itself with a spoken round trip.
24
+ - Changed: setup flows complete the inferred intent — propose extensions,
25
+ ask at genuine forks, never hand the user a command; the Google
26
+ walkthrough accepts pasted values in-conversation and answers with the
27
+ consent link.
28
+
29
+ ## [1.28.10] - 2026-08-05
30
+
31
+ ### Changes
32
+
33
+ - **Fixed: this daemon's answers match its own contract.** Profile field
34
+ reads leaked internal properties past a strict schema, so up-to-date
35
+ clients refused every profile answer and the platform could not tell its
36
+ owner his own address. Responses are explicit wire projections now, and a
37
+ conformance test runs the real routes against the contract (platform
38
+ runtime 2.0.8).
39
+ - **Fixed: one control-plane store.** A path defect made every boot rewrite
40
+ a legacy store nothing reads; state that still lived only at the legacy
41
+ location (occasions, workspace registrations) migrates to the daemon's
42
+ surface-scoped store on boot with a receipt, duplicates are quarantined
43
+ with receipts, and the legacy directory empties and is removed.
44
+ - **Changed: the daemon hosts conversation turns for the agent.** Hosted
45
+ session event streams are render-grade and session-scoped, so a client
46
+ rendering from the stream sees what the model said and what it did — and
47
+ agent conversations become genuinely cross-visible with their messages.
48
+ - Changed: connecting Google is one action, with every needed scope in a
49
+ single consent and a live mail-and-calendar proof at the end; the settings
50
+ catalog now carries the calendar/google/email keys this daemon really
51
+ reads (platform runtime 2.0.8).
52
+
9
53
  ## [1.28.9] - 2026-08-02
10
54
 
11
55
  ### Changes
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/mgd34msu/goodvibes-daemon/actions/workflows/ci.yml/badge.svg)](https://github.com/mgd34msu/goodvibes-daemon/actions/workflows/ci.yml)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![Version](https://img.shields.io/badge/version-1.28.9-blue.svg)](https://github.com/mgd34msu/goodvibes-daemon)
5
+ [![Version](https://img.shields.io/badge/version-1.28.11-blue.svg)](https://github.com/mgd34msu/goodvibes-daemon)
6
6
 
7
7
  The GoodVibes daemon: one long-running process per machine that holds the control plane every
8
8
  GoodVibes client talks to. It answers the operator verb families over HTTP, reads and replies on
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-daemon",
3
- "version": "1.28.9",
3
+ "version": "1.28.11",
4
4
  "description": "The GoodVibes daemon \u2014 the one long-running host for the control plane, channels, cluster membership, scheduled work, knowledge and memory stores, and the verb families every GoodVibes client calls.",
5
5
  "type": "module",
6
6
  "main": "src/daemon/cli.ts",
@@ -65,8 +65,8 @@
65
65
  "@anthropic-ai/bedrock-sdk": "^0.28.1",
66
66
  "@anthropic-ai/sdk": "^0.82.0",
67
67
  "@ast-grep/napi": "^0.42.0",
68
- "@pellux/goodvibes-sdk": "2.0.7",
69
- "@pellux/goodvibes-terminal-shell": "2.0.7",
68
+ "@pellux/goodvibes-sdk": "2.0.9",
69
+ "@pellux/goodvibes-terminal-shell": "2.0.9",
70
70
  "bash-language-server": "^5.6.0",
71
71
  "fuse.js": "^7.1.0",
72
72
  "graphql": "^16.13.2",
@@ -102,6 +102,13 @@ export interface RuntimeServicesOptions {
102
102
  export interface RuntimeServices {
103
103
  readonly workingDirectory: string;
104
104
  readonly homeDirectory: string;
105
+ /**
106
+ * The `.goodvibes/<surface root>/` segment this daemon's own state lives
107
+ * under — always GOODVIBES_DAEMON_SURFACE_ROOT here (config/surface.ts).
108
+ * Declared so a consumer ASKS for it instead of deriving a second one; the
109
+ * unscoped pre-split control-plane store is what deriving it twice produced.
110
+ */
111
+ readonly surfaceRoot: string;
105
112
  /** The declare-once session-storage handle every session reader and writer threads through. */
106
113
  readonly surface: SessionSurface;
107
114
  readonly shellPaths: ShellPathService;
@@ -2,7 +2,7 @@ import { join } from 'node:path';
2
2
  import { ServiceRegistry, SubscriptionManager, ToolLLM } from '@pellux/goodvibes-sdk/platform/config';
3
3
  import { AutomationDeliveryManager, AutomationManager } from '@pellux/goodvibes-sdk/platform/automation';
4
4
  import { ChannelPolicyManager } from '@pellux/goodvibes-sdk/platform/channels';
5
- import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker, buildSharedSessionAgentSpawnRoutingInput } from '@pellux/goodvibes-sdk/platform/control-plane';
5
+ import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker, buildSharedSessionAgentSpawnRoutingInput, controlPlaneStorePath } from '@pellux/goodvibes-sdk/platform/control-plane';
6
6
  import { AcpHostService } from '@pellux/goodvibes-sdk/platform/acp';
7
7
  import { continuationChainOptions } from '@pellux/goodvibes-sdk/platform/agents';
8
8
  import { PersonalCaptureHolder, conversationalTurnSpawnOptions } from '@pellux/goodvibes-sdk/platform/personal-capture';
@@ -132,7 +132,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
132
132
  const { secretsManager, stepUpService, pairingTokens } = composeCredentialServices({
133
133
  workingDirectory, homeDirectory, configManager,
134
134
  daemonHomeDirectory: options.daemonHomeDirectory,
135
- pairingTokenPath: shellPaths.resolveUserPath('control-plane', 'pairing-tokens.json'),
135
+ pairingTokenPath: controlPlaneStorePath(shellPaths, GOODVIBES_DAEMON_SURFACE_ROOT, 'pairing-tokens.json'),
136
136
  });
137
137
  const subscriptionManager = new SubscriptionManager(shellPaths.resolveUserPath(GOODVIBES_DAEMON_SURFACE_ROOT, 'subscriptions.json'));
138
138
  const serviceRegistry = new ServiceRegistry(shellPaths.resolveProjectPath(GOODVIBES_DAEMON_SURFACE_ROOT, 'services.json'), {
@@ -526,6 +526,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
526
526
  // calendar.*/email.* are platform-served; these two let it register (mail-composition.ts).
527
527
  const { emailServiceDeps, describeEmailConfigProblem } = composeMailDeps({ configManager, secretsManager });
528
528
  attachWsOnlyGatewayVerbHandlers(gatewayMethods, {
529
+ // The surface segment every control-plane store path is built from
530
+ // (SDK control-plane-store-paths.ts). Required, not defaulted: a default
531
+ // is what let these stores write to the unscoped orphan directory.
532
+ surfaceRoot: GOODVIBES_DAEMON_SURFACE_ROOT,
529
533
  homeDirectory, emailServiceDeps, describeEmailConfigProblem, processRegistry,
530
534
  // The registration-gated surface, not the raw manager: an explicit create in
531
535
  // an unregistered workspace refuses with something actionable.
@@ -658,6 +662,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
658
662
  const services: RuntimeServices = {
659
663
  workingDirectory,
660
664
  homeDirectory,
665
+ surfaceRoot: GOODVIBES_DAEMON_SURFACE_ROOT,
661
666
  surface,
662
667
  shellPaths,
663
668
  workspaceTrustManager,
@@ -1,4 +1,5 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolveWorkspaceRegisterReadPath } from '@pellux/goodvibes-sdk/platform/workspace';
2
3
  import type { ShellPathService } from '@/runtime/index.ts';
3
4
  import {
4
5
  normalizeWorkspaceRoot,
@@ -30,9 +31,24 @@ import {
30
31
 
31
32
  export type StoreShellPaths = Pick<ShellPathService, 'resolveUserPath' | 'homeDirectory'>;
32
33
 
33
- /** Path of the shared store's JSON document — the same path the SDK's gateway verb group constructs its own store over. */
34
+ /**
35
+ * Path of the shared store's JSON document — the same path the SDK's gateway
36
+ * verb group constructs its own store over.
37
+ *
38
+ * "The same path" is the whole contract, and it is why this goes through the
39
+ * SDK's resolver rather than spelling any location out. goodvibes-agent reads
40
+ * and writes this same file directly and the SDK's gateway writes it, so the
41
+ * register is cross-product state rather than the daemon's own — it lives in
42
+ * the shared tier (~/.goodvibes/shared/), which takes no surface root, so all
43
+ * three resolve one identical path. Until the boot fold has moved it, the
44
+ * resolver falls back to the pre-split location read-only, so this reader never
45
+ * reports an empty register and silently refuses every checkpoint.
46
+ */
34
47
  export function sharedWorkspaceRegistrationStorePath(shellPaths: StoreShellPaths): string {
35
- return shellPaths.resolveUserPath('control-plane', 'workspace-registrations.json');
48
+ // READ path: the shared tier when it is there, the pre-split location until
49
+ // the daemon's boot fold has moved it. This is a reader, so the fallback is
50
+ // read-only and nothing here ever writes to the legacy address.
51
+ return resolveWorkspaceRegisterReadPath(shellPaths, existsSync);
36
52
  }
37
53
 
38
54
  function isRecord(value: unknown): value is Record<string, unknown> {
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 = '1.28.9';
9
+ let _version = '1.28.11';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
12
12
  // Only trust a version read from OUR OWN package.json. A Bun single-file