@adhdev/daemon-core 0.9.82-rc.437 → 0.9.82-rc.439

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/dist/index.js CHANGED
@@ -409,10 +409,10 @@ function readInjected(value) {
409
409
  }
410
410
  function getDaemonBuildInfo() {
411
411
  if (cached) return cached;
412
- const commit = readInjected(true ? "07c5209009300611151cd8363b63b4b066b6ecec" : void 0) ?? "unknown";
413
- const commitShort = readInjected(true ? "07c52090" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
414
- const version = readInjected(true ? "0.9.82-rc.437" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
415
- const builtAt = readInjected(true ? "2026-07-01T00:49:44.850Z" : void 0);
412
+ const commit = readInjected(true ? "065287032ac520cf8950f90025e1758b873723b1" : void 0) ?? "unknown";
413
+ const commitShort = readInjected(true ? "06528703" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
414
+ const version = readInjected(true ? "0.9.82-rc.439" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
415
+ const builtAt = readInjected(true ? "2026-07-01T04:55:17.522Z" : void 0);
416
416
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
417
417
  return cached;
418
418
  }
@@ -2863,16 +2863,21 @@ __export(mesh_config_exports, {
2863
2863
  createMesh: () => createMesh,
2864
2864
  createMeshHostPairingToken: () => createMeshHostPairingToken,
2865
2865
  deleteMesh: () => deleteMesh,
2866
+ getMagiKindPanel: () => getMagiKindPanel,
2866
2867
  getMagiPanel: () => getMagiPanel,
2867
2868
  getMesh: () => getMesh,
2868
2869
  getMeshByRepo: () => getMeshByRepo,
2870
+ listMagiKindPanels: () => listMagiKindPanels,
2869
2871
  listMagiPanels: () => listMagiPanels,
2870
2872
  listMeshes: () => listMeshes,
2871
2873
  markMeshHostPairingJoined: () => markMeshHostPairingJoined,
2872
2874
  normalizeMagiPanel: () => normalizeMagiPanel,
2875
+ normalizeMagiSlots: () => normalizeMagiSlots,
2873
2876
  normalizeRepoIdentity: () => normalizeRepoIdentity,
2877
+ removeMagiKindPanel: () => removeMagiKindPanel,
2874
2878
  removeMagiPanel: () => removeMagiPanel,
2875
2879
  removeNode: () => removeNode,
2880
+ setMagiKindPanel: () => setMagiKindPanel,
2876
2881
  tokenIdForManualPairing: () => tokenIdForManualPairing,
2877
2882
  updateMesh: () => updateMesh,
2878
2883
  updateNode: () => updateNode,
@@ -3288,11 +3293,13 @@ function normalizeMagiPanel(config) {
3288
3293
  throw new Error(`invalid_magi_panel: member[${idx}].provider is required`);
3289
3294
  }
3290
3295
  const nodeId = typeof m.nodeId === "string" && m.nodeId.trim() ? m.nodeId.trim() : void 0;
3296
+ const model = typeof m.model === "string" && m.model.trim() ? m.model.trim() : void 0;
3291
3297
  const capabilityTags = normalizeCapabilityTags(m.capabilityTags);
3292
3298
  const n = normalizeReplicaCount(m.n);
3293
3299
  return {
3294
3300
  provider,
3295
3301
  ...nodeId ? { nodeId } : {},
3302
+ ...model ? { model } : {},
3296
3303
  ...capabilityTags ? { capabilityTags } : {},
3297
3304
  ...n !== void 0 ? { n } : {}
3298
3305
  };
@@ -3345,7 +3352,78 @@ function removeMagiPanel(name) {
3345
3352
  saveMeshConfig(stored);
3346
3353
  return true;
3347
3354
  }
3348
- var import_fs3, import_path3, import_crypto3, mergeMeshPolicy, MAX_MAGI_PANEL_MEMBERS;
3355
+ function normalizeMagiTaskKindKey(raw) {
3356
+ const s2 = typeof raw === "string" ? raw.trim().toLowerCase() : "";
3357
+ if (!MAGI_KIND_PANEL_KINDS.includes(s2)) {
3358
+ throw new Error(`invalid_magi_kind_panel: task_kind must be one of ${MAGI_KIND_PANEL_KINDS.join(" / ")} (got '${s2 || "(empty)"}')`);
3359
+ }
3360
+ return s2;
3361
+ }
3362
+ function normalizeMagiSlots(slots) {
3363
+ if (!Array.isArray(slots) || slots.length === 0) {
3364
+ throw new Error("invalid_magi_kind_panel: slots must be a non-empty array");
3365
+ }
3366
+ if (slots.length > MAX_MAGI_KIND_SLOTS) {
3367
+ throw new Error(`invalid_magi_kind_panel: too many slots (max ${MAX_MAGI_KIND_SLOTS})`);
3368
+ }
3369
+ return slots.map((entry, idx) => {
3370
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
3371
+ throw new Error(`invalid_magi_kind_panel: slot[${idx}] must be an object`);
3372
+ }
3373
+ const s2 = entry;
3374
+ const provider = typeof s2.provider === "string" ? s2.provider.trim() : "";
3375
+ if (!provider) {
3376
+ throw new Error(`invalid_magi_kind_panel: slot[${idx}].provider is required`);
3377
+ }
3378
+ const nodeId = typeof s2.nodeId === "string" && s2.nodeId.trim() ? s2.nodeId.trim() : void 0;
3379
+ const model = typeof s2.model === "string" && s2.model.trim() ? s2.model.trim() : void 0;
3380
+ const capabilityTags = normalizeCapabilityTags(s2.capabilityTags);
3381
+ const n = normalizeReplicaCount(s2.n);
3382
+ return {
3383
+ provider,
3384
+ ...nodeId ? { nodeId } : {},
3385
+ ...model ? { model } : {},
3386
+ ...capabilityTags ? { capabilityTags } : {},
3387
+ ...n !== void 0 ? { n } : {}
3388
+ };
3389
+ });
3390
+ }
3391
+ function listMagiKindPanels() {
3392
+ return loadMeshConfig().magiKindPanels ?? {};
3393
+ }
3394
+ function getMagiKindPanel(kind) {
3395
+ let key2;
3396
+ try {
3397
+ key2 = normalizeMagiTaskKindKey(kind);
3398
+ } catch {
3399
+ return void 0;
3400
+ }
3401
+ return loadMeshConfig().magiKindPanels?.[key2];
3402
+ }
3403
+ function setMagiKindPanel(kind, slots) {
3404
+ const key2 = normalizeMagiTaskKindKey(kind);
3405
+ const normalized = normalizeMagiSlots(slots);
3406
+ const stored = loadMeshConfig();
3407
+ const map = stored.magiKindPanels ?? {};
3408
+ map[key2] = normalized;
3409
+ stored.magiKindPanels = map;
3410
+ saveMeshConfig(stored);
3411
+ return normalized;
3412
+ }
3413
+ function removeMagiKindPanel(kind) {
3414
+ let key2;
3415
+ try {
3416
+ key2 = normalizeMagiTaskKindKey(kind);
3417
+ } catch {
3418
+ return false;
3419
+ }
3420
+ const stored = loadMeshConfig();
3421
+ if (!stored.magiKindPanels || !stored.magiKindPanels[key2]) return false;
3422
+ delete stored.magiKindPanels[key2];
3423
+ saveMeshConfig(stored);
3424
+ return true;
3425
+ }
3426
+ var import_fs3, import_path3, import_crypto3, mergeMeshPolicy, MAX_MAGI_PANEL_MEMBERS, MAGI_KIND_PANEL_KINDS, MAX_MAGI_KIND_SLOTS;
3349
3427
  var init_mesh_config = __esm({
3350
3428
  "src/config/mesh-config.ts"() {
3351
3429
  "use strict";
@@ -3358,6 +3436,8 @@ var init_mesh_config = __esm({
3358
3436
  init_mesh_host_ownership();
3359
3437
  mergeMeshPolicy = mergeAndNormalizePolicy;
3360
3438
  MAX_MAGI_PANEL_MEMBERS = 24;
3439
+ MAGI_KIND_PANEL_KINDS = ["claim_audit", "rca", "design", "freeform"];
3440
+ MAX_MAGI_KIND_SLOTS = 24;
3361
3441
  }
3362
3442
  });
3363
3443
 
@@ -3421,6 +3501,7 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
3421
3501
  sections.push(TOOLS_SECTION);
3422
3502
  sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
3423
3503
  sections.push(WORKFLOW_SECTION);
3504
+ sections.push(ONBOARDING_SECTION);
3424
3505
  sections.push(buildRulesSection(coordinatorCliType));
3425
3506
  return sections.join("\n\n");
3426
3507
  }
@@ -3453,6 +3534,7 @@ function expandPromptPlaceholders(template, ctx) {
3453
3534
  policy: buildPolicySection(mergeAndNormalizePolicy(void 0, mesh.policy)),
3454
3535
  tools: TOOLS_SECTION,
3455
3536
  workflow: WORKFLOW_SECTION,
3537
+ onboarding: ONBOARDING_SECTION,
3456
3538
  rules: buildRulesSection(coordinatorCliType),
3457
3539
  toolExposurePreflight: TOOL_EXPOSURE_PREFLIGHT_SECTION
3458
3540
  };
@@ -3611,7 +3693,7 @@ function buildRulesSection(coordinatorCliType) {
3611
3693
  - **Never fabricate tool results.** Always call the actual tool.
3612
3694
  - **Keep the user informed.** One or two sentences after each delegation round.${coordinatorNote}`;
3613
3695
  }
3614
- var fs2, os2, path8, TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION;
3696
+ var fs2, os2, path8, TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION, ONBOARDING_SECTION;
3615
3697
  var init_coordinator_prompt = __esm({
3616
3698
  "src/mesh/coordinator-prompt.ts"() {
3617
3699
  "use strict";
@@ -3643,7 +3725,12 @@ var init_coordinator_prompt = __esm({
3643
3725
  | \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
3644
3726
  | \`mesh_refine_node\` | Validate and merge a completed worktree node back into its base branch |
3645
3727
  | \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |
3646
- | \`mesh_cleanup_sessions\` | Manually clean up delegated session records for a node |`;
3728
+ | \`mesh_cleanup_sessions\` | Manually clean up delegated session records for a node |
3729
+ | \`mesh_init\` | Guided onboarding for a fresh repo: dry-run scan \u2192 suggest \`.adhdev/*\` configs (refine/bootstrap/change-impact) + providerPriority + current-config echo; gated write on approval |
3730
+ | \`mesh_reinit\` | Re-onboard an already-configured repo: re-suggest with overwrite semantics + current-vs-suggested diff; dry-run preview first, per-section approval before write |
3731
+ | \`mesh_write_mesh_json_config\` | Gated write of \`.adhdev/mesh.json\` (repo coordinator-prompt config) from the mesh entry \u2014 dry-run/overwrite like mesh_init |
3732
+ | \`mesh_magi_kind_panel_set\` | Bind a task_kind \u2192 MAGI kind-panel slots (machine-local, wholesale replacement \u2014 approve current-vs-new first) |
3733
+ | \`mesh_magi_kind_panel_list\` | List configured task_kind \u2192 MAGI kind-panel slot bindings (machine-local, read-only) |`;
3647
3734
  TOOL_EXPOSURE_PREFLIGHT_SECTION = `## Tool Exposure Preflight
3648
3735
 
3649
3736
  Before doing any coordinator work, confirm that the actual callable tool list includes \`mesh_status\` and the other \`mesh_*\` tools from the table above. If this Repo Mesh coordinator prompt is present but the callable \`mesh_*\` tools are missing, the MCP server/tool manifest is stale or not injected yet. Do not substitute terminal/file/git tools, do not inspect or edit the repository directly, and do not continue as a non-mesh local coding agent. Stop immediately and tell the user to run \`/reload-mcp\` or start a fresh coordinator session so ADHDev can reconnect \`adhdev-mesh\`.`;
@@ -3676,6 +3763,28 @@ Follow these recovery rules:
3676
3763
  2. **If "Max retries exceeded"**: Do NOT retry on the same node. Either reassign the task to a different node, or inform the user that the task requires manual intervention.
3677
3764
  3. **If no recovery context**: The stop may be intentional (normal completion). Use \`mesh_read_chat\` once to verify, then move on.
3678
3765
  4. **Always record what happened**: After handling a failure, briefly note the outcome in your report to the user.`;
3766
+ ONBOARDING_SECTION = `## Onboarding / Reinit
3767
+
3768
+ When the user asks to **set up / configure / onboard** this repo for Repo Mesh (or to **re-init / reconfigure** an already-onboarded repo), run ONE guided, approval-gated conversation. You draft, the user approves, the daemon writes. Never auto-write a heuristic suggestion without an explicit user approval turn.
3769
+
3770
+ **Save scopes \u2014 label every draft with its scope before asking for approval:**
3771
+ - **repo-file (commit target)** \u2014 \`.adhdev/refine.json\`, \`.adhdev/worktree_bootstrap.json\`, \`.adhdev/change-impact.json\`, \`.adhdev/mesh.json\`. These are committed to the repository and shared with every machine/contributor.
3772
+ - **machine-local** \u2014 MAGI kind\u2192panel bindings and named MAGI panels, node providerPriority (\`~/.adhdev/meshes.json\`). These stay on this machine and are NOT committed.
3773
+
3774
+ **Guided sequence:**
3775
+ 1. **Scan (dry-run)** \u2014 Call \`mesh_init\` (write=false, the default). It returns per-domain suggested configs for refine / worktree_bootstrap / change-impact, a recommended providerPriority, AND \`currentConfig\` \u2014 the currently-saved config per domain (repo files + machine-local \`magiKindPanels\`). Nothing is written.
3776
+ 2. **Present drafts** \u2014 For each domain, show the user the suggested config with its **save scope label** (repo-file vs machine-local). When \`currentConfig\` already has a saved value for a domain (init on a partially-onboarded repo, or any reinit), present a **current-vs-suggested diff**, not just the suggestion.
3777
+ 3. **Approve \u2192 gated write** \u2014 Only after the user approves, call the matching gated-write tool:
3778
+ - repo \`.adhdev/*\` config files \u2192 \`mesh_init\` with \`write=true\` (and \`overwrite=true\` ONLY for domains the user approved replacing).
3779
+ - \`.adhdev/mesh.json\` (coordinator prompt / operating notes) \u2192 \`mesh_write_mesh_json_config\` (write=true, overwrite only if approved).
3780
+ - machine-local MAGI kind\u2192panel slots \u2192 \`mesh_magi_kind_panel_set\` (write=true). NOTE: a kind binding is a **wholesale replacement** of that kind's slot list \u2014 present the current-vs-new slots first.
3781
+ - machine-local named MAGI panels \u2192 \`mesh_magi_panel_set\`. providerPriority \u2192 apply via node policy update.
3782
+
3783
+ **init vs reinit:**
3784
+ - **\`mesh_init\`** \u2014 for a fresh, never-onboarded repo. Existing config files are kept (existing-wins) unless the user explicitly approves overwrite. Use for first-time setup.
3785
+ - **\`mesh_reinit\`** \u2014 for a repo that is already onboarded and needs its config refreshed. It re-suggests with OVERWRITE semantics and returns the current-vs-suggested \`currentConfig\` echo. Its first call is a DRY-RUN preview: you MUST present the per-section current-vs-suggested diff and get EXPLICIT per-section approval before re-invoking with write=true. Overwrite is a wholesale replacement, so it silently drops operator hand-edits if you skip the diff \u2014 never do that.
3786
+
3787
+ `;
3679
3788
  }
3680
3789
  });
3681
3790
 
@@ -5278,6 +5387,7 @@ function enqueueTask(meshId, message, opts) {
5278
5387
  ...dependsOn.length > 0 ? { dependsOn } : {},
5279
5388
  ...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
5280
5389
  ...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
5390
+ ...typeof opts?.model === "string" && opts.model.trim() ? { model: opts.model.trim() } : {},
5281
5391
  ...typeof opts?.sourceCoordinatorSessionId === "string" && opts.sourceCoordinatorSessionId.trim() ? { sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId.trim() } : {},
5282
5392
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5283
5393
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -12977,7 +13087,10 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12977
13087
  launchResult2 = await components.dispatchMeshCommand(launchTarget.daemonId, "launch_cli", {
12978
13088
  cliType: resolved.providerType,
12979
13089
  dir: node.workspace,
12980
- settings: remoteSettings
13090
+ settings: remoteSettings,
13091
+ // MAGI-KIND-PANEL model axis: forward the task's model override so the
13092
+ // remote worker session launches with it (initialModel). Best-effort.
13093
+ ...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {}
12981
13094
  });
12982
13095
  } catch (e) {
12983
13096
  markAutoLaunch(meshId, task.id, { status: "failed", reason: `remote_launch_dispatch_failed: ${e?.message || String(e)}`, nodeId, providerType: resolved.providerType });
@@ -13003,7 +13116,10 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
13003
13116
  const launchResult = await components.cliManager.handleCliCommand("launch_cli", {
13004
13117
  cliType: resolved.providerType,
13005
13118
  dir: node.workspace,
13006
- settings: launchSettings
13119
+ settings: launchSettings,
13120
+ // MAGI-KIND-PANEL model axis: local launch forwards the task's model
13121
+ // override as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
13122
+ ...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {}
13007
13123
  });
13008
13124
  if (!launchResult?.success) {
13009
13125
  const reason = launchResult?.error || "launch_cli_failed";
@@ -18261,6 +18377,11 @@ var init_provider_schema = __esm({
18261
18377
  minimum: 0,
18262
18378
  description: "Delay between pasting prompt text and pressing Enter."
18263
18379
  },
18380
+ modelLaunchArgs: {
18381
+ type: "array",
18382
+ items: { type: "string" },
18383
+ description: "Template for expanding an initialModel selection into launch args. '{{model}}' is substituted with the model string (e.g. ['--model', '{{model}}'] \u2192 --model opus). Applied at launch when a model is requested for this CLI provider (MAGI kind-panel model axis). Absent \u2192 no launch-time model selection."
18384
+ },
18264
18385
  scriptCallBudgetMs: {
18265
18386
  type: "integer",
18266
18387
  minimum: 1,
@@ -23813,6 +23934,7 @@ __export(index_exports, {
23813
23934
  getLedgerDir: () => getLedgerDir,
23814
23935
  getLedgerSummary: () => getLedgerSummary,
23815
23936
  getLogLevel: () => getLogLevel,
23937
+ getMagiKindPanel: () => getMagiKindPanel,
23816
23938
  getMagiPanel: () => getMagiPanel,
23817
23939
  getMesh: () => getMesh,
23818
23940
  getMeshByRepo: () => getMeshByRepo,
@@ -23869,6 +23991,7 @@ __export(index_exports, {
23869
23991
  launchWithCdp: () => launchWithCdp,
23870
23992
  listCoordinatorsForWorkspace: () => listCoordinatorsForWorkspace,
23871
23993
  listHostedCliRuntimes: () => listHostedCliRuntimes,
23994
+ listMagiKindPanels: () => listMagiKindPanels,
23872
23995
  listMagiPanels: () => listMagiPanels,
23873
23996
  listMeshMissionSummaries: () => listMeshMissionSummaries,
23874
23997
  listMeshes: () => listMeshes,
@@ -23904,6 +24027,7 @@ __export(index_exports, {
23904
24027
  normalizeInteractivePrompt: () => normalizeInteractivePrompt,
23905
24028
  normalizeInteractivePromptResponse: () => normalizeInteractivePromptResponse,
23906
24029
  normalizeMagiPanel: () => normalizeMagiPanel,
24030
+ normalizeMagiSlots: () => normalizeMagiSlots,
23907
24031
  normalizeManagedStatus: () => normalizeManagedStatus,
23908
24032
  normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
23909
24033
  normalizeMeshDaemonRole: () => normalizeMeshDaemonRole,
@@ -23941,6 +24065,7 @@ __export(index_exports, {
23941
24065
  recordMeshToolCall: () => recordMeshToolCall,
23942
24066
  registerExtensionProviders: () => registerExtensionProviders,
23943
24067
  registerMeshCoordinator: () => registerMeshCoordinator,
24068
+ removeMagiKindPanel: () => removeMagiKindPanel,
23944
24069
  removeMagiPanel: () => removeMagiPanel,
23945
24070
  removeNode: () => removeNode,
23946
24071
  removeWorktree: () => removeWorktree,
@@ -23975,6 +24100,7 @@ __export(index_exports, {
23975
24100
  saveState: () => saveState,
23976
24101
  setDebugRuntimeConfig: () => setDebugRuntimeConfig,
23977
24102
  setLogLevel: () => setLogLevel,
24103
+ setMagiKindPanel: () => setMagiKindPanel,
23978
24104
  setupIdeInstance: () => setupIdeInstance,
23979
24105
  shouldAutoRestoreHostedSessionsOnStartup: () => shouldAutoRestoreHostedSessionsOnStartup,
23980
24106
  shouldCollectTraceCategory: () => shouldCollectTraceCategory,
@@ -28541,6 +28667,16 @@ function callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, his
28541
28667
  const result = fn({
28542
28668
  agentType,
28543
28669
  sessionId: normalizedSessionId,
28670
+ // Arm the native-history executor's session pin guard. When the
28671
+ // instance is already bound to a provider session, pass that id as
28672
+ // `providerSessionId` so the executor rejects any *other* newest
28673
+ // session it would otherwise pick (hermes ≥0.14 creates a fresh
28674
+ // `sessions` row per internal sub-session, so an unpinned
28675
+ // newest-wins query drifts to a different id on every read →
28676
+ // re-bind churn + unbounded history re-hydration). When there is no
28677
+ // bound id yet (first-bind / workspace-only discovery) this is '',
28678
+ // which leaves the guard disarmed so discovery still works.
28679
+ providerSessionId: normalizedSessionId,
28544
28680
  historySessionId: normalizedSessionId,
28545
28681
  workspace,
28546
28682
  format: canonicalHistory?.format,
@@ -38956,24 +39092,28 @@ function executeSqlite(src, input) {
38956
39092
  return null;
38957
39093
  }
38958
39094
  try {
38959
- let sessionRow;
38960
- try {
38961
- const sessionFloorSeconds = typeof input.sessionStartedAtMs === "number" ? Math.floor(input.sessionStartedAtMs / 1e3) : 0;
38962
- const stmt = db.prepare(src.session_query);
39095
+ const requested = input.providerSessionId || "";
39096
+ let sessionId;
39097
+ if (requested) {
39098
+ sessionId = requested;
39099
+ } else {
39100
+ let sessionRow;
38963
39101
  try {
38964
- sessionRow = stmt.get(sessionFloorSeconds);
39102
+ const sessionFloorSeconds = typeof input.sessionStartedAtMs === "number" ? Math.floor(input.sessionStartedAtMs / 1e3) : 0;
39103
+ const stmt = db.prepare(src.session_query);
39104
+ try {
39105
+ sessionRow = stmt.get(sessionFloorSeconds);
39106
+ } catch {
39107
+ sessionRow = stmt.get();
39108
+ }
38965
39109
  } catch {
38966
- sessionRow = stmt.get();
39110
+ return null;
38967
39111
  }
38968
- } catch {
38969
- return null;
39112
+ if (!sessionRow) return null;
39113
+ const sessionIdRaw = Object.values(sessionRow)[0];
39114
+ sessionId = sessionIdRaw == null ? "" : String(sessionIdRaw);
38970
39115
  }
38971
- if (!sessionRow) return null;
38972
- const sessionIdRaw = Object.values(sessionRow)[0];
38973
- const sessionId = sessionIdRaw == null ? "" : String(sessionIdRaw);
38974
39116
  if (!sessionId) return null;
38975
- const requested = input.providerSessionId || "";
38976
- if (requested && sessionId !== requested) return null;
38977
39117
  const messageRows = db.prepare(src.message_query).all(sessionId);
38978
39118
  if (!messageRows || messageRows.length === 0) return null;
38979
39119
  const mtime = safeMtimeMs(resolved);
@@ -42415,7 +42555,9 @@ var CliProviderInstance = class _CliProviderInstance {
42415
42555
  typeof data.providerSessionId === "string" ? data.providerSessionId : ""
42416
42556
  );
42417
42557
  if (patchedProviderSessionId) {
42418
- this.promoteProviderSessionId(patchedProviderSessionId);
42558
+ this.promoteProviderSessionId(patchedProviderSessionId, {
42559
+ authoritative: data.sessionEvent === "new_session"
42560
+ });
42419
42561
  }
42420
42562
  if (data.sessionEvent === "new_session") {
42421
42563
  this.runtimeMessages = [];
@@ -42710,9 +42852,13 @@ ${effect.notification.body || ""}`.trim();
42710
42852
  }
42711
42853
  return lines.join("\n");
42712
42854
  }
42713
- promoteProviderSessionId(sessionId) {
42855
+ promoteProviderSessionId(sessionId, opts = {}) {
42714
42856
  const nextSessionId = String(sessionId || "").trim();
42715
42857
  if (!nextSessionId || nextSessionId === this.providerSessionId) return;
42858
+ if (this.providerSessionId && !opts.authoritative) {
42859
+ LOG.debug("CLI", `[${this.type}] ignoring non-authoritative session id ${nextSessionId} (bound to ${this.providerSessionId})`);
42860
+ return;
42861
+ }
42716
42862
  const previousHistorySessionId = this.providerSessionId || this.instanceId;
42717
42863
  const previousProviderSessionId = this.providerSessionId;
42718
42864
  this.providerSessionId = nextSessionId;
@@ -44347,6 +44493,11 @@ function expandResumeArgs(template, sessionId) {
44347
44493
  if (!Array.isArray(template) || template.length === 0) return void 0;
44348
44494
  return template.map((part) => part === "{{id}}" ? sessionId : part);
44349
44495
  }
44496
+ function expandModelLaunchArgs(template, model) {
44497
+ const m = typeof model === "string" ? model.trim() : "";
44498
+ if (!m || !Array.isArray(template) || template.length === 0) return void 0;
44499
+ return template.map((part) => part === "{{model}}" ? m : part);
44500
+ }
44350
44501
  function readSubcommandSessionId(args, subcommands) {
44351
44502
  const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
44352
44503
  if (resumeIndex < 0) return void 0;
@@ -44739,7 +44890,12 @@ Run 'adhdev doctor' for detailed diagnostics.`
44739
44890
  if (provider) {
44740
44891
  console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
44741
44892
  }
44742
- const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgs, options?.resumeSessionId);
44893
+ const modelLaunchArgs = expandModelLaunchArgs(provider?.modelLaunchArgs, initialModel);
44894
+ const cliArgsWithModel = modelLaunchArgs ? [...modelLaunchArgs, ...cliArgs || []] : cliArgs;
44895
+ if (initialModel && !modelLaunchArgs) {
44896
+ LOG.warn("CLI", `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template \u2014 launching without model selection.`);
44897
+ }
44898
+ const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgsWithModel, options?.resumeSessionId);
44743
44899
  const resolvedCliArgs = sessionBinding.cliArgs;
44744
44900
  const instanceManager = this.deps.getInstanceManager();
44745
44901
  if (provider && instanceManager) {
@@ -46618,23 +46774,30 @@ function loadMessagesForSession(db, sessionId) {
46618
46774
  }
46619
46775
  return out;
46620
46776
  }
46621
- function readSession4(sessionPath) {
46777
+ function readSession4(sessionPath, requestedSessionId) {
46622
46778
  if (!sessionPath) return null;
46623
46779
  if (sessionPath === HERMES_STATE_DB) {
46624
46780
  const db = openDb();
46625
46781
  if (!db) return null;
46626
46782
  try {
46627
- const row = db.prepare(
46628
- `SELECT id, started_at FROM sessions
46629
- WHERE source = 'cli' AND message_count > 0
46630
- ORDER BY started_at DESC LIMIT 1`
46631
- ).get();
46632
- if (!row) return null;
46633
- const messages2 = loadMessagesForSession(db, row.id);
46783
+ const pinned = String(requestedSessionId || "").trim();
46784
+ let sessionId2;
46785
+ if (pinned) {
46786
+ sessionId2 = pinned;
46787
+ } else {
46788
+ const row = db.prepare(
46789
+ `SELECT id, started_at FROM sessions
46790
+ WHERE source = 'cli' AND message_count > 0
46791
+ ORDER BY started_at DESC LIMIT 1`
46792
+ ).get();
46793
+ if (!row) return null;
46794
+ sessionId2 = String(row.id);
46795
+ }
46796
+ const messages2 = loadMessagesForSession(db, sessionId2);
46634
46797
  if (messages2.length === 0) return null;
46635
46798
  return {
46636
46799
  messages: messages2,
46637
- providerSessionId: String(row.id),
46800
+ providerSessionId: sessionId2,
46638
46801
  source: "provider-native",
46639
46802
  sourcePath: sessionPath,
46640
46803
  sourceMtimeMs: statMtimeMs4(sessionPath),
@@ -46706,7 +46869,7 @@ function createNativeHistoryDispatcher(reader) {
46706
46869
  } catch {
46707
46870
  }
46708
46871
  }
46709
- const session = readByReader(reader, sourcePath, sessionId, workspace);
46872
+ const session = readByReader(reader, sourcePath, sessionId, workspace, requestedProviderSid);
46710
46873
  if (!session) return null;
46711
46874
  if (requestedProviderSid && session.providerSessionId && session.providerSessionId !== requestedProviderSid) {
46712
46875
  return null;
@@ -46869,7 +47032,7 @@ function resolveHermesPath(workspace, sessionId) {
46869
47032
  if (!fs24.existsSync(dir)) return null;
46870
47033
  return newestRecentFile2(dir, /^session_.*\.json$/);
46871
47034
  }
46872
- function readByReader(reader, sourcePath, sessionId, workspace) {
47035
+ function readByReader(reader, sourcePath, sessionId, workspace, requestedProviderSid) {
46873
47036
  switch (reader) {
46874
47037
  case "claude-cli":
46875
47038
  return readSession(sourcePath);
@@ -46877,8 +47040,13 @@ function readByReader(reader, sourcePath, sessionId, workspace) {
46877
47040
  return readSession2(sourcePath);
46878
47041
  case "antigravity-cli":
46879
47042
  return readSession3(sourcePath, sessionId || void 0, workspace || void 0);
47043
+ // hermes reads a *shared* state.db and would otherwise pick the newest
47044
+ // source='cli' session, which drifts every read (hermes ≥0.14 writes a
47045
+ // fresh row per internal sub-session). Pass the bound id so it reads
47046
+ // THAT session directly instead of newest-wins. claude/codex resolve a
47047
+ // per-session file upstream, so they need no equivalent pin here.
46880
47048
  case "hermes-cli":
46881
- return readSession4(sourcePath);
47049
+ return readSession4(sourcePath, requestedProviderSid || void 0);
46882
47050
  }
46883
47051
  }
46884
47052
  function cwdAsDashes(cwd) {
@@ -49565,6 +49733,88 @@ var meshCrudHandlers = {
49565
49733
  return { success: false, error: e.message };
49566
49734
  }
49567
49735
  },
49736
+ // Gated WRITE path for `.adhdev/mesh.json` — the sibling of export_mesh_json_config
49737
+ // (which only DRAFTS). Same write/overwrite/dry-run contract as mesh_init's config
49738
+ // writer: defaults to dry-run (no write), never clobbers an existing repo mesh.json
49739
+ // unless overwrite=true, and validates the scaffold before persisting. The scaffold
49740
+ // is built from the machine-local mesh entry (coordinator prompt override/append);
49741
+ // policy/operating-notes are intentionally NOT exported (see buildMeshJsonConfigScaffold).
49742
+ write_mesh_json_config: async (_ctx, args) => {
49743
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
49744
+ if (!meshId) return { success: false, error: "meshId required" };
49745
+ const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
49746
+ const write = args?.write === true;
49747
+ const overwrite = args?.overwrite === true;
49748
+ try {
49749
+ const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
49750
+ const mesh = getMesh2(meshId);
49751
+ if (!mesh) return { success: false, error: "Mesh not found" };
49752
+ const {
49753
+ buildMeshJsonConfigScaffold: buildMeshJsonConfigScaffold2,
49754
+ serializeMeshJsonConfigScaffold: serializeMeshJsonConfigScaffold2,
49755
+ loadRepoMeshJsonConfig: loadRepoMeshJsonConfig2,
49756
+ normalizeRepoMeshDeclarativeConfig: normalizeRepoMeshDeclarativeConfig2,
49757
+ MESH_JSON_CONFIG_LOCATIONS: MESH_JSON_CONFIG_LOCATIONS2
49758
+ } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
49759
+ const { mkdirSync: mkdirSync21, writeFileSync: writeFileSync24 } = await import("fs");
49760
+ const { dirname: dirname17, join: join49 } = await import("path");
49761
+ const scaffold = buildMeshJsonConfigScaffold2(mesh);
49762
+ const scaffoldJson = serializeMeshJsonConfigScaffold2(scaffold);
49763
+ const relativePath = MESH_JSON_CONFIG_LOCATIONS2[0];
49764
+ const absolutePath = join49(workspace, relativePath);
49765
+ const validation = normalizeRepoMeshDeclarativeConfig2(scaffold);
49766
+ if (!validation.valid) {
49767
+ return { success: false, meshId, error: `invalid mesh.json scaffold: ${validation.errors.join("; ")}` };
49768
+ }
49769
+ const existing = loadRepoMeshJsonConfig2(workspace);
49770
+ const existingPresent = existing.sourceType === "repo_file" || existing.sourceType === "invalid";
49771
+ if (existingPresent && !overwrite) {
49772
+ return {
49773
+ success: true,
49774
+ meshId,
49775
+ written: false,
49776
+ dryRun: !write,
49777
+ skippedReason: "already_exists",
49778
+ path: absolutePath,
49779
+ relativePath,
49780
+ existing: existing.config,
49781
+ existingSourceType: existing.sourceType,
49782
+ scaffold,
49783
+ scaffoldJson,
49784
+ note: "A repo mesh.json already exists \u2014 kept as-is. Re-run with overwrite=true to replace it (this silently drops operator hand-edits, so present a current-vs-suggested diff first)."
49785
+ };
49786
+ }
49787
+ if (!write) {
49788
+ return {
49789
+ success: true,
49790
+ meshId,
49791
+ written: false,
49792
+ dryRun: true,
49793
+ path: absolutePath,
49794
+ relativePath,
49795
+ scaffold,
49796
+ scaffoldJson,
49797
+ note: "Dry-run: nothing written. Re-run with write=true to persist to the repo (commit target). meshes.json is untouched."
49798
+ };
49799
+ }
49800
+ mkdirSync21(dirname17(absolutePath), { recursive: true });
49801
+ writeFileSync24(absolutePath, `${scaffoldJson}
49802
+ `, "utf-8");
49803
+ return {
49804
+ success: true,
49805
+ meshId,
49806
+ written: true,
49807
+ dryRun: false,
49808
+ path: absolutePath,
49809
+ relativePath,
49810
+ scaffold,
49811
+ scaffoldJson,
49812
+ note: "Wrote .adhdev/mesh.json (repo commit target). Commit it to the repo; meshes.json (machine-local) is unchanged."
49813
+ };
49814
+ } catch (e) {
49815
+ return { success: false, error: e.message };
49816
+ }
49817
+ },
49568
49818
  delete_mesh: async (_ctx, args) => {
49569
49819
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
49570
49820
  if (!meshId) return { success: false, error: "meshId required" };
@@ -49626,6 +49876,42 @@ var meshCrudHandlers = {
49626
49876
  return { success: false, error: e.message };
49627
49877
  }
49628
49878
  },
49879
+ // ─── MAGI kind → panel bindings (MAGI-KIND-PANEL, machine-local config) ───
49880
+ // Per-task_kind slot lists in ~/.adhdev/meshes.json `magiKindPanels`. Same
49881
+ // owner-only gating and structured-error precedent as the magi_panel_* handlers
49882
+ // above (not listed in canPeerUsePrivilegedShareCommand → owner-only). set/remove
49883
+ // are WRITE commands; list is read-only. normalizeMagiSlots (inside setMagiKindPanel)
49884
+ // surfaces invalid_magi_kind_panel: … messages verbatim for the editor.
49885
+ magi_kind_panel_list: async (_ctx, _args) => {
49886
+ try {
49887
+ const { listMagiKindPanels: listMagiKindPanels2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
49888
+ return { success: true, kindPanels: listMagiKindPanels2() };
49889
+ } catch (e) {
49890
+ return { success: false, error: e.message };
49891
+ }
49892
+ },
49893
+ magi_kind_panel_set: async (_ctx, args) => {
49894
+ const kind = typeof args?.kind === "string" ? args.kind.trim() : "";
49895
+ if (!kind) return { success: false, error: "invalid_magi_kind_panel: task_kind is required" };
49896
+ try {
49897
+ const { setMagiKindPanel: setMagiKindPanel2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
49898
+ const slots = setMagiKindPanel2(kind, args?.slots);
49899
+ return { success: true, kind, slots };
49900
+ } catch (e) {
49901
+ return { success: false, error: e.message };
49902
+ }
49903
+ },
49904
+ magi_kind_panel_remove: async (_ctx, args) => {
49905
+ const kind = typeof args?.kind === "string" ? args.kind.trim() : "";
49906
+ if (!kind) return { success: false, error: "invalid_magi_kind_panel: task_kind is required" };
49907
+ try {
49908
+ const { removeMagiKindPanel: removeMagiKindPanel2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
49909
+ const removed = removeMagiKindPanel2(kind);
49910
+ return { success: true, removed };
49911
+ } catch (e) {
49912
+ return { success: false, error: e.message };
49913
+ }
49914
+ },
49629
49915
  add_mesh_node: async (ctx, args) => {
49630
49916
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
49631
49917
  const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
@@ -50556,8 +50842,11 @@ var import_fs17 = require("fs");
50556
50842
  var import_path12 = require("path");
50557
50843
  init_refine_config();
50558
50844
  init_worktree_bootstrap_config();
50845
+ init_change_impact_config();
50846
+ init_mesh_config();
50559
50847
  var MESH_INIT_REFINE_CONFIG_PATH = MESH_REFINE_CONFIG_LOCATIONS[0];
50560
50848
  var MESH_INIT_WORKTREE_BOOTSTRAP_CONFIG_PATH = MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS[0];
50849
+ var MESH_INIT_CHANGE_IMPACT_CONFIG_PATH = CHANGE_IMPACT_CONFIG_LOCATIONS[0];
50561
50850
  var CANDIDATE_STALE_INPUTS = [
50562
50851
  "package-lock.json",
50563
50852
  "pnpm-lock.yaml",
@@ -50639,15 +50928,46 @@ function runMeshInit(mesh, workspace, detected, options = {}) {
50639
50928
  write,
50640
50929
  overwrite
50641
50930
  });
50931
+ const changeImpactLoaded = loadChangeImpactConfig(workspace);
50932
+ const changeImpact = applyConfigSuggestion({
50933
+ workspace,
50934
+ relativePath: MESH_INIT_CHANGE_IMPACT_CONFIG_PATH,
50935
+ existing: changeImpactLoaded.sourceType === "repo_file" ? changeImpactLoaded.config : void 0,
50936
+ suggestedConfig: suggestChangeImpactConfig(workspace).suggestedConfig,
50937
+ validate: (config) => validateChangeImpactConfig(config, MESH_INIT_CHANGE_IMPACT_CONFIG_PATH).valid,
50938
+ write,
50939
+ overwrite
50940
+ });
50642
50941
  const providers = suggestNodeProviderPriority(detected);
50942
+ const refineLoaded = loadMeshRefineConfig(mesh, workspace);
50943
+ const bootstrapLoaded = loadMeshWorktreeBootstrapConfig(mesh, workspace);
50944
+ let magiKindPanels = {};
50945
+ try {
50946
+ magiKindPanels = listMagiKindPanels();
50947
+ } catch {
50948
+ magiKindPanels = {};
50949
+ }
50950
+ const currentConfig2 = {
50951
+ refine: refineLoaded.config,
50952
+ worktreeBootstrap: bootstrapLoaded.config,
50953
+ changeImpact: changeImpactLoaded.sourceType === "repo_file" ? changeImpactLoaded.config : void 0,
50954
+ sourceTypes: {
50955
+ refine: refineLoaded.sourceType,
50956
+ worktreeBootstrap: bootstrapLoaded.sourceType,
50957
+ changeImpact: changeImpactLoaded.sourceType
50958
+ },
50959
+ magiKindPanels
50960
+ };
50643
50961
  return {
50644
50962
  success: true,
50645
50963
  workspace,
50646
50964
  dryRun: !write,
50647
50965
  refine,
50648
50966
  worktreeBootstrap,
50967
+ changeImpact,
50649
50968
  providers,
50650
- note: write ? "Configs written to disk are the execution source of truth; suggestions are scaffold and only take effect once saved. providerPriority is a recommendation \u2014 apply it to node policy via clone/policy update." : "Dry-run: no files written. Re-run with write=true to persist the suggested configs. Heuristic suggestions never execute until saved as repo config."
50969
+ currentConfig: currentConfig2,
50970
+ note: write ? "Configs written to disk are the execution source of truth; suggestions are scaffold and only take effect once saved. providerPriority is a recommendation \u2014 apply it to node policy via clone/policy update. currentConfig echoes what was on disk before this run." : "Dry-run: no files written. Re-run with write=true to persist the suggested configs. Heuristic suggestions never execute until saved as repo config. Use currentConfig to diff current-vs-suggested before overwriting."
50651
50971
  };
50652
50972
  }
50653
50973
  function applyConfigSuggestion(input) {
@@ -65662,6 +65982,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
65662
65982
  getLedgerDir,
65663
65983
  getLedgerSummary,
65664
65984
  getLogLevel,
65985
+ getMagiKindPanel,
65665
65986
  getMagiPanel,
65666
65987
  getMesh,
65667
65988
  getMeshByRepo,
@@ -65718,6 +66039,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
65718
66039
  launchWithCdp,
65719
66040
  listCoordinatorsForWorkspace,
65720
66041
  listHostedCliRuntimes,
66042
+ listMagiKindPanels,
65721
66043
  listMagiPanels,
65722
66044
  listMeshMissionSummaries,
65723
66045
  listMeshes,
@@ -65753,6 +66075,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
65753
66075
  normalizeInteractivePrompt,
65754
66076
  normalizeInteractivePromptResponse,
65755
66077
  normalizeMagiPanel,
66078
+ normalizeMagiSlots,
65756
66079
  normalizeManagedStatus,
65757
66080
  normalizeMeshCapabilityTags,
65758
66081
  normalizeMeshDaemonRole,
@@ -65790,6 +66113,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
65790
66113
  recordMeshToolCall,
65791
66114
  registerExtensionProviders,
65792
66115
  registerMeshCoordinator,
66116
+ removeMagiKindPanel,
65793
66117
  removeMagiPanel,
65794
66118
  removeNode,
65795
66119
  removeWorktree,
@@ -65824,6 +66148,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
65824
66148
  saveState,
65825
66149
  setDebugRuntimeConfig,
65826
66150
  setLogLevel,
66151
+ setMagiKindPanel,
65827
66152
  setupIdeInstance,
65828
66153
  shouldAutoRestoreHostedSessionsOnStartup,
65829
66154
  shouldCollectTraceCategory,