@adhdev/daemon-core 0.9.82-rc.490 → 0.9.82-rc.491

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.490",
3
+ "version": "0.9.82-rc.491",
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.490",
51
- "@adhdev/session-host-core": "0.9.82-rc.490",
50
+ "@adhdev/mesh-shared": "0.9.82-rc.491",
51
+ "@adhdev/session-host-core": "0.9.82-rc.491",
52
52
  "@agentclientprotocol/sdk": "^0.16.1",
53
53
  "ajv": "^8.20.0",
54
54
  "ajv-formats": "^3.0.1",
@@ -537,7 +537,7 @@ export const meshCrudHandlers: Record<string, MedFamilyHandler> = {
537
537
  const ownerFailure = await ctx.requireMeshHostMutationOwner(meshId, args?.inlineMesh, 'node update');
538
538
  if (ownerFailure) return ownerFailure;
539
539
  try {
540
- const { updateNode } = await import('../../config/mesh-config.js');
540
+ const { updateNode, normalizeCapabilityTags } = await import('../../config/mesh-config.js');
541
541
  const policy = args?.policy && typeof args.policy === 'object' && !Array.isArray(args.policy)
542
542
  ? { ...(args.policy as Record<string, unknown>) }
543
543
  : {};
@@ -579,13 +579,54 @@ export const meshCrudHandlers: Record<string, MedFamilyHandler> = {
579
579
  .filter(Boolean);
580
580
  }
581
581
  const node = updateNode(meshId, nodeId, patch as any);
582
- if (!node) return { success: false, error: 'Mesh node not found' };
583
- // Provider priority / systemPrompt changes don't touch
584
- // the queue revision, so without a manual bust the
585
- // cached aggregate keeps surfacing pre-update values
586
- // (priority chip, coordinator prompt preview, etc.).
587
- ctx.invalidateAggregateMeshStatus(meshId);
588
- return { success: true, node };
582
+ if (node) {
583
+ // Provider priority / systemPrompt changes don't touch
584
+ // the queue revision, so without a manual bust the
585
+ // cached aggregate keeps surfacing pre-update values
586
+ // (priority chip, coordinator prompt preview, etc.).
587
+ ctx.invalidateAggregateMeshStatus(meshId);
588
+ return { success: true, node };
589
+ }
590
+ // NODE-SLOTS-REMOTE-WRITE: updateNode reads ONLY this daemon's local
591
+ // meshes.json. When update_mesh_node is forwarded to a node's home-daemon
592
+ // that has no local config entry for a coordinator-owned mesh (a remote
593
+ // member daemon, or a cloud coordinator that holds the mesh solely in its
594
+ // inline cache), updateNode returns undefined and the write failed with
595
+ // "Mesh node not found" — even though the coordinator attached the mesh
596
+ // snapshot as inlineMesh and the read paths (get_mesh / dry-run / list)
597
+ // resolve it fine via getMeshForCommand's inline fallback. Mirror those
598
+ // read paths here: resolve the mesh from the inline cache and apply the
599
+ // same field semantics as updateNode, persisting to the inline cache.
600
+ const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
601
+ const mesh = meshRecord?.mesh;
602
+ if (!mesh) return { success: false, error: 'Mesh not found' };
603
+ const inlineNode = Array.isArray(mesh.nodes)
604
+ ? mesh.nodes.find((n: any) => meshNodeIdMatches(n, nodeId))
605
+ : undefined;
606
+ if (!inlineNode) return { success: false, error: 'Mesh node not found' };
607
+ // Apply the SAME field semantics updateNode uses so the inline write and a
608
+ // local-config write are indistinguishable: shallow-merge policy, honor an
609
+ // explicit systemPrompt clear, replace/normalize capability tags.
610
+ inlineNode.policy = {
611
+ ...(inlineNode.policy && typeof inlineNode.policy === 'object' && !Array.isArray(inlineNode.policy)
612
+ ? inlineNode.policy as Record<string, unknown>
613
+ : {}),
614
+ ...(patch.policy as Record<string, unknown>),
615
+ };
616
+ if (Object.prototype.hasOwnProperty.call(patch, 'systemPrompt')) {
617
+ const sp = (patch as any).systemPrompt;
618
+ if (typeof sp === 'string' && sp.trim()) inlineNode.systemPrompt = sp;
619
+ else delete inlineNode.systemPrompt;
620
+ }
621
+ if (Object.prototype.hasOwnProperty.call(patch, 'capabilities')) {
622
+ const tags = normalizeCapabilityTags((patch as any).capabilities);
623
+ if (tags && tags.length) inlineNode.capabilities = tags;
624
+ else delete inlineNode.capabilities;
625
+ }
626
+ // updateInlineMeshNode canonicalizes node identity, persists the mutated
627
+ // mesh back to the inline cache, and busts the aggregate-status cache.
628
+ ctx.updateInlineMeshNode(meshId, mesh, inlineNode);
629
+ return { success: true, node: inlineNode };
589
630
  } catch (e: any) {
590
631
  return { success: false, error: e.message };
591
632
  }
@@ -104,7 +104,7 @@ function stripDeadRoleFromProviderRoles(policy: unknown): boolean {
104
104
  return changed;
105
105
  }
106
106
 
107
- function normalizeCapabilityTags(value: unknown): string[] | undefined {
107
+ export function normalizeCapabilityTags(value: unknown): string[] | undefined {
108
108
  if (!Array.isArray(value)) return undefined;
109
109
  const seen = new Set<string>();
110
110
  const tags = value