@adhdev/daemon-core 0.9.82-rc.314 → 0.9.82-rc.316

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.
@@ -34,6 +34,28 @@ export interface AcpAdapterHandle {
34
34
  setConfigOption?(configId: string, value: string): Promise<void>;
35
35
  resolvePermission?(approved: boolean): Promise<void>;
36
36
  }
37
+ /**
38
+ * Launch metadata for a CLI session, surfaced by the dashboard Session info panel.
39
+ * Derived from the live adapter's spawn plan — the resolved binary, the full
40
+ * argument vector (provider base args + per-launch extra args), the cwd, and the
41
+ * set of per-launch extra-env KEYS (values are intentionally omitted so secrets in
42
+ * extraEnv are never sent to the dashboard). providerSessionId is the upstream
43
+ * agent's own session id once the CLI reports it.
44
+ */
45
+ export interface CliLaunchInfo {
46
+ /** Resolved executable path the PTY actually spawns. */
47
+ command?: string;
48
+ /** Full argument vector (provider spawn.args + extraArgs, {{workingDir}} expanded). */
49
+ args: string[];
50
+ /** Per-launch extra args only (subset of args), for attribution. */
51
+ extraArgs: string[];
52
+ /** Working directory the session was spawned in. */
53
+ cwd: string;
54
+ /** KEYS of per-launch extra env (values omitted — may contain secrets). */
55
+ extraEnvKeys: string[];
56
+ /** Upstream agent session id, once the CLI reports one. */
57
+ providerSessionId?: string;
58
+ }
37
59
  export interface CliAdapter {
38
60
  cliType: string;
39
61
  cliName: string;
@@ -69,6 +91,7 @@ export interface CliAdapter {
69
91
  setOnPtyData?(callback: (data: string) => void): void;
70
92
  writeRaw?(data: string): void;
71
93
  resize?(cols: number, rows: number): void;
94
+ getLaunchInfo?(): CliLaunchInfo;
72
95
  getRuntimeMetadata?(): unknown;
73
96
  updateRuntimeMeta?(meta: Record<string, unknown>): void;
74
97
  refreshProviderDefinition?(provider: unknown): void;
@@ -13,7 +13,7 @@
13
13
  * type, name, category: 'cli', binary, spawn, approvalKeys
14
14
  * compatibility: [{ ideVersion, scriptDir }] ← versioned scripts
15
15
  */
16
- import type { CliAdapter } from '../cli-adapter-types.js';
16
+ import type { CliAdapter, CliLaunchInfo } from '../cli-adapter-types.js';
17
17
  import type { InteractivePromptResponse } from '../providers/types/interactive-prompt.js';
18
18
  import { type PtyRuntimeMetadata, type PtyTransportFactory } from './pty-transport.js';
19
19
  import { type CliProviderModule, type CliScripts, type CliSessionStatus, type CliTraceEntry, type ParsedSession } from './provider-cli-shared.js';
@@ -190,6 +190,14 @@ export declare class ProviderCliAdapter implements CliAdapter {
190
190
  getPartialResponse(): string;
191
191
  getDebugSnapshot(): Record<string, unknown>;
192
192
  getRuntimeMetadata(): PtyRuntimeMetadata | null;
193
+ /**
194
+ * Launch metadata for the dashboard Session info panel. Re-derives the spawn plan
195
+ * (pure — same inputs the live PTY was spawned with) so the dashboard sees the
196
+ * resolved binary, full arg vector, and cwd without us having to persist it.
197
+ * extraEnv values are intentionally dropped (keys only) so secrets passed at
198
+ * launch time never reach the dashboard.
199
+ */
200
+ getLaunchInfo(): CliLaunchInfo;
193
201
  updateRuntimeMeta(meta: Record<string, unknown>, replace?: boolean): void;
194
202
  cancel(): void;
195
203
  saveAndStop(): Promise<void>;
package/dist/index.d.ts CHANGED
@@ -7,8 +7,8 @@ export type { ChatBubbleState, ChatMessage, ExtensionInfo, CommandResult as Core
7
7
  export type { SessionEntry, CompactSessionEntry, CompactDaemonEntry, CloudDaemonSummaryEntry, DashboardBootstrapDaemonEntry, VersionUpdateReason, CloudStatusReportPayload, DaemonStatusEventPayload, DashboardStatusEventPayload, SessionTransport, SessionKind, SessionCapability, AgentSessionStream, ReadChatCursor, ReadChatSyncResult, TransportTopic, SessionChatTailSubscriptionParams, SessionRuntimeOutputSubscriptionParams, MachineRuntimeSubscriptionParams, SessionHostDiagnosticsSubscriptionParams, SessionModalSubscriptionParams, DaemonMetadataSubscriptionParams, WorkspaceGitSubscriptionParams, SessionChatTailUpdate, MachineRuntimeUpdate, SessionHostDiagnosticsUpdate, SessionModalUpdate, DaemonMetadataUpdate, TopicUpdateEnvelope, SubscribeRequest, UnsubscribeRequest, StandaloneWsStatusPayload, AvailableProviderInfo, AcpConfigOption, AcpMode, ProviderControlSchema, StatusReportPayload, MachineInfo, SessionHostDiagnosticsSnapshot, SessionHostRecord, SessionHostWriteOwner, SessionHostAttachedClient, SessionHostLogEntry, SessionHostRequestTrace, SessionHostRuntimeTransition, DetectedIdeInfo, WorkspaceEntry, ProviderSummaryItem, ProviderSummaryMetadata, ProviderState, ProviderStatus, ProviderErrorReason, SessionActiveChatData, ActiveChatData, IdeProviderState, CliProviderState, AcpProviderState, ExtensionProviderState, MessageInputSupport, InputMediaStrategyDescriptor, InputAttachmentStrategy, InputMediaType, } from './shared-types.js';
8
8
  export type { InteractivePrompt, InteractiveQuestion, InteractiveOption, InteractivePromptResponse, InteractiveAnswer, } from './providers/types/interactive-prompt.js';
9
9
  export { normalizeInteractivePrompt, normalizeInteractivePromptResponse, buildClaudeInteractiveToolResult, interactivePromptFromClaudeAskUserQuestion, detectClaudeAskUserQuestionPromptFromJson, } from './providers/types/interactive-prompt.js';
10
- export type { RepoMesh, RepoMeshDaemonRole, RepoMeshHostMetadata, RepoMeshHostPairingMetadata, RepoMeshHostStatus, RepoMeshNode, RepoMeshNodeHealth, RepoMeshPolicy, RepoMeshNodePolicy, RepoMeshRelatedRepo, RepoMeshNodeCapabilities, DetectedCommand, ProjectContextSnapshot, ProjectContextSource, RepoMeshCoordinatorConfig, LocalMeshConfig, LocalMeshEntry, LocalMeshNodeEntry, RepoMeshStatus, RepoMeshNodeStatus, RepoMeshPeerConnectionStatus, RepoMeshPeerConnectionState, RepoMeshPeerConnectionTransport, RepoMeshSessionStatus, RepoMeshQueueTask, RepoMeshQueueTaskStatus, RepoMeshQueueSummary, RepoMeshQueueStatus, RepoMeshLedgerEntryStatus, RepoMeshLedgerSummaryStatus, RepoMeshLedgerStatus, MeshAsyncJobLifecycle, RepoMeshSchedulingStrategy, } from './repo-mesh-types.js';
11
- export { DEFAULT_MESH_POLICY, resolveDelegatedWorkerAutoApprove, MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, normalizeMeshSchedulingStrategy, resolveNodeSchedulingPriority, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, resolveAutoConvergeCodeChange, } from './repo-mesh-types.js';
10
+ export type { RepoMesh, RepoMeshDaemonRole, RepoMeshHostMetadata, RepoMeshHostPairingMetadata, RepoMeshHostStatus, RepoMeshNode, RepoMeshNodeHealth, RepoMeshPolicy, RepoMeshNodePolicy, RepoMeshRelatedRepo, RepoMeshNodeCapabilities, DetectedCommand, ProjectContextSnapshot, ProjectContextSource, RepoMeshCoordinatorConfig, LocalMeshConfig, LocalMeshEntry, LocalMeshNodeEntry, RepoMeshStatus, RepoMeshNodeStatus, RepoMeshPeerConnectionStatus, RepoMeshPeerConnectionState, RepoMeshPeerConnectionTransport, RepoMeshSessionStatus, RepoMeshQueueTask, RepoMeshQueueTaskStatus, RepoMeshQueueSummary, RepoMeshQueueStatus, RepoMeshLedgerEntryStatus, RepoMeshLedgerSummaryStatus, RepoMeshLedgerStatus, MeshAsyncJobLifecycle, RepoMeshSchedulingStrategy, RepoMeshTaskAffinityPolicy, StandardMeshRole, } from './repo-mesh-types.js';
11
+ export { DEFAULT_MESH_POLICY, resolveDelegatedWorkerAutoApprove, MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, normalizeMeshSchedulingStrategy, resolveNodeSchedulingPriority, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, resolveAutoConvergeCodeChange, STANDARD_MESH_ROLES, DEFAULT_TASKMODE_ROLE_MAP, resolveTaskAffinityRole, resolveMeshRoleOptions, } from './repo-mesh-types.js';
12
12
  export * from './git/index.js';
13
13
  import type { RuntimeWriteOwner as _RuntimeWriteOwner } from './shared-types-extra.js';
14
14
  import type { RuntimeAttachedClient as _RuntimeAttachedClient } from './shared-types-extra.js';
@@ -49,7 +49,7 @@ export { fastForwardMeshNode } from './mesh/mesh-fast-forward.js';
49
49
  export type { MeshFastForwardNodeArgs, MeshFastForwardPlannedStep, MeshFastForwardResult } from './mesh/mesh-fast-forward.js';
50
50
  export { buildMeshLedgerReconciliationEvidence, buildMeshLedgerReplicaEvidence } from './mesh/mesh-ledger-reconciliation.js';
51
51
  export type { AnyLedgerSlice, MeshLedgerReconciliationEvidence, MeshLedgerReplicaEvidence, MeshLedgerReplicaStatus } from './mesh/mesh-ledger-reconciliation.js';
52
- export { enqueueTask, recordDirectDispatchTask, getQueue, claimNextTask, updateTaskStatus, updateSessionTaskStatus, cancelTask, requeueTask, getMeshQueueStats, getMeshQueueRevision, normalizeMeshTaskMode, validateMeshTaskModeRequest, buildMeshNodeCapabilityTags, nodeSatisfiesRequiredTags, normalizeMeshCapabilityTags, resolveConvergeRequiredTags, insertDirectDispatch, getActiveDirectDispatches, updateDirectDispatchStatus, cleanupTerminalDirectDispatches, markStaleDirectDispatches, deleteDirectDispatchesByTaskId, recordMeshToolCall, assertNoDependencyCycle, hasPendingDependents, describeTaskDependencyState } from './mesh/mesh-work-queue.js';
52
+ export { enqueueTask, recordDirectDispatchTask, getQueue, claimNextTask, updateTaskStatus, updateSessionTaskStatus, cancelTask, requeueTask, getMeshQueueStats, getMeshQueueRevision, normalizeMeshTaskMode, validateMeshTaskModeRequest, buildMeshNodeCapabilityTags, nodeSatisfiesRequiredTags, normalizeMeshCapabilityTags, resolveConvergeRequiredTags, resolveTaskAffinityRequiredTags, insertDirectDispatch, getActiveDirectDispatches, updateDirectDispatchStatus, cleanupTerminalDirectDispatches, markStaleDirectDispatches, deleteDirectDispatchesByTaskId, recordMeshToolCall, assertNoDependencyCycle, hasPendingDependents, describeTaskDependencyState } from './mesh/mesh-work-queue.js';
53
53
  export type { MeshWorkQueueEntry, MeshTaskStatus, MeshTaskMode, MeshWorkQueueStats, MeshQueueMutationOptions, MeshTaskModeValidationResult, DirectDispatchRecord, MeshToolCallRateResult } from './mesh/mesh-work-queue.js';
54
54
  export { buildCompactStaleDirectWorkSummary, buildMeshActiveWork, buildMeshActiveWorkSummary, classifyStaleDirectForPrune, PRUNABLE_ORPHAN_STALE_REASONS } from './mesh/mesh-active-work.js';
55
55
  export type { StaleDirectPruneClassification } from './mesh/mesh-active-work.js';
package/dist/index.js CHANGED
@@ -40,6 +40,35 @@ function resolveNodeSchedulingPriority(nodePolicy) {
40
40
  const raw = Number(nodePolicy?.schedulingPriority);
41
41
  return Number.isFinite(raw) ? raw : 0;
42
42
  }
43
+ function resolveTaskAffinityRole(taskMode, policy) {
44
+ if (!taskMode) return null;
45
+ if (policy?.enabled === false) return null;
46
+ const override = policy?.byTaskMode && Object.prototype.hasOwnProperty.call(policy.byTaskMode, taskMode) ? policy.byTaskMode[taskMode] : void 0;
47
+ if (typeof override === "string") {
48
+ const trimmed = override.trim().toLowerCase();
49
+ return trimmed ? trimmed : null;
50
+ }
51
+ const fallback = DEFAULT_TASKMODE_ROLE_MAP[taskMode];
52
+ return fallback ?? null;
53
+ }
54
+ function resolveMeshRoleOptions(policy) {
55
+ const out = [...STANDARD_MESH_ROLES];
56
+ const seen = new Set(out);
57
+ const add = (raw) => {
58
+ if (typeof raw !== "string") return;
59
+ const role = raw.trim().toLowerCase();
60
+ if (!role || seen.has(role)) return;
61
+ seen.add(role);
62
+ out.push(role);
63
+ };
64
+ if (policy?.byTaskMode) {
65
+ for (const value of Object.values(policy.byTaskMode)) add(value);
66
+ }
67
+ if (Array.isArray(policy?.customRoles)) {
68
+ for (const value of policy.customRoles) add(value);
69
+ }
70
+ return out;
71
+ }
43
72
  function resolveAutoConvergeCodeChange(policy) {
44
73
  return policy?.autoConvergeCodeChange === true;
45
74
  }
@@ -70,7 +99,7 @@ function resolveProviderMaxParallel(nodePolicy, providerType) {
70
99
  if (!Number.isFinite(raw) || raw < 0) return void 0;
71
100
  return Math.floor(raw);
72
101
  }
73
- var MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, DEFAULT_MESH_POLICY;
102
+ var MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, STANDARD_MESH_ROLES, DEFAULT_TASKMODE_ROLE_MAP, DEFAULT_MESH_POLICY;
74
103
  var init_repo_mesh_types = __esm({
75
104
  "src/repo-mesh-types.ts"() {
76
105
  "use strict";
@@ -83,6 +112,14 @@ var init_repo_mesh_types = __esm({
83
112
  DEFAULT_MESH_SCHEDULING_STRATEGY = "first_eligible";
84
113
  MESH_CONVERGE_REFINE_TAG = "converge=refine";
85
114
  MESH_CONVERGE_FAST_FORWARD_TAG = "converge=fast_forward";
115
+ STANDARD_MESH_ROLES = ["investigator", "coder", "validator", "converger"];
116
+ DEFAULT_TASKMODE_ROLE_MAP = {
117
+ live_debug_readonly: "investigator",
118
+ code_change: "coder",
119
+ launch_app: "coder",
120
+ validation: "validator",
121
+ convergence: "converger"
122
+ };
86
123
  DEFAULT_MESH_POLICY = {
87
124
  requirePreTaskCheckpoint: false,
88
125
  requirePostTaskCheckpoint: true,
@@ -316,10 +353,10 @@ function readInjected(value) {
316
353
  }
317
354
  function getDaemonBuildInfo() {
318
355
  if (cached) return cached;
319
- const commit = readInjected(true ? "f236ed7432cf04dbcfd2e530fa6c69e77e809c80" : void 0) ?? "unknown";
320
- const commitShort = readInjected(true ? "f236ed74" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
- const version = readInjected(true ? "0.9.82-rc.314" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
- const builtAt = readInjected(true ? "2026-06-18T04:15:40.033Z" : void 0);
356
+ const commit = readInjected(true ? "930909642b3f28668483159d3a8f39d0a796c61a" : void 0) ?? "unknown";
357
+ const commitShort = readInjected(true ? "93090964" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
358
+ const version = readInjected(true ? "0.9.82-rc.316" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
359
+ const builtAt = readInjected(true ? "2026-06-18T07:23:07.242Z" : void 0);
323
360
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
324
361
  return cached;
325
362
  }
@@ -1577,8 +1614,61 @@ function mergeMeshPolicy(base, patch) {
1577
1614
  } else {
1578
1615
  delete policy.autoConvergeCodeChange;
1579
1616
  }
1617
+ const normalizedAffinity = normalizeTaskAffinityPolicy(policy.taskAffinity);
1618
+ if (normalizedAffinity) {
1619
+ policy.taskAffinity = normalizedAffinity;
1620
+ } else {
1621
+ delete policy.taskAffinity;
1622
+ }
1580
1623
  return policy;
1581
1624
  }
1625
+ function normalizeTaskAffinityPolicy(value) {
1626
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1627
+ const record = value;
1628
+ const out = {};
1629
+ let hasContent = false;
1630
+ if (typeof record.enabled === "boolean") {
1631
+ out.enabled = record.enabled;
1632
+ if (record.enabled === false) hasContent = true;
1633
+ else delete out.enabled;
1634
+ }
1635
+ if (record.byTaskMode && typeof record.byTaskMode === "object" && !Array.isArray(record.byTaskMode)) {
1636
+ const byTaskMode = {};
1637
+ for (const [mode, raw] of Object.entries(record.byTaskMode)) {
1638
+ const modeKey = mode.trim();
1639
+ if (!modeKey) continue;
1640
+ if (typeof raw !== "string") continue;
1641
+ const role = raw.trim().toLowerCase();
1642
+ byTaskMode[modeKey] = role;
1643
+ if (role && !STANDARD_MESH_ROLES.includes(role)) {
1644
+ try {
1645
+ console.warn(`[mesh] task_affinity.byTaskMode.${modeKey}: custom role "${role}" is not a standard mesh role (${STANDARD_MESH_ROLES.join("/")}); routing still applies`);
1646
+ } catch {
1647
+ }
1648
+ }
1649
+ }
1650
+ if (Object.keys(byTaskMode).length > 0) {
1651
+ out.byTaskMode = byTaskMode;
1652
+ hasContent = true;
1653
+ }
1654
+ }
1655
+ if (Array.isArray(record.customRoles)) {
1656
+ const seen = /* @__PURE__ */ new Set();
1657
+ const customRoles = [];
1658
+ for (const raw of record.customRoles) {
1659
+ if (typeof raw !== "string") continue;
1660
+ const role = raw.trim().toLowerCase();
1661
+ if (!role || seen.has(role)) continue;
1662
+ seen.add(role);
1663
+ customRoles.push(role);
1664
+ }
1665
+ if (customRoles.length > 0) {
1666
+ out.customRoles = customRoles;
1667
+ hasContent = true;
1668
+ }
1669
+ }
1670
+ return hasContent ? out : void 0;
1671
+ }
1582
1672
  function normalizeAutoFastForwardPolicy(value) {
1583
1673
  const record = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1584
1674
  const maxBehind = Number(record.maxBehind);
@@ -2872,6 +2962,7 @@ __export(mesh_work_queue_exports, {
2872
2962
  recordTaskAutoLaunch: () => recordTaskAutoLaunch,
2873
2963
  requeueTask: () => requeueTask,
2874
2964
  resolveConvergeRequiredTags: () => resolveConvergeRequiredTags,
2965
+ resolveTaskAffinityRequiredTags: () => resolveTaskAffinityRequiredTags,
2875
2966
  updateDirectDispatchStatus: () => updateDirectDispatchStatus,
2876
2967
  updateSessionTaskStatus: () => updateSessionTaskStatus,
2877
2968
  updateTaskStatus: () => updateTaskStatus,
@@ -3010,6 +3101,31 @@ function resolveConvergeRequiredTags(meshId, taskMode, explicitRequiredTags, opt
3010
3101
  if (!optedIn) return explicitRequiredTags;
3011
3102
  return normalizeMeshCapabilityTags([...explicitRequiredTags, MESH_CONVERGE_REFINE_TAG]);
3012
3103
  }
3104
+ function meshHasNodeAdvertisingRole(nodes, role) {
3105
+ if (!Array.isArray(nodes) || nodes.length === 0) return false;
3106
+ const wanted = `role=${role}`;
3107
+ return nodes.some((node) => buildMeshNodeCapabilityTags(node).includes(wanted));
3108
+ }
3109
+ function resolveTaskAffinityRequiredTags(meshId, taskMode, explicitRequiredTags, opts) {
3110
+ if (typeof opts?.targetNodeId === "string" && opts.targetNodeId.trim()) return explicitRequiredTags;
3111
+ if (opts?.callerSpecifiedRequiredTags === true) return explicitRequiredTags;
3112
+ let mesh;
3113
+ try {
3114
+ mesh = getMesh(meshId);
3115
+ } catch {
3116
+ return explicitRequiredTags;
3117
+ }
3118
+ const role = resolveTaskAffinityRole(taskMode, mesh?.policy?.taskAffinity);
3119
+ if (!role) return explicitRequiredTags;
3120
+ if (!meshHasNodeAdvertisingRole(mesh?.nodes, role)) {
3121
+ try {
3122
+ console.warn(`[mesh] task_affinity: no node advertises role=${role} for taskMode=${taskMode} in mesh ${meshId}; skipping injection (least_loaded fallback)`);
3123
+ } catch {
3124
+ }
3125
+ return explicitRequiredTags;
3126
+ }
3127
+ return normalizeMeshCapabilityTags([...explicitRequiredTags, `role=${role}`]);
3128
+ }
3013
3129
  function withQueueLock(_meshId, fn) {
3014
3130
  return MeshRuntimeStore.getInstance().transaction(fn);
3015
3131
  }
@@ -3060,6 +3176,20 @@ function enqueueTask(meshId, message, opts) {
3060
3176
  throw new Error(`duplicate_task_id: task '${id}' already exists in mesh '${meshId}'`);
3061
3177
  }
3062
3178
  assertNoDependencyCycle(meshId, id, dependsOn);
3179
+ const callerTags = normalizeMeshCapabilityTags(opts?.requiredTags);
3180
+ const callerSpecifiedRequiredTags = callerTags.length > 0;
3181
+ let resolvedRequiredTags = resolveConvergeRequiredTags(
3182
+ meshId,
3183
+ modeValidation.taskMode,
3184
+ callerTags,
3185
+ { targetNodeId: opts?.targetNodeId }
3186
+ );
3187
+ resolvedRequiredTags = resolveTaskAffinityRequiredTags(
3188
+ meshId,
3189
+ modeValidation.taskMode,
3190
+ resolvedRequiredTags,
3191
+ { targetNodeId: opts?.targetNodeId, callerSpecifiedRequiredTags }
3192
+ );
3063
3193
  const entry = {
3064
3194
  id,
3065
3195
  meshId,
@@ -3068,15 +3198,7 @@ function enqueueTask(meshId, message, opts) {
3068
3198
  taskMode: modeValidation.taskMode,
3069
3199
  targetNodeId: opts?.targetNodeId,
3070
3200
  targetSessionId: opts?.targetSessionId,
3071
- // Convergence routing (opt-in): auto-inject converge=refine for code_change
3072
- // tasks so they hard-filter onto refine-capable worktree nodes. No-op unless
3073
- // the mesh opts in; explicit target_node_id / required_tags are preserved.
3074
- requiredTags: resolveConvergeRequiredTags(
3075
- meshId,
3076
- modeValidation.taskMode,
3077
- normalizeMeshCapabilityTags(opts?.requiredTags),
3078
- { targetNodeId: opts?.targetNodeId }
3079
- ),
3201
+ requiredTags: resolvedRequiredTags,
3080
3202
  ...dependsOn.length > 0 ? { dependsOn } : {},
3081
3203
  ...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
3082
3204
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -10961,8 +11083,24 @@ function findBinary(name) {
10961
11083
  }
10962
11084
  const isWin = os12.platform() === "win32";
10963
11085
  const paths = (process.env.PATH || "").split(path17.delimiter);
11086
+ const extraDirs = [];
11087
+ if (isWin) {
11088
+ if (process.env.APPDATA) extraDirs.push(path17.join(process.env.APPDATA, "npm"));
11089
+ try {
11090
+ extraDirs.push(path17.dirname(process.execPath));
11091
+ } catch {
11092
+ }
11093
+ } else {
11094
+ extraDirs.push(path17.join(os12.homedir(), ".npm-global", "bin"));
11095
+ extraDirs.push("/usr/local/bin", "/opt/homebrew/bin");
11096
+ try {
11097
+ extraDirs.push(path17.dirname(process.execPath));
11098
+ } catch {
11099
+ }
11100
+ }
11101
+ const searchDirs = [...paths, ...extraDirs];
10964
11102
  const exes = isWin ? [".exe", ".cmd", ".bat", ""] : [""];
10965
- for (const p of paths) {
11103
+ for (const p of searchDirs) {
10966
11104
  if (!p) continue;
10967
11105
  for (const ext of exes) {
10968
11106
  const fullPath = path17.join(p, trimmed + ext);
@@ -14362,6 +14500,37 @@ ${lastSnapshot}`;
14362
14500
  if (!this.ptyProcess || typeof this.ptyProcess.getMetadata !== "function") return null;
14363
14501
  return this.ptyProcess.getMetadata();
14364
14502
  }
14503
+ /**
14504
+ * Launch metadata for the dashboard Session info panel. Re-derives the spawn plan
14505
+ * (pure — same inputs the live PTY was spawned with) so the dashboard sees the
14506
+ * resolved binary, full arg vector, and cwd without us having to persist it.
14507
+ * extraEnv values are intentionally dropped (keys only) so secrets passed at
14508
+ * launch time never reach the dashboard.
14509
+ */
14510
+ getLaunchInfo() {
14511
+ let command;
14512
+ let args = [...this.extraArgs];
14513
+ try {
14514
+ const plan = resolveCliSpawnPlan({
14515
+ provider: this.provider,
14516
+ runtimeSettings: this.runtimeSettings,
14517
+ workingDir: this.workingDir,
14518
+ extraArgs: this.extraArgs,
14519
+ extraEnv: this.extraEnv
14520
+ });
14521
+ command = plan.binaryPath;
14522
+ args = plan.allArgs;
14523
+ } catch {
14524
+ }
14525
+ return {
14526
+ command,
14527
+ args,
14528
+ extraArgs: [...this.extraArgs],
14529
+ cwd: this.workingDir,
14530
+ extraEnvKeys: Object.keys(this.extraEnv || {}),
14531
+ providerSessionId: this.providerSessionId || void 0
14532
+ };
14533
+ }
14365
14534
  updateRuntimeMeta(meta, replace = false) {
14366
14535
  const nextProviderSessionId = typeof meta?.providerSessionId === "string" ? meta.providerSessionId.trim() : "";
14367
14536
  if (nextProviderSessionId) {
@@ -15704,6 +15873,7 @@ __export(index_exports, {
15704
15873
  DEFAULT_STATUS_INITIAL_REPORT_DELAY_MS: () => DEFAULT_STATUS_INITIAL_REPORT_DELAY_MS,
15705
15874
  DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS: () => DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS,
15706
15875
  DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS: () => DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS,
15876
+ DEFAULT_TASKMODE_ROLE_MAP: () => DEFAULT_TASKMODE_ROLE_MAP,
15707
15877
  DEV_SERVER_PORT: () => DEV_SERVER_PORT,
15708
15878
  DaemonAgentStreamManager: () => DaemonAgentStreamManager,
15709
15879
  DaemonCdpInitializer: () => DaemonCdpInitializer,
@@ -15743,6 +15913,7 @@ __export(index_exports, {
15743
15913
  RawTerminalAttachment: () => RawTerminalAttachment,
15744
15914
  STALE_TERMINAL_REFINE_WINDOW_MS: () => STALE_TERMINAL_REFINE_WINDOW_MS,
15745
15915
  STANDALONE_CDP_SCAN_INTERVAL_MS: () => STANDALONE_CDP_SCAN_INTERVAL_MS,
15916
+ STANDARD_MESH_ROLES: () => STANDARD_MESH_ROLES,
15746
15917
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
15747
15918
  TerminalAdapter: () => TerminalAdapter,
15748
15919
  TurnSnapshotTracker: () => TurnSnapshotTracker,
@@ -15976,9 +16147,12 @@ __export(index_exports, {
15976
16147
  resolveGitRepository: () => resolveGitRepository,
15977
16148
  resolveMeshHostStatus: () => resolveMeshHostStatus,
15978
16149
  resolveMeshRefineValidationPlan: () => resolveMeshRefineValidationPlan,
16150
+ resolveMeshRoleOptions: () => resolveMeshRoleOptions,
15979
16151
  resolveNodeSchedulingPriority: () => resolveNodeSchedulingPriority,
15980
16152
  resolveSessionHostAppName: () => resolveSessionHostAppName,
15981
16153
  resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
16154
+ resolveTaskAffinityRequiredTags: () => resolveTaskAffinityRequiredTags,
16155
+ resolveTaskAffinityRole: () => resolveTaskAffinityRole,
15982
16156
  resolveWorktreePath: () => resolveWorktreePath,
15983
16157
  runAsyncBatch: () => runAsyncBatch,
15984
16158
  runGit: () => runGit,
@@ -18940,8 +19114,8 @@ async function detectIDEs(providerLoader) {
18940
19114
  if ((0, import_fs12.existsSync)(bundledCli)) resolvedCli = bundledCli;
18941
19115
  }
18942
19116
  if (!resolvedCli && appPath && os30 === "win32") {
18943
- const { dirname: dirname14 } = await import("path");
18944
- const appDir = dirname14(appPath);
19117
+ const { dirname: dirname15 } = await import("path");
19118
+ const appDir = dirname15(appPath);
18945
19119
  const candidates = [
18946
19120
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
18947
19121
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -31399,6 +31573,7 @@ function collectStableSizes(when, sizes) {
31399
31573
  var fs12 = __toESM(require("fs"));
31400
31574
  var os17 = __toESM(require("os"));
31401
31575
  var path21 = __toESM(require("path"));
31576
+ init_logger();
31402
31577
  var UUID_RE = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
31403
31578
  function executeNativeHistory(cfg, input) {
31404
31579
  if (!cfg?.source) return null;
@@ -31431,8 +31606,33 @@ function executeJsonl(src, input) {
31431
31606
  if (!sourcePath && hasDateTemplateSegment(src.path)) {
31432
31607
  sourcePath = pickExactSessionFileAcrossDateWindow(src.path, input, filePat, requestedSessionId) || (requestedSessionId ? null : pickSessionBoundFileAcrossDateWindow(src.path, input, filePat, windowMs, sessionFloor, workspaceHint)) || (requestedSessionId ? null : newestRecentFileAcrossDateWindow(src.path, input, filePat, windowMs, sessionFloor));
31433
31608
  }
31609
+ if (!sourcePath && !hasDateTemplateSegment(src.path)) {
31610
+ const resolvedRaw = expandPath2(src.path, input, { skipWorkspaceRealpath: true });
31611
+ if (resolvedRaw && resolvedRaw !== resolved) {
31612
+ try {
31613
+ const rawStat = fs12.statSync(resolvedRaw);
31614
+ if (rawStat.isFile()) sourcePath = resolvedRaw;
31615
+ else if (rawStat.isDirectory()) {
31616
+ sourcePath = pickExactSessionFile(resolvedRaw, filePat, requestedSessionId) || (requestedSessionId ? null : newestRecentFile(resolvedRaw, filePat, windowMs, sessionFloor));
31617
+ }
31618
+ } catch {
31619
+ }
31620
+ }
31621
+ }
31622
+ if (!sourcePath && requestedSessionId) {
31623
+ sourcePath = scanProjectsRootForSessionFile(src.path, input, requestedSessionId);
31624
+ }
31625
+ }
31626
+ if (!sourcePath) {
31627
+ const wsRaw = typeof input.workspace === "string" ? input.workspace : "";
31628
+ let wsReal = wsRaw;
31629
+ try {
31630
+ if (wsRaw) wsReal = fs12.realpathSync(wsRaw);
31631
+ } catch {
31632
+ }
31633
+ LOG.debug("NativeHistory", `jsonl unresolved: tried=${JSON.stringify(resolved)} sessionId=${requestedSessionId || "(none)"} wsRaw=${JSON.stringify(wsRaw)} wsReal=${JSON.stringify(wsReal)} rawSlug=${JSON.stringify(claudeProjectDirName(wsRaw))} realSlug=${JSON.stringify(claudeProjectDirName(wsReal))} (concrete miss + raw-slug retry + projects scan all failed)`);
31634
+ return null;
31434
31635
  }
31435
- if (!sourcePath) return null;
31436
31636
  const mtime = safeMtimeMs(sourcePath);
31437
31637
  const lines = readJsonlLines(sourcePath);
31438
31638
  if (lines.length === 0) return null;
@@ -31551,7 +31751,7 @@ function executeSqlite(src, input) {
31551
31751
  }
31552
31752
  }
31553
31753
  }
31554
- function expandPath2(template, input) {
31754
+ function expandPath2(template, input, opts) {
31555
31755
  if (!template) return null;
31556
31756
  let out = template;
31557
31757
  if (out.startsWith("~/") || out === "~") {
@@ -31565,7 +31765,7 @@ function expandPath2(template, input) {
31565
31765
  const now = /* @__PURE__ */ new Date();
31566
31766
  const workspaceRaw = input.workspace ?? "";
31567
31767
  let workspaceResolved = workspaceRaw;
31568
- if (workspaceRaw) {
31768
+ if (workspaceRaw && !opts?.skipWorkspaceRealpath) {
31569
31769
  try {
31570
31770
  workspaceResolved = fs12.realpathSync(workspaceRaw);
31571
31771
  } catch {
@@ -31592,6 +31792,50 @@ function expandPath2(template, input) {
31592
31792
  function claudeProjectDirName(workspace) {
31593
31793
  return workspace.replace(/[^A-Za-z0-9_-]/g, "-");
31594
31794
  }
31795
+ function scanProjectsRootForSessionFile(template, input, requestedSessionId) {
31796
+ if (!requestedSessionId) return null;
31797
+ let head = template;
31798
+ if (head.startsWith("~/") || head === "~") head = path21.join(os17.homedir(), head.slice(2));
31799
+ const segs = head.split("/");
31800
+ const baseParts = [];
31801
+ for (const seg of segs) {
31802
+ if (/[{}*?]/.test(seg)) break;
31803
+ baseParts.push(seg);
31804
+ }
31805
+ const base = baseParts.join("/");
31806
+ if (!base) return null;
31807
+ let baseStat = null;
31808
+ try {
31809
+ baseStat = fs12.statSync(base);
31810
+ } catch {
31811
+ return null;
31812
+ }
31813
+ if (!baseStat.isDirectory()) return null;
31814
+ const needle = `${requestedSessionId.toLowerCase()}.jsonl`;
31815
+ const dirsToScan = [base];
31816
+ try {
31817
+ for (const entry of fs12.readdirSync(base, { withFileTypes: true })) {
31818
+ if (entry.isDirectory()) dirsToScan.push(path21.join(base, entry.name));
31819
+ }
31820
+ } catch {
31821
+ }
31822
+ for (const dir of dirsToScan) {
31823
+ let entries;
31824
+ try {
31825
+ entries = fs12.readdirSync(dir, { withFileTypes: true });
31826
+ } catch {
31827
+ continue;
31828
+ }
31829
+ for (const entry of entries) {
31830
+ if (!entry.isFile()) continue;
31831
+ if (entry.name.toLowerCase() !== needle) continue;
31832
+ const found = path21.join(dir, entry.name);
31833
+ LOG.debug("NativeHistory", `jsonl scan-fallback hit: sessionId=${requestedSessionId} resolved via projects-root scan \u2192 ${JSON.stringify(found)} (slug-derived path missed; likely realpath/slug divergence)`);
31834
+ return found;
31835
+ }
31836
+ }
31837
+ return null;
31838
+ }
31595
31839
  function globToRegex(pattern) {
31596
31840
  const re = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
31597
31841
  return new RegExp(`^${re}$`);
@@ -47034,6 +47278,7 @@ ${hintLines.join("\n")}` : "",
47034
47278
  if (!target && !coord) return { success: false, error: "Session not found", sessionId };
47035
47279
  const adapter = target ? this.deps.cliManager.findAdapter(target.providerType, { instanceKey: sessionId })?.adapter : void 0;
47036
47280
  const runtimeMeta = adapter && typeof adapter.getRuntimeMetadata === "function" ? adapter.getRuntimeMetadata() : void 0;
47281
+ const launchInfo = adapter && typeof adapter.getLaunchInfo === "function" ? adapter.getLaunchInfo() : void 0;
47037
47282
  const providerType = target?.providerType || coord?.cliType || "";
47038
47283
  const providerMetaForSession = providerType ? this.deps.providerLoader.resolve?.(providerType) || this.deps.providerLoader.getMeta(providerType) : void 0;
47039
47284
  return {
@@ -47045,8 +47290,11 @@ ${hintLines.join("\n")}` : "",
47045
47290
  transport: target?.transport,
47046
47291
  workspace: target?.workspace || coord?.workspace,
47047
47292
  spawnedAtMs: target?.spawnedAtMs || coord?.startedAt,
47048
- providerSessionId: target?.providerSessionId,
47049
- runtimeMetadata: runtimeMeta
47293
+ // providerSessionId now comes from the live adapter's launch info
47294
+ // (the registry target never carried it — it was always undefined).
47295
+ providerSessionId: launchInfo?.providerSessionId || target?.providerSessionId,
47296
+ runtimeMetadata: runtimeMeta,
47297
+ launch: launchInfo
47050
47298
  },
47051
47299
  coordinator: coord ? {
47052
47300
  meshId: coord.meshId,
@@ -48887,7 +49135,7 @@ ${ptyResult.output.slice(-2e3)}`);
48887
49135
  };
48888
49136
  }
48889
49137
  const { existsSync: existsSync44, readFileSync: readFileSync35, writeFileSync: writeFileSync23, copyFileSync: copyFileSync4, mkdirSync: mkdirSync21 } = await import("fs");
48890
- const { dirname: dirname14 } = await import("path");
49138
+ const { dirname: dirname15 } = await import("path");
48891
49139
  const mcpConfigPath = coordinatorSetup.configPath;
48892
49140
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
48893
49141
  let hermesBaseConfig = null;
@@ -48922,7 +49170,7 @@ ${ptyResult.output.slice(-2e3)}`);
48922
49170
  };
48923
49171
  }
48924
49172
  try {
48925
- mkdirSync21(dirname14(mcpConfigPath), { recursive: true });
49173
+ mkdirSync21(dirname15(mcpConfigPath), { recursive: true });
48926
49174
  } catch (error) {
48927
49175
  const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
48928
49176
  LOG.error("MeshCoordinator", message);
@@ -48932,7 +49180,7 @@ ${ptyResult.output.slice(-2e3)}`);
48932
49180
  const hadExistingMcpConfig = existsSync44(mcpConfigPath);
48933
49181
  let existingMcpConfig = hermesBaseConfig?.config || {};
48934
49182
  if (hermesBaseConfig) {
48935
- copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname14(mcpConfigPath));
49183
+ copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname15(mcpConfigPath));
48936
49184
  }
48937
49185
  if (hadExistingMcpConfig) {
48938
49186
  try {
@@ -48970,7 +49218,7 @@ ${ptyResult.output.slice(-2e3)}`);
48970
49218
  const cliArgs = [];
48971
49219
  const launchEnv = {};
48972
49220
  if (configFormat === "hermes_config_yaml") {
48973
- launchEnv.HERMES_HOME = dirname14(mcpConfigPath);
49221
+ launchEnv.HERMES_HOME = dirname15(mcpConfigPath);
48974
49222
  launchEnv.HERMES_IGNORE_USER_CONFIG = "";
48975
49223
  }
48976
49224
  let autoImportContextFilePath;
@@ -58098,6 +58346,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
58098
58346
  DEFAULT_STATUS_INITIAL_REPORT_DELAY_MS,
58099
58347
  DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS,
58100
58348
  DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS,
58349
+ DEFAULT_TASKMODE_ROLE_MAP,
58101
58350
  DEV_SERVER_PORT,
58102
58351
  DaemonAgentStreamManager,
58103
58352
  DaemonCdpInitializer,
@@ -58137,6 +58386,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
58137
58386
  RawTerminalAttachment,
58138
58387
  STALE_TERMINAL_REFINE_WINDOW_MS,
58139
58388
  STANDALONE_CDP_SCAN_INTERVAL_MS,
58389
+ STANDARD_MESH_ROLES,
58140
58390
  SessionHostPtyTransportFactory,
58141
58391
  TerminalAdapter,
58142
58392
  TurnSnapshotTracker,
@@ -58370,9 +58620,12 @@ var V1_CONTRACT_VERSION = "1.0.0";
58370
58620
  resolveGitRepository,
58371
58621
  resolveMeshHostStatus,
58372
58622
  resolveMeshRefineValidationPlan,
58623
+ resolveMeshRoleOptions,
58373
58624
  resolveNodeSchedulingPriority,
58374
58625
  resolveSessionHostAppName,
58375
58626
  resolveSessionHostAppNameResolution,
58627
+ resolveTaskAffinityRequiredTags,
58628
+ resolveTaskAffinityRole,
58376
58629
  resolveWorktreePath,
58377
58630
  runAsyncBatch,
58378
58631
  runGit,