@adhdev/daemon-core 0.9.82-rc.230 → 0.9.82-rc.231

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.230",
3
+ "version": "0.9.82-rc.231",
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",
@@ -5916,11 +5916,14 @@ export class DaemonCommandRouter {
5916
5916
  let worktreeCleanup: Record<string, unknown> | undefined;
5917
5917
  if (node?.isLocalWorktree) {
5918
5918
  const nodeDaemonId = typeof node.daemonId === 'string' ? node.daemonId.trim() : undefined;
5919
- const isRemoteWorktree = nodeDaemonId && nodeDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand;
5919
+ const isRemoteWorktree = nodeDaemonId && nodeDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand
5920
+ && !args?._meshDirectDispatch;
5920
5921
  if (isRemoteWorktree) {
5921
5922
  // Worktree lives on a different machine — ask that daemon to clean it up.
5923
+ // _meshDirectDispatch prevents re-forwarding when stored daemonId uses legacy format.
5922
5924
  const forwarded = await this.deps.dispatchMeshCommand!(nodeDaemonId!, 'remove_mesh_node', {
5923
5925
  ...(typeof args === 'object' && args !== null ? args as Record<string, unknown> : {}),
5926
+ _meshDirectDispatch: true,
5924
5927
  });
5925
5928
  return (forwarded ?? { success: false, error: 'no response from remote node' }) as CommandRouterResult;
5926
5929
  }
@@ -6007,10 +6010,14 @@ export class DaemonCommandRouter {
6007
6010
  if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
6008
6011
 
6009
6012
  // Forward to the source node's daemon if it's on a different machine.
6013
+ // _meshDirectDispatch prevents infinite re-forwarding when the stored daemonId
6014
+ // uses a legacy format that doesn't match the receiving daemon's statusInstanceId.
6010
6015
  const sourceDaemonId = typeof sourceNode.daemonId === 'string' ? sourceNode.daemonId.trim() : undefined;
6011
- if (sourceDaemonId && sourceDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand) {
6016
+ if (sourceDaemonId && sourceDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand
6017
+ && !args?._meshDirectDispatch) {
6012
6018
  const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, 'clone_mesh_node', {
6013
6019
  ...(typeof args === 'object' && args !== null ? args as Record<string, unknown> : {}),
6020
+ _meshDirectDispatch: true,
6014
6021
  });
6015
6022
  return (forwarded ?? { success: false, error: 'no response from remote node' }) as CommandRouterResult;
6016
6023
  }
@@ -6271,10 +6278,13 @@ export class DaemonCommandRouter {
6271
6278
  if (!node.isLocalWorktree) return { success: false, error: 'Node is not a local worktree node' };
6272
6279
 
6273
6280
  // Bootstrap runs scripts in the worktree path — forward to the node's daemon if remote.
6281
+ // _meshDirectDispatch prevents re-forwarding when stored daemonId uses legacy format.
6274
6282
  const nodeDaemonId = typeof node.daemonId === 'string' ? node.daemonId.trim() : undefined;
6275
- if (nodeDaemonId && nodeDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand) {
6283
+ if (nodeDaemonId && nodeDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand
6284
+ && !args?._meshDirectDispatch) {
6276
6285
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, 'retry_mesh_node_bootstrap', {
6277
6286
  ...(typeof args === 'object' && args !== null ? args as Record<string, unknown> : {}),
6287
+ _meshDirectDispatch: true,
6278
6288
  });
6279
6289
  return (forwarded ?? { success: false, error: 'no response from remote node' }) as CommandRouterResult;
6280
6290
  }
@@ -97,6 +97,15 @@ export function buildMeshSystemMessage(args: {
97
97
  if (args.event === 'monitor:long_generating') {
98
98
  return `[System] ${args.nodeLabel} is still reported as generating after a long interval${metadata}. Wait for pendingCoordinatorEvents or a completion/status event; if the user explicitly asks for status, make one bounded status check and then wait again.`;
99
99
  }
100
+ if (args.event === 'worktree_bootstrap_complete') {
101
+ const worktreePath = readNonEmptyString(args.metadataEvent.worktreePath);
102
+ const durationMs = typeof args.metadataEvent.durationMs === 'number' ? args.metadataEvent.durationMs : undefined;
103
+ return `[System] ${args.nodeLabel} worktree bootstrap completed${worktreePath ? ` at ${worktreePath}` : ''}${durationMs !== undefined ? ` in ${Math.round(durationMs / 1000)}s` : ''}. The worktree is ready — use \`mesh_launch_session\` to start an agent.`;
104
+ }
105
+ if (args.event === 'worktree_bootstrap_failed') {
106
+ const error = readNonEmptyString(args.metadataEvent.error);
107
+ return `[System] ${args.nodeLabel} worktree bootstrap failed${error ? `: ${error}` : '.'}. Use \`mesh_retry_node_bootstrap\` to retry or inspect the node state.`;
108
+ }
100
109
  if (args.event === 'refine:accepted') {
101
110
  const jobId = readRefineJobId({ metadataEvent: args.metadataEvent });
102
111
  return `[System] Refinery accepted async job${jobId ? ` ${jobId}` : ''} for ${args.nodeLabel}. Completion/failure will be delivered as a terminal refine event; do not poll repeatedly.`;
@@ -295,11 +295,9 @@ function expandPath(template: string, input: NativeHistoryInput): string | null
295
295
  // Re-expand ~ in case the fallback used it.
296
296
  if (out.startsWith('~/')) out = path.join(os.homedir(), out.slice(2));
297
297
  const now = new Date();
298
- // claude (and a couple of other Anthropic-CLI–style providers) writes
299
- // its per-cwd transcript under the *resolved* path
300
- // (/private/tmp/foo, not /tmp/foo on macOS where /tmp -> /private/tmp).
301
- // Without realpath, the spec template `~/.claude/projects/{cwd_dashed}/…`
302
- // builds `-tmp-foo` and never finds the actual `-private-tmp-foo` dir.
298
+ // Claude writes per-cwd transcripts under the resolved path and replaces
299
+ // every non-alphanumeric project-path character except `_` and `-` with
300
+ // `-`. Realpath also handles aliases such as /tmp -> /private/tmp.
303
301
  const workspaceRaw = input.workspace ?? '';
304
302
  let workspaceResolved = workspaceRaw;
305
303
  if (workspaceRaw) {
@@ -309,6 +307,7 @@ function expandPath(template: string, input: NativeHistoryInput): string | null
309
307
  const vars: Record<string, string> = {
310
308
  cwd: workspaceResolved,
311
309
  cwd_dashed: workspaceResolved.replace(/\//g, '-'),
310
+ cwd_claude_project: claudeProjectDirName(workspaceResolved),
312
311
  session_id: input.providerSessionId || input.sessionId || input.historySessionId || '',
313
312
  yyyy: String(now.getFullYear()),
314
313
  mm: String(now.getMonth() + 1).padStart(2, '0'),
@@ -329,6 +328,10 @@ function expandPath(template: string, input: NativeHistoryInput): string | null
329
328
  return out;
330
329
  }
331
330
 
331
+ function claudeProjectDirName(workspace: string): string {
332
+ return workspace.replace(/[^A-Za-z0-9_-]/g, '-');
333
+ }
334
+
332
335
  function globToRegex(pattern: string): RegExp {
333
336
  // Minimal glob: `*` → `[^/]*`, `?` → `[^/]`, `.` → `\.`. Anchored.
334
337
  const re = pattern
@@ -463,6 +466,7 @@ function expandPathForDate(template: string, input: NativeHistoryInput, day: Dat
463
466
  const vars: Record<string, string> = {
464
467
  cwd: workspaceResolved,
465
468
  cwd_dashed: workspaceResolved.replace(/\//g, '-'),
469
+ cwd_claude_project: claudeProjectDirName(workspaceResolved),
466
470
  session_id: input.providerSessionId || input.sessionId || input.historySessionId || '',
467
471
  yyyy: String(day.getFullYear()),
468
472
  mm: String(day.getMonth() + 1).padStart(2, '0'),