@adhdev/daemon-core 0.9.82-rc.545 → 0.9.82-rc.546

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.545",
3
+ "version": "0.9.82-rc.546",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -47,8 +47,8 @@
47
47
  "author": "vilmire",
48
48
  "license": "AGPL-3.0-or-later",
49
49
  "dependencies": {
50
- "@adhdev/mesh-shared": "0.9.82-rc.545",
51
- "@adhdev/session-host-core": "0.9.82-rc.545",
50
+ "@adhdev/mesh-shared": "0.9.82-rc.546",
51
+ "@adhdev/session-host-core": "0.9.82-rc.546",
52
52
  "@agentclientprotocol/sdk": "^0.16.1",
53
53
  "ajv": "^8.20.0",
54
54
  "ajv-formats": "^3.0.1",
@@ -186,6 +186,15 @@ const MESH_FORWARDABLE_SESSION_COMMANDS = new Set([
186
186
  'set_mode',
187
187
  'change_model',
188
188
  'set_thought_level',
189
+ // set_conversation_prefs (per-session user Hide/Mute) is session-scoped: the daemon-owned
190
+ // userHidden/userMuted lives on the OWNING session's live instance (med-family handler
191
+ // getInstance → updateSettings). When the target is a REMOTE worker session the coordinator
192
+ // has no local instance, so without forwarding the handler returns 'Session not found', the
193
+ // dashboard's useConversationPrefs silently rolls back, and the stale worker surfaceHidden is
194
+ // re-stamped every snapshot tick (the "restore does nothing + flicker" defect, mission
195
+ // 6938892f). Forwarding to the owning worker lets it actually clear userHidden/userMuted and
196
+ // report a fresh surfaceHidden=false — which also resolves the re-stamp flicker at the source.
197
+ 'set_conversation_prefs',
189
198
  // agent_command (send_chat / clear_history / stop) is session-scoped too: a command
190
199
  // explicitly naming a targetSessionId MUST reach that session wherever it lives, never a
191
200
  // different local session. Without forwarding, a misrouted/relayed send_chat for a REMOTE
@@ -948,6 +948,17 @@ export function enqueueTask(
948
948
  } & MeshQueueMutationOptions,
949
949
  ): MeshWorkQueueEntry {
950
950
  requireMeshHostQueueOwner(opts);
951
+ // DELIVERY-MSG-GUARD (upstream defence): a task whose message is undefined /
952
+ // non-string / blank must never reach the queue. Left unchecked it persists a
953
+ // message-less payload that later crashes insertSessionDelivery's NOT NULL at
954
+ // claim/dispatch time (the DB-level `message ?? ''` fallback still exists as
955
+ // depth-in-defence, but silently dispatching an empty prompt is itself a bug).
956
+ // Normalise and hard-reject at the single entry point so no caller can slip a
957
+ // blank task past the schema's nominal `required`.
958
+ message = String(message ?? '').trim();
959
+ if (!message) {
960
+ throw new Error('mesh task message must be a non-empty string');
961
+ }
951
962
  const readonly = opts?.readonly === true;
952
963
  const modeValidation = validateMeshTaskModeRequest(opts?.taskMode, message, readonly);
953
964
  if (!modeValidation.valid) {
@@ -1069,6 +1080,14 @@ export function recordDirectDispatchTask(
1069
1080
  if (!missionId) return null;
1070
1081
  const taskId = typeof opts.id === 'string' ? opts.id.trim() : '';
1071
1082
  if (!taskId) return null;
1083
+ // DELIVERY-MSG-GUARD (upstream defence): the direct-dispatch path materialises the
1084
+ // same message-carrying queue entry AND writes a session delivery (createSessionDelivery
1085
+ // below), so a blank/undefined message would hit the same NOT NULL crash. Normalise and
1086
+ // hard-reject before we record anything — consistent with enqueueTask.
1087
+ message = String(message ?? '').trim();
1088
+ if (!message) {
1089
+ throw new Error('mesh task message must be a non-empty string');
1090
+ }
1072
1091
  const readonly = opts.readonly === true;
1073
1092
  const modeValidation = validateMeshTaskModeRequest(opts.taskMode, message, readonly);
1074
1093
  if (!modeValidation.valid) {