@adhdev/daemon-core 0.9.82-rc.315 → 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 ? "e28347641639c9d0a1e46a6141e3cfed2bc90ac2" : void 0) ?? "unknown";
320
- const commitShort = readInjected(true ? "e2834764" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
- const version = readInjected(true ? "0.9.82-rc.315" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
- const builtAt = readInjected(true ? "2026-06-18T05:47:44.462Z" : 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}`,
@@ -47104,6 +47278,7 @@ ${hintLines.join("\n")}` : "",
47104
47278
  if (!target && !coord) return { success: false, error: "Session not found", sessionId };
47105
47279
  const adapter = target ? this.deps.cliManager.findAdapter(target.providerType, { instanceKey: sessionId })?.adapter : void 0;
47106
47280
  const runtimeMeta = adapter && typeof adapter.getRuntimeMetadata === "function" ? adapter.getRuntimeMetadata() : void 0;
47281
+ const launchInfo = adapter && typeof adapter.getLaunchInfo === "function" ? adapter.getLaunchInfo() : void 0;
47107
47282
  const providerType = target?.providerType || coord?.cliType || "";
47108
47283
  const providerMetaForSession = providerType ? this.deps.providerLoader.resolve?.(providerType) || this.deps.providerLoader.getMeta(providerType) : void 0;
47109
47284
  return {
@@ -47115,8 +47290,11 @@ ${hintLines.join("\n")}` : "",
47115
47290
  transport: target?.transport,
47116
47291
  workspace: target?.workspace || coord?.workspace,
47117
47292
  spawnedAtMs: target?.spawnedAtMs || coord?.startedAt,
47118
- providerSessionId: target?.providerSessionId,
47119
- 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
47120
47298
  },
47121
47299
  coordinator: coord ? {
47122
47300
  meshId: coord.meshId,
@@ -48957,7 +49135,7 @@ ${ptyResult.output.slice(-2e3)}`);
48957
49135
  };
48958
49136
  }
48959
49137
  const { existsSync: existsSync44, readFileSync: readFileSync35, writeFileSync: writeFileSync23, copyFileSync: copyFileSync4, mkdirSync: mkdirSync21 } = await import("fs");
48960
- const { dirname: dirname14 } = await import("path");
49138
+ const { dirname: dirname15 } = await import("path");
48961
49139
  const mcpConfigPath = coordinatorSetup.configPath;
48962
49140
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
48963
49141
  let hermesBaseConfig = null;
@@ -48992,7 +49170,7 @@ ${ptyResult.output.slice(-2e3)}`);
48992
49170
  };
48993
49171
  }
48994
49172
  try {
48995
- mkdirSync21(dirname14(mcpConfigPath), { recursive: true });
49173
+ mkdirSync21(dirname15(mcpConfigPath), { recursive: true });
48996
49174
  } catch (error) {
48997
49175
  const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
48998
49176
  LOG.error("MeshCoordinator", message);
@@ -49002,7 +49180,7 @@ ${ptyResult.output.slice(-2e3)}`);
49002
49180
  const hadExistingMcpConfig = existsSync44(mcpConfigPath);
49003
49181
  let existingMcpConfig = hermesBaseConfig?.config || {};
49004
49182
  if (hermesBaseConfig) {
49005
- copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname14(mcpConfigPath));
49183
+ copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname15(mcpConfigPath));
49006
49184
  }
49007
49185
  if (hadExistingMcpConfig) {
49008
49186
  try {
@@ -49040,7 +49218,7 @@ ${ptyResult.output.slice(-2e3)}`);
49040
49218
  const cliArgs = [];
49041
49219
  const launchEnv = {};
49042
49220
  if (configFormat === "hermes_config_yaml") {
49043
- launchEnv.HERMES_HOME = dirname14(mcpConfigPath);
49221
+ launchEnv.HERMES_HOME = dirname15(mcpConfigPath);
49044
49222
  launchEnv.HERMES_IGNORE_USER_CONFIG = "";
49045
49223
  }
49046
49224
  let autoImportContextFilePath;
@@ -58168,6 +58346,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
58168
58346
  DEFAULT_STATUS_INITIAL_REPORT_DELAY_MS,
58169
58347
  DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS,
58170
58348
  DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS,
58349
+ DEFAULT_TASKMODE_ROLE_MAP,
58171
58350
  DEV_SERVER_PORT,
58172
58351
  DaemonAgentStreamManager,
58173
58352
  DaemonCdpInitializer,
@@ -58207,6 +58386,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
58207
58386
  RawTerminalAttachment,
58208
58387
  STALE_TERMINAL_REFINE_WINDOW_MS,
58209
58388
  STANDALONE_CDP_SCAN_INTERVAL_MS,
58389
+ STANDARD_MESH_ROLES,
58210
58390
  SessionHostPtyTransportFactory,
58211
58391
  TerminalAdapter,
58212
58392
  TurnSnapshotTracker,
@@ -58440,9 +58620,12 @@ var V1_CONTRACT_VERSION = "1.0.0";
58440
58620
  resolveGitRepository,
58441
58621
  resolveMeshHostStatus,
58442
58622
  resolveMeshRefineValidationPlan,
58623
+ resolveMeshRoleOptions,
58443
58624
  resolveNodeSchedulingPriority,
58444
58625
  resolveSessionHostAppName,
58445
58626
  resolveSessionHostAppNameResolution,
58627
+ resolveTaskAffinityRequiredTags,
58628
+ resolveTaskAffinityRole,
58446
58629
  resolveWorktreePath,
58447
58630
  runAsyncBatch,
58448
58631
  runGit,